@nanisoft/prism-ui 0.10.2 → 0.13.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 (334) hide show
  1. package/LICENSE +21 -21
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/blocks/app-shell-01/app-shell.js +4 -4
  4. package/dist/blocks/app-shell-01/index.d.ts +2 -2
  5. package/dist/blocks/app-shell-01/index.js +1 -1
  6. package/dist/blocks/auth-form-01/auth-form.d.ts +11 -1
  7. package/dist/blocks/auth-form-01/auth-form.d.ts.map +1 -1
  8. package/dist/blocks/auth-form-01/auth-form.js +11 -8
  9. package/dist/blocks/auth-form-01/index.d.ts +2 -2
  10. package/dist/blocks/auth-form-01/index.js +1 -1
  11. package/dist/blocks/cta-01/cta.d.ts +26 -21
  12. package/dist/blocks/cta-01/cta.d.ts.map +1 -1
  13. package/dist/blocks/cta-01/cta.js +2 -2
  14. package/dist/blocks/cta-01/index.d.ts +2 -2
  15. package/dist/blocks/cta-01/index.js +1 -1
  16. package/dist/blocks/data-table-01/data-table.js +7 -7
  17. package/dist/blocks/data-table-01/index.d.ts +2 -2
  18. package/dist/blocks/data-table-01/index.js +1 -1
  19. package/dist/blocks/empty-state-01/empty-state.d.ts +143 -0
  20. package/dist/blocks/empty-state-01/empty-state.d.ts.map +1 -0
  21. package/dist/blocks/empty-state-01/empty-state.js +104 -0
  22. package/dist/blocks/empty-state-01/index.d.ts +3 -0
  23. package/dist/blocks/empty-state-01/index.d.ts.map +1 -0
  24. package/dist/blocks/empty-state-01/index.js +1 -0
  25. package/dist/blocks/feature-grid-01/feature-grid.d.ts +28 -1
  26. package/dist/blocks/feature-grid-01/feature-grid.d.ts.map +1 -1
  27. package/dist/blocks/feature-grid-01/feature-grid.js +34 -3
  28. package/dist/blocks/feature-grid-01/index.d.ts +2 -2
  29. package/dist/blocks/feature-grid-01/index.js +1 -1
  30. package/dist/blocks/hero-01/hero.d.ts +35 -15
  31. package/dist/blocks/hero-01/hero.d.ts.map +1 -1
  32. package/dist/blocks/hero-01/hero.js +14 -9
  33. package/dist/blocks/hero-01/index.d.ts +2 -1
  34. package/dist/blocks/hero-01/index.d.ts.map +1 -1
  35. package/dist/blocks/hero-01/index.js +1 -1
  36. package/dist/blocks/index.d.ts +20 -20
  37. package/dist/blocks/index.js +19 -19
  38. package/dist/blocks/instrument-panel-01/index.d.ts +2 -2
  39. package/dist/blocks/instrument-panel-01/index.js +1 -1
  40. package/dist/blocks/instrument-panel-01/instrument-panel.js +1 -1
  41. package/dist/blocks/logo-strip-01/index.d.ts +2 -2
  42. package/dist/blocks/logo-strip-01/index.js +1 -1
  43. package/dist/blocks/logo-strip-01/logo-strip.d.ts +1 -1
  44. package/dist/blocks/logo-strip-01/logo-strip.js +2 -2
  45. package/dist/blocks/note-grid-01/index.d.ts +2 -2
  46. package/dist/blocks/note-grid-01/index.js +1 -1
  47. package/dist/blocks/note-grid-01/note-grid.d.ts +1 -1
  48. package/dist/blocks/note-grid-01/note-grid.js +1 -1
  49. package/dist/blocks/page-header-01/index.d.ts +2 -2
  50. package/dist/blocks/page-header-01/index.js +1 -1
  51. package/dist/blocks/page-header-01/page-header.d.ts +1 -1
  52. package/dist/blocks/page-header-01/page-header.js +4 -4
  53. package/dist/blocks/pricing-01/index.d.ts +1 -1
  54. package/dist/blocks/pricing-01/index.js +1 -1
  55. package/dist/blocks/pricing-01/pricing.d.ts +8 -1
  56. package/dist/blocks/pricing-01/pricing.d.ts.map +1 -1
  57. package/dist/blocks/pricing-01/pricing.js +15 -5
  58. package/dist/blocks/process-flow-01/index.d.ts +3 -0
  59. package/dist/blocks/process-flow-01/index.d.ts.map +1 -0
  60. package/dist/blocks/process-flow-01/index.js +1 -0
  61. package/dist/blocks/process-flow-01/process-flow.d.ts +118 -0
  62. package/dist/blocks/process-flow-01/process-flow.d.ts.map +1 -0
  63. package/dist/blocks/process-flow-01/process-flow.js +71 -0
  64. package/dist/blocks/process-rail-01/index.d.ts +2 -2
  65. package/dist/blocks/process-rail-01/index.js +1 -1
  66. package/dist/blocks/process-rail-01/process-rail.d.ts +1 -1
  67. package/dist/blocks/process-rail-01/process-rail.js +2 -2
  68. package/dist/blocks/product-grid-01/index.d.ts +2 -2
  69. package/dist/blocks/product-grid-01/index.js +1 -1
  70. package/dist/blocks/product-grid-01/product-grid.d.ts +37 -5
  71. package/dist/blocks/product-grid-01/product-grid.d.ts.map +1 -1
  72. package/dist/blocks/product-grid-01/product-grid.js +20 -6
  73. package/dist/blocks/run-console-01/index.d.ts +3 -0
  74. package/dist/blocks/run-console-01/index.d.ts.map +1 -0
  75. package/dist/blocks/run-console-01/index.js +1 -0
  76. package/dist/blocks/run-console-01/run-console.d.ts +111 -0
  77. package/dist/blocks/run-console-01/run-console.d.ts.map +1 -0
  78. package/dist/blocks/run-console-01/run-console.js +48 -0
  79. package/dist/blocks/settings-panel-01/index.d.ts +2 -2
  80. package/dist/blocks/settings-panel-01/index.js +1 -1
  81. package/dist/blocks/settings-panel-01/settings-panel.d.ts +11 -1
  82. package/dist/blocks/settings-panel-01/settings-panel.d.ts.map +1 -1
  83. package/dist/blocks/settings-panel-01/settings-panel.js +15 -10
  84. package/dist/blocks/site-footer/index.d.ts +2 -2
  85. package/dist/blocks/site-footer/index.js +1 -1
  86. package/dist/blocks/site-footer/site-footer.d.ts +1 -1
  87. package/dist/blocks/site-footer/site-footer.js +2 -2
  88. package/dist/blocks/site-header/index.d.ts +2 -2
  89. package/dist/blocks/site-header/index.js +1 -1
  90. package/dist/blocks/site-header/site-header.d.ts +2 -2
  91. package/dist/blocks/site-header/site-header.js +3 -3
  92. package/dist/blocks/site-navbar/index.d.ts +3 -0
  93. package/dist/blocks/site-navbar/index.d.ts.map +1 -0
  94. package/dist/blocks/site-navbar/index.js +1 -0
  95. package/dist/blocks/site-navbar/mobile-nav.d.ts +48 -0
  96. package/dist/blocks/site-navbar/mobile-nav.d.ts.map +1 -0
  97. package/dist/blocks/site-navbar/mobile-nav.js +35 -0
  98. package/dist/blocks/site-navbar/mode-toggle.d.ts +39 -0
  99. package/dist/blocks/site-navbar/mode-toggle.d.ts.map +1 -0
  100. package/dist/blocks/site-navbar/mode-toggle.js +39 -0
  101. package/dist/blocks/site-navbar/navbar-controls.d.ts +79 -0
  102. package/dist/blocks/site-navbar/navbar-controls.d.ts.map +1 -0
  103. package/dist/blocks/site-navbar/navbar-controls.js +40 -0
  104. package/dist/blocks/site-navbar/search-entry.d.ts +29 -0
  105. package/dist/blocks/site-navbar/search-entry.d.ts.map +1 -0
  106. package/dist/blocks/site-navbar/search-entry.js +52 -0
  107. package/dist/blocks/site-navbar/site-navbar.d.ts +212 -0
  108. package/dist/blocks/site-navbar/site-navbar.d.ts.map +1 -0
  109. package/dist/blocks/site-navbar/site-navbar.js +61 -0
  110. package/dist/blocks/site-navbar/sites-menu.d.ts +40 -0
  111. package/dist/blocks/site-navbar/sites-menu.d.ts.map +1 -0
  112. package/dist/blocks/site-navbar/sites-menu.js +48 -0
  113. package/dist/blocks/site-navbar/theme-menu.d.ts +47 -0
  114. package/dist/blocks/site-navbar/theme-menu.d.ts.map +1 -0
  115. package/dist/blocks/site-navbar/theme-menu.js +55 -0
  116. package/dist/blocks/stack-grid-01/index.d.ts +2 -2
  117. package/dist/blocks/stack-grid-01/index.js +1 -1
  118. package/dist/blocks/stack-grid-01/stack-grid.d.ts +42 -11
  119. package/dist/blocks/stack-grid-01/stack-grid.d.ts.map +1 -1
  120. package/dist/blocks/stack-grid-01/stack-grid.js +15 -7
  121. package/dist/blocks/stats-01/index.d.ts +9 -1
  122. package/dist/blocks/stats-01/index.d.ts.map +1 -1
  123. package/dist/blocks/stats-01/index.js +8 -1
  124. package/dist/blocks/stats-01/stats.d.ts +1 -1
  125. package/dist/blocks/stats-01/stats.js +2 -2
  126. package/dist/blocks/status-ledger-01/index.d.ts +2 -2
  127. package/dist/blocks/status-ledger-01/index.js +1 -1
  128. package/dist/blocks/status-ledger-01/status-ledger.d.ts +1 -1
  129. package/dist/blocks/status-ledger-01/status-ledger.js +2 -2
  130. package/dist/catalog.d.ts +1 -1
  131. package/dist/catalog.d.ts.map +1 -1
  132. package/dist/catalog.js +473 -1
  133. package/dist/components/index.d.ts +104 -66
  134. package/dist/components/index.d.ts.map +1 -1
  135. package/dist/components/index.js +74 -40
  136. package/dist/components/ui/accordion.js +1 -1
  137. package/dist/components/ui/alert-dialog.d.ts +119 -0
  138. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  139. package/dist/components/ui/alert-dialog.js +82 -0
  140. package/dist/components/ui/alert.js +1 -1
  141. package/dist/components/ui/aspect-ratio.d.ts +60 -0
  142. package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
  143. package/dist/components/ui/aspect-ratio.js +61 -0
  144. package/dist/components/ui/avatar.js +1 -1
  145. package/dist/components/ui/badge.js +1 -1
  146. package/dist/components/ui/breadcrumb.js +1 -1
  147. package/dist/components/ui/button-group.d.ts +68 -0
  148. package/dist/components/ui/button-group.d.ts.map +1 -0
  149. package/dist/components/ui/button-group.js +54 -0
  150. package/dist/components/ui/button.js +1 -1
  151. package/dist/components/ui/calendar.d.ts +158 -0
  152. package/dist/components/ui/calendar.d.ts.map +1 -0
  153. package/dist/components/ui/calendar.js +216 -0
  154. package/dist/components/ui/card.d.ts +18 -6
  155. package/dist/components/ui/card.d.ts.map +1 -1
  156. package/dist/components/ui/card.js +23 -8
  157. package/dist/components/ui/carousel.d.ts +118 -0
  158. package/dist/components/ui/carousel.d.ts.map +1 -0
  159. package/dist/components/ui/carousel.js +152 -0
  160. package/dist/components/ui/chart-frame.d.ts +216 -0
  161. package/dist/components/ui/chart-frame.d.ts.map +1 -0
  162. package/dist/components/ui/chart-frame.js +286 -0
  163. package/dist/components/ui/checkbox.js +1 -1
  164. package/dist/components/ui/collapsible.d.ts +97 -0
  165. package/dist/components/ui/collapsible.d.ts.map +1 -0
  166. package/dist/components/ui/collapsible.js +54 -0
  167. package/dist/components/ui/combobox.d.ts +141 -0
  168. package/dist/components/ui/combobox.d.ts.map +1 -0
  169. package/dist/components/ui/combobox.js +243 -0
  170. package/dist/components/ui/command-palette.d.ts +106 -0
  171. package/dist/components/ui/command-palette.d.ts.map +1 -0
  172. package/dist/components/ui/command-palette.js +176 -0
  173. package/dist/components/ui/command.d.ts +82 -0
  174. package/dist/components/ui/command.d.ts.map +1 -0
  175. package/dist/components/ui/command.js +37 -0
  176. package/dist/components/ui/context-menu.d.ts +151 -0
  177. package/dist/components/ui/context-menu.d.ts.map +1 -0
  178. package/dist/components/ui/context-menu.js +97 -0
  179. package/dist/components/ui/cta-link.js +1 -1
  180. package/dist/components/ui/date-picker.d.ts +111 -0
  181. package/dist/components/ui/date-picker.d.ts.map +1 -0
  182. package/dist/components/ui/date-picker.js +74 -0
  183. package/dist/components/ui/diagram.d.ts +84 -15
  184. package/dist/components/ui/diagram.d.ts.map +1 -1
  185. package/dist/components/ui/diagram.js +77 -7
  186. package/dist/components/ui/dialog.js +1 -1
  187. package/dist/components/ui/diff.d.ts +105 -0
  188. package/dist/components/ui/diff.d.ts.map +1 -0
  189. package/dist/components/ui/diff.js +113 -0
  190. package/dist/components/ui/dropdown-menu.d.ts +18 -0
  191. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  192. package/dist/components/ui/dropdown-menu.js +1 -1
  193. package/dist/components/ui/fact-list.js +1 -1
  194. package/dist/components/ui/field.js +1 -1
  195. package/dist/components/ui/form.d.ts +151 -0
  196. package/dist/components/ui/form.d.ts.map +1 -0
  197. package/dist/components/ui/form.js +73 -0
  198. package/dist/components/ui/hover-card.d.ts +105 -0
  199. package/dist/components/ui/hover-card.d.ts.map +1 -0
  200. package/dist/components/ui/hover-card.js +49 -0
  201. package/dist/components/ui/input-group.d.ts +99 -0
  202. package/dist/components/ui/input-group.d.ts.map +1 -0
  203. package/dist/components/ui/input-group.js +83 -0
  204. package/dist/components/ui/input.js +1 -1
  205. package/dist/components/ui/item.d.ts +113 -0
  206. package/dist/components/ui/item.d.ts.map +1 -0
  207. package/dist/components/ui/item.js +61 -0
  208. package/dist/components/ui/kbd.js +1 -1
  209. package/dist/components/ui/label.d.ts +58 -0
  210. package/dist/components/ui/label.d.ts.map +1 -0
  211. package/dist/components/ui/label.js +29 -0
  212. package/dist/components/ui/live-region.d.ts +9 -0
  213. package/dist/components/ui/live-region.d.ts.map +1 -1
  214. package/dist/components/ui/live-region.js +10 -2
  215. package/dist/components/ui/mark.js +1 -1
  216. package/dist/components/ui/menubar.d.ts +197 -0
  217. package/dist/components/ui/menubar.d.ts.map +1 -0
  218. package/dist/components/ui/menubar.js +109 -0
  219. package/dist/components/ui/meter.d.ts +121 -0
  220. package/dist/components/ui/meter.d.ts.map +1 -0
  221. package/dist/components/ui/meter.js +82 -0
  222. package/dist/components/ui/native-select.d.ts +72 -0
  223. package/dist/components/ui/native-select.d.ts.map +1 -0
  224. package/dist/components/ui/native-select.js +55 -0
  225. package/dist/components/ui/navigation-menu.d.ts +186 -0
  226. package/dist/components/ui/navigation-menu.d.ts.map +1 -0
  227. package/dist/components/ui/navigation-menu.js +94 -0
  228. package/dist/components/ui/number-field.d.ts +111 -0
  229. package/dist/components/ui/number-field.d.ts.map +1 -0
  230. package/dist/components/ui/number-field.js +84 -0
  231. package/dist/components/ui/one-time-code.d.ts +127 -0
  232. package/dist/components/ui/one-time-code.d.ts.map +1 -0
  233. package/dist/components/ui/one-time-code.js +57 -0
  234. package/dist/components/ui/pagination.js +1 -1
  235. package/dist/components/ui/popover.js +1 -1
  236. package/dist/components/ui/product-mark.d.ts +1 -1
  237. package/dist/components/ui/product-mark.js +1 -1
  238. package/dist/components/ui/product-switcher.d.ts +1 -1
  239. package/dist/components/ui/product-switcher.js +2 -2
  240. package/dist/components/ui/progress.js +1 -1
  241. package/dist/components/ui/prose.js +1 -1
  242. package/dist/components/ui/pulse-graph.js +1 -1
  243. package/dist/components/ui/pulse-series.js +1 -1
  244. package/dist/components/ui/radio-group.js +1 -1
  245. package/dist/components/ui/resizable.d.ts +129 -0
  246. package/dist/components/ui/resizable.d.ts.map +1 -0
  247. package/dist/components/ui/resizable.js +205 -0
  248. package/dist/components/ui/scroll-area.d.ts +97 -0
  249. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  250. package/dist/components/ui/scroll-area.js +68 -0
  251. package/dist/components/ui/search-dialog.d.ts +139 -0
  252. package/dist/components/ui/search-dialog.d.ts.map +1 -0
  253. package/dist/components/ui/search-dialog.js +178 -0
  254. package/dist/components/ui/section.d.ts +26 -0
  255. package/dist/components/ui/section.d.ts.map +1 -1
  256. package/dist/components/ui/section.js +32 -1
  257. package/dist/components/ui/select.js +1 -1
  258. package/dist/components/ui/separator.js +1 -1
  259. package/dist/components/ui/sheet.d.ts +103 -0
  260. package/dist/components/ui/sheet.d.ts.map +1 -0
  261. package/dist/components/ui/sheet.js +58 -0
  262. package/dist/components/ui/sidebar.d.ts +228 -0
  263. package/dist/components/ui/sidebar.d.ts.map +1 -0
  264. package/dist/components/ui/sidebar.js +172 -0
  265. package/dist/components/ui/signal-field.js +1 -1
  266. package/dist/components/ui/skeleton.js +1 -1
  267. package/dist/components/ui/slider.js +1 -1
  268. package/dist/components/ui/spinner.d.ts +79 -0
  269. package/dist/components/ui/spinner.d.ts.map +1 -0
  270. package/dist/components/ui/spinner.js +79 -0
  271. package/dist/components/ui/switch.js +1 -1
  272. package/dist/components/ui/table-sort.d.ts +97 -0
  273. package/dist/components/ui/table-sort.d.ts.map +1 -0
  274. package/dist/components/ui/table-sort.js +102 -0
  275. package/dist/components/ui/table.js +1 -1
  276. package/dist/components/ui/tabs.js +1 -1
  277. package/dist/components/ui/textarea.js +1 -1
  278. package/dist/components/ui/timeline.d.ts +106 -0
  279. package/dist/components/ui/timeline.d.ts.map +1 -0
  280. package/dist/components/ui/timeline.js +111 -0
  281. package/dist/components/ui/toast.d.ts +219 -0
  282. package/dist/components/ui/toast.d.ts.map +1 -0
  283. package/dist/components/ui/toast.js +270 -0
  284. package/dist/components/ui/toggle-group.d.ts +118 -0
  285. package/dist/components/ui/toggle-group.d.ts.map +1 -0
  286. package/dist/components/ui/toggle-group.js +194 -0
  287. package/dist/components/ui/toggle.d.ts +73 -0
  288. package/dist/components/ui/toggle.d.ts.map +1 -0
  289. package/dist/components/ui/toggle.js +44 -0
  290. package/dist/components/ui/tooltip.js +1 -1
  291. package/dist/components/ui/tree.js +1 -1
  292. package/dist/components/ui/typography.js +1 -1
  293. package/dist/fonts/Inter-OFL.txt +93 -93
  294. package/dist/index.d.ts +72 -70
  295. package/dist/index.d.ts.map +1 -1
  296. package/dist/index.js +61 -60
  297. package/dist/lib/rank.d.ts +69 -0
  298. package/dist/lib/rank.d.ts.map +1 -0
  299. package/dist/lib/rank.js +77 -0
  300. package/dist/live/index.d.ts +22 -0
  301. package/dist/live/index.d.ts.map +1 -0
  302. package/dist/live/index.js +20 -0
  303. package/dist/live/run-stream-01/index.d.ts +3 -0
  304. package/dist/live/run-stream-01/index.d.ts.map +1 -0
  305. package/dist/live/run-stream-01/index.js +1 -0
  306. package/dist/live/run-stream-01/run-stream.d.ts +125 -0
  307. package/dist/live/run-stream-01/run-stream.d.ts.map +1 -0
  308. package/dist/live/run-stream-01/run-stream.js +111 -0
  309. package/dist/pages/auth-page/index.d.ts +15 -2
  310. package/dist/pages/auth-page/index.d.ts.map +1 -1
  311. package/dist/pages/auth-page/index.js +8 -4
  312. package/dist/pages/blog-post-page/index.js +5 -5
  313. package/dist/pages/dashboard-page/index.d.ts +4 -4
  314. package/dist/pages/dashboard-page/index.js +4 -4
  315. package/dist/pages/docs-shell/docs-shell.d.ts +37 -4
  316. package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -1
  317. package/dist/pages/docs-shell/docs-shell.js +107 -16
  318. package/dist/pages/docs-shell/index.d.ts +2 -2
  319. package/dist/pages/docs-shell/index.js +1 -1
  320. package/dist/pages/index.d.ts +14 -14
  321. package/dist/pages/index.js +7 -7
  322. package/dist/pages/marketing-page/index.d.ts +6 -6
  323. package/dist/pages/marketing-page/index.js +5 -5
  324. package/dist/pages/not-found-page/index.js +4 -4
  325. package/dist/pages/settings-page/index.d.ts +3 -3
  326. package/dist/pages/settings-page/index.js +4 -4
  327. package/dist/provider/index.d.ts +4 -4
  328. package/dist/provider/index.js +2 -2
  329. package/dist/provider/provider.d.ts +1 -1
  330. package/dist/provider/provider.js +1 -1
  331. package/dist/provider/theme-script.d.ts +1 -1
  332. package/dist/provider/theme-script.js +1 -1
  333. package/dist/styles.css +689 -0
  334. package/package.json +9 -1
