zabi-components 8.0.0 → 8.1.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 (364) hide show
  1. package/CHANGELOG.md +1924 -0
  2. package/README.md +243 -10
  3. package/THEME.md +149 -332
  4. package/THEMING.md +1192 -266
  5. package/dist/atoms/ActionPanel.svelte +15 -5
  6. package/dist/atoms/Avatar.svelte +104 -0
  7. package/dist/atoms/Avatar.svelte.d.ts +34 -0
  8. package/dist/atoms/Badge.svelte +36 -7
  9. package/dist/atoms/Badge.svelte.d.ts +2 -2
  10. package/dist/atoms/Button.svelte +177 -27
  11. package/dist/atoms/Button.svelte.d.ts +30 -2
  12. package/dist/atoms/Card.svelte +4 -4
  13. package/dist/atoms/CardHeader.svelte +16 -4
  14. package/dist/atoms/Checkbox.svelte +48 -21
  15. package/dist/atoms/Checkbox.svelte.d.ts +4 -2
  16. package/dist/atoms/CodeBlock.svelte +20 -2
  17. package/dist/atoms/CodeBlock.svelte.d.ts +4 -0
  18. package/dist/atoms/ColorPicker.svelte +259 -49
  19. package/dist/atoms/ColorPicker.svelte.d.ts +3 -0
  20. package/dist/atoms/Container.svelte +16 -8
  21. package/dist/atoms/DateField.svelte +107 -0
  22. package/dist/atoms/DateField.svelte.d.ts +53 -0
  23. package/dist/atoms/FieldMessages.svelte +69 -0
  24. package/dist/atoms/FieldMessages.svelte.d.ts +23 -0
  25. package/dist/atoms/FloatingActionButton.svelte +174 -0
  26. package/dist/atoms/FloatingActionButton.svelte.d.ts +51 -0
  27. package/dist/atoms/Heading.svelte +37 -5
  28. package/dist/atoms/Heading.svelte.d.ts +7 -0
  29. package/dist/atoms/IconButton.svelte +220 -24
  30. package/dist/atoms/IconButton.svelte.d.ts +49 -4
  31. package/dist/atoms/Input.svelte +253 -52
  32. package/dist/atoms/Input.svelte.d.ts +32 -2
  33. package/dist/atoms/List.svelte +4 -1
  34. package/dist/atoms/ListItem.svelte +44 -11
  35. package/dist/atoms/ListItem.svelte.d.ts +5 -0
  36. package/dist/atoms/Progress.svelte +27 -8
  37. package/dist/atoms/Progress.svelte.d.ts +4 -0
  38. package/dist/atoms/Radio.svelte +19 -3
  39. package/dist/atoms/Radio.svelte.d.ts +4 -2
  40. package/dist/atoms/Rating.svelte +494 -0
  41. package/dist/atoms/Rating.svelte.d.ts +56 -0
  42. package/dist/atoms/Select.svelte +433 -91
  43. package/dist/atoms/Select.svelte.d.ts +49 -3
  44. package/dist/atoms/SelectionControl.svelte +94 -17
  45. package/dist/atoms/SelectionControl.svelte.d.ts +4 -3
  46. package/dist/atoms/Skeleton.svelte +1 -1
  47. package/dist/atoms/Slider.svelte +309 -0
  48. package/dist/atoms/Slider.svelte.d.ts +40 -0
  49. package/dist/atoms/Spinner.svelte +57 -0
  50. package/dist/atoms/Spinner.svelte.d.ts +19 -0
  51. package/dist/atoms/Table.svelte +151 -6
  52. package/dist/atoms/Table.svelte.d.ts +15 -3
  53. package/dist/atoms/TemporalField.svelte +140 -0
  54. package/dist/atoms/TemporalField.svelte.d.ts +32 -0
  55. package/dist/atoms/Text.svelte +23 -11
  56. package/dist/atoms/Text.svelte.d.ts +6 -3
  57. package/dist/atoms/Textarea.svelte +55 -44
  58. package/dist/atoms/Textarea.svelte.d.ts +14 -2
  59. package/dist/atoms/ThemeToggle.svelte +223 -44
  60. package/dist/atoms/ThemeToggle.svelte.d.ts +26 -3
  61. package/dist/atoms/TimeField.svelte +108 -0
  62. package/dist/atoms/TimeField.svelte.d.ts +54 -0
  63. package/dist/atoms/Toast.svelte +17 -4
  64. package/dist/atoms/Toast.svelte.d.ts +2 -0
  65. package/dist/atoms/Toggle.svelte +41 -8
  66. package/dist/atoms/Toggle.svelte.d.ts +11 -2
  67. package/dist/atoms/Tooltip.svelte +508 -23
  68. package/dist/atoms/Tooltip.svelte.d.ts +11 -0
  69. package/dist/atoms/ZabiStringsProvider.svelte +45 -0
  70. package/dist/atoms/ZabiStringsProvider.svelte.d.ts +27 -0
  71. package/dist/atoms/index.d.ts +17 -0
  72. package/dist/atoms/index.js +12 -0
  73. package/dist/atoms/selection-control.styles.d.ts +36 -5
  74. package/dist/atoms/selection-control.styles.js +40 -9
  75. package/dist/components/atoms/index.d.ts +17 -0
  76. package/dist/components/atoms/index.d.ts.map +1 -1
  77. package/dist/components/atoms/selection-control.styles.d.ts +36 -5
  78. package/dist/components/atoms/selection-control.styles.d.ts.map +1 -1
  79. package/dist/components/index.d.ts +80 -2
  80. package/dist/components/index.d.ts.map +1 -1
  81. package/dist/components/molecules/index.d.ts +46 -0
  82. package/dist/components/molecules/index.d.ts.map +1 -1
  83. package/dist/components/molecules/toast-store.d.ts +53 -7
  84. package/dist/components/molecules/toast-store.d.ts.map +1 -1
  85. package/dist/components/organisms/index.d.ts +5 -0
  86. package/dist/components/organisms/index.d.ts.map +1 -1
  87. package/dist/components/types/variants.d.ts +15 -1
  88. package/dist/components/types/variants.d.ts.map +1 -1
  89. package/dist/components/util/app-shell.d.ts +28 -0
  90. package/dist/components/util/app-shell.d.ts.map +1 -0
  91. package/dist/components/util/avatar.d.ts +36 -0
  92. package/dist/components/util/avatar.d.ts.map +1 -0
  93. package/dist/components/util/bottom-sheet.d.ts +30 -0
  94. package/dist/components/util/bottom-sheet.d.ts.map +1 -0
  95. package/dist/components/util/bottom-tab-bar.d.ts +35 -0
  96. package/dist/components/util/bottom-tab-bar.d.ts.map +1 -0
  97. package/dist/components/util/calendar.d.ts +56 -0
  98. package/dist/components/util/calendar.d.ts.map +1 -0
  99. package/dist/components/util/collapsible.d.ts +58 -0
  100. package/dist/components/util/collapsible.d.ts.map +1 -0
  101. package/dist/components/util/confirm-dialog.d.ts +12 -0
  102. package/dist/components/util/confirm-dialog.d.ts.map +1 -0
  103. package/dist/components/util/date.d.ts +96 -0
  104. package/dist/components/util/date.d.ts.map +1 -0
  105. package/dist/components/util/drawer.d.ts +13 -0
  106. package/dist/components/util/drawer.d.ts.map +1 -0
  107. package/dist/components/util/dropdown.d.ts +47 -0
  108. package/dist/components/util/dropdown.d.ts.map +1 -0
  109. package/dist/components/util/field.d.ts +39 -0
  110. package/dist/components/util/field.d.ts.map +1 -0
  111. package/dist/components/util/fit-in-viewport.d.ts +201 -0
  112. package/dist/components/util/fit-in-viewport.d.ts.map +1 -0
  113. package/dist/components/util/focus-utils.d.ts +75 -2
  114. package/dist/components/util/focus-utils.d.ts.map +1 -1
  115. package/dist/components/util/hydration.d.ts +45 -0
  116. package/dist/components/util/hydration.d.ts.map +1 -0
  117. package/dist/components/util/keyboard-inset.d.ts +18 -0
  118. package/dist/components/util/keyboard-inset.d.ts.map +1 -0
  119. package/dist/components/util/media-grid.d.ts +51 -0
  120. package/dist/components/util/media-grid.d.ts.map +1 -0
  121. package/dist/components/util/media.d.ts +6 -0
  122. package/dist/components/util/media.d.ts.map +1 -0
  123. package/dist/components/util/overlay-chrome.d.ts +53 -0
  124. package/dist/components/util/overlay-chrome.d.ts.map +1 -0
  125. package/dist/components/util/overlay.d.ts +72 -0
  126. package/dist/components/util/overlay.d.ts.map +1 -0
  127. package/dist/components/util/photo.d.ts +215 -0
  128. package/dist/components/util/photo.d.ts.map +1 -0
  129. package/dist/components/util/portal.d.ts +23 -0
  130. package/dist/components/util/portal.d.ts.map +1 -0
  131. package/dist/components/util/pull-to-refresh.d.ts +27 -0
  132. package/dist/components/util/pull-to-refresh.d.ts.map +1 -0
  133. package/dist/components/util/radio-keys.d.ts +25 -0
  134. package/dist/components/util/radio-keys.d.ts.map +1 -0
  135. package/dist/components/util/rating.d.ts +23 -0
  136. package/dist/components/util/rating.d.ts.map +1 -0
  137. package/dist/components/util/ready-made-strings.d.ts +77 -0
  138. package/dist/components/util/ready-made-strings.d.ts.map +1 -0
  139. package/dist/components/util/scroll-padding.d.ts +20 -0
  140. package/dist/components/util/scroll-padding.d.ts.map +1 -0
  141. package/dist/components/util/segmented-control.d.ts +16 -0
  142. package/dist/components/util/segmented-control.d.ts.map +1 -0
  143. package/dist/components/util/select.d.ts +41 -0
  144. package/dist/components/util/select.d.ts.map +1 -0
  145. package/dist/components/util/sheet-drag.d.ts +60 -0
  146. package/dist/components/util/sheet-drag.d.ts.map +1 -0
  147. package/dist/components/util/sidebar.d.ts +63 -0
  148. package/dist/components/util/sidebar.d.ts.map +1 -0
  149. package/dist/components/util/sortable-list.d.ts +65 -0
  150. package/dist/components/util/sortable-list.d.ts.map +1 -0
  151. package/dist/components/util/stepper.d.ts +40 -0
  152. package/dist/components/util/stepper.d.ts.map +1 -0
  153. package/dist/components/util/swipeable-list-item.d.ts +36 -0
  154. package/dist/components/util/swipeable-list-item.d.ts.map +1 -0
  155. package/dist/components/util/theme-mode.d.ts +80 -0
  156. package/dist/components/util/theme-mode.d.ts.map +1 -0
  157. package/dist/components/util/toaster.d.ts +93 -0
  158. package/dist/components/util/toaster.d.ts.map +1 -0
  159. package/dist/components/util/tooltip.d.ts +10 -0
  160. package/dist/components/util/tooltip.d.ts.map +1 -0
  161. package/dist/components/util/top-navbar.d.ts +11 -0
  162. package/dist/components/util/top-navbar.d.ts.map +1 -0
  163. package/dist/components/util/touch-target.d.ts +31 -0
  164. package/dist/components/util/touch-target.d.ts.map +1 -0
  165. package/dist/components/util/zabi-strings.d.ts +133 -0
  166. package/dist/components/util/zabi-strings.d.ts.map +1 -0
  167. package/dist/create-theme/cli.js +169 -0
  168. package/dist/create-theme/index.d.ts +176 -0
  169. package/dist/create-theme/index.js +817 -0
  170. package/dist/create-theme/lib/ramp-math.js +128 -0
  171. package/dist/create-theme/lib/resolve.js +141 -0
  172. package/dist/create-theme/theme-data.js +1116 -0
  173. package/dist/index.d.ts +80 -2
  174. package/dist/index.js +57 -2
  175. package/dist/molecules/Alert.svelte +33 -5
  176. package/dist/molecules/Alert.svelte.d.ts +2 -0
  177. package/dist/molecules/AppBar.svelte +415 -0
  178. package/dist/molecules/AppBar.svelte.d.ts +69 -0
  179. package/dist/molecules/AvatarGroup.svelte +116 -0
  180. package/dist/molecules/AvatarGroup.svelte.d.ts +40 -0
  181. package/dist/molecules/BottomSheet.svelte +540 -0
  182. package/dist/molecules/BottomSheet.svelte.d.ts +93 -0
  183. package/dist/molecules/BottomTabBar.svelte +297 -0
  184. package/dist/molecules/BottomTabBar.svelte.d.ts +64 -0
  185. package/dist/molecules/Calendar.svelte +597 -0
  186. package/dist/molecules/Calendar.svelte.d.ts +72 -0
  187. package/dist/molecules/Collapsible.svelte +243 -0
  188. package/dist/molecules/Collapsible.svelte.d.ts +44 -0
  189. package/dist/molecules/CollapsibleGroup.svelte +126 -0
  190. package/dist/molecules/CollapsibleGroup.svelte.d.ts +14 -0
  191. package/dist/molecules/ComponentDemo.svelte +16 -4
  192. package/dist/molecules/ComponentDemo.svelte.d.ts +3 -0
  193. package/dist/molecules/ConfirmDialog.svelte +253 -0
  194. package/dist/molecules/ConfirmDialog.svelte.d.ts +55 -0
  195. package/dist/molecules/ContactForm.svelte +34 -17
  196. package/dist/molecules/ContactForm.svelte.d.ts +8 -0
  197. package/dist/molecules/Drawer.svelte +394 -0
  198. package/dist/molecules/Drawer.svelte.d.ts +55 -0
  199. package/dist/molecules/Dropdown.svelte +509 -48
  200. package/dist/molecules/Dropdown.svelte.d.ts +45 -6
  201. package/dist/molecules/DropdownItem.svelte +122 -0
  202. package/dist/molecules/DropdownItem.svelte.d.ts +28 -0
  203. package/dist/molecules/EmptyState.svelte +55 -10
  204. package/dist/molecules/EmptyState.svelte.d.ts +8 -0
  205. package/dist/molecules/FormField.svelte +9 -1
  206. package/dist/molecules/FormField.svelte.d.ts +2 -0
  207. package/dist/molecules/Header.svelte +1 -1
  208. package/dist/molecules/ImageUpload.svelte +383 -70
  209. package/dist/molecules/ImageUpload.svelte.d.ts +47 -2
  210. package/dist/molecules/MediaGrid.svelte +527 -0
  211. package/dist/molecules/MediaGrid.svelte.d.ts +77 -0
  212. package/dist/molecules/Modal.svelte +288 -72
  213. package/dist/molecules/Modal.svelte.d.ts +51 -2
  214. package/dist/molecules/NavigationMenuContent.svelte +58 -1
  215. package/dist/molecules/NavigationMenuItem.svelte +0 -1
  216. package/dist/molecules/NavigationMenuLink.svelte +1 -1
  217. package/dist/molecules/NavigationMenuList.svelte +10 -3
  218. package/dist/molecules/NavigationMenuTrigger.svelte +2 -2
  219. package/dist/molecules/Page.svelte +32 -2
  220. package/dist/molecules/Page.svelte.d.ts +11 -0
  221. package/dist/molecules/PhotoGrid.svelte +433 -0
  222. package/dist/molecules/PhotoGrid.svelte.d.ts +62 -0
  223. package/dist/molecules/PhotoViewer.svelte +1116 -0
  224. package/dist/molecules/PhotoViewer.svelte.d.ts +56 -0
  225. package/dist/molecules/PropsTable.svelte +22 -10
  226. package/dist/molecules/PropsTable.svelte.d.ts +3 -0
  227. package/dist/molecules/PullToRefresh.svelte +263 -0
  228. package/dist/molecules/PullToRefresh.svelte.d.ts +52 -0
  229. package/dist/molecules/RadioGroup.svelte +52 -14
  230. package/dist/molecules/RadioGroup.svelte.d.ts +14 -3
  231. package/dist/molecules/Section.svelte +1 -1
  232. package/dist/molecules/SegmentedControl.svelte +323 -0
  233. package/dist/molecules/SegmentedControl.svelte.d.ts +34 -0
  234. package/dist/molecules/SidebarBrandHeader.svelte +11 -1
  235. package/dist/molecules/SidebarBrandHeader.svelte.d.ts +3 -0
  236. package/dist/molecules/SidebarFooter.svelte +29 -6
  237. package/dist/molecules/SidebarFooter.svelte.d.ts +3 -0
  238. package/dist/molecules/SlideUp.svelte +220 -61
  239. package/dist/molecules/SlideUp.svelte.d.ts +26 -0
  240. package/dist/molecules/SortableList.svelte +632 -0
  241. package/dist/molecules/SortableList.svelte.d.ts +69 -0
  242. package/dist/molecules/Stepper.svelte +548 -0
  243. package/dist/molecules/Stepper.svelte.d.ts +39 -0
  244. package/dist/molecules/StickyActionBar.svelte +191 -0
  245. package/dist/molecules/StickyActionBar.svelte.d.ts +65 -0
  246. package/dist/molecules/SwipeableListItem.svelte +334 -0
  247. package/dist/molecules/SwipeableListItem.svelte.d.ts +54 -0
  248. package/dist/molecules/Tabs.svelte +233 -9
  249. package/dist/molecules/Tabs.svelte.d.ts +7 -0
  250. package/dist/molecules/Toaster.svelte +350 -5
  251. package/dist/molecules/Toaster.svelte.d.ts +95 -2
  252. package/dist/molecules/ToasterToast.svelte +253 -67
  253. package/dist/molecules/ToasterToast.svelte.d.ts +9 -0
  254. package/dist/molecules/UnsavedChangesBar.svelte +212 -0
  255. package/dist/molecules/UnsavedChangesBar.svelte.d.ts +43 -0
  256. package/dist/molecules/index.d.ts +46 -0
  257. package/dist/molecules/index.js +27 -0
  258. package/dist/molecules/toast-store.d.ts +53 -7
  259. package/dist/molecules/toast-store.js +21 -0
  260. package/dist/organisms/AppShell.svelte +196 -0
  261. package/dist/organisms/AppShell.svelte.d.ts +61 -0
  262. package/dist/organisms/SidebarAccountPanel.svelte +107 -12
  263. package/dist/organisms/SidebarAccountPanel.svelte.d.ts +19 -0
  264. package/dist/organisms/SidebarNavigation.svelte +96 -15
  265. package/dist/organisms/SidebarNavigation.svelte.d.ts +29 -1
  266. package/dist/organisms/SidebarPanel.svelte +31 -10
  267. package/dist/organisms/SidebarShell.svelte +162 -11
  268. package/dist/organisms/SidebarShell.svelte.d.ts +56 -2
  269. package/dist/organisms/TopNavbar.svelte +256 -31
  270. package/dist/organisms/TopNavbar.svelte.d.ts +26 -0
  271. package/dist/organisms/index.d.ts +5 -0
  272. package/dist/organisms/index.js +3 -0
  273. package/dist/types/components.d.ts +4 -0
  274. package/dist/types/components.d.ts.map +1 -1
  275. package/dist/types/index.d.ts +605 -25
  276. package/dist/types/index.d.ts.map +1 -1
  277. package/dist/types/variants.ts +17 -1
  278. package/dist/util/app-shell.d.ts +27 -0
  279. package/dist/util/app-shell.js +72 -0
  280. package/dist/util/avatar.d.ts +35 -0
  281. package/dist/util/avatar.js +52 -0
  282. package/dist/util/bottom-sheet.d.ts +29 -0
  283. package/dist/util/bottom-sheet.js +43 -0
  284. package/dist/util/bottom-tab-bar.d.ts +34 -0
  285. package/dist/util/bottom-tab-bar.js +54 -0
  286. package/dist/util/calendar.d.ts +55 -0
  287. package/dist/util/calendar.js +74 -0
  288. package/dist/util/collapsible.d.ts +57 -0
  289. package/dist/util/collapsible.js +23 -0
  290. package/dist/util/confirm-dialog.d.ts +11 -0
  291. package/dist/util/confirm-dialog.js +2 -0
  292. package/dist/util/date.d.ts +95 -0
  293. package/dist/util/date.js +237 -0
  294. package/dist/util/drawer.d.ts +12 -0
  295. package/dist/util/drawer.js +7 -0
  296. package/dist/util/dropdown.d.ts +46 -0
  297. package/dist/util/dropdown.js +21 -0
  298. package/dist/util/field.d.ts +38 -0
  299. package/dist/util/field.js +38 -0
  300. package/dist/util/fit-in-viewport.d.ts +200 -0
  301. package/dist/util/fit-in-viewport.js +399 -0
  302. package/dist/util/focus-utils.d.ts +75 -2
  303. package/dist/util/focus-utils.js +182 -9
  304. package/dist/util/hydration.d.ts +44 -0
  305. package/dist/util/hydration.js +58 -0
  306. package/dist/util/keyboard-inset.d.ts +17 -0
  307. package/dist/util/keyboard-inset.js +53 -0
  308. package/dist/util/media-grid.d.ts +50 -0
  309. package/dist/util/media-grid.js +81 -0
  310. package/dist/util/media.d.ts +5 -0
  311. package/dist/util/media.js +10 -0
  312. package/dist/util/overlay-chrome.d.ts +52 -0
  313. package/dist/util/overlay-chrome.js +56 -0
  314. package/dist/util/overlay.d.ts +71 -0
  315. package/dist/util/overlay.js +240 -0
  316. package/dist/util/photo.d.ts +214 -0
  317. package/dist/util/photo.js +206 -0
  318. package/dist/util/portal.d.ts +22 -0
  319. package/dist/util/portal.js +50 -0
  320. package/dist/util/pull-to-refresh.d.ts +26 -0
  321. package/dist/util/pull-to-refresh.js +30 -0
  322. package/dist/util/radio-keys.d.ts +24 -0
  323. package/dist/util/radio-keys.js +49 -0
  324. package/dist/util/rating.d.ts +22 -0
  325. package/dist/util/rating.js +26 -0
  326. package/dist/util/ready-made-strings.d.ts +76 -0
  327. package/dist/util/ready-made-strings.js +67 -0
  328. package/dist/util/scroll-padding.d.ts +19 -0
  329. package/dist/util/scroll-padding.js +44 -0
  330. package/dist/util/segmented-control.d.ts +15 -0
  331. package/dist/util/segmented-control.js +1 -0
  332. package/dist/util/select.d.ts +40 -0
  333. package/dist/util/select.js +63 -0
  334. package/dist/util/sheet-drag.d.ts +59 -0
  335. package/dist/util/sheet-drag.js +241 -0
  336. package/dist/util/sidebar.d.ts +62 -0
  337. package/dist/util/sidebar.js +38 -0
  338. package/dist/util/sortable-list.d.ts +64 -0
  339. package/dist/util/sortable-list.js +53 -0
  340. package/dist/util/stepper.d.ts +39 -0
  341. package/dist/util/stepper.js +38 -0
  342. package/dist/util/swipeable-list-item.d.ts +35 -0
  343. package/dist/util/swipeable-list-item.js +32 -0
  344. package/dist/util/theme-mode.d.ts +79 -0
  345. package/dist/util/theme-mode.js +121 -0
  346. package/dist/util/toaster.d.ts +92 -0
  347. package/dist/util/toaster.js +75 -0
  348. package/dist/util/tooltip.d.ts +9 -0
  349. package/dist/util/tooltip.js +18 -0
  350. package/dist/util/top-navbar.d.ts +10 -0
  351. package/dist/util/top-navbar.js +5 -0
  352. package/dist/util/touch-target.d.ts +30 -0
  353. package/dist/util/touch-target.js +30 -0
  354. package/dist/util/zabi-strings.d.ts +132 -0
  355. package/dist/util/zabi-strings.js +105 -0
  356. package/dist/zabi-components-colors.css +5 -2
  357. package/dist/zabi-components-theme-dark-only.css +543 -241
  358. package/dist/zabi-components-theme-dark.css +543 -241
  359. package/dist/zabi-components-theme-only.css +1584 -367
  360. package/dist/zabi-components-theme.css +1584 -367
  361. package/dist/zabi-components.css +3885 -518
  362. package/docs/lucide-icons.md +40 -17
  363. package/docs/theme-imports.md +81 -11
  364. package/package.json +35 -8
