@vaam-apps/ui 0.1.0 → 0.1.1

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 (283) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/components/data/code.d.ts +0 -1
  3. package/dist/components/data/code.js +0 -1
  4. package/dist/components/data/copy-button.d.ts +0 -1
  5. package/dist/components/data/copy-button.js +0 -1
  6. package/dist/components/data/detail-row.d.ts +0 -1
  7. package/dist/components/data/detail-row.js +0 -1
  8. package/dist/components/data/id-display.d.ts +0 -1
  9. package/dist/components/data/id-display.js +0 -1
  10. package/dist/components/data/masked-value.d.ts +0 -1
  11. package/dist/components/data/masked-value.js +0 -1
  12. package/dist/components/data/money.d.ts +0 -1
  13. package/dist/components/data/money.js +0 -1
  14. package/dist/components/data/phone-display.d.ts +0 -1
  15. package/dist/components/data/phone-display.js +0 -1
  16. package/dist/components/data/stat-tile.d.ts +0 -1
  17. package/dist/components/data/stat-tile.js +0 -1
  18. package/dist/components/data/timestamp-display.d.ts +0 -1
  19. package/dist/components/data/timestamp-display.js +0 -1
  20. package/dist/components/patterns/inline-banner.d.ts +0 -1
  21. package/dist/components/patterns/inline-banner.js +0 -1
  22. package/dist/components/patterns/inline-empty-state.d.ts +0 -1
  23. package/dist/components/patterns/inline-empty-state.js +0 -1
  24. package/dist/components/patterns/live-row.d.ts +0 -1
  25. package/dist/components/patterns/live-row.js +0 -1
  26. package/dist/components/patterns/payload-inspector.d.ts +0 -1
  27. package/dist/components/patterns/payload-inspector.js +0 -1
  28. package/dist/components/patterns/route-skeleton.d.ts +0 -1
  29. package/dist/components/patterns/route-skeleton.js +0 -1
  30. package/dist/components/patterns/screen-layout.d.ts +0 -1
  31. package/dist/components/patterns/screen-layout.js +0 -1
  32. package/dist/components/patterns/stale-write-banner.d.ts +0 -1
  33. package/dist/components/patterns/stale-write-banner.js +0 -1
  34. package/dist/components/patterns/state-timeline.d.ts +0 -1
  35. package/dist/components/patterns/state-timeline.js +0 -1
  36. package/dist/components/primitives/badge.d.ts +0 -1
  37. package/dist/components/primitives/badge.js +0 -1
  38. package/dist/components/primitives/button.d.ts +0 -1
  39. package/dist/components/primitives/button.js +0 -1
  40. package/dist/components/primitives/calendar.d.ts +0 -1
  41. package/dist/components/primitives/calendar.js +0 -1
  42. package/dist/components/primitives/card.d.ts +0 -1
  43. package/dist/components/primitives/card.js +0 -1
  44. package/dist/components/primitives/checkbox.d.ts +0 -1
  45. package/dist/components/primitives/checkbox.js +0 -1
  46. package/dist/components/primitives/chip-select.d.ts +0 -1
  47. package/dist/components/primitives/chip-select.js +0 -1
  48. package/dist/components/primitives/command-menu.d.ts +0 -1
  49. package/dist/components/primitives/command-menu.js +0 -1
  50. package/dist/components/primitives/confirm-dialog.d.ts +0 -1
  51. package/dist/components/primitives/confirm-dialog.js +0 -1
  52. package/dist/components/primitives/date-picker.d.ts +0 -1
  53. package/dist/components/primitives/date-picker.js +0 -1
  54. package/dist/components/primitives/dialog.d.ts +0 -1
  55. package/dist/components/primitives/dialog.js +0 -1
  56. package/dist/components/primitives/drawer.d.ts +0 -1
  57. package/dist/components/primitives/drawer.js +0 -1
  58. package/dist/components/primitives/dropdown-menu.d.ts +0 -1
  59. package/dist/components/primitives/dropdown-menu.js +0 -1
  60. package/dist/components/primitives/form-field.d.ts +0 -1
  61. package/dist/components/primitives/form-field.js +0 -1
  62. package/dist/components/primitives/inline-confirm.d.ts +0 -1
  63. package/dist/components/primitives/inline-confirm.js +0 -1
  64. package/dist/components/primitives/input.d.ts +0 -1
  65. package/dist/components/primitives/input.js +0 -1
  66. package/dist/components/primitives/label.d.ts +0 -1
  67. package/dist/components/primitives/label.js +0 -1
  68. package/dist/components/primitives/pagination.d.ts +0 -1
  69. package/dist/components/primitives/pagination.js +0 -1
  70. package/dist/components/primitives/popover.d.ts +0 -1
  71. package/dist/components/primitives/popover.js +0 -1
  72. package/dist/components/primitives/progress.d.ts +0 -1
  73. package/dist/components/primitives/progress.js +0 -1
  74. package/dist/components/primitives/radio-group.d.ts +0 -1
  75. package/dist/components/primitives/radio-group.js +0 -1
  76. package/dist/components/primitives/select.d.ts +0 -1
  77. package/dist/components/primitives/select.js +0 -1
  78. package/dist/components/primitives/separator.d.ts +0 -1
  79. package/dist/components/primitives/separator.js +0 -1
  80. package/dist/components/primitives/side-nav.d.ts +0 -1
  81. package/dist/components/primitives/side-nav.js +0 -1
  82. package/dist/components/primitives/skeleton.d.ts +0 -1
  83. package/dist/components/primitives/skeleton.js +0 -1
  84. package/dist/components/primitives/spinner.d.ts +0 -1
  85. package/dist/components/primitives/spinner.js +0 -1
  86. package/dist/components/primitives/switch.d.ts +0 -1
  87. package/dist/components/primitives/switch.js +0 -1
  88. package/dist/components/primitives/table.d.ts +0 -1
  89. package/dist/components/primitives/table.js +0 -1
  90. package/dist/components/primitives/tabs.d.ts +0 -1
  91. package/dist/components/primitives/tabs.js +0 -1
  92. package/dist/components/primitives/textarea.d.ts +0 -1
  93. package/dist/components/primitives/textarea.js +0 -1
  94. package/dist/components/primitives/toast.d.ts +0 -1
  95. package/dist/components/primitives/toast.js +0 -1
  96. package/dist/components/primitives/tooltip.d.ts +0 -1
  97. package/dist/components/primitives/tooltip.js +0 -1
  98. package/dist/components/status/state-chip.d.ts +0 -1
  99. package/dist/components/status/state-chip.js +0 -1
  100. package/dist/components/status/state-mark.d.ts +0 -1
  101. package/dist/components/status/state-mark.js +0 -1
  102. package/dist/components/status/status-pill.d.ts +0 -1
  103. package/dist/components/status/status-pill.js +0 -1
  104. package/dist/components/status/status-tokens.d.ts +0 -1
  105. package/dist/components/status/status-tokens.js +0 -1
  106. package/dist/index.d.ts +0 -1
  107. package/dist/index.js +0 -1
  108. package/dist/lib/cn.d.ts +0 -1
  109. package/dist/lib/cn.js +0 -1
  110. package/dist/lib/money.d.ts +0 -1
  111. package/dist/lib/money.js +0 -1
  112. package/dist/lib/omit-undefined.d.ts +0 -1
  113. package/dist/lib/omit-undefined.js +0 -1
  114. package/package.json +3 -7
  115. package/dist/components/data/code.d.ts.map +0 -1
  116. package/dist/components/data/code.js.map +0 -1
  117. package/dist/components/data/copy-button.d.ts.map +0 -1
  118. package/dist/components/data/copy-button.js.map +0 -1
  119. package/dist/components/data/detail-row.d.ts.map +0 -1
  120. package/dist/components/data/detail-row.js.map +0 -1
  121. package/dist/components/data/id-display.d.ts.map +0 -1
  122. package/dist/components/data/id-display.js.map +0 -1
  123. package/dist/components/data/masked-value.d.ts.map +0 -1
  124. package/dist/components/data/masked-value.js.map +0 -1
  125. package/dist/components/data/money.d.ts.map +0 -1
  126. package/dist/components/data/money.js.map +0 -1
  127. package/dist/components/data/phone-display.d.ts.map +0 -1
  128. package/dist/components/data/phone-display.js.map +0 -1
  129. package/dist/components/data/stat-tile.d.ts.map +0 -1
  130. package/dist/components/data/stat-tile.js.map +0 -1
  131. package/dist/components/data/timestamp-display.d.ts.map +0 -1
  132. package/dist/components/data/timestamp-display.js.map +0 -1
  133. package/dist/components/patterns/inline-banner.d.ts.map +0 -1
  134. package/dist/components/patterns/inline-banner.js.map +0 -1
  135. package/dist/components/patterns/inline-empty-state.d.ts.map +0 -1
  136. package/dist/components/patterns/inline-empty-state.js.map +0 -1
  137. package/dist/components/patterns/live-row.d.ts.map +0 -1
  138. package/dist/components/patterns/live-row.js.map +0 -1
  139. package/dist/components/patterns/payload-inspector.d.ts.map +0 -1
  140. package/dist/components/patterns/payload-inspector.js.map +0 -1
  141. package/dist/components/patterns/route-skeleton.d.ts.map +0 -1
  142. package/dist/components/patterns/route-skeleton.js.map +0 -1
  143. package/dist/components/patterns/screen-layout.d.ts.map +0 -1
  144. package/dist/components/patterns/screen-layout.js.map +0 -1
  145. package/dist/components/patterns/stale-write-banner.d.ts.map +0 -1
  146. package/dist/components/patterns/stale-write-banner.js.map +0 -1
  147. package/dist/components/patterns/state-timeline.d.ts.map +0 -1
  148. package/dist/components/patterns/state-timeline.js.map +0 -1
  149. package/dist/components/primitives/badge.d.ts.map +0 -1
  150. package/dist/components/primitives/badge.js.map +0 -1
  151. package/dist/components/primitives/button.d.ts.map +0 -1
  152. package/dist/components/primitives/button.js.map +0 -1
  153. package/dist/components/primitives/calendar.d.ts.map +0 -1
  154. package/dist/components/primitives/calendar.js.map +0 -1
  155. package/dist/components/primitives/card.d.ts.map +0 -1
  156. package/dist/components/primitives/card.js.map +0 -1
  157. package/dist/components/primitives/checkbox.d.ts.map +0 -1
  158. package/dist/components/primitives/checkbox.js.map +0 -1
  159. package/dist/components/primitives/chip-select.d.ts.map +0 -1
  160. package/dist/components/primitives/chip-select.js.map +0 -1
  161. package/dist/components/primitives/command-menu.d.ts.map +0 -1
  162. package/dist/components/primitives/command-menu.js.map +0 -1
  163. package/dist/components/primitives/confirm-dialog.d.ts.map +0 -1
  164. package/dist/components/primitives/confirm-dialog.js.map +0 -1
  165. package/dist/components/primitives/date-picker.d.ts.map +0 -1
  166. package/dist/components/primitives/date-picker.js.map +0 -1
  167. package/dist/components/primitives/dialog.d.ts.map +0 -1
  168. package/dist/components/primitives/dialog.js.map +0 -1
  169. package/dist/components/primitives/drawer.d.ts.map +0 -1
  170. package/dist/components/primitives/drawer.js.map +0 -1
  171. package/dist/components/primitives/dropdown-menu.d.ts.map +0 -1
  172. package/dist/components/primitives/dropdown-menu.js.map +0 -1
  173. package/dist/components/primitives/form-field.d.ts.map +0 -1
  174. package/dist/components/primitives/form-field.js.map +0 -1
  175. package/dist/components/primitives/inline-confirm.d.ts.map +0 -1
  176. package/dist/components/primitives/inline-confirm.js.map +0 -1
  177. package/dist/components/primitives/input.d.ts.map +0 -1
  178. package/dist/components/primitives/input.js.map +0 -1
  179. package/dist/components/primitives/label.d.ts.map +0 -1
  180. package/dist/components/primitives/label.js.map +0 -1
  181. package/dist/components/primitives/pagination.d.ts.map +0 -1
  182. package/dist/components/primitives/pagination.js.map +0 -1
  183. package/dist/components/primitives/popover.d.ts.map +0 -1
  184. package/dist/components/primitives/popover.js.map +0 -1
  185. package/dist/components/primitives/progress.d.ts.map +0 -1
  186. package/dist/components/primitives/progress.js.map +0 -1
  187. package/dist/components/primitives/radio-group.d.ts.map +0 -1
  188. package/dist/components/primitives/radio-group.js.map +0 -1
  189. package/dist/components/primitives/select.d.ts.map +0 -1
  190. package/dist/components/primitives/select.js.map +0 -1
  191. package/dist/components/primitives/separator.d.ts.map +0 -1
  192. package/dist/components/primitives/separator.js.map +0 -1
  193. package/dist/components/primitives/side-nav.d.ts.map +0 -1
  194. package/dist/components/primitives/side-nav.js.map +0 -1
  195. package/dist/components/primitives/skeleton.d.ts.map +0 -1
  196. package/dist/components/primitives/skeleton.js.map +0 -1
  197. package/dist/components/primitives/spinner.d.ts.map +0 -1
  198. package/dist/components/primitives/spinner.js.map +0 -1
  199. package/dist/components/primitives/switch.d.ts.map +0 -1
  200. package/dist/components/primitives/switch.js.map +0 -1
  201. package/dist/components/primitives/table.d.ts.map +0 -1
  202. package/dist/components/primitives/table.js.map +0 -1
  203. package/dist/components/primitives/tabs.d.ts.map +0 -1
  204. package/dist/components/primitives/tabs.js.map +0 -1
  205. package/dist/components/primitives/textarea.d.ts.map +0 -1
  206. package/dist/components/primitives/textarea.js.map +0 -1
  207. package/dist/components/primitives/toast.d.ts.map +0 -1
  208. package/dist/components/primitives/toast.js.map +0 -1
  209. package/dist/components/primitives/tooltip.d.ts.map +0 -1
  210. package/dist/components/primitives/tooltip.js.map +0 -1
  211. package/dist/components/status/state-chip.d.ts.map +0 -1
  212. package/dist/components/status/state-chip.js.map +0 -1
  213. package/dist/components/status/state-mark.d.ts.map +0 -1
  214. package/dist/components/status/state-mark.js.map +0 -1
  215. package/dist/components/status/status-pill.d.ts.map +0 -1
  216. package/dist/components/status/status-pill.js.map +0 -1
  217. package/dist/components/status/status-tokens.d.ts.map +0 -1
  218. package/dist/components/status/status-tokens.js.map +0 -1
  219. package/dist/index.d.ts.map +0 -1
  220. package/dist/index.js.map +0 -1
  221. package/dist/lib/cn.d.ts.map +0 -1
  222. package/dist/lib/cn.js.map +0 -1
  223. package/dist/lib/money.d.ts.map +0 -1
  224. package/dist/lib/money.js.map +0 -1
  225. package/dist/lib/omit-undefined.d.ts.map +0 -1
  226. package/dist/lib/omit-undefined.js.map +0 -1
  227. package/src/components/data/code.tsx +0 -43
  228. package/src/components/data/copy-button.tsx +0 -97
  229. package/src/components/data/detail-row.tsx +0 -113
  230. package/src/components/data/id-display.tsx +0 -49
  231. package/src/components/data/masked-value.tsx +0 -96
  232. package/src/components/data/money.tsx +0 -46
  233. package/src/components/data/phone-display.tsx +0 -60
  234. package/src/components/data/stat-tile.tsx +0 -68
  235. package/src/components/data/timestamp-display.tsx +0 -106
  236. package/src/components/patterns/inline-banner.tsx +0 -60
  237. package/src/components/patterns/inline-empty-state.tsx +0 -45
  238. package/src/components/patterns/live-row.tsx +0 -75
  239. package/src/components/patterns/payload-inspector.tsx +0 -157
  240. package/src/components/patterns/route-skeleton.tsx +0 -77
  241. package/src/components/patterns/screen-layout.tsx +0 -44
  242. package/src/components/patterns/stale-write-banner.tsx +0 -44
  243. package/src/components/patterns/state-timeline.tsx +0 -229
  244. package/src/components/primitives/badge.tsx +0 -40
  245. package/src/components/primitives/button.tsx +0 -54
  246. package/src/components/primitives/calendar.tsx +0 -136
  247. package/src/components/primitives/card.tsx +0 -70
  248. package/src/components/primitives/checkbox.tsx +0 -101
  249. package/src/components/primitives/chip-select.tsx +0 -105
  250. package/src/components/primitives/command-menu.tsx +0 -92
  251. package/src/components/primitives/confirm-dialog.tsx +0 -109
  252. package/src/components/primitives/date-picker.tsx +0 -271
  253. package/src/components/primitives/dialog.tsx +0 -195
  254. package/src/components/primitives/drawer.tsx +0 -326
  255. package/src/components/primitives/dropdown-menu.tsx +0 -128
  256. package/src/components/primitives/form-field.tsx +0 -136
  257. package/src/components/primitives/inline-confirm.tsx +0 -118
  258. package/src/components/primitives/input.tsx +0 -21
  259. package/src/components/primitives/label.tsx +0 -43
  260. package/src/components/primitives/pagination.tsx +0 -110
  261. package/src/components/primitives/popover.tsx +0 -41
  262. package/src/components/primitives/progress.tsx +0 -66
  263. package/src/components/primitives/radio-group.tsx +0 -90
  264. package/src/components/primitives/select.tsx +0 -254
  265. package/src/components/primitives/separator.tsx +0 -49
  266. package/src/components/primitives/side-nav.tsx +0 -253
  267. package/src/components/primitives/skeleton.tsx +0 -25
  268. package/src/components/primitives/spinner.tsx +0 -39
  269. package/src/components/primitives/switch.tsx +0 -74
  270. package/src/components/primitives/table.tsx +0 -157
  271. package/src/components/primitives/tabs.tsx +0 -163
  272. package/src/components/primitives/textarea.tsx +0 -21
  273. package/src/components/primitives/toast.tsx +0 -117
  274. package/src/components/primitives/tooltip.tsx +0 -38
  275. package/src/components/status/state-chip.tsx +0 -70
  276. package/src/components/status/state-mark.tsx +0 -154
  277. package/src/components/status/status-pill.tsx +0 -153
  278. package/src/components/status/status-tokens.ts +0 -173
  279. package/src/index.ts +0 -96
  280. package/src/lib/cn.ts +0 -168
  281. package/src/lib/money.ts +0 -164
  282. package/src/lib/omit-undefined.ts +0 -25
  283. /package/{src → dist}/styles/theme.css +0 -0
