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
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import { mergeStrings } from "../util/ready-made-strings.js";
3
+ import { zabiStringsFor, zabiCommonStrings } from "../util/zabi-strings.js";
2
4
  import Badge from "../atoms/Badge.svelte";
3
5
  import Button from "../atoms/Button.svelte";
4
6
  import IconButton from "../atoms/IconButton.svelte";
@@ -8,10 +10,19 @@
8
10
  import SidebarNavSection from "../molecules/SidebarNavSection.svelte";
9
11
  import Tooltip from "../atoms/Tooltip.svelte";
10
12
  import SidebarShell from "./SidebarShell.svelte";
11
- import { Command, Search } from "@lucide/svelte";
13
+ import type {
14
+ SidebarDrawerCloseReason,
15
+ SidebarTriggerContext,
16
+ } from "./SidebarShell.svelte";
17
+ import Command from "@lucide/svelte/icons/command";
18
+ import Search from "@lucide/svelte/icons/search";
12
19
  import type { Snippet } from "svelte";
13
20
  import type { Component } from "svelte";
14
21
  import type { ButtonVariant, SizeVariant } from "../types/variants.js";
22
+ import {
23
+ DEFAULT_SIDEBAR_NAVIGATION_STRINGS,
24
+ type SidebarNavigationStrings,
25
+ } from "../util/sidebar.js";
15
26
 
16
27
  export interface SidebarNavigationItem {
17
28
  id: string;
@@ -36,6 +47,12 @@
36
47
  items?: SidebarNavigationItem[];
37
48
  currentPath?: string;
38
49
  ariaLabel?: string;
50
+ /**
51
+ * The words the sidebar says by itself, for another language: the
52
+ * names of its lists, the two lines shown when a search finds
53
+ * nothing, and those of the footer and the brand header in it.
54
+ */
55
+ strings?: Partial<SidebarNavigationStrings>;
39
56
  class?: string;
40
57
  /** @deprecated use `class`. */
41
58
  className?: string;
@@ -73,6 +90,24 @@
73
90
  profilePanel?: Snippet;
74
91
  /** Parent nav href to highlight when `currentPath` is a deeper leaf (e.g. category row). */
75
92
  activePrimaryHref?: string;
93
+ /**
94
+ * What the sidebar is below the `lg` breakpoint. `drawer`: the rail is
95
+ * hidden there and the sidebar opens in a Drawer from the start edge.
96
+ * This and the six props after it are SidebarShell's; see there.
97
+ */
98
+ mobile?: "none" | "drawer";
99
+ /** Whether the drawer is open. Bindable. */
100
+ isOpen?: boolean;
101
+ /** The button that opens the drawer, rendered in the rail's place below `lg`. */
102
+ trigger?: Snippet<[SidebarTriggerContext]>;
103
+ /** Heading of the drawer. Without it, `ariaLabel` is. */
104
+ drawerTitle?: string;
105
+ /** Accessible name of the drawer's close button. */
106
+ closeLabel?: string;
107
+ /** Fired when the drawer closes itself, with why. */
108
+ onclose?: (detail: { reason: SidebarDrawerCloseReason }) => void;
109
+ /** Accessible name of the scrolling region between header and footer. */
110
+ label?: string;
76
111
  }
77
112
 
