@kinetixui/ui 0.16.1 → 0.18.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 (67) hide show
  1. package/dist/index.d.ts +4 -4
  2. package/dist/index.js +498 -248
  3. package/package.json +3 -2
  4. package/src/components/audio-player.tsx +2 -2
  5. package/src/components/badge.tsx +2 -2
  6. package/src/components/banner.tsx +2 -2
  7. package/src/components/button.tsx +18 -14
  8. package/src/components/calendar.tsx +1 -1
  9. package/src/components/chart.tsx +2 -2
  10. package/src/components/checkbox.tsx +2 -2
  11. package/src/components/circular-progress.tsx +1 -1
  12. package/src/components/code-block.tsx +1 -1
  13. package/src/components/color-picker.tsx +6 -4
  14. package/src/components/data-grid.tsx +192 -11
  15. package/src/components/diff-viewer.tsx +9 -8
  16. package/src/components/fab.tsx +1 -1
  17. package/src/components/file-upload.tsx +13 -15
  18. package/src/components/inform.tsx +1 -1
  19. package/src/components/input-group.tsx +1 -1
  20. package/src/components/input-otp.tsx +2 -1
  21. package/src/components/input.tsx +3 -3
  22. package/src/components/json-viewer.tsx +12 -10
  23. package/src/components/kbd.tsx +1 -1
  24. package/src/components/list.tsx +41 -27
  25. package/src/components/markdown-editor.tsx +3 -2
  26. package/src/components/message-bubble.tsx +3 -3
  27. package/src/components/modal.tsx +2 -2
  28. package/src/components/multi-select.tsx +28 -5
  29. package/src/components/native-select.tsx +3 -3
  30. package/src/components/notification-center.tsx +2 -2
  31. package/src/components/progress.tsx +1 -1
  32. package/src/components/radio-group.tsx +3 -3
  33. package/src/components/scroll-area.tsx +1 -1
  34. package/src/components/select.tsx +3 -3
  35. package/src/components/skeleton.tsx +1 -1
  36. package/src/components/slider.tsx +8 -3
  37. package/src/components/sonner.tsx +1 -1
  38. package/src/components/spinner.tsx +3 -3
  39. package/src/components/stepper.tsx +3 -3
  40. package/src/components/switch.tsx +1 -1
  41. package/src/components/tab-bar.tsx +1 -1
  42. package/src/components/table-of-contents.tsx +1 -1
  43. package/src/components/tag.tsx +1 -1
  44. package/src/components/textarea.tsx +3 -3
  45. package/src/components/timeline.tsx +1 -1
  46. package/src/components/tooltip.tsx +1 -1
  47. package/src/components/tour.tsx +45 -2
  48. package/src/components/virtual-list.tsx +2 -1
  49. package/src/components-a11y.test.tsx +69 -0
  50. package/src/components-behavior.test.tsx +1 -1
  51. package/src/components-keyboard.test.tsx +774 -0
  52. package/src/lib/utils.test.ts +12 -0
  53. package/src/lib/utils.ts +22 -1
  54. package/src/stories/Checkbox.stories.tsx +1 -1
  55. package/src/stories/CircularProgress.stories.tsx +4 -4
  56. package/src/stories/InputOTP.stories.tsx +2 -2
  57. package/src/stories/List.stories.tsx +2 -2
  58. package/src/stories/MarkdownEditor.stories.tsx +1 -1
  59. package/src/stories/MultiSelect.stories.tsx +1 -0
  60. package/src/stories/NativeSelect.stories.tsx +1 -1
  61. package/src/stories/NumberInput.stories.tsx +3 -3
  62. package/src/stories/Progress.stories.tsx +3 -3
  63. package/src/stories/Select.stories.tsx +2 -2
  64. package/src/stories/Slider.stories.tsx +3 -3
  65. package/src/stories/Switch.stories.tsx +1 -1
  66. package/src/stories/ToggleGroup.stories.tsx +6 -6
  67. package/tailwind.config.ts +20 -1
package/dist/index.js CHANGED
@@ -7,7 +7,35 @@ import { cva } from "class-variance-authority";
7
7
 
8
8
  // src/lib/utils.ts
9
9
  import { clsx } from "clsx";
10
- import { twMerge } from "tailwind-merge";
10
+ import { extendTailwindMerge } from "tailwind-merge";
11
+ var twMerge = extendTailwindMerge({
12
+ extend: {
13
+ classGroups: {
14
+ "font-size": [
15
+ {
16
+ text: [
17
+ "display-lg",
18
+ "display-md",
19
+ "display-sm",
20
+ "headline-lg",
21
+ "headline-md",
22
+ "headline-sm",
23
+ "title-lg",
24
+ "title-md",
25
+ "title-sm",
26
+ "title-dialog",
27
+ "label-lg",
28
+ "label-md",
29
+ "label-sm",
30
+ "body-lg",
31
+ "body-md",
32
+ "body-sm"
33
+ ]
34
+ }
35
+ ]
36
+ }
37
+ }
38
+ });
11
39
  function cn(...inputs) {
12
40
  return twMerge(clsx(inputs));
13
41
  }
