@vaam-apps/ui 0.1.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 (285) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/LICENSE +21 -0
  3. package/README.md +286 -0
  4. package/dist/components/data/code.d.ts +37 -0
  5. package/dist/components/data/code.d.ts.map +1 -0
  6. package/dist/components/data/code.js +37 -0
  7. package/dist/components/data/code.js.map +1 -0
  8. package/dist/components/data/copy-button.d.ts +39 -0
  9. package/dist/components/data/copy-button.d.ts.map +1 -0
  10. package/dist/components/data/copy-button.js +50 -0
  11. package/dist/components/data/copy-button.js.map +1 -0
  12. package/dist/components/data/detail-row.d.ts +69 -0
  13. package/dist/components/data/detail-row.d.ts.map +1 -0
  14. package/dist/components/data/detail-row.js +27 -0
  15. package/dist/components/data/detail-row.js.map +1 -0
  16. package/dist/components/data/id-display.d.ts +33 -0
  17. package/dist/components/data/id-display.d.ts.map +1 -0
  18. package/dist/components/data/id-display.js +25 -0
  19. package/dist/components/data/id-display.js.map +1 -0
  20. package/dist/components/data/masked-value.d.ts +47 -0
  21. package/dist/components/data/masked-value.d.ts.map +1 -0
  22. package/dist/components/data/masked-value.js +46 -0
  23. package/dist/components/data/masked-value.js.map +1 -0
  24. package/dist/components/data/money.d.ts +28 -0
  25. package/dist/components/data/money.d.ts.map +1 -0
  26. package/dist/components/data/money.js +22 -0
  27. package/dist/components/data/money.js.map +1 -0
  28. package/dist/components/data/phone-display.d.ts +45 -0
  29. package/dist/components/data/phone-display.d.ts.map +1 -0
  30. package/dist/components/data/phone-display.js +23 -0
  31. package/dist/components/data/phone-display.js.map +1 -0
  32. package/dist/components/data/stat-tile.d.ts +33 -0
  33. package/dist/components/data/stat-tile.d.ts.map +1 -0
  34. package/dist/components/data/stat-tile.js +18 -0
  35. package/dist/components/data/stat-tile.js.map +1 -0
  36. package/dist/components/data/timestamp-display.d.ts +14 -0
  37. package/dist/components/data/timestamp-display.d.ts.map +1 -0
  38. package/dist/components/data/timestamp-display.js +77 -0
  39. package/dist/components/data/timestamp-display.js.map +1 -0
  40. package/dist/components/patterns/inline-banner.d.ts +22 -0
  41. package/dist/components/patterns/inline-banner.d.ts.map +1 -0
  42. package/dist/components/patterns/inline-banner.js +11 -0
  43. package/dist/components/patterns/inline-banner.js.map +1 -0
  44. package/dist/components/patterns/inline-empty-state.d.ts +20 -0
  45. package/dist/components/patterns/inline-empty-state.d.ts.map +1 -0
  46. package/dist/components/patterns/inline-empty-state.js +11 -0
  47. package/dist/components/patterns/inline-empty-state.js.map +1 -0
  48. package/dist/components/patterns/live-row.d.ts +23 -0
  49. package/dist/components/patterns/live-row.d.ts.map +1 -0
  50. package/dist/components/patterns/live-row.js +48 -0
  51. package/dist/components/patterns/live-row.js.map +1 -0
  52. package/dist/components/patterns/payload-inspector.d.ts +25 -0
  53. package/dist/components/patterns/payload-inspector.d.ts.map +1 -0
  54. package/dist/components/patterns/payload-inspector.js +33 -0
  55. package/dist/components/patterns/payload-inspector.js.map +1 -0
  56. package/dist/components/patterns/route-skeleton.d.ts +15 -0
  57. package/dist/components/patterns/route-skeleton.d.ts.map +1 -0
  58. package/dist/components/patterns/route-skeleton.js +7 -0
  59. package/dist/components/patterns/route-skeleton.js.map +1 -0
  60. package/dist/components/patterns/screen-layout.d.ts +14 -0
  61. package/dist/components/patterns/screen-layout.d.ts.map +1 -0
  62. package/dist/components/patterns/screen-layout.js +11 -0
  63. package/dist/components/patterns/screen-layout.js.map +1 -0
  64. package/dist/components/patterns/stale-write-banner.d.ts +26 -0
  65. package/dist/components/patterns/stale-write-banner.d.ts.map +1 -0
  66. package/dist/components/patterns/stale-write-banner.js +28 -0
  67. package/dist/components/patterns/stale-write-banner.js.map +1 -0
  68. package/dist/components/patterns/state-timeline.d.ts +58 -0
  69. package/dist/components/patterns/state-timeline.d.ts.map +1 -0
  70. package/dist/components/patterns/state-timeline.js +103 -0
  71. package/dist/components/patterns/state-timeline.js.map +1 -0
  72. package/dist/components/primitives/badge.d.ts +27 -0
  73. package/dist/components/primitives/badge.d.ts.map +1 -0
  74. package/dist/components/primitives/badge.js +33 -0
  75. package/dist/components/primitives/badge.js.map +1 -0
  76. package/dist/components/primitives/button.d.ts +12 -0
  77. package/dist/components/primitives/button.d.ts.map +1 -0
  78. package/dist/components/primitives/button.js +42 -0
  79. package/dist/components/primitives/button.js.map +1 -0
  80. package/dist/components/primitives/calendar.d.ts +39 -0
  81. package/dist/components/primitives/calendar.d.ts.map +1 -0
  82. package/dist/components/primitives/calendar.js +102 -0
  83. package/dist/components/primitives/calendar.js.map +1 -0
  84. package/dist/components/primitives/card.d.ts +24 -0
  85. package/dist/components/primitives/card.d.ts.map +1 -0
  86. package/dist/components/primitives/card.js +28 -0
  87. package/dist/components/primitives/card.js.map +1 -0
  88. package/dist/components/primitives/checkbox.d.ts +42 -0
  89. package/dist/components/primitives/checkbox.d.ts.map +1 -0
  90. package/dist/components/primitives/checkbox.js +31 -0
  91. package/dist/components/primitives/checkbox.js.map +1 -0
  92. package/dist/components/primitives/chip-select.d.ts +38 -0
  93. package/dist/components/primitives/chip-select.d.ts.map +1 -0
  94. package/dist/components/primitives/chip-select.js +25 -0
  95. package/dist/components/primitives/chip-select.js.map +1 -0
  96. package/dist/components/primitives/command-menu.d.ts +54 -0
  97. package/dist/components/primitives/command-menu.d.ts.map +1 -0
  98. package/dist/components/primitives/command-menu.js +24 -0
  99. package/dist/components/primitives/command-menu.js.map +1 -0
  100. package/dist/components/primitives/confirm-dialog.d.ts +52 -0
  101. package/dist/components/primitives/confirm-dialog.d.ts.map +1 -0
  102. package/dist/components/primitives/confirm-dialog.js +30 -0
  103. package/dist/components/primitives/confirm-dialog.js.map +1 -0
  104. package/dist/components/primitives/date-picker.d.ts +68 -0
  105. package/dist/components/primitives/date-picker.d.ts.map +1 -0
  106. package/dist/components/primitives/date-picker.js +107 -0
  107. package/dist/components/primitives/date-picker.js.map +1 -0
  108. package/dist/components/primitives/dialog.d.ts +50 -0
  109. package/dist/components/primitives/dialog.d.ts.map +1 -0
  110. package/dist/components/primitives/dialog.js +90 -0
  111. package/dist/components/primitives/dialog.js.map +1 -0
  112. package/dist/components/primitives/drawer.d.ts +71 -0
  113. package/dist/components/primitives/drawer.d.ts.map +1 -0
  114. package/dist/components/primitives/drawer.js +93 -0
  115. package/dist/components/primitives/drawer.js.map +1 -0
  116. package/dist/components/primitives/dropdown-menu.d.ts +40 -0
  117. package/dist/components/primitives/dropdown-menu.d.ts.map +1 -0
  118. package/dist/components/primitives/dropdown-menu.js +53 -0
  119. package/dist/components/primitives/dropdown-menu.js.map +1 -0
  120. package/dist/components/primitives/form-field.d.ts +94 -0
  121. package/dist/components/primitives/form-field.d.ts.map +1 -0
  122. package/dist/components/primitives/form-field.js +27 -0
  123. package/dist/components/primitives/form-field.js.map +1 -0
  124. package/dist/components/primitives/inline-confirm.d.ts +62 -0
  125. package/dist/components/primitives/inline-confirm.d.ts.map +1 -0
  126. package/dist/components/primitives/inline-confirm.js +11 -0
  127. package/dist/components/primitives/inline-confirm.js.map +1 -0
  128. package/dist/components/primitives/input.d.ts +4 -0
  129. package/dist/components/primitives/input.d.ts.map +1 -0
  130. package/dist/components/primitives/input.js +13 -0
  131. package/dist/components/primitives/input.js.map +1 -0
  132. package/dist/components/primitives/label.d.ts +26 -0
  133. package/dist/components/primitives/label.d.ts.map +1 -0
  134. package/dist/components/primitives/label.js +33 -0
  135. package/dist/components/primitives/label.js.map +1 -0
  136. package/dist/components/primitives/pagination.d.ts +54 -0
  137. package/dist/components/primitives/pagination.d.ts.map +1 -0
  138. package/dist/components/primitives/pagination.js +31 -0
  139. package/dist/components/primitives/pagination.js.map +1 -0
  140. package/dist/components/primitives/popover.d.ts +12 -0
  141. package/dist/components/primitives/popover.d.ts.map +1 -0
  142. package/dist/components/primitives/popover.js +22 -0
  143. package/dist/components/primitives/popover.js.map +1 -0
  144. package/dist/components/primitives/progress.d.ts +25 -0
  145. package/dist/components/primitives/progress.d.ts.map +1 -0
  146. package/dist/components/primitives/progress.js +25 -0
  147. package/dist/components/primitives/progress.js.map +1 -0
  148. package/dist/components/primitives/radio-group.d.ts +47 -0
  149. package/dist/components/primitives/radio-group.d.ts.map +1 -0
  150. package/dist/components/primitives/radio-group.js +11 -0
  151. package/dist/components/primitives/radio-group.js.map +1 -0
  152. package/dist/components/primitives/select.d.ts +39 -0
  153. package/dist/components/primitives/select.d.ts.map +1 -0
  154. package/dist/components/primitives/select.js +142 -0
  155. package/dist/components/primitives/select.js.map +1 -0
  156. package/dist/components/primitives/separator.d.ts +9 -0
  157. package/dist/components/primitives/separator.d.ts.map +1 -0
  158. package/dist/components/primitives/separator.js +16 -0
  159. package/dist/components/primitives/separator.js.map +1 -0
  160. package/dist/components/primitives/side-nav.d.ts +65 -0
  161. package/dist/components/primitives/side-nav.d.ts.map +1 -0
  162. package/dist/components/primitives/side-nav.js +100 -0
  163. package/dist/components/primitives/side-nav.js.map +1 -0
  164. package/dist/components/primitives/skeleton.d.ts +22 -0
  165. package/dist/components/primitives/skeleton.d.ts.map +1 -0
  166. package/dist/components/primitives/skeleton.js +25 -0
  167. package/dist/components/primitives/skeleton.js.map +1 -0
  168. package/dist/components/primitives/spinner.d.ts +20 -0
  169. package/dist/components/primitives/spinner.d.ts.map +1 -0
  170. package/dist/components/primitives/spinner.js +21 -0
  171. package/dist/components/primitives/spinner.js.map +1 -0
  172. package/dist/components/primitives/switch.d.ts +29 -0
  173. package/dist/components/primitives/switch.d.ts.map +1 -0
  174. package/dist/components/primitives/switch.js +24 -0
  175. package/dist/components/primitives/switch.js.map +1 -0
  176. package/dist/components/primitives/table.d.ts +23 -0
  177. package/dist/components/primitives/table.d.ts.map +1 -0
  178. package/dist/components/primitives/table.js +81 -0
  179. package/dist/components/primitives/table.js.map +1 -0
  180. package/dist/components/primitives/tabs.d.ts +38 -0
  181. package/dist/components/primitives/tabs.d.ts.map +1 -0
  182. package/dist/components/primitives/tabs.js +84 -0
  183. package/dist/components/primitives/tabs.js.map +1 -0
  184. package/dist/components/primitives/textarea.d.ts +4 -0
  185. package/dist/components/primitives/textarea.d.ts.map +1 -0
  186. package/dist/components/primitives/textarea.js +11 -0
  187. package/dist/components/primitives/textarea.js.map +1 -0
  188. package/dist/components/primitives/toast.d.ts +24 -0
  189. package/dist/components/primitives/toast.d.ts.map +1 -0
  190. package/dist/components/primitives/toast.js +58 -0
  191. package/dist/components/primitives/toast.js.map +1 -0
  192. package/dist/components/primitives/tooltip.d.ts +30 -0
  193. package/dist/components/primitives/tooltip.d.ts.map +1 -0
  194. package/dist/components/primitives/tooltip.js +6 -0
  195. package/dist/components/primitives/tooltip.js.map +1 -0
  196. package/dist/components/status/state-chip.d.ts +53 -0
  197. package/dist/components/status/state-chip.d.ts.map +1 -0
  198. package/dist/components/status/state-chip.js +8 -0
  199. package/dist/components/status/state-chip.js.map +1 -0
  200. package/dist/components/status/state-mark.d.ts +21 -0
  201. package/dist/components/status/state-mark.d.ts.map +1 -0
  202. package/dist/components/status/state-mark.js +90 -0
  203. package/dist/components/status/state-mark.js.map +1 -0
  204. package/dist/components/status/status-pill.d.ts +62 -0
  205. package/dist/components/status/status-pill.d.ts.map +1 -0
  206. package/dist/components/status/status-pill.js +65 -0
  207. package/dist/components/status/status-pill.js.map +1 -0
  208. package/dist/components/status/status-tokens.d.ts +110 -0
  209. package/dist/components/status/status-tokens.d.ts.map +1 -0
  210. package/dist/components/status/status-tokens.js +102 -0
  211. package/dist/components/status/status-tokens.js.map +1 -0
  212. package/dist/index.d.ts +76 -0
  213. package/dist/index.d.ts.map +1 -0
  214. package/dist/index.js +95 -0
  215. package/dist/index.js.map +1 -0
  216. package/dist/lib/cn.d.ts +11 -0
  217. package/dist/lib/cn.d.ts.map +1 -0
  218. package/dist/lib/cn.js +78 -0
  219. package/dist/lib/cn.js.map +1 -0
  220. package/dist/lib/money.d.ts +73 -0
  221. package/dist/lib/money.d.ts.map +1 -0
  222. package/dist/lib/money.js +123 -0
  223. package/dist/lib/money.js.map +1 -0
  224. package/dist/lib/omit-undefined.d.ts +17 -0
  225. package/dist/lib/omit-undefined.d.ts.map +1 -0
  226. package/dist/lib/omit-undefined.js +24 -0
  227. package/dist/lib/omit-undefined.js.map +1 -0
  228. package/package.json +100 -0
  229. package/src/components/data/code.tsx +43 -0
  230. package/src/components/data/copy-button.tsx +97 -0
  231. package/src/components/data/detail-row.tsx +113 -0
  232. package/src/components/data/id-display.tsx +49 -0
  233. package/src/components/data/masked-value.tsx +96 -0
  234. package/src/components/data/money.tsx +46 -0
  235. package/src/components/data/phone-display.tsx +60 -0
  236. package/src/components/data/stat-tile.tsx +68 -0
  237. package/src/components/data/timestamp-display.tsx +106 -0
  238. package/src/components/patterns/inline-banner.tsx +60 -0
  239. package/src/components/patterns/inline-empty-state.tsx +45 -0
  240. package/src/components/patterns/live-row.tsx +75 -0
  241. package/src/components/patterns/payload-inspector.tsx +157 -0
  242. package/src/components/patterns/route-skeleton.tsx +77 -0
  243. package/src/components/patterns/screen-layout.tsx +44 -0
  244. package/src/components/patterns/stale-write-banner.tsx +44 -0
  245. package/src/components/patterns/state-timeline.tsx +229 -0
  246. package/src/components/primitives/badge.tsx +40 -0
  247. package/src/components/primitives/button.tsx +54 -0
  248. package/src/components/primitives/calendar.tsx +136 -0
  249. package/src/components/primitives/card.tsx +70 -0
  250. package/src/components/primitives/checkbox.tsx +101 -0
  251. package/src/components/primitives/chip-select.tsx +105 -0
  252. package/src/components/primitives/command-menu.tsx +92 -0
  253. package/src/components/primitives/confirm-dialog.tsx +109 -0
  254. package/src/components/primitives/date-picker.tsx +271 -0
  255. package/src/components/primitives/dialog.tsx +195 -0
  256. package/src/components/primitives/drawer.tsx +326 -0
  257. package/src/components/primitives/dropdown-menu.tsx +128 -0
  258. package/src/components/primitives/form-field.tsx +136 -0
  259. package/src/components/primitives/inline-confirm.tsx +118 -0
  260. package/src/components/primitives/input.tsx +21 -0
  261. package/src/components/primitives/label.tsx +43 -0
  262. package/src/components/primitives/pagination.tsx +110 -0
  263. package/src/components/primitives/popover.tsx +41 -0
  264. package/src/components/primitives/progress.tsx +66 -0
  265. package/src/components/primitives/radio-group.tsx +90 -0
  266. package/src/components/primitives/select.tsx +254 -0
  267. package/src/components/primitives/separator.tsx +49 -0
  268. package/src/components/primitives/side-nav.tsx +253 -0
  269. package/src/components/primitives/skeleton.tsx +25 -0
  270. package/src/components/primitives/spinner.tsx +39 -0
  271. package/src/components/primitives/switch.tsx +74 -0
  272. package/src/components/primitives/table.tsx +157 -0
  273. package/src/components/primitives/tabs.tsx +163 -0
  274. package/src/components/primitives/textarea.tsx +21 -0
  275. package/src/components/primitives/toast.tsx +117 -0
  276. package/src/components/primitives/tooltip.tsx +38 -0
  277. package/src/components/status/state-chip.tsx +70 -0
  278. package/src/components/status/state-mark.tsx +154 -0
  279. package/src/components/status/status-pill.tsx +153 -0
  280. package/src/components/status/status-tokens.ts +173 -0
  281. package/src/index.ts +96 -0
  282. package/src/lib/cn.ts +168 -0
  283. package/src/lib/money.ts +164 -0
  284. package/src/lib/omit-undefined.ts +25 -0
  285. package/src/styles/theme.css +381 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,8EAA8E;AAC9E,yEAAyE;AACzE,4CAA4C;AAC5C,8EAA8E;AAC9E,cAAc,wBAAwB,CAAC;AACvC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qCAAqC,CAAC;AACpD,8EAA8E;AAC9E,uEAAuE;AACvE,gEAAgE;AAChE,8EAA8E;AAC9E,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yCAAyC,CAAC;AACxD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,cAAc,sCAAsC,CAAC;AACrD,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAC9E,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,wCAAwC,CAAC;AACvD,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AACnD,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,8EAA8E;AAC9E,gEAAgE;AAChE,0EAA0E;AAC1E,YAAY;AACZ,8EAA8E;AAC9E,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,mCAAmC,CAAC;AAElD,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAC9E,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type ClassValue } from "clsx";
