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
@@ -0,0 +1,187 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+ import { cn } from "../util/cn.js";
5
+
6
+ type Props = Omit<HTMLAttributes<HTMLElement>, "class"> & {
7
+ /**
8
+ * The caption that names the quotation ("Säg så här i luren"), read
9
+ * before it. A string, or a snippet for a caption in the app's own
10
+ * text style.
11
+ */
12
+ label?: string | Snippet;
13
+ /** Keeps the caption for assistive technology and takes it off the screen. */
14
+ labelHidden?: boolean;
15
+ /** The side the tail is on: `end` (default) or `start`. Follows the text direction. */
16
+ side?: "end" | "start";
17
+ /**
18
+ * `ink` (default): the headline colour as fill, the page colour as
19
+ * text, so it is dark in light and light in dark. `paper`: the two
20
+ * swapped, for a bubble on a filled block. A pair of your own:
21
+ * `--zabi-bubble-fill` and `--zabi-bubble-text`, which win over both.
22
+ */
23
+ tone?: "ink" | "paper";
24
+ /**
25
+ * A drawing on the top corner of the tail's side, half over the edge
26
+ * (a sparkle, a quotation mark). Hidden from assistive technology;
27
+ * the app sizes and colours what it passes.
28
+ */
29
+ decoration?: Snippet;
30
+ class?: string;
31
+ /** The quoted text: phrasing content or paragraphs. */
32
+ children?: Snippet;
33
+ };
34
+
35
+ let {
36
+ label,
37
+ labelHidden = false,
38
+ side = "end",
39
+ tone = "ink",
40
+ decoration,
41
+ class: className = "",
42
+ children,
43
+ ...restProps
44
+ }: Props = $props();
45
+
46
+ /* The type is in utility classes, so a call-site class can replace it;
47
+ the quotation inherits it. */
48
+ const hostClasses = $derived(cn("speech-bubble flex flex-col gap-2 text-lg font-medium", className));
49
+ </script>
50
+
51
+ <figure
52
+ class={hostClasses}
53
+ data-side={side === "start" ? "start" : "end"}
54
+ data-tone={tone === "paper" ? "paper" : "ink"}
55
+ {...restProps}
56
+ >
57
+ {#if label}
58
+ <figcaption class={cn("text-description text-sm font-normal", labelHidden && "sr-only")}>
59
+ {#if typeof label === "string"}{label}{:else}{@render label()}{/if}
60
+ </figcaption>
61
+ {/if}
62
+ <blockquote class="quote">
63
+ <span class="art" aria-hidden="true">
64
+ <span class="fill"></span>
65
+ <svg class="tail" viewBox="0 0 30 24" focusable="false">
66
+ <path d="M1 0C1 9 9 20 29 23 22 18 19 10 21 0Z" />
67
+ </svg>
68
+ </span>
69
+ {#if decoration}
70
+ <span class="decoration" aria-hidden="true">{@render decoration()}</span>
71
+ {/if}
72
+ {@render children?.()}
73
+ </blockquote>
74
+ </figure>
75
+
76
+ <style>
77
+ /*
78
+ * What an app may set, on the component or on anything around it (they
79
+ * inherit); read with a fallback and never declared here:
80
+ * --zabi-bubble-fill the bubble and its tail; default by `tone`
81
+ * --zabi-bubble-text the quoted text; default by `tone`
82
+ * --zabi-bubble-radius any border-radius value, the eight-value form
83
+ * included; default 1.5rem
84
+ * --zabi-bubble-tilt turns the fill and the tail, never the text;
85
+ * default 0deg
86
+ * Inside a filled block (`on-brand`, `on-accent`, `on-fill`) the headline
87
+ * role is the block's label colour; `--zabi-theme-headline` is the
88
+ * theme's own, kept by the block's parent, so the bubble is the same
89
+ * object on a block as on the page.
90
+ */
91
+ .quote {
92
+ --_bubble-ink: var(--zabi-theme-headline, var(--color-headline));
93
+ --_bubble-paper: var(--color-surface-base);
94
+ --_bubble-fill: var(--zabi-bubble-fill, var(--_bubble-ink));
95
+ position: relative;
96
+ isolation: isolate;
97
+ /* The tail hangs 0.8rem under the bubble; this keeps it off what follows. */
98
+ margin: 0 0 1rem;
99
+ padding: 1.125rem 1.25rem 1.25rem;
100
+ color: var(--zabi-bubble-text, var(--_bubble-paper));
101
+ font-style: normal;
102
+ overflow-wrap: anywhere;
103
+ -webkit-user-select: text;
104
+ -moz-user-select: text;
105
+ user-select: text;
106
+ }
107
+
108
+ .speech-bubble[data-tone="paper"] .quote {
109
+ --_bubble-fill: var(--zabi-bubble-fill, var(--_bubble-paper));
110
+ color: var(--zabi-bubble-text, var(--_bubble-ink));
111
+ }
112
+
113
+ .art {
114
+ position: absolute;
115
+ inset: 0;
116
+ z-index: -1;
117
+ pointer-events: none;
118
+ rotate: var(--zabi-bubble-tilt, 0deg);
119
+ }
120
+
121
+ .fill {
122
+ position: absolute;
123
+ inset: 0;
124
+ border-radius: var(--zabi-bubble-radius, 1.5rem);
125
+ background-color: var(--_bubble-fill);
126
+ }
127
+
128
+ /* A drawn curl that turns outward, towards the side it is on. Its top
129
+ 0.4rem is under the fill; all of it is in rem, so it grows with the text. */
130
+ .tail {
131
+ position: absolute;
132
+ inset-block-start: calc(100% - 0.4rem);
133
+ inset-inline-end: 1.5rem;
134
+ inline-size: 1.5rem;
135
+ block-size: 1.2rem;
136
+ fill: var(--_bubble-fill);
137
+ }
138
+
139
+ .decoration {
140
+ position: absolute;
141
+ inset-block-start: 0;
142
+ inset-inline-end: 0;
143
+ display: flex;
144
+ line-height: 0;
145
+ pointer-events: none;
146
+ translate: 25% -55%;
147
+ }
148
+
149
+ .speech-bubble[data-side="start"] .tail {
150
+ inset-inline: 1.5rem auto;
151
+ scale: -1 1;
152
+ }
153
+
154
+ .speech-bubble[data-side="start"] .decoration {
155
+ inset-inline: 0 auto;
156
+ translate: -25% -55%;
157
+ }
158
+
159
+ /* The path is drawn turning right; the other three cases follow from it. */
160
+ .speech-bubble:dir(rtl) .tail {
161
+ scale: -1 1;
162
+ }
163
+
164
+ .speech-bubble:dir(rtl) .decoration {
165
+ translate: -25% -55%;
166
+ }
167
+
168
+ .speech-bubble[data-side="start"]:dir(rtl) .tail {
169
+ scale: none;
170
+ }
171
+
172
+ .speech-bubble[data-side="start"]:dir(rtl) .decoration {
173
+ translate: 25% -55%;
174
+ }
175
+
176
+ /* Forced colours drop the fill: the shape is an outline in the text
177
+ colour, tilt and radius kept, and the tail is not drawn. */
178
+ @media (forced-colors: active) {
179
+ .fill {
180
+ outline: 0.125rem solid CanvasText;
181
+ }
182
+
183
+ .tail {
184
+ display: none;
185
+ }
186
+ }
187
+ </style>
@@ -0,0 +1,33 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ type Props = Omit<HTMLAttributes<HTMLElement>, "class"> & {
4
+ /**
5
+ * The caption that names the quotation ("Säg så här i luren"), read
6
+ * before it. A string, or a snippet for a caption in the app's own
7
+ * text style.
8
+ */
9
+ label?: string | Snippet;
10
+ /** Keeps the caption for assistive technology and takes it off the screen. */
11
+ labelHidden?: boolean;
12
+ /** The side the tail is on: `end` (default) or `start`. Follows the text direction. */
13
+ side?: "end" | "start";
14
+ /**
15
+ * `ink` (default): the headline colour as fill, the page colour as
16
+ * text, so it is dark in light and light in dark. `paper`: the two
17
+ * swapped, for a bubble on a filled block. A pair of your own:
18
+ * `--zabi-bubble-fill` and `--zabi-bubble-text`, which win over both.
19
+ */
20
+ tone?: "ink" | "paper";
21
+ /**
22
+ * A drawing on the top corner of the tail's side, half over the edge
23
+ * (a sparkle, a quotation mark). Hidden from assistive technology;
24
+ * the app sizes and colours what it passes.
25
+ */
26
+ decoration?: Snippet;
27
+ class?: string;
28
+ /** The quoted text: phrasing content or paragraphs. */
29
+ children?: Snippet;
30
+ };
31
+ declare const SpeechBubble: import("svelte").Component<Props, {}, "">;
32
+ type SpeechBubble = ReturnType<typeof SpeechBubble>;
33
+ export default SpeechBubble;
@@ -0,0 +1,57 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn } from "../util/cn.js";
4
+
5
+ type Props = Omit<HTMLAttributes<HTMLSpanElement>, "class"> & {
6
+ /**
7
+ * Diameter, on the scale the built-in loading states use: 12, 14, 16
8
+ * and 20px. For another size pass a `size-*` utility through `class`.
9
+ */
10
+ size?: "xs" | "sm" | "md" | "lg";
11
+ /**
12
+ * What is loading. With a label the spinner is a `status` and the
13
+ * label is read out; without one it is decorative and hidden from
14
+ * assistive technology, for use beside text that already says so.
15
+ */
16
+ label?: string;
17
+ /** Extra classes for the ring: a size, a colour, an opacity. */
18
+ class?: string;
19
+ };
20
+
21
+ let {
22
+ size = "md",
23
+ label = "",
24
+ class: className = "",
25
+ ...restProps
26
+ }: Props = $props();
27
+
28
+ const SIZES = {
29
+ xs: "size-3",
30
+ sm: "size-3.5",
31
+ md: "size-4",
32
+ lg: "size-5",
33
+ };
34
+
35
+ /**
36
+ * The same ring Button, IconButton and Input draw while loading, in the
37
+ * text colour. Rotation is the motion a reduced-motion preference is
38
+ * about, so there the ring stays still and fades in and out instead:
39
+ * something must still show that work is going on.
40
+ */
41
+ const ringClasses = $derived(
42
+ cn(
43
+ "inline-block shrink-0 animate-spin rounded-full border-2 border-current border-t-transparent opacity-80 motion-reduce:animate-pulse",
44
+ SIZES[size],
45
+ className,
46
+ ),
47
+ );
48
+ </script>
49
+
50
+ {#if label}
51
+ <span class="inline-flex shrink-0" role="status" {...restProps}>
52
+ <span class={ringClasses} aria-hidden="true"></span>
53
+ <span class="sr-only">{label}</span>
54
+ </span>
55
+ {:else}
56
+ <span class={ringClasses} aria-hidden="true" {...restProps}></span>
57
+ {/if}
@@ -0,0 +1,19 @@
1
+ import type { HTMLAttributes } from "svelte/elements";
2
+ type Props = Omit<HTMLAttributes<HTMLSpanElement>, "class"> & {
3
+ /**
4
+ * Diameter, on the scale the built-in loading states use: 12, 14, 16
5
+ * and 20px. For another size pass a `size-*` utility through `class`.
6
+ */
7
+ size?: "xs" | "sm" | "md" | "lg";
8
+ /**
9
+ * What is loading. With a label the spinner is a `status` and the
10
+ * label is read out; without one it is decorative and hidden from
11
+ * assistive technology, for use beside text that already says so.
12
+ */
13
+ label?: string;
14
+ /** Extra classes for the ring: a size, a colour, an opacity. */
15
+ class?: string;
16
+ };
17
+ declare const Spinner: import("svelte").Component<Props, {}, "">;
18
+ type Spinner = ReturnType<typeof Spinner>;
19
+ export default Spinner;
@@ -0,0 +1,72 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+ import { cn } from "../util/cn.js";
5
+ import { displayVoice } from "../util/display-voice.js";
6
+
7
+ type StatSize = "sm" | "md" | "lg";
8
+
9
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, "class"> & {
10
+ /** The figure, shown as given: the app formats numbers for its locale. */
11
+ value: string | number;
12
+ label?: string;
13
+ /** Drawn after the value, smaller, on the same baseline ("av 19"). */
14
+ unit?: string;
15
+ size?: StatSize;
16
+ align?: "start" | "center" | "end";
17
+ labelPosition?: "below" | "above";
18
+ class?: string;
19
+ /** Replaces `value` for a figure that needs markup. */
20
+ children?: Snippet;
21
+ };
22
+
23
+ let {
24
+ value,
25
+ label = "",
26
+ unit = "",
27
+ size = "md",
28
+ align = "start",
29
+ labelPosition = "below",
30
+ class: className = "",
31
+ children,
32
+ ...restProps
33
+ }: Props = $props();
34
+
35
+ /** Value 24 / 36 / 48px, unit 14 / 16 / 20px, label 12 / 14 / 14px. */
36
+ const sizeClasses: Record<StatSize, { value: string; unit: string; label: string }> = {
37
+ sm: { value: "text-2xl", unit: "text-sm", label: "text-xs" },
38
+ md: { value: "text-4xl", unit: "text-base", label: "text-sm" },
39
+ lg: { value: "text-5xl", unit: "text-xl", label: "text-sm" },
40
+ };
41
+ const alignClasses = {
42
+ start: "items-start text-start",
43
+ center: "items-center text-center",
44
+ end: "items-end text-end",
45
+ } as const;
46
+
47
+ const s = $derived(sizeClasses[size] ?? sizeClasses.md);
48
+ const hostClasses = $derived(
49
+ cn(`flex flex-col gap-1 ${alignClasses[align] ?? alignClasses.start} ${className}`),
50
+ );
51
+ </script>
52
+
53
+ {#snippet figure()}
54
+ <div class="inline-flex items-baseline gap-1 whitespace-nowrap">
55
+ <span class="font-display text-headline tabular-nums leading-none {displayVoice} {s.value}">
56
+ {#if children}{@render children()}{:else}{value}{/if}
57
+ </span>
58
+ {#if unit}
59
+ <span class="text-description font-medium {s.unit}">{unit}</span>
60
+ {/if}
61
+ </div>
62
+ {/snippet}
63
+
64
+ <div class={hostClasses} {...restProps}>
65
+ {#if labelPosition === "above"}
66
+ {#if label}<span class="text-description {s.label}">{label}</span>{/if}
67
+ {@render figure()}
68
+ {:else}
69
+ {@render figure()}
70
+ {#if label}<span class="text-description {s.label}">{label}</span>{/if}
71
+ {/if}
72
+ </div>
@@ -0,0 +1,19 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ type StatSize = "sm" | "md" | "lg";
4
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, "class"> & {
5
+ /** The figure, shown as given: the app formats numbers for its locale. */
6
+ value: string | number;
7
+ label?: string;
8
+ /** Drawn after the value, smaller, on the same baseline ("av 19"). */
9
+ unit?: string;
10
+ size?: StatSize;
11
+ align?: "start" | "center" | "end";
12
+ labelPosition?: "below" | "above";
13
+ class?: string;
14
+ /** Replaces `value` for a figure that needs markup. */
15
+ children?: Snippet;
16
+ };
17
+ declare const Stat: import("svelte").Component<Props, {}, "">;
18
+ type Stat = ReturnType<typeof Stat>;
19
+ export default Stat;
@@ -1,23 +1,168 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
+ import type { HTMLTableAttributes } from 'svelte/elements';
3
4
  import { cn } from "../util/cn.js";
5
+ import { generateId } from "../util/ssr-safe.js";
4
6
 
5
- interface Props {
6
- /** Visible `<caption>` when set. */
7
+ /** `true` stacks at every width; a breakpoint name stacks below it. */
8
+ export type TableStacked = boolean | "sm" | "md" | "lg";
9
+
10
+ /** Other attributes (`id`, `data-*`, `aria-*`, ...) land on the `<table>`. */
11
+ type Props = Omit<HTMLTableAttributes, 'class' | 'children'> & {
12
+ /** `<caption>`, and the table's accessible name, when set. */
7
13
  caption?: string;
14
+ /** Keeps the caption as the accessible name but hides it from view. */
15
+ captionHidden?: boolean;
16
+ /**
17
+ * Lays each row out as a block of label and value pairs instead of
18
+ * scrolling sideways. The label of a cell is its `data-label`
19
+ * attribute, which the caller sets on every `<td>`.
20
+ */
21
+ stacked?: TableStacked;
8
22
  class?: string;
9
23
  children?: Snippet;
24
+ };
25
+
26
+ let {
27
+ caption,
28
+ captionHidden = false,
29
+ stacked = false,
30
+ class: className = '',
31
+ children,
32
+ ...restProps
33
+ }: Props = $props();
34
+
35
+ const captionId = generateId("table-caption");
36
+ let tableElement = $state<HTMLTableElement>();
37
+
38
+ /**
39
+ * The rows arrive as `children`, so the stacked layout is written from the
40
+ * table down. Tailwind only generates classes it can read whole, which is
41
+ * why each breakpoint repeats the list rather than building it.
42
+ *
43
+ * The header row is hidden from view, not removed, so cells keep their
44
+ * column header. The visible label is the cell's `data-label` drawn in
45
+ * `::before`; where the browser supports alternative text for generated
46
+ * content it is given an empty one, so a screen reader reads the column
47
+ * header once instead of the header and then the label.
48
+ *
49
+ * The label takes the start of the line with an auto margin after it, and
50
+ * the cell packs everything else at the end. So a cell's own children stay
51
+ * together however many there are, and a cell with no label still has its
52
+ * value on the value side. An empty cell collapses to nothing but is not
53
+ * hidden: taking it out of the tree would shift the cells after it under
54
+ * the wrong column headers.
55
+ */
56
+ const STACKED_CLASS = {
57
+ always:
58
+ "block min-w-0 [&>:not(thead)]:block [&>thead]:sr-only [&>*>tr]:block [&>*>tr]:py-2 " +
59
+ "[&>*>tr>*]:flex [&>*>tr>*]:items-baseline [&>*>tr>*]:justify-end " +
60
+ "[&>*>tr>*]:gap-4 [&>*>tr>*]:py-1 [&>*>tr>*]:text-end " +
61
+ "[&>*>tr>:empty]:py-0 [&>*>tr>[data-label]:not(:empty)]:before:me-auto " +
62
+ "[&>*>tr>[data-label]:not(:empty)]:before:shrink-0 " +
63
+ "[&>*>tr>[data-label]:not(:empty)]:before:text-start " +
64
+ "[&>*>tr>[data-label]:not(:empty)]:before:font-medium " +
65
+ "[&>*>tr>[data-label]:not(:empty)]:before:text-headline " +
66
+ "[&>*>tr>[data-label]:not(:empty)]:before:content-[attr(data-label)] " +
67
+ "supports-[content:'x'/'']:[&>*>tr>[data-label]:not(:empty)]:before:content-[attr(data-label)/'']",
68
+ sm:
69
+ "max-sm:block max-sm:min-w-0 max-sm:[&>:not(thead)]:block max-sm:[&>thead]:sr-only " +
70
+ "max-sm:[&>*>tr]:block max-sm:[&>*>tr]:py-2 max-sm:[&>*>tr>*]:flex " +
71
+ "max-sm:[&>*>tr>*]:items-baseline " +
72
+ "max-sm:[&>*>tr>*]:justify-end max-sm:[&>*>tr>*]:gap-4 " +
73
+ "max-sm:[&>*>tr>*]:py-1 max-sm:[&>*>tr>*]:text-end max-sm:[&>*>tr>:empty]:py-0 " +
74
+ "max-sm:[&>*>tr>[data-label]:not(:empty)]:before:me-auto " +
75
+ "max-sm:[&>*>tr>[data-label]:not(:empty)]:before:shrink-0 " +
76
+ "max-sm:[&>*>tr>[data-label]:not(:empty)]:before:text-start " +
77
+ "max-sm:[&>*>tr>[data-label]:not(:empty)]:before:font-medium " +
78
+ "max-sm:[&>*>tr>[data-label]:not(:empty)]:before:text-headline " +
79
+ "max-sm:[&>*>tr>[data-label]:not(:empty)]:before:content-[attr(data-label)] " +
80
+ "max-sm:supports-[content:'x'/'']:[&>*>tr>[data-label]:not(:empty)]:before:content-[attr(data-label)/'']",
81
+ md:
82
+ "max-md:block max-md:min-w-0 max-md:[&>:not(thead)]:block max-md:[&>thead]:sr-only " +
83
+ "max-md:[&>*>tr]:block max-md:[&>*>tr]:py-2 max-md:[&>*>tr>*]:flex " +
84
+ "max-md:[&>*>tr>*]:items-baseline " +
85
+ "max-md:[&>*>tr>*]:justify-end max-md:[&>*>tr>*]:gap-4 " +
86
+ "max-md:[&>*>tr>*]:py-1 max-md:[&>*>tr>*]:text-end max-md:[&>*>tr>:empty]:py-0 " +
87
+ "max-md:[&>*>tr>[data-label]:not(:empty)]:before:me-auto " +
88
+ "max-md:[&>*>tr>[data-label]:not(:empty)]:before:shrink-0 " +
89
+ "max-md:[&>*>tr>[data-label]:not(:empty)]:before:text-start " +
90
+ "max-md:[&>*>tr>[data-label]:not(:empty)]:before:font-medium " +
91
+ "max-md:[&>*>tr>[data-label]:not(:empty)]:before:text-headline " +
92
+ "max-md:[&>*>tr>[data-label]:not(:empty)]:before:content-[attr(data-label)] " +
93
+ "max-md:supports-[content:'x'/'']:[&>*>tr>[data-label]:not(:empty)]:before:content-[attr(data-label)/'']",
94
+ lg:
95
+ "max-lg:block max-lg:min-w-0 max-lg:[&>:not(thead)]:block max-lg:[&>thead]:sr-only " +
96
+ "max-lg:[&>*>tr]:block max-lg:[&>*>tr]:py-2 max-lg:[&>*>tr>*]:flex " +
97
+ "max-lg:[&>*>tr>*]:items-baseline " +
98
+ "max-lg:[&>*>tr>*]:justify-end max-lg:[&>*>tr>*]:gap-4 " +
99
+ "max-lg:[&>*>tr>*]:py-1 max-lg:[&>*>tr>*]:text-end max-lg:[&>*>tr>:empty]:py-0 " +
100
+ "max-lg:[&>*>tr>[data-label]:not(:empty)]:before:me-auto " +
101
+ "max-lg:[&>*>tr>[data-label]:not(:empty)]:before:shrink-0 " +
102
+ "max-lg:[&>*>tr>[data-label]:not(:empty)]:before:text-start " +
103
+ "max-lg:[&>*>tr>[data-label]:not(:empty)]:before:font-medium " +
104
+ "max-lg:[&>*>tr>[data-label]:not(:empty)]:before:text-headline " +
105
+ "max-lg:[&>*>tr>[data-label]:not(:empty)]:before:content-[attr(data-label)] " +
106
+ "max-lg:supports-[content:'x'/'']:[&>*>tr>[data-label]:not(:empty)]:before:content-[attr(data-label)/'']",
107
+ } as const;
108
+
109
+ const stackedClass = $derived(
110
+ stacked === true ? STACKED_CLASS.always : stacked ? STACKED_CLASS[stacked] : "",
111
+ );
112
+
113
+ /**
114
+ * Some browsers stop treating a table as one once its boxes are no longer
115
+ * table boxes, and the rows then reach a screen reader as loose text.
116
+ * Explicit roles keep the structure whatever `display` says. The rows are
117
+ * the caller's markup, so the roles are set on the rendered elements and
118
+ * kept up as rows come and go; a role the caller set is left alone.
119
+ */
120
+ function restoreTableRoles(table: HTMLTableElement) {
121
+ const set = (element: Element, role: string) => {
122
+ if (!element.hasAttribute("role")) element.setAttribute("role", role);
123
+ };
124
+ for (const group of table.querySelectorAll(":scope > :is(thead, tbody, tfoot)")) {
125
+ set(group, "rowgroup");
126
+ for (const row of group.querySelectorAll(":scope > tr")) {
127
+ set(row, "row");
128
+ for (const cell of row.querySelectorAll(":scope > :is(td, th)")) {
129
+ if (cell.tagName === "TD") set(cell, "cell");
130
+ else if (cell.getAttribute("scope") === "row") set(cell, "rowheader");
131
+ else if (cell.getAttribute("scope") === "col") set(cell, "columnheader");
132
+ else set(cell, group.tagName === "THEAD" ? "columnheader" : "rowheader");
133
+ }
134
+ }
135
+ }
10
136
  }
11
137
 
12
- let { caption, class: className = '', children }: Props = $props();
138
+ $effect(() => {
139
+ const table = tableElement;
140
+ if (!table || !stacked) return;
141
+
142
+ restoreTableRoles(table);
143
+ const observer = new MutationObserver(() => restoreTableRoles(table));
144
+ observer.observe(table, { childList: true, subtree: true });
145
+ return () => observer.disconnect();
146
+ });
13
147
  </script>
14
148
 
15
149
  <div
16
- class={cn("overflow-x-auto rounded-control border border-border shadow-sm", className)}
150
+ class={cn("overflow-x-auto rounded-control border border-border bg-card shadow-sm", className)}
17
151
  >
18
- <table class="w-full min-w-[20rem] border-collapse text-left text-sm text-body">
152
+ <table
153
+ bind:this={tableElement}
154
+ class={cn("w-full min-w-[20rem] border-collapse text-left text-sm text-body", stackedClass)}
155
+ role={stacked ? "table" : undefined}
156
+ aria-labelledby={stacked && caption ? captionId : undefined}
157
+ {...restProps}
158
+ >
19
159
  {#if caption}
20
- <caption class="border-b border-border bg-base-50 px-4 py-3 text-left text-headline">
160
+ <caption
161
+ id={captionId}
162
+ class={captionHidden
163
+ ? "sr-only"
164
+ : "border-b border-border bg-surface-elevated px-4 py-3 text-left text-headline"}
165
+ >
21
166
  {caption}
22
167
  </caption>
23
168
  {/if}
@@ -1,10 +1,22 @@
1
1
  import type { Snippet } from 'svelte';
2
- interface Props {
3
- /** Visible `<caption>` when set. */
2
+ import type { HTMLTableAttributes } from 'svelte/elements';
3
+ /** `true` stacks at every width; a breakpoint name stacks below it. */
4
+ export type TableStacked = boolean | "sm" | "md" | "lg";
5
+ /** Other attributes (`id`, `data-*`, `aria-*`, ...) land on the `<table>`. */
6
+ type Props = Omit<HTMLTableAttributes, 'class' | 'children'> & {
7
+ /** `<caption>`, and the table's accessible name, when set. */
4
8
  caption?: string;
9
+ /** Keeps the caption as the accessible name but hides it from view. */
10
+ captionHidden?: boolean;
11
+ /**
12
+ * Lays each row out as a block of label and value pairs instead of
13
+ * scrolling sideways. The label of a cell is its `data-label`
14
+ * attribute, which the caller sets on every `<td>`.
15
+ */
16
+ stacked?: TableStacked;
5
17
  class?: string;
6
18
  children?: Snippet;
7
- }
19
+ };
8
20
  declare const Table: import("svelte").Component<Props, {}, "">;
9
21
  type Table = ReturnType<typeof Table>;
10
22
  export default Table;