78
113
  let {
@@ -82,6 +117,7 @@
82
117
  currentPath = "",
83
118
  activePrimaryHref = "",
84
119
  ariaLabel = "Sidebar navigation",
120
+ strings,
85
121
  class: classAttr = "",
86
122
  className: legacyClass = "",
87
123
  logoSrc = "",
@@ -93,8 +129,8 @@
93
129
  profileInitials = "ZA",
94
130
  showSearch = true,
95
131
  searchMode = "input",
96
- searchPlaceholder = "Search...",
97
- searchValue = $bindable(""),
132
+ searchPlaceholder: searchPlaceholderGiven,
133
+ searchValue = $bindable<Exclude<Props["searchValue"], undefined>>(),
98
134
  searchTriggerIcon = Command,
99
135
  searchTriggerVariant = "outline",
100
136
  searchTriggerSize = "sm",
@@ -102,7 +138,7 @@
102
138
  logoutLabel = "Logout",
103
139
  showThemeToggle = true,
104
140
  lightModeLabel = "Light mode",
105
- isLightMode = $bindable(false),
141
+ isLightMode = $bindable<Exclude<Props["isLightMode"], undefined>>(),
106
142
  emptyStateTitle = "Create your first navigation item",
107
143
  emptyStateDescription = "Add your first sidebar item so users can start navigating your product.",
108
144
  emptyStateActionLabel = "Add navigation item",
@@ -115,12 +151,42 @@
115
151
  profilePanelOpen = false,
116
152
  profilePanelControlsId = "",
117
153
  profilePanel,
154
+ mobile = "none",
155
+ isOpen = $bindable<Exclude<Props["isOpen"], undefined>>(),
156
+ trigger,
157
+ drawerTitle,
158
+ closeLabel,
159
+ onclose,
160
+ label,
118
161
  ...restProps
119
162
  }: Props = $props();
120
163
 
164
+ // No fallback on a bindable prop: Svelte refuses `bind:…={undefined}` on
165
+ // one that has a fallback (`props_invalid_value`), and a page that throws
166
+ // while it hydrates never becomes interactive. The default is applied
167
+ // here instead: at once, for the server and the first render, and again
168
+ // whenever a parent hands back `undefined`.
169
+ const applyDefaults = () => {
170
+ if (searchValue === undefined) searchValue = "";
171
+ if (isLightMode === undefined) isLightMode = false;
172
+ if (isOpen === undefined) isOpen = false;
173
+ };
174
+ applyDefaults();
175
+ $effect.pre(applyDefaults);
176
+
177
+ /** Words many components share: a `ZabiStringsProvider` above this one may give them; else English. */
178
+ const common = zabiCommonStrings();
179
+ const searchPlaceholder = $derived(searchPlaceholderGiven ?? common().search);
180
+
121
181
  /** `class` is the public prop; `className` is a deprecated alias.
122
182
  * Both are merged here so existing call sites keep working. */
123
183
 
184
+ /** The app-wide words for this component, from a `ZabiStringsProvider` above it, if there is one. */
185
+ const provided = zabiStringsFor("sidebarNavigation");
186
+ const text = $derived(mergeStrings(DEFAULT_SIDEBAR_NAVIGATION_STRINGS, provided(), strings));
187
+ /** For the brand header and the footer: the provider's words for this sidebar, then the instance's. */
188
+ const handedOn = $derived(mergeStrings<Partial<SidebarNavigationStrings>>({}, provided(), strings));
189
+
124
190
  const isCollapsed = $derived(mode === "collapsed");
125
191
  const showBrandRow = $derived(
126
192
  Boolean(logoSrc.trim() || brandName.trim()),
@@ -186,7 +252,7 @@
186
252
  );
187
253
 
188
254
  const iconContainerClasses = $derived(
189
- "flex size-6 shrink-0 items-center justify-center leading-none text-current",
255
+ "flex size-5 shrink-0 items-center justify-center leading-none text-current",
190
256
  );
191
257
  /** With `searchMode: "input"`, the field stays visible even if `onSearchClick` is set (e.g. Storybook). */
192
258
  const shouldRenderSearchButton = $derived(
@@ -200,17 +266,10 @@
200
266
  }
201
267
 
202
268
  /**
203
- * The selected row used to be carried by its fill alone, and the fill was
204
- * 1.05:1 against the sidebar in light mode — not a fill, a rumour. Active
205
- * and idle labels were #18181b and #27272a at the same weight, a 15-unit
206
- * difference in one channel that nobody can see. So in light mode there
207
- * was effectively no indication of where you were.
208
- *
209
- * Three cues now, only one of which is colour-discrimination dependent:
210
- * the label takes --color-nav-menu-item-active (defined all along and
211
- * never referenced — the row said `text-inherit`), a 3px bar marks the
212
- * leading edge, and the tint stays as reinforcement rather than as the
213
- * whole message.
269
+ * One indicator marks the current row: the tinted fill, with the active
270
+ * label colour (--color-nav-menu-item-active) and a heavier weight, so the
271
+ * cue does not depend on telling two similar fills apart. (A 3px bar on
272
+ * the leading edge used to mark it a second time; D127.)
214
273
  */
