@ponti-studios/ui 0.3.0 → 0.4.0

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 (50) hide show
  1. package/dist/index.js +70 -112
  2. package/dist/index.js.map +1 -1
  3. package/package.json +25 -23
  4. package/src/animations.css +92 -15
  5. package/src/components/data-display/accordion.tsx +15 -6
  6. package/src/components/data-display/filter-chip.stories.tsx +38 -0
  7. package/src/components/data-display/filter-chip.tsx +9 -3
  8. package/src/components/data-display/sort-controls.tsx +1 -1
  9. package/src/components/data-display/table.tsx +3 -7
  10. package/src/components/feedback/empty-state.tsx +16 -6
  11. package/src/components/feedback/file-upload-status-badge.tsx +1 -1
  12. package/src/components/feedback/progress.tsx +2 -2
  13. package/src/components/feedback/update-guard.tsx +1 -1
  14. package/src/components/forms/calendar.tsx +6 -3
  15. package/src/components/forms/field.tsx +3 -3
  16. package/src/components/forms/input.tsx +1 -1
  17. package/src/components/forms/passkey-management.tsx +2 -2
  18. package/src/components/forms/radio-group.tsx +1 -1
  19. package/src/components/forms/select.tsx +11 -4
  20. package/src/components/forms/slider.tsx +16 -4
  21. package/src/components/forms/stepper.tsx +1 -1
  22. package/src/components/forms/textarea.tsx +1 -1
  23. package/src/components/layout/section-intro.tsx +1 -1
  24. package/src/components/navigation/app-navigation.tsx +4 -4
  25. package/src/components/navigation/pagination-controls.tsx +2 -2
  26. package/src/components/navigation/tabs.tsx +1 -1
  27. package/src/components/overlays/alert-dialog.tsx +30 -8
  28. package/src/components/overlays/command.tsx +123 -20
  29. package/src/components/overlays/dialog.tsx +4 -4
  30. package/src/components/overlays/dropdown-menu.tsx +137 -21
  31. package/src/components/overlays/popover.tsx +14 -3
  32. package/src/components/overlays/sheet.tsx +24 -8
  33. package/src/components/primitives/avatar.tsx +6 -2
  34. package/src/components/primitives/badge.tsx +5 -2
  35. package/src/components/primitives/button.tsx +16 -18
  36. package/src/components/primitives/card.stories.tsx +2 -2
  37. package/src/components/primitives/card.tsx +2 -5
  38. package/src/constants/chart-colors.ts +2 -2
  39. package/src/styles.css +153 -63
  40. package/src/tokens/chart-colors.stories.tsx +192 -0
  41. package/src/tokens/color-systems.stories.tsx +21 -3
  42. package/src/tokens/foundations.stories.tsx +66 -16
  43. package/src/tokens/generated/dark.colors.generated.ts +23 -50
  44. package/src/tokens/generated/dark.css +23 -48
  45. package/src/tokens/generated/foundations.css +2 -2
  46. package/src/tokens/generated/foundations.generated.ts +14 -6
  47. package/src/tokens/generated/light.colors.generated.ts +23 -50
  48. package/src/tokens/generated/light.css +23 -48
  49. package/src/tokens/index.ts +14 -9
  50. package/src/tokens/layout.stories.tsx +40 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponti-studios/ui",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "description": "Shared UI component library for ponti-studios labs",
6
6
  "license": "MIT",
@@ -71,12 +71,25 @@
71
71
  "./styles.css": "./src/styles.css",
72
72
  "./animations.css": "./src/animations.css"
73
73
  },
