@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,55 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChevronDownIcon } from 'lucide-react';
3
+ import { cn } from '../../lib/utils.js';
4
+ /**
5
+ * A native `<select>`, styled to match the rest of this package.
6
+ *
7
+ * **This is not a second Select, and the difference is which element is on the
8
+ * page.** The `Select` in this package is Base UI's: a `<button>` carrying
9
+ * `role="combobox"` and a popup list Base UI positions, types into and manages the
10
+ * keyboard for. It is a custom control, and everything it offers over the platform
11
+ * is the price of being one: it needs JavaScript to open, it cannot be operated by
12
+ * the mobile picker a reader expects when they tap a select on a phone, it is
13
+ * invisible to a right-click menu that offers "Save as", and it is a set of `div`s
14
+ * where the browser's own is one element with thirty years of platform behaviour
15
+ * behind it.
16
+ *
17
+ * So this Component renders the platform element. Everything the browser does with
18
+ * a `<select>` it still does: the wheel on Windows, the wheel on macOS and iOS,
19
+ * type-ahead on the first letter, the mobile picker, the form submission, and the
20
+ * context menu. The styling is the package's, so the control looks like its
21
+ * neighbours, and the appearance is suppressed so the drawn chevron is Prism's
22
+ * rather than the platform's.
23
+ *
24
+ * **When this is the right answer rather than the compromise it sounds like.** A
25
+ * native select is right when the platform's picker is better than anything this
26
+ * package could draw: a long list of plain strings on a phone, a form that must
27
+ * submit without JavaScript, a control inside a page that is already a form and
28
+ * gains nothing from a popup that is portalled and dismissed. It is wrong when the
29
+ * option needs to be more than a string, because an `<option>` holds text and
30
+ * nothing else: no description, no count, no state, no nested markup. That is the
31
+ * line, and the `Select` is on the other side of it.
32
+ *
33
+ * **The chevron is decoration and says so.** It is `aria-hidden` and it is not
34
+ * focusable, because the value is already announced by the platform control and a
35
+ * reader hearing "graphic" after every option set is a reader being told something
36
+ * about the drawing rather than about the value. The control is one tab stop and
37
+ * the browser owns its key handling entirely, which is the point.
38
+ *
39
+ * It is a server Component. A native select holds no state, runs no effect and
40
+ * attaches no handler, so a form of twenty of them costs no JavaScript at all,
41
+ * which is a real answer to the argument above rather than a footnote to it.
42
+ */
43
+ function NativeSelect({ className, size = 'default', children, ...props }) {
44
+ return (_jsxs("div", { "data-slot": "native-select", className: "relative w-full", children: [_jsx("select", { "data-slot": "native-select-control", className: cn(
45
+ // `appearance-none` is what lets the chevron be drawn rather than
46
+ // inherited: the platform's own arrow is the one piece of this control
47
+ // that would otherwise belong to no design system, and the whole reason
48
+ // this Component exists is to take that over.
49
+ 'border-input bg-background text-foreground w-full appearance-none rounded-md border ps-3 pe-9 text-sm outline-none', 'transition-[color,box-shadow,border-color] duration-fast ease-out', 'focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-[3px]', 'aria-invalid:border-destructive aria-invalid:ring-destructive/20', 'disabled:cursor-not-allowed disabled:opacity-50',
50
+ // The font is inherited explicitly, because a `<select>` does not
51
+ // inherit one in every engine and a control in the platform's face
52
+ // beside text in Inter is a control nobody designed.
53
+ 'font-inherit', size === 'sm' ? 'h-8' : 'h-9', className), ...props, children: children }), _jsx("span", { "data-slot": "native-select-icon", "aria-hidden": "true", className: "text-muted-foreground pointer-events-none absolute top-1/2 right-3 flex size-4 -translate-y-1/2 items-center justify-center", children: _jsx(ChevronDownIcon, { className: "size-4" }) })] }));
54
+ }
55
+ export { NativeSelect };
@@ -0,0 +1,186 @@
1
+ import type { ComponentProps } from 'react';
2
+ /**
3
+ * The props the NavigationMenu 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 NavigationMenuProps extends Omit<ComponentProps<'nav'>, 'defaultValue'> {
9
+ /**
10
+ * The accessible name of this region of links.
11
+ *
12
+ * Required rather than defaulted, because the root renders a `<nav>`, and a
13
+ * `<nav>` with no name is a landmark a screen reader announces only as
14
+ * "navigation". A site header's primary links and a footer link list are both
15
+ * `<nav>`, and a reader moving between them is told nothing about which is
16
+ * which. The name is the caller's word and it is usually the region: primary,
17
+ * product, footer.
18
+ */
19
+ label: string;
20
+ /** The controlled value of the open group. */
21
+ value?: string | null;
22
+ /** The group open initially, for an uncontrolled menu. */
23
+ defaultValue?: string | null;
24
+ /** Called when the open group changes. */
25
+ onValueChange?: (value: string | null) => void;
26
+ /** Whether the groups stack. @defaultValue horizontal */
27
+ orientation?: 'horizontal' | 'vertical';
28
+ /**
29
+ * How long the pointer must rest on a trigger before the group opens, in
30
+ * milliseconds.
31
+ *
32
+ * The default is short because this is a menu of links rather than of
33
+ * previews: the reader is about to take one of these addresses, and a rest
34
+ * followed by a long wait is a rest they will conclude did nothing.
35
+ *
36
+ * @defaultValue 50
37
+ */
38
+ delay?: number;
39
+ /** How long the group stays open after the pointer leaves it, in milliseconds. @defaultValue 50 */
40
+ closeDelay?: number;
41
+ }
42
+ /** The props NavigationMenuList forwards to Base UI. */
43
+ export interface NavigationMenuListProps extends ComponentProps<'ul'> {
44
+ }
45
+ /**
46
+ * The props NavigationMenuItem forwards to Base UI.
47
+ *
48
+ * Declared here rather than re-exported from Base UI so no upstream type
49
+ * crosses the package seam (ticket 07 section 6).
50
+ */
51
+ export interface NavigationMenuItemProps extends ComponentProps<'li'> {
52
+ /** The value this item contributes to the root, and the value its trigger opens. */
53
+ value: string;
54
+ }
55
+ /** The props NavigationMenuTrigger forwards to Base UI. */
56
+ export interface NavigationMenuTriggerProps extends ComponentProps<'button'> {
57
+ }
58
+ /** The props NavigationMenuContent forwards to Base UI. */
59
+ export interface NavigationMenuContentProps extends ComponentProps<'div'> {
60
+ /**
61
+ * Whether the closed group stays in the DOM.
62
+ *
63
+ * A navigation menu is the one overlay here a crawler reads. Every other
64
+ * popup is unmounted when closed, and that is right for them, but a closed
65
+ * navigation group holding the links of a site header is the only place a
66
+ * reader, a crawler and a reader with JavaScript off all see the same set of
67
+ * addresses, so a consumer who needs the header to read the same either way
68
+ * turns this on and owns the layout shift that follows.
69
+ *
70
+ * @defaultValue false
71
+ */
72
+ keepMounted?: boolean;
73
+ }
74
+ /**
75
+ * The props NavigationMenuLink forwards to Base UI.
76
+ *
77
+ * Declared here rather than re-exported from Base UI so no upstream type
78
+ * crosses the package seam (ticket 07 section 6).
79
+ */
80
+ export interface NavigationMenuLinkProps extends ComponentProps<'a'> {
81
+ /**
82
+ * Whether this link is the page the reader is on.
83
+ *
84
+ * Required, and required for a reason a colour cannot express: a navigation
85
+ * menu that does not say where the reader is has made them guess. It is
86
+ * rendered as `aria-current="page"` rather than as a fill, so a reader who
87
+ * cannot distinguish the active colour still knows they are in the right
88
+ * place, and so the marking survives a theme change.
89
+ */
90
+ active?: boolean;
91
+ /** Whether taking the link closes the group. @defaultValue false */
92
+ closeOnClick?: boolean;
93
+ }
94
+ /** The props NavigationMenuIcon forwards to Base UI. */
95
+ export interface NavigationMenuIconProps extends ComponentProps<'span'> {
96
+ }
97
+ /**
98
+ * The props NavigationMenuPortal forward to Base UI.
99
+ *
100
+ * Declared here rather than re-exported from Base UI so no upstream type
101
+ * crosses the package seam (ticket 07 section 6).
102
+ */
103
+ export interface NavigationMenuPortalProps extends ComponentProps<'div'> {
104
+ }
105
+ /** The props NavigationMenuPositioner forwards to Base UI. */
106
+ export interface NavigationMenuPositionerProps extends ComponentProps<'div'> {
107
+ /** The distance in pixels between the trigger and the group. @defaultValue 8 */
108
+ sideOffset?: number;
109
+ /** The offset in pixels along the alignment axis. @defaultValue 0 */
110
+ alignOffset?: number;
111
+ }
112
+ /** The props NavigationMenuPopup forwards to Base UI. */
113
+ export interface NavigationMenuPopupProps extends ComponentProps<'nav'> {
114
+ }
115
+ /** The props NavigationMenuViewport forwards to Base UI. */
116
+ export interface NavigationMenuViewportProps extends ComponentProps<'div'> {
117
+ }
118
+ /** The props NavigationMenuBackdrop forwards to Base UI. */
119
+ export interface NavigationMenuBackdropProps extends ComponentProps<'div'> {
120
+ }
121
+ /**
122
+ * A list of links with groups that expand and collapse.
123
+ *
124
+ * **It knows it holds links, and that is what every part is for.** A link can be
125
+ * opened in a new tab, copied by address, middle-clicked and crawled; a command
126
+ * cannot do any of those, and a menu that renders a command where a reader
127
+ * expected a destination gives them a middle-click that does nothing. So
128
+ * `NavigationMenuLink` is the only interactive leaf here and it is a native
129
+ * anchor, there is no command part to reach for by mistake, and a caller who
130
+ * wants commands in a header is using a Menubar or a DropdownMenu instead.
131
+ * `active` is a required prop on the link because a navigation menu that does
132
+ * not say where the reader is has made them guess.
133
+ *
134
+ * **A closed group shows nothing, and that is deliberate.** The list is a
135
+ * `<ul>` of triggers, and the links live in a group that is only in the document
136
+ * while it is open. A reader with JavaScript off, and a crawler, therefore see
137
+ * the triggers and nothing else, which is why `NavigationMenuContent` takes
138
+ * `keepMounted` for the consumer who needs the header to read the same either
139
+ * way and owns the layout shift that follows. Do not put a destination only in
140
+ * a closed group.
141
+ *
142
+ * The bar is one Tab stop: Tab moves through the triggers and into the open
143
+ * group, Escape closes the group and returns focus to the trigger that opened
144
+ * it. Use a Menubar for an application window's commands and a DropdownMenu for
145
+ * a menu attached to one control.
146
+ */
147
+ declare function NavigationMenu({ className, label, orientation, ...props }: NavigationMenuProps): import("react").JSX.Element;
148
+ /** The row of group triggers. */
149
+ declare function NavigationMenuList({ className, ...props }: NavigationMenuListProps): import("react").JSX.Element;
150
+ /** One group: a trigger and the links it opens. */
151
+ declare function NavigationMenuItem({ className, ...props }: NavigationMenuItemProps): import("react").JSX.Element;
152
+ /**
153
+ * The control that opens a group, and the only Tab stop for it.
154
+ *
155
+ * It is a real button and it owns the expanded state, so a reader knows the
156
+ * group is open before they enter it. The chevron rotates on the open state
157
+ * rather than on a timer, which is the only motion here: something happened and
158
+ * the reader can see that it did.
159
+ */
160
+ declare function NavigationMenuTrigger({ className, children, ...props }: NavigationMenuTriggerProps): import("react").JSX.Element;
161
+ /** The group of links a trigger opens. */
162
+ declare function NavigationMenuContent({ className, ...props }: NavigationMenuContentProps): import("react").JSX.Element;
163
+ /**
164
+ * One destination, rendered as a native anchor.
165
+ *
166
+ * This is the only interactive leaf the Component ships, and the reason is the
167
+ * difference between a link and a command: a link carries an address, so the
168
+ * browser can open it in a new tab, copy it, and a crawler can follow it. A
169
+ * command has none of those, and a header that renders commands where a reader
170
+ * expected destinations is a header whose links cannot be shared.
171
+ */
172
+ declare function NavigationMenuLink({ className, active, ...props }: NavigationMenuLinkProps): import("react").JSX.Element;
173
+ /** The chevron slot, so a caller can put their own mark beside a trigger's words. */
174
+ declare function NavigationMenuIcon({ className, ...props }: NavigationMenuIconProps): import("react").JSX.Element;
175
+ /** The portal the open group is rendered into. */
176
+ declare function NavigationMenuPortal({ ...props }: NavigationMenuPortalProps): import("react").JSX.Element;
177
+ /** The positioned wrapper around the open group. */
178
+ declare function NavigationMenuPositioner({ className, sideOffset, alignOffset, ...props }: NavigationMenuPositionerProps): import("react").JSX.Element;
179
+ /** The surface the open group sits on. */
180
+ declare function NavigationMenuPopup({ className, ...props }: NavigationMenuPopupProps): import("react").JSX.Element;
181
+ /** The area one group's content is measured and animated in. */
182
+ declare function NavigationMenuViewport({ className, ...props }: NavigationMenuViewportProps): import("react").JSX.Element;
183
+ /** The scrim behind an open group, so the page behind does not read as live. */
184
+ declare function NavigationMenuBackdrop({ className, ...props }: NavigationMenuBackdropProps): import("react").JSX.Element;
185
+ export { NavigationMenu, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink, NavigationMenuIcon, NavigationMenuPortal, NavigationMenuPositioner, NavigationMenuPopup, NavigationMenuViewport, NavigationMenuBackdrop, };
186
+ //# sourceMappingURL=navigation-menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-menu.d.ts","sourceRoot":"","sources":["../../../src/components/ui/navigation-menu.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { NavigationMenu as NavigationMenuPrimitive } from '@base-ui/react/navigation-menu';
4
+ import { ChevronDownIcon } from 'lucide-react';
5
+ import { cn } from '../../lib/utils.js';
6
+ /**
7
+ * A list of links with groups that expand and collapse.
8
+ *
9
+ * **It knows it holds links, and that is what every part is for.** A link can be
10
+ * opened in a new tab, copied by address, middle-clicked and crawled; a command
11
+ * cannot do any of those, and a menu that renders a command where a reader
12
+ * expected a destination gives them a middle-click that does nothing. So
13
+ * `NavigationMenuLink` is the only interactive leaf here and it is a native
14
+ * anchor, there is no command part to reach for by mistake, and a caller who
15
+ * wants commands in a header is using a Menubar or a DropdownMenu instead.
16
+ * `active` is a required prop on the link because a navigation menu that does
17
+ * not say where the reader is has made them guess.
18
+ *
19
+ * **A closed group shows nothing, and that is deliberate.** The list is a
20
+ * `<ul>` of triggers, and the links live in a group that is only in the document
21
+ * while it is open. A reader with JavaScript off, and a crawler, therefore see
22
+ * the triggers and nothing else, which is why `NavigationMenuContent` takes
23
+ * `keepMounted` for the consumer who needs the header to read the same either
24
+ * way and owns the layout shift that follows. Do not put a destination only in
25
+ * a closed group.
26
+ *
27
+ * The bar is one Tab stop: Tab moves through the triggers and into the open
28
+ * group, Escape closes the group and returns focus to the trigger that opened
29
+ * it. Use a Menubar for an application window's commands and a DropdownMenu for
30
+ * a menu attached to one control.
31
+ */
32
+ function NavigationMenu({ className, label, orientation = 'horizontal', ...props }) {
33
+ return (_jsx(NavigationMenuPrimitive.Root, { "data-slot": "navigation-menu", "aria-label": label, orientation: orientation, className: cn('relative flex max-w-max flex-1 items-center justify-center', 'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch', className), ...props }));
34
+ }
35
+ /** The row of group triggers. */
36
+ function NavigationMenuList({ className, ...props }) {
37
+ return (_jsx(NavigationMenuPrimitive.List, { "data-slot": "navigation-menu-list", className: cn('flex flex-1 list-none items-center gap-1', 'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch', className), ...props }));
38
+ }
39
+ /** One group: a trigger and the links it opens. */
40
+ function NavigationMenuItem({ className, ...props }) {
41
+ return (_jsx(NavigationMenuPrimitive.Item, { "data-slot": "navigation-menu-item", className: cn('relative', className), ...props }));
42
+ }
43
+ /**
44
+ * The control that opens a group, and the only Tab stop for it.
45
+ *
46
+ * It is a real button and it owns the expanded state, so a reader knows the
47
+ * group is open before they enter it. The chevron rotates on the open state
48
+ * rather than on a timer, which is the only motion here: something happened and
49
+ * the reader can see that it did.
50
+ */
51
+ function NavigationMenuTrigger({ className, children, ...props }) {
52
+ return (_jsxs(NavigationMenuPrimitive.Trigger, { "data-slot": "navigation-menu-trigger", className: cn('text-foreground group inline-flex h-9 items-center gap-1.5 rounded-md px-3 text-sm font-medium whitespace-nowrap outline-none', 'transition-[color,background-color,box-shadow] duration-fast ease-out', 'hover:bg-accent hover:text-accent-foreground focus-visible:ring-ring focus-visible:ring-[3px]', 'data-[popup-open]:bg-accent/60 data-[popup-open]:text-accent-foreground', className), ...props, children: [children, _jsx(NavigationMenuIcon, { children: _jsx(ChevronDownIcon, { className: "size-4 transition-transform duration-base ease-out group-data-[popup-open]:rotate-180" }) })] }));
53
+ }
54
+ /** The group of links a trigger opens. */
55
+ function NavigationMenuContent({ className, ...props }) {
56
+ return (_jsx(NavigationMenuPrimitive.Content, { "data-slot": "navigation-menu-content", className: cn('p-2', className), ...props }));
57
+ }
58
+ /**
59
+ * One destination, rendered as a native anchor.
60
+ *
61
+ * This is the only interactive leaf the Component ships, and the reason is the
62
+ * difference between a link and a command: a link carries an address, so the
63
+ * browser can open it in a new tab, copy it, and a crawler can follow it. A
64
+ * command has none of those, and a header that renders commands where a reader
65
+ * expected destinations is a header whose links cannot be shared.
66
+ */
67
+ function NavigationMenuLink({ className, active, ...props }) {
68
+ return (_jsx(NavigationMenuPrimitive.Link, { "data-slot": "navigation-menu-link", active: active, className: cn('hover:bg-accent hover:text-accent-foreground focus-visible:ring-ring focus-visible:ring-[3px] block rounded-md px-3 py-2 text-sm outline-none', 'transition-[color,background-color,box-shadow] duration-fast ease-out', 'data-[active]:bg-accent data-[active]:text-accent-foreground data-[active]:font-medium', className), ...props }));
69
+ }
70
+ /** The chevron slot, so a caller can put their own mark beside a trigger's words. */
71
+ function NavigationMenuIcon({ className, ...props }) {
72
+ return (_jsx(NavigationMenuPrimitive.Icon, { "data-slot": "navigation-menu-icon", className: cn('flex size-4 items-center justify-center', className), ...props }));
73
+ }
74
+ /** The portal the open group is rendered into. */
75
+ function NavigationMenuPortal({ ...props }) {
76
+ return _jsx(NavigationMenuPrimitive.Portal, { ...props });
77
+ }
78
+ /** The positioned wrapper around the open group. */
79
+ function NavigationMenuPositioner({ className, sideOffset = 8, alignOffset = 0, ...props }) {
80
+ return (_jsx(NavigationMenuPrimitive.Positioner, { "data-slot": "navigation-menu-positioner", sideOffset: sideOffset, alignOffset: alignOffset, className: cn('z-50', className), ...props }));
81
+ }
82
+ /** The surface the open group sits on. */
83
+ function NavigationMenuPopup({ className, ...props }) {
84
+ return (_jsx(NavigationMenuPrimitive.Popup, { "data-slot": "navigation-menu-popup", className: cn('bg-popover text-popover-foreground origin-(--transform-origin) rounded-lg border p-2 shadow-md outline-none', 'transition-[opacity,transform] duration-base 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 }));
85
+ }
86
+ /** The area one group's content is measured and animated in. */
87
+ function NavigationMenuViewport({ className, ...props }) {
88
+ return (_jsx(NavigationMenuPrimitive.Viewport, { "data-slot": "navigation-menu-viewport", className: cn('relative h-full w-full overflow-hidden', className), ...props }));
89
+ }
90
+ /** The scrim behind an open group, so the page behind does not read as live. */
91
+ function NavigationMenuBackdrop({ className, ...props }) {
92
+ return (_jsx(NavigationMenuPrimitive.Backdrop, { "data-slot": "navigation-menu-backdrop", className: cn('fixed inset-0 z-40 bg-background/40 transition-opacity duration-base ease-out data-[starting-style]:opacity-0 data-[ending-style]:opacity-0', className), ...props }));
93
+ }
94
+ export { NavigationMenu, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink, NavigationMenuIcon, NavigationMenuPortal, NavigationMenuPositioner, NavigationMenuPopup, NavigationMenuViewport, NavigationMenuBackdrop, };
@@ -0,0 +1,111 @@
1
+ /** The props the Number field accepts. */
2
+ export interface NumberFieldProps {
3
+ /**
4
+ * The accessible names of the two steppers.
5
+ *
6
+ * Required, and required as a pair, because a stepper is an icon and an icon has
7
+ * no name. The words are the caller's because they are sentences a reader hears,
8
+ * and a Component that chose them would be shipping English into every consumer's
9
+ * form and would get "increase" wrong for at least one of the two.
10
+ */
11
+ labels: {
12
+ increment: string;
13
+ decrement: string;
14
+ };
15
+ /** The accessible name of the field, when no visible label is used. */
16
+ 'aria-label'?: string;
17
+ /** The current value, when the field is controlled. */
18
+ value?: number | null;
19
+ /** The value the field starts at, for an uncontrolled field. */
20
+ defaultValue?: number | null;
21
+ /** Called with the value, or `null` when the field is emptied. */
22
+ onValueChange?: (value: number | null) => void;
23
+ /**
24
+ * The smallest value the field will hold.
25
+ *
26
+ * A value below it is clamped, by typing, by the steppers and by a paste alike.
27
+ * Without a minimum there is nothing to clamp against, so this and `max` are what
28
+ * turn a number field from a text field that happens to accept digits into a
29
+ * control that holds a range.
30
+ */
31
+ min?: number;
32
+ /** The largest value the field will hold. */
33
+ max?: number;
34
+ /** The amount one press of a stepper changes the value by. @defaultValue 1 */
35
+ step?: number;
36
+ /**
37
+ * The unit shown after the number.
38
+ *
39
+ * A unit is a word in the reader's language and it is hidden from the
40
+ * accessibility tree, because a screen reader already says the unit when the
41
+ * caller puts it in the field's description. It is a prop because the Component
42
+ * does not know whether the reader measures in kilograms, pounds or seconds.
43
+ */
44
+ unit?: string;
45
+ /** How the value is written for display: grouping, decimals, and so on. */
46
+ format?: Intl.NumberFormatOptions;
47
+ /** Whether a value must be entered before the form submits. */
48
+ required?: boolean;
49
+ /** Whether the field ignores interaction. */
50
+ disabled?: boolean;
51
+ /** Whether the reader may see the value but not change it. */
52
+ readOnly?: boolean;
53
+ /** The form field name. The value is submitted under it. */
54
+ name?: string;
55
+ /** Identifies the form that owns the hidden input. */
56
+ form?: string;
57
+ /** The field's own id, so a label elsewhere can point at it. */
58
+ id?: string;
59
+ /** Layout only. */
60
+ className?: string;
61
+ }
62
+ /**
63
+ * A numeric field that will not hold a value outside its own range.
64
+ *
65
+ * **Clamping is the Component, not the HTML.** A number field with a `max` that
66
+ * accepts a value past it is a field that will submit a number the caller has
67
+ * already said is impossible, and the browser's own range validation is no answer
68
+ * to that: it reports the problem after the reader has typed and leaves them with a
69
+ * value they cannot submit. So the value is clamped on every path that can produce
70
+ * one, typing, the steppers, a paste and a value that arrived from outside, and
71
+ * the field shows and submits only what is inside its range. Text that is not a
72
+ * number never becomes a value at all: the field refuses the character as it is
73
+ * typed, so a reader who mistypes a digit gets a shorter number rather than a
74
+ * number the server will reject.
75
+ *
76
+ * **It is one Component rather than a root, a group, an input and two steppers.**
77
+ * The range and the two ways of moving inside it are one contract, and a caller
78
+ * who composes the parts can leave out the steppers and get a field that clamps
79
+ * with no affordance to reach the middle of its own range. The parts Base UI owns
80
+ * are still what draw and what enforce; what this adds is the decision not to let
81
+ * them be rearranged into something else.
82
+ *
83
+ * **A value outside the range is clamped as it arrives rather than refused.** A
84
+ * controlled field whose `value` prop is out of range displays the clamped number,
85
+ * because the alternative is a field showing one number and submitting another.
86
+ * `onValueChange` is the authority: a consumer whose own state holds an
87
+ * out-of-range number has to take the clamped one back, and this Component will
88
+ * not rewrite a state it does not own.
89
+ *
90
+ * **The steppers are in the tab order.** Base UI takes them out of it, on the
91
+ * reasoning that the arrow keys already step the value and one field should be one
92
+ * Tab stop. A control that is announced and cannot be reached is worse than a
93
+ * second stop, so they are put back: three stops for one value, and the arrow keys
94
+ * still work for a reader who is typing through the form.
95
+ *
96
+ * **Empty is a value.** The field reports `null` when it is cleared, rather than
97
+ * zero, because zero is a number a reader may have meant and an empty field is
98
+ * not. A consumer that treats `null` as zero has made a decision this Component
99
+ * refuses to make for it.
100
+ *
101
+ * **The unit is decoration.** It is hidden from the accessibility tree and the
102
+ * caller describes the field once, in words, where a screen reader will reach it.
103
+ * Two announcements of the same unit is one too many, and the visible one is the
104
+ * one that was written in the reader's language by the reader's own product.
105
+ *
106
+ * Reachable by Tab, moved by the arrow keys and by its two steppers, and the whole
107
+ * field reads as one surface: one frame, one border, one focus colour.
108
+ */
109
+ declare function NumberField({ labels, 'aria-label': ariaLabel, value, defaultValue, onValueChange, min, max, step, unit, format, required, disabled, readOnly, name, form, id, className, }: NumberFieldProps): import("react").JSX.Element;
110
+ export { NumberField };
111
+ //# sourceMappingURL=number-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"number-field.d.ts","sourceRoot":"","sources":["../../../src/components/ui/number-field.tsx"],"names":[],"mappings":"AAOA,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAChD,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,kEAAkE;IAClE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC9C;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,6CAA6C;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2EAA2E;IAC3E,MAAM,CAAC,EAAE,IAAI,CAAC,mBAAmB,CAAA;IACjC,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,4DAA4D;IAC5D,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;AAwBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,iBAAS,WAAW,CAAC,EACnB,MAAM,EACN,YAAY,EAAE,SAAS,EACvB,KAAK,EACL,YAAmB,EACnB,aAAa,EACb,GAAG,EACH,GAAG,EACH,IAAQ,EACR,IAAI,EACJ,MAAM,EACN,QAAgB,EAChB,QAAgB,EAChB,QAAgB,EAChB,IAAI,EACJ,IAAI,EACJ,EAAE,EACF,SAAS,GACV,EAAE,gBAAgB,+BAsFlB;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -0,0 +1,84 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { NumberField as NumberFieldPrimitive } from '@base-ui/react/number-field';
4
+ import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
5
+ import { cn } from '../../lib/utils.js';
6
+ /**
7
+ * The value inside the field's own range, or nothing.
8
+ *
9
+ * Base UI clamps what the reader types and what the steppers reach, but it does
10
+ * not clamp a value that was already outside the range when it arrived, so this is
11
+ * the Component's own half of the promise. A field that accepted it would display
12
+ * and submit a number the caller has already said is impossible, and the browser's
13
+ * range validation answers that after the reader has typed, which is too late to
14
+ * be a control and too late to be a form.
15
+ */
16
+ function clamp(value, min, max) {
17
+ if (value === null || value === undefined || !Number.isFinite(value))
18
+ return null;
19
+ let out = value;
20
+ if (typeof min === 'number' && out < min)
21
+ out = min;
22
+ if (typeof max === 'number' && out > max)
23
+ out = max;
24
+ return out;
25
+ }
26
+ /**
27
+ * A numeric field that will not hold a value outside its own range.
28
+ *
29
+ * **Clamping is the Component, not the HTML.** A number field with a `max` that
30
+ * accepts a value past it is a field that will submit a number the caller has
31
+ * already said is impossible, and the browser's own range validation is no answer
32
+ * to that: it reports the problem after the reader has typed and leaves them with a
33
+ * value they cannot submit. So the value is clamped on every path that can produce
34
+ * one, typing, the steppers, a paste and a value that arrived from outside, and
35
+ * the field shows and submits only what is inside its range. Text that is not a
36
+ * number never becomes a value at all: the field refuses the character as it is
37
+ * typed, so a reader who mistypes a digit gets a shorter number rather than a
38
+ * number the server will reject.
39
+ *
40
+ * **It is one Component rather than a root, a group, an input and two steppers.**
41
+ * The range and the two ways of moving inside it are one contract, and a caller
42
+ * who composes the parts can leave out the steppers and get a field that clamps
43
+ * with no affordance to reach the middle of its own range. The parts Base UI owns
44
+ * are still what draw and what enforce; what this adds is the decision not to let
45
+ * them be rearranged into something else.
46
+ *
47
+ * **A value outside the range is clamped as it arrives rather than refused.** A
48
+ * controlled field whose `value` prop is out of range displays the clamped number,
49
+ * because the alternative is a field showing one number and submitting another.
50
+ * `onValueChange` is the authority: a consumer whose own state holds an
51
+ * out-of-range number has to take the clamped one back, and this Component will
52
+ * not rewrite a state it does not own.
53
+ *
54
+ * **The steppers are in the tab order.** Base UI takes them out of it, on the
55
+ * reasoning that the arrow keys already step the value and one field should be one
56
+ * Tab stop. A control that is announced and cannot be reached is worse than a
57
+ * second stop, so they are put back: three stops for one value, and the arrow keys
58
+ * still work for a reader who is typing through the form.
59
+ *
60
+ * **Empty is a value.** The field reports `null` when it is cleared, rather than
61
+ * zero, because zero is a number a reader may have meant and an empty field is
62
+ * not. A consumer that treats `null` as zero has made a decision this Component
63
+ * refuses to make for it.
64
+ *
65
+ * **The unit is decoration.** It is hidden from the accessibility tree and the
66
+ * caller describes the field once, in words, where a screen reader will reach it.
67
+ * Two announcements of the same unit is one too many, and the visible one is the
68
+ * one that was written in the reader's language by the reader's own product.
69
+ *
70
+ * Reachable by Tab, moved by the arrow keys and by its two steppers, and the whole
71
+ * field reads as one surface: one frame, one border, one focus colour.
72
+ */
73
+ function NumberField({ labels, 'aria-label': ariaLabel, value, defaultValue = null, onValueChange, min, max, step = 1, unit, format, required = false, disabled = false, readOnly = false, name, form, id, className, }) {
74
+ return (_jsx(NumberFieldPrimitive.Root, { "data-slot": "number-field", className: cn('w-full', className), ...(value === undefined
75
+ ? { defaultValue: clamp(defaultValue, min, max) ?? undefined }
76
+ : { value: clamp(value, min, max) }), onValueChange: (next) => onValueChange?.(next),
77
+ // The id belongs to the root, not to the input, because Base UI's steppers
78
+ // point their `aria-controls` at it and a dangling reference is a violation
79
+ // that reads, in a screen reader, as a control pointing at nothing.
80
+ id: id, min: min, max: max, step: step, required: required, disabled: disabled, readOnly: readOnly, name: name, ...(form === undefined ? null : { form }), ...(format === undefined ? null : { format }), children: _jsxs("div", { "data-slot": "number-field-group", className: cn('border-input bg-background focus-within:border-ring flex w-full items-stretch rounded-md border shadow-xs', 'transition-[color,box-shadow] duration-fast ease-out', 'has-[input:disabled]:opacity-50'), children: [_jsx(NumberFieldPrimitive.Input, { "data-slot": "number-field-input", "aria-label": ariaLabel, className: cn('placeholder:text-muted-foreground flex h-9 min-w-0 flex-1 border-0 bg-transparent px-3 py-1 text-base shadow-none outline-none md:text-sm', 'focus-visible:border-0 focus-visible:ring-ring focus-visible:ring-[3px]') }), unit === undefined ? null : (_jsx("span", { "data-slot": "number-field-unit", "aria-hidden": "true", className: "text-muted-foreground flex shrink-0 items-center pr-2 text-sm", children: unit })), _jsxs("div", { "data-slot": "number-field-stepper", className: "border-input flex shrink-0 flex-col border-s", children: [_jsx(NumberFieldPrimitive.Increment, { "data-slot": "number-field-increment", "aria-label": labels.increment,
81
+ // Put back into the tab order on purpose; see the JSDoc.
82
+ tabIndex: 0, className: cn('text-muted-foreground hover:bg-accent hover:text-accent-foreground flex h-1/2 items-center justify-center border-b px-2 outline-none', 'transition-colors duration-fast ease-out focus-visible:ring-ring focus-visible:ring-[3px]', 'data-[disabled]:pointer-events-none data-[disabled]:opacity-40'), children: _jsx(ChevronUpIcon, { className: "size-3.5" }) }), _jsx(NumberFieldPrimitive.Decrement, { "data-slot": "number-field-decrement", "aria-label": labels.decrement, tabIndex: 0, className: cn('text-muted-foreground hover:bg-accent hover:text-accent-foreground flex h-1/2 items-center justify-center px-2 outline-none', 'transition-colors duration-fast ease-out focus-visible:ring-ring focus-visible:ring-[3px]', 'data-[disabled]:pointer-events-none data-[disabled]:opacity-40'), children: _jsx(ChevronDownIcon, { className: "size-3.5" }) })] })] }) }));
83
+ }
84
+ export { NumberField };