@nanisoft/prism-ui 0.10.1 → 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 +49 -17
  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,113 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../lib/utils.js';
3
+ /** The bar and the text tint for each kind, from the existing semantic roles. */
4
+ const KIND_BAR = {
5
+ // A context line has no bar at all rather than an empty one: a zero-width mark
6
+ // beside an unchanged line reads as "this changed a little", which is a claim
7
+ // about a line the diff is saying did not change.
8
+ context: 'bg-transparent',
9
+ added: 'bg-brand-ink',
10
+ removed: 'bg-destructive',
11
+ };
12
+ const KIND_TEXT = {
13
+ context: 'text-muted-foreground',
14
+ added: 'text-foreground',
15
+ removed: 'text-foreground',
16
+ };
17
+ /** How much of a line changed, as a fraction, clamped to the line it is on. */
18
+ function density(line) {
19
+ if (line.changed === undefined || line.content.length === 0)
20
+ return 0;
21
+ const covered = line.changed.reduce((total, [start, end]) => {
22
+ const from = Math.max(0, Math.min(start, line.content.length));
23
+ const to = Math.max(0, Math.min(end, line.content.length));
24
+ return total + Math.max(0, to - from);
25
+ }, 0);
26
+ // Clamped, because two ranges that overlap would otherwise report more than the
27
+ // whole line changed and a bar past the end of its own gutter says nothing.
28
+ return Math.min(covered / line.content.length, 1);
29
+ }
30
+ /**
31
+ * The line's text with its changed runs emphasised, and the rest left alone.
32
+ *
33
+ * The emphasis is weight, not colour. A diff that tinted its changed words green
34
+ * and red would be leaning on the two hues a reader is most likely to be unable to
35
+ * distinguish, and the tint would also fight the line's own state colour. A bolder
36
+ * weight inside a line that is already marked as added or removed says what
37
+ * changed without adding a second colour channel, and it survives greyscale,
38
+ * which is the condition any encoding here has to survive eventually.
39
+ */
40
+ function emphasised(line) {
41
+ const ranges = (line.changed ?? [])
42
+ .map(([start, end]) => [Math.max(0, start), Math.min(end, line.content.length)])
43
+ .filter(([start, end]) => end > start)
44
+ .sort((a, b) => a[0] - b[0]);
45
+ if (ranges.length === 0)
46
+ return line.content;
47
+ const parts = [];
48
+ let at = 0;
49
+ ranges.forEach(([start, end], index) => {
50
+ if (start > at)
51
+ parts.push(line.content.slice(at, start));
52
+ parts.push(_jsx("strong", { className: "font-semibold", children: line.content.slice(start, end) }, `${start}-${end}-${index}`));
53
+ at = end;
54
+ });
55
+ if (at < line.content.length)
56
+ parts.push(line.content.slice(at));
57
+ return parts;
58
+ }
59
+ /**
60
+ * A change, as lines with the numbers they had and the numbers they have.
61
+ *
62
+ * **The bar is change density, not a side marker.** A diff conventionally marks
63
+ * each line with a coloured wash and a rail, which tells a reader that a line
64
+ * changed and nothing about how much. Rewriting one identifier in a long line
65
+ * leaves the same mark as replacing the whole line, so the reader's eye, which is
66
+ * fast at finding saturated bands, is drawn to the least interesting change in the
67
+ * file. Here the bar's width is the fraction of the line that actually changed, so
68
+ * the eye goes to the line that was rewritten rather than the line that was
69
+ * touched, and the marks that used to be a wash become a measurement.
70
+ *
71
+ * **The line numbers carry the side, not the colour.** An added line has a new
72
+ * number and no old one; a removed line the reverse. That asymmetry is structural,
73
+ * it is how every diff reader a developer has ever used distinguishes the two, and
74
+ * it does not depend on distinguishing red from green. The colour is redundant on
75
+ * top of it, which is the right way round: the shape carries the meaning and the
76
+ * colour reinforces it.
77
+ *
78
+ * **It is a table, because a diff is two columns of numbers beside a column of
79
+ * text.** Row and column navigation, the count of lines, and the association
80
+ * between a line and its number all come from the semantics rather than from a
81
+ * grid of divs, and a reader moving by row hears the file the way they read it.
82
+ *
83
+ * **The changed words are emphasised by weight.** See the note on the helper: a
84
+ * diff that tinted them would spend the two hues a reader is most likely to be
85
+ * unable to tell apart, and weight survives greyscale.
86
+ */
87
+ function Diff({ lines, label, labels, file, summary, className, empty, ...props }) {
88
+ if (lines.length === 0) {
89
+ // A diff with nothing in it is a state a caller reaches, and an empty grid
90
+ // with no words in it is a gap rather than a state.
91
+ return (_jsx("div", { "data-slot": "diff-empty", className: cn('text-muted-foreground text-sm', className), children: empty ?? null }));
92
+ }
93
+ const added = lines.filter((line) => (line.kind ?? 'context') === 'added').length;
94
+ const removed = lines.filter((line) => line.kind === 'removed').length;
95
+ return (_jsxs("div", { "data-slot": "diff", className: cn('border-border flex flex-col overflow-hidden rounded-md border', className), ...props, children: [_jsxs("div", { "data-slot": "diff-header", className: "border-border bg-muted/40 flex items-baseline justify-between gap-3 border-b px-3 py-2", children: [_jsx("span", { "data-slot": "diff-file", className: "text-foreground min-w-0 truncate text-sm font-medium", children: file ?? null }), summary === undefined ? (_jsx("span", { "data-slot": "diff-summary", className: "text-muted-foreground shrink-0 text-xs tabular-nums", "data-added": added, "data-removed": removed })) : (_jsx("span", { "data-slot": "diff-summary", className: "text-muted-foreground shrink-0 text-xs tabular-nums", children: summary }))] }), _jsx("table", { "data-slot": "diff-table", "aria-label": label, className: "w-full table-fixed border-collapse", children: _jsx("tbody", { children: lines.map((line, index) => {
96
+ const kind = line.kind ?? 'context';
97
+ const share = density(line);
98
+ return (_jsxs("tr", { "data-kind": kind, children: [_jsx("td", { "data-slot": "diff-old-number", className: "text-muted-foreground w-10 border-r border-transparent px-2 text-right align-top text-xs tabular-nums select-none", children: line.oldNumber ?? null }), _jsx("td", { "data-slot": "diff-new-number", className: "text-muted-foreground w-10 border-r border-transparent px-2 text-right align-top text-xs tabular-nums select-none", children: line.newNumber ?? null }), _jsx("td", { "data-slot": "diff-gutter", className: "w-1.5 border-r border-transparent p-0 align-stretch", children: kind === 'context' ? null : (_jsx("span", { "data-slot": "diff-bar", "aria-hidden": "true", className: cn('block h-full min-h-5 w-full', KIND_BAR[kind]),
99
+ /*
100
+ * The floor applies only when the density is unknown, which is
101
+ * a changed line the caller gave no ranges for. It does not
102
+ * apply to a measured density, because a floor on a real
103
+ * measurement overstates it: a one-character change in a long
104
+ * line is half a percent, and drawing it at twelve percent
105
+ * would have the bar claim something the data does not say,
106
+ * which is the one thing a measurement is not allowed to do.
107
+ * The floor exists to keep a line with no reported ranges
108
+ * findable, and that is the only case it serves.
109
+ */
110
+ style: { width: `${(share > 0 ? share : 0.12) * 100}%` } })) }), _jsx("td", { "data-slot": "diff-content", "aria-label": labels[kind], className: cn('px-3 py-0.5 text-left font-mono text-xs leading-relaxed', KIND_TEXT[kind]), children: emphasised(line) })] }, `${kind}-${line.oldNumber ?? 'x'}-${line.newNumber ?? 'x'}-${index}`));
111
+ }) }) })] }));
112
+ }
113
+ export { Diff };
@@ -43,6 +43,24 @@ export interface DropdownMenuContentProps extends ComponentProps<'div'> {
43
43
  * crosses the package seam (ticket 07 section 6).
44
44
  */
45
45
  export interface DropdownMenuItemProps extends ComponentProps<'div'> {
46
+ /**
47
+ * The element the item is rendered as.
48
+ *
49
+ * Declared here rather than re-exported from Base UI so no upstream type crosses
50
+ * the package seam (ticket 07 section 6), and narrowed to the element form of
51
+ * the two Base UI accepts. The narrowing is stated because it is a narrowing:
52
+ * Base UI also takes a function of the props and the component's state, and that
53
+ * form is not forwarded, because typing it means naming Base UI's own prop and
54
+ * event types in a declaration a consumer reads. The element form is the one a
55
+ * menu of links needs, since the attributes that make a row a destination are
56
+ * the attributes of the anchor itself.
57
+ *
58
+ * It is here because a menu item is not always a command: an item that navigates
59
+ * has to BE the link, because a link nested inside a focusable item is two tab
60
+ * stops for one row, and a reader who middle-clicks a row that only looks like a
61
+ * link gets nothing.
62
+ */
63
+ render?: React.ReactElement;
46
64
  /** Whether the item aligns with the labels above it. @defaultValue false */
47
65
  inset?: boolean;
48
66
  /** Whether the item reads as a destructive action. @defaultValue default */
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown-menu.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dropdown-menu.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dropdown-menu.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dropdown-menu.tsx"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Menu as MenuPrimitive } from '@base-ui/react/menu';
4
4
  import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react';
5
- import { cn } from '../../lib/utils';
5
+ import { cn } from '../../lib/utils.js';
6
6
  const POPUP = 'bg-popover text-popover-foreground z-50 max-h-(--available-height) min-w-36 overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md outline-none transition-[opacity,transform] duration-fast ease-out data-[starting-style]:scale-95 data-[starting-style]:opacity-0 data-[ending-style]:scale-95 data-[ending-style]:opacity-0';
7
7
  const ITEM = 'focus:bg-accent focus:text-accent-foreground data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*="size-"])]:size-4';
8
8
  /**
@@ -1,5 +1,5 @@
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
3
  /**
4
4
  * A short list of named facts, as a definition list.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { cn } from '../../lib/utils';
2
+ import { cn } from '../../lib/utils.js';
3
3
  /**
4
4
  * The layout and labelling components that wrap a form control.
5
5
  *
@@ -0,0 +1,151 @@
1
+ import type { ComponentProps } from 'react';
2
+ /** The props the Form accepts. */
3
+ export interface FormProps extends Omit<ComponentProps<'form'>, 'onSubmit'> {
4
+ /**
5
+ * The errors the server returned, keyed by field name.
6
+ *
7
+ * This is the whole point of the binding. A submission fails and comes back with
8
+ * a record of what was wrong with it, and a form that cannot take that record has
9
+ * to either drop it or turn it into a banner above the form that the reader has to
10
+ * match to a field themselves. Passed here, each `FormField` named after the key
11
+ * renders it under the control that caused it, and the control is marked invalid.
12
+ * Pass an empty record to clear them: the errors are cleared as data, not by
13
+ * reloading the page. A key with no error is an absent key rather than a key
14
+ * holding nothing, because a record that says "this field is wrong" and does not
15
+ * say how is not one this can draw.
16
+ */
17
+ errors?: Record<string, string | string[]>;
18
+ /**
19
+ * Called with the field values when the form submits.
20
+ *
21
+ * The native submit event is prevented, so this is where a server action goes.
22
+ * Nothing is submitted to the browser and no navigation happens unless the caller
23
+ * does it.
24
+ */
25
+ onSubmit?: (values: Record<string, unknown>) => void;
26
+ /**
27
+ * Whether the browser's own validation bubbles are off. @defaultValue true
28
+ *
29
+ * On by default, because the binding reports validity on the field and a form
30
+ * that shows the browser's bubble and a styled message is two reports of one
31
+ * problem, in two places, in two voices.
32
+ */
33
+ noValidate?: boolean;
34
+ }
35
+ /** The props the Form field accepts. */
36
+ export interface FormFieldProps extends ComponentProps<'div'> {
37
+ /**
38
+ * The name of the field, and the key its error arrives under.
39
+ *
40
+ * Required, and it is the join between the control's `name`, the key in the
41
+ * server's `errors` and the field the error is drawn under. A field that is not
42
+ * named cannot receive an error, so this is the one prop that makes the rest of
43
+ * the binding work.
44
+ */
45
+ name: string;
46
+ /**
47
+ * The rule the field is checked against, returning the message to show.
48
+ *
49
+ * The message is the caller's, because it is a sentence about their product's
50
+ * rules. Returning nothing means the value is valid.
51
+ */
52
+ validate?: (value: unknown) => string | string[] | null | void;
53
+ /** Whether the field is invalid, for a value a library of the caller's owns. */
54
+ invalid?: boolean;
55
+ /** Whether the field ignores interaction. */
56
+ disabled?: boolean;
57
+ }
58
+ /** The props the Form label accepts. */
59
+ export interface FormLabelProps extends ComponentProps<'label'> {
60
+ }
61
+ /** The props the Form description accepts. */
62
+ export interface FormDescriptionProps extends ComponentProps<'p'> {
63
+ }
64
+ /**
65
+ * The props the Form control accepts.
66
+ *
67
+ * Declared here rather than as `ComponentProps<typeof FieldPrimitive.Control>`,
68
+ * for the same reason `Progress` declares its own props rather than re-exporting
69
+ * Base UI's (ticket 07 section 6): an upstream type in the signature reaches the
70
+ * emitted declaration, and the surface gate fails a declaration file that names
71
+ * an upstream module. A consumer would then need Base UI resolvable to typecheck a
72
+ * Prism import, which is the seam the rule exists to keep closed.
73
+ *
74
+ * It is `ComponentProps<'input'>` because that is the element the control renders
75
+ * by default, and naming the element is more honest than naming a `div` and being
76
+ * wrong about every attribute. A caller who swaps the element for a select or a
77
+ * textarea passes that element's own attributes and the runtime does the rest; the
78
+ * type here is the default case, not a limit on what may be rendered.
79
+ */
80
+ export interface FormControlProps extends ComponentProps<'input'> {
81
+ }
82
+ /** The props the Form error accepts. */
83
+ export interface FormErrorProps extends ComponentProps<'div'> {
84
+ /**
85
+ * What the reader can do about the error, drawn after the message.
86
+ *
87
+ * The message and the way out are one unit. "That address is already registered"
88
+ * with nothing after it is a dead end, and the reader is left to guess whether
89
+ * they should sign in instead, change the address or ask somebody. So this
90
+ * Component renders both in the same live region: the recovery is announced with
91
+ * the problem rather than being something the reader has to find.
92
+ */
93
+ action?: React.ReactNode;
94
+ }
95
+ /**
96
+ * The form binding: a form, its fields, and the errors that came back from it.
97
+ *
98
+ * **`Field` is the layout; this is the wiring.** `Field` is presentational and says
99
+ * so: nothing in it generates an `id`, so the consumer owns the control's id and
100
+ * wires it to the label's `htmlFor` and to the description or error's `id` through
101
+ * `aria-describedby`. That is the right default for a layout, and it is a lot of
102
+ * hand-written ids in a form with eleven fields, none of which a reader can see
103
+ * and all of which a screen reader depends on. This module is the part that
104
+ * generates them: `FormField` owns the name, `FormControl` registers itself with
105
+ * the field, and `FormLabel` and `FormDescription` find the control and point at
106
+ * it. Nothing here changes how `Field` looks.
107
+ *
108
+ * **A server error arrives as data and lands under the control that caused it.**
109
+ * `errors` is a record keyed by field name and `FormField` is keyed by the same
110
+ * name, so the message a submission came back with is drawn under the control the
111
+ * reader has to fix, the control is marked invalid, and the message is added to the
112
+ * control's description so it is read out when the reader reaches the field. The
113
+ * errors clear when the record clears: a field that fixed itself still shows the
114
+ * server's complaint until the caller stops passing it, which is exactly as
115
+ * honest as it sounds.
116
+ *
117
+ * **The error and the way out are rendered together, in one live region.** The
118
+ * recovery is the half of an error that is usually missing. A `FormError` renders
119
+ * the message and then the caller's `action`, and the region is in the document
120
+ * before either of them is, because a live region inserted at the same moment as
121
+ * its content is not announced by every screen reader. The region is therefore
122
+ * present and empty while the field is valid, which is the cost of the reliable
123
+ * half.
124
+ *
125
+ * **Use a `FormControl` inside a `FormField`.** The control is the part that
126
+ * registers itself, which is what makes the label's `for` resolve and what puts the
127
+ * description and the error into the control's accessible description. A plain
128
+ * `Input` renders and submits perfectly well inside a `FormField` and is not
129
+ * registered, so its label points at an id that is on nothing and its error is
130
+ * never announced with it. That is the one rule this module asks for, and it is
131
+ * the rule `Field` deliberately leaves to the caller.
132
+ */
133
+ declare function Form({ errors, onSubmit, noValidate, className, ...props }: FormProps): import("react").JSX.Element;
134
+ /** One field's name, its rule and the control that answers to it. */
135
+ declare function FormField({ name, validate, invalid, disabled, className, ...props }: FormFieldProps): import("react").JSX.Element;
136
+ /** The control's accessible name, associated with it rather than placed near it. */
137
+ declare function FormLabel({ className, ...props }: FormLabelProps): import("react").JSX.Element;
138
+ /** The control itself, registered with the field so the label and errors find it. */
139
+ declare function FormControl({ className, ...props }: FormControlProps): import("react").JSX.Element;
140
+ /** A short helper line under the control, announced with the control itself. */
141
+ declare function FormDescription({ className, ...props }: FormDescriptionProps): import("react").JSX.Element;
142
+ /**
143
+ * The field's error and what to do about it, in one announced region.
144
+ *
145
+ * The region is always in the document and the message is not, because a live
146
+ * region that arrives with its content is missed by some screen readers. It is
147
+ * empty while the field is valid.
148
+ */
149
+ declare function FormError({ className, action, ...props }: FormErrorProps): import("react").JSX.Element;
150
+ export { Form, FormControl, FormDescription, FormError, FormField, FormLabel };
151
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/components/ui/form.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAI3C,kCAAkC;AAClC,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IACzE;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;IAC1C;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACpD;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wCAAwC;AACxC,MAAM,WAAW,cAAe,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC3D;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;IAC9D,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,wCAAwC;AACxC,MAAM,WAAW,cAAe,SAAQ,cAAc,CAAC,OAAO,CAAC;CAAG;AAElE,8CAA8C;AAC9C,MAAM,WAAW,oBAAqB,SAAQ,cAAc,CAAC,GAAG,CAAC;CAAG;AAEpE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,OAAO,CAAC;CAAG;AAEpE,wCAAwC;AACxC,MAAM,WAAW,cAAe,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC3D;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,iBAAS,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAiB,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,SAAS,+BAUpF;AAED,qEAAqE;AACrE,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,cAAc,+BAYhB;AAED,oFAAoF;AACpF,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BAQzD;AAED,qFAAqF;AACrF,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,gBAAgB,+BAc7D;AAED,gFAAgF;AAChF,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,oBAAoB,+BAQrE;AAED;;;;;;GAMG;AACH,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BAyBjE;AAED,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAA"}
@@ -0,0 +1,73 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Field as FieldPrimitive } from '@base-ui/react/field';
4
+ import { Form as FormPrimitive } from '@base-ui/react/form';
5
+ import { cn } from '../../lib/utils.js';
6
+ /**
7
+ * The form binding: a form, its fields, and the errors that came back from it.
8
+ *
9
+ * **`Field` is the layout; this is the wiring.** `Field` is presentational and says
10
+ * so: nothing in it generates an `id`, so the consumer owns the control's id and
11
+ * wires it to the label's `htmlFor` and to the description or error's `id` through
12
+ * `aria-describedby`. That is the right default for a layout, and it is a lot of
13
+ * hand-written ids in a form with eleven fields, none of which a reader can see
14
+ * and all of which a screen reader depends on. This module is the part that
15
+ * generates them: `FormField` owns the name, `FormControl` registers itself with
16
+ * the field, and `FormLabel` and `FormDescription` find the control and point at
17
+ * it. Nothing here changes how `Field` looks.
18
+ *
19
+ * **A server error arrives as data and lands under the control that caused it.**
20
+ * `errors` is a record keyed by field name and `FormField` is keyed by the same
21
+ * name, so the message a submission came back with is drawn under the control the
22
+ * reader has to fix, the control is marked invalid, and the message is added to the
23
+ * control's description so it is read out when the reader reaches the field. The
24
+ * errors clear when the record clears: a field that fixed itself still shows the
25
+ * server's complaint until the caller stops passing it, which is exactly as
26
+ * honest as it sounds.
27
+ *
28
+ * **The error and the way out are rendered together, in one live region.** The
29
+ * recovery is the half of an error that is usually missing. A `FormError` renders
30
+ * the message and then the caller's `action`, and the region is in the document
31
+ * before either of them is, because a live region inserted at the same moment as
32
+ * its content is not announced by every screen reader. The region is therefore
33
+ * present and empty while the field is valid, which is the cost of the reliable
34
+ * half.
35
+ *
36
+ * **Use a `FormControl` inside a `FormField`.** The control is the part that
37
+ * registers itself, which is what makes the label's `for` resolve and what puts the
38
+ * description and the error into the control's accessible description. A plain
39
+ * `Input` renders and submits perfectly well inside a `FormField` and is not
40
+ * registered, so its label points at an id that is on nothing and its error is
41
+ * never announced with it. That is the one rule this module asks for, and it is
42
+ * the rule `Field` deliberately leaves to the caller.
43
+ */
44
+ function Form({ errors, onSubmit, noValidate = true, className, ...props }) {
45
+ return (_jsx(FormPrimitive, { className: cn('flex w-full flex-col gap-6', className), noValidate: noValidate, ...(errors === undefined ? null : { errors }), onFormSubmit: (values) => onSubmit?.(values), ...props }));
46
+ }
47
+ /** One field's name, its rule and the control that answers to it. */
48
+ function FormField({ name, validate, invalid, disabled, className, ...props }) {
49
+ return (_jsx(FieldPrimitive.Root, { "data-slot": "form-field", name: name, className: cn('flex w-full flex-col gap-1.5', className), ...(validate === undefined ? null : { validate }), ...(invalid === undefined ? null : { invalid }), ...(disabled === undefined ? null : { disabled }), ...props }));
50
+ }
51
+ /** The control's accessible name, associated with it rather than placed near it. */
52
+ function FormLabel({ className, ...props }) {
53
+ return (_jsx(FieldPrimitive.Label, { "data-slot": "form-label", className: cn('text-foreground text-sm leading-none font-medium', className), ...props }));
54
+ }
55
+ /** The control itself, registered with the field so the label and errors find it. */
56
+ function FormControl({ className, ...props }) {
57
+ return (_jsx(FieldPrimitive.Control, { "data-slot": "form-control", className: cn('border-input bg-background text-foreground placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base shadow-xs transition-[color,box-shadow] duration-fast ease-out outline-none md:text-sm', 'focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-[3px]', 'aria-invalid:border-destructive aria-invalid:ring-destructive/20', 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50', className), ...props }));
58
+ }
59
+ /** A short helper line under the control, announced with the control itself. */
60
+ function FormDescription({ className, ...props }) {
61
+ return (_jsx(FieldPrimitive.Description, { "data-slot": "form-description", className: cn('text-muted-foreground text-sm', className), ...props }));
62
+ }
63
+ /**
64
+ * The field's error and what to do about it, in one announced region.
65
+ *
66
+ * The region is always in the document and the message is not, because a live
67
+ * region that arrives with its content is missed by some screen readers. It is
68
+ * empty while the field is valid.
69
+ */
70
+ function FormError({ className, action, ...props }) {
71
+ return (_jsxs("div", { "data-slot": "form-error", role: "alert", className: cn('flex flex-col items-start gap-1', className), ...props, children: [_jsx(FieldPrimitive.Error, { "data-slot": "form-error-message", className: "text-destructive text-sm font-medium" }), action === undefined ? null : (_jsx(FieldPrimitive.Validity, { children: (state) => (state.validity.valid === false ? action : null) }))] }));
72
+ }
73
+ export { Form, FormControl, FormDescription, FormError, FormField, FormLabel };
@@ -0,0 +1,105 @@
1
+ import type { ComponentProps } from 'react';
2
+ /**
3
+ * The props the HoverCard root forwards to Base UI.
4
+ *
5
+ * Declared here rather than re-exported from Base UI so no upstream type
6
+ * crosses the package seam (ticket 07 section 6).
7
+ */
8
+ export interface HoverCardProps {
9
+ /** The controlled open state. */
10
+ open?: boolean;
11
+ /** The initially open state, for an uncontrolled hover card. */
12
+ defaultOpen?: boolean;
13
+ /** Called when the open state changes. */
14
+ onOpenChange?: (open: boolean) => void;
15
+ /** The trigger and the preview. */
16
+ children?: React.ReactNode;
17
+ }
18
+ /**
19
+ * The props HoverCardTrigger forwards to Base UI.
20
+ *
21
+ * Declared here rather than re-exported from Base UI so no upstream type
22
+ * crosses the package seam (ticket 07 section 6).
23
+ */
24
+ export interface HoverCardTriggerProps extends ComponentProps<'a'> {
25
+ /**
26
+ * How long the pointer must rest on the trigger before the card opens, in
27
+ * milliseconds.
28
+ *
29
+ * A prop and not a fixed number, because the delay is a decision about what
30
+ * counts as intent and a caller whose readers move differently, or whose
31
+ * pointer hardware reports a rest as a hover, has a different answer. What the
32
+ * Component refuses to do is decide that intent is instant, which is the
33
+ * failure a card with no delay always ships: the pointer crossing a line of
34
+ * text opens a surface, and a page of links becomes a page of flashes.
35
+ *
36
+ * @defaultValue 600
37
+ */
38
+ delay?: number;
39
+ /**
40
+ * How long the card stays open after the pointer leaves it, in milliseconds.
41
+ *
42
+ * This is the half that is easy to leave at zero and that punishes the reader
43
+ * who was about to get what they wanted. Moving from the trigger to the card
44
+ * crosses a gap, and a card that closes on the first pixel outside the trigger
45
+ * closes in the gap, so the reader who did everything right gets nothing. A
46
+ * generous close delay is what makes a rest on the trigger mean something.
47
+ *
48
+ * @defaultValue 300
49
+ */
50
+ closeDelay?: number;
51
+ }
52
+ /**
53
+ * The props HoverCardContent forwards to Base UI.
54
+ *
55
+ * Declared here rather than re-exported from Base UI so no upstream type
56
+ * crosses the package seam (ticket 07 section 6).
57
+ */
58
+ export interface HoverCardContentProps extends ComponentProps<'div'> {
59
+ /** Which side of the trigger the card is placed on. @defaultValue bottom */
60
+ side?: 'top' | 'right' | 'bottom' | 'left';
61
+ /** How the card aligns against the trigger. @defaultValue center */
62
+ align?: 'start' | 'center' | 'end';
63
+ /** The distance in pixels between the trigger and the card. @defaultValue 8 */
64
+ sideOffset?: number;
65
+ }
66
+ /**
67
+ * A preview of a destination, shown when the reader rests on a link.
68
+ *
69
+ * **The delay is the Component's decision, and the close delay is the half that
70
+ * matters.** A card with no open delay opens as the pointer crosses a line of
71
+ * text, so a page of links becomes a page of flashes and a reader learns that
72
+ * resting is punished. A card with no close delay is worse and quieter: the
73
+ * reader rests, waits, sees the card start to appear, moves toward it, and it
74
+ * vanishes in the gap between the trigger and the card, so the one reader who
75
+ * did everything right is the one who gets nothing. Both are delays here, and
76
+ * both are props, because how long a reader's pointer rests is a fact about the
77
+ * reader and not about the design system.
78
+ *
79
+ * **The preview is never the only copy of what it shows.** The trigger is a real
80
+ * anchor, so everything in the card is reachable at the destination without the
81
+ * card ever appearing, and a touch reader, who has no hover at all, is not
82
+ * missing anything. That is the honest way to express "the reader wants this"
83
+ * without punishing a reader on a slow device: the card is an accelerant for a
84
+ * reader with a pointer, and removing it costs the reader nothing. If a fact
85
+ * lives only in the card, it does not exist for half the people who can see it.
86
+ *
87
+ * The card is not a dialog. It takes no focus, traps nothing, and is not
88
+ * announced, because a screen reader is already moving through the link text and
89
+ * a surface that interrupted that to read a summary of it would be a worse
90
+ * version of the same information. For the same reason, put nothing in the card
91
+ * that is not also on the destination.
92
+ */
93
+ declare function HoverCard({ ...props }: HoverCardProps): import("react").JSX.Element;
94
+ /**
95
+ * The link the card previews. It is an anchor, and it navigates on its own.
96
+ *
97
+ * The href is what makes the card safe to add: the destination is reachable
98
+ * whether or not the card ever opens, so the delay can be as long as intent
99
+ * requires without costing a reader anything they cannot already get.
100
+ */
101
+ declare function HoverCardTrigger({ className, delay, closeDelay, ...props }: HoverCardTriggerProps): import("react").JSX.Element;
102
+ /** The floating preview surface. */
103
+ declare function HoverCardContent({ className, side, align, sideOffset, ...props }: HoverCardContentProps): import("react").JSX.Element;
104
+ export { HoverCard, HoverCardTrigger, HoverCardContent };
105
+ //# sourceMappingURL=hover-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hover-card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/hover-card.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAI3C;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,mCAAmC;IACnC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAsB,SAAQ,cAAc,CAAC,GAAG,CAAC;IAChE;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAsB,SAAQ,cAAc,CAAC,KAAK,CAAC;IAClE,4EAA4E;IAC5E,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IAC1C,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAA;IAClC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,iBAAS,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BAE9C;AAED;;;;;;GAMG;AACH,iBAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,KAAK,EAAE,EAAE,qBAAqB,+BAe1F;AAED,oCAAoC;AACpC,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,IAAe,EACf,KAAgB,EAChB,UAAc,EACd,GAAG,KAAK,EACT,EAAE,qBAAqB,+BAwBvB;AAED,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAA"}
@@ -0,0 +1,49 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { PreviewCard as PreviewCardPrimitive } from '@base-ui/react/preview-card';
4
+ import { cn } from '../../lib/utils.js';
5
+ /**
6
+ * A preview of a destination, shown when the reader rests on a link.
7
+ *
8
+ * **The delay is the Component's decision, and the close delay is the half that
9
+ * matters.** A card with no open delay opens as the pointer crosses a line of
10
+ * text, so a page of links becomes a page of flashes and a reader learns that
11
+ * resting is punished. A card with no close delay is worse and quieter: the
12
+ * reader rests, waits, sees the card start to appear, moves toward it, and it
13
+ * vanishes in the gap between the trigger and the card, so the one reader who
14
+ * did everything right is the one who gets nothing. Both are delays here, and
15
+ * both are props, because how long a reader's pointer rests is a fact about the
16
+ * reader and not about the design system.
17
+ *
18
+ * **The preview is never the only copy of what it shows.** The trigger is a real
19
+ * anchor, so everything in the card is reachable at the destination without the
20
+ * card ever appearing, and a touch reader, who has no hover at all, is not
21
+ * missing anything. That is the honest way to express "the reader wants this"
22
+ * without punishing a reader on a slow device: the card is an accelerant for a
23
+ * reader with a pointer, and removing it costs the reader nothing. If a fact
24
+ * lives only in the card, it does not exist for half the people who can see it.
25
+ *
26
+ * The card is not a dialog. It takes no focus, traps nothing, and is not
27
+ * announced, because a screen reader is already moving through the link text and
28
+ * a surface that interrupted that to read a summary of it would be a worse
29
+ * version of the same information. For the same reason, put nothing in the card
30
+ * that is not also on the destination.
31
+ */
32
+ function HoverCard({ ...props }) {
33
+ return _jsx(PreviewCardPrimitive.Root, { ...props });
34
+ }
35
+ /**
36
+ * The link the card previews. It is an anchor, and it navigates on its own.
37
+ *
38
+ * The href is what makes the card safe to add: the destination is reachable
39
+ * whether or not the card ever opens, so the delay can be as long as intent
40
+ * requires without costing a reader anything they cannot already get.
41
+ */
42
+ function HoverCardTrigger({ className, delay, closeDelay, ...props }) {
43
+ return (_jsx(PreviewCardPrimitive.Trigger, { "data-slot": "hover-card-trigger", ...(delay === undefined ? null : { delay }), ...(closeDelay === undefined ? null : { closeDelay }), className: cn('hover:decoration-foreground rounded-sm text-foreground underline decoration-muted-foreground underline-offset-2 outline-none', 'transition-colors duration-fast ease-out', 'focus-visible:ring-ring focus-visible:ring-[3px]', className), ...props }));
44
+ }
45
+ /** The floating preview surface. */
46
+ function HoverCardContent({ className, side = 'bottom', align = 'center', sideOffset = 8, ...props }) {
47
+ return (_jsx(PreviewCardPrimitive.Portal, { children: _jsx(PreviewCardPrimitive.Positioner, { side: side, align: align, sideOffset: sideOffset, className: "z-50", children: _jsx(PreviewCardPrimitive.Popup, { "data-slot": "hover-card-content", className: cn('bg-popover text-popover-foreground w-72 origin-(--transform-origin) rounded-md border p-4 shadow-md outline-none', 'transition-[opacity,transform] duration-fast ease-out', 'focus-visible:ring-ring focus-visible:ring-[3px]', 'data-[starting-style]:scale-95 data-[starting-style]:opacity-0', 'data-[ending-style]:scale-95 data-[ending-style]:opacity-0', className), ...props }) }) }));
48
+ }
49
+ export { HoverCard, HoverCardTrigger, HoverCardContent };