74
+ "scripts": {
75
+ "build": "vite build",
76
+ "dev": "vite",
77
+ "storybook": "style-dictionary build --config style-dictionary.dark-storybook.json && storybook dev -p 6006",
78
+ "check:source": "node tokens/check-source.mjs",
79
+ "test:a11y": "vitest --run --config vitest.config.ts",
80
+ "tokens:build": "style-dictionary build --config style-dictionary.foundations.json && style-dictionary build --config style-dictionary.light.json && style-dictionary build --config style-dictionary.dark.json && style-dictionary build --config style-dictionary.dark-storybook.json",
81
+ "tokens:check": "pnpm run tokens:build && node tokens/check-foundations.mjs && git diff --exit-code -- src/tokens/generated",
82
+ "typecheck": "tsc --noEmit",
83
+ "lint": "oxlint src --fix",
84
+ "format": "oxfmt src --write",
85
+ "prepack": "pnpm run tokens:check && pnpm run check:source && pnpm run typecheck && pnpm run build"
86
+ },
74
87
  "dependencies": {
75
88
  "@base-ui/react": "^1.6.0",
89
+ "@radix-ui/colors": "^3.0.0",
76
90
  "class-variance-authority": "^0.7.1",
77
91
  "clsx": "^2.1.1",
78
92
  "date-fns": "^4.1.0",
79
- "framer-motion": "^12.42.2",
80
93
  "lucide-react": "^1.24.0",
81
94
  "react-day-picker": "^10.0.1",
82
95
  "tailwind-merge": "^3.6.0"
@@ -90,39 +103,28 @@
90
103
  "@storybook/addon-themes": "10.5.3",
91
104
  "@storybook/addon-vitest": "10.5.3",
92
105
  "@storybook/react-vite": "^10.5.3",
93
- "@tailwindcss/vite": "^4.3.3",
94
- "@types/node": "^26.1.1",
106
+ "@tailwindcss/vite": "catalog:",
107
+ "@types/node": "catalog:",
95
108
  "@types/react": "^19.2.17",
96
109
  "@types/react-dom": "^19.2.3",
97
110
  "@vitejs/plugin-react": "^6.0.3",
98
111
  "@vitest/browser": "4.1.10",
99
112
  "@vitest/browser-playwright": "4.1.10",
100
- "oxfmt": "0.59.0",
101
- "oxlint": "^1.74.0",
102
- "playwright": "^1.61.1",
113
+ "oxfmt": "catalog:shared",
114
+ "oxlint": "catalog:shared",
115
+ "playwright": "catalog:",
103
116
  "react": "^19.2.7",
104
117
  "react-dom": "^19.2.7",
105
118
  "storybook": "^10.5.3",
106
119
  "style-dictionary": "5.5.0",
107
- "tailwindcss": "^4.3.3",
120
+ "tailwindcss": "catalog:",
108
121
  "typescript": "6.0.3",
109
- "vite": "^8.1.5",
110
- "vitest": "^4.1.10"
122
+ "vite": "catalog:",
123
+ "vitest": "catalog:"
111
124
  },
112
125
  "peerDependencies": {
113
126
  "react": "^18.2.0 || ^19.0.0",
114
127
  "react-dom": "^18.2.0 || ^19.0.0"
115
128
  },
116
- "scripts": {
117
- "build": "vite build",
118
- "dev": "vite",
119
- "storybook": "storybook dev -p 6006",
120
- "check:source": "node tokens/check-source.mjs",
121
- "test:a11y": "vitest --run --config vitest.config.ts",
122
- "tokens:build": "style-dictionary build --config style-dictionary.foundations.json && style-dictionary build --config style-dictionary.light.json && style-dictionary build --config style-dictionary.dark.json",
123
- "tokens:check": "pnpm run tokens:build && node tokens/check-foundations.mjs && git diff --exit-code -- src/tokens/generated",
124
- "typecheck": "tsc --noEmit",
125
- "lint": "oxlint src --fix",
126
- "format": "oxfmt src --write"
127
- }
128
- }
129
+ "packageManager": "pnpm@10.30.3"
130
+ }
@@ -1,19 +1,96 @@
1
- @keyframes accordion-down { from { height: 0; } to { height: var(--accordion-content-height); } }
2
- @keyframes accordion-up { from { height: var(--accordion-content-height); } to { height: 0; } }
3
- @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
4
- @keyframes fade-out { from { opacity: 1; } to { opacity: 0; } }
5
- @keyframes zoom-in { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }
6
- @keyframes zoom-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.95); } }
1
+ @keyframes accordion-down {
2
+ from {
3
+ height: 0;
4
+ }
5
+ to {
6
+ height: var(--accordion-content-height);
7
+ }
8
+ }
9
+ @keyframes accordion-up {
10
+ from {
11
+ height: var(--accordion-content-height);
12
+ }
13
+ to {
14
+ height: 0;
15
+ }
16
+ }
17
+ @keyframes fade-in {
18
+ from {
19
+ opacity: 0;
20
+ }
21
+ to {
22
+ opacity: 1;
23
+ }
24
+ }
25
+ @keyframes fade-out {
26
+ from {
27
+ opacity: 1;
28
+ }
29
+ to {
30
+ opacity: 0;
31
+ }
32
+ }
33
+ @keyframes zoom-in {
34
+ from {
35
+ opacity: 0;
36
+ transform: scale(0.95);
37
+ }
38
+ to {
39
+ opacity: 1;
40
+ transform: scale(1);
41
+ }
42
+ }
43
+ @keyframes zoom-out {
44
+ from {
45
+ opacity: 1;
46
+ transform: scale(1);
47
+ }
48
+ to {
49
+ opacity: 0;
50
+ transform: scale(0.95);
51
+ }
52
+ }
7
53
 