@@ -0,0 +1,111 @@
1
+ import { type CalendarWeekdays } from './calendar.js';
2
+ /** The props the Date picker accepts. */
3
+ export interface DatePickerProps {
4
+ /**
5
+ * The accessible name of the field.
6
+ *
7
+ * Required. It is rendered as the field's own name rather than as visible text,
8
+ * because a visible label belongs above the control and that is the caller's
9
+ * `Label` to place. What the Component owns is the name, and a field with no
10
+ * name is a field a screen reader reader cannot say out loud.
11
+ */
12
+ label: string;
13
+ /**
14
+ * Formats a chosen date for the field.
15
+ *
16
+ * Required, and required as a function rather than as a format string, because a
17
+ * date is a phrase in the reader's language and their convention. This Component
18
+ * ships no date format: a hardcoded one would be a claim about how dates are
19
+ * written in every consumer's product.
20
+ */
21
+ format: (date: Date) => string;
22
+ /** The caption for a month on show, in the reader's language. */
23
+ monthLabel: (month: Date) => string;
24
+ /** The seven weekday headings, starting from `firstWeekday`. */
25
+ weekdayLabels: CalendarWeekdays;
26
+ /** Which day the reader's week starts on, as `Date.prototype.getDay()` numbers it. */
27
+ firstWeekday?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
28
+ /** The accessible name of the control that steps back one month. */
29
+ previousLabel: string;
30
+ /** The accessible name of the control that steps forward one month. */
31
+ nextLabel: string;
32
+ /**
33
+ * The accessible name of the control that clears the field.
34
+ *
35
+ * Omit it and the control is not rendered. The words are the caller's because
36
+ * they are a sentence a reader hears, and a Component that chose them would be
37
+ * shipping English into every consumer's form.
38
+ */
39
+ clearLabel?: string;
40
+ /**
41
+ * What the field shows before a date is chosen.
42
+ *
43
+ * Hidden from the accessibility tree, because the field already has a name and
44
+ * a placeholder that becomes a second name is a field announced twice.
45
+ */
46
+ placeholder?: string;
47
+ /** The chosen date, when the field is controlled. */
48
+ value?: Date | null;
49
+ /** The date chosen initially, for an uncontrolled field. */
50
+ defaultValue?: Date | null;
51
+ /** Called with the chosen date, or `null` when the reader clears the field. */
52
+ onValueChange?: (date: Date | null) => void;
53
+ /** Whether a date cannot be chosen. */
54
+ isDateDisabled?: (date: Date) => boolean;
55
+ /** The full accessible name of a day, in the reader's own date format. */
56
+ dayLabel?: (date: Date) => string;
57
+ /** The date to mark as today. Defaults to the reader's clock. */
58
+ today?: Date;
59
+ /** Whether the reader may not open the calendar or choose a date. */
60
+ disabled?: boolean;
61
+ /** Whether a date must be chosen before the form submits. */
62
+ required?: boolean;
63
+ /**
64
+ * The form field name. The chosen date is submitted as `YYYY-MM-DD`.
65
+ *
66
+ * Never the displayed string. A form that posts whatever the reader's locale
67
+ * wrote makes every reader of that data parse a phrase.
68
+ */
69
+ name?: string;
70
+ /** Identifies the form that owns the hidden input. */
71
+ form?: string;
72
+ /** The field's own id, so a label elsewhere can point at it. */
73
+ id?: string;
74
+ /** Layout only. */
75
+ className?: string;
76
+ }
77
+ /**
78
+ * A field that opens a month grid and holds the date the reader picks.
79
+ *
80
+ * **It is built on the Calendar rather than beside it.** The month grid is a
81
+ * month grid: six rows, a roving tab stop, arrow keys that cross into the next
82
+ * month, and a rule about what a disabled date means. A picker with its own grid
83
+ * would be a second answer to all six questions, and the second answer is the one
84
+ * that ships the bug.
85
+ *
86
+ * **Choosing a date commits it and closes, in one gesture.** A field that left the
87
+ * grid open after a choice asks the reader to confirm an answer they already gave,
88
+ * and the Popover returns focus to the trigger on close, so a reader who is
89
+ * tabbing onward from the field is where they expect to be rather than back at
90
+ * the top of the document.
91
+ *
92
+ * **The month on show follows the answer, every time the field is opened.** A
93
+ * filled field opens on the month of its value, and an empty one on the current
94
+ * month. Without this, re-picking a date in a different month would reset the grid
95
+ * to the month the caller seeded it with, which is the month the reader was in
96
+ * the first time and is a silent undo of the navigation they just did.
97
+ *
98
+ * **The field shows the caller's formatted date and submits an ISO day.** Those are
99
+ * two different strings on purpose: one is read by a person and written in their
100
+ * language, the other is read by a machine that has no locale. A field that
101
+ * submitted what it displayed hands every downstream reader a phrase to parse.
102
+ *
103
+ * **The name and the value are announced separately.** The name is the field's
104
+ * label and the value is its description, which is how a field is read: "Delivery
105
+ * date, 17 March 2026". Letting the visible date become the button's name would
106
+ * replace the field's name with its current answer, so a reader who tabs through
107
+ * a form of five date fields hears five dates and no questions.
108
+ */
109
+ declare function DatePicker({ label, format, monthLabel, weekdayLabels, firstWeekday, previousLabel, nextLabel, clearLabel, placeholder, value, defaultValue, onValueChange, isDateDisabled, dayLabel, today, disabled, required, name, form, id, className, }: DatePickerProps): import("react").JSX.Element;
110
+ export { DatePicker };
111
+ //# sourceMappingURL=date-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-picker.d.ts","sourceRoot":"","sources":["../../../src/components/ui/date-picker.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAY,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAI5D,yCAAyC;AACzC,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;OAOG;IACH,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAA;IAC9B,iEAAiE;IACjE,UAAU,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,MAAM,CAAA;IACnC,gEAAgE;IAChE,aAAa,EAAE,gBAAgB,CAAA;IAC/B,sFAAsF;IACtF,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACxC,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAA;IACrB,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,KAAK,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IACnB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAC1B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAA;IAC3C,uCAAuC;IACvC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAA;IACxC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAA;IACjC,iEAAiE;IACjE,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gEAAgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,mBAAmB;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,iBAAS,UAAU,CAAC,EAClB,KAAK,EACL,MAAM,EACN,UAAU,EACV,aAAa,EACb,YAAgB,EAChB,aAAa,EACb,SAAS,EACT,UAAU,EACV,WAAW,EACX,KAAK,EACL,YAAmB,EACnB,aAAa,EACb,cAAc,EACd,QAAQ,EACR,KAAkB,EAClB,QAAgB,EAChB,QAAgB,EAChB,IAAI,EACJ,IAAI,EACJ,EAAE,EACF,SAAS,GACV,EAAE,eAAe,+BA0HjB;AAED,OAAO,EAAE,UAAU,EAAE,CAAA"}
@@ -0,0 +1,74 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { XIcon } from 'lucide-react';
4
+ import { useCallback, useId, useState } from 'react';
5
+ import { Calendar } from './calendar.js';
6
+ import { Popover, PopoverContent, PopoverTrigger } from './popover.js';
7
+ import { cn } from '../../lib/utils.js';
8
+ /** `YYYY-MM-DD`, which is the only date format a form should post. */
9
+ const iso = (date) => `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
10
+ const startOfMonth = (date) => new Date(date.getFullYear(), date.getMonth(), 1);
11
+ /**
12
+ * A field that opens a month grid and holds the date the reader picks.
13
+ *
14
+ * **It is built on the Calendar rather than beside it.** The month grid is a
15
+ * month grid: six rows, a roving tab stop, arrow keys that cross into the next
16
+ * month, and a rule about what a disabled date means. A picker with its own grid
17
+ * would be a second answer to all six questions, and the second answer is the one
18
+ * that ships the bug.
19
+ *
20
+ * **Choosing a date commits it and closes, in one gesture.** A field that left the
21
+ * grid open after a choice asks the reader to confirm an answer they already gave,
22
+ * and the Popover returns focus to the trigger on close, so a reader who is
23
+ * tabbing onward from the field is where they expect to be rather than back at
24
+ * the top of the document.
25
+ *
26
+ * **The month on show follows the answer, every time the field is opened.** A
27
+ * filled field opens on the month of its value, and an empty one on the current
28
+ * month. Without this, re-picking a date in a different month would reset the grid
29
+ * to the month the caller seeded it with, which is the month the reader was in
30
+ * the first time and is a silent undo of the navigation they just did.
31
+ *
32
+ * **The field shows the caller's formatted date and submits an ISO day.** Those are
33
+ * two different strings on purpose: one is read by a person and written in their
34
+ * language, the other is read by a machine that has no locale. A field that
35
+ * submitted what it displayed hands every downstream reader a phrase to parse.
36
+ *
37
+ * **The name and the value are announced separately.** The name is the field's
38
+ * label and the value is its description, which is how a field is read: "Delivery
39
+ * date, 17 March 2026". Letting the visible date become the button's name would
40
+ * replace the field's name with its current answer, so a reader who tabs through
41
+ * a form of five date fields hears five dates and no questions.
42
+ */
43
+ function DatePicker({ label, format, monthLabel, weekdayLabels, firstWeekday = 0, previousLabel, nextLabel, clearLabel, placeholder, value, defaultValue = null, onValueChange, isDateDisabled, dayLabel, today = new Date(), disabled = false, required = false, name, form, id, className, }) {
44
+ const [ownValue, setOwnValue] = useState(defaultValue);
45
+ const [ownOpen, setOwnOpen] = useState(false);
46
+ const [month, setMonth] = useState(() => startOfMonth(defaultValue ?? today));
47
+ const generated = useId();
48
+ const triggerId = id ?? generated;
49
+ const valueId = `${generated}-value`;
50
+ const chosen = value === undefined ? ownValue : value;
51
+ const open = ownOpen;
52
+ const shown = chosen === null ? '' : format(chosen);
53
+ const choose = (date) => {
54
+ if (value === undefined)
55
+ setOwnValue(date);
56
+ onValueChange?.(date);
57
+ setOwnOpen(false);
58
+ };
59
+ const clear = useCallback(() => {
60
+ if (value === undefined)
61
+ setOwnValue(null);
62
+ onValueChange?.(null);
63
+ }, [onValueChange, value]);
64
+ const onOpenChange = (next) => {
65
+ // Reseeded on every open rather than held, so the grid always arrives on the
66
+ // month the reader is about to edit.
67
+ if (next)
68
+ setMonth(startOfMonth(chosen ?? today));
69
+ setOwnOpen(next);
70
+ };
71
+ const canClear = chosen !== null && clearLabel !== undefined;
72
+ return (_jsxs("div", { "data-slot": "date-picker", className: cn('relative w-full', className), children: [canClear ? (_jsx("button", { type: "button", "data-slot": "date-picker-clear", "aria-label": clearLabel, disabled: disabled, onClick: clear, className: cn('text-muted-foreground hover:text-foreground absolute top-1/2 right-9 z-10 inline-flex size-6 -translate-y-1/2 items-center justify-center rounded-sm outline-none', 'transition-colors duration-fast ease-out focus-visible:ring-ring focus-visible:ring-[3px]', 'disabled:pointer-events-none disabled:opacity-50'), children: _jsx(XIcon, { className: "size-4", "aria-hidden": "true" }) })) : null, _jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { "data-slot": "date-picker-trigger", id: triggerId, "aria-label": label, "aria-describedby": shown === '' ? undefined : valueId, "aria-invalid": required && chosen === null ? true : undefined, disabled: disabled, className: cn('border-input bg-background text-foreground w-full justify-between outline-none', 'focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-[3px]', canClear && 'pr-16'), children: _jsx("span", { "data-slot": "date-picker-value", "aria-hidden": "true", className: shown === '' ? 'text-muted-foreground' : undefined, children: shown === '' ? placeholder : shown }) }), _jsx(PopoverContent, { sideOffset: 4, "aria-label": label, className: "w-auto p-0", children: _jsx(Calendar, { label: label, monthLabel: monthLabel(month), weekdayLabels: weekdayLabels, firstWeekday: firstWeekday, previousLabel: previousLabel, nextLabel: nextLabel, month: month, onMonthChange: setMonth, value: chosen, onValueChange: choose, isDateDisabled: isDateDisabled, dayLabel: dayLabel, today: today }) })] }), shown === '' ? null : (_jsx("span", { id: valueId, className: "sr-only", children: shown })), name === undefined ? null : (_jsx("input", { type: "hidden", name: name, ...(form === undefined ? null : { form }), value: chosen === null ? '' : iso(chosen), readOnly: true }))] }));
73
+ }
74
+ export { DatePicker };
@@ -1,3 +1,4 @@
1
+ import type { PackId } from '../../theming/index.js';
1
2
  /**
2
3
  * One named thing in a Diagram, at a position the caller chooses.
3
4
  *
@@ -7,11 +8,12 @@
7
8
  * another, so a caller that means a column spreads it rather than repeating a
8
9
  * number.
9
10
  *
10
- * `emphasis` marks the one node the drawing is about, and it is the only
11
- * difference a node may carry: the emphasised node takes the brand ink, which
12
- * DESIGN.md's Brand Ink Rule names as the colour for something that must read
13
- * as the brand rather than as body text. Two emphasised nodes are a caller's
14
- * mistake, not a second emphasis level.
11
+ * A node carries two differences and no more. `emphasis` marks the one node the
12
+ * drawing is about, and it is the emphasised node that takes the brand ink,
13
+ * which is what DESIGN.md's Brand Ink Rule names as the colour for something
14
+ * that must read as the brand rather than as body text; two emphasised nodes are
15
+ * a caller's mistake, not a second emphasis level. `pack` is the node's own hue,
16
+ * and it is per node for the reasons given on that field.
15
17
  */
16
18
  export type DiagramNode = {
17
19
  /**
@@ -25,12 +27,48 @@ export type DiagramNode = {
25
27
  * reader does not read it: see `DiagramProps` for what carries the meaning.
26
28
  */
27
29
  name: string;
30
+ /**
31
+ * The second line printed under the name, which is the one-line role the thing
32
+ * plays: "the shared language", "the engine", "built next".
33
+ *
34
+ * It is a field rather than a word written into `label`, because the two
35
+ * audiences are different and a role description that exists only inside the
36
+ * accessible name has been given to one of them and withheld from the other.
37
+ * It is drawn on the picture, it is read aloud as part of the name when the
38
+ * caller passes no `label`, and because both come out of the same field they
39
+ * are the same words and cannot drift.
40
+ */
41
+ subtitle?: string;
28
42
  /** The node's position along the horizontal axis, in the caller's space. */
29
43
  x: number;
30
44
  /** The node's position along the vertical axis, in the caller's space. */
31
45
  y: number;
32
46
  /** Marks the node the diagram is about. See the Brand Ink Rule. */
33
47
  emphasis?: boolean;
48
+ /**
49
+ * The node's pack, which is the hue its mark wears.
50
+ *
51
+ * `PackId` rather than `string`, because a pack is one of the six published
52
+ * packs: a free-text field would accept a name matching no emitted rule, and a
53
+ * mark under a boundary nothing matches keeps the colour of whatever pack is
54
+ * above it, which is a silent wrong answer rather than a rejected one.
55
+ *
56
+ * **It is per node, and that is settled rather than incidental.** A pack on
57
+ * the Diagram would be one boundary on the section, and the boundary is the
58
+ * unit of a second pack on a MARK: `ProductMark` is the item that established
59
+ * it, and a mark here is a node. Per node is also what a schematic wants. One
60
+ * drawing of a product set shows one mark per product and each wears its own
61
+ * hue, which a single boundary could not express at all.
62
+ *
63
+ * The boundary lands on the `<circle>` this node draws, and not on the `<svg>`
64
+ * and not on the node's `<g>`, so it moves that one mark's fill and stroke and
65
+ * nothing else. A circle has no radius concept, so the pack re-inks the mark
66
+ * and cannot re-round it, which is the half of the pack boundary law a
67
+ * consumer implementing only the colour half gets wrong. `default` is the
68
+ * absence of the attribute, exactly as `themeAttributes` spells it, so a node
69
+ * on the base pack carries no `data-pack` and resolves from the page.
70
+ */
71
+ pack?: PackId;
34
72
  };
35
73
  /**
36
74
  * One relation between two nodes, with the word that says what it is.
@@ -55,7 +93,7 @@ export type DiagramRelation = {
55
93
  /** Draws the line dashed, for a relation that holds but not by this route. */
56
94
  indirect?: boolean;
57
95
  };
58
- /** What both arms of `DiagramProps` carry. */
96
+ /** What every arm of `DiagramProps` carries. */
59
97
  type DiagramFigure = {
60
98
  /** The things drawn. At least one, or the Diagram renders an empty canvas. */
61
99
  nodes: readonly DiagramNode[];
@@ -71,11 +109,18 @@ type DiagramFigure = {
71
109
  /**
72
110
  * The props a Diagram takes.
73
111
  *
74
- * The name is required unless the drawing is decorative, and it is forbidden
75
- * when it is. That is a union rather than `label?: string` because only a union
76
- * lets the type system see the exception: an optional label on one type can
77
- * only be optional everywhere or required everywhere, and both halves of that
78
- * are wrong. `Separator` takes the same shape as `decorative`.
112
+ * The name is required unless the drawing is decorative or the nodes can be read
113
+ * as the name, and it is forbidden when the drawing is decorative. That is a
114
+ * union rather than `label?: string` because only a union lets the type system
115
+ * see the exception: an optional label on one type can only be optional
116
+ * everywhere or required everywhere, and both halves of that are wrong.
117
+ * `Separator` takes the same shape as `decorative`.
118
+ *
119
+ * The third arm is the one that makes the name derivable. It spells the absence
120
+ * as `label?: never` rather than `label?: string`, so "the caller named it" and
121
+ * "the caller passed nothing" cannot be confused for one another and a caller
122
+ * cannot hand the drawing an empty name by passing one: an unnamed image is the
123
+ * one outcome this prop must not have.
79
124
  */
80
125
  export type DiagramProps = DiagramFigure & ({
81
126
  /**
@@ -90,6 +135,16 @@ export type DiagramProps = DiagramFigure & ({
90
135
  /** The name of the drawing, and the only thing a screen reader reads from it. */
91
136
  label: string;
92
137
  decorative?: false;
138
+ } | {
139
+ /**
140
+ * No name is passed, so the drawing is named by what its own marks say:
141
+ * every node's `name`, and its `subtitle` where it has one, in the order
142
+ * the caller drew them. A caller who gives a node a role description is
143
+ * describing the picture, and a picture's own words are the honest source
144
+ * for the name announced over it.
145
+ */
146
+ label?: never;
147
+ decorative?: false;
93
148
  });
94
149
  /**
95
150
  * A diagram of named things and the relations between them.
@@ -107,13 +162,27 @@ export type DiagramProps = DiagramFigure & ({
107
162
  * roster, and a `'use client'` line added here would put it back on that roster.
108
163
  *
109
164
  * **Accessibility.** A diagram carries meaning, so by default it is one image
110
- * with a name: `role="img"` and the `label` the caller passes. Everything inside
111
- * a `role="img"` is presentational, so the node names and relation words are
112
- * drawn for sighted readers and the surrounding sentence is what a screen reader
113
- * gets. Pass `decorative` when the sentence already says what the drawing
165
+ * with a name: `role="img"` and the drawing's name. Everything inside a
166
+ * `role="img"` is presentational, so the node names, the node subtitles and the
167
+ * relation words are drawn for sighted readers and the name is what a screen
168
+ * reader gets. That is why the name is derived from the nodes' own text when the
169
+ * caller passes no `label`: everything on the marks is invisible to the one
170
+ * reader who is not looking at the picture, so a role description written only
171
+ * into a label is a role description a sighted reader never sees. Pass `label`
172
+ * when the drawing needs a name that says what it is rather than what it holds,
173
+ * and omit it when the two would be the same sentence written twice. Pass
174
+ * `decorative` when the surrounding sentence already says what the drawing
114
175
  * shows, and the whole tree leaves the accessibility tree with nothing named
115
176
  * inside it.
116
177
  *
178
+ * **A node may wear its own pack.** `pack` on a node puts the boundary on the
179
+ * circle that node draws, which is the mark, and the mark is the one place a
180
+ * pack boundary belongs without moving anything but colour: a circle has no
181
+ * radius concept, so the pack re-inks the mark and cannot re-round it. Nothing
182
+ * else in the drawing answers to it, the node's name beside the mark keeps the
183
+ * page's ink, and a page that files two pack regions can make a diagram section
184
+ * the second one rather than moving it to the header's product switcher.
185
+ *
117
186
  * **Shape.** Nodes are circles and relations are paths. Both are shapes with no
118
187
  * radius concept, so no corner radius here is a function of `--radius` and a
119
188
  * pack boundary above the drawing moves nothing about its shape. A `<rect>` was
@@ -1 +1 @@
1
- {"version":3,"file":"diagram.d.ts","sourceRoot":"","sources":["../../../src/components/ui/diagram.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB;;;;OAIG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,CAAC,EAAE,MAAM,CAAA;IACT,0EAA0E;IAC1E,CAAC,EAAE,MAAM,CAAA;IACT,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAA;IACV,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,8CAA8C;AAC9C,KAAK,aAAa,GAAG;IACnB,8EAA8E;IAC9E,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;IAC7B,oGAAoG;IACpG,SAAS,EAAE,SAAS,eAAe,EAAE,CAAA;IACrC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,aAAa,GACtC,CACI;IACE;;;;;OAKG;IACH,UAAU,EAAE,IAAI,CAAA;IAChB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd,GACD;IACE,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB,CACJ,CAAA;AAoFH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,iBAAS,OAAO,CAAC,EACf,KAAK,EACL,SAAS,EACT,KAAK,EACL,UAAkB,EAClB,SAAS,GACV,EAAE,YAAY,+BAsFd;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"diagram.d.ts","sourceRoot":"","sources":["../../../src/components/ui/diagram.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAI3C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB;;;;OAIG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4EAA4E;IAC5E,CAAC,EAAE,MAAM,CAAA;IACT,0EAA0E;IAC1E,CAAC,EAAE,MAAM,CAAA;IACT,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAA;IACV,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,gDAAgD;AAChD,KAAK,aAAa,GAAG;IACnB,8EAA8E;IAC9E,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;IAC7B,oGAAoG;IACpG,SAAS,EAAE,SAAS,eAAe,EAAE,CAAA;IACrC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,YAAY,GAAG,aAAa,GACtC,CACI;IACE;;;;;OAKG;IACH,UAAU,EAAE,IAAI,CAAA;IAChB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd,GACD;IACE,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB,GACD;IACE;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB,CACJ,CAAA;AAiIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,iBAAS,OAAO,CAAC,EACf,KAAK,EACL,SAAS,EACT,KAAK,EACL,UAAkB,EAClB,SAAS,GACV,EAAE,YAAY,+BAgHd;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
@@ -1,5 +1,32 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cn } from '../../lib/utils';
2
+ import { cn } from '../../lib/utils.js';
3
+ /**
4
+ * The drawing's accessible name, derived from the text its own marks carry.
5
+ *
6
+ * Derived rather than passed because the two audiences are different and a
7
+ * Component able to reach only one of them reaches neither. Everything inside a
8
+ * `role="img"` is presentational, so the words drawn on the marks are words no
9
+ * screen reader reads, and the label is the one thing it does read. A caller who
10
+ * put a node's role description into the label and not onto the node had
11
+ * published half of it: the half a sighted reader loses. Reading the name off the
12
+ * marks is what makes that drift impossible rather than merely discouraged, and
13
+ * it is why the drawn line and the announced line are the same field.
14
+ *
15
+ * Relation words are not part of it, and that is the honest limit of a
16
+ * derivation rather than an oversight. A derived name says what the drawing
17
+ * holds; a caller whose relations matter to a screen reader user passes a
18
+ * `label` that says so. Inventing a sentence out of the relations would be this
19
+ * Component writing the words, which is the one thing it does not do.
20
+ */
21
+ function derivedName(nodes) {
22
+ return nodes.reduce((name, node) => {
23
+ // Parentheses between a thing and its role, commas between things, so a
24
+ // reader hearing the list can tell which words belong to which mark. Both
25
+ // are punctuation assembled here rather than a word this Component wrote.
26
+ const words = node.subtitle ? `${node.name} (${node.subtitle})` : node.name;
27
+ return name === '' ? words : `${name}, ${words}`;
28
+ }, '');
29
+ }
3
30
  /**
4
31
  * The canvas the Diagram draws into, in its own user units.
5
32
  *
@@ -21,6 +48,12 @@ const CANVAS_HEIGHT = 400;
21
48
  * and a name is wider than the mark. The band is the honest cost of a server
22
49
  * component not being able to measure text, and it is why a name that runs long
23
50
  * still lands inside the canvas rather than off its edge.
51
+ *
52
+ * A node's subtitle, where it has one, is the deepest ink a node draws, at
53
+ * `NODE_SUBTITLE_OFFSET` below the mark, and that is inside the band too. The
54
+ * cost of not being able to measure text is paid once rather than per line, and
55
+ * paying it for the second line is what keeps the two-line node inside the
56
+ * canvas rather than under its own floor.
24
57
  */
25
58
  const PADDING = 56;
26
59
  /** The node mark's radius. A circle, so there is no corner radius for the pack to move. */
@@ -35,7 +68,17 @@ const NODE_RADIUS = 5;
35
68
  */
36
69
  const NODE_NAME_SIZE = 13;
37
70
  const NODE_NAME_OFFSET = 20;
71
+ const NODE_SUBTITLE_SIZE = 11;
38
72
  const RELATION_NAME_SIZE = 11;
73
+ /**
74
+ * The subtitle's baseline, measured down from the mark's centre.
75
+ *
76
+ * The name's baseline, then the subtitle's own size, then a line of leading. It is
77
+ * the deepest any node draws and it is why `PADDING` has to be what it is; a
78
+ * second line that were placed on the name rather than below it would collide
79
+ * with it on every node that had one.
80
+ */
81
+ const NODE_SUBTITLE_OFFSET = NODE_NAME_OFFSET + NODE_SUBTITLE_SIZE + 5;
39
82
  /**
40
83
  * How far a relation's label sits off its line, in user units. Perpendicular to
41
84
  * the line, so the label never sits on the stroke it belongs to.
@@ -83,13 +126,27 @@ function fit(nodes) {
83
126
  * roster, and a `'use client'` line added here would put it back on that roster.
84
127
  *
85
128
  * **Accessibility.** A diagram carries meaning, so by default it is one image
86
- * with a name: `role="img"` and the `label` the caller passes. Everything inside
87
- * a `role="img"` is presentational, so the node names and relation words are
88
- * drawn for sighted readers and the surrounding sentence is what a screen reader
89
- * gets. Pass `decorative` when the sentence already says what the drawing
129
+ * with a name: `role="img"` and the drawing's name. Everything inside a
130
+ * `role="img"` is presentational, so the node names, the node subtitles and the
131
+ * relation words are drawn for sighted readers and the name is what a screen
132
+ * reader gets. That is why the name is derived from the nodes' own text when the
133
+ * caller passes no `label`: everything on the marks is invisible to the one
134
+ * reader who is not looking at the picture, so a role description written only
135
+ * into a label is a role description a sighted reader never sees. Pass `label`
136
+ * when the drawing needs a name that says what it is rather than what it holds,
137
+ * and omit it when the two would be the same sentence written twice. Pass
138
+ * `decorative` when the surrounding sentence already says what the drawing
90
139
  * shows, and the whole tree leaves the accessibility tree with nothing named
91
140
  * inside it.
92
141
  *
142
+ * **A node may wear its own pack.** `pack` on a node puts the boundary on the
143
+ * circle that node draws, which is the mark, and the mark is the one place a
144
+ * pack boundary belongs without moving anything but colour: a circle has no
145
+ * radius concept, so the pack re-inks the mark and cannot re-round it. Nothing
146
+ * else in the drawing answers to it, the node's name beside the mark keeps the
147
+ * page's ink, and a page that files two pack regions can make a diagram section
148
+ * the second one rather than moving it to the header's product switcher.
149
+ *
93
150
  * **Shape.** Nodes are circles and relations are paths. Both are shapes with no
94
151
  * radius concept, so no corner radius here is a function of `--radius` and a
95
152
  * pack boundary above the drawing moves nothing about its shape. A `<rect>` was
@@ -128,12 +185,17 @@ function fit(nodes) {
128
185
  function Diagram({ nodes, relations, label, decorative = false, className, }) {
129
186
  const place = fit(nodes);
130
187
  const byId = new Map(nodes.map((node) => [node.id, node]));
188
+ // An empty `label` is the same answer as no `label`, so the drawing is named by
189
+ // what its own marks carry rather than announced as an unnamed image. A blank
190
+ // string is the one value the accessible name must never take, and the caller
191
+ // who passed it has said no more than the caller who passed nothing.
192
+ const name = label !== undefined && label.trim() !== '' ? label : derivedName(nodes);
131
193
  const drawn = relations.flatMap((relation) => {
132
194
  const from = byId.get(relation.from);
133
195
  const to = byId.get(relation.to);
134
196
  return from && to ? [{ relation, from: place(from), to: place(to) }] : [];
135
197
  });
136
- return (_jsxs("svg", { "data-slot": "diagram", "data-unresolved-relations": relations.length - drawn.length, viewBox: `0 0 ${CANVAS_WIDTH} ${CANVAS_HEIGHT}`, xmlns: "http://www.w3.org/2000/svg", role: decorative ? undefined : 'img', "aria-label": decorative ? undefined : label, "aria-hidden": decorative || undefined, className: cn('h-auto w-full', className), children: [drawn.map(({ relation, from, to }) => {
198
+ return (_jsxs("svg", { "data-slot": "diagram", "data-unresolved-relations": relations.length - drawn.length, viewBox: `0 0 ${CANVAS_WIDTH} ${CANVAS_HEIGHT}`, xmlns: "http://www.w3.org/2000/svg", role: decorative ? undefined : 'img', "aria-label": decorative ? undefined : name, "aria-hidden": decorative || undefined, className: cn('h-auto w-full', className), children: [drawn.map(({ relation, from, to }) => {
137
199
  // A label placed beside its line rather than on it. The offset is the
138
200
  // line's normal, so a vertical relation's label sits beside it and a
139
201
  // horizontal one's sits above it, and neither ever sits on the stroke.
@@ -144,7 +206,15 @@ function Diagram({ nodes, relations, label, decorative = false, className, }) {
144
206
  return (_jsxs("g", { "data-slot": "diagram-relation", "data-relation": `${relation.from}-${relation.to}`, children: [_jsx("path", { d: `M ${from.x} ${from.y} L ${to.x} ${to.y}`, strokeWidth: 1, strokeDasharray: relation.indirect ? '4 4' : undefined, className: "stroke-muted-foreground fill-none" }), _jsx("text", { x: (from.x + to.x) / 2 - dy * lift, y: (from.y + to.y) / 2 + dx * lift, fontSize: RELATION_NAME_SIZE, textAnchor: "middle", className: "fill-muted-foreground font-mono", children: relation.label })] }, `${relation.from}-${relation.to}`));
145
207
  }), nodes.map((node) => {
146
208
  const at = place(node);
147
- return (_jsxs("g", { "data-slot": "diagram-node", "data-node": node.id, "data-emphasis": node.emphasis || undefined, children: [_jsx("circle", { cx: at.x, cy: at.y, r: NODE_RADIUS, strokeWidth: node.emphasis ? 2 : 1, className: cn(node.emphasis ? 'fill-accent stroke-brand-ink' : 'fill-card stroke-border') }), _jsx("text", { x: at.x, y: at.y + NODE_NAME_OFFSET, fontSize: NODE_NAME_SIZE, textAnchor: "middle", className: "fill-foreground font-mono", children: node.name })] }, node.id));
209
+ // `default` is the absence of the attribute, spelled the way the token
210
+ // build spells it, so a node on the base pack resolves its fill and its
211
+ // stroke from the page rather than from a selector nothing emits.
212
+ const boundary = node.pack !== undefined && node.pack !== 'default' ? node.pack : undefined;
213
+ return (_jsxs("g", { "data-slot": "diagram-node", "data-node": node.id, "data-emphasis": node.emphasis || undefined, children: [_jsx("circle", { cx: at.x, cy: at.y, r: NODE_RADIUS, "data-pack": boundary, strokeWidth: node.emphasis ? 2 : 1, className: cn(node.emphasis ? 'fill-accent stroke-brand-ink' : 'fill-card stroke-border') }), _jsx("text", { x: at.x, y: at.y + NODE_NAME_OFFSET, fontSize: NODE_NAME_SIZE, textAnchor: "middle", className: "fill-foreground font-mono", children: node.name }), node.subtitle ? (_jsx("text", { "data-slot": "diagram-node-subtitle", x: at.x, y: at.y + NODE_SUBTITLE_OFFSET, fontSize: NODE_SUBTITLE_SIZE, textAnchor: "middle",
214
+ // Muted ink rather than the name's own: the line below a name is
215
+ // supporting, and a reader's eye reaches the name first. Both are
216
+ // contract roles, so a boundary above either moves it.
217
+ className: "fill-muted-foreground font-mono", children: node.subtitle })) : null] }, node.id));
148
218
  })] }));
149
219
  }
150
220
  export { Diagram };
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Dialog as DialogPrimitive } from '@base-ui/react/dialog';
4
4
  import { XIcon } from 'lucide-react';
5
- import { cn } from '../../lib/utils';
5
+ import { cn } from '../../lib/utils.js';
6
6
  const VIEWPORT = {
7
7
  center: 'fixed inset-0 z-50 flex items-center justify-center p-4',
8
8
  top: 'fixed inset-x-0 top-0 z-50 flex justify-center',
@@ -0,0 +1,105 @@
1
+ import type { ComponentProps, ReactNode } from 'react';
2
+ /** What happened to one line. */
3
+ export type DiffLineKind = 'context' | 'added' | 'removed';
4
+ /** One line of a change. */
5
+ export type DiffLine = {
6
+ /** What happened to it. @defaultValue 'context' */
7
+ kind?: DiffLineKind;
8
+ /**
9
+ * The number this line had before the change.
10
+ *
11
+ * A removed line has one and no new number, an added line the reverse, and a
12
+ * context line both. That asymmetry is the structural signal that says which
13
+ * side a line is on, and it is why the line numbers are the first thing in the
14
+ * markup rather than decoration beside the content.
15
+ */
16
+ oldNumber?: number;
17
+ /** The number this line has after the change. */
18
+ newNumber?: number;
19
+ /** The line's text, exactly as it is in the file. */
20
+ content: string;
21
+ /**
22
+ * The character ranges within `content` that actually changed.
23
+ *
24
+ * Optional, and a line with none is drawn whole. This is what separates a diff
25
+ * that shows a line changed from one that shows what changed inside it, and it
26
+ * is the difference between reading a change and scanning for it.
27
+ */
28
+ changed?: readonly (readonly [number, number])[];
29
+ };
30
+ /** The words a reader is told for each kind, because the Component ships none. */
31
+ export type DiffLabels = {
32
+ /** Read for a line that was added. */
33
+ added: string;
34
+ /** Read for a line that was removed. */
35
+ removed: string;
36
+ /** Read for a line that did not change. */
37
+ context: string;
38
+ };
39
+ /** The props the Diff accepts. */
40
+ export interface DiffProps extends Omit<ComponentProps<'div'>, 'children'> {
41
+ /** The lines, in file order. */
42
+ lines: readonly DiffLine[];
43
+ /**
44
+ * The accessible name of the change, read before its lines.
45
+ *
46
+ * Required rather than defaulted, because a page with two diffs is a page where
47
+ * a reader cannot tell which change they are in, and the name is the caller's
48
+ * word.
49
+ */
50
+ label: string;
51
+ /**
52
+ * The words for each kind of line.
53
+ *
54
+ * Required, and the reason is the same one that makes a Dialog's close label a
55
+ * prop: a diff that announced "added" and "removed" in English would be a diff
56
+ * every consumer inherits in a language they did not choose. A shared library
57
+ * cannot know whether the word for this is "added" or "ajoute" or "hinzugefugt".
58
+ */
59
+ labels: DiffLabels;
60
+ /** The name of the thing that changed, shown above the lines. */
61
+ file?: string;
62
+ /**
63
+ * A summary of the change, shown beside the file name.
64
+ *
65
+ * The caller's words, because a diff that computed "3 additions, 1 deletion"
66
+ * would be shipping a sentence. What it counts is left to the caller for the
67
+ * same reason, and because a diff of a rename has no additions at all.
68
+ */
69
+ summary?: ReactNode;
70
+ /** Layout only. */
71
+ className?: string;
72
+ /** What a reader is told when there is nothing to show. */
73
+ empty?: ReactNode;
74
+ }
75
+ /**
76
+ * A change, as lines with the numbers they had and the numbers they have.
77
+ *
78
+ * **The bar is change density, not a side marker.** A diff conventionally marks
79
+ * each line with a coloured wash and a rail, which tells a reader that a line
80
+ * changed and nothing about how much. Rewriting one identifier in a long line
81
+ * leaves the same mark as replacing the whole line, so the reader's eye, which is
82
+ * fast at finding saturated bands, is drawn to the least interesting change in the
83
+ * file. Here the bar's width is the fraction of the line that actually changed, so
84
+ * the eye goes to the line that was rewritten rather than the line that was
85
+ * touched, and the marks that used to be a wash become a measurement.
86
+ *
87
+ * **The line numbers carry the side, not the colour.** An added line has a new
88
+ * number and no old one; a removed line the reverse. That asymmetry is structural,
89
+ * it is how every diff reader a developer has ever used distinguishes the two, and
90
+ * it does not depend on distinguishing red from green. The colour is redundant on
91
+ * top of it, which is the right way round: the shape carries the meaning and the
92
+ * colour reinforces it.
93
+ *
94
+ * **It is a table, because a diff is two columns of numbers beside a column of
95
+ * text.** Row and column navigation, the count of lines, and the association
96
+ * between a line and its number all come from the semantics rather than from a
97
+ * grid of divs, and a reader moving by row hears the file the way they read it.
98
+ *
99
+ * **The changed words are emphasised by weight.** See the note on the helper: a
100
+ * diff that tinted them would spend the two hues a reader is most likely to be
101
+ * unable to tell apart, and weight survives greyscale.
102
+ */
103
+ declare function Diff({ lines, label, labels, file, summary, className, empty, ...props }: DiffProps): import("react").JSX.Element;
104
+ export { Diff };
105
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/components/ui/diff.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItD,iCAAiC;AACjC,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;AAE1D,4BAA4B;AAC5B,MAAM,MAAM,QAAQ,GAAG;IACrB,mDAAmD;IACnD,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAA;IACf;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAA;CACjD,CAAA;AAED,kFAAkF;AAClF,MAAM,MAAM,UAAU,GAAG;IACvB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAA;IACf,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,kCAAkC;AAClC,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IACxE,gCAAgC;IAChC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC1B;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;OAOG;IACH,MAAM,EAAE,UAAU,CAAA;IAClB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,mBAAmB;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,SAAS,CAAA;CAClB;AAgED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,iBAAS,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,SAAS,+BA6H3F;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}