Skip to content

Commit 943bcb9

Browse files
authored
Merge pull request #1205 from objectstack-ai/claude/upgrade-shadcn-controls
[WIP] Update shadcn controls to latest version
2 parents 4540503 + 85a512a commit 943bcb9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+938
-543
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import { test, expect } from '@playwright/test';
2+
import { waitForReactMount, CONSOLE_BASE } from './helpers';
3+
4+
/**
5+
* Sidebar text visibility tests
6+
*
7+
* These tests validate that the sidebar displays text correctly
8+
* when toggled between collapsed (icon mode) and expanded states.
9+
*/
10+
11+
test.describe('Sidebar Text Visibility', () => {
12+
test('should show all text labels when sidebar is expanded in icon mode', async ({ page }) => {
13+
await page.goto(`${CONSOLE_BASE}/`);
14+
await waitForReactMount(page);
15+
16+
// Wait for sidebar to be visible
17+
const sidebar = page.locator('[data-sidebar="sidebar"]').first();
18+
await expect(sidebar).toBeVisible();
19+
20+
// Find the sidebar toggle button
21+
const toggleButton = page.locator('[data-sidebar="trigger"]').first();
22+
await expect(toggleButton).toBeVisible();
23+
24+
// Get the parent sidebar element that has data-state attribute
25+
const sidebarGroup = page.locator('.group[data-collapsible="icon"]').first();
26+
27+
// First, collapse the sidebar if it's expanded
28+
let currentState = await sidebarGroup.getAttribute('data-state');
29+
if (currentState === 'expanded') {
30+
await toggleButton.click();
31+
await page.waitForTimeout(300); // Wait for animation
32+
currentState = await sidebarGroup.getAttribute('data-state');
33+
expect(currentState).toBe('collapsed');
34+
}
35+
36+
// Now expand the sidebar
37+
await toggleButton.click();
38+
await page.waitForTimeout(300); // Wait for animation
39+
40+
// Verify sidebar is expanded
41+
currentState = await sidebarGroup.getAttribute('data-state');
42+
expect(currentState).toBe('expanded');
43+
44+
// Check that group labels are visible
45+
const groupLabels = page.locator('[data-sidebar="group-label"]');
46+
const labelCount = await groupLabels.count();
47+
48+
if (labelCount > 0) {
49+
for (let i = 0; i < labelCount; i++) {
50+
const label = groupLabels.nth(i);
51+
52+
// Check opacity
53+
const opacity = await label.evaluate((el) => {
54+
return window.getComputedStyle(el).opacity;
55+
});
56+
expect(parseFloat(opacity), `Group label ${i} should be fully visible (opacity: 1)`).toBe(1);
57+
58+
// Check display
59+
const display = await label.evaluate((el) => {
60+
return window.getComputedStyle(el).display;
61+
});
62+
expect(display, `Group label ${i} should not be hidden`).not.toBe('none');
63+
}
64+
}
65+
66+
// Check that menu button text is visible
67+
const menuButtons = page.locator('[data-sidebar="menu-button"]');
68+
const buttonCount = await menuButtons.count();
69+
70+
if (buttonCount > 0) {
71+
for (let i = 0; i < buttonCount; i++) {
72+
const button = menuButtons.nth(i);
73+
74+
// Check that button has proper width (not constrained to icon size)
75+
const width = await button.evaluate((el) => {
76+
return window.getComputedStyle(el).width;
77+
});
78+
79+
// In expanded mode, button should not be constrained to 2rem (32px)
80+
const widthPx = parseFloat(width);
81+
expect(widthPx, `Menu button ${i} should be wider than icon size (${widthPx}px)`).toBeGreaterThan(32);
82+
}
83+
}
84+
85+
// Take a screenshot for visual verification
86+
await page.screenshot({
87+
path: '/tmp/sidebar-expanded.png',
88+
fullPage: false
89+
});
90+
91+
console.log(`Found ${labelCount} group labels and ${buttonCount} menu buttons`);
92+
});
93+
94+
test('should hide text labels when sidebar is collapsed in icon mode', async ({ page }) => {
95+
await page.goto(`${CONSOLE_BASE}/`);
96+
await waitForReactMount(page);
97+
98+
const sidebar = page.locator('[data-sidebar="sidebar"]').first();
99+
await expect(sidebar).toBeVisible();
100+
101+
const toggleButton = page.locator('[data-sidebar="trigger"]').first();
102+
await expect(toggleButton).toBeVisible();
103+
104+
const sidebarGroup = page.locator('.group[data-collapsible="icon"]').first();
105+
106+
// Expand first if needed
107+
let currentState = await sidebarGroup.getAttribute('data-state');
108+
if (currentState === 'collapsed') {
109+
await toggleButton.click();
110+
await page.waitForTimeout(300);
111+
}
112+
113+
// Now collapse
114+
await toggleButton.click();
115+
await page.waitForTimeout(300);
116+
117+
currentState = await sidebarGroup.getAttribute('data-state');
118+
expect(currentState).toBe('collapsed');
119+
120+
// Check that group labels are hidden
121+
const groupLabels = page.locator('[data-sidebar="group-label"]');
122+
const labelCount = await groupLabels.count();
123+
124+
if (labelCount > 0) {
125+
for (let i = 0; i < labelCount; i++) {
126+
const label = groupLabels.nth(i);
127+
128+
const opacity = await label.evaluate((el) => {
129+
return window.getComputedStyle(el).opacity;
130+
});
131+
expect(parseFloat(opacity), `Group label ${i} should be hidden (opacity: 0) when collapsed`).toBe(0);
132+
}
133+
}
134+
135+
// Take a screenshot
136+
await page.screenshot({
137+
path: '/tmp/sidebar-collapsed.png',
138+
fullPage: false
139+
});
140+
});
141+
});