@@ -1,136 +0,0 @@
1
- "use client";
2
-
3
- import { ChevronLeft, ChevronRight } from "lucide-react";
4
- import { DayPicker, type DayPickerProps } from "react-day-picker";
5
- import { cn } from "../../lib/cn";
6
-
7
- export type CalendarProps = DayPickerProps & { className?: string | undefined };
8
-
9
- /**
10
- * `react-day-picker`, themed with this design system's own tokens.
11
- *
12
- * # Why the whole `classNames` map is spelled out
13
- *
14
- * `react-day-picker` ships a stylesheet (`react-day-picker/style.css`)
15
- * built on its own `--rdp-*` variables. Importing it would put a second,
16
- * independent theme in the page whose colours are set from somewhere
17
- * other than `theme.css` — so the first time anyone changed a surface
18
- * colour, the calendar would not follow, and the mismatch would be
19
- * invisible until someone opened a date picker.
20
- *
21
- * The stylesheet is therefore **not** imported, and every element gets a
22
- * class from the tokens here instead. That is more code than a handful of
23
- * overrides, and it is the point: there is exactly one place this
24
- * component's colours come from, and it is the same place every other
25
- * component's come from.
26
- *
27
- * # `selected` without `onSelect` is not a binding
28
- *
29
- * This component is a thin pass-through, so react-day-picker's own
30
- * control semantics apply unchanged: given `selected` but no `onSelect`,
31
- * it manages selection internally and treats `selected` as an initial
32
- * value. A caller who expects a controlled component gets one that
33
- * silently diverges from its own prop the first time someone clicks a
34
- * day — found exactly that way, in a gallery demo. Pass both, or neither.
35
- *
36
- * # Layout is deliberately not themed away
37
- *
38
- * The grid itself is a `<table>` and needs `border-collapse` plus fixed
39
- * cell sizing to stay square; those are structural, not thematic, and
40
- * live here rather than in a token.
41
- */
42
- export function Calendar({
43
- className,
44
- classNames,
45
- showOutsideDays = true,
46
- ...props
47
- }: CalendarProps) {
48
- return (
49
- <DayPicker
50
- showOutsideDays={showOutsideDays}
51
- className={cn("p-3", className)}
52
- classNames={{
53
- root: "text-body text-foreground",
54
- months: "flex flex-col gap-4 sm:flex-row",
55
- month: "flex flex-col gap-3",
56
- month_caption: "flex h-8 items-center justify-center",
57
- caption_label: "font-medium text-body text-foreground",
58
- nav: "flex items-center gap-1",
59
- // The nav buttons are absolutely positioned by RDP's own layout at
60
- // the top corners of the month; these restyle them in place.
61
- button_previous: cn(
62
- "absolute top-3 left-3 inline-flex size-7 items-center justify-center rounded-sm",
63
- "text-muted-foreground transition-colors hover:bg-surface-3 hover:text-foreground",
64
- "disabled:pointer-events-none disabled:opacity-40",
65
- ),
66
- button_next: cn(
67
- "absolute top-3 right-3 inline-flex size-7 items-center justify-center rounded-sm",
68
- "text-muted-foreground transition-colors hover:bg-surface-3 hover:text-foreground",
69
- "disabled:pointer-events-none disabled:opacity-40",
70
- ),
71
- month_grid: "w-full border-collapse",
72
- weekdays: "flex",
73
- weekday: "w-8 font-normal text-caption text-subtle-foreground",
74
- week: "mt-1 flex w-full",
75
- // Selection state lives on the CELL, not on the button inside it.
76
- // Read off the real DOM, not guessed: react-day-picker puts
77
- // `aria-selected` and `data-selected` on the `<td>` and leaves the
78
- // `<button>` carrying only `type`/`tabindex`/`aria-label`. An
79
- // earlier revision of this file styled the button with
80
- // `aria-selected:bg-primary` and the cell with
81
- // `[&:has([data-range-middle])]`, and BOTH silently matched
82
- // nothing — no selected day had a fill and no range had a tint.
83
- // Neither `tsc` nor the classNames-key test could see it: the keys
84
- // were all real, and the class strings were valid CSS for a DOM
85
- // shape that does not exist. Found by rendering it.
86
- day: "relative size-8 p-0 text-center",
87
- day_button: cn(
88
- "inline-flex size-8 items-center justify-center rounded-sm font-mono text-caption tabular-nums",
89
- "text-foreground transition-colors hover:bg-surface-3",
90
- "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
91
- ),
92
- // Fills the button from the cell's own state, which is where the
93
- // state actually is. Covers single mode outright and both ends of
94
- // a range; `range_middle` below overrides it for the interior.
95
- selected:
96
- "[&>button]:bg-primary [&>button]:text-primary-content [&>button]:hover:bg-primary",
97
- today: "font-semibold text-state-uncertain-fg",
98
- outside: "text-subtle-foreground opacity-50",
99
- disabled: "pointer-events-none opacity-30",
100
- hidden: "invisible",
101
- // The interior of a range: tint the CELL so consecutive days meet
102
- // with no gap, and knock the button's own fill back out.
103
- //
104
- // Two things here were wrong on the first attempt and are worth
105
- // keeping written down. The tint was `bg-state-neutral-bg`, which
106
- // is a real token that resolves to `transparent` — `neutral` is
107
- // the quiet hue and deliberately has no fill — so the interior
108
- // rendered as nothing at all. It is a wash of the selection
109
- // colour instead, which is also what it means. And the `!` is
110
- // load-bearing: a middle day also carries `selected` above, and
111
- // both rules are arbitrary variants of equal specificity, so
112
- // without it the winner is whichever class Tailwind emits last.
113
- range_middle:
114
- "bg-primary/15 [&>button]:bg-transparent! [&>button]:text-foreground! [&>button]:hover:bg-surface-3!",
115
- range_start: "rounded-l-sm",
116
- range_end: "rounded-r-sm",
117
- week_number: "w-8 font-mono text-caption text-subtle-foreground",
118
- footer: "pt-2 text-caption text-muted-foreground",
119
- ...classNames,
120
- }}
121
- components={{
122
- // RDP renders one `Chevron` for both directions and flips it with
123
- // `orientation`; swapping in two real icons reads better than a
124
- // CSS rotation and keeps the stroke weight matching every other
125
- // icon in the system.
126
- Chevron: ({ orientation, ...iconProps }) =>
127
- orientation === "left" ? (
128
- <ChevronLeft size={16} strokeWidth={1.5} {...iconProps} />
129
- ) : (
130
- <ChevronRight size={16} strokeWidth={1.5} {...iconProps} />
131
- ),
132
- }}
133
- {...props}
134
- />
135
- );
136
- }
@@ -1,70 +0,0 @@
1
- import type { HTMLAttributes, ReactNode } from "react";
2
- import { cn } from "../../lib/cn";
3
-
4
- export type CardProps = HTMLAttributes<HTMLDivElement>;
5
-
6
- // Borders, not shadows (design doc §3.6): every card is `--shadow-none` +
7
- // a 1px border. daisyUI's own `card` class would add `shadow-xl` under
8
- // some presets — explicitly opted out here rather than stripped after the
9
- // fact, since this is a hand-built component, not a generated one.
10
- //
11
- // D8: the previous `rounded-sm` override is dropped, not swapped for
12
- // `rounded-box` — daisyUI's own `.card` rule already sets
13
- // `border-radius: var(--radius-box)` (confirmed by reading
14
- // `daisyui/components/card.css` directly), so an explicit override was
15
- // fighting the component's own class at equal specificity for no reason.
16
- // This *is* the deliberate D8 value change §5's inventory calls for
17
- // ("new radius (`--radius-box`)") — the previous `rounded-sm` resolved to
18
- // `--radius-field` (12px) once Phase 0 rewrote the alias, one tier tighter
19
- // than the box-tier corners the reference lock (§1.1/§1.2/§1.5) shows for
20
- // card/drawer/panel chrome.
21
- export function Card({ className, ...props }: CardProps) {
22
- return (
23
- <div className={cn("card border border-edge bg-base-300 shadow-none", className)} {...props} />
24
- );
25
- }
26
-
27
- export interface CardHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
28
- title: ReactNode;
29
- /**
30
- * Heading level for `title`. Defaults to `h3`, which is right for a
31
- * card inside a section that already has an `h2`.
32
- *
33
- * It is a prop rather than a constant because a heading level is a
34
- * property of the page's outline, not of the card: a card placed
35
- * directly under the screen's `h1` with `h3` skips a level, which axe
36
- * reports as `heading-order` and a screen-reader user experiences as a
37
- * missing section.
38
- */
39
- headingLevel?: 2 | 3 | 4 | 5 | 6;
40
- /** Optional mono metadata line beneath the title. */
41
- meta?: ReactNode;
42
- /** Right-aligned slot, e.g. a row of buttons. */
43
- action?: ReactNode;
44
- }
45
-
46
- export function CardHeader({
47
- title,
48
- meta,
49
- action,
50
- headingLevel = 3,
51
- className,
52
- ...props
53
- }: CardHeaderProps) {
54
- const Heading = `h${headingLevel}` as const;
55
- return (
56
- <div className={cn("flex items-start justify-between gap-4 p-4", className)} {...props}>
57
- <div className="min-w-0">
58
- <Heading className="truncate font-medium text-foreground text-title-sm">{title}</Heading>
59
- {meta != null && (
60
- <p className="mt-1 truncate font-mono text-caption text-subtle-foreground">{meta}</p>
61
- )}
62
- </div>
63
- {action != null && <div className="shrink-0">{action}</div>}
64
- </div>
65
- );
66
- }
67
-
68
- export function CardBody({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
69
- return <div className={cn("px-4 pb-4", className)} {...props} />;
70
- }
@@ -1,101 +0,0 @@
1
- "use client";
2
-
3
- import { Field, Checkbox as HeadlessCheckbox, Label as HeadlessLabel } from "@headlessui/react";
4
- import { Check, Minus } from "lucide-react";
5
- import type { ReactNode } from "react";
6
- import { cn } from "../../lib/cn";
7
-
8
- export interface CheckboxProps {
9
- checked: boolean;
10
- /** Omit for an uncontrolled display-only checkbox (e.g. inside a row
11
- * whose whole surface handles the click). */
12
- onCheckedChange?: ((checked: boolean) => void) | undefined;
13
- /** Neither on nor off — a parent whose children disagree. Rendered as a
14
- * dash. `checked` is still what a click toggles from. */
15
- indeterminate?: boolean;
16
- disabled?: boolean | undefined;
17
- /** Required when no visible `<CheckboxField>` label wraps it. */
18
- "aria-label"?: string | undefined;
19
- "aria-labelledby"?: string | undefined;
20
- className?: string | undefined;
21
- }
22
-
23
- /**
24
- * A checkbox, rendered as a real focusable control rather than a styled
25
- * `<input>`.
26
- *
27
- * Headless UI gives it `role="checkbox"`, `aria-checked`, space-to-toggle
28
- * and focus management; everything here is appearance. A native
29
- * `<input type="checkbox">` styled with `appearance-none` would be
30
- * equivalent for the plain case but cannot express `indeterminate`
31
- * without an imperative DOM write on a ref, which is how that state ends
32
- * up out of sync with React's own.
33
- */
34
- export function Checkbox({
35
- checked,
36
- onCheckedChange,
37
- indeterminate = false,
38
- disabled,
39
- className,
40
- ...aria
41
- }: CheckboxProps) {
42
- return (
43
- <HeadlessCheckbox
44
- checked={checked}
45
- onChange={onCheckedChange ?? (() => undefined)}
46
- disabled={disabled ?? false}
47
- indeterminate={indeterminate}
48
- className={cn(
49
- "group inline-flex size-4 shrink-0 items-center justify-center rounded-selector border border-edge-strong bg-surface-2",
50
- "transition-colors data-checked:border-primary data-checked:bg-primary",
51
- "data-indeterminate:border-primary data-indeterminate:bg-primary",
52
- "data-focus:outline-none data-focus:ring-1 data-focus:ring-ring",
53
- "data-disabled:cursor-not-allowed data-disabled:opacity-50",
54
- className,
55
- )}
56
- {...aria}
57
- >
58
- {indeterminate ? (
59
- <Minus size={12} strokeWidth={2.5} className="text-primary-content" />
60
- ) : (
61
- <Check
62
- size={12}
63
- strokeWidth={2.5}
64
- className="text-primary-content opacity-0 group-data-checked:opacity-100"
65
- />
66
- )}
67
- </HeadlessCheckbox>
68
- );
69
- }
70
-
71
- export interface CheckboxFieldProps extends Omit<CheckboxProps, "aria-label" | "aria-labelledby"> {
72
- label: ReactNode;
73
- /** One line beneath the label. */
74
- description?: ReactNode;
75
- }
76
-
77
- /**
78
- * A checkbox with a clickable label beside it.
79
- *
80
- * Separate from `FormField`, which stacks a label *above* a control:
81
- * a checkbox's label belongs on the same line and must itself be a click
82
- * target, which is a different layout and a different association
83
- * (`Field`/`Label` wiring rather than `htmlFor`).
84
- */
85
- export function CheckboxField({ label, description, className, ...props }: CheckboxFieldProps) {
86
- return (
87
- <Field className={cn("flex items-start gap-2", className)}>
88
- <span className="mt-0.5">
89
- <Checkbox {...props} />
90
- </span>
91
- <span className="flex flex-col gap-0.5">
92
- <HeadlessLabel className="cursor-pointer text-body text-foreground data-disabled:cursor-not-allowed data-disabled:opacity-50">
93
- {label}
94
- </HeadlessLabel>
95
- {description !== undefined && (
96
- <span className="text-caption text-muted-foreground">{description}</span>
97
- )}
98
- </span>
99
- </Field>
100
- );
101
- }
@@ -1,105 +0,0 @@
1
- "use client";
2
-
3
- // No `CheckboxGroup` — Headless UI 2.2.10 does not export one (checked,
4
- // not assumed: `tsc` rejected it), so the grouping is done here.
5
- //
6
- // A `<fieldset>`, not `<div role="group">`. Biome's `a11y/useSemanticElements`
7
- // is right that the native element beats the ARIA role, and it caught the
8
- // div in CI after a local `biome check frontends` had passed — CI runs
9
- // `pnpm biome ci .`, which is not the same command. Run CI's own.
10
- //
11
- // `min-w-0` because a `<fieldset>` has a UA `min-width: min-content` that a
12
- // `<div>` does not, which would otherwise stop the chips wrapping inside a
13
- // narrow drawer.
14
- import { Checkbox, Field, Label } from "@headlessui/react";
15
- import { Check } from "lucide-react";
16
- import type { ReactNode } from "react";
17
- import { cn } from "../../lib/cn";
18
-
19
- /**
20
- * Multi-select over a small, fixed vocabulary, rendered as toggleable
21
- * chips.
22
- *
23
- * # Why chips rather than a text field or a multi-select
24
- *
25
- * The motivating case is OAuth scopes when provisioning a client. That
26
- * field was a free-text input: an operator had to already know both that
27
- * scopes are space-delimited *and* what the fourteen valid strings are,
28
- * with a typo silently producing a client that is denied at Layer 2 with
29
- * no hint why. Showing the vocabulary is the whole point.
30
- *
31
- * Not a `Select` with `multiple`: this renders inline with no portal and
32
- * no transition, so it cannot hit the focus-trap bug that made `Select`
33
- * unusable inside a drawer (#315). Same reasoning as `RadioGroup` — for a
34
- * bounded vocabulary in a drawer, the inline control is the safer one.
35
- *
36
- * Not a `<datalist>` or a tag input either: both still let a caller type
37
- * something outside the vocabulary, which is exactly the property being
38
- * removed.
39
- */
40
- export interface ChipOption<T extends string> {
41
- value: T;
42
- label: ReactNode;
43
- /** Shown beneath the label — for scopes, what the scope actually permits. */
44
- description?: ReactNode;
45
- }
46
-
47
- export interface ChipSelectProps<T extends string> {
48
- value: readonly T[];
49
- onValueChange: (value: T[]) => void;
50
- options: readonly ChipOption<T>[];
51
- disabled?: boolean | undefined;
52
- "aria-label"?: string | undefined;
53
- className?: string | undefined;
54
- }
55
-
56
- export function ChipSelect<T extends string>({
57
- value,
58
- onValueChange,
59
- options,
60
- disabled,
61
- className,
62
- ...aria
63
- }: ChipSelectProps<T>) {
64
- return (
65
- <fieldset className={cn("flex min-w-0 flex-wrap gap-2", className)} {...aria}>
66
- {options.map((option) => {
67
- const checked = value.includes(option.value);
68
- return (
69
- <Field key={option.value}>
70
- <Checkbox
71
- checked={checked}
72
- disabled={disabled ?? false}
73
- onChange={(next: boolean) => {
74
- onValueChange(
75
- next ? [...value, option.value] : value.filter((v) => v !== option.value),
76
- );
77
- }}
78
- className={cn(
79
- "flex cursor-pointer items-start gap-2 rounded-sm border border-edge bg-surface-2 px-3 py-2 text-body text-muted-foreground",
80
- "data-checked:border-state-success-border data-checked:bg-state-success-bg data-checked:text-state-success-fg",
81
- "data-focus:outline-none data-focus:ring-1 data-focus:ring-state-success-border",
82
- "data-disabled:cursor-not-allowed data-disabled:opacity-50",
83
- )}
84
- >
85
- <span
86
- className={cn(
87
- "mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-xs border border-edge",
88
- checked && "border-state-success-fg",
89
- )}
90
- >
91
- {checked && <Check className="size-3" aria-hidden="true" />}
92
- </span>
93
- <span className="flex flex-col gap-0.5">
94
- <Label className="cursor-pointer font-mono font-medium">{option.label}</Label>
95
- {option.description !== undefined && (
96
- <span className="text-caption text-subtle-foreground">{option.description}</span>
97
- )}
98
- </span>
99
- </Checkbox>
100
- </Field>
101
- );
102
- })}
103
- </fieldset>
104
- );
105
- }
@@ -1,92 +0,0 @@
1
- "use client";
2
-
3
- import { Command as CommandPrimitive } from "cmdk";
4
- import { Search } from "lucide-react";
5
- import { forwardRef } from "react";
6
- import { cn } from "../../lib/cn";
7
-
8
- // cmdk is standalone (no Radix wrapper needed — it already owns its own
9
- // keyboard nav/ARIA). Styled with the same surface-2/border-edge/radius-md
10
- // floating-layer treatment as Popover/DropdownMenu for visual consistency.
11
-
12
- export const CommandMenu = forwardRef<
13
- React.ElementRef<typeof CommandPrimitive>,
14
- React.ComponentPropsWithoutRef<typeof CommandPrimitive>
15
- >(({ className, ...props }, ref) => (
16
- <CommandPrimitive
17
- ref={ref}
18
- className={cn(
19
- "flex w-full flex-col overflow-hidden rounded-md border border-edge bg-surface-2 text-foreground",
20
- className,
21
- )}
22
- {...props}
23
- />
24
- ));
25
- CommandMenu.displayName = "CommandMenu";
26
-
27
- export function CommandMenuInput(
28
- props: React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>,
29
- ) {
30
- return (
31
- <div className="flex items-center gap-2 border-edge border-b px-3">
32
- <Search size={14} strokeWidth={1.5} className="shrink-0 text-subtle-foreground" />
33
- <CommandPrimitive.Input
34
- className="h-10 w-full bg-transparent text-prose outline-none placeholder:text-subtle-foreground"
35
- {...props}
36
- />
37
- </div>
38
- );
39
- }
40
-
41
- export const CommandMenuList = forwardRef<
42
- React.ElementRef<typeof CommandPrimitive.List>,
43
- React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
44
- >(({ className, ...props }, ref) => (
45
- <CommandPrimitive.List
46
- ref={ref}
47
- className={cn("max-h-80 overflow-y-auto overflow-x-hidden p-1", className)}
48
- {...props}
49
- />
50
- ));
51
- CommandMenuList.displayName = "CommandMenuList";
52
-
53
- export function CommandMenuEmpty(
54
- props: React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>,
55
- ) {
56
- return (
57
- <CommandPrimitive.Empty
58
- className="px-3 py-6 text-center text-body text-muted-foreground"
59
- {...props}
60
- />
61
- );
62
- }
63
-
64
- export const CommandMenuGroup = forwardRef<
65
- React.ElementRef<typeof CommandPrimitive.Group>,
66
- React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
67
- >(({ className, ...props }, ref) => (
68
- <CommandPrimitive.Group
69
- ref={ref}
70
- className={cn(
71
- "text-body [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-micro [&_[cmdk-group-heading]]:text-muted-foreground",
72
- className,
73
- )}
74
- {...props}
75
- />
76
- ));
77
- CommandMenuGroup.displayName = "CommandMenuGroup";
78
-
79
- export const CommandMenuItem = forwardRef<
80
- React.ElementRef<typeof CommandPrimitive.Item>,
81
- React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
82
- >(({ className, ...props }, ref) => (
83
- <CommandPrimitive.Item
84
- ref={ref}
85
- className={cn(
86
- "flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-body data-[selected=true]:bg-surface-3",
87
- className,
88
- )}
89
- {...props}
90
- />
91
- ));
92
- CommandMenuItem.displayName = "CommandMenuItem";
@@ -1,109 +0,0 @@
1
- "use client";
2
-
3
- import type { ReactNode } from "react";
4
- import { Button } from "./button";
5
- import {
6
- Dialog,
7
- DialogContent,
8
- DialogDescription,
9
- DialogFooter,
10
- DialogHeader,
11
- DialogTitle,
12
- } from "./dialog";
13
- import { Spinner } from "./spinner";
14
-
15
- export interface ConfirmDialogProps {
16
- open: boolean;
17
- onOpenChange: (open: boolean) => void;
18
- title: ReactNode;
19
- /**
20
- * What will happen, in the user's terms — and for anything
21
- * irreversible, say so here. "This cannot be undone" is not filler;
22
- * it is the one sentence that changes the decision.
23
- */
24
- description: ReactNode;
25
- /** Names the action, e.g. "Delete endpoint". Never "OK" or "Yes": the
26
- * confirm button is often the only text read before clicking, so it has
27
- * to say what it does on its own. */
28
- confirmLabel: string;
29
- cancelLabel?: string;
30
- /** `destructive` renders the confirm button in the error variant. Use
31
- * it for anything that deletes, revokes or cancels — not merely for
32
- * anything important. */
33
- tone?: "default" | "destructive";
34
- onConfirm: () => void;
35
- /** In-flight: both buttons disabled, confirm shows a spinner. The
36
- * dialog does not close itself — the caller closes it when the write
37
- * actually lands, so a failure leaves the dialog open with its error
38
- * rather than vanishing and losing the context. */
39
- busy?: boolean;
40
- /** Rendered above the buttons. The place for a failed attempt's message. */
41
- children?: ReactNode;
42
- }
43
-
44
- /**
45
- * A modal yes/no for an action worth interrupting someone over.
46
- *
47
- * # When *not* to use it
48
- *
49
- * Most of the time. A modal confirm is an interruption, and an
50
- * interruption that appears on every delete trains people to dismiss it
51
- * without reading — at which point it protects nothing and costs a click.
52
- * `InlineConfirm` (the two-step button that expands in place) is the
53
- * right default for a row-level action; this is for the ones where
54
- * getting it wrong is expensive and hard to reverse.
55
- *
56
- * # Why the caller closes it
57
- *
58
- * `onConfirm` returning does not close the dialog, and `busy` is a prop
59
- * rather than internal state. Both follow from the same requirement: the
60
- * dialog must still be open, with its context intact, when a write fails.
61
- * A self-closing confirm reports failure through a toast on a screen the
62
- * operator has already been returned to, which is where error messages go
63
- * to be missed.
64
- */
65
- export function ConfirmDialog({
66
- open,
67
- onOpenChange,
68
- title,
69
- description,
70
- confirmLabel,
71
- cancelLabel = "Cancel",
72
- tone = "default",
73
- onConfirm,
74
- busy = false,
75
- children,
76
- }: ConfirmDialogProps) {
77
- return (
78
- <Dialog open={open} onOpenChange={onOpenChange}>
79
- <DialogContent className="max-w-sm">
80
- <DialogHeader>
81
- <DialogTitle>{title}</DialogTitle>
82
- <DialogDescription>{description}</DialogDescription>
83
- </DialogHeader>
84
- {children}
85
- <DialogFooter>
86
- <Button
87
- type="button"
88
- variant="ghost"
89
- size="sm"
90
- disabled={busy}
91
- onClick={() => onOpenChange(false)}
92
- >
93
- {cancelLabel}
94
- </Button>
95
- <Button
96
- type="button"
97
- variant={tone === "destructive" ? "destructive" : "primary"}
98
- size="sm"
99
- disabled={busy}
100
- onClick={onConfirm}
101
- >
102
- {busy && <Spinner size="xs" />}
103
- {confirmLabel}
104
- </Button>
105
- </DialogFooter>
106
- </DialogContent>
107
- </Dialog>
108
- );
109
- }