gladvn 0.2.36 → 0.2.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/scripts/strip-comments.ts +79 -0
  4. package/src/blocks/auth-form.tsx +34 -30
  5. package/src/blocks/auth-recovery.tsx +9 -13
  6. package/src/blocks/auth-split.tsx +46 -36
  7. package/src/blocks/settings.tsx +84 -117
  8. package/src/components/macro/alert-preset.tsx +3 -1
  9. package/src/components/macro/carousel-preset.tsx +0 -1
  10. package/src/components/macro/checkbox-preset.test.tsx +2 -2
  11. package/src/components/macro/checkbox-preset.tsx +1 -2
  12. package/src/components/macro/command-preset.tsx +1 -1
  13. package/src/components/macro/date-picker.tsx +5 -18
  14. package/src/components/macro/dialog-preset.tsx +5 -3
  15. package/src/components/macro/input-preset.tsx +0 -1
  16. package/src/components/macro/select-preset.tsx +1 -1
  17. package/src/components/macro/switch-preset.test.tsx +1 -1
  18. package/src/components/micro/accordion.test.tsx +6 -12
  19. package/src/components/micro/alert-dialog.tsx +0 -2
  20. package/src/components/micro/alert.test.tsx +5 -8
  21. package/src/components/micro/alert.tsx +0 -2
  22. package/src/components/micro/badge.test.tsx +5 -7
  23. package/src/components/micro/badge.tsx +1 -3
  24. package/src/components/micro/button.test.tsx +19 -26
  25. package/src/components/micro/button.tsx +3 -11
  26. package/src/components/micro/calendar.tsx +12 -13
  27. package/src/components/micro/card.test.tsx +3 -5
  28. package/src/components/micro/carousel.tsx +0 -1
  29. package/src/components/micro/chart.tsx +3 -2
  30. package/src/components/micro/checkbox.test.tsx +9 -18
  31. package/src/components/micro/combobox.tsx +1 -3
  32. package/src/components/micro/command.tsx +23 -11
  33. package/src/components/micro/context-menu.tsx +0 -2
  34. package/src/components/micro/dialog.test.tsx +6 -14
  35. package/src/components/micro/dialog.tsx +0 -2
  36. package/src/components/micro/drawer.tsx +0 -3
  37. package/src/components/micro/dropdown-menu.test.tsx +8 -14
  38. package/src/components/micro/dropdown-menu.tsx +0 -2
  39. package/src/components/micro/field.tsx +3 -3
  40. package/src/components/micro/hover-card.tsx +0 -2
  41. package/src/components/micro/input-group.tsx +9 -42
  42. package/src/components/micro/input.test.tsx +15 -24
  43. package/src/components/micro/navigation-menu.tsx +0 -2
  44. package/src/components/micro/popover.test.tsx +5 -9
  45. package/src/components/micro/progress.tsx +5 -1
  46. package/src/components/micro/select.test.tsx +5 -18
  47. package/src/components/micro/select.tsx +3 -5
  48. package/src/components/micro/separator.tsx +1 -1
  49. package/src/components/micro/sheet.test.tsx +6 -14
  50. package/src/components/micro/sheet.tsx +0 -2
  51. package/src/components/micro/sidebar.tsx +5 -6
  52. package/src/components/micro/sonner.tsx +0 -1
  53. package/src/components/micro/switch.test.tsx +9 -18
  54. package/src/components/micro/switch.tsx +1 -1
  55. package/src/components/micro/tabs.test.tsx +5 -11
  56. package/src/components/micro/theme-provider.tsx +0 -12
  57. package/src/components/micro/toggle-group.tsx +1 -12
  58. package/src/components/micro/tooltip.test.tsx +7 -12
  59. package/src/dev/App.tsx +6 -6
  60. package/src/dev/components/BlockViewer.tsx +15 -4
  61. package/src/dev/components/Container.tsx +20 -0
  62. package/src/dev/components/GladvnLogo.tsx +3 -9
  63. package/src/dev/components/code-highlighter.tsx +5 -3
  64. package/src/dev/components/showcase.tsx +116 -168
  65. package/src/dev/sections/buttons.tsx +4 -9
  66. package/src/dev/sections/display.tsx +68 -72
  67. package/src/dev/sections/feedback.tsx +304 -314
  68. package/src/dev/sections/forms.tsx +10 -14
  69. package/src/dev/sections/interactive.tsx +32 -32
  70. package/src/dev/sections/overview.tsx +2 -10
  71. package/src/dev/showcase/accordion.tsx +512 -554
  72. package/src/dev/showcase/alert-dialog.tsx +525 -565
  73. package/src/dev/showcase/alert.tsx +352 -402
  74. package/src/dev/showcase/aspect-ratio.tsx +167 -193
  75. package/src/dev/showcase/avatar.tsx +231 -269
  76. package/src/dev/showcase/badge.tsx +92 -140
  77. package/src/dev/showcase/breadcrumb.tsx +113 -135
  78. package/src/dev/showcase/button.tsx +140 -173
  79. package/src/dev/showcase/calendar.tsx +187 -237
  80. package/src/dev/showcase/card.tsx +229 -261
  81. package/src/dev/showcase/carousel.tsx +288 -315
  82. package/src/dev/showcase/chart.tsx +44 -50
  83. package/src/dev/showcase/checkbox.tsx +286 -330
  84. package/src/dev/showcase/collapsible.tsx +143 -160
  85. package/src/dev/showcase/combobox.tsx +327 -369
  86. package/src/dev/showcase/command.tsx +106 -120
  87. package/src/dev/showcase/context-menu.tsx +93 -107
  88. package/src/dev/showcase/dialog.tsx +585 -630
  89. package/src/dev/showcase/drawer.tsx +176 -196
  90. package/src/dev/showcase/dropdown-menu.tsx +183 -201
  91. package/src/dev/showcase/empty.tsx +232 -274
  92. package/src/dev/showcase/hover-card.tsx +153 -180
  93. package/src/dev/showcase/input-group.tsx +221 -253
  94. package/src/dev/showcase/input-otp.tsx +204 -250
  95. package/src/dev/showcase/input.tsx +246 -325
  96. package/src/dev/showcase/item.tsx +134 -152
  97. package/src/dev/showcase/kbd.tsx +149 -172
  98. package/src/dev/showcase/label.tsx +50 -68
  99. package/src/dev/showcase/menubar.tsx +194 -213
  100. package/src/dev/showcase/navigation-menu.tsx +119 -133
  101. package/src/dev/showcase/overview-components/ArchitectureSection.tsx +126 -0
  102. package/src/dev/showcase/overview-components/CodeBlock.tsx +50 -0
  103. package/src/dev/showcase/overview-components/ColorPaletteSection.tsx +44 -0
  104. package/src/dev/showcase/overview-components/DashboardPreview.tsx +159 -0
  105. package/src/dev/showcase/overview-components/FeatureGridSection.tsx +535 -0
  106. package/src/dev/showcase/overview-components/FooterCTA.tsx +137 -0
  107. package/src/dev/showcase/overview-components/HeroSection.tsx +65 -0
  108. package/src/dev/showcase/overview-components/PrinciplesSection.tsx +128 -0
  109. package/src/dev/showcase/overview.tsx +21 -1163
  110. package/src/dev/showcase/pagination.tsx +144 -190
  111. package/src/dev/showcase/popover.tsx +181 -196
  112. package/src/dev/showcase/progress.tsx +141 -189
  113. package/src/dev/showcase/radio-group.tsx +272 -332
  114. package/src/dev/showcase/resizable.tsx +119 -141
  115. package/src/dev/showcase/scroll-area.tsx +21 -36
  116. package/src/dev/showcase/select.tsx +262 -322
  117. package/src/dev/showcase/separator.tsx +75 -73
  118. package/src/dev/showcase/sheet.tsx +333 -361
  119. package/src/dev/showcase/sidebar.tsx +53 -59
  120. package/src/dev/showcase/skeleton.tsx +93 -112
  121. package/src/dev/showcase/slider.tsx +244 -296
  122. package/src/dev/showcase/sonner.tsx +251 -258
  123. package/src/dev/showcase/spinner.tsx +46 -67
  124. package/src/dev/showcase/switch.tsx +298 -362
  125. package/src/dev/showcase/table.tsx +76 -80
  126. package/src/dev/showcase/tabs.tsx +302 -355
  127. package/src/dev/showcase/textarea.tsx +240 -293
  128. package/src/dev/showcase/toast.tsx +48 -54
  129. package/src/dev/showcase/toggle-group.tsx +104 -129
  130. package/src/dev/showcase/toggle.tsx +82 -102
  131. package/src/dev/showcase/tooltip.tsx +173 -192
  132. package/src/dev/showcase/why.tsx +6 -12
  133. package/src/hooks/use-mobile.test.ts +3 -2
  134. package/src/lib/utils.test.ts +5 -4