8
- .animate-in { animation: fade-in 150ms ease-out, zoom-in 150ms ease-out; }
9
- .animate-out { animation: fade-out 120ms ease-in, zoom-out 120ms ease-in; }
10
- .fade-in-0 { animation-name: fade-in; }
11
- .fade-out-0 { animation-name: fade-out; }
12
- .zoom-in-95 { animation-name: zoom-in; }
13
- .zoom-out-95 { animation-name: zoom-out; }
14
- .data-open\:animate-in[data-open], .data-open\:animate-in[data-state="open"] { animation: fade-in 150ms ease-out, zoom-in 150ms ease-out; }
15
- .data-closed\:animate-out[data-closed], .data-closed\:animate-out[data-state="closed"] { animation: fade-out 120ms ease-in, zoom-out 120ms ease-in; }
54
+ .animate-in {
55
+ animation:
56
+ fade-in 150ms ease-out,
57
+ zoom-in 150ms ease-out;
58
+ }
59
+ .animate-out {
60
+ animation:
61
+ fade-out 120ms ease-in,
62
+ zoom-out 120ms ease-in;
63
+ }
64
+ .fade-in-0 {
65
+ animation-name: fade-in;
66
+ }
67
+ .fade-out-0 {
68
+ animation-name: fade-out;
69
+ }
70
+ .zoom-in-95 {
71
+ animation-name: zoom-in;
72
+ }
73
+ .zoom-out-95 {
74
+ animation-name: zoom-out;
75
+ }
76
+ .data-open\:animate-in[data-open],
77
+ .data-open\:animate-in[data-state="open"] {
78
+ animation:
79
+ fade-in 150ms ease-out,
80
+ zoom-in 150ms ease-out;
81
+ }
82
+ .data-closed\:animate-out[data-closed],
83
+ .data-closed\:animate-out[data-state="closed"] {
84
+ animation:
85
+ fade-out 120ms ease-in,
86
+ zoom-out 120ms ease-in;
87
+ }
16
88
 
17
89
  @media (prefers-reduced-motion: reduce) {
18
- .animate-in, .animate-out, [data-open], [data-closed] { animation: none !important; }
90
+ .animate-in,
91
+ .animate-out,
92
+ [data-open],
93
+ [data-closed] {
94
+ animation: none !important;
95
+ }
19
96
  }
@@ -4,11 +4,23 @@ import * as React from "react";
4
4
 
5
5
  import { cn } from "../../lib/utils";
6
6
 
