zabi-components 7.0.2 → 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.
- package/CHANGELOG.md +1924 -0
- package/README.md +287 -11
- package/THEME.md +149 -332
- package/THEMING.md +1329 -163
- package/dist/atoms/ActionPanel.svelte +24 -9
- package/dist/atoms/ActionPanel.svelte.d.ts +2 -0
- package/dist/atoms/Avatar.svelte +104 -0
- package/dist/atoms/Avatar.svelte.d.ts +34 -0
- package/dist/atoms/Badge.svelte +124 -58
- package/dist/atoms/Badge.svelte.d.ts +17 -5
- package/dist/atoms/Button.svelte +212 -62
- package/dist/atoms/Button.svelte.d.ts +33 -2
- package/dist/atoms/Card.svelte +31 -28
- package/dist/atoms/Card.svelte.d.ts +5 -2
- package/dist/atoms/CardContent.svelte +10 -2
- package/dist/atoms/CardContent.svelte.d.ts +2 -0
- package/dist/atoms/CardFooter.svelte +10 -2
- package/dist/atoms/CardFooter.svelte.d.ts +2 -0
- package/dist/atoms/CardHeader.svelte +26 -6
- package/dist/atoms/CardHeader.svelte.d.ts +2 -0
- package/dist/atoms/Checkbox.svelte +52 -21
- package/dist/atoms/Checkbox.svelte.d.ts +6 -2
- package/dist/atoms/CodeBlock.svelte +35 -9
- package/dist/atoms/CodeBlock.svelte.d.ts +13 -3
- package/dist/atoms/ColorPicker.svelte +272 -52
- package/dist/atoms/ColorPicker.svelte.d.ts +6 -1
- package/dist/atoms/Container.svelte +17 -10
- package/dist/atoms/DateField.svelte +107 -0
- package/dist/atoms/DateField.svelte.d.ts +53 -0
- package/dist/atoms/Divider.svelte +4 -4
- package/dist/atoms/FeatureCard.svelte +4 -3
- package/dist/atoms/FieldMessages.svelte +69 -0
- package/dist/atoms/FieldMessages.svelte.d.ts +23 -0
- package/dist/atoms/FloatingActionButton.svelte +174 -0
- package/dist/atoms/FloatingActionButton.svelte.d.ts +51 -0
- package/dist/atoms/Heading.svelte +93 -32
- package/dist/atoms/Heading.svelte.d.ts +24 -4
- package/dist/atoms/IconButton.svelte +242 -53
- package/dist/atoms/IconButton.svelte.d.ts +49 -4
- package/dist/atoms/Input.svelte +267 -74
- package/dist/atoms/Input.svelte.d.ts +32 -2
- package/dist/atoms/List.svelte +13 -2
- package/dist/atoms/List.svelte.d.ts +2 -0
- package/dist/atoms/ListItem.svelte +44 -11
- package/dist/atoms/ListItem.svelte.d.ts +5 -0
- package/dist/atoms/ListItemLeading.svelte +4 -2
- package/dist/atoms/ListItemLeading.svelte.d.ts +1 -1
- package/dist/atoms/OptimizedImage.svelte +11 -2
- package/dist/atoms/OptimizedImage.svelte.d.ts +2 -0
- package/dist/atoms/Progress.svelte +31 -9
- package/dist/atoms/Progress.svelte.d.ts +6 -0
- package/dist/atoms/Radio.svelte +23 -3
- package/dist/atoms/Radio.svelte.d.ts +6 -2
- package/dist/atoms/Rating.svelte +494 -0
- package/dist/atoms/Rating.svelte.d.ts +56 -0
- package/dist/atoms/Select.svelte +475 -135
- package/dist/atoms/Select.svelte.d.ts +52 -2
- package/dist/atoms/SelectionControl.svelte +99 -18
- package/dist/atoms/SelectionControl.svelte.d.ts +6 -3
- package/dist/atoms/Skeleton.svelte +5 -3
- package/dist/atoms/Slider.svelte +309 -0
- package/dist/atoms/Slider.svelte.d.ts +40 -0
- package/dist/atoms/Spinner.svelte +57 -0
- package/dist/atoms/Spinner.svelte.d.ts +19 -0
- package/dist/atoms/Table.svelte +152 -6
- package/dist/atoms/Table.svelte.d.ts +15 -3
- package/dist/atoms/TemporalField.svelte +140 -0
- package/dist/atoms/TemporalField.svelte.d.ts +32 -0
- package/dist/atoms/Text.svelte +56 -15
- package/dist/atoms/Text.svelte.d.ts +13 -4
- package/dist/atoms/Textarea.svelte +57 -45
- package/dist/atoms/Textarea.svelte.d.ts +14 -2
- package/dist/atoms/ThemeToggle.svelte +238 -56
- package/dist/atoms/ThemeToggle.svelte.d.ts +28 -3
- package/dist/atoms/TimeField.svelte +108 -0
- package/dist/atoms/TimeField.svelte.d.ts +54 -0
- package/dist/atoms/Toast.svelte +25 -10
- package/dist/atoms/Toast.svelte.d.ts +2 -0
- package/dist/atoms/Toggle.svelte +60 -19
- package/dist/atoms/Toggle.svelte.d.ts +18 -2
- package/dist/atoms/Tooltip.svelte +583 -40
- package/dist/atoms/Tooltip.svelte.d.ts +26 -0
- package/dist/atoms/ZabiStringsProvider.svelte +45 -0
- package/dist/atoms/ZabiStringsProvider.svelte.d.ts +27 -0
- package/dist/atoms/index.d.ts +17 -0
- package/dist/atoms/index.js +12 -0
- package/dist/atoms/selection-control.styles.d.ts +36 -5
- package/dist/atoms/selection-control.styles.js +40 -9
- package/dist/components/atoms/index.d.ts +17 -0
- package/dist/components/atoms/index.d.ts.map +1 -1
- package/dist/components/atoms/selection-control.styles.d.ts +36 -5
- package/dist/components/atoms/selection-control.styles.d.ts.map +1 -1
- package/dist/components/index.d.ts +83 -3
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/molecules/index.d.ts +46 -0
- package/dist/components/molecules/index.d.ts.map +1 -1
- package/dist/components/molecules/toast-store.d.ts +53 -7
- package/dist/components/molecules/toast-store.d.ts.map +1 -1
- package/dist/components/organisms/index.d.ts +6 -0
- package/dist/components/organisms/index.d.ts.map +1 -1
- package/dist/components/types/variants.d.ts +15 -1
- package/dist/components/types/variants.d.ts.map +1 -1
- package/dist/components/util/app-shell.d.ts +28 -0
- package/dist/components/util/app-shell.d.ts.map +1 -0
- package/dist/components/util/avatar.d.ts +36 -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 +35 -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/cn.d.ts +8 -0
- package/dist/components/util/cn.d.ts.map +1 -0
- package/dist/components/util/collapsible.d.ts +58 -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/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.d.ts +39 -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 +75 -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/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 +215 -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/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-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 +60 -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/sortable-list.d.ts +65 -0
- package/dist/components/util/sortable-list.d.ts.map +1 -0
- package/dist/components/util/ssr-safe.d.ts +4 -4
- package/dist/components/util/ssr-safe.d.ts.map +1 -1
- 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/theme-mode.d.ts +80 -0
- package/dist/components/util/theme-mode.d.ts.map +1 -0
- package/dist/components/util/toaster.d.ts +93 -0
- package/dist/components/util/toaster.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 +11 -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 +133 -0
- package/dist/components/util/zabi-strings.d.ts.map +1 -0
- package/dist/create-theme/cli.js +169 -0
- package/dist/create-theme/index.d.ts +176 -0
- package/dist/create-theme/index.js +817 -0
- package/dist/create-theme/lib/ramp-math.js +128 -0
- package/dist/create-theme/lib/resolve.js +141 -0
- package/dist/create-theme/theme-data.js +1116 -0
- package/dist/index.d.ts +83 -3
- package/dist/index.js +60 -8
- package/dist/molecules/Alert.svelte +73 -66
- package/dist/molecules/Alert.svelte.d.ts +9 -1
- package/dist/molecules/AppBar.svelte +415 -0
- package/dist/molecules/AppBar.svelte.d.ts +69 -0
- package/dist/molecules/AvatarGroup.svelte +116 -0
- package/dist/molecules/AvatarGroup.svelte.d.ts +40 -0
- package/dist/molecules/BottomSheet.svelte +540 -0
- package/dist/molecules/BottomSheet.svelte.d.ts +93 -0
- package/dist/molecules/BottomTabBar.svelte +297 -0
- package/dist/molecules/BottomTabBar.svelte.d.ts +64 -0
- package/dist/molecules/Calendar.svelte +597 -0
- package/dist/molecules/Calendar.svelte.d.ts +72 -0
- package/dist/molecules/Collapsible.svelte +243 -0
- package/dist/molecules/Collapsible.svelte.d.ts +44 -0
- package/dist/molecules/CollapsibleGroup.svelte +126 -0
- package/dist/molecules/CollapsibleGroup.svelte.d.ts +14 -0
- package/dist/molecules/ComponentDemo.svelte +25 -5
- package/dist/molecules/ComponentDemo.svelte.d.ts +5 -0
- package/dist/molecules/ConfirmDialog.svelte +253 -0
- package/dist/molecules/ConfirmDialog.svelte.d.ts +55 -0
- package/dist/molecules/ContactForm.svelte +46 -19
- package/dist/molecules/ContactForm.svelte.d.ts +10 -0
- package/dist/molecules/Drawer.svelte +394 -0
- package/dist/molecules/Drawer.svelte.d.ts +55 -0
- package/dist/molecules/Dropdown.svelte +540 -50
- package/dist/molecules/Dropdown.svelte.d.ts +49 -6
- package/dist/molecules/DropdownItem.svelte +122 -0
- package/dist/molecules/DropdownItem.svelte.d.ts +28 -0
- package/dist/molecules/EmptyState.svelte +56 -10
- package/dist/molecules/EmptyState.svelte.d.ts +8 -0
- package/dist/molecules/Form.svelte +25 -14
- package/dist/molecules/Form.svelte.d.ts +13 -5
- package/dist/molecules/FormField.svelte +11 -2
- package/dist/molecules/FormField.svelte.d.ts +2 -0
- package/dist/molecules/Header.svelte +13 -3
- package/dist/molecules/Header.svelte.d.ts +2 -0
- package/dist/molecules/ImageUpload.svelte +422 -70
- package/dist/molecules/ImageUpload.svelte.d.ts +61 -5
- package/dist/molecules/MediaGrid.svelte +527 -0
- package/dist/molecules/MediaGrid.svelte.d.ts +77 -0
- package/dist/molecules/Modal.svelte +340 -45
- package/dist/molecules/Modal.svelte.d.ts +59 -7
- package/dist/molecules/NavigationMenu.svelte +15 -3
- package/dist/molecules/NavigationMenu.svelte.d.ts +4 -0
- package/dist/molecules/NavigationMenuContent.svelte +91 -36
- package/dist/molecules/NavigationMenuContent.svelte.d.ts +2 -0
- package/dist/molecules/NavigationMenuItem.svelte +10 -3
- package/dist/molecules/NavigationMenuItem.svelte.d.ts +2 -0
- package/dist/molecules/NavigationMenuLink.svelte +10 -2
- package/dist/molecules/NavigationMenuLink.svelte.d.ts +2 -0
- package/dist/molecules/NavigationMenuList.svelte +19 -4
- package/dist/molecules/NavigationMenuList.svelte.d.ts +2 -0
- package/dist/molecules/NavigationMenuTrigger.svelte +16 -3
- package/dist/molecules/NavigationMenuTrigger.svelte.d.ts +2 -0
- package/dist/molecules/Page.svelte +38 -2
- package/dist/molecules/Page.svelte.d.ts +13 -0
- package/dist/molecules/PhotoGrid.svelte +433 -0
- package/dist/molecules/PhotoGrid.svelte.d.ts +62 -0
- package/dist/molecules/PhotoViewer.svelte +1116 -0
- package/dist/molecules/PhotoViewer.svelte.d.ts +56 -0
- package/dist/molecules/PropsTable.svelte +26 -11
- package/dist/molecules/PropsTable.svelte.d.ts +5 -0
- package/dist/molecules/PullToRefresh.svelte +263 -0
- package/dist/molecules/PullToRefresh.svelte.d.ts +52 -0
- package/dist/molecules/RadioGroup.svelte +57 -15
- package/dist/molecules/RadioGroup.svelte.d.ts +16 -3
- package/dist/molecules/Section.svelte +13 -5
- package/dist/molecules/Section.svelte.d.ts +3 -1
- package/dist/molecules/SegmentedControl.svelte +323 -0
- package/dist/molecules/SegmentedControl.svelte.d.ts +34 -0
- package/dist/molecules/SidebarBrandHeader.svelte +24 -5
- package/dist/molecules/SidebarBrandHeader.svelte.d.ts +5 -0
- package/dist/molecules/SidebarFooter.svelte +39 -8
- package/dist/molecules/SidebarFooter.svelte.d.ts +5 -0
- package/dist/molecules/SidebarNavSection.svelte +12 -4
- package/dist/molecules/SidebarNavSection.svelte.d.ts +2 -0
- package/dist/molecules/SlideUp.svelte +253 -30
- package/dist/molecules/SlideUp.svelte.d.ts +31 -4
- package/dist/molecules/SortableList.svelte +632 -0
- package/dist/molecules/SortableList.svelte.d.ts +69 -0
- package/dist/molecules/Stepper.svelte +548 -0
- package/dist/molecules/Stepper.svelte.d.ts +39 -0
- package/dist/molecules/StickyActionBar.svelte +191 -0
- package/dist/molecules/StickyActionBar.svelte.d.ts +65 -0
- package/dist/molecules/SwipeableListItem.svelte +334 -0
- package/dist/molecules/SwipeableListItem.svelte.d.ts +54 -0
- package/dist/molecules/Tabs.svelte +254 -24
- package/dist/molecules/Tabs.svelte.d.ts +15 -4
- package/dist/molecules/Toaster.svelte +352 -6
- package/dist/molecules/Toaster.svelte.d.ts +95 -2
- package/dist/molecules/ToasterToast.svelte +279 -62
- package/dist/molecules/ToasterToast.svelte.d.ts +11 -0
- package/dist/molecules/UnsavedChangesBar.svelte +212 -0
- package/dist/molecules/UnsavedChangesBar.svelte.d.ts +43 -0
- package/dist/molecules/index.d.ts +46 -0
- package/dist/molecules/index.js +27 -0
- package/dist/molecules/toast-store.d.ts +53 -7
- package/dist/molecules/toast-store.js +21 -0
- package/dist/organisms/AppShell.svelte +196 -0
- package/dist/organisms/AppShell.svelte.d.ts +61 -0
- package/dist/organisms/SidebarAccountPanel.svelte +111 -12
- package/dist/organisms/SidebarAccountPanel.svelte.d.ts +21 -0
- package/dist/organisms/SidebarNavigation.svelte +193 -69
- package/dist/organisms/SidebarNavigation.svelte.d.ts +31 -1
- package/dist/organisms/SidebarPanel.svelte +45 -16
- package/dist/organisms/SidebarPanel.svelte.d.ts +2 -0
- package/dist/organisms/SidebarShell.svelte +263 -0
- package/dist/organisms/SidebarShell.svelte.d.ts +106 -0
- package/dist/organisms/TopNavbar.svelte +329 -33
- package/dist/organisms/TopNavbar.svelte.d.ts +28 -0
- package/dist/organisms/index.d.ts +6 -0
- package/dist/organisms/index.js +4 -0
- package/dist/routes/lib/variant-utils.d.ts +26 -0
- package/dist/routes/lib/{variant-utils.ts → variant-utils.js} +15 -46
- package/dist/types/components.d.ts +4 -0
- package/dist/types/components.d.ts.map +1 -1
- package/dist/types/events.js +1 -0
- package/dist/types/index.d.ts +605 -25
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -0
- package/dist/types/variants.ts +17 -1
- package/dist/util/app-shell.d.ts +27 -0
- package/dist/util/app-shell.js +72 -0
- package/dist/util/avatar.d.ts +35 -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 +34 -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/cn.d.ts +7 -0
- package/dist/util/cn.js +48 -0
- package/dist/util/collapsible.d.ts +57 -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/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.d.ts +38 -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 +75 -2
- package/dist/util/focus-utils.js +182 -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/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 +214 -0
- package/dist/util/photo.js +206 -0
- package/dist/util/portal.d.ts +22 -0
- package/dist/util/portal.js +50 -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-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 +59 -0
- package/dist/util/sheet-drag.js +241 -0
- package/dist/util/sidebar.d.ts +62 -0
- package/dist/util/sidebar.js +38 -0
- package/dist/util/sortable-list.d.ts +64 -0
- package/dist/util/sortable-list.js +53 -0
- package/dist/util/ssr-safe.d.ts +4 -4
- 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/theme-mode.d.ts +79 -0
- package/dist/util/theme-mode.js +121 -0
- package/dist/util/toaster.d.ts +92 -0
- package/dist/util/toaster.js +75 -0
- package/dist/util/tooltip.d.ts +9 -0
- package/dist/util/tooltip.js +18 -0
- package/dist/util/top-navbar.d.ts +10 -0
- package/dist/util/top-navbar.js +5 -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 +132 -0
- package/dist/util/zabi-strings.js +105 -0
- package/dist/zabi-components-colors.css +5 -2
- package/dist/zabi-components-theme-dark-only.css +574 -225
- package/dist/zabi-components-theme-dark.css +574 -225
- package/dist/zabi-components-theme-only.css +1680 -317
- package/dist/zabi-components-theme.css +1680 -317
- package/dist/zabi-components.css +4473 -1158
- package/docs/lucide-icons.md +41 -16
- package/docs/theme-imports.md +81 -11
- package/package.json +51 -29
- package/dist/lib/layout-width-tokens.d.ts +0 -17
- package/dist/lib/layout-width-tokens.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Button.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Button.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Input.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Input.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/List.d.ts +0 -3
- package/dist/lib/showcase/component-docs/List.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Modal.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Modal.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Radio.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Radio.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts +0 -3
- package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Skeleton.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Skeleton.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/_shared.d.ts +0 -12
- package/dist/lib/showcase/component-docs/_shared.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/index.d.ts +0 -4
- package/dist/lib/showcase/component-docs/index.d.ts.map +0 -1
- package/dist/lib/showcase/components-catalog.d.ts +0 -3
- package/dist/lib/showcase/components-catalog.d.ts.map +0 -1
- package/dist/lib/showcase/components-showcase-constants.d.ts +0 -89
- package/dist/lib/showcase/components-showcase-constants.d.ts.map +0 -1
- package/dist/lib/showcase/docs-sidebar-helpers.d.ts +0 -15
- package/dist/lib/showcase/docs-sidebar-helpers.d.ts.map +0 -1
- package/dist/routes/lib/focus-utils.d.ts +0 -12
- package/dist/routes/lib/focus-utils.ts +0 -110
- package/dist/routes/lib/ssr-safe.ts +0 -58
- package/scripts/fix-lucide-svelte-icon-dts.js +0 -35
|
@@ -2,17 +2,20 @@
|
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import type { SizeVariant } from "../types/variants.js";
|
|
4
4
|
import Heading from "../atoms/Heading.svelte";
|
|
5
|
+
import { cn } from "../util/cn.js";
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
title?: string;
|
|
8
9
|
description?: string;
|
|
9
10
|
/** Title heading level (1–6). */
|
|
10
|
-
headingLevel?:
|
|
11
|
+
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
11
12
|
size?: SizeVariant;
|
|
12
13
|
maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full" | "none";
|
|
13
14
|
background?: "default" | "muted" | "accent" | "transparent";
|
|
14
15
|
padding?: "none" | "sm" | "md" | "lg" | "xl";
|
|
15
16
|
centered?: boolean;
|
|
17
|
+
class?: string;
|
|
18
|
+
/** @deprecated use `class`. */
|
|
16
19
|
className?: string;
|
|
17
20
|
children?: Snippet;
|
|
18
21
|
}
|
|
@@ -26,11 +29,16 @@
|
|
|
26
29
|
background = "default",
|
|
27
30
|
padding = "lg",
|
|
28
31
|
centered = false,
|
|
29
|
-
|
|
32
|
+
class: classAttr = "",
|
|
33
|
+
className: legacyClass = "",
|
|
30
34
|
children,
|
|
31
35
|
...restProps
|
|
32
36
|
}: Props = $props();
|
|
33
37
|
|
|
38
|
+
/** `class` is the public prop; `className` is a deprecated alias.
|
|
39
|
+
* Both are merged here so existing call sites keep working. */
|
|
40
|
+
const className = $derived(cn(`${classAttr} ${legacyClass}`));
|
|
41
|
+
|
|
34
42
|
const sizeClasses = $derived.by(() => {
|
|
35
43
|
switch (size) {
|
|
36
44
|
case "sm":
|
|
@@ -68,7 +76,7 @@
|
|
|
68
76
|
case "muted":
|
|
69
77
|
return "bg-base-50";
|
|
70
78
|
case "accent":
|
|
71
|
-
return "bg-brand-50
|
|
79
|
+
return "bg-brand-50";
|
|
72
80
|
case "transparent":
|
|
73
81
|
return "bg-transparent";
|
|
74
82
|
default:
|
|
@@ -97,13 +105,13 @@
|
|
|
97
105
|
const base = "w-full";
|
|
98
106
|
const maxWidthClass = maxWidthClasses;
|
|
99
107
|
const centeredClass = centered ? "mx-auto" : "";
|
|
100
|
-
return `${base} ${maxWidthClass} ${centeredClass}
|
|
108
|
+
return cn(`${base} ${maxWidthClass} ${centeredClass}`);
|
|
101
109
|
});
|
|
102
110
|
|
|
103
111
|
const contentClasses = $derived.by(() => {
|
|
104
112
|
const base = "px-4 sm:px-6 lg:px-8";
|
|
105
113
|
const centeredClass = centered ? "text-center" : "";
|
|
106
|
-
return `${base} ${centeredClass}
|
|
114
|
+
return cn(`${base} ${centeredClass}`);
|
|
107
115
|
});
|
|
108
116
|
</script>
|
|
109
117
|
|
|
@@ -4,12 +4,14 @@ interface Props {
|
|
|
4
4
|
title?: string;
|
|
5
5
|
description?: string;
|
|
6
6
|
/** Title heading level (1–6). */
|
|
7
|
-
headingLevel?:
|
|
7
|
+
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
8
8
|
size?: SizeVariant;
|
|
9
9
|
maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full" | "none";
|
|
10
10
|
background?: "default" | "muted" | "accent" | "transparent";
|
|
11
11
|
padding?: "none" | "sm" | "md" | "lg" | "xl";
|
|
12
12
|
centered?: boolean;
|
|
13
|
+
class?: string;
|
|
14
|
+
/** @deprecated use `class`. */
|
|
13
15
|
className?: string;
|
|
14
16
|
children?: Snippet;
|
|
15
17
|
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type { SizeVariant } from "../types/variants.js";
|
|
4
|
+
import { cn } from "../util/cn.js";
|
|
5
|
+
import { resetValueOf, groupBinding } from "../util/hydration.js";
|
|
6
|
+
import { isRtl, radioKeyIndex } from "../util/radio-keys.js";
|
|
7
|
+
import type { SegmentedControlOption } from "../util/segmented-control.js";
|
|
8
|
+
import { generateId } from "../util/ssr-safe.js";
|
|
9
|
+
|
|
10
|
+
/** Other attributes (`data-*`, `id`, ...) land on the host element. */
|
|
11
|
+
type Props = Omit<
|
|
12
|
+
HTMLAttributes<HTMLDivElement>,
|
|
13
|
+
"class" | "onchange" | "aria-label" | "aria-labelledby"
|
|
14
|
+
> & {
|
|
15
|
+
/** Extra classes for the host element. */
|
|
16
|
+
class?: string;
|
|
17
|
+
/** Two to four choices, shown in one row. */
|
|
18
|
+
options: SegmentedControlOption[];
|
|
19
|
+
/** Selected value; supports `bind:value`. `undefined` for no selection. */
|
|
20
|
+
value?: string | undefined;
|
|
21
|
+
/** Accessible name of the group. Not shown. */
|
|
22
|
+
label?: string;
|
|
23
|
+
/** Accessible name of the group, the same as `label`. */
|
|
24
|
+
"aria-label"?: string;
|
|
25
|
+
/** Id of a visible element that names the group, in place of `label`. */
|
|
26
|
+
"aria-labelledby"?: string;
|
|
27
|
+
/** Height, on the scale Input and Button use. At least 44px on a touch screen. */
|
|
28
|
+
size?: SizeVariant;
|
|
29
|
+
/** Equal-width segments that fill the row. Off: each segment is as wide as its label. */
|
|
30
|
+
fullWidth?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Name the value is submitted under in a form. Without a name the
|
|
33
|
+
* control is not part of the form around it: it submits nothing and a
|
|
34
|
+
* form reset leaves it alone.
|
|
35
|
+
*/
|
|
36
|
+
name?: string;
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
/** Called with the new value when the user picks another segment. */
|
|
39
|
+
onchange?: (value: string) => void;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
let {
|
|
43
|
+
class: className = "",
|
|
44
|
+
options,
|
|
45
|
+
value = $bindable(),
|
|
46
|
+
label = "",
|
|
47
|
+
"aria-label": ariaLabel,
|
|
48
|
+
"aria-labelledby": ariaLabelledby,
|
|
49
|
+
size = "md",
|
|
50
|
+
fullWidth = true,
|
|
51
|
+
name = "",
|
|
52
|
+
disabled = false,
|
|
53
|
+
onchange,
|
|
54
|
+
...restProps
|
|
55
|
+
}: Props = $props();
|
|
56
|
+
|
|
57
|
+
$effect(() => {
|
|
58
|
+
if (import.meta.env?.DEV && (options.length < 2 || options.length > 4)) {
|
|
59
|
+
console.warn(
|
|
60
|
+
`[zabi-components] SegmentedControl is made for 2 to 4 options and got ${options.length}. Use Tabs, RadioGroup or Select for more.`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The radios always share a name, the caller's or one made here: without
|
|
67
|
+
* one they are not a group to the browser, and before the page hydrates a
|
|
68
|
+
* second choice would leave the first one checked beside it.
|
|
69
|
+
*
|
|
70
|
+
* With a name made here they are also kept out of any form around them
|
|
71
|
+
* (`form` names a form that does not exist), so nothing is submitted
|
|
72
|
+
* that the caller did not name, as before.
|
|
73
|
+
*/
|
|
74
|
+
const fallbackName = generateId("segmented");
|
|
75
|
+
const groupName = $derived(name || fallbackName);
|
|
76
|
+
|
|
77
|
+
const enabled = $derived(
|
|
78
|
+
options.filter((option) => !disabled && !option.disabled),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
/** The segment that takes Tab: the selected one, or the first that can be chosen. */
|
|
82
|
+
const tabStop = $derived(
|
|
83
|
+
enabled.find((option) => option.value === value)?.value ?? enabled[0]?.value,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const inputs: Record<string, HTMLInputElement | undefined> = $state({});
|
|
87
|
+
|
|
88
|
+
/** A press on the selected segment is not a change: a single selection never clears. */
|
|
89
|
+
function select(next: string) {
|
|
90
|
+
if (disabled || next === value) return;
|
|
91
|
+
value = next;
|
|
92
|
+
onchange?.(next);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The radios are bound, so a segment picked before the page hydrated is
|
|
97
|
+
* kept: Svelte's binding hands it over here instead of overwriting it
|
|
98
|
+
* (see util/hydration.ts), and it goes through `select` like any other
|
|
99
|
+
* choice, `onchange` included. A form reset empties the selection, as it
|
|
100
|
+
* empties a bound native input.
|
|
101
|
+
*/
|
|
102
|
+
const chosen = groupBinding<string>(
|
|
103
|
+
() => value,
|
|
104
|
+
(next) => select(next),
|
|
105
|
+
() => {
|
|
106
|
+
if (!disabled) value = resetValueOf<string>(Object.values(inputs));
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
/** `focused` is the value of the segment the key was pressed on, which need not be the selected one. */
|
|
111
|
+
function handleKeydown(event: KeyboardEvent, focused: string) {
|
|
112
|
+
const next = radioKeyIndex(
|
|
113
|
+
event.key,
|
|
114
|
+
enabled.findIndex((option) => option.value === focused),
|
|
115
|
+
enabled.length,
|
|
116
|
+
isRtl(event.currentTarget as Element),
|
|
117
|
+
enabled.some((option) => option.value === value),
|
|
118
|
+
);
|
|
119
|
+
if (next === -1) return;
|
|
120
|
+
event.preventDefault();
|
|
121
|
+
select(enabled[next].value);
|
|
122
|
+
inputs[enabled[next].value]?.focus();
|
|
123
|
+
}
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<!-- Native radio inputs: one Tab stop, Space selects, a press on the selected
|
|
127
|
+
one changes nothing, and the value goes with a form. -->
|
|
128
|
+
<div
|
|
129
|
+
class={cn("segmented", fullWidth ? "w-full" : "", className)}
|
|
130
|
+
data-size={size}
|
|
131
|
+
data-full-width={fullWidth ? "" : undefined}
|
|
132
|
+
role="radiogroup"
|
|
133
|
+
aria-label={ariaLabelledby ? undefined : label || ariaLabel}
|
|
134
|
+
aria-labelledby={ariaLabelledby}
|
|
135
|
+
aria-disabled={disabled ? "true" : undefined}
|
|
136
|
+
{...restProps}
|
|
137
|
+
>
|
|
138
|
+
{#each options as option (option.value)}
|
|
139
|
+
{@const optionDisabled = disabled || !!option.disabled}
|
|
140
|
+
{@const Icon = option.icon}
|
|
141
|
+
<label class="segment">
|
|
142
|
+
<input
|
|
143
|
+
bind:this={inputs[option.value]}
|
|
144
|
+
type="radio"
|
|
145
|
+
class="sr-only"
|
|
146
|
+
name={groupName}
|
|
147
|
+
form={name ? undefined : groupName}
|
|
148
|
+
value={option.value}
|
|
149
|
+
bind:group={chosen.value}
|
|
150
|
+
disabled={optionDisabled}
|
|
151
|
+
tabindex={option.value === tabStop ? 0 : -1}
|
|
152
|
+
onkeydown={(event) => handleKeydown(event, option.value)}
|
|
153
|
+
/>
|
|
154
|
+
<span class="segment-face text-sm font-medium">
|
|
155
|
+
{#if Icon}
|
|
156
|
+
<span class="flex shrink-0" aria-hidden="true"><Icon size={16} /></span>
|
|
157
|
+
{/if}
|
|
158
|
+
<span class="segment-label">{option.label}</span>
|
|
159
|
+
</span>
|
|
160
|
+
</label>
|
|
161
|
+
{/each}
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<style>
|
|
165
|
+
/*
|
|
166
|
+
* The states hang off the radio input (`:checked`, `:disabled`,
|
|
167
|
+
* `:focus-visible`), which utilities on the face could only reach through
|
|
168
|
+
* a `peer-*` variant per declaration.
|
|
169
|
+
*
|
|
170
|
+
* Columns are as many as fit at 3.5rem each, so two to four segments share
|
|
171
|
+
* one row down to a 320px screen, and fold into rows instead of squeezing
|
|
172
|
+
* the labels when the text is zoomed or the container is narrower still.
|
|
173
|
+
*/
|
|
174
|
+
.segmented {
|
|
175
|
+
--zabi-segment-height: 2.125rem;
|
|
176
|
+
/* In px: side padding that grew with zoomed text would take the room the text needs. */
|
|
177
|
+
--zabi-segment-pad: 12px;
|
|
178
|
+
display: grid;
|
|
179
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, 3.5rem), 1fr));
|
|
180
|
+
/* One value for the padding and the gap, and for the segments' corner radius below. */
|
|
181
|
+
--zabi-segment-inset: 0.125rem;
|
|
182
|
+
gap: var(--zabi-segment-inset);
|
|
183
|
+
padding: var(--zabi-segment-inset);
|
|
184
|
+
border: 1px solid var(--color-border);
|
|
185
|
+
border-radius: var(--radius-control);
|
|
186
|
+
background: var(--color-action-secondary);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.segmented:not([data-full-width]) {
|
|
190
|
+
display: inline-flex;
|
|
191
|
+
flex-wrap: wrap;
|
|
192
|
+
max-width: 100%;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.segmented[data-size="sm"] {
|
|
196
|
+
--zabi-segment-height: 1.625rem;
|
|
197
|
+
--zabi-segment-pad: 8px;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.segmented[data-size="lg"] {
|
|
201
|
+
--zabi-segment-height: 2.625rem;
|
|
202
|
+
--zabi-segment-pad: 16px;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* A finger needs 44px whatever the size says. */
|
|
206
|
+
@media (pointer: coarse) {
|
|
207
|
+
.segmented,
|
|
208
|
+
.segmented[data-size] {
|
|
209
|
+
--zabi-segment-height: 2.75rem;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.segment {
|
|
214
|
+
position: relative;
|
|
215
|
+
display: flex;
|
|
216
|
+
min-width: 0;
|
|
217
|
+
cursor: pointer;
|
|
218
|
+
-webkit-tap-highlight-color: transparent;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.segmented:not([data-full-width]) .segment {
|
|
222
|
+
flex: 0 1 auto;
|
|
223
|
+
min-width: 3.5rem;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.segment-face {
|
|
227
|
+
display: flex;
|
|
228
|
+
flex: 1;
|
|
229
|
+
align-items: center;
|
|
230
|
+
justify-content: center;
|
|
231
|
+
/* An icon moves above its label before the label has to break. */
|
|
232
|
+
flex-wrap: wrap;
|
|
233
|
+
gap: 0.125rem 0.5rem;
|
|
234
|
+
min-width: 0;
|
|
235
|
+
min-height: var(--zabi-segment-height);
|
|
236
|
+
padding: 0.25rem var(--zabi-segment-pad);
|
|
237
|
+
/* Nested corners: the track's radius less what lies between its edge and
|
|
238
|
+
the segment, which is the track's padding and its 1px border. */
|
|
239
|
+
border-radius: calc(var(--radius-control) - var(--zabi-segment-inset) - 1px);
|
|
240
|
+
color: var(--color-body);
|
|
241
|
+
line-height: 1.25;
|
|
242
|
+
text-align: center;
|
|
243
|
+
transition:
|
|
244
|
+
background-color 150ms,
|
|
245
|
+
color 150ms;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* A long label wraps onto a second line, and breaks inside a word only when a word alone does not fit. */
|
|
249
|
+
.segment-label {
|
|
250
|
+
min-width: 0;
|
|
251
|
+
overflow-wrap: anywhere;
|
|
252
|
+
hyphens: auto;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* Only where a pointer can hover: after a tap, `:hover` stays on the segment until the next tap elsewhere. */
|
|
256
|
+
@media (hover: hover) {
|
|
257
|
+
.segment:hover input:enabled:not(:checked) + .segment-face {
|
|
258
|
+
background: var(--color-surface-hover);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.segment:active input:enabled:not(:checked) + .segment-face {
|
|
263
|
+
background: var(--color-surface-active);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
input:checked + .segment-face {
|
|
267
|
+
background: var(--color-action-primary);
|
|
268
|
+
color: var(--color-action-primary-text);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* Same geometry as `.focus-ring`: a 2px gap, then a 2px ring. */
|
|
272
|
+
input:focus-visible + .segment-face {
|
|
273
|
+
box-shadow:
|
|
274
|
+
0 0 0 2px var(--color-focus-ring-offset),
|
|
275
|
+
0 0 0 4px var(--color-focus-ring);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.segment:has(input:disabled) {
|
|
279
|
+
cursor: not-allowed;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
input:disabled + .segment-face {
|
|
283
|
+
opacity: 0.5;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/*
|
|
287
|
+
* Forced colours paint every background with the canvas colour and drop
|
|
288
|
+
* every box-shadow, which would leave the selected segment looking like
|
|
289
|
+
* the others and keyboard focus with no mark. The selection takes the
|
|
290
|
+
* system's own selection colours, and focus an outline, as `.focus-ring`
|
|
291
|
+
* gets in app.css.
|
|
292
|
+
*/
|
|
293
|
+
@media (forced-colors: active) {
|
|
294
|
+
input:checked + .segment-face {
|
|
295
|
+
forced-color-adjust: none;
|
|
296
|
+
background: Highlight;
|
|
297
|
+
color: HighlightText;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
input:disabled + .segment-face {
|
|
301
|
+
opacity: 1;
|
|
302
|
+
color: GrayText;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
input:checked:disabled + .segment-face {
|
|
306
|
+
background: GrayText;
|
|
307
|
+
color: Canvas;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/* The selected face opted out of forced colours above, so its shadow ring would come back beside the outline. */
|
|
311
|
+
input:focus-visible + .segment-face {
|
|
312
|
+
box-shadow: none;
|
|
313
|
+
outline: 2px solid Highlight;
|
|
314
|
+
outline-offset: 2px;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
@media (prefers-reduced-motion: reduce) {
|
|
319
|
+
.segment-face {
|
|
320
|
+
transition: none;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
2
|
+
import type { SizeVariant } from "../types/variants.js";
|
|
3
|
+
import type { SegmentedControlOption } from "../util/segmented-control.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
|
+
/** Two to four choices, shown in one row. */
|
|
9
|
+
options: SegmentedControlOption[];
|
|
10
|
+
/** Selected value; supports `bind:value`. `undefined` for no selection. */
|
|
11
|
+
value?: string | undefined;
|
|
12
|
+
/** Accessible name of the group. Not shown. */
|
|
13
|
+
label?: string;
|
|
14
|
+
/** Accessible name of the group, the same as `label`. */
|
|
15
|
+
"aria-label"?: string;
|
|
16
|
+
/** Id of a visible element that names the group, in place of `label`. */
|
|
17
|
+
"aria-labelledby"?: string;
|
|
18
|
+
/** Height, on the scale Input and Button use. At least 44px on a touch screen. */
|
|
19
|
+
size?: SizeVariant;
|
|
20
|
+
/** Equal-width segments that fill the row. Off: each segment is as wide as its label. */
|
|
21
|
+
fullWidth?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Name the value is submitted under in a form. Without a name the
|
|
24
|
+
* control is not part of the form around it: it submits nothing and a
|
|
25
|
+
* form reset leaves it alone.
|
|
26
|
+
*/
|
|
27
|
+
name?: string;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/** Called with the new value when the user picks another segment. */
|
|
30
|
+
onchange?: (value: string) => void;
|
|
31
|
+
};
|
|
32
|
+
declare const SegmentedControl: import("svelte").Component<Props, {}, "value">;
|
|
33
|
+
type SegmentedControl = ReturnType<typeof SegmentedControl>;
|
|
34
|
+
export default SegmentedControl;
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { zabiStringsFor } from "../util/zabi-strings.js";
|
|
3
|
+
import { cn } from "../util/cn.js";
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_SIDEBAR_BRAND_HEADER_STRINGS,
|
|
6
|
+
type SidebarBrandHeaderStrings,
|
|
7
|
+
} from "../util/sidebar.js";
|
|
8
|
+
|
|
2
9
|
interface Props {
|
|
3
10
|
collapsed?: boolean;
|
|
4
11
|
brandName?: string;
|
|
5
12
|
logoSrc?: string;
|
|
6
13
|
logoAlt?: string;
|
|
14
|
+
/** `brandAlt`: the logo's alt text when neither `logoAlt` nor `brandName` is given. */
|
|
15
|
+
strings?: Partial<SidebarBrandHeaderStrings>;
|
|
16
|
+
class?: string;
|
|
17
|
+
/** @deprecated use `class`. */
|
|
7
18
|
className?: string;
|
|
8
19
|
}
|
|
9
20
|
|
|
@@ -12,9 +23,17 @@
|
|
|
12
23
|
brandName = "",
|
|
13
24
|
logoSrc = "",
|
|
14
25
|
logoAlt = "",
|
|
15
|
-
|
|
26
|
+
strings,
|
|
27
|
+
class: classAttr = "",
|
|
28
|
+
className: legacyClass = "",
|
|
16
29
|
}: Props = $props();
|
|
17
30
|
|
|
31
|
+
const provided = zabiStringsFor("sidebarBrandHeader");
|
|
32
|
+
|
|
33
|
+
/** `class` is the public prop; `className` is a deprecated alias.
|
|
34
|
+
* Both are merged here so existing call sites keep working. */
|
|
35
|
+
const className = $derived(`${classAttr} ${legacyClass}`.trim());
|
|
36
|
+
|
|
18
37
|
const trimmedName = $derived(brandName.trim());
|
|
19
38
|
const monogram = $derived(
|
|
20
39
|
trimmedName
|
|
@@ -35,15 +54,15 @@
|
|
|
35
54
|
|
|
36
55
|
{#if showLogo || trimmedName}
|
|
37
56
|
<div
|
|
38
|
-
class={
|
|
57
|
+
class={cn("flex w-full min-w-0 items-center gap-3", className)}
|
|
39
58
|
>
|
|
40
59
|
{#if showLogo}
|
|
41
60
|
<span
|
|
42
|
-
class="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-
|
|
61
|
+
class="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-container bg-background ring-1 ring-border"
|
|
43
62
|
>
|
|
44
63
|
<img
|
|
45
64
|
src={logoSrc}
|
|
46
|
-
alt={logoAlt || trimmedName ||
|
|
65
|
+
alt={logoAlt || trimmedName || (strings?.brandAlt ?? provided()?.brandAlt ?? DEFAULT_SIDEBAR_BRAND_HEADER_STRINGS.brandAlt)}
|
|
47
66
|
class="size-full object-cover"
|
|
48
67
|
width="36"
|
|
49
68
|
height="36"
|
|
@@ -51,7 +70,7 @@
|
|
|
51
70
|
</span>
|
|
52
71
|
{:else if showMonogram}
|
|
53
72
|
<span
|
|
54
|
-
class="flex size-9 shrink-0 items-center justify-center rounded-
|
|
73
|
+
class="flex size-9 shrink-0 items-center justify-center rounded-container bg-action-primary-subtle text-xs font-bold text-headline ring-1 ring-border"
|
|
55
74
|
aria-hidden="true"
|
|
56
75
|
>
|
|
57
76
|
{monogram}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import { type SidebarBrandHeaderStrings } from "../util/sidebar.js";
|
|
1
2
|
interface Props {
|
|
2
3
|
collapsed?: boolean;
|
|
3
4
|
brandName?: string;
|
|
4
5
|
logoSrc?: string;
|
|
5
6
|
logoAlt?: string;
|
|
7
|
+
/** `brandAlt`: the logo's alt text when neither `logoAlt` nor `brandName` is given. */
|
|
8
|
+
strings?: Partial<SidebarBrandHeaderStrings>;
|
|
9
|
+
class?: string;
|
|
10
|
+
/** @deprecated use `class`. */
|
|
6
11
|
className?: string;
|
|
7
12
|
}
|
|
8
13
|
declare const SidebarBrandHeader: import("svelte").Component<Props, {}, "">;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { mergeStrings } from "../util/ready-made-strings.js";
|
|
3
|
+
import { zabiStringsFor } from "../util/zabi-strings.js";
|
|
2
4
|
import type { Snippet } from "svelte";
|
|
3
5
|
import { fixedSidebarFlyout } from "../util/fixed-sidebar-flyout.js";
|
|
6
|
+
import { cn } from "../util/cn.js";
|
|
7
|
+
import { DEFAULT_SIDEBAR_FOOTER_STRINGS, type SidebarFooterStrings } from "../util/sidebar.js";
|
|
4
8
|
|
|
5
9
|
interface Props {
|
|
6
10
|
collapsed?: boolean;
|
|
11
|
+
/** The footer's name and the profile button's, for another language. */
|
|
12
|
+
strings?: Partial<SidebarFooterStrings>;
|
|
7
13
|
showProfile?: boolean;
|
|
8
14
|
profileName?: string;
|
|
9
15
|
profileEmail?: string;
|
|
@@ -15,6 +21,8 @@
|
|
|
15
21
|
isLightMode?: boolean;
|
|
16
22
|
onLogout?: () => void;
|
|
17
23
|
onThemeToggle?: (nextIsLightMode: boolean) => void;
|
|
24
|
+
class?: string;
|
|
25
|
+
/** @deprecated use `class`. */
|
|
18
26
|
className?: string;
|
|
19
27
|
profilePanelOpen?: boolean;
|
|
20
28
|
profilePanelControlsId?: string;
|
|
@@ -24,6 +32,7 @@
|
|
|
24
32
|
|
|
25
33
|
let {
|
|
26
34
|
collapsed = false,
|
|
35
|
+
strings,
|
|
27
36
|
showProfile = true,
|
|
28
37
|
profileName = "Zabi",
|
|
29
38
|
profileEmail = "hello@zabi.dev",
|
|
@@ -32,21 +41,43 @@
|
|
|
32
41
|
logoutLabel = "Logout",
|
|
33
42
|
showThemeToggle = true,
|
|
34
43
|
lightModeLabel = "Light mode",
|
|
35
|
-
isLightMode = $bindable(
|
|
44
|
+
isLightMode = $bindable<Exclude<Props["isLightMode"], undefined>>(),
|
|
36
45
|
onLogout,
|
|
37
46
|
onThemeToggle,
|
|
38
|
-
|
|
47
|
+
class: classAttr = "",
|
|
48
|
+
className: legacyClass = "",
|
|
39
49
|
profilePanelOpen = false,
|
|
40
50
|
profilePanelControlsId = "",
|
|
41
51
|
onProfileClick,
|
|
42
52
|
profilePanel,
|
|
43
53
|
}: Props = $props();
|
|
44
54
|
|
|
55
|
+
// No fallback on a bindable prop: Svelte refuses `bind:…={undefined}` on
|
|
56
|
+
// one that has a fallback (`props_invalid_value`), and a page that throws
|
|
57
|
+
// while it hydrates never becomes interactive. The default is applied
|
|
58
|
+
// here instead: at once, for the server and the first render, and again
|
|
59
|
+
// whenever a parent hands back `undefined`.
|
|
60
|
+
const applyDefaults = () => {
|
|
61
|
+
if (isLightMode === undefined) isLightMode = false;
|
|
62
|
+
};
|
|
63
|
+
applyDefaults();
|
|
64
|
+
$effect.pre(applyDefaults);
|
|
65
|
+
|
|
66
|
+
/** `class` is the public prop; `className` is a deprecated alias.
|
|
67
|
+
* Both are merged here so existing call sites keep working. */
|
|
68
|
+
const className = $derived(cn(`${classAttr} ${legacyClass}`));
|
|
69
|
+
|
|
70
|
+
/** The app-wide words for this component, from a `ZabiStringsProvider` above it, if there is one. */
|
|
71
|
+
const provided = zabiStringsFor("sidebarFooter");
|
|
72
|
+
const text = $derived(mergeStrings(DEFAULT_SIDEBAR_FOOTER_STRINGS, provided(), strings));
|
|
73
|
+
|
|
45
74
|
const showFooter = $derived(showProfile || showLogout || showThemeToggle);
|
|
46
75
|
const showPanelLauncher = $derived(showProfile);
|
|
47
76
|
|
|
77
|
+
// Nested corners: the avatar sits 0.5rem (`px-2 py-2`) inside the profile
|
|
78
|
+
// button, so its radius is the button's less that gap.
|
|
48
79
|
const avatarClasses =
|
|
49
|
-
"size-10 rounded-
|
|
80
|
+
"size-10 rounded-[calc(var(--radius-container)-0.5rem)] bg-action-primary text-action-primary flex items-center justify-center text-sm font-semibold shrink-0 ring-1 ring-border";
|
|
50
81
|
|
|
51
82
|
function getTextToneClass(isMuted = false): string {
|
|
52
83
|
return isMuted ? "text-description" : "text-headline";
|
|
@@ -60,22 +91,22 @@
|
|
|
60
91
|
{#if showFooter}
|
|
61
92
|
<div class="w-full shrink-0" data-sidebar-flyout-root>
|
|
62
93
|
<footer
|
|
63
|
-
class={`flex w-full shrink-0 flex-col gap-
|
|
64
|
-
aria-label=
|
|
94
|
+
class={cn(`flex w-full shrink-0 flex-col gap-3 border-t border-border pt-3 pb-1 ${className}`)}
|
|
95
|
+
aria-label={text.accountAndSettings}
|
|
65
96
|
>
|
|
66
97
|
{#if showPanelLauncher}
|
|
67
98
|
<button
|
|
68
99
|
type="button"
|
|
69
100
|
data-sidebar-flyout-anchor="profile"
|
|
70
|
-
class="w-full cursor-pointer rounded-
|
|
101
|
+
class="w-full cursor-pointer rounded-container px-2 py-2 outline-none transition-colors hover:bg-nav-menu-hover hover:text-nav-menu-item-hover hover:ring-1 hover:ring-border active:bg-surface-active focus-ring focus-ring--nav"
|
|
71
102
|
aria-haspopup="dialog"
|
|
72
103
|
aria-expanded={profilePanelOpen}
|
|
73
104
|
aria-controls={profilePanelControlsId.trim()
|
|
74
105
|
? profilePanelControlsId.trim()
|
|
75
106
|
: undefined}
|
|
76
107
|
aria-label={collapsed
|
|
77
|
-
?
|
|
78
|
-
:
|
|
108
|
+
? text.openAccountPanel
|
|
109
|
+
: text.openAccountPanelFor(profileName)}
|
|
79
110
|
onclick={handleProfileClick}
|
|
80
111
|
>
|
|
81
112
|
<span class="flex w-full items-center gap-3 text-left">
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
|
+
import { type SidebarFooterStrings } from "../util/sidebar.js";
|
|
2
3
|
interface Props {
|
|
3
4
|
collapsed?: boolean;
|
|
5
|
+
/** The footer's name and the profile button's, for another language. */
|
|
6
|
+
strings?: Partial<SidebarFooterStrings>;
|
|
4
7
|
showProfile?: boolean;
|
|
5
8
|
profileName?: string;
|
|
6
9
|
profileEmail?: string;
|
|
@@ -12,6 +15,8 @@ interface Props {
|
|
|
12
15
|
isLightMode?: boolean;
|
|
13
16
|
onLogout?: () => void;
|
|
14
17
|
onThemeToggle?: (nextIsLightMode: boolean) => void;
|
|
18
|
+
class?: string;
|
|
19
|
+
/** @deprecated use `class`. */
|
|
15
20
|
className?: string;
|
|
16
21
|
profilePanelOpen?: boolean;
|
|
17
22
|
profilePanelControlsId?: string;
|