@@ -1,9 +1,14 @@
1
1
  <script lang="ts">
2
+ import type { HTMLInputAttributes } from "svelte/elements";
2
3
  import SelectionControl from "./SelectionControl.svelte";
3
4
  import type { SelectionControlMarkProps } from "./SelectionControl.svelte";
4
5
  import { RADIO_CHECKED_DOT_CLASSES } from "./selection-control.styles";
5
6
 
6
- interface Props {
7
+ /** Other attributes (`required`, `data-*`, `aria-*`, ...) land on the `<input>`. */
8
+ type Props = Omit<
9
+ HTMLInputAttributes,
10
+ "class" | "id" | "name" | "value" | "disabled" | "checked" | "type" | "onchange"
11
+ > & {
7
12
  /** Extra classes for the host element. */
8
13
  class?: string;
9
14
  id?: string;
@@ -15,7 +20,7 @@
15
20
  checked?: boolean;
16
21
  onChange?: (event: Event) => void;
17
22
  onchange?: (event: Event) => void;
18
- }
23
+ };
19
24
 
20
25
  let {
21
26
  class: className = "",
@@ -25,11 +30,22 @@
25
30
  label = "",
26
31
  disabled = false,
27
32
  defaultChecked = false,
28
- checked = $bindable(defaultChecked),
33
+ checked = $bindable<Exclude<Props["checked"], undefined>>(),
29
34
  onChange,
30
35
  onchange,
31
36
  ...restProps
32
37
  }: Props = $props();