packages/components/package.json

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,33 @@
3939
"@object-ui/i18n": "workspace:*",
4040
"@object-ui/react": "workspace:*",
4141
"@object-ui/types": "workspace:*",
42+
"@radix-ui/react-accordion": "^1.2.2",
43+
"@radix-ui/react-alert-dialog": "^1.1.4",
44+
"@radix-ui/react-aspect-ratio": "^1.1.1",
45+
"@radix-ui/react-avatar": "^1.1.2",
46+
"@radix-ui/react-checkbox": "^1.1.4",
47+
"@radix-ui/react-collapsible": "^1.1.2",
48+
"@radix-ui/react-context-menu": "^2.2.7",
49+
"@radix-ui/react-dialog": "^1.1.4",
50+
"@radix-ui/react-dropdown-menu": "^2.1.5",
51+
"@radix-ui/react-hover-card": "^1.1.4",
52+
"@radix-ui/react-label": "^2.1.2",
53+
"@radix-ui/react-menubar": "^1.1.3",
54+
"@radix-ui/react-navigation-menu": "^1.2.4",
55+
"@radix-ui/react-popover": "^1.1.4",
56+
"@radix-ui/react-progress": "^1.1.1",
57+
"@radix-ui/react-radio-group": "^1.2.3",
58+
"@radix-ui/react-scroll-area": "^1.2.3",
59+
"@radix-ui/react-select": "^2.1.8",
60+
"@radix-ui/react-separator": "^1.1.1",
61+
"@radix-ui/react-slider": "^1.2.3",
62+
"@radix-ui/react-slot": "^1.1.2",
63+
"@radix-ui/react-switch": "^1.1.4",
64+
"@radix-ui/react-tabs": "^1.1.3",
65+
"@radix-ui/react-toast": "^1.2.6",
66+
"@radix-ui/react-toggle": "^1.1.1",
67+
"@radix-ui/react-toggle-group": "^1.1.1",
68+
"@radix-ui/react-tooltip": "^1.1.8",
4269
"class-variance-authority": "^0.7.1",
4370
"clsx": "^2.1.1",
4471
"cmdk": "^1.1.1",
@@ -47,7 +74,6 @@
4774
"input-otp": "^1.4.2",
4875
"lucide-react": "^1.7.0",
4976
"next-themes": "^0.4.6",
50-
"radix-ui": "^1.4.3",
5177
"react-day-picker": "^9.14.0",
5278
"react-hook-form": "^7.72.1",
5379
"react-resizable-panels": "^4.9.0",