@@ -28,28 +56,32 @@ var buttonVariants = cva(
28
56
  variant: {
29
57
  // bg primary / text on-primary; hover+active step down the blue ramp; disabled -> border grey
30
58
  // rest = --primary; hover/active dim it via opacity so it works in BOTH themes.
59
+ // Alphas are bounded by contrast, not taste: text on the dimmed fill must stay >= 4.5:1
60
+ // (light: 90% = 5.05, 85% = 4.54, 80% = 4.11 fails) — enforced by check:contrast.
31
61
  // (the old hover:bg-[--color-blue-600] was a hard-coded dark navy — on dark mode,
32
62
  // where --primary is light, it inverted the button into the near-black background.)
33
- Primary: "bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80 disabled:bg-border disabled:text-muted-foreground",
63
+ Primary: "bg-action text-action-foreground hover:bg-action/90 active:bg-action/85 disabled:bg-border disabled:text-muted-foreground",
34
64
  // rest = --secondary; hover/active promote to the --secondary-foreground fill with
35
- // inverted text — theme-aware, unlike the previous hard-coded green primitives
36
- Secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-foreground hover:text-secondary active:bg-secondary-foreground/90 active:text-secondary focus-visible:bg-secondary disabled:bg-border disabled:text-muted-foreground",
65
+ // inverted text — theme-aware, unlike the previous hard-coded green primitives.
66
+ // Active is solid like hover: dimming it (90% was 3.97:1) drops the text under AA,
67
+ // and anything above ~97% is imperceptible. Enforced by check:contrast.
68
+ Secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-foreground hover:text-secondary active:bg-secondary-foreground active:text-secondary focus-visible:bg-secondary disabled:bg-border disabled:text-muted-foreground",
37
69
  // 1px outline; hover fills with accent + strengthens the edge to --ring so the
38
70
  // state stays visible on the darkest surfaces (WCAG 2.2 SC 1.4.11); active pins primary
39
- Outline: "border border-input bg-transparent text-foreground hover:border-ring hover:bg-accent active:border-primary active:bg-accent active:text-primary disabled:border-input disabled:text-muted-foreground disabled:bg-transparent",
71
+ Outline: "border border-input bg-transparent text-foreground hover:border-ring hover:bg-accent active:border-action active:bg-accent active:text-action disabled:border-input disabled:text-muted-foreground disabled:bg-transparent",
40
72
  Destructive: "bg-destructive text-destructive-foreground hover:brightness-95 active:brightness-90 disabled:bg-border disabled:text-muted-foreground",
41
73
  // transparent rest; hover adds an inset --ring outline (the accent fill alone is
42
74
  // <3:1 against the page on dark) plus the accent fill; active pins primary text
43
- Ghost: "bg-transparent text-foreground hover:bg-accent hover:ring-1 hover:ring-inset hover:ring-ring active:bg-accent active:text-primary active:ring-0 disabled:text-muted-foreground disabled:bg-transparent",
44
- Link: "bg-transparent text-primary underline-offset-4 hover:underline hover:text-foreground rounded-none px-0 disabled:text-muted-foreground disabled:no-underline"
75
+ Ghost: "bg-transparent text-foreground hover:bg-accent hover:ring-1 hover:ring-inset hover:ring-ring active:bg-accent active:text-action active:ring-0 disabled:text-muted-foreground disabled:bg-transparent",
76
+ Link: "bg-transparent text-link underline-offset-4 hover:underline hover:text-foreground rounded-none px-0 disabled:text-muted-foreground disabled:no-underline"
45
77
  },
46
78
  size: {
47
79
  // padding = Figma spacing/3 + spacing/2 ; type = Label Small (11/16, +0.5 tracking)
48
- sm: "px-3 py-2 text-[11px] leading-4 tracking-[0.5px]",
80
+ sm: "px-3 py-2 text-label-sm",
49
81
  // spacing/4 + spacing/3 ; Label Medium (12/16, +0.5)
50
- md: "px-4 py-3 text-[12px] leading-4 tracking-[0.5px]",
82
+ md: "px-4 py-3 text-label-md",
51
83
  // spacing/6 + spacing/3 ; Label Large (14/20, +0.1)
52
- lg: "px-6 py-3 text-[14px] leading-5 tracking-[0.1px]",
84
+ lg: "px-6 py-3 text-label-lg",
53
85
  // spacing/3 all round, square
54
86
  icon: "p-3 [&>*:not(svg)]:sr-only"
55
87
  },
@@ -70,14 +102,14 @@ var buttonVariants = cva(
70
102
  },
71
103
  compoundVariants: [
72
104
  { variant: "Destructive", class: "focus-visible:shadow-focus-destructive" },
73
- { variant: "Primary", state: "Hover", class: "bg-primary/90" },
74
- { variant: "Primary", state: "Active", class: "bg-primary/80" },
105
+ { variant: "Primary", state: "Hover", class: "bg-action/90" },
106
+ { variant: "Primary", state: "Active", class: "bg-action/85" },
75
107
  { variant: "Secondary", state: "Hover", class: "bg-secondary-foreground text-secondary" },
76
- { variant: "Secondary", state: "Active", class: "bg-secondary-foreground/90 text-secondary" },
108
+ { variant: "Secondary", state: "Active", class: "bg-secondary-foreground text-secondary" },
77
109
  { variant: "Outline", state: "Hover", class: "border-ring bg-accent" },
78
- { variant: "Outline", state: "Active", class: "border-primary bg-accent text-primary" },
110
+ { variant: "Outline", state: "Active", class: "border-action bg-accent text-action" },
79
111
  { variant: "Ghost", state: "Hover", class: "bg-accent ring-1 ring-inset ring-ring" },
80
- { variant: "Ghost", state: "Active", class: "bg-accent text-primary" },
112
+ { variant: "Ghost", state: "Active", class: "bg-accent text-action" },
81
113
  { variant: "Link", state: "Hover", class: "underline text-foreground" },
82
114
  { variant: "Link", size: ["sm", "md", "lg"], class: "py-2 px-0 h-auto" }
83
115
  ],
@@ -110,10 +142,10 @@ import { jsx as jsx2 } from "react/jsx-runtime";
110
142
  var inputVariants = cva2(
111
143
  [
112
144
  "flex w-full border border-input bg-background px-3 py-3",
113
- "font-sans text-[14px] leading-5 tracking-[0.25px] text-foreground",
145
+ "font-sans text-body-md text-foreground",
114
146
  "placeholder:text-muted-foreground",
115
147
  "outline-none transition-colors",
116
- "focus-visible:border-primary focus-visible:shadow-focus",
148
+ "focus-visible:border-action focus-visible:shadow-focus",
117
149
  "disabled:cursor-not-allowed disabled:opacity-disabled",
118
150
  "aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:border-destructive aria-[invalid=true]:focus-visible:shadow-focus-destructive"
119
151
  ],
@@ -121,7 +153,7 @@ var inputVariants = cva2(
121
153
  variants: {
122
154
  state: {
123
155
  Default: "",
124
- Focus: "border-primary shadow-focus",
156
+ Focus: "border-action shadow-focus",
125
157
  Error: "border-destructive",
126
158
  Disabled: "opacity-disabled pointer-events-none"
127
159
  },
@@ -160,10 +192,10 @@ import { jsx as jsx3 } from "react/jsx-runtime";
160
192
  var textareaVariants = cva3(
161
193
  [
162
194
  "flex w-full min-h-[100px] resize-y rounded-sm border border-input bg-background px-3 py-3",
163
- "font-sans text-[14px] leading-5 tracking-[0.25px] text-foreground",
195
+ "font-sans text-body-md text-foreground",
164
196
  "placeholder:text-muted-foreground",
165
197
  "outline-none transition-colors",
166
- "focus-visible:border-primary focus-visible:shadow-focus",
198
+ "focus-visible:border-action focus-visible:shadow-focus",
167
199
  "disabled:cursor-not-allowed disabled:opacity-disabled",
168
200
  "aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:border-destructive aria-[invalid=true]:focus-visible:shadow-focus-destructive"
169
201
  ],
@@ -171,7 +203,7 @@ var textareaVariants = cva3(
171
203
  variants: {
172
204
  state: {
173
205
  Default: "",
174
- Focus: "border-primary shadow-focus",
206
+ Focus: "border-action shadow-focus",
175
207
  Error: "border-destructive",
176
208
  Disabled: "opacity-disabled pointer-events-none resize-none"
177
209
  }
@@ -393,11 +425,11 @@ import { Slot as Slot2 } from "@radix-ui/react-slot";
393
425
  import { cva as cva5 } from "class-variance-authority";
394
426
  import { jsx as jsx9 } from "react/jsx-runtime";
395
427
  var badgeVariants = cva5(
396
- "inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium font-sans tracking-[0.5px] transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
428
+ "inline-flex items-center rounded-full px-2.5 py-1 text-label-md font-sans transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
397
429
  {
398
430
  variants: {
399
431
  variant: {
400
- default: "bg-primary text-primary-foreground",
432
+ default: "bg-action text-action-foreground",
401
433
  secondary: "bg-secondary-foreground text-secondary",
402
434
  destructive: "bg-destructive text-destructive-foreground",
403
435
  outline: "border border-input text-foreground",
@@ -514,8 +546,8 @@ var Checkbox = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__
514
546
  "peer size-[18px] shrink-0 rounded-sm border-2 border-input outline-none transition-colors",
515
547
  "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
516
548
  "disabled:cursor-not-allowed disabled:opacity-disabled",
517
- "data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
518
- "data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground",
549
+ "data-[state=checked]:border-action data-[state=checked]:bg-action data-[state=checked]:text-action-foreground",
550
+ "data-[state=indeterminate]:border-action data-[state=indeterminate]:bg-action data-[state=indeterminate]:text-action-foreground",
519
551
  "aria-invalid:border-destructive aria-invalid:data-[state=checked]:border-destructive aria-invalid:data-[state=checked]:bg-destructive",
520
552
  className
521
553
  ),
@@ -782,7 +814,7 @@ var Progress = React18.forwardRef(({ className, value, ...props }, ref) => /* @_
782
814
  children: /* @__PURE__ */ jsx19(
783
815
  ProgressPrimitive.Indicator,
784
816
  {
785
- className: "size-full flex-1 bg-primary transition-transform",
817
+ className: "size-full flex-1 bg-action transition-transform",
786
818
  style: { transform: `translateX(-${100 - (value || 0)}%)` }
787
819
  }
788
820
  )
@@ -802,15 +834,15 @@ var RadioGroupItem = React19.forwardRef(({ className, ...props }, ref) => /* @__
802
834
  {
803
835
  ref,
804
836
  className: cn(
805
- "aspect-square size-[18px] rounded-full border-2 border-input text-primary outline-none transition-colors",
837
+ "aspect-square size-[18px] rounded-full border-2 border-input text-action outline-none transition-colors",
806
838
  "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
807
839
  "disabled:cursor-not-allowed disabled:opacity-disabled",
808
- "data-[state=checked]:border-primary",
840
+ "data-[state=checked]:border-action",
809
841
  "aria-invalid:border-destructive",
810
842
  className
811
843
  ),
812
844
  ...props,
813
- children: /* @__PURE__ */ jsx20(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx20(Circle2, { className: "size-2.5 fill-primary text-primary" }) })
845
+ children: /* @__PURE__ */ jsx20(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx20(Circle2, { className: "size-2.5 fill-action text-action" }) })
814
846
  }
815
847
  ));
816
848
  RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
@@ -820,7 +852,7 @@ import * as React20 from "react";
820
852
  import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
821
853
  import { jsx as jsx21, jsxs as jsxs8 } from "react/jsx-runtime";
822
854
  var ScrollArea = React20.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs8(ScrollAreaPrimitive.Root, { ref, className: cn("relative overflow-hidden", className), ...props, children: [
823
- /* @__PURE__ */ jsx21(ScrollAreaPrimitive.Viewport, { className: "size-full rounded-[inherit]", children }),
855
+ /* @__PURE__ */ jsx21(ScrollAreaPrimitive.Viewport, { tabIndex: 0, className: "size-full rounded-[inherit] outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring", children }),
824
856
  /* @__PURE__ */ jsx21(ScrollBar, {}),
825
857
  /* @__PURE__ */ jsx21(ScrollAreaPrimitive.Corner, {})
826
858
  ] }));
@@ -856,11 +888,11 @@ var SelectTrigger = React21.forwardRef(({ className, children, ...props }, ref)
856
888
  ref,
857
889
  className: cn(
858
890
  "flex min-h-[44px] w-full items-center justify-between rounded-sm border border-input bg-background px-3 py-3",
859
- "font-sans text-[14px] leading-5 tracking-[0.25px] text-foreground",
891
+ "font-sans text-body-md text-foreground",
860
892
  "data-[placeholder]:text-muted-foreground [&>span]:line-clamp-1",
861
893
  "outline-none transition-colors",
862
- "focus:border-primary focus:shadow-focus",
863
- "data-[state=open]:border-primary",
894
+ "focus:border-action focus:shadow-focus",
895
+ "data-[state=open]:border-action",
864
896
  "aria-[invalid=true]:border-destructive aria-[invalid=true]:focus:border-destructive aria-[invalid=true]:focus:shadow-focus-destructive",
865
897
  "disabled:cursor-not-allowed disabled:opacity-disabled",
866
898
  className
@@ -1041,7 +1073,7 @@ function Modal({
1041
1073
  ),
1042
1074
  children: [
1043
1075
  /* @__PURE__ */ jsxs11("header", { className: "flex items-center justify-between px-6 pb-3 pt-5", children: [
1044
- /* @__PURE__ */ jsx25(DialogPrimitive2.Title, { className: "min-w-0 flex-1 text-[18px] font-semibold leading-6 text-foreground", children: title }),
1076
+ /* @__PURE__ */ jsx25(DialogPrimitive2.Title, { className: "min-w-0 flex-1 text-title-dialog text-foreground", children: title }),
1045
1077
  /* @__PURE__ */ jsx25(
1046
1078
  DialogPrimitive2.Close,
1047
1079
  {
@@ -1053,7 +1085,7 @@ function Modal({
1053
1085
  ] }),
1054
1086
  /* @__PURE__ */ jsx25("div", { className: "h-px w-full bg-border" }),
1055
1087
  /* @__PURE__ */ jsxs11("div", { className: "px-6 py-5", children: [
1056
- description && /* @__PURE__ */ jsx25(DialogPrimitive2.Description, { className: "text-[14px] leading-5 tracking-[0.25px] text-muted-foreground", children: description }),
1088
+ description && /* @__PURE__ */ jsx25(DialogPrimitive2.Description, { className: "text-body-md text-muted-foreground", children: description }),
1057
1089
  children
1058
1090
  ] }),
1059
1091
  /* @__PURE__ */ jsx25("div", { className: "h-px w-full bg-border" }),
@@ -1079,22 +1111,29 @@ function Modal({
1079
1111
  // src/components/skeleton.tsx
1080
1112
  import { jsx as jsx26 } from "react/jsx-runtime";
1081
1113
  function Skeleton({ className, ...props }) {
1082
- return /* @__PURE__ */ jsx26("div", { className: cn("animate-pulse rounded-md bg-muted", className), ...props });
1114
+ return /* @__PURE__ */ jsx26("div", { className: cn("animate-pulse rounded-md bg-muted motion-reduce:animate-none", className), ...props });
1083
1115
  }
1084
1116
 
1085
1117
  // src/components/slider.tsx
1086
1118
  import * as React24 from "react";
1087
1119
  import * as SliderPrimitive from "@radix-ui/react-slider";
1088
1120
  import { jsx as jsx27, jsxs as jsxs12 } from "react/jsx-runtime";
1089
- var Slider = React24.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs12(
1121
+ var Slider = React24.forwardRef(({ className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }, ref) => /* @__PURE__ */ jsxs12(
1090
1122
  SliderPrimitive.Root,
1091
1123
  {
1092
1124
  ref,
1093
1125
  className: cn("relative flex w-full touch-none select-none items-center", className),
1094
1126
  ...props,
1095
1127
  children: [
1096
- /* @__PURE__ */ jsx27(SliderPrimitive.Track, { className: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx27(SliderPrimitive.Range, { className: "absolute h-full bg-primary" }) }),
1097
- /* @__PURE__ */ jsx27(SliderPrimitive.Thumb, { className: "block size-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-disabled" })
1128
+ /* @__PURE__ */ jsx27(SliderPrimitive.Track, { className: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx27(SliderPrimitive.Range, { className: "absolute h-full bg-action" }) }),
1129
+ /* @__PURE__ */ jsx27(
1130
+ SliderPrimitive.Thumb,
1131
+ {
1132
+ "aria-label": ariaLabel,
1133
+ "aria-labelledby": ariaLabelledBy,
1134
+ className: "block size-4 rounded-full border border-action/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-disabled"
1135
+ }
1136
+ )
1098
1137
  ]
1099
1138
  }
1100
1139
  ));
@@ -1113,7 +1152,7 @@ function Toaster({ theme = "system", ...props }) {
1113
1152
  classNames: {
1114
1153
  toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
1115
1154
  description: "group-[.toast]:text-muted-foreground",
1116
- actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
1155
+ actionButton: "group-[.toast]:bg-action group-[.toast]:text-action-foreground",
1117
1156
  cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground"
1118
1157
  }
1119
1158
  },
@@ -1134,7 +1173,7 @@ var Switch = React25.forwardRef(({ className, ...props }, ref) => /* @__PURE__ *
1134
1173
  "peer inline-flex h-6 w-12 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
1135
1174
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1136
1175
  "disabled:cursor-not-allowed disabled:opacity-disabled",
1137
- "data-[state=checked]:bg-primary data-[state=unchecked]:bg-tertiary",
1176
+ "data-[state=checked]:bg-action data-[state=unchecked]:bg-tertiary",
1138
1177
  className
1139
1178
  ),
1140
1179
  ...props,
@@ -1158,7 +1197,7 @@ import { cva as cva8 } from "class-variance-authority";
1158
1197
  import { X as X4 } from "lucide-react";
1159
1198
  import { jsx as jsx30, jsxs as jsxs13 } from "react/jsx-runtime";
1160
1199
  var tagVariants = cva8(
1161
- "inline-flex items-center gap-1 rounded-sm px-2 py-1 text-xs font-medium font-sans tracking-[0.5px]",
1200
+ "inline-flex items-center gap-1 rounded-sm px-2 py-1 text-label-md font-sans",
1162
1201
  {
1163
1202
  variants: {
1164
1203
  variant: {
@@ -1347,7 +1386,7 @@ var TooltipContent = React31.forwardRef(({ className, sideOffset = 4, ...props }
1347
1386
  ref,
1348
1387
  sideOffset,
1349
1388
  className: cn(
1350
- "z-overlay overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground font-sans",
1389
+ "z-overlay overflow-hidden rounded-md bg-action px-3 py-1.5 text-xs text-action-foreground font-sans",
1351
1390
  "animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
1352
1391
  "data-[side=bottom]:slide-in-from-top-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",
1353
1392
  className
@@ -1399,7 +1438,7 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }) {
1399
1438
  ),
1400
1439
  day_button: cn(
1401
1440
  buttonVariants({ variant: "Ghost", size: "icon" }),
1402
- "size-8 p-0 font-normal group-aria-selected:opacity-visible group-data-[selected=true]:bg-primary group-data-[selected=true]:text-primary-foreground group-data-[selected=true]:hover:bg-primary group-data-[selected=true]:hover:text-primary-foreground group-data-[selected=true]:focus:bg-primary group-data-[selected=true]:focus:text-primary-foreground"
1441
+ "size-8 p-0 font-normal group-aria-selected:opacity-visible group-data-[selected=true]:bg-action group-data-[selected=true]:text-action-foreground group-data-[selected=true]:hover:bg-action group-data-[selected=true]:hover:text-action-foreground group-data-[selected=true]:focus:bg-action group-data-[selected=true]:focus:text-action-foreground"
1403
1442
  ),
1404
1443
  range_start: "day-range-start rounded-l-md",
1405
1444
  range_end: "day-range-end rounded-r-md",
@@ -1623,7 +1662,7 @@ var ChartContainer = React33.forwardRef(({
1623
1662
  role: role ?? "img",
1624
1663
  "aria-label": name,
1625
1664
  className: cn(
1626
- "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
1665
+ "flex aspect-video justify-center text-xs [&_.recharts-surface:focus-visible]:[outline:2px_solid_hsl(var(--ring))] [&_.recharts-surface:focus-visible]:rounded-sm [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
1627
1666
  className
1628
1667
  ),
1629
1668
  ...props,
@@ -1657,7 +1696,7 @@ function ChartState({
1657
1696
  state === "loading" ? /* @__PURE__ */ jsx38("div", { "aria-hidden": true, className: "flex w-full max-w-[220px] items-end justify-between gap-1.5", children: [40, 72, 56, 88, 48, 64, 80].map((h, i) => /* @__PURE__ */ jsx38(
1658
1697
  "span",
1659
1698
  {
1660
- className: "w-full animate-pulse rounded-sm bg-muted",
1699
+ className: "w-full animate-pulse rounded-sm bg-muted motion-reduce:animate-none",
1661
1700
  style: { height: `${h}px`, animationDelay: `${i * 90}ms` }
1662
1701
  },
1663
1702
  i
@@ -2150,7 +2189,7 @@ var InputGroup = React40.forwardRef(
2150
2189
  "data-slot": "input-group",
2151
2190
  className: cn(
2152
2191
  "flex w-full items-center overflow-hidden rounded-sm border border-input bg-background font-sans transition-colors",
2153
- "focus-within:border-primary focus-within:shadow-focus",
2192
+ "focus-within:border-action focus-within:shadow-focus",
2154
2193
  "has-[[aria-invalid=true]]:border-destructive has-[[aria-invalid=true]]:focus-within:shadow-focus-destructive",
2155
2194
  "has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-disabled",
2156
2195
  className
@@ -2237,7 +2276,8 @@ var InputOTPSlot = React41.forwardRef(({ index, className, ...props }, ref) => {
2237
2276
  ref,
2238
2277
  className: cn(
2239
2278
  "relative flex size-9 items-center justify-center border-y border-r border-input text-sm shadow-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
2240
- isActive && "z-docked ring-1 ring-ring",
2279
+ // ring is a box-shadow, which forced-colors mode strips; the outline survives it
2280
+ isActive && "z-docked ring-1 ring-ring forced-colors:[outline:2px_solid] forced-colors:[outline-offset:-2px]",
2241
2281
  className
2242
2282
  ),
2243
2283
  ...props,
@@ -2787,7 +2827,7 @@ var AudioPlayer = React46.forwardRef(
2787
2827
  type: "button",
2788
2828
  onClick: toggle,
2789
2829
  "aria-label": playing ? "Pause" : "Play",
2790
- className: "grid shrink-0 place-items-center rounded-full bg-primary text-primary-foreground outline-none transition-transform hover:scale-105 focus-visible:shadow-focus",
2830
+ className: "grid shrink-0 place-items-center rounded-full bg-action text-action-foreground outline-none transition-transform hover:scale-105 focus-visible:shadow-focus",
2791
2831
  style: { width: size, height: size },
2792
2832
  children: playing ? /* @__PURE__ */ jsx52(Pause, { className: "size-1/3 fill-current" }) : /* @__PURE__ */ jsx52(Play, { className: "size-1/3 translate-x-px fill-current" })
2793
2833
  }
@@ -2813,7 +2853,7 @@ var AudioPlayer = React46.forwardRef(
2813
2853
  ] }),
2814
2854
  /* @__PURE__ */ jsx52("button", { type: "button", onClick: () => skip(skipBy), "aria-label": `Forward ${skipBy}s`, className: iconBtn, children: /* @__PURE__ */ jsx52(SkipForward, {}) }),
2815
2855
  /* @__PURE__ */ jsx52(PlayPause, { size: 36 }),
2816
- /* @__PURE__ */ jsx52("div", { className: "absolute inset-x-0 bottom-0 h-1 bg-muted", children: /* @__PURE__ */ jsx52("div", { className: "h-full bg-primary transition-[width]", style: { width: `${pct}%` } }) })
2856
+ /* @__PURE__ */ jsx52("div", { className: "absolute inset-x-0 bottom-0 h-1 bg-muted", children: /* @__PURE__ */ jsx52("div", { className: "h-full bg-action transition-[width]", style: { width: `${pct}%` } }) })
2817
2857
  ]
2818
2858
  }
2819
2859
  );
@@ -2897,7 +2937,7 @@ var CircularProgress = React47.forwardRef(
2897
2937
  strokeLinecap: "round",
2898
2938
  strokeDasharray: c,
2899
2939
  strokeDashoffset: c - v / 100 * c,
2900
- className: "stroke-primary transition-[stroke-dashoffset] duration-base"
2940
+ className: "stroke-action transition-[stroke-dashoffset] duration-base"
2901
2941
  }
2902
2942
  )
2903
2943
  ] }),
@@ -2984,7 +3024,7 @@ var informVariants = cva14(
2984
3024
  {
2985
3025
  variants: {
2986
3026
  variant: {
2987
- information: "bg-info/10 text-info",
3027
+ information: "bg-info/10 text-info-on-container",
2988
3028
  warning: "bg-warning/15 text-warning",
2989
3029
  success: "bg-success/15 text-success",
2990
3030
  error: "bg-destructive/10 text-destructive",
@@ -3110,7 +3150,7 @@ Rating.displayName = "Rating";
3110
3150
  import * as React51 from "react";
3111
3151
  import { cva as cva16 } from "class-variance-authority";
3112
3152
  import { jsx as jsx57 } from "react/jsx-runtime";
3113
- var spinnerVariants = cva16("inline-block animate-spin rounded-full border-2 border-current border-t-transparent", {
3153
+ var spinnerVariants = cva16("inline-block animate-spin motion-reduce:animate-[spin_3s_linear_infinite] rounded-full border-2 border-current border-t-transparent", {
3114
3154
  variants: {
3115
3155
  size: {
3116
3156
  sm: "size-4",
@@ -3118,9 +3158,9 @@ var spinnerVariants = cva16("inline-block animate-spin rounded-full border-2 bor
3118
3158
  lg: "size-8"
3119
3159
  },
3120
3160
  variant: {
3121
- default: "text-primary",
3161
+ default: "text-action",
3122
3162
  muted: "text-muted-foreground",
3123
- onColor: "text-primary-foreground"
3163
+ onColor: "text-action-foreground"
3124
3164
  }
3125
3165
  },
3126
3166
  defaultVariants: { size: "md", variant: "default" }
@@ -3132,7 +3172,7 @@ Spinner.displayName = "Spinner";
3132
3172
 
3133
3173
  // src/components/list.tsx
3134
3174
  import * as React52 from "react";
3135
- import { jsx as jsx58, jsxs as jsxs29 } from "react/jsx-runtime";
3175
+ import { Fragment, jsx as jsx58, jsxs as jsxs29 } from "react/jsx-runtime";
3136
3176
  var List3 = React52.forwardRef(
3137
3177
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx58("div", { ref, role: "list", className: cn("flex flex-col divide-y divide-border", className), ...props })
3138
3178
  );
@@ -3140,38 +3180,42 @@ List3.displayName = "List";
3140
3180
  var ListItem = React52.forwardRef(
3141
3181
  ({ className, leading, title, description, trailing, disabled, onSelect, ...props }, ref) => {
3142
3182
  const interactive = !!onSelect && !disabled;
3143
- return /* @__PURE__ */ jsxs29(
3183
+ const rowClass = cn(
3184
+ "flex items-center gap-3 px-3 py-3 font-sans outline-none",
3185
+ // ring keeps the highlighted row perceptible where the accent fill is <3:1 (dark)
3186
+ interactive && "cursor-pointer hover:bg-accent hover:ring-1 hover:ring-inset hover:ring-ring focus-visible:bg-accent focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring",
3187
+ disabled && "pointer-events-none opacity-disabled",
3188
+ className
3189
+ );
3190
+ const content = /* @__PURE__ */ jsxs29(Fragment, { children: [
3191
+ leading && /* @__PURE__ */ jsx58("div", { className: "flex shrink-0 items-center justify-center", children: leading }),
3192
+ /* @__PURE__ */ jsxs29("div", { className: "min-w-0 flex-1", children: [
3193
+ /* @__PURE__ */ jsx58("div", { className: "truncate text-body-md text-foreground", children: title }),
3194
+ description && /* @__PURE__ */ jsx58("div", { className: "truncate text-body-sm text-muted-foreground", children: description })
3195
+ ] }),
3196
+ trailing && /* @__PURE__ */ jsx58("div", { className: "flex shrink-0 items-center gap-2", children: trailing })
3197
+ ] });
3198
+ if (!interactive) {
3199
+ return /* @__PURE__ */ jsx58("div", { ref, role: "listitem", "aria-disabled": disabled, className: rowClass, ...props, children: content });
3200
+ }
3201
+ return /* @__PURE__ */ jsx58("div", { role: "listitem", children: /* @__PURE__ */ jsx58(
3144
3202
  "div",
3145
3203
  {
3146
3204
  ref,
3147
- role: interactive ? "button" : "listitem",
3148
- tabIndex: interactive ? 0 : void 0,
3149
- "aria-disabled": disabled,
3150
- onClick: disabled ? void 0 : onSelect,
3151
- onKeyDown: interactive ? (e) => {
3205
+ role: "button",
3206
+ tabIndex: 0,
3207
+ onClick: onSelect,
3208
+ onKeyDown: (e) => {
3152
3209
  if (e.key === "Enter" || e.key === " ") {
3153
3210
  e.preventDefault();
3154
3211
  onSelect?.();
3155
3212
  }
3156
- } : void 0,
3157
- className: cn(
3158
- "flex items-center gap-3 px-3 py-3 font-sans outline-none",
3159
- // ring keeps the highlighted row perceptible where the accent fill is <3:1 (dark)
3160
- interactive && "cursor-pointer hover:bg-accent hover:ring-1 hover:ring-inset hover:ring-ring focus-visible:bg-accent focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring",
3161
- disabled && "pointer-events-none opacity-disabled",
3162
- className
3163
- ),
3213
+ },
3214
+ className: rowClass,
3164
3215
  ...props,
3165
- children: [
3166
- leading && /* @__PURE__ */ jsx58("div", { className: "flex shrink-0 items-center justify-center", children: leading }),
3167
- /* @__PURE__ */ jsxs29("div", { className: "min-w-0 flex-1", children: [
3168
- /* @__PURE__ */ jsx58("div", { className: "truncate text-body-md text-foreground", children: title }),
3169
- description && /* @__PURE__ */ jsx58("div", { className: "truncate text-body-sm text-muted-foreground", children: description })
3170
- ] }),
3171
- trailing && /* @__PURE__ */ jsx58("div", { className: "flex shrink-0 items-center gap-2", children: trailing })
3172
- ]
3216
+ children: content
3173
3217
  }
3174
- );
3218
+ ) });
3175
3219
  }
3176
3220
  );
3177
3221
  ListItem.displayName = "ListItem";
@@ -3198,8 +3242,8 @@ var Stepper = React53.forwardRef(
3198
3242
  {
3199
3243
  className: cn(
3200
3244
  "flex size-7 shrink-0 items-center justify-center rounded-full text-label-md font-medium",
3201
- status === "complete" && "bg-primary text-primary-foreground",
3202
- status === "current" && "border-2 border-primary text-primary",
3245
+ status === "complete" && "bg-action text-action-foreground",
3246
+ status === "current" && "border-2 border-action text-action",
3203
3247
  status === "upcoming" && "border border-input text-muted-foreground"
3204
3248
  ),
3205
3249
  children: status === "complete" ? /* @__PURE__ */ jsx59(Check6, { className: "size-4" }) : i + 1
@@ -3212,7 +3256,7 @@ var Stepper = React53.forwardRef(
3212
3256
  className: cn(
3213
3257
  "bg-border",
3214
3258
  vertical ? "my-1 min-h-6 w-px flex-1 self-stretch" : "mt-3.5 h-px flex-1",
3215
- status === "complete" && "bg-primary"
3259
+ status === "complete" && "bg-action"
3216
3260
  )
3217
3261
  }
3218
3262
  )
@@ -3245,7 +3289,7 @@ var fabVariants = cva17(
3245
3289
  {
3246
3290
  variants: {
3247
3291
  variant: {
3248
- Primary: "bg-primary text-primary-foreground hover:bg-[--color-blue-600] active:bg-[--color-blue-700]",
3292
+ Primary: "bg-action text-action-foreground hover:bg-action/90 active:bg-action/85",
3249
3293
  Secondary: "bg-secondary text-secondary-foreground hover:bg-[--color-green-500] hover:text-[--color-green-50] active:bg-[--color-green-600] active:text-[--color-green-50]"
3250
3294
  },
3251
3295
  size: {
@@ -3300,7 +3344,7 @@ var TabBarItem = React55.forwardRef(
3300
3344
  "aria-current": active ? "page" : void 0,
3301
3345
  className: cn(
3302
3346
  "relative flex flex-1 flex-col items-center justify-center gap-1 py-2 text-label-sm outline-none transition-colors",
3303
- active ? "text-primary" : "text-muted-foreground hover:text-foreground",
3347
+ active ? "text-action" : "text-muted-foreground hover:text-foreground",
3304
3348
  "focus-visible:bg-accent",
3305
3349
  className
3306
3350
  ),
@@ -3470,16 +3514,7 @@ var FileUpload = React58.forwardRef(
3470
3514
  /* @__PURE__ */ jsxs34(
3471
3515
  "div",
3472
3516
  {
3473
- role: "button",
3474
- tabIndex: disabled ? -1 : 0,
3475
- "aria-disabled": disabled,
3476
3517
  onClick: () => !disabled && inputRef.current?.click(),
3477
- onKeyDown: (e) => {
3478
- if (!disabled && (e.key === "Enter" || e.key === " ")) {
3479
- e.preventDefault();
3480
- inputRef.current?.click();
3481
- }
3482
- },
3483
3518
  onDragOver: (e) => {
3484
3519
  e.preventDefault();
3485
3520
  if (!disabled) setDragging(true);
@@ -3491,9 +3526,9 @@ var FileUpload = React58.forwardRef(
3491
3526
  if (!disabled) pick(e.dataTransfer.files);
3492
3527
  },
3493
3528
  className: cn(
3494
- "flex flex-col items-center gap-2 rounded-md border border-dashed border-input p-6 text-center outline-none transition-colors",
3495
- !disabled && "cursor-pointer hover:bg-accent/50 focus-visible:shadow-focus",
3496
- dragging && "border-primary bg-accent",
3529
+ "flex flex-col items-center gap-2 rounded-md border border-dashed border-input p-6 text-center transition-colors",
3530
+ !disabled && "cursor-pointer hover:bg-accent/50",
3531
+ dragging && "border-action bg-accent",
3497
3532
  disabled && "pointer-events-none opacity-disabled"
3498
3533
  ),
3499
3534
  children: [
@@ -3526,6 +3561,8 @@ var FileUpload = React58.forwardRef(
3526
3561
  multiple,
3527
3562
  accept,
3528
3563
  disabled,
3564
+ tabIndex: -1,
3565
+ "aria-hidden": "true",
3529
3566
  className: "sr-only",
3530
3567
  onChange: (e) => {
3531
3568
  pick(e.target.files);
@@ -3545,18 +3582,18 @@ function FileUploadItem({ file, onRemove, onRetry }) {
3545
3582
  const isError = file.status === "error";
3546
3583
  const isLoading = file.status === "loading";
3547
3584
  return /* @__PURE__ */ jsxs34("li", { className: cn("flex items-center gap-2.5 rounded-md border p-2.5 text-body-sm", isError ? "border-destructive bg-destructive/5" : "border-input"), children: [
3548
- isLoading ? /* @__PURE__ */ jsx64(Loader2, { className: "size-4 shrink-0 animate-spin text-muted-foreground", "aria-hidden": true }) : isError ? /* @__PURE__ */ jsx64(TriangleAlert3, { className: "size-4 shrink-0 text-destructive", "aria-hidden": true }) : /* @__PURE__ */ jsx64(File, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
3585
+ isLoading ? /* @__PURE__ */ jsx64(Loader2, { className: "size-4 shrink-0 animate-spin motion-reduce:animate-[spin_3s_linear_infinite] text-muted-foreground", "aria-hidden": true }) : isError ? /* @__PURE__ */ jsx64(TriangleAlert3, { className: "size-4 shrink-0 text-destructive", "aria-hidden": true }) : /* @__PURE__ */ jsx64(File, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
3549
3586
  /* @__PURE__ */ jsxs34("div", { className: "min-w-0 flex-1", children: [
3550
3587
  /* @__PURE__ */ jsx64("p", { className: "truncate text-foreground", children: file.name }),
3551
3588
  isError && file.error ? /* @__PURE__ */ jsx64("p", { className: "text-destructive", children: file.error }) : /* @__PURE__ */ jsx64("p", { className: "text-muted-foreground", children: formatBytes(file.size) }),
3552
- isLoading && typeof file.progress === "number" && /* @__PURE__ */ jsx64("div", { className: "mt-1 h-1 w-full overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx64("div", { className: "h-full bg-primary transition-[width]", style: { width: `${Math.max(0, Math.min(100, file.progress))}%` } }) })
3589
+ isLoading && typeof file.progress === "number" && /* @__PURE__ */ jsx64("div", { className: "mt-1 h-1 w-full overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx64("div", { className: "h-full bg-action transition-[width]", style: { width: `${Math.max(0, Math.min(100, file.progress))}%` } }) })
3553
3590
  ] }),
3554
3591
  isError && onRetry && /* @__PURE__ */ jsx64(
3555
3592
  "button",
3556
3593
  {
3557
3594
  type: "button",
3558
3595
  onClick: () => onRetry(file.id),
3559
- className: "shrink-0 text-label-md font-medium text-primary underline-offset-2 outline-none hover:underline focus-visible:underline",
3596
+ className: "shrink-0 text-label-md font-medium text-link underline-offset-2 outline-none hover:underline focus-visible:underline",
3560
3597
  children: "Retry"
3561
3598
  }
3562
3599
  ),
@@ -3646,7 +3683,7 @@ var CodeBlock = React60.forwardRef(
3646
3683
  onClick: () => setActive(i),
3647
3684
  className: cn(
3648
3685
  "border-b-2 px-3 py-2 text-body-sm transition-colors outline-none",
3649
- i === active ? "border-primary text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
3686
+ i === active ? "border-action text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
3650
3687
  ),
3651
3688
  children: t.name || "code"
3652
3689
  },
@@ -3869,7 +3906,7 @@ var TableOfContents = React65.forwardRef(
3869
3906
  style: { paddingInlineStart: `${((item.level ?? 1) - 1) * 12 + 12}px` },
3870
3907
  className: cn(
3871
3908
  "-ms-px border-s py-1.5 text-body-sm outline-none transition-colors",
3872
- isActive ? "border-primary font-medium text-primary" : "border-transparent text-muted-foreground hover:text-foreground"
3909
+ isActive ? "border-action font-medium text-action" : "border-transparent text-muted-foreground hover:text-foreground"
3873
3910
  ),
3874
3911
  children: item.label
3875
3912
  },
@@ -3890,7 +3927,7 @@ var Kbd = React66.forwardRef(({ className, asChild = false, ...props }, ref) =>
3890
3927
  {
3891
3928
  ref,
3892
3929
  className: cn(
3893
- "inline-flex h-5 min-w-5 items-center justify-center rounded-sm border border-input bg-muted px-1.5 font-sans text-[11px] font-medium text-muted-foreground",
3930
+ "inline-flex h-5 min-w-5 items-center justify-center rounded-sm border border-input bg-muted px-1.5 font-sans text-label-sm text-muted-foreground",
3894
3931
  className
3895
3932
  ),
3896
3933
  ...props
@@ -4003,9 +4040,9 @@ import { jsx as jsx75, jsxs as jsxs41 } from "react/jsx-runtime";
4003
4040
  var nativeSelectVariants = cva19(
4004
4041
  [
4005
4042
  "flex w-full appearance-none border border-input bg-background px-3 py-3 pe-9",
4006
- "font-sans text-[14px] leading-5 tracking-[0.25px] text-foreground",
4043
+ "font-sans text-body-md text-foreground",
4007
4044
  "outline-none transition-colors",
4008
- "focus-visible:border-primary focus-visible:shadow-focus",
4045
+ "focus-visible:border-action focus-visible:shadow-focus",
4009
4046
  "disabled:cursor-not-allowed disabled:opacity-disabled",
4010
4047
  "aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:border-destructive aria-[invalid=true]:focus-visible:shadow-focus-destructive"
4011
4048
  ],
@@ -4013,7 +4050,7 @@ var nativeSelectVariants = cva19(
4013
4050
  variants: {
4014
4051
  state: {
4015
4052
  Default: "",
4016
- Focus: "border-primary shadow-focus",
4053
+ Focus: "border-action shadow-focus",
4017
4054
  Error: "border-destructive",
4018
4055
  Disabled: "opacity-disabled pointer-events-none"
4019
4056
  },
@@ -4104,7 +4141,7 @@ var bannerVariants = cva20(
4104
4141
  {
4105
4142
  variants: {
4106
4143
  variant: {
4107
- information: "border-info/20 bg-info/10 text-info",
4144
+ information: "border-info/20 bg-info/10 text-info-on-container",
4108
4145
  warning: "border-warning/25 bg-warning/15 text-warning",
4109
4146
  success: "border-success/25 bg-success/15 text-success",
4110
4147
  error: "border-destructive/20 bg-destructive/10 text-destructive",
@@ -4128,7 +4165,7 @@ var ICON2 = {
4128
4165
  var Banner = React71.forwardRef(
4129
4166
  ({ className, variant = "information", sticky, hideIcon, onDismiss, action, children, ...props }, ref) => {
4130
4167
  const Icon2 = ICON2[variant ?? "information"];
4131
- return /* @__PURE__ */ jsxs43("div", { ref, role: "banner", className: cn(bannerVariants({ variant, sticky }), className), ...props, children: [
4168
+ return /* @__PURE__ */ jsxs43("div", { ref, className: cn(bannerVariants({ variant, sticky }), className), ...props, children: [
4132
4169
  !hideIcon && /* @__PURE__ */ jsx77(Icon2, {}),
4133
4170
  /* @__PURE__ */ jsxs43("div", { className: "mx-auto flex min-w-0 max-w-4xl flex-1 flex-wrap items-center justify-center gap-x-3 gap-y-1 text-center", children: [
4134
4171
  /* @__PURE__ */ jsx77("span", { children }),
@@ -4196,7 +4233,7 @@ var Body = ({ item, align }) => /* @__PURE__ */ jsxs44("div", { className: cn("p
4196
4233
  item.content && /* @__PURE__ */ jsx79("div", { className: "text-body-sm text-muted-foreground", children: item.content })
4197
4234
  ] });
4198
4235
  var Rail = ({ item, isLast }) => /* @__PURE__ */ jsxs44("div", { className: "flex flex-col items-center", children: [
4199
- /* @__PURE__ */ jsx79("span", { className: "flex size-2.5 shrink-0 items-center justify-center rounded-full bg-primary", children: item.icon }),
4236
+ /* @__PURE__ */ jsx79("span", { className: "flex size-2.5 shrink-0 items-center justify-center rounded-full bg-action", children: item.icon }),
4200
4237
  !isLast && /* @__PURE__ */ jsx79("span", { "aria-hidden": true, className: "my-1 w-px flex-1 bg-border" })
4201
4238
  ] });
4202
4239
  var Timeline = React73.forwardRef(
@@ -4374,7 +4411,7 @@ var NotificationCenterContent = React77.forwardRef(
4374
4411
  {
4375
4412
  type: "button",
4376
4413
  onClick: onMarkAllRead,
4377
- className: "text-label-md font-medium text-primary outline-none hover:underline focus-visible:underline",
4414
+ className: "text-label-md font-medium text-link outline-none hover:underline focus-visible:underline",
4378
4415
  children: "Mark all read"
4379
4416
  }
4380
4417
  )
@@ -4406,7 +4443,7 @@ var NotificationItem = React77.forwardRef(
4406
4443
  ),
4407
4444
  ...props,
4408
4445
  children: [
4409
- /* @__PURE__ */ jsx83("span", { className: cn("mt-1.5 size-2 shrink-0 rounded-full", unread ? "bg-primary" : "bg-transparent") }),
4446
+ /* @__PURE__ */ jsx83("span", { className: cn("mt-1.5 size-2 shrink-0 rounded-full", unread ? "bg-action" : "bg-transparent") }),
4410
4447
  /* @__PURE__ */ jsxs48("div", { className: "min-w-0 flex-1", children: [
4411
4448
  /* @__PURE__ */ jsx83("p", { className: cn("truncate text-body-sm", unread ? "font-medium text-foreground" : "text-muted-foreground"), children: title }),
4412
4449
  description && /* @__PURE__ */ jsx83("p", { className: "truncate text-body-sm text-muted-foreground", children: description }),
@@ -4627,6 +4664,12 @@ var MultiSelect = React79.forwardRef(
4627
4664
  const current = value ?? internal;
4628
4665
  const [open, setOpen] = React79.useState(false);
4629
4666
  const [query, setQuery] = React79.useState("");
4667
+ const anchorRef = React79.useRef(null);
4668
+ const setRefs = (node) => {
4669
+ anchorRef.current = node;
4670
+ if (typeof ref === "function") ref(node);
4671
+ else if (ref) ref.current = node;
4672
+ };
4630
4673
  const set = (next) => {
4631
4674
  setInternal(next);
4632
4675
  onValueChange?.(next);
@@ -4641,7 +4684,7 @@ var MultiSelect = React79.forwardRef(
4641
4684
  /* @__PURE__ */ jsx85(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs50(
4642
4685
  "div",
4643
4686
  {
4644
- ref,
4687
+ ref: setRefs,
4645
4688
  role: "combobox",
4646
4689
  "aria-expanded": open,
4647
4690
  "aria-haspopup": "listbox",
@@ -4655,8 +4698,8 @@ var MultiSelect = React79.forwardRef(
4655
4698
  },
4656
4699
  className: cn(
4657
4700
  "flex min-h-11 w-full flex-wrap items-center gap-1.5 border border-input bg-background px-3 py-2 font-sans",
4658
- "outline-none focus-visible:border-primary focus-visible:shadow-focus",
4659
- "aria-expanded:border-primary aria-expanded:shadow-focus",
4701
+ "outline-none focus-visible:border-action focus-visible:shadow-focus",
4702
+ "aria-expanded:border-action aria-expanded:shadow-focus",
4660
4703
  className
4661
4704
  ),
4662
4705
  ...props,
@@ -4671,9 +4714,25 @@ var MultiSelect = React79.forwardRef(
4671
4714
  {
4672
4715
  align: "start",
4673
4716
  className: "w-[var(--radix-popover-trigger-width)] p-0",
4674
- onOpenAutoFocus: (e) => e.preventDefault(),
4717
+ onCloseAutoFocus: (e) => {
4718
+ e.preventDefault();
4719
+ anchorRef.current?.focus();
4720
+ },
4675
4721
  children: /* @__PURE__ */ jsxs50(Command, { shouldFilter: !creatable, children: [
4676
- /* @__PURE__ */ jsx85(CommandInput, { placeholder: "Search\u2026", value: query, onValueChange: setQuery }),
4722
+ /* @__PURE__ */ jsx85(
4723
+ CommandInput,
4724
+ {
4725
+ placeholder: "Search\u2026",
4726
+ value: query,
4727
+ onValueChange: setQuery,
4728
+ onKeyDown: (e) => {
4729
+ if (e.key === "Backspace" && query === "" && current.length > 0) {
4730
+ e.preventDefault();
4731
+ remove(current[current.length - 1]);
4732
+ }
4733
+ }
4734
+ }
4735
+ ),
4677
4736
  /* @__PURE__ */ jsxs50(CommandList, { children: [
4678
4737
  /* @__PURE__ */ jsx85(CommandEmpty, { children: canCreate ? /* @__PURE__ */ jsxs50(
4679
4738
  "button",
@@ -4719,7 +4778,7 @@ var MessageBubble = React80.forwardRef(
4719
4778
  {
4720
4779
  className: cn(
4721
4780
  "min-w-0 rounded-2xl px-3.5 py-2 text-body-sm",
4722
- sent ? "bg-primary text-primary-foreground" : "bg-muted text-foreground",
4781
+ sent ? "bg-action text-action-foreground" : "bg-muted text-foreground",
4723
4782
  sent && grouped && "rounded-tr-md",
4724
4783
  !sent && grouped && "rounded-tl-md"
4725
4784
  ),
@@ -4728,7 +4787,7 @@ var MessageBubble = React80.forwardRef(
4728
4787
  ),
4729
4788
  (timestamp || sent && status) && /* @__PURE__ */ jsxs51("div", { className: "flex items-center gap-1 px-1 text-label-sm text-muted-foreground", children: [
4730
4789
  timestamp,
4731
- sent && status && /* @__PURE__ */ jsx86("span", { className: cn(status === "read" && "text-primary"), children: status === "sent" ? /* @__PURE__ */ jsx86(Check9, { className: "size-3.5" }) : /* @__PURE__ */ jsx86(CheckCheck, { className: "size-3.5" }) })
4790
+ sent && status && /* @__PURE__ */ jsx86("span", { className: cn(status === "read" && "text-action"), children: status === "sent" ? /* @__PURE__ */ jsx86(Check9, { className: "size-3.5" }) : /* @__PURE__ */ jsx86(CheckCheck, { className: "size-3.5" }) })
4732
4791
  ] })
4733
4792
  ] })
4734
4793
  ] });
@@ -4748,7 +4807,7 @@ var TypingIndicator = React80.forwardRef(
4748
4807
  "span",
4749
4808
  {
4750
4809
  "aria-hidden": true,
4751
- className: "size-1.5 animate-typing-dot rounded-full bg-muted-foreground",
4810
+ className: "size-1.5 animate-typing-dot motion-reduce:animate-none motion-reduce:opacity-70 rounded-full bg-muted-foreground",
4752
4811
  style: { animationDelay: `${i * 150}ms` }
4753
4812
  },
4754
4813
  i
@@ -4761,7 +4820,7 @@ TypingIndicator.displayName = "TypingIndicator";
4761
4820
  // src/components/tour.tsx
4762
4821
  import * as React81 from "react";
4763
4822
  import { createPortal } from "react-dom";
4764
- import { Fragment, jsx as jsx87, jsxs as jsxs52 } from "react/jsx-runtime";
4823
+ import { Fragment as Fragment2, jsx as jsx87, jsxs as jsxs52 } from "react/jsx-runtime";
4765
4824
  var SPOTLIGHT_PADDING = 8;
4766
4825
  var Tour = ({
4767
4826
  steps,
@@ -4778,6 +4837,36 @@ var Tour = ({
4778
4837
  const [rect, setRect] = React81.useState(null);
4779
4838
  const step = steps[stepIndex];
4780
4839
  React81.useEffect(() => setMounted(true), []);
4840
+ const titleId = React81.useId();
4841
+ const dialogRef = React81.useRef(null);
4842
+ const returnFocusRef = React81.useRef(null);
4843
+ React81.useEffect(() => {
4844
+ if (!open) return;
4845
+ returnFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
4846
+ return () => returnFocusRef.current?.focus();
4847
+ }, [open]);
4848
+ React81.useEffect(() => {
4849
+ if (open && mounted) dialogRef.current?.focus();
4850
+ }, [open, mounted, stepIndex]);
4851
+ const trapTab = (e) => {
4852
+ if (e.key !== "Tab") return;
4853
+ const dialog = e.currentTarget;
4854
+ const focusable = Array.from(dialog.querySelectorAll("button:not([disabled]), [href], input:not([disabled]), [tabindex]:not([tabindex='-1'])"));
4855
+ if (focusable.length === 0) {
4856
+ e.preventDefault();
4857
+ return;
4858
+ }
4859
+ const first = focusable[0];
4860
+ const last = focusable[focusable.length - 1];
4861
+ const active = document.activeElement;
4862
+ if (e.shiftKey && (active === first || active === dialog)) {
4863
+ e.preventDefault();
4864
+ last.focus();
4865
+ } else if (!e.shiftKey && active === last) {
4866
+ e.preventDefault();
4867
+ first.focus();
4868
+ }
4869
+ };
4781
4870
  React81.useEffect(() => {
4782
4871
  if (!open || !step) return;
4783
4872
  const update = () => {
@@ -4820,7 +4909,7 @@ var Tour = ({
4820
4909
  left: Math.min(Math.max(rect.left, 16), window.innerWidth - 336)
4821
4910
  } : { top: "50%", left: "50%", transform: "translate(-50%, -50%)" };
4822
4911
  return createPortal(
4823
- /* @__PURE__ */ jsxs52(Fragment, { children: [
4912
+ /* @__PURE__ */ jsxs52(Fragment2, { children: [
4824
4913
  /* @__PURE__ */ jsx87(
4825
4914
  "div",
4826
4915
  {
@@ -4832,12 +4921,16 @@ var Tour = ({
4832
4921
  /* @__PURE__ */ jsxs52(
4833
4922
  "div",
4834
4923
  {
4924
+ ref: dialogRef,
4835
4925
  role: "dialog",
4836
4926
  "aria-modal": "true",
4837
- className: "fixed z-overlay w-80 rounded-lg border border-border bg-popover p-4 font-sans text-popover-foreground shadow-lg transition-all duration-fast",
4927
+ "aria-labelledby": titleId,
4928
+ tabIndex: -1,
4929
+ onKeyDown: trapTab,
4930
+ className: "fixed z-overlay w-80 rounded-lg border border-border bg-popover p-4 font-sans text-popover-foreground shadow-lg outline-none transition-all duration-fast",
4838
4931
  style: cardStyle,
4839
4932
  children: [
4840
- /* @__PURE__ */ jsx87("p", { className: "text-title-sm font-medium text-foreground", children: step.title }),
4933
+ /* @__PURE__ */ jsx87("p", { id: titleId, className: "text-title-sm font-medium text-foreground", children: step.title }),
4841
4934
  /* @__PURE__ */ jsx87("div", { className: "mt-1.5 text-body-sm text-muted-foreground", children: step.content }),
4842
4935
  /* @__PURE__ */ jsxs52("div", { className: "mt-4 flex items-center justify-between", children: [
4843
4936
  /* @__PURE__ */ jsxs52("span", { className: "text-label-sm text-muted-foreground", children: [
@@ -4847,7 +4940,7 @@ var Tour = ({
4847
4940
  ] }),
4848
4941
  /* @__PURE__ */ jsxs52("div", { className: "flex items-center gap-2", children: [
4849
4942
  !isFirst && /* @__PURE__ */ jsx87(Button, { variant: "Ghost", size: "sm", onClick: () => onStepIndexChange(stepIndex - 1), children: backLabel }),
4850
- !isLast ? /* @__PURE__ */ jsxs52(Fragment, { children: [
4943
+ !isLast ? /* @__PURE__ */ jsxs52(Fragment2, { children: [
4851
4944
  /* @__PURE__ */ jsx87(Button, { variant: "Link", size: "sm", onClick: () => onOpenChange(false), children: skipLabel }),
4852
4945
  /* @__PURE__ */ jsx87(Button, { size: "sm", onClick: () => onStepIndexChange(stepIndex + 1), children: nextLabel })
4853
4946
  ] }) : /* @__PURE__ */ jsx87(Button, { size: "sm", onClick: () => onOpenChange(false), children: doneLabel })
@@ -4899,7 +4992,8 @@ function VirtualList({
4899
4992
  {
4900
4993
  ref: containerRef,
4901
4994
  role: "list",
4902
- className: cn("overflow-y-auto font-sans", className),
4995
+ tabIndex: 0,
4996
+ className: cn("overflow-y-auto font-sans outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring", className),
4903
4997
  style: { height, ...style },
4904
4998
  onScroll: (e) => {
4905
4999
  onScroll?.(e);
@@ -4924,7 +5018,7 @@ function VirtualList({
4924
5018
 
4925
5019
  // src/components/data-grid.tsx
4926
5020
  import * as React83 from "react";
4927
- import { jsx as jsx89, jsxs as jsxs53 } from "react/jsx-runtime";
5021
+ import { Fragment as Fragment3, jsx as jsx89, jsxs as jsxs53 } from "react/jsx-runtime";
4928
5022
  var DEFAULT_WIDTH = 160;
4929
5023
  var DEFAULT_MIN_WIDTH = 60;
4930
5024
  var DEFAULT_ROW_HEIGHT = 40;
@@ -5032,121 +5126,273 @@ function DataGrid({
5032
5126
  window.addEventListener("pointermove", handleMove);
5033
5127
  window.addEventListener("pointerup", handleUp);
5034
5128
  }
5035
- function commitEdit(column, row, rowIndex, value) {
5036
- column.onCellEdit?.(row, rowIndex, value);
5129
+ const restoreFocusRef = React83.useRef(null);
5130
+ React83.useEffect(() => {
5131
+ const target = restoreFocusRef.current;
5132
+ if (editing || !target) return;
5133
+ restoreFocusRef.current = null;
5134
+ containerRef.current?.querySelector(`[data-cell="${target.rowIndex}:${target.columnId}"]`)?.focus();
5135
+ }, [editing]);
5136
+ function endEdit(restoreFocus) {
5137
+ if (restoreFocus && editing) restoreFocusRef.current = { rowIndex: editing.rowIndex, columnId: editing.columnId };
5037
5138
  setEditing(null);
5038
5139
  }
5039
- return /* @__PURE__ */ jsx89(
5040
- "div",
5041
- {
5042
- ref: containerRef,
5043
- role: "grid",
5044
- className: cn("relative overflow-auto rounded-md border font-sans text-sm", className),
5045
- style: { height },
5046
- onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
5047
- children: /* @__PURE__ */ jsxs53("div", { style: { width: totalWidth, minWidth: "100%" }, children: [
5048
- /* @__PURE__ */ jsx89("div", { role: "row", className: "sticky top-0 z-[2] flex border-b bg-background", children: renderedColumns.map((column) => {
5049
- const width = widths[column.id] ?? column.width ?? DEFAULT_WIDTH;
5050
- const pinnedStyle = column.pinned === "left" ? { position: "sticky", left: leftOffsets[column.id], zIndex: 3 } : column.pinned === "right" ? { position: "sticky", right: rightOffsets[column.id], zIndex: 3 } : {};
5051
- const isSorted = sort?.columnId === column.id;
5052
- return /* @__PURE__ */ jsxs53(
5053
- "div",
5054
- {
5055
- role: "columnheader",
5056
- ...column.sortable ? { "aria-sort": isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none" } : {},
5057
- draggable: !column.pinned,
5058
- onDragStart: () => {
5059
- dragIdRef.current = column.id;
5060
- },
5061
- onDragOver: (e) => {
5062
- if (!column.pinned) e.preventDefault();
5063
- },
5064
- onDrop: (e) => {
5065
- e.preventDefault();
5066
- const draggedId = dragIdRef.current;
5067
- dragIdRef.current = null;
5068
- if (!draggedId || draggedId === column.id) return;
5069
- setOrder((prev) => {
5070
- const next = prev.filter((id) => id !== draggedId);
5071
- const targetIndex = next.indexOf(column.id);
5072
- next.splice(targetIndex, 0, draggedId);
5073
- return next;
5074
- });
5140
+ function commitEdit(column, row, rowIndex, value, restoreFocus = false) {
5141
+ column.onCellEdit?.(row, rowIndex, value);
5142
+ endEdit(restoreFocus);
5143
+ }
5144
+ const HEADER_HEIGHT = 40;
5145
+ const [active, setActive] = React83.useState({ row: -1, columnId: columns[0]?.id ?? "" });
5146
+ const pendingFocusRef = React83.useRef(null);
5147
+ const [announcement, setAnnouncement] = React83.useState("");
5148
+ const rowCount = sortedData.length;
5149
+ const colIds = renderedColumns.map((c) => c.id);
5150
+ const activeCol = colIds.includes(active.columnId) ? active.columnId : colIds[0] ?? "";
5151
+ const activeRow = Math.min(active.row, rowCount - 1);
5152
+ const activeRendered = activeRow < 0 || activeRow >= startIndex && activeRow < endIndex;
5153
+ const tabStop = { row: activeRendered ? activeRow : -1, columnId: activeCol };
5154
+ const pageRows = Math.max(1, Math.floor((viewportHeight - HEADER_HEIGHT) / rowHeight) - 1);
5155
+ const labelOf = (c) => typeof c.header === "string" ? c.header : c.id;
5156
+ function ensureRowVisible(row) {
5157
+ const el = containerRef.current;
5158
+ if (!el) return;
5159
+ if (row < 0) {
5160
+ if (scrollTop !== 0) {
5161
+ el.scrollTop = 0;
5162
+ setScrollTop(0);
5163
+ }
5164
+ return;
5165
+ }
5166
+ const top = HEADER_HEIGHT + row * rowHeight;
5167
+ const bottom = top + rowHeight;
5168
+ let next = scrollTop;
5169
+ if (top < scrollTop + HEADER_HEIGHT) next = row * rowHeight;
5170
+ else if (bottom > scrollTop + viewportHeight) next = bottom - viewportHeight;
5171
+ if (next !== scrollTop) {
5172
+ el.scrollTop = next;
5173
+ setScrollTop(next);
5174
+ }
5175
+ }
5176
+ function moveTo(row, columnId) {
5177
+ const r = Math.max(-1, Math.min(row, rowCount - 1));
5178
+ ensureRowVisible(r);
5179
+ pendingFocusRef.current = { row: r, columnId };
5180
+ setActive({ row: r, columnId });
5181
+ }
5182
+ React83.useEffect(() => {
5183
+ const p = pendingFocusRef.current;
5184
+ if (!p) return;
5185
+ const selector = p.row < 0 ? `[data-header="${p.columnId}"]` : `[data-cell="${p.row}:${p.columnId}"]`;
5186
+ const el = containerRef.current?.querySelector(selector);
5187
+ if (el) {
5188
+ pendingFocusRef.current = null;
5189
+ el.focus();
5190
+ }
5191
+ });
5192
+ function moveColumn(column, dir) {
5193
+ if (column.pinned) return;
5194
+ const ids = unpinnedOrdered.map((c) => c.id);
5195
+ const from = ids.indexOf(column.id);
5196
+ const to = from + dir;
5197
+ if (to < 0 || to >= ids.length) {
5198
+ setAnnouncement(`${labelOf(column)} is already the ${dir < 0 ? "first" : "last"} movable column`);
5199
+ return;
5200
+ }
5201
+ const targetId = ids[to];
5202
+ setOrder((prev) => {
5203
+ const next = prev.filter((id) => id !== column.id);
5204
+ next.splice(next.indexOf(targetId) + (dir > 0 ? 1 : 0), 0, column.id);
5205
+ return next;
5206
+ });
5207
+ pendingFocusRef.current = { row: -1, columnId: column.id };
5208
+ setAnnouncement(`${labelOf(column)} moved to position ${leftPinned.length + to + 1} of ${colIds.length}`);
5209
+ }
5210
+ function resizeColumn(column, delta) {
5211
+ const current = widths[column.id] ?? column.width ?? DEFAULT_WIDTH;
5212
+ const next = Math.max(column.minWidth ?? DEFAULT_MIN_WIDTH, current + delta);
5213
+ setWidths((prev) => ({ ...prev, [column.id]: next }));
5214
+ setAnnouncement(`${labelOf(column)} column width ${next} pixels`);
5215
+ }
5216
+ function onNavKeyDown(e, row, column) {
5217
+ if (e.target !== e.currentTarget) return;
5218
+ const rtl = getComputedStyle(e.currentTarget).direction === "rtl";
5219
+ const idx = colIds.indexOf(column.id);
5220
+ const horizontal = e.key === "ArrowRight" ? rtl ? -1 : 1 : e.key === "ArrowLeft" ? rtl ? 1 : -1 : 0;
5221
+ if (row < 0 && horizontal !== 0 && (e.altKey || e.shiftKey)) {
5222
+ e.preventDefault();
5223
+ if (e.altKey) moveColumn(column, horizontal);
5224
+ else resizeColumn(column, horizontal * 10);
5225
+ return;
5226
+ }
5227
+ const go = (r, i) => {
5228
+ e.preventDefault();
5229
+ moveTo(r, colIds[Math.max(0, Math.min(i, colIds.length - 1))]);
5230
+ };
5231
+ switch (e.key) {
5232
+ case "ArrowRight":
5233
+ case "ArrowLeft":
5234
+ return go(row, idx + horizontal);
5235
+ case "ArrowDown":
5236
+ return go(row + 1, idx);
5237
+ case "ArrowUp":
5238
+ return go(row - 1, idx);
5239
+ case "Home":
5240
+ return go(e.ctrlKey ? -1 : row, 0);
5241
+ case "End":
5242
+ return go(e.ctrlKey ? rowCount - 1 : row, colIds.length - 1);
5243
+ case "PageDown":
5244
+ return go(row + pageRows, idx);
5245
+ case "PageUp":
5246
+ return go(Math.max(row - pageRows, row >= 0 ? 0 : -1), idx);
5247
+ case "Enter":
5248
+ case " ":
5249
+ if (row < 0 && column.sortable) {
5250
+ e.preventDefault();
5251
+ toggleSort(column.id);
5252
+ } else if (row >= 0 && column.editable && e.key === "Enter") {
5253
+ e.preventDefault();
5254
+ setEditing({ rowIndex: row, columnId: column.id });
5255
+ }
5256
+ return;
5257
+ case "F2":
5258
+ if (row >= 0 && column.editable) {
5259
+ e.preventDefault();
5260
+ setEditing({ rowIndex: row, columnId: column.id });
5261
+ }
5262
+ return;
5263
+ }
5264
+ }
5265
+ return /* @__PURE__ */ jsxs53(Fragment3, { children: [
5266
+ /* @__PURE__ */ jsx89(
5267
+ "div",
5268
+ {
5269
+ ref: containerRef,
5270
+ role: "grid",
5271
+ "aria-rowcount": rowCount + 1,
5272
+ "aria-colcount": colIds.length,
5273
+ className: cn("relative overflow-auto rounded-md border font-sans text-sm", className),
5274
+ style: { height },
5275
+ onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
5276
+ children: /* @__PURE__ */ jsxs53("div", { style: { width: totalWidth, minWidth: "100%" }, children: [
5277
+ /* @__PURE__ */ jsx89("div", { role: "row", "aria-rowindex": 1, className: "sticky top-0 z-[2] flex border-b bg-background", children: renderedColumns.map((column, colIdx) => {
5278
+ const width = widths[column.id] ?? column.width ?? DEFAULT_WIDTH;
5279
+ const pinnedStyle = column.pinned === "left" ? { position: "sticky", left: leftOffsets[column.id], zIndex: 3 } : column.pinned === "right" ? { position: "sticky", right: rightOffsets[column.id], zIndex: 3 } : {};
5280
+ const isSorted = sort?.columnId === column.id;
5281
+ return /* @__PURE__ */ jsxs53(
5282
+ "div",
5283
+ {
5284
+ role: "columnheader",
5285
+ "data-header": column.id,
5286
+ "aria-colindex": colIdx + 1,
5287
+ "aria-keyshortcuts": `Shift+ArrowLeft Shift+ArrowRight${column.pinned ? "" : " Alt+ArrowLeft Alt+ArrowRight"}`,
5288
+ ...column.sortable ? { "aria-sort": isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none" } : {},
5289
+ draggable: !column.pinned,
5290
+ onDragStart: () => {
5291
+ dragIdRef.current = column.id;
5292
+ },
5293
+ onDragOver: (e) => {
5294
+ if (!column.pinned) e.preventDefault();
5295
+ },
5296
+ onDrop: (e) => {
5297
+ e.preventDefault();
5298
+ const draggedId = dragIdRef.current;
5299
+ dragIdRef.current = null;
5300
+ if (!draggedId || draggedId === column.id) return;
5301
+ setOrder((prev) => {
5302
+ const next = prev.filter((id) => id !== draggedId);
5303
+ const targetIndex = next.indexOf(column.id);
5304
+ next.splice(targetIndex, 0, draggedId);
5305
+ return next;
5306
+ });
5307
+ },
5308
+ onClick: () => column.sortable && toggleSort(column.id),
5309
+ tabIndex: tabStop.row === -1 && tabStop.columnId === column.id ? 0 : -1,
5310
+ onFocus: () => setActive({ row: -1, columnId: column.id }),
5311
+ onKeyDown: (e) => onNavKeyDown(e, -1, column),
5312
+ className: cn(
5313
+ "relative flex h-10 shrink-0 select-none items-center gap-1 px-2 font-medium text-muted-foreground outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring",
5314
+ column.sortable && "cursor-pointer hover:text-foreground",
5315
+ column.pinned && "bg-background"
5316
+ ),
5317
+ style: { width, ...pinnedStyle },
5318
+ children: [
5319
+ /* @__PURE__ */ jsx89("span", { className: "truncate", children: column.header }),
5320
+ column.sortable && isSorted && /* @__PURE__ */ jsx89("span", { "aria-hidden": "true", className: "text-xs", children: sort.direction === "asc" ? "\u25B2" : "\u25BC" }),
5321
+ /* @__PURE__ */ jsx89(
5322
+ "div",
5323
+ {
5324
+ onPointerDown: (e) => {
5325
+ e.stopPropagation();
5326
+ beginResize(column.id, column.minWidth ?? DEFAULT_MIN_WIDTH, e.clientX, width);
5327
+ },
5328
+ className: "absolute right-0 top-0 h-full w-1 touch-none cursor-col-resize hover:bg-action/50"
5329
+ }
5330
+ )
5331
+ ]
5075
5332
  },
5076
- onClick: () => column.sortable && toggleSort(column.id),
5077
- className: cn(
5078
- "relative flex h-10 shrink-0 select-none items-center gap-1 px-2 font-medium text-muted-foreground",
5079
- column.sortable && "cursor-pointer hover:text-foreground",
5080
- column.pinned && "bg-background"
5081
- ),
5082
- style: { width, ...pinnedStyle },
5083
- children: [
5084
- /* @__PURE__ */ jsx89("span", { className: "truncate", children: column.header }),
5085
- column.sortable && isSorted && /* @__PURE__ */ jsx89("span", { "aria-hidden": "true", className: "text-xs", children: sort.direction === "asc" ? "\u25B2" : "\u25BC" }),
5086
- /* @__PURE__ */ jsx89(
5087
- "div",
5088
- {
5089
- onPointerDown: (e) => {
5090
- e.stopPropagation();
5091
- beginResize(column.id, column.minWidth ?? DEFAULT_MIN_WIDTH, e.clientX, width);
5333
+ column.id
5334
+ );
5335
+ }) }),
5336
+ /* @__PURE__ */ jsx89("div", { style: { height: totalHeight, position: "relative" }, children: visibleRows.map((row, i) => {
5337
+ const rowIndex = startIndex + i;
5338
+ return /* @__PURE__ */ jsx89(
5339
+ "div",
5340
+ {
5341
+ role: "row",
5342
+ "aria-rowindex": rowIndex + 2,
5343
+ className: "absolute flex w-full border-b hover:bg-muted/50",
5344
+ style: { top: rowIndex * rowHeight, height: rowHeight },
5345
+ children: renderedColumns.map((column, colIdx) => {
5346
+ const width = widths[column.id] ?? column.width ?? DEFAULT_WIDTH;
5347
+ const pinnedStyle = column.pinned === "left" ? { position: "sticky", left: leftOffsets[column.id], zIndex: 1 } : column.pinned === "right" ? { position: "sticky", right: rightOffsets[column.id], zIndex: 1 } : {};
5348
+ const isEditing = editing?.rowIndex === rowIndex && editing.columnId === column.id;
5349
+ return /* @__PURE__ */ jsx89(
5350
+ "div",
5351
+ {
5352
+ role: "gridcell",
5353
+ "aria-colindex": colIdx + 1,
5354
+ "data-cell": `${rowIndex}:${column.id}`,
5355
+ onDoubleClick: () => column.editable && setEditing({ rowIndex, columnId: column.id }),
5356
+ tabIndex: tabStop.row === rowIndex && tabStop.columnId === column.id ? 0 : -1,
5357
+ onFocus: () => setActive({ row: rowIndex, columnId: column.id }),
5358
+ onKeyDown: (e) => onNavKeyDown(e, rowIndex, column),
5359
+ className: cn(
5360
+ "flex shrink-0 items-center px-2 outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring",
5361
+ column.pinned && "bg-background"
5362
+ ),
5363
+ style: { width, ...pinnedStyle },
5364
+ children: isEditing ? /* @__PURE__ */ jsx89(
5365
+ "input",
5366
+ {
5367
+ autoFocus: true,
5368
+ defaultValue: column.value ? String(column.value(row)) : "",
5369
+ className: "h-7 w-full rounded-sm border-0 bg-transparent px-1 text-sm outline-none ring-1 ring-inset ring-ring",
5370
+ onKeyDown: (e) => {
5371
+ if (e.key === "Enter") commitEdit(column, row, rowIndex, e.currentTarget.value, true);
5372
+ else if (e.key === "Escape") endEdit(true);
5373
+ },
5374
+ onBlur: (e) => commitEdit(column, row, rowIndex, e.currentTarget.value)
5375
+ }
5376
+ ) : /* @__PURE__ */ jsx89("span", { className: "truncate", children: column.cell(row, rowIndex) })
5092
5377
  },
5093
- className: "absolute right-0 top-0 h-full w-1 touch-none cursor-col-resize hover:bg-primary/50"
5094
- }
5095
- )
5096
- ]
5097
- },
5098
- column.id
5099
- );
5100
- }) }),
5101
- /* @__PURE__ */ jsx89("div", { style: { height: totalHeight, position: "relative" }, children: visibleRows.map((row, i) => {
5102
- const rowIndex = startIndex + i;
5103
- return /* @__PURE__ */ jsx89(
5104
- "div",
5105
- {
5106
- role: "row",
5107
- className: "absolute flex w-full border-b hover:bg-muted/50",
5108
- style: { top: rowIndex * rowHeight, height: rowHeight },
5109
- children: renderedColumns.map((column) => {
5110
- const width = widths[column.id] ?? column.width ?? DEFAULT_WIDTH;
5111
- const pinnedStyle = column.pinned === "left" ? { position: "sticky", left: leftOffsets[column.id], zIndex: 1 } : column.pinned === "right" ? { position: "sticky", right: rightOffsets[column.id], zIndex: 1 } : {};
5112
- const isEditing = editing?.rowIndex === rowIndex && editing.columnId === column.id;
5113
- return /* @__PURE__ */ jsx89(
5114
- "div",
5115
- {
5116
- role: "gridcell",
5117
- onDoubleClick: () => column.editable && setEditing({ rowIndex, columnId: column.id }),
5118
- className: cn("flex shrink-0 items-center px-2", column.pinned && "bg-background"),
5119
- style: { width, ...pinnedStyle },
5120
- children: isEditing ? /* @__PURE__ */ jsx89(
5121
- "input",
5122
- {
5123
- autoFocus: true,
5124
- defaultValue: column.value ? String(column.value(row)) : "",
5125
- className: "h-7 w-full rounded-sm border-0 bg-transparent px-1 text-sm outline-none ring-1 ring-inset ring-ring",
5126
- onKeyDown: (e) => {
5127
- if (e.key === "Enter") commitEdit(column, row, rowIndex, e.currentTarget.value);
5128
- else if (e.key === "Escape") setEditing(null);
5129
- },
5130
- onBlur: (e) => commitEdit(column, row, rowIndex, e.currentTarget.value)
5131
- }
5132
- ) : /* @__PURE__ */ jsx89("span", { className: "truncate", children: column.cell(row, rowIndex) })
5133
- },
5134
- column.id
5135
- );
5136
- })
5137
- },
5138
- getRowId ? getRowId(row, rowIndex) : rowIndex
5139
- );
5140
- }) })
5141
- ] })
5142
- }
5143
- );
5378
+ column.id
5379
+ );
5380
+ })
5381
+ },
5382
+ getRowId ? getRowId(row, rowIndex) : rowIndex
5383
+ );
5384
+ }) })
5385
+ ] })
5386
+ }
5387
+ ),
5388
+ /* @__PURE__ */ jsx89("div", { role: "status", "aria-live": "polite", className: "sr-only", children: announcement })
5389
+ ] });
5144
5390
  }
5145
5391
 
5146
5392
  // src/components/json-viewer.tsx
5147
5393
  import * as React84 from "react";
5148
5394
  import { Check as Check10, ChevronRight as ChevronRight8, Copy as Copy2 } from "lucide-react";
5149
- import { Fragment as Fragment2, jsx as jsx90, jsxs as jsxs54 } from "react/jsx-runtime";
5395
+ import { Fragment as Fragment4, jsx as jsx90, jsxs as jsxs54 } from "react/jsx-runtime";
5150
5396
  var JsonViewer = React84.forwardRef(
5151
5397
  ({ data, expandDepth = 1, hideCopy, className, ...props }, ref) => {
5152
5398
  const [copied, setCopied] = React84.useState(false);
@@ -5248,8 +5494,8 @@ function JsonNode({
5248
5494
  !expanded && !isLast && /* @__PURE__ */ jsx90("span", { className: "text-muted-foreground", children: "," })
5249
5495
  ] })
5250
5496
  ] }),
5251
- expanded && /* @__PURE__ */ jsxs54(Fragment2, { children: [
5252
- entries.map(([key, val], i) => /* @__PURE__ */ jsx90(
5497
+ expanded && /* @__PURE__ */ jsxs54(Fragment4, { children: [
5498
+ /* @__PURE__ */ jsx90("div", { role: "group", children: entries.map(([key, val], i) => /* @__PURE__ */ jsx90(
5253
5499
  JsonNode,
5254
5500
  {
5255
5501
  name: isArray ? void 0 : key,
@@ -5259,7 +5505,7 @@ function JsonNode({
5259
5505
  isLast: i === entries.length - 1
5260
5506
  },
5261
5507
  key
5262
- )),
5508
+ )) }),
5263
5509
  /* @__PURE__ */ jsxs54("div", { style: { paddingLeft: depth * 16 }, children: [
5264
5510
  /* @__PURE__ */ jsx90("span", { children: closeBracket }),
5265
5511
  !isLast && /* @__PURE__ */ jsx90("span", { className: "text-muted-foreground", children: "," })
@@ -5330,11 +5576,12 @@ function UnifiedDiff({ ops }) {
5330
5576
  role: "row",
5331
5577
  className: cn("flex", op.type === "add" && "bg-success/10", op.type === "remove" && "bg-destructive/10"),
5332
5578
  children: [
5333
- /* @__PURE__ */ jsx91("span", { className: "w-9 shrink-0 select-none border-r px-1.5 text-right text-muted-foreground", children: op.type !== "add" ? op.oldLine : "" }),
5334
- /* @__PURE__ */ jsx91("span", { className: "w-9 shrink-0 select-none border-r px-1.5 text-right text-muted-foreground", children: op.type !== "remove" ? op.newLine : "" }),
5579
+ /* @__PURE__ */ jsx91("span", { role: "cell", className: "w-9 shrink-0 select-none border-r px-1.5 text-right text-muted-foreground", children: op.type !== "add" ? op.oldLine : "" }),
5580
+ /* @__PURE__ */ jsx91("span", { role: "cell", className: "w-9 shrink-0 select-none border-r px-1.5 text-right text-muted-foreground", children: op.type !== "remove" ? op.newLine : "" }),
5335
5581
  /* @__PURE__ */ jsx91(
5336
5582
  "span",
5337
5583
  {
5584
+ role: "cell",
5338
5585
  className: cn(
5339
5586
  "w-4 shrink-0 select-none text-center",
5340
5587
  op.type === "add" && "text-success",
@@ -5343,7 +5590,7 @@ function UnifiedDiff({ ops }) {
5343
5590
  children: op.type === "add" ? "+" : op.type === "remove" ? "\u2212" : ""
5344
5591
  }
5345
5592
  ),
5346
- /* @__PURE__ */ jsx91("span", { className: "min-w-0 flex-1 whitespace-pre px-1", children: op.text })
5593
+ /* @__PURE__ */ jsx91("span", { role: "cell", className: "min-w-0 flex-1 whitespace-pre px-1", children: op.text })
5347
5594
  ]
5348
5595
  },
5349
5596
  i
@@ -5351,16 +5598,16 @@ function UnifiedDiff({ ops }) {
5351
5598
  }
5352
5599
  function SplitDiff({ ops, oldLabel, newLabel }) {
5353
5600
  return /* @__PURE__ */ jsxs55("div", { role: "table", children: [
5354
- /* @__PURE__ */ jsxs55("div", { className: "flex border-b bg-muted/40 text-muted-foreground", children: [
5355
- /* @__PURE__ */ jsx91("div", { className: "flex-1 px-2 py-1", children: oldLabel }),
5356
- /* @__PURE__ */ jsx91("div", { className: "flex-1 border-l px-2 py-1", children: newLabel })
5601
+ /* @__PURE__ */ jsxs55("div", { role: "row", className: "flex border-b bg-muted/40 text-muted-foreground", children: [
5602
+ /* @__PURE__ */ jsx91("div", { role: "columnheader", className: "flex-1 px-2 py-1", children: oldLabel }),
5603
+ /* @__PURE__ */ jsx91("div", { role: "columnheader", className: "flex-1 border-l px-2 py-1", children: newLabel })
5357
5604
  ] }),
5358
5605
  ops.map((op, i) => /* @__PURE__ */ jsxs55("div", { role: "row", className: "flex", children: [
5359
- /* @__PURE__ */ jsxs55("div", { className: cn("flex flex-1 items-start", op.type === "remove" && "bg-destructive/10"), children: [
5606
+ /* @__PURE__ */ jsxs55("div", { role: "cell", className: cn("flex flex-1 items-start", op.type === "remove" && "bg-destructive/10"), children: [
5360
5607
  /* @__PURE__ */ jsx91("span", { className: "w-9 shrink-0 select-none px-1.5 text-right text-muted-foreground", children: op.type !== "add" ? op.oldLine : "" }),
5361
5608
  /* @__PURE__ */ jsx91("span", { className: "min-w-0 flex-1 whitespace-pre px-1", children: op.type !== "add" ? op.text : "" })
5362
5609
  ] }),
5363
- /* @__PURE__ */ jsxs55("div", { className: cn("flex flex-1 items-start border-l", op.type === "add" && "bg-success/10"), children: [
5610
+ /* @__PURE__ */ jsxs55("div", { role: "cell", className: cn("flex flex-1 items-start border-l", op.type === "add" && "bg-success/10"), children: [
5364
5611
  /* @__PURE__ */ jsx91("span", { className: "w-9 shrink-0 select-none px-1.5 text-right text-muted-foreground", children: op.type !== "remove" ? op.newLine : "" }),
5365
5612
  /* @__PURE__ */ jsx91("span", { className: "min-w-0 flex-1 whitespace-pre px-1", children: op.type !== "remove" ? op.text : "" })
5366
5613
  ] })
@@ -5513,6 +5760,9 @@ var ColorPicker = React86.forwardRef(
5513
5760
  role: "slider",
5514
5761
  tabIndex: 0,
5515
5762
  "aria-label": "Saturation and value",
5763
+ "aria-valuemin": 0,
5764
+ "aria-valuemax": 100,
5765
+ "aria-valuenow": Math.round(s),
5516
5766
  "aria-valuetext": `saturation ${Math.round(s)}%, value ${Math.round(v)}%`,
5517
5767
  onPointerDown: handleSquarePointerDown,
5518
5768
  onPointerMove: handleSquarePointerMove,
@@ -5540,7 +5790,6 @@ var ColorPicker = React86.forwardRef(
5540
5790
  max: 360,
5541
5791
  step: 1,
5542
5792
  onValueChange: ([nh]) => commit(nh ?? h, s, v, a),
5543
- "aria-label": "Hue",
5544
5793
  className: "relative flex h-4 w-full touch-none select-none items-center",
5545
5794
  children: [
5546
5795
  /* @__PURE__ */ jsx92(
@@ -5552,7 +5801,7 @@ var ColorPicker = React86.forwardRef(
5552
5801
  }
5553
5802
  }
5554
5803
  ),
5555
- /* @__PURE__ */ jsx92(SliderPrimitive3.Thumb, { className: "block size-4 rounded-full border-2 border-white bg-background shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" })
5804
+ /* @__PURE__ */ jsx92(SliderPrimitive3.Thumb, { "aria-label": "Hue", className: "block size-4 rounded-full border-2 border-white bg-background shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" })
5556
5805
  ]
5557
5806
  }
5558
5807
  ),
@@ -5564,7 +5813,6 @@ var ColorPicker = React86.forwardRef(
5564
5813
  max: 100,
5565
5814
  step: 1,
5566
5815
  onValueChange: ([na]) => commit(h, s, v, (na ?? a * 100) / 100),
5567
- "aria-label": "Alpha",
5568
5816
  className: "relative flex h-4 w-full touch-none select-none items-center",
5569
5817
  children: [
5570
5818
  /* @__PURE__ */ jsx92(
@@ -5584,7 +5832,7 @@ var ColorPicker = React86.forwardRef(
5584
5832
  )
5585
5833
  }
5586
5834
  ),
5587
- /* @__PURE__ */ jsx92(SliderPrimitive3.Thumb, { className: "block size-4 rounded-full border-2 border-white bg-background shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" })
5835
+ /* @__PURE__ */ jsx92(SliderPrimitive3.Thumb, { "aria-label": "Alpha", className: "block size-4 rounded-full border-2 border-white bg-background shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" })
5588
5836
  ]
5589
5837
  }
5590
5838
  ),
@@ -5652,6 +5900,7 @@ function HexField({
5652
5900
  return /* @__PURE__ */ jsx92(
5653
5901
  Input,
5654
5902
  {
5903
+ "aria-label": "Hex color",
5655
5904
  value: draft,
5656
5905
  onChange: (e) => setDraft(e.target.value.replace(/[^0-9a-fA-F]/g, "").slice(0, alpha ? 8 : 6)),
5657
5906
  onBlur: commit,
@@ -5934,7 +6183,7 @@ function renderMarkdown(source) {
5934
6183
  return out.join("\n");
5935
6184
  }
5936
6185
  var MarkdownEditor = React88.forwardRef(
5937
- ({ value, onChange, placeholder, rows = 10, className, ...props }, ref) => {
6186
+ ({ value, onChange, placeholder, rows = 10, className, "aria-label": ariaLabel = "Markdown", ...props }, ref) => {
5938
6187
  const textareaRef = React88.useRef(null);
5939
6188
  const [showPreview, setShowPreview] = React88.useState(false);
5940
6189
  const pendingSelection = React88.useRef(null);
@@ -5990,13 +6239,14 @@ var MarkdownEditor = React88.forwardRef(
5990
6239
  onChange: (e) => onChange(e.target.value),
5991
6240
  placeholder,
5992
6241
  rows,
6242
+ "aria-label": ariaLabel,
5993
6243
  className: "resize-none rounded-none border-0 font-mono text-[13px] focus-visible:border-transparent focus-visible:shadow-none"
5994
6244
  }
5995
6245
  ),
5996
6246
  showPreview && /* @__PURE__ */ jsx94(
5997
6247
  "div",
5998
6248
  {
5999
- className: "overflow-auto p-3 text-sm [&_a]:text-primary [&_a]:underline [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground [&_code]:rounded-sm [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.9em] [&_h1]:text-xl [&_h1]:font-semibold [&_h2]:text-lg [&_h2]:font-semibold [&_h3]:font-semibold [&_li]:ml-5 [&_ol]:list-decimal [&_p]:mb-2 [&_pre]:overflow-auto [&_pre]:rounded-sm [&_pre]:bg-muted [&_pre]:p-2 [&_ul]:list-disc",
6249
+ className: "overflow-auto p-3 text-sm [&_a]:text-link [&_a]:underline [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground [&_code]:rounded-sm [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.9em] [&_h1]:text-xl [&_h1]:font-semibold [&_h2]:text-lg [&_h2]:font-semibold [&_h3]:font-semibold [&_li]:ml-5 [&_ol]:list-decimal [&_p]:mb-2 [&_pre]:overflow-auto [&_pre]:rounded-sm [&_pre]:bg-muted [&_pre]:p-2 [&_ul]:list-disc",
6000
6250
  dangerouslySetInnerHTML: { __html: renderMarkdown(value) }
6001
6251
  }
6002
6252
  )