38
+
39
+ // No fallback on a bindable prop: Svelte refuses `bind:…={undefined}` on
40
+ // one that has a fallback (`props_invalid_value`), and a page that throws
41
+ // while it hydrates never becomes interactive. The default is applied
42
+ // here instead: at once, for the server and the first render, and again
43
+ // whenever a parent hands back `undefined`.
44
+ const applyDefaults = () => {
45
+ if (checked === undefined) checked = defaultChecked;
46
+ };
47
+ applyDefaults();
48
+ $effect.pre(applyDefaults);
33
49
  </script>
34
50
 
35
51
  {#snippet mark(_props: SelectionControlMarkProps)}
@@ -1,4 +1,6 @@
1
- interface Props {
1
+ import type { HTMLInputAttributes } from "svelte/elements";
2
+ /** Other attributes (`required`, `data-*`, `aria-*`, ...) land on the `<input>`. */
3
+ type Props = Omit<HTMLInputAttributes, "class" | "id" | "name" | "value" | "disabled" | "checked" | "type" | "onchange"> & {
2
4
  /** Extra classes for the host element. */
3
5
  class?: string;
4
6
  id?: string;
@@ -10,7 +12,7 @@ interface Props {
10
12
  checked?: boolean;
11
13
  onChange?: (event: Event) => void;
12
14
  onchange?: (event: Event) => void;
13
- }
15
+ };
14
16
  declare const Radio: import("svelte").Component<Props, {}, "checked">;
15
17
  type Radio = ReturnType<typeof Radio>;
16
18
  export default Radio;
@@ -0,0 +1,494 @@
1
+ <script lang="ts">
2
+ import { mergeStrings } from "../util/ready-made-strings.js";
3
+ import { zabiStringsFor } from "../util/zabi-strings.js";
4
+ import Star from "@lucide/svelte/icons/star";
5
+ import X from "@lucide/svelte/icons/x";
6
+ import type { HTMLAttributes } from "svelte/elements";
7
+ import type { SizeVariant } from "../types/variants.js";
8
+ import { cn } from "../util/cn.js";
9
+ import { resetValueOf, groupBinding } from "../util/hydration.js";
10
+ import { isRtl, radioKeyIndex } from "../util/radio-keys.js";
11
+ import {
12
+ RATING_STRINGS,
13
+ clampRating,
14
+ defaultRatingFormat,
15
+ starCount,
16
+ starFill,
17
+ type RatingStrings,
18
+ } from "../util/rating.js";
19
+ import { generateId } from "../util/ssr-safe.js";
20
+
21
+ /** Other attributes (`data-*`, `id`, ...) land on the host element. */
22
+ type Props = Omit<
23
+ HTMLAttributes<HTMLDivElement>,
24
+ "class" | "onchange" | "aria-label" | "aria-labelledby"
25
+ > & {
26
+ /** Extra classes for the host element. */
27
+ class?: string;
28
+ /** Stars given, or `null` for no rating; supports `bind:value`. */
29
+ value?: number | null;
30
+ /** Number of stars. */
31
+ max?: number;
32
+ /** Names the rating ("Quiz"). Shown above the stars unless `hideLabel`. */
33
+ label?: string;
34
+ /** Keeps `label` as the accessible name only. */
35
+ hideLabel?: boolean;
36
+ /** Names the rating when there is no `label`. */
37
+ "aria-label"?: string;
38
+ /** Id of the element that names the rating, when there is no `label`. */
39
+ "aria-labelledby"?: string;
40
+ /** Size of a star. An interactive star is a 44px target at every size. */
41
+ size?: SizeVariant;
42
+ /**
43
+ * Colour of a filled star: the primary action colour, or the app's
44
+ * accent (`--color-accent`). An app can also set the colours itself:
45
+ * `--zabi-rating-on` and `--zabi-rating-off`, see THEMING.md.
46
+ */
47
+ tone?: "primary" | "accent";
48
+ /**
49
+ * Shows a score instead of asking for one: one image with one name,
50
+ * and a star can be partly filled (3.5 fills half of the fourth).
51
+ */
52
+ readonly?: boolean;
53
+ /**
54
+ * Adds a clear button beside the stars, and Delete or Backspace clears
55
+ * too. Pressing the selected star again never clears.
56
+ */
57
+ clearable?: boolean;
58
+ disabled?: boolean;
59
+ /**
60
+ * Name the value is submitted under in a form. Nothing is submitted
61
+ * without a rating. Without a name the rating is not part of the form
62
+ * around it: it submits nothing and a form reset leaves it alone.
63
+ */
64
+ name?: string;
65
+ /** Shows the number beside the stars. On by default when `readonly`. */
66
+ showValue?: boolean;
67
+ /** Turns the value into text for a locale ("3,5"). At most one decimal by default. */
68
+ formatValue?: (value: number) => string;
69
+ /** Overrides for the built-in strings. */
70
+ strings?: Partial<RatingStrings>;
71
+ /** Called when the user changes the rating; `null` when it was cleared. */
72
+ onchange?: (value: number | null) => void;
73
+ };
74
+
75
+ let {
76
+ class: className = "",
77
+ value = $bindable<Exclude<Props["value"], undefined>>(),
78
+ max = 5,
79
+ label = "",
80
+ hideLabel = false,
81
+ "aria-label": ariaLabel,
82
+ "aria-labelledby": ariaLabelledby,
83
+ size = "md",
84
+ tone = "primary",
85
+ readonly = false,
86
+ clearable = false,
87
+ disabled = false,
88
+ name = "",
89
+ showValue,
90
+ formatValue,
91
+ strings,
92
+ onchange,
93
+ ...restProps
94
+ }: Props = $props();
95
+
96
+ // No fallback on a bindable prop: Svelte refuses `bind:…={undefined}` on
97
+ // one that has a fallback (`props_invalid_value`), and a page that throws
98
+ // while it hydrates never becomes interactive. The default is applied
99
+ // here instead: at once, for the server and the first render, and again
100
+ // whenever a parent hands back `undefined`.
101
+ const applyDefaults = () => {
102
+ if (value === undefined) value = null;
103
+ };
104
+ applyDefaults();
105
+ $effect.pre(applyDefaults);
106
+
107
+ const baseId = generateId("rating");
108
+ const labelId = `${baseId}-label`;
109
+ const valueId = `${baseId}-value`;
110
+ /**
111
+ * The radios always share a name, the caller's or one made here: without
112
+ * one they are not a group to the browser, and before the page hydrates a
113
+ * second choice would leave the first one checked beside it.
114
+ *
115
+ * With a name made here they are also kept out of any form around them
116
+ * (`form` names a form that does not exist), so nothing is submitted
117
+ * that the caller did not name, as before.
118
+ */
119
+ const groupName = $derived(name || `${baseId}-group`);
120
+
121
+ /** The app-wide words for this component, from a `ZabiStringsProvider` above it, if there is one. */
122
+ const provided = zabiStringsFor("rating");
123
+ const text = $derived(mergeStrings(RATING_STRINGS, provided(), strings));
124
+ const count = $derived(starCount(max));
125
+ const stars = $derived(Array.from({ length: count }, (_, index) => index + 1));
126
+ /** What the stars show: the value held within 0..max. */
127
+ const shown = $derived(clampRating(value, count));
128
+ const valueShown = $derived(showValue ?? readonly);
129
+ const labelVisible = $derived(!!label && !hideLabel);
130
+
131
+ function format(current: number): string {
132
+ return formatValue ? formatValue(current) : defaultRatingFormat(current);
133
+ }
134
+
135
+ const valueText = $derived(shown === null ? "" : format(shown));
136
+ /** "3.5 of 5 stars", or "No rating". */
137
+ const valueLabel = $derived(
138
+ shown === null ? text.noRating : text.starLabel(valueText, count),
139
+ );
140
+
141
+ /** The star that takes Tab: the selected one, or the first when none is. */
142
+ const tabStop = $derived(value !== null && stars.includes(value) ? value : 1);
143
+
144
+ const inputs: (HTMLInputElement | undefined)[] = $state([]);
145
+
146
+ function select(next: number | null) {
147
+ if (disabled || next === value) return;
148
+ value = next;
149
+ onchange?.(next);
150
+ }
151
+
152
+ /**
153
+ * The radios are bound, so a star picked before the page hydrated is kept:
154
+ * Svelte's binding hands it over here instead of overwriting it (see
155
+ * util/hydration.ts), and it goes through `select` like any other choice,
156
+ * `onchange` included. A form reset empties the rating, as it empties
157
+ * a bound native input.
158
+ */
159
+ const chosen = groupBinding<number>(
160
+ () => value,
161
+ (star) => select(star),
162
+ () => {
163
+ if (!disabled) value = resetValueOf<number>(inputs) ?? null;
164
+ },
165
+ );
166
+
167
+ /** The clear button hides once there is nothing to clear, so focus goes back to the stars. */
168
+ function clear() {
169
+ if (disabled || value === null) return;
170
+ select(null);
171
+ inputs[0]?.focus();
172
+ }
173
+
174
+ /** `focused` is the index of the star the key was pressed on, which need not be the selected one. */
175
+ function handleKeydown(event: KeyboardEvent, focused: number) {
176
+ if (disabled) return;
177
+ if (event.key === "Delete" || event.key === "Backspace") {
178
+ if (!clearable) return;
179
+ event.preventDefault();
180
+ clear();
181
+ return;
182
+ }
183
+ const next = radioKeyIndex(
184
+ event.key,
185
+ focused,
186
+ count,
187
+ isRtl(event.currentTarget as Element),
188
+ value !== null && stars.includes(value),
189
+ );
190
+ if (next === -1) return;
191
+ event.preventDefault();
192
+ select(stars[next]);
193
+ inputs[next]?.focus();
194
+ }
195
+ </script>
196
+
197
+ {#snippet glyph(fill: number | undefined)}
198
+ <span class="rating-glyph" style:--zabi-rating-fill={fill} aria-hidden="true">
199
+ <Star class="rating-glyph-empty" />
200
+ <span class="rating-glyph-fill"><Star fill="currentColor" /></span>
201
+ </span>
202
+ {/snippet}
203
+
204
+ {#snippet valueOutput()}
205
+ <span
206
+ class={cn(
207
+ "shrink-0 text-sm tabular-nums",
208
+ shown === null ? "text-description" : "font-medium text-body",
209
+ )}
210
+ data-rating-value
211
+ aria-hidden={readonly ? undefined : "true"}
212
+ >
213
+ {shown === null ? (readonly ? text.noRating : "") : valueText}
214
+ </span>
215
+ {/snippet}
216
+
217
+ {#if readonly}
218
+ <!-- One image with one name. Its children, the visible label and number
219
+ included, are presentational, so nothing is read twice. -->
220
+ <div
221
+ class={cn("rating", className)}
222
+ data-size={size}
223
+ data-tone={tone}
224
+ data-readonly
225
+ role="img"
226
+ aria-label={ariaLabelledby
227
+ ? undefined
228
+ : [label || ariaLabel, valueLabel].filter(Boolean).join(", ")}
229
+ aria-labelledby={ariaLabelledby ? `${ariaLabelledby} ${valueId}` : undefined}
230
+ {...restProps}
231
+ >
232
+ {#if labelVisible}
233
+ <span class="mb-1 block text-sm font-medium text-label">{label}</span>
234
+ {/if}
235
+ <span class="flex flex-wrap items-center gap-2">
236
+ <span class="rating-stars">
237
+ {#each stars as star (star)}
238
+ {@render glyph(starFill(shown, star))}
239
+ {/each}
240
+ </span>
241
+ {#if valueShown}
242
+ {@render valueOutput()}
243
+ {/if}
244
+ </span>
245
+ {#if ariaLabelledby}
246
+ <span id={valueId} class="sr-only">{valueLabel}</span>
247
+ {/if}
248
+ </div>
249
+ {:else}
250
+ <div
251
+ class={cn("rating", disabled && "opacity-50", className)}
252
+ data-size={size}
253
+ data-tone={tone}
254
+ {...restProps}
255
+ >
256
+ {#if labelVisible}
257
+ <span id={labelId} class="mb-1 block text-sm font-medium text-label">{label}</span>
258
+ {/if}
259
+ <div class="flex flex-wrap items-center gap-2">
260
+ <!-- Native radio inputs: one Tab stop, Space selects, a press on
261
+ the selected one changes nothing, and the value goes with a form. -->
262
+ <div
263
+ class="rating-stars"
264
+ role="radiogroup"
265
+ aria-labelledby={labelVisible ? labelId : label ? undefined : ariaLabelledby}
266
+ aria-label={labelVisible ? undefined : label || ariaLabel}
267
+ aria-disabled={disabled ? "true" : undefined}
268
+ >
269
+ {#each stars as star, index (star)}
270
+ <label class="rating-star" data-on={shown !== null && star <= shown ? "" : undefined}>
271
+ <input
272
+ bind:this={inputs[index]}
273
+ type="radio"
274
+ class="sr-only"
275
+ name={groupName}
276
+ form={name ? undefined : groupName}
277
+ value={star}
278
+ bind:group={chosen.value}
279
+ {disabled}
280
+ tabindex={star === tabStop ? 0 : -1}
281
+ aria-label={text.starLabel(format(star), count)}
282
+ onkeydown={(event) => handleKeydown(event, index)}
283
+ />
284
+ {@render glyph(undefined)}
285
+ </label>
286
+ {/each}
287
+ </div>
288
+ {#if clearable}
289
+ <!-- No `disabled:opacity-50`: the host dims a disabled rating
290
+ once, and the button is invisible while there is nothing to clear. -->
291
+ <button
292
+ type="button"
293
+ class={cn(
294
+ "focus-ring focus-ring--muted flex size-11 shrink-0 cursor-pointer items-center justify-center rounded-control text-description transition-colors duration-150 hover:bg-surface-hover hover:text-body active:bg-surface-active motion-reduce:transition-none disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-description",
295
+ value === null && "invisible",
296
+ )}
297
+ aria-label={text.clearLabel}
298
+ title={text.clearLabel}
299
+ disabled={disabled || value === null}
300
+ onclick={clear}
301
+ data-rating-clear
302
+ >
303
+ <X class="size-4" aria-hidden="true" />
304
+ </button>
305
+ {/if}
306
+ {#if valueShown}
307
+ {@render valueOutput()}
308
+ {/if}
309
+ </div>
310
+ </div>
311
+ {/if}
312
+
313
+ <style>
314
+ /*
315
+ * A star is two glyphs: an outline, and a filled one on top that is cut
316
+ * off at `--zabi-rating-fill` of its width. So a star can be half filled,
317
+ * and filled differs from empty by shape as well as by colour.
318
+ */
319
+ .rating {
320
+ --zabi-rating-star: 1.5rem;
321
+ /* A finger is the same size whatever the text size is, so the target
322
+ is in px; it only grows to keep room around a star enlarged by zoom. */
323
+ --zabi-rating-target: max(44px, var(--zabi-rating-star) + 8px);
324
+ /*
325
+ * The star colours an app may set, on the component or on anything
326
+ * around it (they inherit):
327
+ * --zabi-rating-on a filled star
328
+ * --zabi-rating-on-hover the same under the pointer; default: --zabi-rating-on
329
+ * --zabi-rating-on-active the same while pressed; default: --zabi-rating-on
330
+ * --zabi-rating-on-edge the outline of a filled star; default: its fill
331
+ * --zabi-rating-off the outline of an empty star
332
+ * They are read with a fallback and never declared here. Declared on
333
+ * `.rating`, they could only be overridden by an inline style: this
334
+ * rule would beat any class or ancestor an app set them on.
335
+ * The defaults below are the component's own and are not for apps.
336
+ */
337
+ --_rating-on: var(--color-action-primary);
338
+ --_rating-on-hover: var(--color-action-primary-hover);
339
+ --_rating-on-active: var(--color-action-primary-active);
340
+ --_rating-on-edge: currentColor;
341
+ /* The outline is all there is of an empty star, so it needs 3:1 against
342
+ what it sits on (WCAG 1.4.11). `--color-border-medium` is 2.2:1 on
343
+ the light page and 1.9:1 on a dark card, and `--color-border-strong`
344
+ 2.49:1 on the dark elevated surface; the control boundary is held to
345
+ 3:1 on every surface level of both themes. The fallback is for an
346
+ app whose own theme file predates the role. */
347
+ --_rating-off: var(--color-control-border, var(--color-border-strong));
348
+ }
349
+
350
+ /*
351
+ * The app's accent. An accent can be a light colour: a yellow fill is
352
+ * about 1.3:1 on a white card, and no star made of it alone can be seen
353
+ * there. So the filled star is outlined in the accent's text step, which
354
+ * is held to 4.5:1 on the page and a card and 3:1 on the inset surface in
355
+ * both themes. The outline carries the shape whatever the accent is; the
356
+ * fill carries the colour.
357
+ */
358
+ .rating[data-tone="accent"] {
359
+ --_rating-on: var(--color-accent);
360
+ --_rating-on-hover: var(--color-accent-hover);
361
+ --_rating-on-active: var(--color-accent-active);
362
+ --_rating-on-edge: var(--color-accent-text);
363
+ }
364
+
365
+ .rating[data-size="sm"] {
366
+ --zabi-rating-star: 1.25rem;
367
+ }
368
+
369
+ .rating[data-size="lg"] {
370
+ --zabi-rating-star: 2rem;
371
+ --zabi-rating-target: max(48px, var(--zabi-rating-star) + 8px);
372
+ }
373
+
374
+ .rating-stars {
375
+ display: inline-flex;
376
+ flex-wrap: wrap;
377
+ /* The 44px target reaches past the first glyph; pulled back so the
378
+ glyph lines up with the label above. Only at the start: overflow
379
+ there cannot make the page scroll sideways, at the end it could. */
380
+ --zabi-rating-inset: calc((var(--zabi-rating-target) - var(--zabi-rating-star)) / 2);
381
+ margin-inline-start: calc(var(--zabi-rating-inset) * -1);
382
+ max-width: calc(100% + var(--zabi-rating-inset));
383
+ }
384
+
385
+ .rating[data-readonly] .rating-stars {
386
+ gap: 0.125rem;
387
+ margin-inline-start: 0;
388
+ max-width: 100%;
389
+ }
390
+
391
+ .rating-star {
392
+ position: relative;
393
+ display: inline-flex;
394
+ align-items: center;
395
+ justify-content: center;
396
+ width: var(--zabi-rating-target);
397
+ height: var(--zabi-rating-target);
398
+ border-radius: var(--radius-control);
399
+ cursor: pointer;
400
+ -webkit-tap-highlight-color: transparent;
401
+ }
402
+
403
+ .rating-star[data-on] {
404
+ --zabi-rating-fill: 1;
405
+ }
406
+
407
+ .rating-glyph {
408
+ position: relative;
409
+ display: block;
410
+ flex: none;
411
+ width: var(--zabi-rating-star);
412
+ height: var(--zabi-rating-star);
413
+ transition: transform 150ms;
414
+ }
415
+
416
+ .rating-glyph :global(svg) {
417
+ display: block;
418
+ width: var(--zabi-rating-star);
419
+ height: var(--zabi-rating-star);
420
+ max-width: none;
421
+ }
422
+
423
+ .rating-glyph :global(.rating-glyph-empty) {
424
+ color: var(--zabi-rating-off, var(--_rating-off));
425
+ }
426
+
427
+ /* Anchored at the start, so the filled part is on the right in a right-to-left layout. */
428
+ .rating-glyph-fill {
429
+ position: absolute;
430
+ inset-block: 0;
431
+ inset-inline-start: 0;
432
+ width: calc(var(--zabi-rating-fill, 0) * 100%);
433
+ overflow: hidden;
434
+ color: var(--_rating-on-now, var(--zabi-rating-on, var(--_rating-on)));
435
+ }
436
+
437
+ .rating-glyph-fill :global(svg) {
438
+ stroke: var(--zabi-rating-on-edge, var(--_rating-on-edge));
439
+ }
440
+
441
+ /* A preview of the rating a click would give, where a pointer can hover. */
442
+ @media (hover: hover) {
443
+ .rating-stars:not([aria-disabled="true"]):hover .rating-star {
444
+ --zabi-rating-fill: 1;
445
+ /* An app that set only --zabi-rating-on keeps that colour here. */
446
+ --_rating-on-now: var(--zabi-rating-on-hover, var(--zabi-rating-on, var(--_rating-on-hover)));
447
+ }
448
+
449
+ .rating-stars:not([aria-disabled="true"]) .rating-star:hover ~ .rating-star {
450
+ --zabi-rating-fill: 0;
451
+ }
452
+ }
453
+
454
+ /* Pressed, on every pointer: the star under the finger fills and dips. */
455
+ .rating-stars:not([aria-disabled="true"]) .rating-star:active {
456
+ --zabi-rating-fill: 1;
457
+ --_rating-on-now: var(--zabi-rating-on-active, var(--zabi-rating-on, var(--_rating-on-active)));
458
+ }
459
+
460
+ .rating-stars:not([aria-disabled="true"]) .rating-star:active .rating-glyph {
461
+ transform: scale(0.85);
462
+ }
463
+
464
+ /* Same geometry as `.focus-ring`: a 2px gap, then a 2px ring. */
465
+ .rating-star:has(:focus-visible) {
466
+ z-index: 1;
467
+ box-shadow:
468
+ 0 0 0 2px var(--color-focus-ring-offset),
469
+ 0 0 0 4px var(--color-focus-ring);
470
+ }
471
+
472
+ .rating-stars[aria-disabled="true"] .rating-star {
473
+ cursor: not-allowed;
474
+ }
475
+
476
+ /* Forced colours drop every box-shadow; an outline is kept. As `.focus-ring` does in app.css. */
477
+ @media (forced-colors: active) {
478
+ .rating-star:has(:focus-visible) {
479
+ outline: 2px solid Highlight;
480
+ outline-offset: 2px;
481
+ }
482
+
483
+ /* An svg keeps its author colour in forced colours; the outline takes the text colour as the fill does. */
484
+ .rating-glyph :global(.rating-glyph-empty) {
485
+ color: CanvasText;
486
+ }
487
+ }
488
+
489
+ @media (prefers-reduced-motion: reduce) {
490
+ .rating-glyph {
491
+ transition: none;
492
+ }
493
+ }
494
+ </style>
@@ -0,0 +1,56 @@
1
+ import type { HTMLAttributes } from "svelte/elements";
2
+ import type { SizeVariant } from "../types/variants.js";
3
+ import { type RatingStrings } from "../util/rating.js";
4
+ /** Other attributes (`data-*`, `id`, ...) land on the host element. */
5
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, "class" | "onchange" | "aria-label" | "aria-labelledby"> & {
6
+ /** Extra classes for the host element. */
7
+ class?: string;
8
+ /** Stars given, or `null` for no rating; supports `bind:value`. */
9
+ value?: number | null;
10
+ /** Number of stars. */
11
+ max?: number;
12
+ /** Names the rating ("Quiz"). Shown above the stars unless `hideLabel`. */
13
+ label?: string;
14
+ /** Keeps `label` as the accessible name only. */
15
+ hideLabel?: boolean;
16
+ /** Names the rating when there is no `label`. */
17
+ "aria-label"?: string;
18
+ /** Id of the element that names the rating, when there is no `label`. */
19
+ "aria-labelledby"?: string;
20
+ /** Size of a star. An interactive star is a 44px target at every size. */
21
+ size?: SizeVariant;
22
+ /**
23
+ * Colour of a filled star: the primary action colour, or the app's
24
+ * accent (`--color-accent`). An app can also set the colours itself:
25
+ * `--zabi-rating-on` and `--zabi-rating-off`, see THEMING.md.
26
+ */
27
+ tone?: "primary" | "accent";
28
+ /**
29
+ * Shows a score instead of asking for one: one image with one name,
30
+ * and a star can be partly filled (3.5 fills half of the fourth).
31
+ */
32
+ readonly?: boolean;
33
+ /**
34
+ * Adds a clear button beside the stars, and Delete or Backspace clears
35
+ * too. Pressing the selected star again never clears.
36
+ */
37
+ clearable?: boolean;
38
+ disabled?: boolean;
39
+ /**
40
+ * Name the value is submitted under in a form. Nothing is submitted
41
+ * without a rating. Without a name the rating is not part of the form
42
+ * around it: it submits nothing and a form reset leaves it alone.
43
+ */
44
+ name?: string;
45
+ /** Shows the number beside the stars. On by default when `readonly`. */
46
+ showValue?: boolean;
47
+ /** Turns the value into text for a locale ("3,5"). At most one decimal by default. */
48
+ formatValue?: (value: number) => string;
49
+ /** Overrides for the built-in strings. */
50
+ strings?: Partial<RatingStrings>;
51
+ /** Called when the user changes the rating; `null` when it was cleared. */
52
+ onchange?: (value: number | null) => void;
53
+ };
54
+ declare const Rating: import("svelte").Component<Props, {}, "value">;
55
+ type Rating = ReturnType<typeof Rating>;
56
+ export default Rating;