2
+ /**
3
+ * Merge class names, resolving conflicting utilities so the *last* one
4
+ * wins — Tailwind's own, this design system's custom scales, and daisyUI's
5
+ * component modifiers alike.
6
+ */
7
+ export declare function cn(...inputs: ClassValue[]): string;
8
+ /** The font-size steps this package registers with `tailwind-merge`. Exported
9
+ * for `theme-tokens.test.ts`, which checks them against `theme.css`. */
10
+ export declare const REGISTERED_FONT_SIZES: readonly string[];
11
+ //# sourceMappingURL=cn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../src/lib/cn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAQ,MAAM,MAAM,CAAC;AA4J7C;;;;GAIG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAElD;AAED;wEACwE;AACxE,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAAe,CAAC"}
package/dist/lib/cn.js ADDED
@@ -0,0 +1,78 @@
1
+ import { clsx } from "clsx";
2
+ import { extendTailwindMerge } from "tailwind-merge";
3
+ /**
4
+ * The `--text-*` steps declared in `styles/theme.css`. Kept in sync with
5
+ * that file by `theme-tokens.test.ts`, which parses the stylesheet rather
6
+ * than trusting this list.
7
+ */
8
+ const FONT_SIZES = [
9
+ "micro",
10
+ "caption",
11
+ "body",
12
+ "prose",
13
+ "title-sm",
14
+ "title",
15
+ "metric",
16
+ "metric-lg",
17
+ ];
18
+ /** daisyUI's radius tiers, which its own components read from. */
19
+ const RADII = ["selector", "field", "box"];
20
+ const DAISY_COLOURS = [
21
+ "primary",
22
+ "secondary",
23
+ "accent",
24
+ "neutral",
25
+ "info",
26
+ "success",
27
+ "warning",
28
+ "error",
29
+ ];
30
+ const DAISY_SIZES = ["xs", "sm", "md", "lg", "xl"];
31
+ const twMerge = extendTailwindMerge({
32
+ extend: {
33
+ theme: {
34
+ // Registering these as *font sizes* is what stops `text-caption`
35
+ // being mistaken for a colour and dropped. See point 1 above.
36
+ text: [...FONT_SIZES],
37
+ radius: [...RADII],
38
+ },
39
+ classGroups: {
40
+ "daisy-btn-variant": [{ btn: [...DAISY_COLOURS, "ghost", "link"] }],
41
+ "daisy-btn-style": [{ btn: ["outline", "soft", "dash"] }],
42
+ "daisy-btn-size": [{ btn: [...DAISY_SIZES, "wide", "block", "square", "circle"] }],
43
+ "daisy-badge-variant": [{ badge: [...DAISY_COLOURS, "ghost"] }],
44
+ "daisy-badge-style": [{ badge: ["outline", "soft", "dash"] }],
45
+ "daisy-badge-size": [{ badge: [...DAISY_SIZES] }],
46
+ "daisy-alert-variant": [{ alert: ["info", "success", "warning", "error"] }],
47
+ "daisy-alert-style": [{ alert: ["outline", "soft", "dash"] }],
48
+ "daisy-input-variant": [{ input: [...DAISY_COLOURS, "ghost"] }],
49
+ "daisy-select-variant": [{ select: [...DAISY_COLOURS, "ghost"] }],
50
+ "daisy-select-size": [{ select: [...DAISY_SIZES] }],
51
+ "daisy-checkbox-variant": [{ checkbox: [...DAISY_COLOURS] }],
52
+ "daisy-checkbox-size": [{ checkbox: [...DAISY_SIZES] }],
53
+ "daisy-radio-variant": [{ radio: [...DAISY_COLOURS] }],
54
+ "daisy-radio-size": [{ radio: [...DAISY_SIZES] }],
55
+ "daisy-toggle-variant": [{ toggle: [...DAISY_COLOURS] }],
56
+ "daisy-toggle-size": [{ toggle: [...DAISY_SIZES] }],
57
+ "daisy-card-size": [{ card: [...DAISY_SIZES] }],
58
+ "daisy-table-size": [{ table: [...DAISY_SIZES] }],
59
+ "daisy-tabs-style": [{ tabs: ["box", "border", "lift"] }],
60
+ "daisy-tabs-size": [{ tabs: [...DAISY_SIZES] }],
61
+ "daisy-progress-variant": [{ progress: [...DAISY_COLOURS] }],
62
+ "daisy-loading-type": [{ loading: ["spinner", "dots", "ring", "ball", "bars", "infinity"] }],
63
+ "daisy-loading-size": [{ loading: [...DAISY_SIZES] }],
64
+ },
65
+ },
66
+ });
67
+ /**
68
+ * Merge class names, resolving conflicting utilities so the *last* one
69
+ * wins — Tailwind's own, this design system's custom scales, and daisyUI's
70
+ * component modifiers alike.
71
+ */
72
+ export function cn(...inputs) {
73
+ return twMerge(clsx(inputs));
74
+ }
75
+ /** The font-size steps this package registers with `tailwind-merge`. Exported
76
+ * for `theme-tokens.test.ts`, which checks them against `theme.css`. */
77
+ export const REGISTERED_FONT_SIZES = FONT_SIZES;
78
+ //# sourceMappingURL=cn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.js","sourceRoot":"","sources":["../../src/lib/cn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Money formatting from minor units, without losing precision.
3
+ *
4
+ * # Why this exists
5
+ *
6
+ * Money is the single most duplicated formatter in every application that
7
+ * handles it. The sibling payments codebase this package was generalised
8
+ * for had **four** independent implementations at the time of writing, in
9
+ * four packages, with four different signatures and three different
10
+ * hard-coded tables of which currencies have no decimal places — and one
11
+ * of them divided by a power of ten in floating point, which silently
12
+ * corrupts any amount past 2^53 minor units. All four also got the
13
+ * three-decimal currencies wrong, because every hand-written table
14
+ * remembers `JPY` and `XAF` and forgets `KWD` and `BHD`.
15
+ *
16
+ * # Three decisions, each load-bearing
17
+ *
18
+ * **Minor units in, never a decimal number.** An amount is an integer
19
+ * count of the currency's smallest unit — that is how it is stored, how
20
+ * it is transmitted, and the only representation that cannot be wrong by
21
+ * a rounding error. `bigint` and a decimal-digit `string` are accepted
22
+ * alongside `number` so an `i64` from a Rust backend survives the trip;
23
+ * JSON gives it to you as a string precisely because `number` cannot hold
24
+ * it.
25
+ *
26
+ * **The exponent comes from `Intl`, not from a table here.** `Intl`
27
+ * already ships the ISO 4217 exponent for every currency, so there is no
28
+ * list to maintain and no currency this gets wrong. Verified rather than
29
+ * assumed: `XAF`/`XOF`/`JPY`/`CLP`/`VND` resolve to 0 and `KWD`/`BHD` to
30
+ * 3, which is exactly the set hand-written tables miss.
31
+ *
32
+ * **The scaling is string surgery, never division.** The minor-unit
33
+ * integer is split into whole and fractional parts by digit position and
34
+ * handed to `Intl.NumberFormat` as a string, which accepts arbitrary
35
+ * precision. No value is ever converted to a float, so an amount larger
36
+ * than `Number.MAX_SAFE_INTEGER` formats exactly.
37
+ */
38
+ /** An integer count of a currency's smallest unit. */
39
+ export type MinorUnits = number | bigint | string;
40
+ export interface FormatMoneyOptions {
41
+ /** BCP 47 tag. Defaults to the runtime's own locale.
42
+ *
43
+ * Pass one explicitly anywhere the output must be stable — a test, a
44
+ * server-rendered page whose HTML must match the client's hydration, or
45
+ * a value a human will compare against a bank statement. */
46
+ locale?: string | undefined;
47
+ /** `symbol` → `FCFA 5,000`; `code` → `XAF 5,000`; `none` → `5,000`.
48
+ *
49
+ * `code` is the honest default for an operator console: currency
50
+ * symbols are ambiguous across locales ($ alone names at least a dozen
51
+ * currencies) and an operator reconciling against a ledger needs the
52
+ * ISO code. */
53
+ display?: "symbol" | "code" | "none";
54
+ /** Force a sign even when positive, e.g. for a ledger delta. */
55
+ signDisplay?: Intl.NumberFormatOptions["signDisplay"];
56
+ }
57
+ /**
58
+ * How many decimal places this currency has, per ISO 4217, as `Intl`
59
+ * knows it. `2` for a currency `Intl` has never heard of — the majority
60
+ * case, and the same fallback `Intl` itself uses.
61
+ */
62
+ export declare function currencyExponent(currency: string, locale?: string): number;
63
+ /**
64
+ * `formatMoney(500000, "XAF")` → `"XAF 500,000"`.
65
+ * `formatMoney("1250", "USD")` → `"USD 12.50"`.
66
+ *
67
+ * @throws if `minorUnits` is not an integer. A non-integer minor-unit
68
+ * amount is always a bug — usually a caller that already divided — and
69
+ * silently rounding it here would hide the real error at the point where
70
+ * it is least visible.
71
+ */
72
+ export declare function formatMoney(minorUnits: MinorUnits, currency: string, options?: FormatMoneyOptions): string;
73
+ //# sourceMappingURL=money.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../../src/lib/money.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,sDAAsD;AACtD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAElD,MAAM,WAAW,kBAAkB;IACjC;;;;gEAI4D;IAC5D,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B;;;;;mBAKe;IACf,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IACrC,gEAAgE;IAChE,WAAW,CAAC,EAAE,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;CACvD;AAkBD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAK1E;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CA8CR"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Money formatting from minor units, without losing precision.
3
+ *
4
+ * # Why this exists
5
+ *
6
+ * Money is the single most duplicated formatter in every application that
7
+ * handles it. The sibling payments codebase this package was generalised
8
+ * for had **four** independent implementations at the time of writing, in
9
+ * four packages, with four different signatures and three different
10
+ * hard-coded tables of which currencies have no decimal places — and one
11
+ * of them divided by a power of ten in floating point, which silently
12
+ * corrupts any amount past 2^53 minor units. All four also got the
13
+ * three-decimal currencies wrong, because every hand-written table
14
+ * remembers `JPY` and `XAF` and forgets `KWD` and `BHD`.
15
+ *
16
+ * # Three decisions, each load-bearing
17
+ *
18
+ * **Minor units in, never a decimal number.** An amount is an integer
19
+ * count of the currency's smallest unit — that is how it is stored, how
20
+ * it is transmitted, and the only representation that cannot be wrong by
21
+ * a rounding error. `bigint` and a decimal-digit `string` are accepted
22
+ * alongside `number` so an `i64` from a Rust backend survives the trip;
23
+ * JSON gives it to you as a string precisely because `number` cannot hold
24
+ * it.
25
+ *
26
+ * **The exponent comes from `Intl`, not from a table here.** `Intl`
27
+ * already ships the ISO 4217 exponent for every currency, so there is no
28
+ * list to maintain and no currency this gets wrong. Verified rather than
29
+ * assumed: `XAF`/`XOF`/`JPY`/`CLP`/`VND` resolve to 0 and `KWD`/`BHD` to
30
+ * 3, which is exactly the set hand-written tables miss.
31
+ *
32
+ * **The scaling is string surgery, never division.** The minor-unit
33
+ * integer is split into whole and fractional parts by digit position and
34
+ * handed to `Intl.NumberFormat` as a string, which accepts arbitrary
35
+ * precision. No value is ever converted to a float, so an amount larger
36
+ * than `Number.MAX_SAFE_INTEGER` formats exactly.
37
+ */
38
+ const DIGITS_ONLY = /^-?\d+$/;
39
+ /** Cache: constructing an `Intl.NumberFormat` is the expensive part, and a
40
+ * table renders the same currency once per row. */
41
+ const formatters = new Map();
42
+ function formatter(key, options, locale) {
43
+ const cacheKey = `${locale ?? ""}|${key}`;
44
+ let found = formatters.get(cacheKey);
45
+ if (found === undefined) {
46
+ found = new Intl.NumberFormat(locale, options);
47
+ formatters.set(cacheKey, found);
48
+ }
49
+ return found;
50
+ }
51
+ /**
52
+ * How many decimal places this currency has, per ISO 4217, as `Intl`
53
+ * knows it. `2` for a currency `Intl` has never heard of — the majority
54
+ * case, and the same fallback `Intl` itself uses.
55
+ */
56
+ export function currencyExponent(currency, locale) {
57
+ return (formatter(`exp:${currency}`, { style: "currency", currency }, locale).resolvedOptions()
58
+ .maximumFractionDigits ?? 2);
59
+ }
60
+ /**
61
+ * Shifts a minor-unit integer right by `exponent` places, as a string.
62
+ *
63
+ * `"500"`, 2 → `"5.00"`; `"5"`, 2 → `"0.05"`; `"-5"`, 2 → `"-0.05"`;
64
+ * `"5000"`, 0 → `"5000"`.
65
+ */
66
+ function shiftDecimal(digits, exponent) {
67
+ const negative = digits.startsWith("-");
68
+ const abs = negative ? digits.slice(1) : digits;
69
+ const sign = negative ? "-" : "";
70
+ if (exponent === 0)
71
+ return sign + abs;
72
+ const padded = abs.padStart(exponent + 1, "0");
73
+ const whole = padded.slice(0, padded.length - exponent);
74
+ const fraction = padded.slice(padded.length - exponent);
75
+ return `${sign}${whole}.${fraction}`;
76
+ }
77
+ /**
78
+ * `formatMoney(500000, "XAF")` → `"XAF 500,000"`.
79
+ * `formatMoney("1250", "USD")` → `"USD 12.50"`.
80
+ *
81
+ * @throws if `minorUnits` is not an integer. A non-integer minor-unit
82
+ * amount is always a bug — usually a caller that already divided — and
83
+ * silently rounding it here would hide the real error at the point where
84
+ * it is least visible.
85
+ */
86
+ export function formatMoney(minorUnits, currency, options = {}) {
87
+ const { locale, display = "code", signDisplay } = options;
88
+ let digits;
89
+ if (typeof minorUnits === "bigint") {
90
+ digits = minorUnits.toString();
91
+ }
92
+ else if (typeof minorUnits === "number") {
93
+ if (!Number.isInteger(minorUnits)) {
94
+ throw new TypeError(`formatMoney expects an integer count of minor units, got ${minorUnits} (${currency}). ` +
95
+ "Pass 1250 for USD 12.50, not 12.5.");
96
+ }
97
+ digits = minorUnits.toFixed(0);
98
+ }
99
+ else {
100
+ const trimmed = minorUnits.trim();
101
+ if (!DIGITS_ONLY.test(trimmed)) {
102
+ throw new TypeError(`formatMoney expects an integer count of minor units, got ${JSON.stringify(minorUnits)} (${currency}).`);
103
+ }
104
+ digits = trimmed;
105
+ }
106
+ const exponent = currencyExponent(currency, locale);
107
+ const value = shiftDecimal(digits, exponent);
108
+ const intlOptions = display === "none"
109
+ ? {
110
+ style: "decimal",
111
+ minimumFractionDigits: exponent,
112
+ maximumFractionDigits: exponent,
113
+ }
114
+ : {
115
+ style: "currency",
116
+ currency,
117
+ currencyDisplay: display,
118
+ };
119
+ if (signDisplay !== undefined)
120
+ intlOptions.signDisplay = signDisplay;
121
+ return formatter(`fmt:${currency}:${display}:${signDisplay ?? ""}:${exponent}`, intlOptions, locale).format(value);
122
+ }
123
+ //# sourceMappingURL=money.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"money.js","sourceRoot":"","sources":["../../src/lib/money.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Strips every key whose value is explicitly `undefined`, and narrows the
3
+ * return type to match: `exactOptionalPropertyTypes` (this workspace's own
4
+ * `tsconfig`) makes `{ disabled?: boolean }` reject a spread whose *type*
5
+ * is `{ disabled?: boolean | undefined }` even when the value at runtime is
6
+ * always defined for the keys that matter — every `React.*HTMLAttributes`
7
+ * type declares its optional fields as `T | undefined` explicitly, but
8
+ * Headless UI's own prop types (`ListboxProps`, `MenuItemProps`, `LabelProps`,
9
+ * …) declare theirs as plain `T`. Spreading `...props` from a native-element
10
+ * prop type onto a Headless UI component hits this every time (found
11
+ * porting `select.tsx`/`dropdown-menu.tsx`/`label.tsx` off Radix, D3) —
12
+ * this is the one general fix rather than a one-off cast at each call site.
13
+ */
14
+ export declare function omitUndefined<T extends Record<string, unknown>>(props: T): {
15
+ [K in keyof T]: Exclude<T[K], undefined>;
16
+ };
17
+ //# sourceMappingURL=omit-undefined.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"omit-undefined.d.ts","sourceRoot":"","sources":["../../src/lib/omit-undefined.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7D,KAAK,EAAE,CAAC,GACP;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;CAAE,CAS9C"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Strips every key whose value is explicitly `undefined`, and narrows the
3
+ * return type to match: `exactOptionalPropertyTypes` (this workspace's own
4
+ * `tsconfig`) makes `{ disabled?: boolean }` reject a spread whose *type*
5
+ * is `{ disabled?: boolean | undefined }` even when the value at runtime is
6
+ * always defined for the keys that matter — every `React.*HTMLAttributes`
7
+ * type declares its optional fields as `T | undefined` explicitly, but
8
+ * Headless UI's own prop types (`ListboxProps`, `MenuItemProps`, `LabelProps`,
9
+ * …) declare theirs as plain `T`. Spreading `...props` from a native-element
10
+ * prop type onto a Headless UI component hits this every time (found
11
+ * porting `select.tsx`/`dropdown-menu.tsx`/`label.tsx` off Radix, D3) —
12
+ * this is the one general fix rather than a one-off cast at each call site.
13
+ */
14
+ export function omitUndefined(props) {
15
+ const result = {};
16
+ for (const key of Object.keys(props)) {
17
+ const value = props[key];
18
+ if (value !== undefined) {
19
+ result[key] = value;
20
+ }
21
+ }
22
+ return result;
23
+ }
24
+ //# sourceMappingURL=omit-undefined.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"omit-undefined.js","sourceRoot":"","sources":["../../src/lib/omit-undefined.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAQ;IAER,MAAM,MAAM,GAAG,EAAkD,CAAC;IAClE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAgB,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAuC,CAAC;QACxD,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ "name": "@vaam-apps/ui",
3
+ "version": "0.1.0",
4
+ "description": "A dark-first React component library for operator consoles — daisyUI styling, Headless UI behaviour, and a parameterised status-glyph system.",
5
+ "license": "MIT",
6
+ "author": "Vaam Apps",
7
+ "homepage": "https://github.com/vaam-apps/ui#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/vaam-apps/ui.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/vaam-apps/ui/issues"
14
+ },
15
+ "keywords": [
16
+ "react",
17
+ "ui",
18
+ "components",
19
+ "design-system",
20
+ "tailwindcss",
21
+ "daisyui",
22
+ "headlessui",
23
+ "dashboard",
24
+ "admin"
25
+ ],
26
+ "type": "module",
27
+ "sideEffects": [
28
+ "*.css"
29
+ ],
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "default": "./dist/index.js"
34
+ },
35
+ "./styles/theme.css": "./src/styles/theme.css",
36
+ "./package.json": "./package.json"
37
+ },
38
+ "types": "./dist/index.d.ts",
39
+ "main": "./dist/index.js",
40
+ "files": [
41
+ "dist",
42
+ "src",
43
+ "!src/**/*.test.ts",
44
+ "!src/**/*.test.tsx",
45
+ "!src/**/*.stories.tsx",
46
+ "README.md",
47
+ "CHANGELOG.md"
48
+ ],
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "peerDependencies": {
53
+ "daisyui": "^5",
54
+ "react": "^18.3.0 || ^19",
55
+ "react-dom": "^18.3.0 || ^19",
56
+ "tailwindcss": "^4.1.0"
57
+ },
58
+ "dependencies": {
59
+ "@headlessui/react": "^2.2.10",
60
+ "@radix-ui/react-dialog": "^1.1.1",
61
+ "class-variance-authority": "^0.7.1",
62
+ "clsx": "^2.1.1",
63
+ "cmdk": "1.1.1",
64
+ "lucide-react": "^1.44.0",
65
+ "react-day-picker": "^10.0.1",
66
+ "tailwind-merge": "^3.6.0",
67
+ "vaul": "1.1.2"
68
+ },
69
+ "devDependencies": {
70
+ "@biomejs/biome": "2.5.13",
71
+ "@storybook/addon-a11y": "10.6.0",
72
+ "@storybook/addon-docs": "10.6.0",
73
+ "@storybook/react-vite": "10.6.0",
74
+ "@tailwindcss/vite": "^4.3.3",
75
+ "@types/node": "^26",
76
+ "@types/react": "^19",
77
+ "@types/react-dom": "^19",
78
+ "daisyui": "^5.7.36",
79
+ "react": "^19",
80
+ "react-dom": "^19",
81
+ "storybook": "10.6.0",
82
+ "tailwindcss": "^4.3.3",
83
+ "typescript": "^7",
84
+ "vite": "^8",
85
+ "vitest": "^5"
86
+ },
87
+ "engines": {
88
+ "node": ">=18"
89
+ },
90
+ "scripts": {
91
+ "build": "tsc -p tsconfig.build.json && node scripts/specify-extensions.mjs dist",
92
+ "build-storybook": "storybook build -o storybook-static",
93
+ "clean": "rm -rf dist storybook-static",
94
+ "format": "biome check --write .",
95
+ "lint": "biome check .",
96
+ "storybook": "storybook dev -p 6006",
97
+ "test": "vitest run",
98
+ "typecheck": "tsc --noEmit"
99
+ }
100
+ }
@@ -0,0 +1,43 @@
1
+ import type { ReactNode } from "react";
2
+ import { cn } from "../../lib/cn";
3
+
4
+ /**
5
+ * Inline monospace emphasis for a literal term — a config key, a role key,
6
+ * a job kind, a model or field name.
7
+ *
8
+ * **Not `IdDisplay`, and the distinction is load-bearing.** `IdDisplay` is
9
+ * documented as specifically for `cs_cuid()` values: it truncates to seven
10
+ * characters with no middle ellipsis and offers a copy button, both of
11
+ * which are correct for an opaque 23-character id and wrong for anything
12
+ * else. Three separate agents independently checked their own sites
13
+ * against `schemas/vsms.cstack` and reached the same conclusion — none of
14
+ * these are `Cuid` (`AppClient.clientId` is a plain bounded `String`,
15
+ * `Role.key` is `@regex`-constrained, a route predicate is an operator or
16
+ * prefix, `providerMessageRef` is an *external* provider's id) — so
17
+ * routing them through `IdDisplay` would truncate values that must be read
18
+ * in full.
19
+ *
20
+ * This exists because `font-mono text-foreground` was the most-repeated
21
+ * class string left after the R6 factorization (31 occurrences), and
22
+ * because three route groups had already each created a byte-identical
23
+ * local `Code` component for it. Those three copies are exactly the
24
+ * "same shape, different name" duplication that produced two
25
+ * `ScreenHeader`s and two `MESSAGE_CLASSES` earlier in this effort — the
26
+ * agents that wrote them flagged the risk themselves and could not fix it,
27
+ * because a cross-route duplicate is not a route-scoped change.
28
+ *
29
+ * Renders a `<span>`, not a `<code>`: several call sites sit inside a
30
+ * `<dd>` or a sentence where `<code>` would add semantics the content does
31
+ * not have (a role key in prose is emphasis, not a code sample). A caller
32
+ * that genuinely wants `<code>` semantics should say so rather than have
33
+ * this component guess.
34
+ */
35
+ export function Code({
36
+ children,
37
+ className,
38
+ }: {
39
+ children: ReactNode;
40
+ className?: string | undefined;
41
+ }) {
42
+ return <span className={cn("font-mono text-foreground", className)}>{children}</span>;
43
+ }
@@ -0,0 +1,97 @@
1
+ "use client";
2
+
3
+ import { Check, Copy } from "lucide-react";
4
+ import { useCallback, useEffect, useRef, useState } from "react";
5
+ import { cn } from "../../lib/cn";
6
+
7
+ export interface CopyButtonProps {
8
+ /** The exact text put on the clipboard. Always the full, unformatted,
9
+ * machine-readable value — never what is displayed. A truncated id or a
10
+ * prettily-spaced phone number pasted into a query returns nothing. */
11
+ value: string;
12
+ /** Accessible name. Defaults to `Copy ${value}`, which is right for a
13
+ * short id and wrong for a paragraph — pass something shorter then. */
14
+ label?: string | undefined;
15
+ /** Hide until the containing `.group` is hovered or this button is
16
+ * focused. For dense tables, where a permanently visible icon on every
17
+ * row is noise. Keyboard users always reach it: focus reveals it. */
18
+ revealOnGroupHover?: boolean;
19
+ size?: 12 | 14 | 16;
20
+ className?: string | undefined;
21
+ }
22
+
23
+ const CONFIRMATION_MS = 1500;
24
+
25
+ /**
26
+ * Copy-to-clipboard affordance: a click, then a checkmark for a moment.
27
+ *
28
+ * Extracted because `IdDisplay` and `MsisdnDisplay` each carried their own
29
+ * byte-identical copy — the same `useState`, the same 1500ms timeout, the
30
+ * same icon swap, the same class string — and any component that later
31
+ * wanted the behaviour would have written a third.
32
+ *
33
+ * Two things the duplicated versions got wrong, fixed here rather than
34
+ * copied a third time:
35
+ *
36
+ * - **The timeout was never cleared.** Unmounting within the confirmation
37
+ * window (a row scrolling out of a virtualised table, a drawer closing)
38
+ * left a timer that fired `setCopied` on a dead component. Now cleared
39
+ * on unmount, and any in-flight timer is cleared before a new one
40
+ * starts, so a double-click cannot end the confirmation early.
41
+ * - **A rejected `writeText` was unhandled.** `navigator.clipboard` is
42
+ * unavailable on an insecure origin and can be refused by permissions
43
+ * policy; the bare `await` meant an unhandled rejection and a button
44
+ * that silently did nothing. Failure now leaves the icon unchanged,
45
+ * which is at least honest, and reports the reason to the console.
46
+ */
47
+ export function CopyButton({
48
+ value,
49
+ label,
50
+ revealOnGroupHover = false,
51
+ size = 12,
52
+ className,
53
+ }: CopyButtonProps) {
54
+ const [copied, setCopied] = useState(false);
55
+ const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
56
+
57
+ useEffect(
58
+ () => () => {
59
+ if (timer.current !== null) clearTimeout(timer.current);
60
+ },
61
+ [],
62
+ );
63
+
64
+ const copy = useCallback(() => {
65
+ void navigator.clipboard.writeText(value).then(
66
+ () => {
67
+ setCopied(true);
68
+ if (timer.current !== null) clearTimeout(timer.current);
69
+ timer.current = setTimeout(() => setCopied(false), CONFIRMATION_MS);
70
+ },
71
+ (error: unknown) => {
72
+ // Insecure origin, or a permissions policy that forbids it. Leave
73
+ // the icon alone rather than claim a copy that did not happen.
74
+ console.error("Clipboard write refused", error);
75
+ },
76
+ );
77
+ }, [value]);
78
+
79
+ return (
80
+ <button
81
+ type="button"
82
+ onClick={copy}
83
+ aria-label={label ?? `Copy ${value}`}
84
+ className={cn(
85
+ "shrink-0 text-subtle-foreground transition-opacity hover:text-foreground",
86
+ revealOnGroupHover && "opacity-0 focus-visible:opacity-100 group-hover:opacity-100",
87
+ className,
88
+ )}
89
+ >
90
+ {copied ? (
91
+ <Check size={size} strokeWidth={1.5} className="text-state-success-fg" />
92
+ ) : (
93
+ <Copy size={size} strokeWidth={1.5} />
94
+ )}
95
+ </button>
96
+ );
97
+ }