zabi-components 8.0.0 → 9.0.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 (456) hide show
  1. package/CHANGELOG.md +2935 -0
  2. package/README.md +243 -10
  3. package/THEME.md +162 -332
  4. package/THEMING.md +1419 -259
  5. package/dist/atoms/ActionPanel.svelte +15 -5
  6. package/dist/atoms/Avatar.svelte +120 -0
  7. package/dist/atoms/Avatar.svelte.d.ts +46 -0
  8. package/dist/atoms/Badge.svelte +71 -13
  9. package/dist/atoms/Badge.svelte.d.ts +8 -2
  10. package/dist/atoms/Block.svelte +74 -0
  11. package/dist/atoms/Block.svelte.d.ts +29 -0
  12. package/dist/atoms/Button.svelte +217 -30
  13. package/dist/atoms/Button.svelte.d.ts +33 -4
  14. package/dist/atoms/Card.svelte +182 -26
  15. package/dist/atoms/Card.svelte.d.ts +55 -3
  16. package/dist/atoms/CardHeader.svelte +16 -4
  17. package/dist/atoms/Checkbox.svelte +81 -21
  18. package/dist/atoms/Checkbox.svelte.d.ts +31 -2
  19. package/dist/atoms/Chip.svelte +351 -0
  20. package/dist/atoms/Chip.svelte.d.ts +57 -0
  21. package/dist/atoms/CodeBlock.svelte +20 -2
  22. package/dist/atoms/CodeBlock.svelte.d.ts +4 -0
  23. package/dist/atoms/CodeField.svelte +385 -0
  24. package/dist/atoms/CodeField.svelte.d.ts +61 -0
  25. package/dist/atoms/ColorPicker.svelte +260 -49
  26. package/dist/atoms/ColorPicker.svelte.d.ts +3 -0
  27. package/dist/atoms/Container.svelte +16 -8
  28. package/dist/atoms/DateField.svelte +145 -0
  29. package/dist/atoms/DateField.svelte.d.ts +81 -0
  30. package/dist/atoms/FieldMessages.svelte +69 -0
  31. package/dist/atoms/FieldMessages.svelte.d.ts +23 -0
  32. package/dist/atoms/FloatingActionButton.svelte +176 -0
  33. package/dist/atoms/FloatingActionButton.svelte.d.ts +51 -0
  34. package/dist/atoms/Heading.svelte +63 -5
  35. package/dist/atoms/Heading.svelte.d.ts +14 -0
  36. package/dist/atoms/IconButton.svelte +294 -26
  37. package/dist/atoms/IconButton.svelte.d.ts +62 -4
  38. package/dist/atoms/Input.svelte +259 -53
  39. package/dist/atoms/Input.svelte.d.ts +33 -2
  40. package/dist/atoms/List.svelte +5 -1
  41. package/dist/atoms/ListItem.svelte +70 -13
  42. package/dist/atoms/ListItem.svelte.d.ts +11 -0
  43. package/dist/atoms/PickerField.svelte +239 -0
  44. package/dist/atoms/PickerField.svelte.d.ts +67 -0
  45. package/dist/atoms/Progress.svelte +99 -19
  46. package/dist/atoms/Progress.svelte.d.ts +15 -1
  47. package/dist/atoms/Radio.svelte +51 -3
  48. package/dist/atoms/Radio.svelte.d.ts +30 -2
  49. package/dist/atoms/Rating.svelte +620 -0
  50. package/dist/atoms/Rating.svelte.d.ts +77 -0
  51. package/dist/atoms/Select.svelte +438 -98
  52. package/dist/atoms/Select.svelte.d.ts +61 -3
  53. package/dist/atoms/SelectionControl.svelte +193 -23
  54. package/dist/atoms/SelectionControl.svelte.d.ts +29 -3
  55. package/dist/atoms/Skeleton.svelte +114 -18
  56. package/dist/atoms/Skeleton.svelte.d.ts +30 -3
  57. package/dist/atoms/SkeletonGroup.svelte +43 -0
  58. package/dist/atoms/SkeletonGroup.svelte.d.ts +20 -0
  59. package/dist/atoms/Slider.svelte +344 -0
  60. package/dist/atoms/Slider.svelte.d.ts +40 -0
  61. package/dist/atoms/Sparkline.svelte +109 -0
  62. package/dist/atoms/Sparkline.svelte.d.ts +27 -0
  63. package/dist/atoms/SpeechBubble.svelte +187 -0
  64. package/dist/atoms/SpeechBubble.svelte.d.ts +33 -0
  65. package/dist/atoms/Spinner.svelte +57 -0
  66. package/dist/atoms/Spinner.svelte.d.ts +19 -0
  67. package/dist/atoms/Stat.svelte +72 -0
  68. package/dist/atoms/Stat.svelte.d.ts +19 -0
  69. package/dist/atoms/Table.svelte +151 -6
  70. package/dist/atoms/Table.svelte.d.ts +15 -3
  71. package/dist/atoms/TemporalField.svelte +472 -0
  72. package/dist/atoms/TemporalField.svelte.d.ts +48 -0
  73. package/dist/atoms/Text.svelte +23 -11
  74. package/dist/atoms/Text.svelte.d.ts +6 -3
  75. package/dist/atoms/Textarea.svelte +150 -44
  76. package/dist/atoms/Textarea.svelte.d.ts +35 -2
  77. package/dist/atoms/ThemeToggle.svelte +223 -44
  78. package/dist/atoms/ThemeToggle.svelte.d.ts +26 -3
  79. package/dist/atoms/TimeColumn.svelte +150 -0
  80. package/dist/atoms/TimeColumn.svelte.d.ts +25 -0
  81. package/dist/atoms/TimeField.svelte +151 -0
  82. package/dist/atoms/TimeField.svelte.d.ts +85 -0
  83. package/dist/atoms/Toast.svelte +22 -8
  84. package/dist/atoms/Toast.svelte.d.ts +2 -0
  85. package/dist/atoms/Toggle.svelte +98 -14
  86. package/dist/atoms/Toggle.svelte.d.ts +26 -2
  87. package/dist/atoms/Tooltip.svelte +528 -24
  88. package/dist/atoms/Tooltip.svelte.d.ts +18 -0
  89. package/dist/atoms/ZabiStringsProvider.svelte +45 -0
  90. package/dist/atoms/ZabiStringsProvider.svelte.d.ts +27 -0
  91. package/dist/atoms/index.d.ts +38 -0
  92. package/dist/atoms/index.js +29 -0
  93. package/dist/atoms/selection-control.styles.d.ts +47 -5
  94. package/dist/atoms/selection-control.styles.js +52 -10
  95. package/dist/components/atoms/index.d.ts +38 -0
  96. package/dist/components/atoms/index.d.ts.map +1 -1
  97. package/dist/components/atoms/selection-control.styles.d.ts +47 -5
  98. package/dist/components/atoms/selection-control.styles.d.ts.map +1 -1
  99. package/dist/components/index.d.ts +104 -2
  100. package/dist/components/index.d.ts.map +1 -1
  101. package/dist/components/map.d.ts +11 -0
  102. package/dist/components/map.d.ts.map +1 -0
  103. package/dist/components/molecules/index.d.ts +51 -0
  104. package/dist/components/molecules/index.d.ts.map +1 -1
  105. package/dist/components/molecules/toast-store.d.ts +83 -7
  106. package/dist/components/molecules/toast-store.d.ts.map +1 -1
  107. package/dist/components/organisms/index.d.ts +10 -0
  108. package/dist/components/organisms/index.d.ts.map +1 -1
  109. package/dist/components/types/variants.d.ts +24 -1
  110. package/dist/components/types/variants.d.ts.map +1 -1
  111. package/dist/components/util/app-shell.d.ts +79 -0
  112. package/dist/components/util/app-shell.d.ts.map +1 -0
  113. package/dist/components/util/avatar.d.ts +39 -0
  114. package/dist/components/util/avatar.d.ts.map +1 -0
  115. package/dist/components/util/bottom-sheet.d.ts +30 -0
  116. package/dist/components/util/bottom-sheet.d.ts.map +1 -0
  117. package/dist/components/util/bottom-tab-bar.d.ts +41 -0
  118. package/dist/components/util/bottom-tab-bar.d.ts.map +1 -0
  119. package/dist/components/util/calendar.d.ts +56 -0
  120. package/dist/components/util/calendar.d.ts.map +1 -0
  121. package/dist/components/util/chart.d.ts +140 -0
  122. package/dist/components/util/chart.d.ts.map +1 -0
  123. package/dist/components/util/chip.d.ts +66 -0
  124. package/dist/components/util/chip.d.ts.map +1 -0
  125. package/dist/components/util/cn.d.ts.map +1 -1
  126. package/dist/components/util/code-field.d.ts +63 -0
  127. package/dist/components/util/code-field.d.ts.map +1 -0
  128. package/dist/components/util/collapsible.d.ts +64 -0
  129. package/dist/components/util/collapsible.d.ts.map +1 -0
  130. package/dist/components/util/confirm-dialog.d.ts +12 -0
  131. package/dist/components/util/confirm-dialog.d.ts.map +1 -0
  132. package/dist/components/util/date.d.ts +96 -0
  133. package/dist/components/util/date.d.ts.map +1 -0
  134. package/dist/components/util/display-voice.d.ts +10 -0
  135. package/dist/components/util/display-voice.d.ts.map +1 -0
  136. package/dist/components/util/drawer.d.ts +13 -0
  137. package/dist/components/util/drawer.d.ts.map +1 -0
  138. package/dist/components/util/dropdown.d.ts +47 -0
  139. package/dist/components/util/dropdown.d.ts.map +1 -0
  140. package/dist/components/util/field-control.d.ts +30 -0
  141. package/dist/components/util/field-control.d.ts.map +1 -0
  142. package/dist/components/util/field.d.ts +45 -0
  143. package/dist/components/util/field.d.ts.map +1 -0
  144. package/dist/components/util/fit-in-viewport.d.ts +201 -0
  145. package/dist/components/util/fit-in-viewport.d.ts.map +1 -0
  146. package/dist/components/util/focus-utils.d.ts +77 -2
  147. package/dist/components/util/focus-utils.d.ts.map +1 -1
  148. package/dist/components/util/hydration.d.ts +45 -0
  149. package/dist/components/util/hydration.d.ts.map +1 -0
  150. package/dist/components/util/keyboard-inset.d.ts +18 -0
  151. package/dist/components/util/keyboard-inset.d.ts.map +1 -0
  152. package/dist/components/util/map-view.d.ts +144 -0
  153. package/dist/components/util/map-view.d.ts.map +1 -0
  154. package/dist/components/util/media-grid.d.ts +51 -0
  155. package/dist/components/util/media-grid.d.ts.map +1 -0
  156. package/dist/components/util/media.d.ts +6 -0
  157. package/dist/components/util/media.d.ts.map +1 -0
  158. package/dist/components/util/overlay-chrome.d.ts +53 -0
  159. package/dist/components/util/overlay-chrome.d.ts.map +1 -0
  160. package/dist/components/util/overlay.d.ts +72 -0
  161. package/dist/components/util/overlay.d.ts.map +1 -0
  162. package/dist/components/util/photo.d.ts +234 -0
  163. package/dist/components/util/photo.d.ts.map +1 -0
  164. package/dist/components/util/portal.d.ts +23 -0
  165. package/dist/components/util/portal.d.ts.map +1 -0
  166. package/dist/components/util/progress.d.ts +19 -0
  167. package/dist/components/util/progress.d.ts.map +1 -0
  168. package/dist/components/util/pull-to-refresh.d.ts +27 -0
  169. package/dist/components/util/pull-to-refresh.d.ts.map +1 -0
  170. package/dist/components/util/radio-keys.d.ts +25 -0
  171. package/dist/components/util/radio-keys.d.ts.map +1 -0
  172. package/dist/components/util/rating.d.ts +23 -0
  173. package/dist/components/util/rating.d.ts.map +1 -0
  174. package/dist/components/util/ready-made-strings.d.ts +77 -0
  175. package/dist/components/util/ready-made-strings.d.ts.map +1 -0
  176. package/dist/components/util/scroll-edge.d.ts +33 -0
  177. package/dist/components/util/scroll-edge.d.ts.map +1 -0
  178. package/dist/components/util/scroll-padding.d.ts +20 -0
  179. package/dist/components/util/scroll-padding.d.ts.map +1 -0
  180. package/dist/components/util/segmented-control.d.ts +16 -0
  181. package/dist/components/util/segmented-control.d.ts.map +1 -0
  182. package/dist/components/util/select.d.ts +41 -0
  183. package/dist/components/util/select.d.ts.map +1 -0
  184. package/dist/components/util/sheet-drag.d.ts +84 -0
  185. package/dist/components/util/sheet-drag.d.ts.map +1 -0
  186. package/dist/components/util/sidebar.d.ts +63 -0
  187. package/dist/components/util/sidebar.d.ts.map +1 -0
  188. package/dist/components/util/skeleton.d.ts +15 -0
  189. package/dist/components/util/skeleton.d.ts.map +1 -0
  190. package/dist/components/util/sliding-indicator.d.ts +25 -0
  191. package/dist/components/util/sliding-indicator.d.ts.map +1 -0
  192. package/dist/components/util/sortable-list.d.ts +65 -0
  193. package/dist/components/util/sortable-list.d.ts.map +1 -0
  194. package/dist/components/util/stepper.d.ts +40 -0
  195. package/dist/components/util/stepper.d.ts.map +1 -0
  196. package/dist/components/util/swipeable-list-item.d.ts +36 -0
  197. package/dist/components/util/swipeable-list-item.d.ts.map +1 -0
  198. package/dist/components/util/temporal-field.d.ts +89 -0
  199. package/dist/components/util/temporal-field.d.ts.map +1 -0
  200. package/dist/components/util/theme-mode.d.ts +80 -0
  201. package/dist/components/util/theme-mode.d.ts.map +1 -0
  202. package/dist/components/util/toaster.d.ts +133 -0
  203. package/dist/components/util/toaster.d.ts.map +1 -0
  204. package/dist/components/util/tone-surface.d.ts +34 -0
  205. package/dist/components/util/tone-surface.d.ts.map +1 -0
  206. package/dist/components/util/tooltip.d.ts +10 -0
  207. package/dist/components/util/tooltip.d.ts.map +1 -0
  208. package/dist/components/util/top-navbar.d.ts +35 -0
  209. package/dist/components/util/top-navbar.d.ts.map +1 -0
  210. package/dist/components/util/touch-target.d.ts +31 -0
  211. package/dist/components/util/touch-target.d.ts.map +1 -0
  212. package/dist/components/util/zabi-strings.d.ts +142 -0
  213. package/dist/components/util/zabi-strings.d.ts.map +1 -0
  214. package/dist/create-theme/cli.js +173 -0
  215. package/dist/create-theme/index.d.ts +190 -0
  216. package/dist/create-theme/index.js +1034 -0
  217. package/dist/create-theme/lib/ramp-math.js +128 -0
  218. package/dist/create-theme/lib/resolve.js +238 -0
  219. package/dist/create-theme/theme-data.js +2644 -0
  220. package/dist/index.d.ts +104 -2
  221. package/dist/index.js +75 -2
  222. package/dist/map.d.ts +10 -0
  223. package/dist/map.js +9 -0
  224. package/dist/molecules/Alert.svelte +63 -16
  225. package/dist/molecules/Alert.svelte.d.ts +14 -1
  226. package/dist/molecules/AppBar.svelte +674 -0
  227. package/dist/molecules/AppBar.svelte.d.ts +131 -0
  228. package/dist/molecules/AvatarGroup.svelte +116 -0
  229. package/dist/molecules/AvatarGroup.svelte.d.ts +40 -0
  230. package/dist/molecules/BarChart.svelte +381 -0
  231. package/dist/molecules/BarChart.svelte.d.ts +45 -0
  232. package/dist/molecules/BottomSheet.svelte +608 -0
  233. package/dist/molecules/BottomSheet.svelte.d.ts +109 -0
  234. package/dist/molecules/BottomTabBar.svelte +403 -0
  235. package/dist/molecules/BottomTabBar.svelte.d.ts +98 -0
  236. package/dist/molecules/Calendar.svelte +597 -0
  237. package/dist/molecules/Calendar.svelte.d.ts +72 -0
  238. package/dist/molecules/ChipGroup.svelte +325 -0
  239. package/dist/molecules/ChipGroup.svelte.d.ts +41 -0
  240. package/dist/molecules/Collapsible.svelte +347 -0
  241. package/dist/molecules/Collapsible.svelte.d.ts +61 -0
  242. package/dist/molecules/CollapsibleGroup.svelte +136 -0
  243. package/dist/molecules/CollapsibleGroup.svelte.d.ts +14 -0
  244. package/dist/molecules/ComponentDemo.svelte +16 -4
  245. package/dist/molecules/ComponentDemo.svelte.d.ts +3 -0
  246. package/dist/molecules/ConfirmDialog.svelte +257 -0
  247. package/dist/molecules/ConfirmDialog.svelte.d.ts +58 -0
  248. package/dist/molecules/ContactForm.svelte +34 -17
  249. package/dist/molecules/ContactForm.svelte.d.ts +8 -0
  250. package/dist/molecules/Drawer.svelte +415 -0
  251. package/dist/molecules/Drawer.svelte.d.ts +55 -0
  252. package/dist/molecules/Dropdown.svelte +517 -48
  253. package/dist/molecules/Dropdown.svelte.d.ts +47 -6
  254. package/dist/molecules/DropdownItem.svelte +122 -0
  255. package/dist/molecules/DropdownItem.svelte.d.ts +28 -0
  256. package/dist/molecules/EmptyState.svelte +55 -10
  257. package/dist/molecules/EmptyState.svelte.d.ts +8 -0
  258. package/dist/molecules/FormField.svelte +9 -1
  259. package/dist/molecules/FormField.svelte.d.ts +2 -0
  260. package/dist/molecules/Header.svelte +1 -1
  261. package/dist/molecules/ImageUpload.svelte +492 -69
  262. package/dist/molecules/ImageUpload.svelte.d.ts +82 -2
  263. package/dist/molecules/LineChart.svelte +459 -0
  264. package/dist/molecules/LineChart.svelte.d.ts +53 -0
  265. package/dist/molecules/MapView.svelte +565 -0
  266. package/dist/molecules/MapView.svelte.d.ts +88 -0
  267. package/dist/molecules/MediaGrid.svelte +527 -0
  268. package/dist/molecules/MediaGrid.svelte.d.ts +77 -0
  269. package/dist/molecules/Modal.svelte +293 -72
  270. package/dist/molecules/Modal.svelte.d.ts +51 -2
  271. package/dist/molecules/NavigationMenuContent.svelte +58 -1
  272. package/dist/molecules/NavigationMenuItem.svelte +0 -1
  273. package/dist/molecules/NavigationMenuLink.svelte +1 -1
  274. package/dist/molecules/NavigationMenuList.svelte +10 -3
  275. package/dist/molecules/NavigationMenuTrigger.svelte +2 -2
  276. package/dist/molecules/Page.svelte +32 -2
  277. package/dist/molecules/Page.svelte.d.ts +11 -0
  278. package/dist/molecules/PhotoGrid.svelte +523 -0
  279. package/dist/molecules/PhotoGrid.svelte.d.ts +73 -0
  280. package/dist/molecules/PhotoViewer.svelte +1213 -0
  281. package/dist/molecules/PhotoViewer.svelte.d.ts +74 -0
  282. package/dist/molecules/PieChart.svelte +421 -0
  283. package/dist/molecules/PieChart.svelte.d.ts +51 -0
  284. package/dist/molecules/PropsTable.svelte +22 -10
  285. package/dist/molecules/PropsTable.svelte.d.ts +3 -0
  286. package/dist/molecules/PullToRefresh.svelte +263 -0
  287. package/dist/molecules/PullToRefresh.svelte.d.ts +52 -0
  288. package/dist/molecules/RadioGroup.svelte +72 -18
  289. package/dist/molecules/RadioGroup.svelte.d.ts +19 -3
  290. package/dist/molecules/Section.svelte +1 -1
  291. package/dist/molecules/SegmentedControl.svelte +456 -0
  292. package/dist/molecules/SegmentedControl.svelte.d.ts +40 -0
  293. package/dist/molecules/SidebarBrandHeader.svelte +11 -1
  294. package/dist/molecules/SidebarBrandHeader.svelte.d.ts +3 -0
  295. package/dist/molecules/SidebarFooter.svelte +30 -7
  296. package/dist/molecules/SidebarFooter.svelte.d.ts +3 -0
  297. package/dist/molecules/SidebarNavSection.svelte +1 -1
  298. package/dist/molecules/SlideUp.svelte +220 -61
  299. package/dist/molecules/SlideUp.svelte.d.ts +26 -0
  300. package/dist/molecules/SortableList.svelte +633 -0
  301. package/dist/molecules/SortableList.svelte.d.ts +69 -0
  302. package/dist/molecules/Stepper.svelte +562 -0
  303. package/dist/molecules/Stepper.svelte.d.ts +39 -0
  304. package/dist/molecules/StickyActionBar.svelte +250 -0
  305. package/dist/molecules/StickyActionBar.svelte.d.ts +78 -0
  306. package/dist/molecules/SwipeableListItem.svelte +334 -0
  307. package/dist/molecules/SwipeableListItem.svelte.d.ts +54 -0
  308. package/dist/molecules/Tabs.svelte +310 -9
  309. package/dist/molecules/Tabs.svelte.d.ts +7 -0
  310. package/dist/molecules/Toaster.svelte +514 -5
  311. package/dist/molecules/Toaster.svelte.d.ts +153 -2
  312. package/dist/molecules/ToasterToast.svelte +495 -77
  313. package/dist/molecules/ToasterToast.svelte.d.ts +15 -0
  314. package/dist/molecules/UnsavedChangesBar.svelte +223 -0
  315. package/dist/molecules/UnsavedChangesBar.svelte.d.ts +43 -0
  316. package/dist/molecules/index.d.ts +51 -0
  317. package/dist/molecules/index.js +31 -0
  318. package/dist/molecules/toast-store.d.ts +83 -7
  319. package/dist/molecules/toast-store.js +25 -1
  320. package/dist/organisms/AppNavigation.svelte +440 -0
  321. package/dist/organisms/AppNavigation.svelte.d.ts +72 -0
  322. package/dist/organisms/AppShell.svelte +696 -0
  323. package/dist/organisms/AppShell.svelte.d.ts +157 -0
  324. package/dist/organisms/AppShellHeaderPart.svelte +163 -0
  325. package/dist/organisms/AppShellHeaderPart.svelte.d.ts +57 -0
  326. package/dist/organisms/SidebarAccountPanel.svelte +107 -12
  327. package/dist/organisms/SidebarAccountPanel.svelte.d.ts +19 -0
  328. package/dist/organisms/SidebarNavigation.svelte +111 -43
  329. package/dist/organisms/SidebarNavigation.svelte.d.ts +29 -1
  330. package/dist/organisms/SidebarPanel.svelte +34 -17
  331. package/dist/organisms/SidebarPanel.svelte.d.ts +1 -0
  332. package/dist/organisms/SidebarShell.svelte +164 -14
  333. package/dist/organisms/SidebarShell.svelte.d.ts +56 -2
  334. package/dist/organisms/TopNavbar.svelte +353 -39
  335. package/dist/organisms/TopNavbar.svelte.d.ts +47 -0
  336. package/dist/organisms/TopNavbarSheetContent.svelte +145 -0
  337. package/dist/organisms/TopNavbarSheetContent.svelte.d.ts +24 -0
  338. package/dist/organisms/index.d.ts +10 -0
  339. package/dist/organisms/index.js +7 -0
  340. package/dist/types/components.d.ts +21 -1
  341. package/dist/types/components.d.ts.map +1 -1
  342. package/dist/types/index.d.ts +1093 -26
  343. package/dist/types/index.d.ts.map +1 -1
  344. package/dist/types/variants.ts +28 -1
  345. package/dist/util/app-shell.d.ts +78 -0
  346. package/dist/util/app-shell.js +97 -0
  347. package/dist/util/avatar.d.ts +38 -0
  348. package/dist/util/avatar.js +52 -0
  349. package/dist/util/bottom-sheet.d.ts +29 -0
  350. package/dist/util/bottom-sheet.js +43 -0
  351. package/dist/util/bottom-tab-bar.d.ts +40 -0
  352. package/dist/util/bottom-tab-bar.js +54 -0
  353. package/dist/util/calendar.d.ts +55 -0
  354. package/dist/util/calendar.js +74 -0
  355. package/dist/util/chart.d.ts +139 -0
  356. package/dist/util/chart.js +305 -0
  357. package/dist/util/chip.d.ts +65 -0
  358. package/dist/util/chip.js +58 -0
  359. package/dist/util/cn.js +28 -2
  360. package/dist/util/code-field.d.ts +62 -0
  361. package/dist/util/code-field.js +112 -0
  362. package/dist/util/collapsible.d.ts +63 -0
  363. package/dist/util/collapsible.js +23 -0
  364. package/dist/util/confirm-dialog.d.ts +11 -0
  365. package/dist/util/confirm-dialog.js +2 -0
  366. package/dist/util/date.d.ts +95 -0
  367. package/dist/util/date.js +237 -0
  368. package/dist/util/display-voice.d.ts +9 -0
  369. package/dist/util/display-voice.js +9 -0
  370. package/dist/util/drawer.d.ts +12 -0
  371. package/dist/util/drawer.js +7 -0
  372. package/dist/util/dropdown.d.ts +46 -0
  373. package/dist/util/dropdown.js +21 -0
  374. package/dist/util/field-control.d.ts +29 -0
  375. package/dist/util/field-control.js +32 -0
  376. package/dist/util/field.d.ts +44 -0
  377. package/dist/util/field.js +38 -0
  378. package/dist/util/fit-in-viewport.d.ts +200 -0
  379. package/dist/util/fit-in-viewport.js +399 -0
  380. package/dist/util/focus-utils.d.ts +77 -2
  381. package/dist/util/focus-utils.js +186 -9
  382. package/dist/util/hydration.d.ts +44 -0
  383. package/dist/util/hydration.js +58 -0
  384. package/dist/util/keyboard-inset.d.ts +17 -0
  385. package/dist/util/keyboard-inset.js +53 -0
  386. package/dist/util/map-view.d.ts +143 -0
  387. package/dist/util/map-view.js +121 -0
  388. package/dist/util/media-grid.d.ts +50 -0
  389. package/dist/util/media-grid.js +81 -0
  390. package/dist/util/media.d.ts +5 -0
  391. package/dist/util/media.js +10 -0
  392. package/dist/util/overlay-chrome.d.ts +52 -0
  393. package/dist/util/overlay-chrome.js +56 -0
  394. package/dist/util/overlay.d.ts +71 -0
  395. package/dist/util/overlay.js +240 -0
  396. package/dist/util/photo.d.ts +233 -0
  397. package/dist/util/photo.js +209 -0
  398. package/dist/util/portal.d.ts +22 -0
  399. package/dist/util/portal.js +50 -0
  400. package/dist/util/progress.d.ts +18 -0
  401. package/dist/util/progress.js +17 -0
  402. package/dist/util/pull-to-refresh.d.ts +26 -0
  403. package/dist/util/pull-to-refresh.js +30 -0
  404. package/dist/util/radio-keys.d.ts +24 -0
  405. package/dist/util/radio-keys.js +49 -0
  406. package/dist/util/rating.d.ts +22 -0
  407. package/dist/util/rating.js +26 -0
  408. package/dist/util/ready-made-strings.d.ts +76 -0
  409. package/dist/util/ready-made-strings.js +67 -0
  410. package/dist/util/scroll-edge.d.ts +32 -0
  411. package/dist/util/scroll-edge.js +87 -0
  412. package/dist/util/scroll-padding.d.ts +19 -0
  413. package/dist/util/scroll-padding.js +44 -0
  414. package/dist/util/segmented-control.d.ts +15 -0
  415. package/dist/util/segmented-control.js +1 -0
  416. package/dist/util/select.d.ts +40 -0
  417. package/dist/util/select.js +63 -0
  418. package/dist/util/sheet-drag.d.ts +83 -0
  419. package/dist/util/sheet-drag.js +311 -0
  420. package/dist/util/sidebar.d.ts +62 -0
  421. package/dist/util/sidebar.js +38 -0
  422. package/dist/util/skeleton.d.ts +14 -0
  423. package/dist/util/skeleton.js +22 -0
  424. package/dist/util/sliding-indicator.d.ts +24 -0
  425. package/dist/util/sliding-indicator.js +44 -0
  426. package/dist/util/sortable-list.d.ts +64 -0
  427. package/dist/util/sortable-list.js +53 -0
  428. package/dist/util/stepper.d.ts +39 -0
  429. package/dist/util/stepper.js +38 -0
  430. package/dist/util/swipeable-list-item.d.ts +35 -0
  431. package/dist/util/swipeable-list-item.js +32 -0
  432. package/dist/util/temporal-field.d.ts +88 -0
  433. package/dist/util/temporal-field.js +136 -0
  434. package/dist/util/theme-mode.d.ts +79 -0
  435. package/dist/util/theme-mode.js +121 -0
  436. package/dist/util/toaster.d.ts +132 -0
  437. package/dist/util/toaster.js +130 -0
  438. package/dist/util/tone-surface.d.ts +33 -0
  439. package/dist/util/tone-surface.js +35 -0
  440. package/dist/util/tooltip.d.ts +9 -0
  441. package/dist/util/tooltip.js +18 -0
  442. package/dist/util/top-navbar.d.ts +34 -0
  443. package/dist/util/top-navbar.js +28 -0
  444. package/dist/util/touch-target.d.ts +30 -0
  445. package/dist/util/touch-target.js +30 -0
  446. package/dist/util/zabi-strings.d.ts +141 -0
  447. package/dist/util/zabi-strings.js +105 -0
  448. package/dist/zabi-components-colors.css +11 -2
  449. package/dist/zabi-components-theme-dark-only.css +870 -258
  450. package/dist/zabi-components-theme-dark.css +870 -258
  451. package/dist/zabi-components-theme-only.css +2419 -368
  452. package/dist/zabi-components-theme.css +2419 -368
  453. package/dist/zabi-components.css +6032 -711
  454. package/docs/lucide-icons.md +40 -17
  455. package/docs/theme-imports.md +81 -11
  456. package/package.json +45 -8