215
274
  function isItemActive(item: SidebarNavigationItem): boolean {
216
275
  return (
@@ -222,20 +281,25 @@
222
281
  function getNavItemClasses(item: SidebarNavigationItem): string {
223
282
  const isActive = isItemActive(item);
224
283
  const layoutClasses = isCollapsed
225
- ? "flex min-h-10 items-center justify-center px-0 py-2"
226
- : "flex min-h-10 items-center gap-3 px-2 py-2";
284
+ ? "flex min-h-9 pointer-coarse:min-h-11 items-center justify-center px-0 py-2"
285
+ : "flex min-h-9 pointer-coarse:min-h-11 items-center gap-3 px-2 py-2";
227
286
  const structural =
228
- "focus-ring focus-ring--nav relative w-full cursor-pointer rounded-control no-underline transition-colors duration-150 outline-none";
287
+ "focus-ring focus-ring--nav relative w-full cursor-pointer rounded-control no-underline transition-colors duration-(--duration-base) ease-standard outline-none";
229
288
 
230
289
  if (isActive) {
290
+ // In forced colours the fill is gone and every link takes the
291
+ // system's link colour. An outline is a shape and is drawn there,
292
+ // so the current row keeps one. Inset, so a focused row's ring (2px
293
+ // outside) reads as a different thing.
231
294
  return (
232
295
  `${structural} ${layoutClasses} bg-nav-menu-active ` +
233
- "text-nav-menu-item-active hover:bg-nav-menu-active " +
234
- "active:bg-nav-menu-active-hover"
296
+ "font-semibold text-nav-menu-item-active hover:bg-nav-menu-active " +
297
+ "active:bg-nav-menu-active-hover " +
298
+ "forced-colors:outline-solid forced-colors:outline-2 forced-colors:-outline-offset-2"
235
299
  );
236
300
  }
237
301
 
238
- return `${structural} ${layoutClasses} text-nav-menu-item hover:bg-nav-menu-hover hover:text-nav-menu-item-hover active:bg-surface-active`;
302
+ return `${structural} ${layoutClasses} font-medium text-nav-menu-item hover:bg-nav-menu-hover hover:text-nav-menu-item-hover active:bg-surface-active`;
239
303
  }
240
304
 
241
305
  function handleNavigate(item: SidebarNavigationItem, event: MouseEvent) {
@@ -285,11 +349,19 @@
285
349
  {ariaLabel}
286
350
  class={classAttr}
287
351
  className={legacyClass}
352
+ {mobile}
353
+ bind:isOpen
354
+ {trigger}
355
+ {drawerTitle}
356
+ {closeLabel}
357
+ {onclose}
358
+ {label}
288
359
  {...restProps}
289
360
  >
290
361
  {#snippet header()}
291
362
  {#if showBrandRow}
292
363
  <SidebarBrandHeader
364
+ strings={handedOn}
293
365
  collapsed={isCollapsed}
294
366
  {brandName}
295
367
  logoSrc={logoSrc.trim()}
@@ -322,6 +394,7 @@
322
394
  <Button
323
395
  variant={searchTriggerVariant}
324
396
  size={searchTriggerSize}
397
+ class="min-h-9 pointer-coarse:min-h-11"
325
398
  fullWidth
326
399
  onclick={handleSearchClick}
327
400
  >
@@ -349,7 +422,7 @@
349
422
  bind:value={searchValue}
350
423
  placeholder={searchPlaceholder}
351
424
  aria-label={searchPlaceholder}
352
- class="focus-ring focus-ring--nav w-full min-w-0 min-h-10 rounded-container border-transparent !bg-transparent py-2 pl-10 text-sm ring-1 ring-border/60 hover:!bg-nav-menu-hover focus:!bg-transparent"
425
+ class="focus-ring focus-ring--nav w-full min-w-0 min-h-9 pointer-coarse:min-h-11 rounded-container border-transparent !bg-transparent py-2 pl-10 text-sm ring-1 ring-input-border hover:!bg-input-hover focus:!bg-transparent"
353
426
  />
354
427
  </div>
355
428
  {/if}
@@ -358,16 +431,16 @@
358
431
 
359
432
  {#if hasFilteredItems}
360
433
  <div
361
- class="flex w-full min-w-0 flex-col divide-y divide-border"
434
+ class="flex w-full min-w-0 flex-col gap-5"
362
435
  >
363
436
  {#each primarySectionGroups as group, gi (`${gi}-${group.sectionLabel ?? "x"}`)}
364
- <div class="py-4 first:pt-1 last:pb-1">
437
+ <div>
365
438
  <SidebarNavSection
366
439
  title={group.sectionLabel ?? ""}
367
440
  sectionKey={`p-${gi}`}
368
441
  listAriaLabel={group.sectionLabel
369
- ? `${group.sectionLabel} navigation`
370
- : "Primary navigation"}
442
+ ? text.sectionNavigation(group.sectionLabel)
443
+ : text.primaryNavigation}
371
444
  collapsed={isCollapsed}
372
445
  >
373
446
  {#each group.items as item (item.id)}
@@ -393,23 +466,17 @@
393
466
  aria-current={getAriaCurrent(item)}
394
467
  aria-label={isCollapsed ? item.label : undefined}
395
468
  >
396
- {#if isItemActive(item)}
397
- <span
398
- class="absolute left-0 top-1/2 h-5 w-[3px] -translate-y-1/2 rounded-pill bg-nav-menu-item-active"
399
- aria-hidden="true"
400
- ></span>
401
- {/if}
402
469
  {#if Icon}
403
470
  <span
404
471
  class={iconContainerClasses}
405
472
  aria-hidden="true"
406
473
  >
407
- <Icon size={18} />
474
+ <Icon size={20} />
408
475
  </span>
409
476
  {/if}
410
477
  {#if !isCollapsed}
411
478
  <span
412
- class="text-sm font-medium leading-snug text-inherit"
479
+ class="text-sm leading-snug text-inherit"
413
480
  >{item.label}</span
414
481
  >
415
482
  {/if}
@@ -447,12 +514,12 @@
447
514
 
448
515
  {#if filteredSecondaryItems.length > 0}
449
516
  <div
450
- class="mt-3 border-t border-border pt-4"
517
+ class="mt-5"
451
518
  role="presentation"
452
519
  >
453
520
  <SidebarNavSection
454
521
  sectionKey="secondary"
455
- listAriaLabel="Secondary navigation"
522
+ listAriaLabel={text.secondaryNavigation}
456
523
  collapsed={isCollapsed}
457
524
  >
458
525
  {#each filteredSecondaryItems as item (item.id)}
@@ -473,12 +540,12 @@
473
540
  class={iconContainerClasses}
474
541
  aria-hidden="true"
475
542
  >
476
- <Icon size={18} />
543
+ <Icon size={20} />
477
544
  </span>
478
545
  {/if}
479
546
  {#if !isCollapsed}
480
547
  <span
481
- class="text-sm font-medium leading-snug text-inherit"
548
+ class="text-sm leading-snug text-inherit"
482
549
  >{item.label}</span
483
550
  >
484
551
  {/if}
@@ -490,22 +557,22 @@
490
557
  {/if}
491
558
  {:else}
492
559
  <div
493
- class="rounded-container border border-border border-dashed bg-transparent px-4 py-4 ring-1 ring-border/60"
560
+ class="rounded-container border border-border border-dashed bg-transparent px-4 py-4"
494
561
  >
495
562
  <h3 class="text-sm font-semibold {getTextToneClass()}">
496
563
  {normalizedSearchTerm && searchMode === "input"
497
- ? "No matching navigation items"
564
+ ? text.noMatchesTitle
498
565
  : emptyStateTitle}
499
566
  </h3>
500
567
  <p class="mt-1 text-sm {getTextToneClass(true)}">
501
568
  {normalizedSearchTerm && searchMode === "input"
502
- ? `No results found for "${searchValue}". Try another keyword.`
569
+ ? text.noMatchesDescription(searchValue)
503
570
  : emptyStateDescription}
504
571
  </p>
505
572
  {#if !(normalizedSearchTerm && searchMode === "input")}
506
573
  <button
507
574
  type="button"
508
- class="focus-ring focus-ring--nav mt-3 inline-flex min-h-10 cursor-pointer items-center rounded-control bg-action-primary px-3 py-2 text-sm font-medium text-action-primary outline-none transition-colors hover:bg-action-primary-hover"
575
+ class="focus-ring focus-ring--nav mt-3 inline-flex min-h-9 pointer-coarse:min-h-11 cursor-pointer items-center rounded-control bg-action-primary px-3 py-2 text-sm font-medium text-action-primary outline-none transition-colors hover:bg-action-primary-hover"
509
576
  onclick={handleEmptyStateAction}
510
577
  >
511
578
  {emptyStateActionLabel}
@@ -516,6 +583,7 @@
516
583
  {#snippet footer({ insetX })}
517
584
  <SidebarFooter
518
585
  collapsed={isCollapsed}
586
+ strings={handedOn}
519
587
  {showProfile}
520
588
  {profileName}
521
589
  {profileEmail}
@@ -1,6 +1,8 @@
1
+ import type { SidebarDrawerCloseReason, SidebarTriggerContext } from "./SidebarShell.svelte";
1
2
  import type { Snippet } from "svelte";
2
3
  import type { Component } from "svelte";
3
4
  import type { ButtonVariant, SizeVariant } from "../types/variants.js";
5
+ import { type SidebarNavigationStrings } from "../util/sidebar.js";
4
6
  export interface SidebarNavigationItem {
5
7
  id: string;
6
8
  label: string;
@@ -21,6 +23,12 @@ interface Props {
21
23
  items?: SidebarNavigationItem[];
22
24
  currentPath?: string;
23
25
  ariaLabel?: string;
26
+ /**
27
+ * The words the sidebar says by itself, for another language: the
28
+ * names of its lists, the two lines shown when a search finds
29
+ * nothing, and those of the footer and the brand header in it.
30
+ */
31
+ strings?: Partial<SidebarNavigationStrings>;
24
32
  class?: string;
25
33
  /** @deprecated use `class`. */
26
34
  className?: string;
@@ -61,7 +69,27 @@ interface Props {
61
69
  profilePanel?: Snippet;
62
70
  /** Parent nav href to highlight when `currentPath` is a deeper leaf (e.g. category row). */
63
71
  activePrimaryHref?: string;
72
+ /**
73
+ * What the sidebar is below the `lg` breakpoint. `drawer`: the rail is
74
+ * hidden there and the sidebar opens in a Drawer from the start edge.
75
+ * This and the six props after it are SidebarShell's; see there.
76
+ */
77
+ mobile?: "none" | "drawer";
78
+ /** Whether the drawer is open. Bindable. */
79
+ isOpen?: boolean;
80
+ /** The button that opens the drawer, rendered in the rail's place below `lg`. */
81
+ trigger?: Snippet<[SidebarTriggerContext]>;
82
+ /** Heading of the drawer. Without it, `ariaLabel` is. */
83
+ drawerTitle?: string;
84
+ /** Accessible name of the drawer's close button. */
85
+ closeLabel?: string;
86
+ /** Fired when the drawer closes itself, with why. */
87
+ onclose?: (detail: {
88
+ reason: SidebarDrawerCloseReason;
89
+ }) => void;
90
+ /** Accessible name of the scrolling region between header and footer. */
91
+ label?: string;
64
92
  }
65
- declare const SidebarNavigation: Component<Props, {}, "isLightMode" | "searchValue">;
93
+ declare const SidebarNavigation: Component<Props, {}, "isOpen" | "isLightMode" | "searchValue">;
66
94
  type SidebarNavigation = ReturnType<typeof SidebarNavigation>;
67
95
  export default SidebarNavigation;
@@ -1,7 +1,9 @@
1
1
  <script lang="ts">
2
+ import { zabiCommonStrings } from "../util/zabi-strings.js";
2
3
  import Input from "../atoms/Input.svelte";
3
4
  import Badge from "../atoms/Badge.svelte";
4
- import { Search, X } from "@lucide/svelte";
5
+ import Search from "@lucide/svelte/icons/search";
6
+ import X from "@lucide/svelte/icons/x";
5
7
  import type { Component } from "svelte";
6
8
  import { cn } from "../util/cn.js";
7
9
 
@@ -18,6 +20,7 @@
18
20
  /** @deprecated use `class`. */
19
21
  className?: string;
20
22
  widthClass?: string;
23
+ /** Both values draw the same flat card now (D127); the prop stays so existing usage compiles. */
21
24
  variant?: "plain" | "elevated";
22
25
  ariaLabel?: string;
23
26
  title?: string;
@@ -46,10 +49,10 @@
46
49
  title = "Items",
47
50
  subtitle = "Choose an item to continue",
48
51
  showSearch = true,
49
- searchPlaceholder = "Search...",
50
- searchValue = $bindable(""),
52
+ searchPlaceholder: searchPlaceholderGiven,
53
+ searchValue = $bindable<Exclude<Props["searchValue"], undefined>>(),
51
54
  items = [],
52
- selectedItemId = $bindable(""),
55
+ selectedItemId = $bindable<Exclude<Props["selectedItemId"], undefined>>(),
53
56
  emptyStateTitle = "No matches",
54
57
  emptyStateDescription = "Try a different keyword.",
55
58
  emptyStateActionLabel = "",
@@ -61,6 +64,22 @@
61
64
  ...restProps
62
65
  }: Props = $props();
63
66
 
67
+ // No fallback on a bindable prop: Svelte refuses `bind:…={undefined}` on
68
+ // one that has a fallback (`props_invalid_value`), and a page that throws
69
+ // while it hydrates never becomes interactive. The default is applied
70
+ // here instead: at once, for the server and the first render, and again
71
+ // whenever a parent hands back `undefined`.
72
+ const applyDefaults = () => {
73
+ if (searchValue === undefined) searchValue = "";
74
+ if (selectedItemId === undefined) selectedItemId = "";
75
+ };
76
+ applyDefaults();
77
+ $effect.pre(applyDefaults);
78
+
79
+ /** Words many components share: a `ZabiStringsProvider` above this one may give them; else English. */
80
+ const common = zabiCommonStrings();
81
+ const searchPlaceholder = $derived(searchPlaceholderGiven ?? common().search);
82
+
64
83
  /** `class` is the public prop; `className` is a deprecated alias.
65
84
  * Both are merged here so existing call sites keep working. */
66
85
  const className = $derived(cn(`${classAttr} ${legacyClass}`));
@@ -74,22 +93,20 @@
74
93
  : items,
75
94
  );
76
95
 
77
- const isElevated = $derived(variant === "elevated");
78
-
79
96
  const containerClasses = $derived.by(() => {
80
97
  const resolvedWidthClass = widthClass.trim() || "w-80";
81
- const shell = isElevated
82
- ? "rounded-container border border-border bg-card text-headline shadow-sm ring-1 ring-border/50"
83
- : "rounded-container border border-border bg-card text-headline shadow-sm";
98
+ const shell = "rounded-container border border-border bg-card text-headline";
84
99
  return cn(`${resolvedWidthClass} shrink-0 p-5 ${shell} ${className}`);
85
100
  });
86
101
 
87
102
  function getItemClasses(itemId: string): string {
88
103
  const isActive = selectedItemId === itemId;
89
104
  const baseClasses =
90
- "focus-ring focus-ring--nav w-full cursor-pointer rounded-control px-3 py-2 text-left transition-colors duration-150";
105
+ "focus-ring focus-ring--nav w-full cursor-pointer min-h-9 pointer-coarse:min-h-11 rounded-control px-3 py-2 text-left transition-colors duration-(--duration-base) ease-standard";
91
106
  if (isActive) {
92
- return `${baseClasses} bg-nav-menu-active text-inherit shadow-sm ring-1 ring-border/80`;
107
+ // The fill is dropped in forced colours; an outline is drawn
108
+ // there, so the selected item keeps a shape of its own.
109
+ return `${baseClasses} bg-nav-menu-active text-nav-menu-item-active forced-colors:outline-solid forced-colors:outline-2 forced-colors:-outline-offset-2`;
93
110
  }
94
111
  return `${baseClasses} text-nav-menu-item hover:bg-nav-menu-hover hover:text-nav-menu-item-hover active:bg-surface-active`;
95
112
  }
@@ -124,7 +141,7 @@
124
141
  </div>
125
142
  <button
126
143
  type="button"
127
- class="-mr-0.5 -mt-0.5 inline-flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-control text-nav-menu-item transition-colors hover:bg-nav-menu-hover hover:text-nav-menu-item-hover focus-ring focus-ring--nav"
144
+ class="-mr-0.5 -mt-0.5 inline-flex size-9 pointer-coarse:min-h-11 pointer-coarse:min-w-11 shrink-0 cursor-pointer items-center justify-center rounded-control text-nav-menu-item transition-colors hover:bg-nav-menu-hover hover:text-nav-menu-item-hover active:bg-nav-menu-active focus-ring focus-ring--nav"
128
145
  aria-label={closeLabel}
129
146
  onclick={handleClose}
130
147
  >
@@ -145,7 +162,7 @@
145
162
  bind:value={searchValue}
146
163
  placeholder={searchPlaceholder}
147
164
  aria-label={searchPlaceholder}
148
- class="w-full min-w-0 min-h-10 rounded-container border-transparent !bg-transparent py-2 pl-10 text-sm ring-1 ring-border/60 hover:!bg-nav-menu-hover focus:!bg-transparent focus-ring focus-ring--nav"
165
+ class="w-full min-w-0 min-h-9 pointer-coarse:min-h-11 rounded-container border-transparent !bg-transparent py-2 pl-10 text-sm ring-1 ring-input-border hover:!bg-nav-menu-hover focus:!bg-transparent focus-ring focus-ring--nav"
149
166
  />
150
167
  </div>
151
168
  {/if}
@@ -169,12 +186,12 @@
169
186
  class="mt-0.5 inline-flex size-5 shrink-0 items-center justify-center text-current"
170
187
  aria-hidden="true"
171
188
  >
172
- <Icon size={18} />
189
+ <Icon size={20} />
173
190
  </span>
174
191
  {/if}
175
192
  <span class="min-w-0">
176
193
  <span
177
- class="block truncate text-sm font-medium text-current"
194
+ class={cn("block truncate text-sm text-current", selectedItemId === item.id ? "font-semibold" : "font-medium")}
178
195
  >
179
196
  {item.label}
180
197
  </span>
@@ -197,14 +214,14 @@
197
214
  </ul>
198
215
  {:else}
199
216
  <div
200
- class="rounded-container border border-dashed border-border bg-transparent px-4 py-4 ring-1 ring-border/40"
217
+ class="rounded-container border border-dashed border-border bg-transparent px-4 py-4"
201
218
  >
202
219
  <h4 class="text-sm font-semibold text-headline">{emptyStateTitle}</h4>
203
220
  <p class="mt-1 text-sm leading-relaxed text-description">{emptyStateDescription}</p>
204
221
  {#if emptyStateActionLabel.trim() && onEmptyStateAction}
205
222
  <button
206
223
  type="button"
207
- class="mt-3 inline-flex min-h-10 cursor-pointer items-center rounded-control bg-action-primary px-3 py-2 text-sm font-medium text-action-primary transition-colors hover:bg-action-primary-hover focus-ring focus-ring--nav"
224
+ class="mt-3 inline-flex min-h-9 pointer-coarse:min-h-11 cursor-pointer items-center rounded-control bg-action-primary px-3 py-2 text-sm font-medium text-action-primary transition-colors hover:bg-action-primary-hover focus-ring focus-ring--nav"
208
225
  onclick={handleEmptyStateAction}
209
226
  >
210
227
  {emptyStateActionLabel.trim()}
@@ -14,6 +14,7 @@ interface Props {
14
14
  /** @deprecated use `class`. */
15
15
  className?: string;
16
16
  widthClass?: string;
17
+ /** Both values draw the same flat card now (D127); the prop stays so existing usage compiles. */
17
18
  variant?: "plain" | "elevated";
18
19
  ariaLabel?: string;
19
20
  title?: string;