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
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
type Props = Omit<HTMLAttributes<HTMLDivElement>, "class" | "role"> & {
|
|
4
|
+
/** Shows the bar. Set it while the form differs from what is saved. */
|
|
5
|
+
dirty?: boolean;
|
|
6
|
+
/** Shown in the bar, and announced once when it appears. */
|
|
7
|
+
message?: string;
|
|
8
|
+
/** Accessible name of the bar as a landmark. */
|
|
9
|
+
label?: string;
|
|
10
|
+
saveLabel?: string;
|
|
11
|
+
discardLabel?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Save shows its loading state and Discard is disabled. Set by the
|
|
14
|
+
* bar itself while a promise from `onsave` is pending.
|
|
15
|
+
*/
|
|
16
|
+
saving?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Called when Save is activated. Return a promise to keep the bar in
|
|
19
|
+
* its saving state until it settles. The bar does not hide itself:
|
|
20
|
+
* clear `dirty` once the save has gone through.
|
|
21
|
+
*/
|
|
22
|
+
onsave?: () => void | Promise<unknown>;
|
|
23
|
+
/** Called when Discard is activated. */
|
|
24
|
+
ondiscard?: () => void;
|
|
25
|
+
/**
|
|
26
|
+
* Called when the promise from `onsave` rejects; the bar stays.
|
|
27
|
+
* Without it the error goes to the global error handler.
|
|
28
|
+
*/
|
|
29
|
+
onerror?: (error: unknown) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Which edge of its scroll container the bar sticks to. It is sticky,
|
|
32
|
+
* not fixed, so it keeps its place in the flow: put it after the
|
|
33
|
+
* form's last field (`bottom`) or before its first (`top`).
|
|
34
|
+
*/
|
|
35
|
+
position?: "bottom" | "top";
|
|
36
|
+
/** Extra buttons, placed before Discard. */
|
|
37
|
+
actions?: Snippet;
|
|
38
|
+
/** Extra classes for the bar. */
|
|
39
|
+
class?: string;
|
|
40
|
+
};
|
|
41
|
+
declare const UnsavedChangesBar: import("svelte").Component<Props, {}, "">;
|
|
42
|
+
type UnsavedChangesBar = ReturnType<typeof UnsavedChangesBar>;
|
|
43
|
+
export default UnsavedChangesBar;
|
|
@@ -2,8 +2,12 @@ export { default as Alert } from './Alert.svelte';
|
|
|
2
2
|
export { default as ComponentDemo } from './ComponentDemo.svelte';
|
|
3
3
|
export { default as ContactForm } from './ContactForm.svelte';
|
|
4
4
|
export { default as Dropdown } from './Dropdown.svelte';
|
|
5
|
+
export { default as DropdownItem } from './DropdownItem.svelte';
|
|
6
|
+
export type { DropdownItemIcon, DropdownItemTone, DropdownOption, } from '../util/dropdown.js';
|
|
5
7
|
export { default as Form } from './Form.svelte';
|
|
6
8
|
export { default as ImageUpload } from './ImageUpload.svelte';
|
|
9
|
+
export { default as MediaGrid } from './MediaGrid.svelte';
|
|
10
|
+
export type { MediaGridItemType, MediaGridKey, MediaGridSelectDetail, MediaGridStrings, } from '../util/media-grid.js';
|
|
7
11
|
export { default as Modal } from './Modal.svelte';
|
|
8
12
|
export { default as NavigationMenu } from './NavigationMenu.svelte';
|
|
9
13
|
export { default as NavigationMenuList } from './NavigationMenuList.svelte';
|
|
@@ -23,4 +27,46 @@ export { default as Header } from './Header.svelte';
|
|
|
23
27
|
export { default as EmptyState } from './EmptyState.svelte';
|
|
24
28
|
export { default as Toaster } from './Toaster.svelte';
|
|
25
29
|
export { default as RadioGroup } from './RadioGroup.svelte';
|
|
30
|
+
export { default as SegmentedControl } from './SegmentedControl.svelte';
|
|
31
|
+
export type { SegmentedControlIcon, SegmentedControlOption, } from '../util/segmented-control.js';
|
|
32
|
+
export { default as SortableList } from './SortableList.svelte';
|
|
33
|
+
export type { SortableListAnnouncement, SortableListReorderDetail, SortableListRow, SortableListStrings, } from '../util/sortable-list.js';
|
|
34
|
+
export { default as Collapsible } from './Collapsible.svelte';
|
|
35
|
+
export { default as SwipeableListItem } from './SwipeableListItem.svelte';
|
|
36
|
+
export { DEFAULT_SWIPEABLE_LIST_ITEM_STRINGS } from '../util/swipeable-list-item.js';
|
|
37
|
+
export type { SwipeableListItemAction, SwipeableListItemStrings } from '../util/swipeable-list-item.js';
|
|
38
|
+
export { default as PullToRefresh } from './PullToRefresh.svelte';
|
|
39
|
+
export { DEFAULT_PULL_TO_REFRESH_STRINGS } from '../util/pull-to-refresh.js';
|
|
40
|
+
export type { PullToRefreshStrings } from '../util/pull-to-refresh.js';
|
|
41
|
+
export { default as CollapsibleGroup } from './CollapsibleGroup.svelte';
|
|
42
|
+
export type { CollapsibleHeadingLevel, CollapsibleTriggerProps, CollapsibleTriggerState, } from '../util/collapsible.js';
|
|
43
|
+
export { default as ConfirmDialog } from './ConfirmDialog.svelte';
|
|
44
|
+
export type { ConfirmDialogCancelReason, ConfirmDialogResult, ConfirmDialogVariant, } from '../util/confirm-dialog.js';
|
|
45
|
+
export { default as Drawer } from './Drawer.svelte';
|
|
46
|
+
export type { DrawerCloseReason, DrawerSide, DrawerSize, } from '../util/drawer.js';
|
|
47
|
+
export { default as UnsavedChangesBar } from './UnsavedChangesBar.svelte';
|
|
48
|
+
export { default as AppBar } from './AppBar.svelte';
|
|
49
|
+
export { default as BottomTabBar } from './BottomTabBar.svelte';
|
|
50
|
+
export type { BottomTabBarIcon, BottomTabBarItem, } from '../util/bottom-tab-bar.js';
|
|
51
|
+
export { default as BottomSheet } from './BottomSheet.svelte';
|
|
52
|
+
export type { BottomSheetCloseReason, BottomSheetSnap, } from '../util/bottom-sheet.js';
|
|
53
|
+
export { default as StickyActionBar } from './StickyActionBar.svelte';
|
|
54
|
+
export { default as Calendar } from './Calendar.svelte';
|
|
55
|
+
export type { CalendarEvent, CalendarStrings, CalendarTone, } from '../util/calendar.js';
|
|
56
|
+
export { default as PhotoGrid } from './PhotoGrid.svelte';
|
|
57
|
+
export { default as PhotoViewer } from './PhotoViewer.svelte';
|
|
58
|
+
export type { Photo, PhotoGridSelectDetail, PhotoGridStrings, PhotoKey, PhotoViewerAction, PhotoViewerCloseReason, PhotoViewerStrings, } from '../util/photo.js';
|
|
59
|
+
export { default as AvatarGroup } from './AvatarGroup.svelte';
|
|
60
|
+
export { DEFAULT_AVATAR_GROUP_STRINGS } from '../util/avatar.js';
|
|
61
|
+
export type { AvatarGroupStrings, AvatarPerson } from '../util/avatar.js';
|
|
62
|
+
export { default as Stepper } from './Stepper.svelte';
|
|
63
|
+
export type { StepperItem, StepperLayout, StepperStep, StepperStepState, StepperStrings, } from '../util/stepper.js';
|
|
26
64
|
export * from './toast-store.js';
|
|
65
|
+
export { DEFAULT_TOASTER_STRINGS, TOAST_DURATIONS } from '../util/toaster.js';
|
|
66
|
+
export type { ToasterStrings, ToastPauseChange, ToastDuration } from '../util/toaster.js';
|
|
67
|
+
export { DEFAULT_SELECT_STRINGS } from '../util/select.js';
|
|
68
|
+
export type { SelectStrings, SelectPresentation } from '../util/select.js';
|
|
69
|
+
export { DEFAULT_SIDEBAR_BRAND_HEADER_STRINGS, DEFAULT_SIDEBAR_FOOTER_STRINGS, } from '../util/sidebar.js';
|
|
70
|
+
export type { SidebarBrandHeaderStrings, SidebarFooterStrings } from '../util/sidebar.js';
|
|
71
|
+
export { DEFAULT_COMPONENT_DEMO_STRINGS, DEFAULT_CONTACT_FORM_STRINGS, DEFAULT_PROPS_TABLE_STRINGS, } from '../util/ready-made-strings.js';
|
|
72
|
+
export type { ComponentDemoStrings, ContactFormStrings, PropsTableStrings, } from '../util/ready-made-strings.js';
|
package/dist/molecules/index.js
CHANGED
|
@@ -2,8 +2,10 @@ export { default as Alert } from './Alert.svelte';
|
|
|
2
2
|
export { default as ComponentDemo } from './ComponentDemo.svelte';
|
|
3
3
|
export { default as ContactForm } from './ContactForm.svelte';
|
|
4
4
|
export { default as Dropdown } from './Dropdown.svelte';
|
|
5
|
+
export { default as DropdownItem } from './DropdownItem.svelte';
|
|
5
6
|
export { default as Form } from './Form.svelte';
|
|
6
7
|
export { default as ImageUpload } from './ImageUpload.svelte';
|
|
8
|
+
export { default as MediaGrid } from './MediaGrid.svelte';
|
|
7
9
|
export { default as Modal } from './Modal.svelte';
|
|
8
10
|
export { default as NavigationMenu } from './NavigationMenu.svelte';
|
|
9
11
|
export { default as NavigationMenuList } from './NavigationMenuList.svelte';
|
|
@@ -23,4 +25,29 @@ export { default as Header } from './Header.svelte';
|
|
|
23
25
|
export { default as EmptyState } from './EmptyState.svelte';
|
|
24
26
|
export { default as Toaster } from './Toaster.svelte';
|
|
25
27
|
export { default as RadioGroup } from './RadioGroup.svelte';
|
|
28
|
+
export { default as SegmentedControl } from './SegmentedControl.svelte';
|
|
29
|
+
export { default as SortableList } from './SortableList.svelte';
|
|
30
|
+
export { default as Collapsible } from './Collapsible.svelte';
|
|
31
|
+
export { default as SwipeableListItem } from './SwipeableListItem.svelte';
|
|
32
|
+
export { DEFAULT_SWIPEABLE_LIST_ITEM_STRINGS } from '../util/swipeable-list-item.js';
|
|
33
|
+
export { default as PullToRefresh } from './PullToRefresh.svelte';
|
|
34
|
+
export { DEFAULT_PULL_TO_REFRESH_STRINGS } from '../util/pull-to-refresh.js';
|
|
35
|
+
export { default as CollapsibleGroup } from './CollapsibleGroup.svelte';
|
|
36
|
+
export { default as ConfirmDialog } from './ConfirmDialog.svelte';
|
|
37
|
+
export { default as Drawer } from './Drawer.svelte';
|
|
38
|
+
export { default as UnsavedChangesBar } from './UnsavedChangesBar.svelte';
|
|
39
|
+
export { default as AppBar } from './AppBar.svelte';
|
|
40
|
+
export { default as BottomTabBar } from './BottomTabBar.svelte';
|
|
41
|
+
export { default as BottomSheet } from './BottomSheet.svelte';
|
|
42
|
+
export { default as StickyActionBar } from './StickyActionBar.svelte';
|
|
43
|
+
export { default as Calendar } from './Calendar.svelte';
|
|
44
|
+
export { default as PhotoGrid } from './PhotoGrid.svelte';
|
|
45
|
+
export { default as PhotoViewer } from './PhotoViewer.svelte';
|
|
46
|
+
export { default as AvatarGroup } from './AvatarGroup.svelte';
|
|
47
|
+
export { DEFAULT_AVATAR_GROUP_STRINGS } from '../util/avatar.js';
|
|
48
|
+
export { default as Stepper } from './Stepper.svelte';
|
|
26
49
|
export * from './toast-store.js';
|
|
50
|
+
export { DEFAULT_TOASTER_STRINGS, TOAST_DURATIONS } from '../util/toaster.js';
|
|
51
|
+
export { DEFAULT_SELECT_STRINGS } from '../util/select.js';
|
|
52
|
+
export { DEFAULT_SIDEBAR_BRAND_HEADER_STRINGS, DEFAULT_SIDEBAR_FOOTER_STRINGS, } from '../util/sidebar.js';
|
|
53
|
+
export { DEFAULT_COMPONENT_DEMO_STRINGS, DEFAULT_CONTACT_FORM_STRINGS, DEFAULT_PROPS_TABLE_STRINGS, } from '../util/ready-made-strings.js';
|
|
@@ -1,17 +1,52 @@
|
|
|
1
|
+
import type { ToastDuration } from '../util/toaster.js';
|
|
1
2
|
export type ToastLevel = 'success' | 'error' | 'warning' | 'info';
|
|
3
|
+
/**
|
|
4
|
+
* One action offered inside a toast, such as Undo.
|
|
5
|
+
*
|
|
6
|
+
* A toast with an action stays until it is dismissed, unless you give it a
|
|
7
|
+
* `duration` (a named length or milliseconds): a keyboard user has to reach the button first, and the toaster
|
|
8
|
+
* may be far away in the tab order (WCAG 2.2.1). `focusToasts()` moves focus
|
|
9
|
+
* there. The action must still not be the only way to do the thing: offer it
|
|
10
|
+
* elsewhere in the page as well.
|
|
11
|
+
*/
|
|
12
|
+
export interface ToastAction {
|
|
13
|
+
/** Button text, and its accessible name. */
|
|
14
|
+
label: string;
|
|
15
|
+
onclick: () => void;
|
|
16
|
+
/** Close the toast after the handler runs. Defaults to `true`. */
|
|
17
|
+
dismissOnClick?: boolean;
|
|
18
|
+
}
|
|
2
19
|
export interface ToastItem {
|
|
3
20
|
id: string;
|
|
4
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* What the toast says. Always shown: as its one line, or under `title`
|
|
23
|
+
* when it has one.
|
|
24
|
+
*/
|
|
5
25
|
message: string;
|
|
6
26
|
type: ToastLevel;
|
|
27
|
+
/** A heading over the message. Without it the message stands alone. */
|
|
7
28
|
title?: string;
|
|
8
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* The long version, kept behind a button that opens it. Only a toast
|
|
31
|
+
* with `detail` has that button.
|
|
32
|
+
*/
|
|
9
33
|
detail?: string;
|
|
10
34
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
35
|
+
* How long the toast stays: `"short"` (3 s, a few words that need no
|
|
36
|
+
* reading time), `"medium"` (7 s), `"long"` (14 s), `"persistent"`
|
|
37
|
+
* (until it is dismissed: what the user has to act on, and errors), or
|
|
38
|
+
* a number of milliseconds, where `0` is persistent too. What is given
|
|
39
|
+
* here always wins.
|
|
40
|
+
*
|
|
41
|
+
* When omitted, the toaster decides: an error and a toast with an
|
|
42
|
+
* `action` stay until dismissed. Everything else goes by its title and
|
|
43
|
+
* message together: up to 120 characters gets `medium` (or the
|
|
44
|
+
* Toaster's `defaultDuration`), 121 to 240 gets `long`, and more than
|
|
45
|
+
* 240 stays until dismissed.
|
|
13
46
|
*/
|
|
14
|
-
duration?:
|
|
47
|
+
duration?: ToastDuration;
|
|
48
|
+
/** An action button in the toast, such as Undo. */
|
|
49
|
+
action?: ToastAction;
|
|
15
50
|
}
|
|
16
51
|
export declare const toastStore: {
|
|
17
52
|
subscribe: (this: void, run: import("svelte/store").Subscriber<ToastItem[]>, invalidate?: () => void) => import("svelte/store").Unsubscriber;
|
|
@@ -19,10 +54,11 @@ export declare const toastStore: {
|
|
|
19
54
|
message: string;
|
|
20
55
|
type?: ToastLevel;
|
|
21
56
|
/** Same semantics as {@link ToastItem.duration}. */
|
|
22
|
-
duration?:
|
|
57
|
+
duration?: ToastDuration;
|
|
23
58
|
id?: string;
|
|
24
59
|
title?: string;
|
|
25
60
|
detail?: string;
|
|
61
|
+
action?: ToastAction;
|
|
26
62
|
}): string;
|
|
27
63
|
dismiss: (id: string) => void;
|
|
28
64
|
clear(): void;
|
|
@@ -31,8 +67,18 @@ export declare function pushToast(options: {
|
|
|
31
67
|
message: string;
|
|
32
68
|
type?: ToastLevel;
|
|
33
69
|
/** Same semantics as {@link ToastItem.duration}. */
|
|
34
|
-
duration?:
|
|
70
|
+
duration?: ToastDuration;
|
|
35
71
|
title?: string;
|
|
36
72
|
detail?: string;
|
|
73
|
+
/** An action button in the toast, such as Undo. See {@link ToastAction}. */
|
|
74
|
+
action?: ToastAction;
|
|
37
75
|
}): string;
|
|
38
76
|
export declare function dismissToast(id: string): void;
|
|
77
|
+
/**
|
|
78
|
+
* Moves keyboard focus to the newest toast, so its action can be reached
|
|
79
|
+
* without tabbing through the page. Bind it to a shortcut of your own; the
|
|
80
|
+
* library registers none. Returns false when there is no toast to focus.
|
|
81
|
+
*
|
|
82
|
+
* Focus returns to where it was when that toast is dismissed.
|
|
83
|
+
*/
|
|
84
|
+
export declare function focusToasts(): boolean;
|
|
@@ -15,6 +15,7 @@ function createToastStore() {
|
|
|
15
15
|
duration: options.duration,
|
|
16
16
|
title: options.title,
|
|
17
17
|
detail: options.detail,
|
|
18
|
+
action: options.action,
|
|
18
19
|
};
|
|
19
20
|
update((list) => [...list, item]);
|
|
20
21
|
return id;
|
|
@@ -32,3 +33,23 @@ export function pushToast(options) {
|
|
|
32
33
|
export function dismissToast(id) {
|
|
33
34
|
toastStore.dismiss(id);
|
|
34
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Moves keyboard focus to the newest toast, so its action can be reached
|
|
38
|
+
* without tabbing through the page. Bind it to a shortcut of your own; the
|
|
39
|
+
* library registers none. Returns false when there is no toast to focus.
|
|
40
|
+
*
|
|
41
|
+
* Focus returns to where it was when that toast is dismissed.
|
|
42
|
+
*/
|
|
43
|
+
export function focusToasts() {
|
|
44
|
+
if (typeof document === 'undefined')
|
|
45
|
+
return false;
|
|
46
|
+
const toasts = document.querySelectorAll('[data-zabi-toaster] [data-toast-id]');
|
|
47
|
+
const newest = toasts[toasts.length - 1];
|
|
48
|
+
// The action if the toast has one, else its first control.
|
|
49
|
+
const target = newest?.querySelector('[data-toast-action]') ??
|
|
50
|
+
newest?.querySelector('button');
|
|
51
|
+
if (!target)
|
|
52
|
+
return false;
|
|
53
|
+
target.focus();
|
|
54
|
+
return document.activeElement === target;
|
|
55
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
import { untrack } from "svelte";
|
|
5
|
+
import { markAppShell, publishAppShellInsets } from "../util/app-shell.js";
|
|
6
|
+
import { cn } from "../util/cn.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The layout of a phone app: a bar at the top, content that scrolls, a
|
|
10
|
+
* tab bar at the bottom, and none of it under the notch or the home
|
|
11
|
+
* indicator.
|
|
12
|
+
*
|
|
13
|
+
* The shell is exactly as tall as the visible screen (`100dvh`, so the
|
|
14
|
+
* browser's own bars are accounted for) and only the middle scrolls. The
|
|
15
|
+
* header stays at the top of that scrolling area; the footer sits below it.
|
|
16
|
+
*
|
|
17
|
+
* ```svelte
|
|
18
|
+
* <AppShell>
|
|
19
|
+
* {#snippet header()}
|
|
20
|
+
* <AppBar title="Quizrundan" collapseOnScroll />
|
|
21
|
+
* {/snippet}
|
|
22
|
+
* <div class="p-4">…</div>
|
|
23
|
+
* {#snippet footer()}
|
|
24
|
+
* <BottomTabBar {items} active={page.url.pathname} />
|
|
25
|
+
* {/snippet}
|
|
26
|
+
* </AppShell>
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* Two custom properties on the host say how much of the screen the bars
|
|
30
|
+
* take, safe areas included, so anything inside the shell can stay clear
|
|
31
|
+
* of them:
|
|
32
|
+
*
|
|
33
|
+
* - `--app-shell-top-inset`: the height of the header;
|
|
34
|
+
* - `--app-shell-bottom-inset`: the height of the footer.
|
|
35
|
+
*
|
|
36
|
+
* Without a bar the value is the safe-area inset alone. The host is the
|
|
37
|
+
* containing block for anything positioned inside it, and such an element
|
|
38
|
+
* does not scroll with the content, so a floating button above the tab bar
|
|
39
|
+
* is `absolute` with `bottom: calc(var(--app-shell-bottom-inset) + 1rem)`.
|
|
40
|
+
*
|
|
41
|
+
* While the shell is mounted the same two properties are also set on
|
|
42
|
+
* `<html>`, so an overlay that is moved to `document.body` (a sheet, a
|
|
43
|
+
* toast) can read them too. With more than one shell on the page, the one
|
|
44
|
+
* mounted last is the one mirrored there.
|
|
45
|
+
*/
|
|
46
|
+
type Props = Omit<HTMLAttributes<HTMLDivElement>, "class" | "style"> & {
|
|
47
|
+
/** The top bar, an `AppBar`. It handles the safe area above it. */
|
|
48
|
+
header?: Snippet;
|
|
49
|
+
/** The scrolling content, rendered in the element `contentElement` names. */
|
|
50
|
+
children?: Snippet;
|
|
51
|
+
/**
|
|
52
|
+
* The element around the content. `main` when the shell is the page,
|
|
53
|
+
* which is what it is for. A page has one `<main>`: use `div` for a
|
|
54
|
+
* shell that sits inside another one, such as a preview in a page of
|
|
55
|
+
* its own.
|
|
56
|
+
*/
|
|
57
|
+
contentElement?: "main" | "div";
|
|
58
|
+
/** The bottom bar, a `BottomTabBar`. It handles the safe area below it. */
|
|
59
|
+
footer?: Snippet;
|
|
60
|
+
class?: string;
|
|
61
|
+
/** Added after the two custom properties the shell sets. */
|
|
62
|
+
style?: string;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
let {
|
|
66
|
+
header,
|
|
67
|
+
children,
|
|
68
|
+
contentElement = "main",
|
|
69
|
+
footer,
|
|
70
|
+
class: className = "",
|
|
71
|
+
style = "",
|
|
72
|
+
...restProps
|
|
73
|
+
}: Props = $props();
|
|
74
|
+
|
|
75
|
+
markAppShell();
|
|
76
|
+
|
|
77
|
+
let headerRegion: HTMLDivElement | undefined = $state();
|
|
78
|
+
let footerRegion: HTMLDivElement | undefined = $state();
|
|
79
|
+
/** Measured heights in px; null on the server and until the first measurement. */
|
|
80
|
+
let headerHeight = $state<number | null>(null);
|
|
81
|
+
let footerHeight = $state<number | null>(null);
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* What the bars measure before they have been measured: the default
|
|
85
|
+
* heights of AppBar and BottomTabBar. The real size replaces it once the
|
|
86
|
+
* shell runs, which matters when the text is enlarged or a label wraps.
|
|
87
|
+
*/
|
|
88
|
+
// In px: AppBar and BottomTabBar keep their height when the text is enlarged.
|
|
89
|
+
const HEADER_ESTIMATE = "calc(57px + env(safe-area-inset-top, 0px))";
|
|
90
|
+
const FOOTER_ESTIMATE = "calc(65px + env(safe-area-inset-bottom, 0px))";
|
|
91
|
+
|
|
92
|
+
function track(region: HTMLElement | undefined, set: (height: number | null) => void) {
|
|
93
|
+
if (!region) {
|
|
94
|
+
set(null);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const measure = () => {
|
|
98
|
+
const height = region.getBoundingClientRect().height;
|
|
99
|
+
// No layout (a hidden shell, a test DOM): keep the estimate.
|
|
100
|
+
set(height > 0 ? height : null);
|
|
101
|
+
};
|
|
102
|
+
measure();
|
|
103
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
104
|
+
const observer = new ResizeObserver(measure);
|
|
105
|
+
observer.observe(region);
|
|
106
|
+
return () => observer.disconnect();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
$effect(() => track(headerRegion, (height) => (headerHeight = height)));
|
|
110
|
+
$effect(() => track(footerRegion, (height) => (footerHeight = height)));
|
|
111
|
+
|
|
112
|
+
const topInset = $derived(
|
|
113
|
+
!header
|
|
114
|
+
? "env(safe-area-inset-top, 0px)"
|
|
115
|
+
: headerHeight === null
|
|
116
|
+
? HEADER_ESTIMATE
|
|
117
|
+
: `${headerHeight}px`,
|
|
118
|
+
);
|
|
119
|
+
const bottomInset = $derived(
|
|
120
|
+
!footer
|
|
121
|
+
? "env(safe-area-inset-bottom, 0px)"
|
|
122
|
+
: footerHeight === null
|
|
123
|
+
? FOOTER_ESTIMATE
|
|
124
|
+
: `${footerHeight}px`,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// On `<html>` as well, for what is rendered outside the shell.
|
|
128
|
+
let published: ReturnType<typeof publishAppShellInsets> | undefined;
|
|
129
|
+
$effect(() => {
|
|
130
|
+
published = untrack(() => publishAppShellInsets(topInset, bottomInset));
|
|
131
|
+
return () => {
|
|
132
|
+
published?.leave();
|
|
133
|
+
published = undefined;
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
$effect(() => {
|
|
137
|
+
published?.update(topInset, bottomInset);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const contentClasses = $derived(
|
|
141
|
+
cn(
|
|
142
|
+
"min-w-0 flex-1 pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]",
|
|
143
|
+
!header && "pt-[env(safe-area-inset-top)]",
|
|
144
|
+
!footer && "pb-[env(safe-area-inset-bottom)]",
|
|
145
|
+
),
|
|
146
|
+
);
|
|
147
|
+
</script>
|
|
148
|
+
|
|
149
|
+
<div
|
|
150
|
+
data-app-shell
|
|
151
|
+
class={cn(
|
|
152
|
+
"relative flex h-dvh w-full flex-col overflow-hidden bg-background text-body",
|
|
153
|
+
className,
|
|
154
|
+
)}
|
|
155
|
+
style="--app-shell-top-inset: {topInset}; --app-shell-bottom-inset: {bottomInset}; {style}"
|
|
156
|
+
{...restProps}
|
|
157
|
+
>
|
|
158
|
+
<!--
|
|
159
|
+
The header is inside the scrolling area and sticks to its top. It keeps
|
|
160
|
+
its place in the flow, so the content starts below it with nothing to
|
|
161
|
+
measure, and it can slide away (AppBar's collapseOnScroll) without the
|
|
162
|
+
content moving. scroll-padding keeps a focused field from landing under it.
|
|
163
|
+
-->
|
|
164
|
+
<div
|
|
165
|
+
data-app-shell-scroller
|
|
166
|
+
class="flex min-h-0 flex-1 flex-col overflow-x-hidden overflow-y-auto overscroll-y-contain scroll-pt-(--app-shell-top-inset)"
|
|
167
|
+
>
|
|
168
|
+
{#if header}
|
|
169
|
+
<!-- An empty strip is left when the bar slides away; it must not take taps. -->
|
|
170
|
+
<div
|
|
171
|
+
bind:this={headerRegion}
|
|
172
|
+
data-app-shell-header
|
|
173
|
+
class="pointer-events-none sticky top-0 z-sticky shrink-0 *:pointer-events-auto"
|
|
174
|
+
>
|
|
175
|
+
{@render header()}
|
|
176
|
+
</div>
|
|
177
|
+
{/if}
|
|
178
|
+
<!-- Two branches, not `<svelte:element>`: hydration takes a dynamic
|
|
179
|
+
element out and puts it back, which blurs a control inside it that the
|
|
180
|
+
user had already tabbed to, and the whole page is inside this one. -->
|
|
181
|
+
{#if contentElement === "div"}
|
|
182
|
+
<div data-app-shell-content class={contentClasses}>
|
|
183
|
+
{@render children?.()}
|
|
184
|
+
</div>
|
|
185
|
+
{:else}
|
|
186
|
+
<main data-app-shell-content class={contentClasses}>
|
|
187
|
+
{@render children?.()}
|
|
188
|
+
</main>
|
|
189
|
+
{/if}
|
|
190
|
+
</div>
|
|
191
|
+
{#if footer}
|
|
192
|
+
<div bind:this={footerRegion} data-app-shell-footer class="shrink-0">
|
|
193
|
+
{@render footer()}
|
|
194
|
+
</div>
|
|
195
|
+
{/if}
|
|
196
|
+
</div>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
/**
|
|
4
|
+
* The layout of a phone app: a bar at the top, content that scrolls, a
|
|
5
|
+
* tab bar at the bottom, and none of it under the notch or the home
|
|
6
|
+
* indicator.
|
|
7
|
+
*
|
|
8
|
+
* The shell is exactly as tall as the visible screen (`100dvh`, so the
|
|
9
|
+
* browser's own bars are accounted for) and only the middle scrolls. The
|
|
10
|
+
* header stays at the top of that scrolling area; the footer sits below it.
|
|
11
|
+
*
|
|
12
|
+
* ```svelte
|
|
13
|
+
* <AppShell>
|
|
14
|
+
* {#snippet header()}
|
|
15
|
+
* <AppBar title="Quizrundan" collapseOnScroll />
|
|
16
|
+
* {/snippet}
|
|
17
|
+
* <div class="p-4">…</div>
|
|
18
|
+
* {#snippet footer()}
|
|
19
|
+
* <BottomTabBar {items} active={page.url.pathname} />
|
|
20
|
+
* {/snippet}
|
|
21
|
+
* </AppShell>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Two custom properties on the host say how much of the screen the bars
|
|
25
|
+
* take, safe areas included, so anything inside the shell can stay clear
|
|
26
|
+
* of them:
|
|
27
|
+
*
|
|
28
|
+
* - `--app-shell-top-inset`: the height of the header;
|
|
29
|
+
* - `--app-shell-bottom-inset`: the height of the footer.
|
|
30
|
+
*
|
|
31
|
+
* Without a bar the value is the safe-area inset alone. The host is the
|
|
32
|
+
* containing block for anything positioned inside it, and such an element
|
|
33
|
+
* does not scroll with the content, so a floating button above the tab bar
|
|
34
|
+
* is `absolute` with `bottom: calc(var(--app-shell-bottom-inset) + 1rem)`.
|
|
35
|
+
*
|
|
36
|
+
* While the shell is mounted the same two properties are also set on
|
|
37
|
+
* `<html>`, so an overlay that is moved to `document.body` (a sheet, a
|
|
38
|
+
* toast) can read them too. With more than one shell on the page, the one
|
|
39
|
+
* mounted last is the one mirrored there.
|
|
40
|
+
*/
|
|
41
|
+
type Props = Omit<HTMLAttributes<HTMLDivElement>, "class" | "style"> & {
|
|
42
|
+
/** The top bar, an `AppBar`. It handles the safe area above it. */
|
|
43
|
+
header?: Snippet;
|
|
44
|
+
/** The scrolling content, rendered in the element `contentElement` names. */
|
|
45
|
+
children?: Snippet;
|
|
46
|
+
/**
|
|
47
|
+
* The element around the content. `main` when the shell is the page,
|
|
48
|
+
* which is what it is for. A page has one `<main>`: use `div` for a
|
|
49
|
+
* shell that sits inside another one, such as a preview in a page of
|
|
50
|
+
* its own.
|
|
51
|
+
*/
|
|
52
|
+
contentElement?: "main" | "div";
|
|
53
|
+
/** The bottom bar, a `BottomTabBar`. It handles the safe area below it. */
|
|
54
|
+
footer?: Snippet;
|
|
55
|
+
class?: string;
|
|
56
|
+
/** Added after the two custom properties the shell sets. */
|
|
57
|
+
style?: string;
|
|
58
|
+
};
|
|
59
|
+
declare const AppShell: import("svelte").Component<Props, {}, "">;
|
|
60
|
+
type AppShell = ReturnType<typeof AppShell>;
|
|
61
|
+
export default AppShell;
|