package/dist/util/cn.js CHANGED
@@ -20,7 +20,9 @@ import { extendTailwindMerge } from "tailwind-merge";
20
20
  * role names, not scale values, so they have to be declared or tailwind-merge
21
21
  * keeps both and we are back to stylesheet order deciding.
22
22
  */
23
- const RADIUS_ROLES = ["control", "container", "overlay", "pill"];
23
+ // `button` is the control corner an app can set apart from its fields
24
+ // (`rounded-button`, src/app.css), so a call-site `rounded-full` still beats it.
25
+ const RADIUS_ROLES = ["control", "button", "container", "overlay", "pill"];
24
26
  /**
25
27
  * Every corner group tailwind-merge knows about, so `rounded-t-overlay` on a
26
28
  * sheet is still beaten by a call-site `rounded-t-control`. Declaring only the
@@ -32,9 +34,33 @@ const RADIUS_GROUPS = [
32
34
  "rounded-ss", "rounded-se", "rounded-ee", "rounded-es",
33
35
  "rounded-tl", "rounded-tr", "rounded-br", "rounded-bl",
34
36
  ];
37
+ /**
38
+ * The named spacing steps (`--spacing-xs` to `--spacing-2xl`, src/app.css).
39
+ * tailwind-merge knows the numeric scale only, so `p-xs p-sm` kept both and
40
+ * stylesheet order picked the padding. Declared as theme spacing, they count
41
+ * in every group that takes a spacing value: padding, margin, gap, inset,
42
+ * size, scroll padding and the rest.
43
+ */
44
+ const SPACING_STEPS = ["xs", "sm", "md", "lg", "xl", "2xl"];
35
45
  const twMerge = extendTailwindMerge({
36
46
  extend: {
37
- classGroups: Object.fromEntries(RADIUS_GROUPS.map((group) => [group, [{ [group]: RADIUS_ROLES }]])),
47
+ theme: {
48
+ spacing: SPACING_STEPS,
49
+ // The two theme faces (`font-heading`, `font-display`, from --font-heading
50
+ // and --font-display). tailwind-merge already reads any plain name after
51
+ // `font-` as a family; they are listed so that stays true if that rule
52
+ // narrows to the weights.
53
+ font: ["heading", "display"],
54
+ },
55
+ classGroups: {
56
+ ...Object.fromEntries(RADIUS_GROUPS.map((group) => [group, [{ [group]: RADIUS_ROLES }]])),
57
+ // The control veils are background images, not colours: without
58
+ // this they would delete the fill beside them (`bg-action-primary`)
59
+ // as a conflicting `bg-*`, and the fill would be gone.
60
+ "bg-image": [{ bg: ["control-gradient", "control-gradient-accent"] }],
61
+ // Button's label weights, so a call-site `font-bold` still wins.
62
+ "font-weight": [{ font: ["button", "button-strong"] }],
63
+ },
38
64
  },
39
65
  });
