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