7
- function Accordion({ type, collapsible: _collapsible, ...props }: React.ComponentProps<typeof AccordionPrimitive.Root> & {
7
+ function Accordion({
8
+ type,
9
+ collapsible: _collapsible,
10
+ className,
11
+ ...props
12
+ }: React.ComponentProps<typeof AccordionPrimitive.Root> & {
8
13
  type?: "single" | "multiple";
9
14
  collapsible?: boolean;
10
15
  }) {
11
- return <AccordionPrimitive.Root data-slot="accordion" multiple={type === "multiple"} {...props} className="w-full" />;
16
+ return (
17
+ <AccordionPrimitive.Root
18
+ data-slot="accordion"
19
+ multiple={type === "multiple"}
20
+ {...props}
21
+ className={cn("w-full", className)}
22
+ />
23
+ );
12
24
  }
13
25
 
14
26
  function AccordionItem({
@@ -18,10 +30,7 @@ function AccordionItem({
18
30
  return (
19
31
  <AccordionPrimitive.Item
20
32
  data-slot="accordion-item"
21
- className={cn(
22
- "mb-2 overflow-hidden rounded-md border last:mb-0",
23
- className,
24
- )}
33
+ className={cn("mb-2 overflow-hidden rounded-md border last:mb-0", className)}
25
34
  {...props}
26
35
  />
27
36
  );
@@ -0,0 +1,38 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+
3
+ import { FilterChip } from "./filter-chip";
4
+
5
+ const meta = {
6
+ title: "DataDisplay/FilterChip",
7
+ component: FilterChip,
8
+ tags: ["autodocs"],
9
+ args: {
10
+ onRemove: () => {},
11
+ },
12
+ } satisfies Meta<typeof FilterChip>;
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ export const Default: Story = {
18
+ args: { label: "Status: Active" },
19
+ };
20
+
21
+ export const Editable: Story = {
22
+ args: { label: "Status: Active", onClick: () => {} },
23
+ };
24
+
25
+ export const LongLabel: Story = {
26
+ args: { label: "Created between Jan 1, 2026 and Jul 24, 2026" },
27
+ };
28
+
29
+ export const Group: Story = {
30
+ args: { label: "Filters" },
31
+ render: () => (
32
+ <div className="flex flex-wrap gap-2">
33
+ <FilterChip label="Status: Active" onRemove={() => {}} onClick={() => {}} />
34
+ <FilterChip label="Team: Design" onRemove={() => {}} onClick={() => {}} />
35
+ <FilterChip label="Archived" onRemove={() => {}} />
36
+ </div>
37
+ ),
38
+ };
@@ -13,15 +13,21 @@ export interface FilterChipProps {
13
13
  /** An applied filter with an optional edit action and an explicit remove action. */
14
14
  export function FilterChip({ label, onRemove, onClick, className }: FilterChipProps) {
15
15
  const labelContent = onClick ? (
16
- <button type="button" className="min-h-11 px-3 text-left" onClick={onClick}>
16
+ <button
17
+ type="button"
18
+ className="focus-visible:ring-ring min-h-9 rounded-full px-3 text-left transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
19
+ onClick={onClick}
20
+ >
17
21
  {label}
18
22
  </button>
19
23
  ) : (
20
- <span className="flex min-h-11 items-center px-3">{label}</span>
24
+ <span className="flex min-h-9 items-center px-3">{label}</span>
21
25
  );
22
26
 
23
27
  return (
24
28
  <span
29
+ role="group"
30
+ aria-label={typeof label === "string" ? `${label} filter` : "filter"}
25
31
  className={cn(
26
32
  "border-border bg-secondary text-secondary-foreground inline-flex items-center rounded-full border text-sm font-medium",
27
33
  className,
@@ -30,7 +36,7 @@ export function FilterChip({ label, onRemove, onClick, className }: FilterChipPr
30
36
  {labelContent}
31
37
  <button
32
38
  type="button"
33
- className="text-muted-foreground hover:text-foreground mr-1 flex size-10 items-center justify-center rounded-full"
39
+ className="text-muted-foreground hover:text-foreground focus-visible:ring-ring mr-1 flex size-9 items-center justify-center rounded-full transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
34
40
  onClick={onRemove}
35
41
  aria-label={`Remove filter: ${typeof label === "string" ? label : "selected filter"}`}
36
42
  >
@@ -60,7 +60,7 @@ export function SortControls({
60
60
  <DropdownMenuItem
61
61
  key={sort.field}
62
62
  onSelect={(e) => e.preventDefault()}
63
- className={`p-0 focus:bg-transparent ${index === focusedSortIndex ? "bg-accent" : ""}`}
63
+ className={`p-0 focus:bg-transparent ${index === focusedSortIndex ? "bg-muted" : ""}`}
64
64
  >
65
65
  <SortRow
66
66
  sortOption={sort}
@@ -37,11 +37,7 @@ TableFooter.displayName = "TableFooter";
37
37
 
38
38
  const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
39
39
  ({ className, ...props }, ref) => (
40
- <tr
41
- ref={ref}
42
- className={cn("data-[state=selected]:bg-muted border-b", className)}
43
- {...props}
44
- />
40
+ <tr ref={ref} className={cn("data-[state=selected]:bg-muted border-b", className)} {...props} />
45
41
  ),
46
42
  );
47
43
  TableRow.displayName = "TableRow";
@@ -53,7 +49,7 @@ const TableHead = React.forwardRef<
53
49
  <th
54
50
  ref={ref}
55
51
  className={cn(
56
- "h-9 px-3 text-left align-middle text-xs font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
52
+ "text-muted-foreground h-9 px-3 text-left align-middle text-xs font-medium [&:has([role=checkbox])]:pr-0",
57
53
  className,
58
54
  )}
59
55
  {...props}
@@ -77,7 +73,7 @@ const TableCaption = React.forwardRef<
77
73
  HTMLTableCaptionElement,
78
74
  React.HTMLAttributes<HTMLTableCaptionElement>
79
75
  >(({ className, ...props }, ref) => (
80
- <caption ref={ref} className={cn("mt-4 text-sm text-muted-foreground", className)} {...props} />
76
+ <caption ref={ref} className={cn("text-muted-foreground mt-4 text-sm", className)} {...props} />
81
77
  ));
82
78
  TableCaption.displayName = "TableCaption";
83
79
 
@@ -37,9 +37,9 @@ export function EmptyState({
37
37
  <section
38
38
  className={cn(
39
39
  "rounded-lg px-5 py-8",
40
- variant === "default" && "border bg-card",
41
- variant === "dashed" && "border bg-card border-dashed",
42
- variant === "search" && "border bg-muted border-dashed",
40
+ variant === "default" && "bg-card border",
41
+ variant === "dashed" && "bg-card border border-dashed",
42
+ variant === "search" && "bg-muted border border-dashed",
43
43
  variant === "quiet" && "bg-surface",
44
44
  centered
45
45
  ? cn(
@@ -51,13 +51,23 @@ export function EmptyState({
51
51
  )}
52
52
  >
53
53
  {icon ? (
54
- <div className="text-muted-foreground mb-3 flex size-11 items-center justify-center" aria-hidden>
54
+ <div
55
+ className="text-muted-foreground mb-3 flex size-11 items-center justify-center"
56
+ aria-hidden
57
+ >
55
58
  {icon}
56
59
  </div>
57
60
  ) : null}
58
61
  <div className={cn("space-y-2", centered && "max-w-[34ch]")}>
59
- <h2 className={cn("text-foreground font-semibold tracking-tight", large ? "text-lg" : "text-base")}>{title}</h2>
60
- {description ? <p className="text-sm text-muted-foreground">{description}</p> : null}
62
+ <h2
63
+ className={cn(
64
+ "text-foreground font-semibold tracking-tight",
65
+ large ? "text-lg" : "text-base",
66
+ )}
67
+ >
68
+ {title}
69
+ </h2>
70
+ {description ? <p className="text-muted-foreground text-sm">{description}</p> : null}
61
71
  </div>
62
72
  {children ? <div className="mt-3">{children}</div> : null}
63
73
  {action ? <div className="mt-4">{action}</div> : null}
@@ -8,7 +8,7 @@ const STATUS_CONFIG: Record<FileUploadStatusValue, { bg: string; text: string; l
8
8
  uploading: { bg: "bg-muted", text: "text-foreground", label: "Uploading" },
9
9
  processing: { bg: "bg-muted", text: "text-foreground", label: "Processing" },
10
10
  queued: { bg: "bg-secondary", text: "text-secondary-foreground", label: "Queued" },
11
- done: { bg: "bg-accent", text: "text-accent-foreground", label: "Complete" },
11
+ done: { bg: "bg-muted", text: "text-muted-foreground", label: "Complete" },
12
12
  error: { bg: "bg-destructive/10", text: "text-destructive", label: "Error" },
13
13
  };
14
14
 
@@ -14,13 +14,13 @@ function Progress({
14
14
  return (
15
15
  <ProgressPrimitive.Root
16
16
  data-slot="progress"
17
- className={cn("bg-accent/20 relative h-2 w-full overflow-hidden rounded-full", className)}
17
+ className={cn("bg-primary/20 relative h-2 w-full overflow-hidden rounded-full", className)}
18
18
  value={value}
19
19
  {...props}
20
20
  >
21
21
  <ProgressPrimitive.Indicator
22
22
  data-slot="progress-indicator"
23
- className={cn("bg-accent h-full w-full flex-1 transition-all", indicatorClassName)}
23
+ className={cn("bg-primary h-full w-full flex-1 transition-all", indicatorClassName)}
24
24
  style={{ transform: `translateX(-${100 - (value ?? 0)}%)` }}
25
25
  />
26
26
  </ProgressPrimitive.Root>
@@ -240,7 +240,7 @@ function UpdateGuardClient({
240
240
  {copy?.refreshButton ?? "Refresh"}
241
241
  </button>
242
242
  ) : null}
243
- <button type="button" onClick={closePrompt} className="text-muted-foreground text-sm">
243
+ <button type="button" onClick={closePrompt} className="text-muted-foreground text-sm">
244
244
  {copy?.closeButton ?? "Close"}
245
245
  </button>
246
246
  </div>
@@ -24,7 +24,8 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
24
24
  "inline-flex size-8 p-2 items-center justify-center rounded-full border bg-background text-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50",
25
25
  month_grid: "w-full border-collapse",
26
26
  weekdays: "flex",
27
- weekday: "flex size-8 items-center justify-center text-[0.8rem] font-normal text-muted-foreground",
27
+ weekday:
28
+ "flex size-8 items-center justify-center text-[0.8rem] font-normal text-muted-foreground",
28
29
  week: "mt-1 flex w-full",
29
30
  day: "relative size-8 p-0 text-center text-lg focus-within:z-20",
30
31
  day_button:
@@ -34,9 +35,11 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
34
35
  today: "[&>button]:bg-primary [&>button]:text-primary-foreground",
35
36
  outside: "text-muted-foreground [&>button]:text-muted-foreground",
36
37
  disabled: "text-muted-foreground opacity-50",
37
- range_start: "rounded-l-md bg-primary [&>button]:bg-primary [&>button]:text-primary-foreground",
38
+ range_start:
39
+ "rounded-l-md bg-primary [&>button]:bg-primary [&>button]:text-primary-foreground",
38
40
  range_middle: "bg-primary [&>button]:rounded-none [&>button]:text-primary-foreground",
39
- range_end: "rounded-r-md bg-primary [&>button]:bg-primary [&>button]:text-primary-foreground",
41
+ range_end:
42
+ "rounded-r-md bg-primary [&>button]:bg-primary [&>button]:text-primary-foreground",
40
43
  hidden: "invisible",
41
44
  ...classNames,
42
45
  }}
@@ -29,7 +29,7 @@ function Field({ label, helpText, error, required, children, id: externalId }: F
29
29
  <label
30
30
  htmlFor={id}
31
31
  className={cn(
32
- "text-sm text-foreground font-medium",
32
+ "text-foreground text-sm font-medium",
33
33
  required && "after:text-destructive after:ml-0.5 after:content-['*']",
34
34
  )}
35
35
  >
@@ -50,11 +50,11 @@ function Field({ label, helpText, error, required, children, id: externalId }: F
50
50
  : children}
51
51
 
52
52
  {error ? (
53
- <p id={errorId} role="alert" className="text-sm text-destructive">
53
+ <p id={errorId} role="alert" className="text-destructive text-sm">
54
54
  {error}
55
55
  </p>
56
56
  ) : helpText ? (
57
- <p id={descId} className="text-sm text-muted-foreground">
57
+ <p id={descId} className="text-muted-foreground text-sm">
58
58
  {helpText}
59
59
  </p>
60
60
  ) : null}
@@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
8
8
  type={type}
9
9
  data-slot="input"
10
10
  className={cn(
11
- "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground bg-background focus-visible:ring-ring h-9 w-full min-w-0 rounded-md border border-input px-3 py-1 text-base transition-colors file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
11
+ "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground bg-background focus-visible:ring-ring border-input h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base transition-colors file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
12
12
  "aria-invalid:ring-destructive/20 aria-invalid:border-destructive",
13
13
  className,
14
14
  )}
@@ -69,10 +69,10 @@ export function PasskeyManagement({
69
69
  <section aria-labelledby="passkey-heading" className="space-y-4">
70
70
  <div className="flex items-center justify-between">
71
71
  <div>
72
- <h2 id="passkey-heading" className="text-sm font-medium text-foreground">
72
+ <h2 id="passkey-heading" className="text-foreground text-sm font-medium">
73
73
  Passkeys
74
74
  </h2>
75
- <p className="text-sm text-muted-foreground">
75
+ <p className="text-muted-foreground text-sm">
76
76
  Sign in without a password using biometrics or a security key.
77
77
  </p>
78
78
  </div>
@@ -23,7 +23,7 @@ const RadioGroupItem = React.forwardRef<
23
23
  <RadioPrimitive.Root
24
24
  ref={ref}
25
25
  className={cn(
26
- "border-primary bg-background text-foreground focus-visible:border-ring focus-visible:bg-accent/25 focus-visible:ring-ring aspect-square h-6 w-6 rounded-full border focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
26
+ "border-primary bg-background text-foreground focus-visible:border-ring focus-visible:bg-muted/25 focus-visible:ring-ring aspect-square h-6 w-6 rounded-full border focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
27
27
  className,
28
28
  )}
29
29
  {...props}
@@ -4,7 +4,10 @@ import * as React from "react";
4
4
 
5
5
  import { cn } from "../../lib/utils";
6
6
 
7
- type SelectProps = Omit<React.ComponentProps<typeof SelectPrimitive.Root<string>>, "onValueChange" | "value" | "defaultValue"> & {
7
+ type SelectProps = Omit<
8
+ React.ComponentProps<typeof SelectPrimitive.Root<string>>,
9
+ "onValueChange" | "value" | "defaultValue"
10
+ > & {
8
11
  value?: string;
9
12
  defaultValue?: string;
10
13
  onValueChange?: (value: string) => void;
@@ -41,7 +44,7 @@ function SelectTrigger({
41
44
  data-slot="select-trigger"
42
45
  data-size={size}
43
46
  className={cn(
44
- "data-placeholder:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 aria-invalid:border-destructive flex w-fit items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-inset disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
47
+ "data-placeholder:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 aria-invalid:border-destructive border-input flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-inset disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
45
48
  className,
46
49
  )}
47
50
  {...props}
@@ -92,12 +95,16 @@ function SelectLabel({ className, ...props }: React.ComponentProps<typeof Select
92
95
  );
93
96
  }
94
97
 
95
- function SelectItem({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Item>) {
98
+ function SelectItem({
99
+ className,
100
+ children,
101
+ ...props
102
+ }: React.ComponentProps<typeof SelectPrimitive.Item>) {
96
103
  return (
97
104
  <SelectPrimitive.Item
98
105
  data-slot="select-item"
99
106
  className={cn(
100
- "data-highlighted:bg-accent data-highlighted:text-accent-foreground relative flex w-full cursor-default items-center gap-2 rounded-md py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50",
107
+ "data-highlighted:bg-muted data-highlighted:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-md py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50",
101
108
  className,
102
109
  )}
103
110
  {...props}
@@ -5,14 +5,26 @@ import * as React from "react";
5
5
 
6
6
  import { cn } from "../../lib/utils";
7
7
 
8
- type SliderProps = Omit<React.ComponentProps<typeof SliderPrimitive.Root>, "onValueChange" | "value" | "defaultValue"> & {
8
+ type SliderProps = Omit<
9
+ React.ComponentProps<typeof SliderPrimitive.Root>,
10
+ "onValueChange" | "value" | "defaultValue"
11
+ > & {
9
12
  value?: number[];
10
13
  defaultValue?: number[];
11
14
  onValueChange?: (value: number[]) => void;
12
15
  };
13
16
 
14
17
  const Slider = React.forwardRef<HTMLDivElement, SliderProps>(
15
- ({ className, onValueChange, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }, ref) => (
18
+ (
19
+ {
20
+ className,
21
+ onValueChange,
22
+ "aria-label": ariaLabel,
23
+ "aria-labelledby": ariaLabelledby,
24
+ ...props
25
+ },
26
+ ref,
27
+ ) => (
16
28
  <SliderPrimitive.Root
17
29
  ref={ref}
18
30
  className={cn("relative flex w-full touch-none items-center select-none", className)}
@@ -20,12 +32,12 @@ const Slider = React.forwardRef<HTMLDivElement, SliderProps>(
20
32
  onValueChange={(value) => onValueChange?.(Array.isArray(value) ? [...value] : [value])}
21
33
  >
22
34
  <SliderPrimitive.Track className="bg-muted relative h-2 w-full grow overflow-hidden rounded-full">
23
- <SliderPrimitive.Indicator className="bg-accent absolute h-full" />
35
+ <SliderPrimitive.Indicator className="bg-primary absolute h-full" />
24
36
  </SliderPrimitive.Track>
25
37
  <SliderPrimitive.Thumb
26
38
  aria-label={ariaLabel ?? "Slider"}
27
39
  aria-labelledby={ariaLabelledby}
28
- className="border-border focus-visible:border-ring focus-visible:bg-accent focus-visible:ring-ring block h-6 w-6 rounded-full border bg-background shadow-sm ring-1 ring-black/5 transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50"
40
+ className="border-border focus-visible:border-ring focus-visible:bg-primary focus-visible:ring-ring bg-background block h-6 w-6 rounded-full border shadow-sm ring-1 ring-black/5 transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50"
29
41
  />
30
42
  </SliderPrimitive.Root>
31
43
  ),
@@ -32,7 +32,7 @@ function Stepper({
32
32
  const atMax = value >= max;
33
33
 
34
34
  return (
35
- <div className={cn("flex items-center rounded-lg border border-input bg-muted", className)}>
35
+ <div className={cn("border-input bg-muted flex items-center rounded-lg border", className)}>
36
36
  <Button
37
37
  type="button"
38
38
  variant="ghost"
@@ -7,7 +7,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
7
7
  <textarea
8
8
  data-slot="textarea"
9
9
  className={cn(
10
- "placeholder:text-muted-foreground aria-invalid:ring-destructive/20 aria-invalid:border-destructive focus-visible:ring-ring flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
10
+ "placeholder:text-muted-foreground aria-invalid:ring-destructive/20 aria-invalid:border-destructive focus-visible:ring-ring border-input flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
11
11
  className,
12
12
  )}
13
13
  {...props}
@@ -22,7 +22,7 @@ export function SectionIntro({ eyebrow, title, description, actions }: SectionIn
22
22
  ) : null}
23
23
  <div className="space-y-3">
24
24
  <h1 className="text-title-2 text-foreground font-semibold tracking-tight">{title}</h1>
25
- {description ? <p className="text-sm text-muted-foreground">{description}</p> : null}
25
+ {description ? <p className="text-muted-foreground text-sm">{description}</p> : null}
26
26
  </div>
27
27
  </div>
28
28
  {actions ? <div className="shrink-0">{actions}</div> : null}