40
66
  /**
@@ -0,0 +1,62 @@
1
+ /** Types and pure helpers for `CodeField`. Kept out of the component so they can be tested without a DOM. */
2
+ /** `numeric`: digits only, the numeric keyboard. `alphanumeric`: digits and letters. */
3
+ export type CodeFieldMode = "numeric" | "alphanumeric";
4
+ /** Every built-in string. Pass a partial object to `strings` to translate. */
5
+ export interface CodeFieldStrings {
6
+ /** The field's name when no `label` is given. */
7
+ label: string;
8
+ /** Read after the name, so a screen reader user knows how long the code is ("6 digits"). */
9
+ description: (length: number, mode: CodeFieldMode) => string;
10
+ }
11
+ export declare const DEFAULT_CODE_FIELD_STRINGS: CodeFieldStrings;
12
+ /** The fewest and the most places a code field draws. */
13
+ export declare const CODE_FIELD_LENGTH_MAX = 12;
14
+ /** `length` as a whole number from 1 to 12; 6 for anything that is not a number. */
15
+ export declare function codeLength(length: number | undefined): number;
16
+ /** Whether one character belongs in a code of this mode. */
17
+ export declare function isCodeChar(char: string, mode: CodeFieldMode): boolean;
18
+ /**
19
+ * What is left of `text` once everything that does not belong is dropped
20
+ * (spaces, dashes, letters in a numeric code), cut to `length`. "123 456" and
21
+ * "123-456" are "123456".
22
+ */
23
+ export declare function sanitiseCode(text: string, mode: CodeFieldMode, length: number): string;
24
+ /** The characters kept of `text` before position `caret`: where the caret goes after `text` is cleaned. */
25
+ export declare function caretAfterSanitise(text: string, caret: number, mode: CodeFieldMode, length: number): number;
26
+ /** `value` with the place at `index` replaced by `char`. */
27
+ export declare function replaceAt(value: string, index: number, char: string): string;
28
+ /** The text with `pasted` where the selection from `start` to `end` is. A whole code replaces what was there. */
29
+ export declare function pasteInto(value: string, start: number, end: number, pasted: string, mode: CodeFieldMode, length: number): string;
30
+ /** The place the caret is in, for the focus mark: the next empty place, or the last when the code is whole. */
31
+ export declare function activePlace(caret: number, length: number): number;
32
+ /** The sizes of the boxes: the field's `size`. `md` is the size the field has always had. */
33
+ export type CodeFieldSize = "sm" | "md" | "lg";
34
+ /**
35
+ * Per size: the box height, the digit class, the widest a box grows (rem) and
36
+ * the least it is (`minEm`, in ems of its own digit, so a digit is never wider than its
37
+ * box at any text size). `sm` stays 44px tall, the least for a touch target.
38
+ */
39
+ export declare const CODE_FIELD_SIZES: Record<CodeFieldSize, {
40
+ box: string;
41
+ text: string;
42
+ digitRem: number;
43
+ maxRem: number;
44
+ minEm: number;
45
+ }>;
46
+ /** The gap between boxes in a group, and the wider gap between groups (rem). */
47
+ export declare const CODE_FIELD_GAP_REM = 0.5;
48
+ export declare const CODE_FIELD_GROUP_GAP_REM = 1;
49
+ /**
50
+ * `groups` as the sizes of the groups the boxes are drawn in. A number is the
51
+ * size of each group (4 for 8 places is 4 and 4, 3 for 8 is 3, 3 and 2); a list
52
+ * gives each group's size and the places left over form a last group. One
53
+ * group, or anything unusable, means no grouping: an empty list.
54
+ */
55
+ export declare function codeGroups(groups: number | number[] | undefined, length: number): number[];
56
+ /** The index of the box nearest to a point, by its rectangle; -1 when there are none. */
57
+ export declare function nearestBox(rects: {
58
+ left: number;
59
+ right: number;
60
+ top?: number;
61
+ bottom?: number;
62
+ }[], x: number, y: number): number;
@@ -0,0 +1,112 @@
1
+ /** Types and pure helpers for `CodeField`. Kept out of the component so they can be tested without a DOM. */
2
+ export const DEFAULT_CODE_FIELD_STRINGS = {
3
+ label: "Verification code",
4
+ description: (length, mode) => (mode === "numeric" ? `${length} digits` : `${length} characters`),
5
+ };
6
+ /** The fewest and the most places a code field draws. */
7
+ export const CODE_FIELD_LENGTH_MAX = 12;
8
+ /** `length` as a whole number from 1 to 12; 6 for anything that is not a number. */
9
+ export function codeLength(length) {
10
+ if (length === undefined || !Number.isFinite(length))
11
+ return 6;
12
+ return Math.max(1, Math.min(CODE_FIELD_LENGTH_MAX, Math.floor(length)));
13
+ }
14
+ /** Whether one character belongs in a code of this mode. */
15
+ export function isCodeChar(char, mode) {
16
+ return mode === "numeric" ? /^[0-9]$/.test(char) : /^[0-9A-Za-z]$/.test(char);
17
+ }
18
+ /**
19
+ * What is left of `text` once everything that does not belong is dropped
20
+ * (spaces, dashes, letters in a numeric code), cut to `length`. "123 456" and
21
+ * "123-456" are "123456".
22
+ */
23
+ export function sanitiseCode(text, mode, length) {
24
+ let kept = "";
25
+ for (const char of text) {
26
+ if (isCodeChar(char, mode))
27
+ kept += char;
28
+ }
29
+ return kept.slice(0, length);
30
+ }
31
+ /** The characters kept of `text` before position `caret`: where the caret goes after `text` is cleaned. */
32
+ export function caretAfterSanitise(text, caret, mode, length) {
33
+ return sanitiseCode(text.slice(0, caret), mode, length).length;
34
+ }
35
+ /** `value` with the place at `index` replaced by `char`. */
36
+ export function replaceAt(value, index, char) {
37
+ return value.slice(0, index) + char + value.slice(index + 1);
38
+ }
39
+ /** The text with `pasted` where the selection from `start` to `end` is. A whole code replaces what was there. */
40
+ export function pasteInto(value, start, end, pasted, mode, length) {
41
+ const clean = sanitiseCode(pasted, mode, Number.MAX_SAFE_INTEGER);
42
+ if (clean.length >= length)
43
+ return clean.slice(0, length);
44
+ return sanitiseCode(value.slice(0, start) + clean + value.slice(end), mode, length);
45
+ }
46
+ /** The place the caret is in, for the focus mark: the next empty place, or the last when the code is whole. */
47
+ export function activePlace(caret, length) {
48
+ return Math.max(0, Math.min(caret, length - 1));
49
+ }
50
+ /**
51
+ * Per size: the box height, the digit class, the widest a box grows (rem) and
52
+ * the least it is (`minEm`, in ems of its own digit, so a digit is never wider than its
53
+ * box at any text size). `sm` stays 44px tall, the least for a touch target.
54
+ */
55
+ export const CODE_FIELD_SIZES = {
56
+ sm: { box: "h-11", text: "text-lg", digitRem: 1.125, maxRem: 2.5, minEm: 1.15 },
57
+ md: { box: "h-12", text: "text-xl", digitRem: 1.25, maxRem: 3, minEm: 1.15 },
58
+ lg: { box: "h-14", text: "text-2xl", digitRem: 1.5, maxRem: 3.5, minEm: 1.15 },
59
+ };
60
+ /** The gap between boxes in a group, and the wider gap between groups (rem). */
61
+ export const CODE_FIELD_GAP_REM = 0.5;
62
+ export const CODE_FIELD_GROUP_GAP_REM = 1;
63
+ /**
64
+ * `groups` as the sizes of the groups the boxes are drawn in. A number is the
65
+ * size of each group (4 for 8 places is 4 and 4, 3 for 8 is 3, 3 and 2); a list
66
+ * gives each group's size and the places left over form a last group. One
67
+ * group, or anything unusable, means no grouping: an empty list.
68
+ */
69
+ export function codeGroups(groups, length) {
70
+ if (groups === undefined)
71
+ return [];
72
+ const sizes = [];
73
+ let left = length;
74
+ if (typeof groups === "number") {
75
+ if (!Number.isFinite(groups) || groups < 1)
76
+ return [];
77
+ const each = Math.floor(groups);
78
+ while (left > 0) {
79
+ sizes.push(Math.min(each, left));
80
+ left -= each;
81
+ }
82
+ }
83
+ else {
84
+ for (const size of groups) {
85
+ if (left <= 0)
86
+ break;
87
+ if (!Number.isFinite(size) || size < 1)
88
+ continue;
89
+ const take = Math.min(Math.floor(size), left);
90
+ sizes.push(take);
91
+ left -= take;
92
+ }
93
+ if (left > 0)
94
+ sizes.push(left);
95
+ }
96
+ return sizes.length > 1 ? sizes : [];
97
+ }
98
+ /** The index of the box nearest to a point, by its rectangle; -1 when there are none. */
99
+ export function nearestBox(rects, x, y) {
100
+ let best = -1;
101
+ let bestDistance = Infinity;
102
+ rects.forEach((rect, index) => {
103
+ const dx = Math.max(rect.left - x, 0, x - rect.right);
104
+ const dy = Math.max((rect.top ?? 0) - y, 0, y - (rect.bottom ?? 0));
105
+ const distance = dy * 1000 + dx;
106
+ if (distance < bestDistance) {
107
+ bestDistance = distance;
108
+ best = index;
109
+ }
110
+ });
111
+ return best;
112
+ }
@@ -0,0 +1,63 @@
1
+ /** Types and pure helpers for `Collapsible` and `CollapsibleGroup`. Kept out of the components so they can be tested without a DOM. */
2
+ /** Heading element the default trigger is wrapped in. */
3
+ export type CollapsibleHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
4
+ /**
5
+ * First argument of the `trigger` snippet. Spread it on your own `<button>`:
6
+ * it carries the whole wiring, so the button needs nothing else to work.
7
+ */
8
+ export type CollapsibleTriggerProps = {
9
+ id: string;
10
+ /** Keeps a trigger inside a `<form>` from submitting it. */
11
+ type: "button";
12
+ "aria-expanded": boolean;
13
+ "aria-controls": string;
14
+ disabled: boolean;
15
+ onclick: (event: MouseEvent) => void;
16
+ /** How a `CollapsibleGroup` finds its header buttons for the arrow keys. */
17
+ "data-collapsible-trigger": "";
18
+ };
19
+ /** Second argument of the `trigger` snippet. */
20
+ export interface CollapsibleTriggerState {
21
+ open: boolean;
22
+ disabled: boolean;
23
+ }
24
+ /** What a `Collapsible` hands its group. */
25
+ export interface CollapsibleGroupMember {
26
+ triggerId: string;
27
+ isOpen: () => boolean;
28
+ /** A disabled member keeps its state: the group neither closes it nor counts it. */
29
+ isDisabled: () => boolean;
30
+ close: () => void;
31
+ }
32
+ /** What a member gets back when it joins a group. */
33
+ export interface CollapsibleGroupRegistration {
34
+ /** Removes the member again. */
35
+ unregister: () => void;
36
+ /**
37
+ * True when the member asked to start open in a single-open group that
38
+ * already has an open panel. The member then renders closed from the
39
+ * start, on the server too, instead of opening and being closed again.
40
+ */
41
+ startClosed: boolean;
42
+ }
43
+ /** What a `CollapsibleGroup` offers the Collapsibles inside it, through context. */
44
+ export interface CollapsibleGroupContext {
45
+ /** False when opening one panel closes the others. */
46
+ readonly multiple: boolean;
47
+ /**
48
+ * Shared `name` for the `<details>` of the default triggers when the group
49
+ * is single-open, so the browser keeps them exclusive without scripts.
50
+ * `undefined` when `multiple`.
51
+ */
52
+ readonly exclusiveName: string | undefined;
53
+ register: (member: CollapsibleGroupMember) => CollapsibleGroupRegistration;
54
+ /** Called whenever a member is open, however it got there. */
55
+ opened: (member: CollapsibleGroupMember) => void;
56
+ }
57
+ /** Context key shared by the two components. */
58
+ export declare const COLLAPSIBLE_GROUP: unique symbol;
59
+ /**
60
+ * Index of the header button an accordion key moves focus to, or `null` when
61
+ * the key is not one of them. Arrow keys wrap, as they do in Tabs and Dropdown.
62
+ */
63
+ export declare function nextTriggerIndex(key: string, current: number, count: number): number | null;
@@ -0,0 +1,23 @@
1
+ /** Types and pure helpers for `Collapsible` and `CollapsibleGroup`. Kept out of the components so they can be tested without a DOM. */
2
+ /** Context key shared by the two components. */
3
+ export const COLLAPSIBLE_GROUP = Symbol("zabi-collapsible-group");
4
+ /**
5
+ * Index of the header button an accordion key moves focus to, or `null` when
6
+ * the key is not one of them. Arrow keys wrap, as they do in Tabs and Dropdown.
7
+ */
8
+ export function nextTriggerIndex(key, current, count) {
9
+ if (count === 0)
10
+ return null;
11
+ switch (key) {
12
+ case "ArrowDown":
13
+ return (current + 1) % count;
14
+ case "ArrowUp":
15
+ return (current - 1 + count) % count;
16
+ case "Home":
17
+ return 0;
18
+ case "End":
19
+ return count - 1;
20
+ default:
21
+ return null;
22
+ }
23
+ }
@@ -0,0 +1,11 @@
1
+ /** Public types for `ConfirmDialog`. */
2
+ /** Sets the confirm button's style and the icon beside the message. */
3
+ export type ConfirmDialogVariant = "danger" | "warning" | "info";
4
+ /** How the user backed out: the cancel button, or one of Modal's own ways to close. */
5
+ export type ConfirmDialogCancelReason = "cancel-button" | "escape" | "backdrop" | "close-button";
6
+ /**
7
+ * What `onconfirm` may return. `false`, returned or resolved, keeps the dialog
8
+ * open; anything else closes it. A promise puts the dialog in its loading
9
+ * state until it settles.
10
+ */
11
+ export type ConfirmDialogResult = void | boolean | Promise<void | boolean>;
@@ -0,0 +1,2 @@
1
+ /** Public types for `ConfirmDialog`. */
2
+ export {};
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Calendar dates as strings: `YYYY-MM-DD` for a day, `YYYY-MM` for a month,
3
+ * `HH:mm` (or `HH:mm:ss`) for a time of day. The formats a native date or
4
+ * time input reads and writes.
5
+ *
6
+ * A date here is a day on the calendar, not a moment. Nothing in this file
7
+ * goes through a local `Date`: the arithmetic is on the numbers, or on UTC,
8
+ * where every day has 24 hours. So a date never moves to the day before or
9
+ * after because of a time zone, and a day on which the clocks change is a day
10
+ * like any other.
11
+ *
12
+ * Years 0001 to 9999, four digits: within that, two dates compare as strings.
13
+ */
14
+ export interface DateParts {
15
+ year: number;
16
+ /** 1 to 12. */
17
+ month: number;
18
+ day: number;
19
+ }
20
+ export declare function isLeapYear(year: number): boolean;
21
+ /** Days in a month; `month` is 1 to 12. */
22
+ export declare function daysInMonth(year: number, month: number): number;
23
+ /** The parts of a `YYYY-MM-DD` string, or null when it is not a real date. */
24
+ export declare function parseIsoDate(value: string | null | undefined): DateParts | null;
25
+ export declare function isIsoDate(value: string | null | undefined): value is string;
26
+ /** The parts of a `YYYY-MM` string, or null when it is not a real month. */
27
+ export declare function parseIsoMonth(value: string | null | undefined): {
28
+ year: number;
29
+ month: number;
30
+ } | null;
31
+ export declare function toIsoDate(year: number, month: number, day: number): string;
32
+ export declare function toIsoMonth(year: number, month: number): string;
33
+ /** The month a date is in: `2026-10-06` gives `2026-10`. Null for a string that is not a date. */
34
+ export declare function monthOf(date: string | null | undefined): string | null;
35
+ /** The date `count` days later (earlier when negative), or null outside years 1 to 9999. */
36
+ export declare function addDays(date: string, count: number): string | null;
37
+ /** The month `count` months later (earlier when negative), or null outside years 1 to 9999. */
38
+ export declare function addMonthsToMonth(month: string, count: number): string | null;
39
+ /**
40
+ * The same day of the month `count` months later. A day the target month does
41
+ * not have becomes its last one: 31 January plus a month is 28 or 29 February.
42
+ */
43
+ export declare function addMonths(date: string, count: number): string | null;
44
+ /** Day of the week, 0 for Sunday to 6 for Saturday. -1 for a string that is not a date. */
45
+ export declare function weekdayOf(date: string): number;
46
+ /** A whole number from 0 to 6 for the first day of the week; anything else is Monday. */
47
+ export declare function normaliseWeekStart(weekStartsOn: number | undefined): number;
48
+ /** The first day of the week a date is in. */
49
+ export declare function startOfWeek(date: string, weekStartsOn?: number): string | null;
50
+ /** The last day of the week a date is in. */
51
+ export declare function endOfWeek(date: string, weekStartsOn?: number): string | null;
52
+ /**
53
+ * The weeks of a month, each seven entries from the first day of the week. A
54
+ * day of the month is its ISO date; a place before the 1st or after the last
55
+ * day is null. There are as many weeks as the month touches: four (a
56
+ * 28-day February that starts on the first day of the week), five or six.
57
+ */
58
+ export declare function monthGrid(month: string, weekStartsOn?: number): (string | null)[][];
59
+ /** The seven days of the week as numbers (0 for Sunday), from the first day of the week. */
60
+ export declare function weekdayOrder(weekStartsOn?: number): number[];
61
+ /**
62
+ * Today where the user is, as `YYYY-MM-DD`. This is the one place that reads
63
+ * the local clock: "today" is a local idea. Call it in the browser; on a
64
+ * server it is the server's day.
65
+ */
66
+ export declare function todayIso(now?: Date): string;
67
+ /** Today in UTC: the same on a server and in a browser at the same moment. */
68
+ export declare function todayIsoUtc(now?: Date): string;
69
+ /** A date held between `min` and `max`, either of which may be missing or invalid. */
70
+ export declare function clampDate(date: string, min?: string | null, max?: string | null): string;
71
+ /**
72
+ * A date for reading: `formatDate("2026-10-06", "sv")` is "6 okt. 2026",
73
+ * `formatDate("2026-10-06", "en-GB")` is "6 Oct 2026".
74
+ *
75
+ * `value` is `YYYY-MM-DD`, what a DateField holds. The day shown is always
76
+ * the day in the string: it does not depend on the time zone of the browser
77
+ * or the server. An empty or invalid value gives an empty string.
78
+ *
79
+ * Pass the `locale` of the page. Without it the runtime's own is used, which
80
+ * on a server is the server's and may differ from the reader's, so text
81
+ * rendered on the server and again in the browser may not match.
82
+ *
83
+ * `options` are those of `Intl.DateTimeFormat`; `timeZone` is not one you can
84
+ * set here.
85
+ */
86
+ export declare function formatDate(value: string | null | undefined, locale?: string | string[], options?: Intl.DateTimeFormatOptions): string;
87
+ /**
88
+ * A time of day for reading: `formatTime("19:00", "sv")` is "19:00",
89
+ * `formatTime("19:00", "en-US")` is "7:00 PM".
90
+ *
91
+ * `value` is `HH:mm` or `HH:mm:ss`, what a TimeField holds. It is a time on
92
+ * the clock, with no zone: nothing shifts it. An empty or invalid value gives
93
+ * an empty string. `locale` and `options` as for `formatDate`.
94
+ */
95
+ export declare function formatTime(value: string | null | undefined, locale?: string | string[], options?: Intl.DateTimeFormatOptions): string;
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Calendar dates as strings: `YYYY-MM-DD` for a day, `YYYY-MM` for a month,
3
+ * `HH:mm` (or `HH:mm:ss`) for a time of day. The formats a native date or
4
+ * time input reads and writes.
5
+ *
6
+ * A date here is a day on the calendar, not a moment. Nothing in this file
7
+ * goes through a local `Date`: the arithmetic is on the numbers, or on UTC,
8
+ * where every day has 24 hours. So a date never moves to the day before or
9
+ * after because of a time zone, and a day on which the clocks change is a day
10
+ * like any other.
11
+ *
12
+ * Years 0001 to 9999, four digits: within that, two dates compare as strings.
13
+ */
14
+ const ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
15
+ const ISO_MONTH = /^(\d{4})-(\d{2})$/;
16
+ const ISO_TIME = /^(\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?$/;
17
+ const pad = (value, length = 2) => String(value).padStart(length, "0");
18
+ export function isLeapYear(year) {
19
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
20
+ }
21
+ /** Days in a month; `month` is 1 to 12. */
22
+ export function daysInMonth(year, month) {
23
+ if (month === 2)
24
+ return isLeapYear(year) ? 29 : 28;
25
+ return [4, 6, 9, 11].includes(month) ? 30 : 31;
26
+ }
27
+ /** The parts of a `YYYY-MM-DD` string, or null when it is not a real date. */
28
+ export function parseIsoDate(value) {
29
+ const match = ISO_DATE.exec(value ?? "");
30
+ if (!match)
31
+ return null;
32
+ const year = Number(match[1]);
33
+ const month = Number(match[2]);
34
+ const day = Number(match[3]);
35
+ if (year < 1 || month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month))
36
+ return null;
37
+ return { year, month, day };
38
+ }
39
+ export function isIsoDate(value) {
40
+ return parseIsoDate(value) !== null;
41
+ }
42
+ /** The parts of a `YYYY-MM` string, or null when it is not a real month. */
43
+ export function parseIsoMonth(value) {
44
+ const match = ISO_MONTH.exec(value ?? "");
45
+ if (!match)
46
+ return null;
47
+ const year = Number(match[1]);
48
+ const month = Number(match[2]);
49
+ if (year < 1 || month < 1 || month > 12)
50
+ return null;
51
+ return { year, month };
52
+ }
53
+ export function toIsoDate(year, month, day) {
54
+ return `${pad(year, 4)}-${pad(month)}-${pad(day)}`;
55
+ }
56
+ export function toIsoMonth(year, month) {
57
+ return `${pad(year, 4)}-${pad(month)}`;
58
+ }
59
+ /** The month a date is in: `2026-10-06` gives `2026-10`. Null for a string that is not a date. */
60
+ export function monthOf(date) {
61
+ const parts = parseIsoDate(date);
62
+ return parts ? toIsoMonth(parts.year, parts.month) : null;
63
+ }
64
+ /**
65
+ * A UTC timestamp for the day. `Date.UTC` reads a year under 100 as 19xx, so
66
+ * the year is set afterwards.
67
+ */
68
+ function utcOf({ year, month, day }) {
69
+ const date = new Date(Date.UTC(2000, month - 1, day));
70
+ date.setUTCFullYear(year);
71
+ return date;
72
+ }
73
+ function isoOfUtc(date) {
74
+ return toIsoDate(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate());
75
+ }
76
+ const inRange = (year) => year >= 1 && year <= 9999;
77
+ /** The date `count` days later (earlier when negative), or null outside years 1 to 9999. */
78
+ export function addDays(date, count) {
79
+ const parts = parseIsoDate(date);
80
+ if (!parts)
81
+ return null;
82
+ const moved = utcOf(parts);
83
+ moved.setUTCDate(moved.getUTCDate() + count);
84
+ return inRange(moved.getUTCFullYear()) ? isoOfUtc(moved) : null;
85
+ }
86
+ /** The month `count` months later (earlier when negative), or null outside years 1 to 9999. */
87
+ export function addMonthsToMonth(month, count) {
88
+ const parts = parseIsoMonth(month);
89
+ if (!parts)
90
+ return null;
91
+ const index = parts.year * 12 + (parts.month - 1) + count;
92
+ const year = Math.floor(index / 12);
93
+ return inRange(year) ? toIsoMonth(year, (index % 12 + 12) % 12 + 1) : null;
94
+ }
95
+ /**
96
+ * The same day of the month `count` months later. A day the target month does
97
+ * not have becomes its last one: 31 January plus a month is 28 or 29 February.
98
+ */
99
+ export function addMonths(date, count) {
100
+ const parts = parseIsoDate(date);
101
+ if (!parts)
102
+ return null;
103
+ const target = parseIsoMonth(addMonthsToMonth(toIsoMonth(parts.year, parts.month), count));
104
+ if (!target)
105
+ return null;
106
+ const day = Math.min(parts.day, daysInMonth(target.year, target.month));
107
+ return toIsoDate(target.year, target.month, day);
108
+ }
109
+ /** Day of the week, 0 for Sunday to 6 for Saturday. -1 for a string that is not a date. */
110
+ export function weekdayOf(date) {
111
+ const parts = parseIsoDate(date);
112
+ return parts ? utcOf(parts).getUTCDay() : -1;
113
+ }
114
+ /** A whole number from 0 to 6 for the first day of the week; anything else is Monday. */
115
+ export function normaliseWeekStart(weekStartsOn) {
116
+ return Number.isInteger(weekStartsOn) && weekStartsOn >= 0 && weekStartsOn <= 6
117
+ ? weekStartsOn
118
+ : 1;
119
+ }
120
+ /** The first day of the week a date is in. */
121
+ export function startOfWeek(date, weekStartsOn = 1) {
122
+ const weekday = weekdayOf(date);
123
+ if (weekday === -1)
124
+ return null;
125
+ return addDays(date, -((weekday - normaliseWeekStart(weekStartsOn) + 7) % 7));
126
+ }
127
+ /** The last day of the week a date is in. */
128
+ export function endOfWeek(date, weekStartsOn = 1) {
129
+ const start = startOfWeek(date, weekStartsOn);
130
+ return start ? addDays(start, 6) : null;
131
+ }
132
+ /**
133
+ * The weeks of a month, each seven entries from the first day of the week. A
134
+ * day of the month is its ISO date; a place before the 1st or after the last
135
+ * day is null. There are as many weeks as the month touches: four (a
136
+ * 28-day February that starts on the first day of the week), five or six.
137
+ */
138
+ export function monthGrid(month, weekStartsOn = 1) {
139
+ const parts = parseIsoMonth(month);
140
+ if (!parts)
141
+ return [];
142
+ const first = toIsoDate(parts.year, parts.month, 1);
143
+ const lead = (weekdayOf(first) - normaliseWeekStart(weekStartsOn) + 7) % 7;
144
+ const days = daysInMonth(parts.year, parts.month);
145
+ const cells = Array.from({ length: lead }, () => null);
146
+ for (let day = 1; day <= days; day += 1)
147
+ cells.push(toIsoDate(parts.year, parts.month, day));
148
+ while (cells.length % 7 !== 0)
149
+ cells.push(null);
150
+ const weeks = [];
151
+ for (let index = 0; index < cells.length; index += 7)
152
+ weeks.push(cells.slice(index, index + 7));
153
+ return weeks;
154
+ }
155
+ /** The seven days of the week as numbers (0 for Sunday), from the first day of the week. */
156
+ export function weekdayOrder(weekStartsOn = 1) {
157
+ const start = normaliseWeekStart(weekStartsOn);
158
+ return Array.from({ length: 7 }, (_, index) => (start + index) % 7);
159
+ }
160
+ /**
161
+ * Today where the user is, as `YYYY-MM-DD`. This is the one place that reads
162
+ * the local clock: "today" is a local idea. Call it in the browser; on a
163
+ * server it is the server's day.
164
+ */
165
+ export function todayIso(now = new Date()) {
166
+ return toIsoDate(now.getFullYear(), now.getMonth() + 1, now.getDate());
167
+ }
168
+ /** Today in UTC: the same on a server and in a browser at the same moment. */
169
+ export function todayIsoUtc(now = new Date()) {
170
+ return isoOfUtc(now);
171
+ }
172
+ /** A date held between `min` and `max`, either of which may be missing or invalid. */
173
+ export function clampDate(date, min, max) {
174
+ if (isIsoDate(min) && date < min)
175
+ return min;
176
+ if (isIsoDate(max) && date > max)
177
+ return max;
178
+ return date;
179
+ }
180
+ function formatter(locale, options) {
181
+ try {
182
+ // Formatted in UTC, where the value was put: the reader's zone never moves it.
183
+ return new Intl.DateTimeFormat(locale || undefined, { ...options, timeZone: "UTC" });
184
+ }
185
+ catch {
186
+ // An unknown locale tag or option: fall back to the runtime's own.
187
+ try {
188
+ return new Intl.DateTimeFormat(undefined, { ...options, timeZone: "UTC" });
189
+ }
190
+ catch {
191
+ return null;
192
+ }
193
+ }
194
+ }
195
+ /**
196
+ * A date for reading: `formatDate("2026-10-06", "sv")` is "6 okt. 2026",
197
+ * `formatDate("2026-10-06", "en-GB")` is "6 Oct 2026".
198
+ *
199
+ * `value` is `YYYY-MM-DD`, what a DateField holds. The day shown is always
200
+ * the day in the string: it does not depend on the time zone of the browser
201
+ * or the server. An empty or invalid value gives an empty string.
202
+ *
203
+ * Pass the `locale` of the page. Without it the runtime's own is used, which
204
+ * on a server is the server's and may differ from the reader's, so text
205
+ * rendered on the server and again in the browser may not match.
206
+ *
207
+ * `options` are those of `Intl.DateTimeFormat`; `timeZone` is not one you can
208
+ * set here.
209
+ */
210
+ export function formatDate(value, locale, options = { day: "numeric", month: "short", year: "numeric" }) {
211
+ const parts = parseIsoDate(value);
212
+ if (!parts)
213
+ return "";
214
+ return formatter(locale, options)?.format(utcOf(parts)) ?? value;
215
+ }
216
+ /**
217
+ * A time of day for reading: `formatTime("19:00", "sv")` is "19:00",
218
+ * `formatTime("19:00", "en-US")` is "7:00 PM".
219
+ *
220
+ * `value` is `HH:mm` or `HH:mm:ss`, what a TimeField holds. It is a time on
221
+ * the clock, with no zone: nothing shifts it. An empty or invalid value gives
222
+ * an empty string. `locale` and `options` as for `formatDate`.
223
+ */
224
+ export function formatTime(value, locale,
225
+ // The locale's own short time: "07:05" in Swedish, "7:05 AM" in American English.
226
+ options = { timeStyle: "short" }) {
227
+ const match = ISO_TIME.exec(value ?? "");
228
+ if (!match)
229
+ return "";
230
+ const hours = Number(match[1]);
231
+ const minutes = Number(match[2]);
232
+ const seconds = Number(match[3] ?? "0");
233
+ if (hours > 23 || minutes > 59 || seconds > 59)
234
+ return "";
235
+ const moment = new Date(Date.UTC(2000, 0, 1, hours, minutes, seconds));
236
+ return formatter(locale, options)?.format(moment) ?? value;
237
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The display voice: the weight and tracking of a figure or a display line.
3
+ * Both are read from custom properties that are declared nowhere, so any
4
+ * ancestor can set them (`--zabi-display-weight: 400` for a light serif) and
5
+ * the defaults are what the display face looked like before. The `number:`
6
+ * hint is what makes Tailwind read the weight as a weight and not a family.
7
+ * Heading `variant="display"` and Stat share this string.
8
+ */
9
+ export declare const displayVoice = "font-[number:var(--zabi-display-weight,700)] tracking-[var(--zabi-display-tracking,-0.02em)]";