@@ -15,7 +15,7 @@ import {
15
15
 
16
16
  describe("DropdownMenu", () => {
17
17
  it("[3C.5-01] [P1] renders trigger correctly and content is hidden initially", () => {
18
- // Given
18
+
19
19
  render(
20
20
  <DropdownMenu>
21
21
  <DropdownMenuTrigger>Open Menu</DropdownMenuTrigger>
@@ -31,15 +31,14 @@ describe("DropdownMenu", () => {
31
31
  );
32
32
 
33
33
  const trigger = screen.getByRole("button", { name: "Open Menu" });
34
- // Then
34
+
35
35
  expect(trigger).toBeInTheDocument();
36
36
 
37
- // Base UI Menu might not use role="dialog" or "menu" before open, but it's hidden
38
37
  expect(screen.queryByRole("menu")).not.toBeInTheDocument();
39
38
  });
40
39
 
41
40
  it("[3C.5-02] [P1] opens the menu when trigger is clicked", async () => {
42
- // Given
41
+
43
42
  const user = userEvent.setup();
44
43
  render(
45
44
  <DropdownMenu>
@@ -54,10 +53,9 @@ describe("DropdownMenu", () => {
54
53
  );
55
54
 
56
55
  const trigger = screen.getByRole("button", { name: "Open Menu" });
57
- // When
56
+
58
57
  await user.click(trigger);
59
58
 
60
- // Then
61
59
  await waitFor(() => {
62
60
  const menu = screen.getByRole("menu");
63
61
  expect(menu).toBeInTheDocument();
@@ -69,7 +67,7 @@ describe("DropdownMenu", () => {
69
67
  });
70
68
 
71
69
  it("[3C.5-03] [P1] closes the menu when an item is clicked", async () => {
72
- // Given
70
+
73
71
  const user = userEvent.setup();
74
72
  render(
75
73
  <DropdownMenu>
@@ -80,10 +78,8 @@ describe("DropdownMenu", () => {
80
78
  </DropdownMenu>,
81
79
  );
82
80
 
83
- // When
84
81
  await user.click(screen.getByRole("button", { name: "Open Menu" }));
85
82
 
86
- // Then
87
83
  await waitFor(() => {
88
84
  expect(screen.getByRole("menu")).toBeInTheDocument();
89
85
  });
@@ -97,7 +93,7 @@ describe("DropdownMenu", () => {
97
93
  });
98
94
 
99
95
  it("[3C.5-04] [P1] supports keyboard navigation (ArrowDown, Escape)", async () => {
100
- // Given
96
+
101
97
  const user = userEvent.setup();
102
98
  render(
103
99
  <DropdownMenu>
@@ -110,19 +106,17 @@ describe("DropdownMenu", () => {
110
106
  );
111
107
 
112
108
  const trigger = screen.getByRole("button", { name: "Open Menu" });
113
- // When
109
+
114
110
  await user.tab();
115
- // Then
111
+
116
112
  expect(trigger).toHaveFocus();
117
113
 
118
- // Open with ArrowDown or Enter
119
114
  await user.keyboard("[Enter]");
120
115
 
121
116
  await waitFor(() => {
122
117
  expect(screen.getByRole("menu")).toBeInTheDocument();
123
118
  });
124
119
 
125
- // Close with Escape
126
120
  await user.keyboard("[Escape]");
127
121
 
128
122
  await waitFor(() => {
@@ -22,8 +22,6 @@ function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
22
22
  }
23
23
  DropdownMenu.displayName = "DropdownMenu";
24
24
 
25
-
26
-
27
25
  const DropdownMenuTrigger = React.forwardRef<
28
26
  HTMLButtonElement,
29
27
  MenuPrimitive.Trigger.Props
@@ -73,7 +73,7 @@ const fieldVariants = cva("group/field flex min-w-fit", {
73
73
  orientation: {
74
74
  vertical: "flex-col [&>.sr-only]:w-auto",
75
75
  horizontal: "flex-row items-center [&>[data-slot=field-label]]:flex-auto",
76
- // Responsive: vertical on mobile, horizontal on @md breakpoint.
76
+
77
77
  responsive:
78
78
  "flex-col @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>[data-slot=field-label]]:flex-auto [&>.sr-only]:w-auto",
79
79
  },
@@ -200,9 +200,9 @@ const FieldDescription = React.forwardRef<
200
200
  ref={ref}
201
201
  data-slot="field-description"
202
202
  className={cn(
203
- // Pull up when after a legend variant; balance text when inside horizontal Field
203
+
204
204
  "text-left leading-normal font-normal text-muted-foreground group-data-[orientation=horizontal]/field:text-balance [[data-variant=legend]+&]:-mt-1.5",
205
- // Tighten gap: no margin when last child, pull up when second-to-last (before FieldError)
205
+
206
206
  "last:mt-0 nth-last-2:-mt-1",
207
207
  "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
208
208
  "text-sm group-data-[size=sm]/field:text-xs",
@@ -39,8 +39,6 @@ const HoverCardTrigger = React.forwardRef<
39
39
  ));
40
40
  HoverCardTrigger.displayName = "HoverCardTrigger";
41
41
 
42
-
43
-
44
42
  const HoverCardContent = React.forwardRef<
45
43
  HTMLDivElement,
46
44
  React.ComponentPropsWithoutRef<typeof PreviewCardPrimitive.Popup> &
@@ -13,28 +13,23 @@ import { type VariantProps, cva } from "class-variance-authority";
13
13
 
14
14
  import { cn } from "../../lib/utils";
15
15
 
16
- /* ── InputGroup ─────────────────────────────────────────────────
17
- Wrapper that groups inputs, addons, and action buttons.
18
- `size` is set once here and propagated to all children via
19
- CSS group modifiers: group-data-[size=sm|md|lg]/input-group:*
20
- ─────────────────────────────────────────────────────────────── */
21
16
  const inputGroupVariants = cva(
22
17
  [
23
18
  "group/input-group relative flex min-w-0 items-center overflow-hidden rounded-lg border border-input transition-colors outline-none",
24
- // Disabled state delegated from inner elements
19
+
25
20
  "has-disabled:bg-input/50 has-disabled:opacity-50 has-disabled:cursor-not-allowed dark:has-disabled:bg-input/80",
26
- // Focus ring delegated from [data-slot=input-group-control]
21
+
27
22
  "has-[[data-slot=input-group-control]:focus-visible]:border-ring",
28
23
  "has-[[data-slot=input-group-control]:focus-visible]:ring-3",
29
24
  "has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50",
30
25
  "has-[[data-slot=input-group-control]:focus-visible]:ring-offset-1",
31
26
  "has-[[data-slot=input-group-control]:focus-visible]:ring-offset-background",
32
- // Error state delegated from aria-invalid on inner control
27
+
33
28
  "has-[[data-slot][aria-invalid=true]]:border-destructive",
34
29
  "has-[[data-slot][aria-invalid=true]:focus-visible]:ring-3",
35
30
  "has-[[data-slot][aria-invalid=true]:focus-visible]:ring-destructive/50",
36
31
  "has-[[data-slot][aria-invalid=true]:focus-visible]:border-destructive",
37
- // Dark mode base
32
+
38
33
  "dark:bg-input/30",
39
34
  ],
40
35
  {
@@ -66,11 +61,6 @@ const InputGroup = React.forwardRef<
66
61
  });
67
62
  InputGroup.displayName = "InputGroup";
68
63
 
69
- /* ── InputGroupAddon ─────────────────────────────────────────────
70
- Decorative slot for text/icon labels only (non-interactive).
71
- Clicking the addon area focuses the nearest input/textarea.
72
- Use `align="start"` (default) or `align="end"`.
73
- ─────────────────────────────────────────────────────────────── */
74
64
  const inputGroupAddonVariants = cva(
75
65
  [
76
66
  "flex h-auto cursor-text items-center justify-center gap-2 font-medium text-muted-foreground select-none",
@@ -114,12 +104,6 @@ const InputGroupAddon = React.forwardRef<
114
104
  });
115
105
  InputGroupAddon.displayName = "InputGroupAddon";
116
106
 
117
- /* ── InputGroupText ──────────────────────────────────────────────
118
- Inline label text or icon+text combo inside an InputGroupAddon.
119
- @note Decorative icons placed here should include `aria-hidden="true"`
120
- to prevent screen readers from announcing them, e.g.:
121
- <InputGroupText><SearchIcon aria-hidden="true" /></InputGroupText>
122
- ─────────────────────────────────────────────────────────────── */
123
107
  const InputGroupText = React.forwardRef<
124
108
  HTMLSpanElement,
125
109
  React.ComponentPropsWithoutRef<"span">
@@ -139,26 +123,15 @@ const InputGroupText = React.forwardRef<
139
123
  });
140
124
  InputGroupText.displayName = "InputGroupText";
141
125
 
142
- /* ── InputGroupButton ────────────────────────────────────────────
143
- Self-contained native <button>. Place directly inside InputGroup
144
- (not inside InputGroupAddon). Size is always inherited from the
145
- parent InputGroup via CSS group modifiers — no `size` prop.
146
-
147
- Separator borders (border-l / border-r) are applied automatically
148
- based on DOM position within the flex container.
149
-
150
- icon={true} → square icon-only button (width = row height)
151
- icon={false} → text button with horizontal padding (default)
152
- ─────────────────────────────────────────────────────────────── */
153
126
  const inputGroupButtonVariants = cva(
154
127
  [
155
128
  "inline-flex shrink-0 self-stretch cursor-pointer items-center justify-center gap-1.5 font-medium whitespace-nowrap transition-colors duration-150 select-none",
156
- // Self-managed focus ring (separate from wrapper delegation)
129
+
157
130
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
158
131
  "disabled:pointer-events-none disabled:opacity-50",
159
- // Auto separator borders based on sibling position
132
+
160
133
  "[&:not(:first-child)]:border-l [&:not(:last-child)]:border-r border-border",
161
- // Icon sizing — base (md/lg), overridden for sm. Shared by both icon and text modes.
134
+
162
135
  "[&>svg:not([class*='size-'])]:size-4",
163
136
  "group-data-[size=sm]/input-group:[&>svg:not([class*='size-'])]:size-3.5",
164
137
  ],
@@ -174,13 +147,13 @@ const inputGroupButtonVariants = cva(
174
147
  },
175
148
  icon: {
176
149
  true: [
177
- // Square: width = min-h of wrapper
150
+
178
151
  "group-data-[size=sm]/input-group:w-7",
179
152
  "group-data-[size=md]/input-group:w-8",
180
153
  "group-data-[size=lg]/input-group:w-9",
181
154
  ],
182
155
  false: [
183
- // Text button: horizontal padding + font size from group
156
+
184
157
  "group-data-[size=sm]/input-group:px-2 group-data-[size=sm]/input-group:text-xs",
185
158
  "group-data-[size=md]/input-group:px-2.5 group-data-[size=md]/input-group:text-sm",
186
159
  "group-data-[size=lg]/input-group:px-3 group-data-[size=lg]/input-group:text-sm",
@@ -212,9 +185,6 @@ const InputGroupButton = React.forwardRef<
212
185
  });
213
186
  InputGroupButton.displayName = "InputGroupButton";
214
187
 
215
- /* ── InputGroupInput ─────────────────────────────────────────────
216
- Self-contained native <input>. Size inherited from InputGroup.
217
- ─────────────────────────────────────────────────────────────── */
218
188
  const InputGroupInput = React.forwardRef<
219
189
  HTMLInputElement,
220
190
  React.ComponentPropsWithoutRef<"input">
@@ -236,9 +206,6 @@ const InputGroupInput = React.forwardRef<
236
206
  });
237
207
  InputGroupInput.displayName = "InputGroupInput";
238
208
 
239
- /* ── InputGroupTextarea ──────────────────────────────────────────
240
- Self-contained native <textarea>. Size inherited from InputGroup.
241
- ─────────────────────────────────────────────────────────────── */
242
209
  const InputGroupTextarea = React.forwardRef<
243
210
  HTMLTextAreaElement,
244
211
  React.ComponentPropsWithoutRef<"textarea">
@@ -7,88 +7,79 @@ import { describe, expect, it, vi } from "vitest";
7
7
  import { Input } from "./input";
8
8
 
9
9
  describe("Input", () => {
10
- // 1. Rendering & Attributes (API Surface)
10
+
11
11
  it("[3C.2-01] [P1] renders correctly with default props", () => {
12
- // Given
12
+
13
13
  render(<Input placeholder="Enter email" />);
14
14
  const input = screen.getByPlaceholderText("Enter email");
15
- // Then
15
+
16
16
  expect(input).toBeInTheDocument();
17
17
  expect(input.tagName).toBe("INPUT");
18
18
  expect(input).toHaveAttribute("data-slot", "input");
19
19
  });
20
20
 
21
21
  it("[3C.2-02] [P1] applies sizing correctly", () => {
22
- // Given
22
+
23
23
  render(<Input placeholder="Small input" size="sm" />);
24
24
  const input = screen.getByPlaceholderText("Small input");
25
- // We check the merged class string instead of exact match to avoid fragility,
26
- // but a basic check that it received the size classes is fine.
27
- // The cva variant for sm contains "h-7"
28
- // Then
25
+
29
26
  expect(input.className).toContain("h-7");
30
27
  });
31
28
 
32
29
  it("[3C.2-03] [P1] merges custom classNames properly", () => {
33
- // Given
30
+
34
31
  render(<Input placeholder="Classy input" className="custom-test-class" />);
35
32
  const input = screen.getByPlaceholderText("Classy input");
36
- // Then
33
+
37
34
  expect(input).toHaveClass("custom-test-class");
38
35
  });
39
36
 
40
- // 2. Behaviors (Interaction & Events)
41
37
  it("[3C.2-04] [P1] handles user typing correctly", async () => {
42
- // Given
38
+
43
39
  const user = userEvent.setup();
44
40
  const handleChange = vi.fn();
45
41
  render(<Input placeholder="Type here" onChange={handleChange} />);
46
42
 
47
43
  const input = screen.getByPlaceholderText("Type here");
48
- // When
44
+
49
45
  await user.type(input, "Hello");
50
46
 
51
- // Then
52
47
  expect(input).toHaveValue("Hello");
53
48
  expect(handleChange).toHaveBeenCalled();
54
49
  });
55
50
 
56
51
  it("[3C.2-05] [P1] can be focused and activated via keyboard", async () => {
57
- // Given
52
+
58
53
  const user = userEvent.setup();
59
54
  render(<Input placeholder="Focus me" />);
60
55
 
61
56
  const input = screen.getByPlaceholderText("Focus me");
62
57
 
63
- // Test focus
64
- // When
65
58
  await user.tab();
66
- // Then
59
+
67
60
  expect(input).toHaveFocus();
68
61
  });
69
62
 
70
63
  it("[3C.2-06] [P1] handles disabled state correctly and blocks typing", async () => {
71
- // Given
64
+
72
65
  const user = userEvent.setup();
73
66
  render(<Input placeholder="Disabled" disabled />);
74
67
 
75
68
  const input = screen.getByPlaceholderText("Disabled");
76
- // Then
69
+
77
70
  expect(input).toBeDisabled();
78
71
 
79
- // When
80
72
  await user.type(input, "Hello");
81
73
  expect(input).toHaveValue("");
82
74
  });
83
75
 
84
- // 3. Architecture & Integration
85
76
  it("[3C.2-07] [P1] forwards the ref to the underlying DOM element", () => {
86
- // Given
77
+
87
78
  const ref = React.createRef<HTMLInputElement>();
88
79
  render(
89
80
  <Input ref={ref} placeholder="Ref input" defaultValue="ref value" />,
90
81
  );
91
- // Then
82
+
92
83
  expect(ref.current).toBeInstanceOf(HTMLInputElement);
93
84
  expect(ref.current?.value).toBe("ref value");
94
85
  });
@@ -190,8 +190,6 @@ const NavigationMenuLink = React.forwardRef<
190
190
  });
191
191
  NavigationMenuLink.displayName = "NavigationMenuLink";
192
192
 
193
-
194
-
195
193
  export {
196
194
  NavigationMenu,
197
195
  NavigationMenuContent,
@@ -13,7 +13,7 @@ import {
13
13
 
14
14
  describe("Popover", () => {
15
15
  it("[3C.14-01] [P1] renders trigger correctly and content is hidden initially", () => {
16
- // Given
16
+
17
17
  render(
18
18
  <Popover>
19
19
  <PopoverTrigger>Open Popover</PopoverTrigger>
@@ -25,15 +25,14 @@ describe("Popover", () => {
25
25
  );
26
26
 
27
27
  const trigger = screen.getByRole("button", { name: "Open Popover" });
28
- // Then
28
+
29
29
  expect(trigger).toBeInTheDocument();
30
30
 
31
- // Content should not be in the document
32
31
  expect(screen.queryByText("Popover Title")).not.toBeInTheDocument();
33
32
  });
34
33
 
35
34
  it("[3C.14-02] [P1] opens the popover when trigger is clicked", async () => {
36
- // Given
35
+
37
36
  const user = userEvent.setup();
38
37
  render(
39
38
  <Popover>
@@ -45,17 +44,16 @@ describe("Popover", () => {
45
44
  );
46
45
 
47
46
  const trigger = screen.getByRole("button", { name: "Open Popover" });
48
- // When
47
+
49
48
  await user.click(trigger);
50
49
 
51
- // Then
52
50
  await waitFor(() => {
53
51
  expect(screen.getByText("Popover Title")).toBeInTheDocument();
54
52
  });
55
53
  });
56
54
 
57
55
  it("[3C.14-03] [P1] closes the popover when Escape is pressed", async () => {
58
- // Given
56
+
59
57
  const user = userEvent.setup();
60
58
  render(
61
59
  <Popover>
@@ -66,10 +64,8 @@ describe("Popover", () => {
66
64
  </Popover>,
67
65
  );
68
66
 
69
- // When
70
67
  await user.click(screen.getByRole("button", { name: "Open Popover" }));
71
68
 
72
- // Then
73
69
  await waitFor(() => {
74
70
  expect(screen.getByText("Popover Title")).toBeInTheDocument();
75
71
  });
@@ -62,7 +62,11 @@ function ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {
62
62
  <ProgressPrimitive.Track
63
63
  className={cn(
64
64
  "relative flex w-full items-center overflow-x-hidden rounded-full bg-muted",
65
- size ? sizeClasses[size] : "",
65
+ {
66
+ "h-1": size === "sm",
67
+ "h-1.5": size === "md",
68
+ "h-2": size === "lg",
69
+ },
66
70
  className,
67
71
  )}
68
72
  data-slot="progress-track"
@@ -14,7 +14,7 @@ import {
14
14
 
15
15
  describe("Select", () => {
16
16
  it("[3C.3-01] [P1] renders correctly with default closed state", () => {
17
- // Given
17
+
18
18
  render(
19
19
  <Select>
20
20
  <SelectTrigger aria-label="Food">
@@ -27,20 +27,17 @@ describe("Select", () => {
27
27
  </Select>,
28
28
  );
29
29
 
30
- // The trigger should be visible
31
30
  const trigger = screen.getByRole("combobox", { name: "Food" });
32
- // Then
31
+
33
32
  expect(trigger).toBeInTheDocument();
34
33
 
35
- // Check placeholder
36
34
  expect(trigger).toHaveTextContent("Select a fruit");
37
35
 
38
- // The popup content should not be in the document initially
39
36
  expect(screen.queryByRole("listbox")).not.toBeInTheDocument();
40
37
  });
41
38
 
42
39
  it("[3C.3-02] [P1] opens the popup on click and allows selection", async () => {
43
- // Given
40
+
44
41
  const user = userEvent.setup();
45
42
 
46
43
  const ControlledSelect = () => {
@@ -62,28 +59,22 @@ describe("Select", () => {
62
59
 
63
60
  const trigger = screen.getByRole("combobox", { name: "Food" });
64
61
 
65
- // Click trigger to open
66
- // When
67
62
  await user.click(trigger);
68
63
 
69
- // Wait for the popup to appear in the document
70
- // Then
71
64
  await waitFor(() => {
72
65
  expect(screen.getByRole("listbox")).toBeInTheDocument();
73
66
  });
74
67
 
75
- // Select Banana
76
68
  const bananaItem = screen.getByRole("option", { name: "Banana" });
77
69
  await user.click(bananaItem);
78
70
 
79
- // Wait for the trigger to update
80
71
  await waitFor(() => {
81
72
  expect(trigger).toHaveTextContent(/banana/i);
82
73
  });
83
74
  });
84
75
 
85
76
  it("[3C.3-03] [P1] can be navigated via keyboard", async () => {
86
- // Given
77
+
87
78
  const user = userEvent.setup();
88
79
  render(
89
80
  <Select defaultValue="apple">
@@ -99,20 +90,16 @@ describe("Select", () => {
99
90
 
100
91
  const trigger = screen.getByRole("combobox", { name: "Food" });
101
92
 
102
- // Focus trigger
103
- // When
104
93
  await user.tab();
105
- // Then
94
+
106
95
  expect(trigger).toHaveFocus();
107
96
 
108
- // Open menu with Enter (or Space)
109
97
  await user.keyboard("[Enter]");
110
98
 
111
99
  await waitFor(() => {
112
100
  expect(screen.getByRole("listbox")).toBeInTheDocument();
113
101
  });
114
102
 
115
- // Pressing Escape should close it
116
103
  await user.keyboard("[Escape]");
117
104
 
118
105
  await waitFor(() => {
@@ -44,8 +44,6 @@ const SelectValue = React.forwardRef<
44
44
  ));
45
45
  SelectValue.displayName = "SelectValue";
46
46
 
47
-
48
-
49
47
  const selectTriggerVariants = cva(
50
48
  "inline-flex items-center justify-between rounded-lg border border-input bg-transparent text-foreground text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:focus-visible:ring-3 aria-invalid:focus-visible:ring-destructive/50 data-placeholder:text-muted-foreground [&_[data-slot=select-value]]:line-clamp-1 [&_[data-slot=select-value]]:flex [&_[data-slot=select-value]]:items-center [&>svg]:pointer-events-none [&>svg]:shrink-0 [&>svg:not([class*='size-'])]:size-4 dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:focus-visible:ring-destructive/50",
51
49
  {
@@ -120,9 +118,9 @@ const SelectContent = React.forwardRef<
120
118
  data-align-trigger={alignItemWithTrigger}
121
119
  className={cn(
122
120
  "relative isolate z-50 max-h-(--available-height) w-[calc(var(--anchor-width)+8px)] overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
123
- alignItemWithTrigger
124
- ? "origin-(--transform-origin) data-[align-trigger=true]:animate-none"
125
- : "",
121
+ {
122
+ "origin-(--transform-origin) data-[align-trigger=true]:animate-none": alignItemWithTrigger,
123
+ },
126
124
  className,
127
125
  )}
128
126
  {...props}
@@ -26,7 +26,7 @@ function Separator({
26
26
  data-slot="separator"
27
27
  orientation={orientation}
28
28
  className={cn(
29
- "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
29
+ "shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=vertical]:w-px",
30
30
  className,
31
31
  )}
32
32
  {...props}
@@ -14,7 +14,7 @@ import {
14
14
 
15
15
  describe("Sheet", () => {
16
16
  it("[3C.15-01] [P1] renders trigger correctly and content is hidden initially", () => {
17
- // Given
17
+
18
18
  render(
19
19
  <Sheet>
20
20
  <SheetTrigger>Open Sheet</SheetTrigger>
@@ -28,15 +28,14 @@ describe("Sheet", () => {
28
28
  );
29
29
 
30
30
  const trigger = screen.getByRole("button", { name: "Open Sheet" });
31
- // Then
31
+
32
32
  expect(trigger).toBeInTheDocument();
33
33
 
34
- // Content should not be in the document
35
34
  expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
36
35
  });
37
36
 
38
37
  it("[3C.15-02] [P1] opens the sheet when trigger is clicked", async () => {
39
- // Given
38
+
40
39
  const user = userEvent.setup();
41
40
  render(
42
41
  <Sheet>
@@ -51,10 +50,9 @@ describe("Sheet", () => {
51
50
  );
52
51
 
53
52
  const trigger = screen.getByRole("button", { name: "Open Sheet" });
54
- // When
53
+
55
54
  await user.click(trigger);
56
55
 
57
- // Then
58
56
  await waitFor(() => {
59
57
  const sheet = screen.getByRole("dialog");
60
58
  expect(sheet).toBeInTheDocument();
@@ -64,7 +62,7 @@ describe("Sheet", () => {
64
62
  });
65
63
 
66
64
  it("[3C.15-03] [P1] closes the sheet when default Close button is clicked", async () => {
67
- // Given
65
+
68
66
  const user = userEvent.setup();
69
67
  render(
70
68
  <Sheet>
@@ -75,16 +73,12 @@ describe("Sheet", () => {
75
73
  </Sheet>,
76
74
  );
77
75
 
78
- // Open
79
- // When
80
76
  await user.click(screen.getByRole("button", { name: "Open Sheet" }));
81
77
 
82
- // Then
83
78
  await waitFor(() => {
84
79
  expect(screen.getByRole("dialog")).toBeInTheDocument();
85
80
  });
86
81
 
87
- // Close via default 'X' button
88
82
  const closeBtn = screen.getByRole("button", { name: "Close" });
89
83
  await user.click(closeBtn);
90
84
 
@@ -94,7 +88,7 @@ describe("Sheet", () => {
94
88
  });
95
89
 
96
90
  it("[3C.15-04] [P1] closes the sheet when Escape is pressed", async () => {
97
- // Given
91
+
98
92
  const user = userEvent.setup();
99
93
  render(
100
94
  <Sheet>
@@ -105,10 +99,8 @@ describe("Sheet", () => {
105
99
  </Sheet>,
106
100
  );
107
101
 
108
- // When
109
102
  await user.click(screen.getByRole("button", { name: "Open Sheet" }));
110
103
 
111
- // Then
112
104
  await waitFor(() => {
113
105
  expect(screen.getByRole("dialog")).toBeInTheDocument();
114
106
  });
@@ -28,8 +28,6 @@ function SheetClose({ ...props }: SheetPrimitive.Close.Props) {
28
28
  return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
29
29
  }
30
30
 
31
-
32
-
33
31
  function SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {
34
32
  return (
35
33
  <SheetPrimitive.Backdrop