packages/components/src/__tests__/__snapshots__/snapshot-critical.test.tsx.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ exports[`Dialog snapshots > renders open dialog structure 1`] = `
460460
<div
461461
aria-describedby="radix-_r_2_"
462462
aria-labelledby="radix-_r_1_"
463-
class="fixed inset-0 z-50 grid w-full bg-background p-4 shadow-lg duration-200 h-[100dvh] sm:inset-auto sm:left-[50%] sm:top-[50%] sm:translate-x-[-50%] sm:translate-y-[-50%] sm:max-w-lg sm:h-auto sm:max-h-[90vh] sm:rounded-lg sm:border sm:p-6 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]"
463+
class="fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg"
464464
data-state="open"
465465
id="radix-_r_0_"
466466
role="dialog"
@@ -496,12 +496,12 @@ exports[`Dialog snapshots > renders open dialog structure 1`] = `
496496
</button>
497497
</div>
498498
<button
499-
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground min-h-[44px] min-w-[44px] sm:min-h-0 sm:min-w-0 flex items-center justify-center"
499+
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
500500
type="button"
501501
>
502502
<svg
503503
aria-hidden="true"
504-
class="lucide lucide-x h-5 w-5 sm:h-4 sm:w-4"
504+
class="lucide lucide-x h-4 w-4"
505505
fill="none"
506506
height="24"
507507
stroke="currentColor"

packages/components/src/custom/button-group.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
import { Slot as SlotPrimitive } from "radix-ui"
9+
import { Slot as SlotPrimitive } from "@radix-ui/react-slot"
1010
import { cva, type VariantProps } from "class-variance-authority"
1111

1212
import { cn } from "../lib/utils"
@@ -52,7 +52,7 @@ function ButtonGroupText({
5252
}: React.ComponentProps<"div"> & {
5353
asChild?: boolean
5454
}) {
55-
const Comp = asChild ? SlotPrimitive.Slot : "div"
55+
const Comp = asChild ? SlotPrimitive : "div"
5656

5757
return (
5858
<Comp

packages/components/src/custom/field.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import * as React from "react"
10-
import { Slot as SlotPrimitive } from "radix-ui"
10+
import { Slot as SlotPrimitive } from "@radix-ui/react-slot"
1111
import { cva, type VariantProps } from "class-variance-authority"
1212

1313
import { cn } from "../lib/utils"
@@ -43,7 +43,7 @@ const Field = React.forwardRef<HTMLDivElement, FieldProps>(
4343
</Label>
4444
)}
4545

46-
<SlotPrimitive.Slot
46+
<SlotPrimitive
4747
id={fieldId}
4848
aria-describedby={
4949
[description && descriptionId, error && errorId]
@@ -53,7 +53,7 @@ const Field = React.forwardRef<HTMLDivElement, FieldProps>(
5353
aria-invalid={!!error}
5454
>
5555
{children}
56-
</SlotPrimitive.Slot>
56+
</SlotPrimitive>
5757

5858
{description && !error && (
5959
<p

packages/components/src/custom/filter-builder.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ function FilterBuilder({
388388

389389
<Button
390390
variant="ghost"
391-
size="icon-sm"
391+
size="icon"
392392
className="h-9 w-9 shrink-0"
393393
onClick={() => removeCondition(condition.id)}
394394
>

packages/components/src/custom/item.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import * as React from "react"
10-
import { Slot as SlotPrimitive } from "radix-ui"
10+
import { Slot as SlotPrimitive } from "@radix-ui/react-slot"
1111
import { cva, type VariantProps } from "class-variance-authority"
1212

1313
import { cn } from "../lib/utils"
@@ -67,7 +67,7 @@ function Item({
6767
...props
6868
}: React.ComponentProps<"div"> &
6969
VariantProps<typeof itemVariants> & { asChild?: boolean }) {
70-
const Comp = asChild ? SlotPrimitive.Slot : "div"
70+
const Comp = asChild ? SlotPrimitive : "div"
7171
return (
7272
<Comp
7373
data-slot="item"

packages/components/src/custom/mobile-dialog-content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
import * as React from 'react';
21-
import { Dialog as DialogPrimitive } from "radix-ui";
21+
import * as DialogPrimitive from "@radix-ui/react-dialog";
2222
import { X } from 'lucide-react';
2323
import { cn } from '../lib/utils';
2424
import { DialogOverlay, DialogPortal } from '../ui/dialog';

packages/components/src/custom/sort-builder.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export function SortBuilder({
105105
</div>
106106
<Button
107107
variant="ghost"
108-
size="icon-sm"
108+
size="icon"
109109
className="h-9 w-9 shrink-0"
110110
onClick={() => removeItem(item.id)}
111111
>

0 commit comments

Comments
 (0)