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,56 @@
|
|
|
1
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
2
|
+
import { type Photo, type PhotoViewerAction, type PhotoViewerCloseReason, type PhotoViewerStrings } from "../util/photo.js";
|
|
3
|
+
/**
|
|
4
|
+
* Photos one at a time, on the whole screen: swipe or use the arrows to
|
|
5
|
+
* go between them, pinch or double tap to look closer, swipe down or
|
|
6
|
+
* press Escape to leave.
|
|
7
|
+
*
|
|
8
|
+
* ```svelte
|
|
9
|
+
* <PhotoGrid {photos} onopen={(at) => { index = at; open = true; }} />
|
|
10
|
+
* <PhotoViewer {photos} bind:index bind:isOpen={open} actions={[share, remove]} />
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* It is a modal dialog, on the same footing as Modal, Drawer and
|
|
14
|
+
* BottomSheet. When it closes, focus goes to the tile of the photo that
|
|
15
|
+
* was showing, if the `PhotoGrid` it was opened from shows it; otherwise
|
|
16
|
+
* to whatever opened it.
|
|
17
|
+
*
|
|
18
|
+
* It is dark in both themes: the photos are on black. Nothing in it is
|
|
19
|
+
* written on that black: every control, the counter and the caption sit
|
|
20
|
+
* on plates in the theme's own surface colour, so they read over any
|
|
21
|
+
* photo in either theme.
|
|
22
|
+
*
|
|
23
|
+
* Other attributes (`id`, `data-*`, ...) land on the `role="dialog"` panel.
|
|
24
|
+
*/
|
|
25
|
+
type Props = Omit<HTMLAttributes<HTMLDivElement>, "class" | "onclose" | "aria-label"> & {
|
|
26
|
+
photos: Photo[];
|
|
27
|
+
/** Place in `photos` of the photo that is showing. Supports `bind:index`. */
|
|
28
|
+
index?: number;
|
|
29
|
+
isOpen?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Things to do with the photo that is showing. Up to three are
|
|
32
|
+
* buttons in a bar under the photo; with more, two are, and the
|
|
33
|
+
* rest are in a menu. The viewer does nothing by itself: each action
|
|
34
|
+
* is your own function.
|
|
35
|
+
*/
|
|
36
|
+
actions?: PhotoViewerAction[];
|
|
37
|
+
/**
|
|
38
|
+
* Render the overlay in `document.body`, so an ancestor with a
|
|
39
|
+
* transform, filter or clipped overflow cannot trap it; pass `false`
|
|
40
|
+
* to render in place.
|
|
41
|
+
*/
|
|
42
|
+
portal?: boolean;
|
|
43
|
+
/** Fired when the viewer closes itself, with what the user did. */
|
|
44
|
+
onclose?: (detail: {
|
|
45
|
+
reason: PhotoViewerCloseReason;
|
|
46
|
+
}) => void;
|
|
47
|
+
/** Accessible name of the dialog. */
|
|
48
|
+
label?: string;
|
|
49
|
+
/** Overrides for the built-in strings. */
|
|
50
|
+
strings?: Partial<PhotoViewerStrings>;
|
|
51
|
+
/** Extra classes for the dialog panel. */
|
|
52
|
+
class?: string;
|
|
53
|
+
};
|
|
54
|
+
declare const PhotoViewer: import("svelte").Component<Props, {}, "index" | "isOpen">;
|
|
55
|
+
type PhotoViewer = ReturnType<typeof PhotoViewer>;
|
|
56
|
+
export default PhotoViewer;
|
|
@@ -1,43 +1,58 @@
|
|
|
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 { ComponentProp } from "../types/page.types";
|
|
3
5
|
import Table from "../atoms/Table.svelte";
|
|
6
|
+
import { cn } from "../util/cn.js";
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_PROPS_TABLE_STRINGS,
|
|
9
|
+
type PropsTableStrings,
|
|
10
|
+
} from "../util/ready-made-strings.js";
|
|
4
11
|
|
|
5
12
|
interface Props {
|
|
13
|
+
/** Extra classes for the host element. */
|
|
14
|
+
class?: string;
|
|
6
15
|
props: ComponentProp[];
|
|
7
16
|
caption?: string;
|
|
17
|
+
/** The column headings, Yes and No, and the line for an empty table. */
|
|
18
|
+
strings?: Partial<PropsTableStrings>;
|
|
8
19
|
}
|
|
9
20
|
|
|
10
|
-
let { props, caption = "Props / API" }: Props = $props();
|
|
21
|
+
let { class: className = "", props, caption = "Props / API", strings }: Props = $props();
|
|
22
|
+
|
|
23
|
+
/** The app-wide words for this component, from a `ZabiStringsProvider` above it, if there is one. */
|
|
24
|
+
const provided = zabiStringsFor("propsTable");
|
|
25
|
+
const text = $derived(mergeStrings(DEFAULT_PROPS_TABLE_STRINGS, provided(), strings));
|
|
11
26
|
</script>
|
|
12
27
|
|
|
13
28
|
{#if props.length === 0}
|
|
14
|
-
<div class="rounded-
|
|
15
|
-
|
|
29
|
+
<div class={cn("rounded-control border border-border bg-card px-4 py-4 text-sm text-description", className)}>
|
|
30
|
+
{text.empty}
|
|
16
31
|
</div>
|
|
17
32
|
{:else}
|
|
18
33
|
<Table caption={caption}>
|
|
19
34
|
<thead>
|
|
20
|
-
<tr class="bg-
|
|
35
|
+
<tr class="bg-surface-elevated">
|
|
21
36
|
<th class="border-b border-border px-4 py-3 text-left font-semibold text-headline">
|
|
22
|
-
|
|
37
|
+
{text.name}
|
|
23
38
|
</th>
|
|
24
39
|
<th class="border-b border-border px-4 py-3 text-left font-semibold text-headline">
|
|
25
|
-
|
|
40
|
+
{text.type}
|
|
26
41
|
</th>
|
|
27
42
|
<th class="border-b border-border px-4 py-3 text-left font-semibold text-headline">
|
|
28
|
-
|
|
43
|
+
{text.required}
|
|
29
44
|
</th>
|
|
30
45
|
<th class="border-b border-border px-4 py-3 text-left font-semibold text-headline">
|
|
31
|
-
|
|
46
|
+
{text.default}
|
|
32
47
|
</th>
|
|
33
48
|
<th class="border-b border-border px-4 py-3 text-left font-semibold text-headline">
|
|
34
|
-
|
|
49
|
+
{text.description}
|
|
35
50
|
</th>
|
|
36
51
|
</tr>
|
|
37
52
|
</thead>
|
|
38
53
|
<tbody>
|
|
39
54
|
{#each props as prop}
|
|
40
|
-
<tr class="hover:bg-
|
|
55
|
+
<tr class="hover:bg-surface-hover">
|
|
41
56
|
<td class="border-b border-border px-4 py-3 font-mono text-body">
|
|
42
57
|
{prop.name}
|
|
43
58
|
</td>
|
|
@@ -45,7 +60,7 @@
|
|
|
45
60
|
{prop.type}
|
|
46
61
|
</td>
|
|
47
62
|
<td class="border-b border-border px-4 py-3 text-description">
|
|
48
|
-
{prop.required ?
|
|
63
|
+
{prop.required ? text.yes : text.no}
|
|
49
64
|
</td>
|
|
50
65
|
<td class="border-b border-border px-4 py-3 text-description">
|
|
51
66
|
{prop.defaultValue || "—"}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { ComponentProp } from "../types/page.types";
|
|
2
|
+
import { type PropsTableStrings } from "../util/ready-made-strings.js";
|
|
2
3
|
interface Props {
|
|
4
|
+
/** Extra classes for the host element. */
|
|
5
|
+
class?: string;
|
|
3
6
|
props: ComponentProp[];
|
|
4
7
|
caption?: string;
|
|
8
|
+
/** The column headings, Yes and No, and the line for an empty table. */
|
|
9
|
+
strings?: Partial<PropsTableStrings>;
|
|
5
10
|
}
|
|
6
11
|
declare const PropsTable: import("svelte").Component<Props, {}, "">;
|
|
7
12
|
type PropsTable = ReturnType<typeof PropsTable>;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { mergeStrings } from "../util/ready-made-strings.js";
|
|
3
|
+
import { zabiStringsFor } from "../util/zabi-strings.js";
|
|
4
|
+
import type { Snippet } from "svelte";
|
|
5
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
6
|
+
import ArrowDown from "@lucide/svelte/icons/arrow-down";
|
|
7
|
+
import Spinner from "../atoms/Spinner.svelte";
|
|
8
|
+
import { cn } from "../util/cn.js";
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_PULL_TO_REFRESH_STRINGS,
|
|
11
|
+
pullDistance,
|
|
12
|
+
scrollContainerOf,
|
|
13
|
+
type PullToRefreshStrings,
|
|
14
|
+
} from "../util/pull-to-refresh.js";
|
|
15
|
+
import { DRAG_SLOP, prefersReducedMotion } from "../util/sheet-drag.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A list that reloads when it is pulled down from its top, on a touch
|
|
19
|
+
* screen.
|
|
20
|
+
*
|
|
21
|
+
* The pull is a shortcut. The same refresh is a button at the top of the
|
|
22
|
+
* region, out of sight until keyboard focus reaches it, and named for a
|
|
23
|
+
* screen reader; "Refreshing" and "Updated" are announced, and the
|
|
24
|
+
* region is `aria-busy` meanwhile.
|
|
25
|
+
*
|
|
26
|
+
* It only acts while what scrolls the list (the page, or the nearest
|
|
27
|
+
* scrolling ancestor, such as the content of an `AppShell`) is at its
|
|
28
|
+
* top, and never takes an ordinary scroll. The indicator is in the flow
|
|
29
|
+
* of the region, above the list, so under an app bar it comes out below
|
|
30
|
+
* the bar.
|
|
31
|
+
*
|
|
32
|
+
* ```svelte
|
|
33
|
+
* <PullToRefresh onrefresh={() => loadRounds()}>
|
|
34
|
+
* <List items={rounds} />
|
|
35
|
+
* </PullToRefresh>
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
type Props = Omit<HTMLAttributes<HTMLDivElement>, "class" | "children" | "aria-busy"> & {
|
|
39
|
+
/**
|
|
40
|
+
* Reloads the list. Return the promise: the indicator stays until it
|
|
41
|
+
* settles. A promise that rejects ends the refresh too, and nothing
|
|
42
|
+
* is announced as updated; say what went wrong yourself.
|
|
43
|
+
*/
|
|
44
|
+
onrefresh?: () => Promise<void> | void;
|
|
45
|
+
/** Whether a refresh is running. Bindable: set it to show the indicator for a refresh of your own. */
|
|
46
|
+
refreshing?: boolean;
|
|
47
|
+
/** No pull and no button. */
|
|
48
|
+
disabled?: boolean;
|
|
49
|
+
/** How far the indicator has to come out for letting go to refresh, in px. */
|
|
50
|
+
threshold?: number;
|
|
51
|
+
/**
|
|
52
|
+
* The button that refreshes without the gesture. Without it the pull
|
|
53
|
+
* is the only way this component offers, and the app has to give
|
|
54
|
+
* another (WCAG 2.5.1).
|
|
55
|
+
*/
|
|
56
|
+
showButton?: boolean;
|
|
57
|
+
/** The words the component says by itself, for another language. */
|
|
58
|
+
strings?: Partial<PullToRefreshStrings>;
|
|
59
|
+
class?: string;
|
|
60
|
+
/** The list. */
|
|
61
|
+
children?: Snippet;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
let {
|
|
65
|
+
onrefresh,
|
|
66
|
+
refreshing = $bindable<Exclude<Props["refreshing"], undefined>>(),
|
|
67
|
+
disabled = false,
|
|
68
|
+
threshold = 64,
|
|
69
|
+
showButton = true,
|
|
70
|
+
strings,
|
|
71
|
+
class: className = "",
|
|
72
|
+
children,
|
|
73
|
+
...restProps
|
|
74
|
+
}: Props = $props();
|
|
75
|
+
|
|
76
|
+
// No fallback on a bindable prop (see Collapsible): the default is applied here.
|
|
77
|
+
const applyDefaults = () => {
|
|
78
|
+
if (refreshing === undefined) refreshing = false;
|
|
79
|
+
};
|
|
80
|
+
applyDefaults();
|
|
81
|
+
$effect.pre(applyDefaults);
|
|
82
|
+
|
|
83
|
+
/** The app-wide words for this component, from a `ZabiStringsProvider` above it, if there is one. */
|
|
84
|
+
const provided = zabiStringsFor("pullToRefresh");
|
|
85
|
+
const text = $derived(mergeStrings(DEFAULT_PULL_TO_REFRESH_STRINGS, provided(), strings));
|
|
86
|
+
|
|
87
|
+
let root = $state<HTMLDivElement>();
|
|
88
|
+
/** How far the indicator is out under a finger, in px; null when no pull is going on. */
|
|
89
|
+
let pulled = $state<number | null>(null);
|
|
90
|
+
/** What the status region says. It is in the page, empty, before anything is said. */
|
|
91
|
+
let status = $state("");
|
|
92
|
+
/** Set when a refresh of this component's own failed: nothing was updated. */
|
|
93
|
+
let failed = false;
|
|
94
|
+
|
|
95
|
+
const armed = $derived(pulled !== null && pulled >= threshold);
|
|
96
|
+
|
|
97
|
+
async function refresh() {
|
|
98
|
+
if (disabled || refreshing) return;
|
|
99
|
+
failed = false;
|
|
100
|
+
refreshing = true;
|
|
101
|
+
try {
|
|
102
|
+
await onrefresh?.();
|
|
103
|
+
} catch {
|
|
104
|
+
// The app's to report (see `onrefresh`). The refresh is over all the same.
|
|
105
|
+
failed = true;
|
|
106
|
+
} finally {
|
|
107
|
+
refreshing = false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// The announcements follow `refreshing`, whoever set it.
|
|
112
|
+
let wasRefreshing = false;
|
|
113
|
+
$effect(() => {
|
|
114
|
+
const now = !!refreshing;
|
|
115
|
+
if (now === wasRefreshing) return;
|
|
116
|
+
wasRefreshing = now;
|
|
117
|
+
status = now ? text.refreshing : failed ? "" : text.done;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// The browser's own pull-to-refresh must not fire as well: that is a
|
|
121
|
+
// property of what scrolls, which is not this element.
|
|
122
|
+
$effect(() => {
|
|
123
|
+
const element = root;
|
|
124
|
+
if (!element || disabled) return;
|
|
125
|
+
const scroller = scrollContainerOf(element);
|
|
126
|
+
const before = scroller.style.overscrollBehaviorY;
|
|
127
|
+
scroller.style.overscrollBehaviorY = "contain";
|
|
128
|
+
return () => {
|
|
129
|
+
scroller.style.overscrollBehaviorY = before;
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// --- The pull. Touch events, because the browser owns the gesture (it
|
|
134
|
+
// scrolls) until it is taken, and only a touch listener that is not
|
|
135
|
+
// passive can take it. A mouse does not pull.
|
|
136
|
+
$effect(() => {
|
|
137
|
+
const element = root;
|
|
138
|
+
if (!element || disabled) return;
|
|
139
|
+
const scroller = scrollContainerOf(element);
|
|
140
|
+
let touchId: number | null = null;
|
|
141
|
+
let startX = 0;
|
|
142
|
+
let startY = 0;
|
|
143
|
+
let pulling = false;
|
|
144
|
+
|
|
145
|
+
const find = (list: TouchList) => Array.from(list).find((touch) => touch.identifier === touchId);
|
|
146
|
+
|
|
147
|
+
function onTouchStart(event: TouchEvent) {
|
|
148
|
+
if (touchId !== null || event.touches.length !== 1 || refreshing) return;
|
|
149
|
+
if (scroller.scrollTop > 0) return;
|
|
150
|
+
const touch = event.touches[0];
|
|
151
|
+
touchId = touch.identifier;
|
|
152
|
+
startX = touch.clientX;
|
|
153
|
+
startY = touch.clientY;
|
|
154
|
+
pulling = false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function onTouchMove(event: TouchEvent) {
|
|
158
|
+
const touch = find(event.touches);
|
|
159
|
+
if (!touch) return;
|
|
160
|
+
const dx = touch.clientX - startX;
|
|
161
|
+
const dy = touch.clientY - startY;
|
|
162
|
+
if (!pulling) {
|
|
163
|
+
// Scrolled since, upwards, or sideways: not a pull.
|
|
164
|
+
if (scroller.scrollTop > 0 || dy < DRAG_SLOP) return;
|
|
165
|
+
if (Math.abs(dx) > Math.abs(dy)) {
|
|
166
|
+
touchId = null;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
pulling = true;
|
|
170
|
+
// Measured from where the pull was recognised.
|
|
171
|
+
startY = touch.clientY;
|
|
172
|
+
}
|
|
173
|
+
if (event.cancelable) event.preventDefault();
|
|
174
|
+
pulled = pullDistance(touch.clientY - startY, threshold);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function finish(event: TouchEvent, cancelled: boolean) {
|
|
178
|
+
if (!find(event.changedTouches)) return;
|
|
179
|
+
touchId = null;
|
|
180
|
+
const far = pulling && !cancelled && pulled !== null && pulled >= threshold;
|
|
181
|
+
pulling = false;
|
|
182
|
+
pulled = null;
|
|
183
|
+
if (far) void refresh();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const onTouchEnd = (event: TouchEvent) => finish(event, false);
|
|
187
|
+
const onTouchCancel = (event: TouchEvent) => finish(event, true);
|
|
188
|
+
|
|
189
|
+
element.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
190
|
+
element.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
191
|
+
element.addEventListener("touchend", onTouchEnd);
|
|
192
|
+
element.addEventListener("touchcancel", onTouchCancel);
|
|
193
|
+
return () => {
|
|
194
|
+
element.removeEventListener("touchstart", onTouchStart);
|
|
195
|
+
element.removeEventListener("touchmove", onTouchMove);
|
|
196
|
+
element.removeEventListener("touchend", onTouchEnd);
|
|
197
|
+
element.removeEventListener("touchcancel", onTouchCancel);
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The height of the indicator: under the finger while pulling, at the
|
|
203
|
+
* threshold while the refresh runs. Where motion is unwanted it does not
|
|
204
|
+
* follow the finger: it is there, at full height, or it is not.
|
|
205
|
+
*/
|
|
206
|
+
const indicatorHeight = $derived.by(() => {
|
|
207
|
+
if (refreshing) return threshold;
|
|
208
|
+
if (pulled === null) return 0;
|
|
209
|
+
return prefersReducedMotion() ? (pulled > 0 ? threshold : 0) : pulled;
|
|
210
|
+
});
|
|
211
|
+
</script>
|
|
212
|
+
|
|
213
|
+
<div
|
|
214
|
+
{...restProps}
|
|
215
|
+
bind:this={root}
|
|
216
|
+
class={cn("relative", className)}
|
|
217
|
+
aria-busy={refreshing ? "true" : undefined}
|
|
218
|
+
data-pull-to-refresh
|
|
219
|
+
data-refreshing={refreshing ? "true" : "false"}
|
|
220
|
+
>
|
|
221
|
+
<!-- In the page before it says anything, or the first announcement is lost. -->
|
|
222
|
+
<div class="sr-only" role="status" aria-live="polite" data-pull-status>{status}</div>
|
|
223
|
+
|
|
224
|
+
{#if showButton && !disabled}
|
|
225
|
+
<!-- Out of sight until keyboard focus reaches it: the list is what the region is for. -->
|
|
226
|
+
<button
|
|
227
|
+
type="button"
|
|
228
|
+
class="focus-ring sr-only cursor-pointer rounded-control bg-action-secondary text-sm font-medium text-headline hover:bg-action-secondary-hover active:bg-action-secondary-active focus-visible:not-sr-only focus-visible:absolute focus-visible:start-[8px] focus-visible:top-[8px] focus-visible:z-10 focus-visible:min-h-11 focus-visible:px-[16px]"
|
|
229
|
+
aria-disabled={refreshing ? "true" : undefined}
|
|
230
|
+
data-pull-button
|
|
231
|
+
onclick={() => void refresh()}
|
|
232
|
+
>
|
|
233
|
+
{text.refresh}
|
|
234
|
+
</button>
|
|
235
|
+
{/if}
|
|
236
|
+
|
|
237
|
+
<!-- Decorative: the status region and the button carry it for assistive technology. -->
|
|
238
|
+
<div
|
|
239
|
+
class={cn(
|
|
240
|
+
"flex items-end justify-center overflow-hidden text-sm text-description",
|
|
241
|
+
pulled === null && "transition-[height] duration-200 ease-out motion-reduce:transition-none",
|
|
242
|
+
)}
|
|
243
|
+
style:height="{indicatorHeight}px"
|
|
244
|
+
aria-hidden="true"
|
|
245
|
+
data-pull-indicator
|
|
246
|
+
data-armed={armed ? "true" : "false"}
|
|
247
|
+
>
|
|
248
|
+
<div class="flex h-[64px] shrink-0 items-center gap-[8px]">
|
|
249
|
+
{#if refreshing}
|
|
250
|
+
<Spinner size="md" />
|
|
251
|
+
<span>{text.refreshing}</span>
|
|
252
|
+
{:else}
|
|
253
|
+
<ArrowDown
|
|
254
|
+
size={16}
|
|
255
|
+
class={cn("transition-transform duration-150 motion-reduce:transition-none", armed && "rotate-180")}
|
|
256
|
+
/>
|
|
257
|
+
<span>{armed ? text.release : text.pull}</span>
|
|
258
|
+
{/if}
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
{@render children?.()}
|
|
263
|
+
</div>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import { type PullToRefreshStrings } from "../util/pull-to-refresh.js";
|
|
4
|
+
/**
|
|
5
|
+
* A list that reloads when it is pulled down from its top, on a touch
|
|
6
|
+
* screen.
|
|
7
|
+
*
|
|
8
|
+
* The pull is a shortcut. The same refresh is a button at the top of the
|
|
9
|
+
* region, out of sight until keyboard focus reaches it, and named for a
|
|
10
|
+
* screen reader; "Refreshing" and "Updated" are announced, and the
|
|
11
|
+
* region is `aria-busy` meanwhile.
|
|
12
|
+
*
|
|
13
|
+
* It only acts while what scrolls the list (the page, or the nearest
|
|
14
|
+
* scrolling ancestor, such as the content of an `AppShell`) is at its
|
|
15
|
+
* top, and never takes an ordinary scroll. The indicator is in the flow
|
|
16
|
+
* of the region, above the list, so under an app bar it comes out below
|
|
17
|
+
* the bar.
|
|
18
|
+
*
|
|
19
|
+
* ```svelte
|
|
20
|
+
* <PullToRefresh onrefresh={() => loadRounds()}>
|
|
21
|
+
* <List items={rounds} />
|
|
22
|
+
* </PullToRefresh>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
type Props = Omit<HTMLAttributes<HTMLDivElement>, "class" | "children" | "aria-busy"> & {
|
|
26
|
+
/**
|
|
27
|
+
* Reloads the list. Return the promise: the indicator stays until it
|
|
28
|
+
* settles. A promise that rejects ends the refresh too, and nothing
|
|
29
|
+
* is announced as updated; say what went wrong yourself.
|
|
30
|
+
*/
|
|
31
|
+
onrefresh?: () => Promise<void> | void;
|
|
32
|
+
/** Whether a refresh is running. Bindable: set it to show the indicator for a refresh of your own. */
|
|
33
|
+
refreshing?: boolean;
|
|
34
|
+
/** No pull and no button. */
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
/** How far the indicator has to come out for letting go to refresh, in px. */
|
|
37
|
+
threshold?: number;
|
|
38
|
+
/**
|
|
39
|
+
* The button that refreshes without the gesture. Without it the pull
|
|
40
|
+
* is the only way this component offers, and the app has to give
|
|
41
|
+
* another (WCAG 2.5.1).
|
|
42
|
+
*/
|
|
43
|
+
showButton?: boolean;
|
|
44
|
+
/** The words the component says by itself, for another language. */
|
|
45
|
+
strings?: Partial<PullToRefreshStrings>;
|
|
46
|
+
class?: string;
|
|
47
|
+
/** The list. */
|
|
48
|
+
children?: Snippet;
|
|
49
|
+
};
|
|
50
|
+
declare const PullToRefresh: import("svelte").Component<Props, {}, "refreshing">;
|
|
51
|
+
type PullToRefresh = ReturnType<typeof PullToRefresh>;
|
|
52
|
+
export default PullToRefresh;
|
|
@@ -4,9 +4,13 @@
|
|
|
4
4
|
RADIO_GROUP_CONTROL_SHELL,
|
|
5
5
|
RADIO_GROUP_OPTION_LABEL_ROW,
|
|
6
6
|
RADIO_GROUP_RING_OVERLAY,
|
|
7
|
+
SELECTION_CONTROL_INPUT,
|
|
7
8
|
} from "../atoms/selection-control.styles";
|
|
9
|
+
import type { HTMLFieldsetAttributes } from "svelte/elements";
|
|
8
10
|
import { generateId } from "../util/ssr-safe.js";
|
|
9
11
|
import { SvelteMap } from "svelte/reactivity";
|
|
12
|
+
import { cn } from "../util/cn.js";
|
|
13
|
+
import { resetValueOf, groupBinding } from "../util/hydration.js";
|
|
10
14
|
|
|
11
15
|
export type RadioGroupOption = {
|
|
12
16
|
value: string;
|
|
@@ -15,22 +19,35 @@
|
|
|
15
19
|
description?: string;
|
|
16
20
|
};
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
/** Other attributes (`id`, `data-*`, `aria-*`, ...) land on the `<fieldset>`. */
|
|
23
|
+
type Props = Omit<HTMLFieldsetAttributes, "class" | "name" | "disabled"> & {
|
|
24
|
+
/** Extra classes for the host element. */
|
|
25
|
+
class?: string;
|
|
19
26
|
options: RadioGroupOption[];
|
|
20
27
|
/** Selected value; `bind:value`. Use `undefined` for no selection. */
|
|
21
28
|
value?: string | undefined;
|
|
22
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* The selection to start with when `value` is `undefined` as the
|
|
31
|
+
* group is created. Applied once: it does not come back when the
|
|
32
|
+
* value is set to `undefined` later, and it never replaces a choice.
|
|
33
|
+
*/
|
|
23
34
|
defaultValue?: string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Name the value is submitted under in a form. Without a name the
|
|
37
|
+
* group is not part of the form around it: it submits nothing and a
|
|
38
|
+
* form reset leaves it alone.
|
|
39
|
+
*/
|
|
24
40
|
name?: string;
|
|
25
41
|
disabled?: boolean;
|
|
26
42
|
legend?: string;
|
|
27
43
|
label?: string;
|
|
28
|
-
}
|
|
44
|
+
};
|
|
29
45
|
|
|
30
46
|
let {
|
|
47
|
+
class: className = "",
|
|
31
48
|
options,
|
|
32
49
|
defaultValue,
|
|
33
|
-
value = $bindable(
|
|
50
|
+
value = $bindable(),
|
|
34
51
|
name: nameProp,
|
|
35
52
|
disabled = false,
|
|
36
53
|
legend = "",
|
|
@@ -38,6 +55,21 @@
|
|
|
38
55
|
...restProps
|
|
39
56
|
}: Props = $props();
|
|
40
57
|
|
|
58
|
+
// No fallback on the bindable prop: with one, `bind:value={undefined}`
|
|
59
|
+
// (which the prop's own documentation names as "no selection") throws
|
|
60
|
+
// `props_invalid_value` and the page never hydrates. The default is
|
|
61
|
+
// applied once, here, so the server renders it too. A choice made in the
|
|
62
|
+
// server markup before hydration is taken in after this and wins.
|
|
63
|
+
(() => {
|
|
64
|
+
if (value === undefined && defaultValue !== undefined) value = defaultValue;
|
|
65
|
+
})();
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The radios always share a name, the caller's or one made here: without
|
|
69
|
+
* one they are not a group to the browser. With a name made here they are
|
|
70
|
+
* kept out of any form around them (`form` names a form that does not
|
|
71
|
+
* exist): it used to be submitted as `radiogroup-…`, a field nobody named.
|
|
72
|
+
*/
|
|
41
73
|
const fallbackName = generateId("radiogroup");
|
|
42
74
|
const groupName = $derived(nameProp || fallbackName);
|
|
43
75
|
const legendText = $derived(legend || label);
|
|
@@ -71,13 +103,24 @@
|
|
|
71
103
|
return option.value === fallbackValue ? 0 : -1;
|
|
72
104
|
}
|
|
73
105
|
|
|
74
|
-
function handleChange(event: Event) {
|
|
75
|
-
if (disabled) return;
|
|
76
|
-
const target = event.target as HTMLInputElement;
|
|
77
|
-
value = target.value;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
106
|
const elementsByValue = new SvelteMap<string, HTMLInputElement>();
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The radios are bound, so an option picked before the page hydrated is
|
|
110
|
+
* kept: Svelte's binding hands it over here instead of overwriting it
|
|
111
|
+
* (see util/hydration.ts). A form reset empties the selection, as it empties
|
|
112
|
+
* a bound native input.
|
|
113
|
+
*/
|
|
114
|
+
const chosen = groupBinding<string>(
|
|
115
|
+
() => value,
|
|
116
|
+
(next) => {
|
|
117
|
+
if (!disabled) value = next;
|
|
118
|
+
},
|
|
119
|
+
() => {
|
|
120
|
+
if (!disabled) value = resetValueOf<string>(elementsByValue.values());
|
|
121
|
+
},
|
|
122
|
+
);
|
|
123
|
+
|
|
81
124
|
function registerRadio(valueKey: string) {
|
|
82
125
|
return (node: HTMLInputElement) => {
|
|
83
126
|
elementsByValue.set(valueKey, node);
|
|
@@ -150,7 +193,7 @@
|
|
|
150
193
|
</script>
|
|
151
194
|
|
|
152
195
|
<fieldset
|
|
153
|
-
class="space-y-3"
|
|
196
|
+
class={cn("space-y-3", className)}
|
|
154
197
|
aria-disabled={disabled ? "true" : undefined}
|
|
155
198
|
onkeydown={handleKeydown}
|
|
156
199
|
{...restProps}
|
|
@@ -164,18 +207,17 @@
|
|
|
164
207
|
<div class="space-y-3">
|
|
165
208
|
{#each options as option (option.value)}
|
|
166
209
|
{@const optionDisabled = isOptionDisabled(option)}
|
|
167
|
-
{@const isChecked = value === option.value}
|
|
168
210
|
<label class={optionLabelWrapperClasses}>
|
|
169
211
|
<span class={radioControlShellClasses}>
|
|
170
212
|
<input
|
|
171
213
|
type="radio"
|
|
172
214
|
name={groupName}
|
|
215
|
+
form={nameProp ? undefined : groupName}
|
|
173
216
|
value={option.value}
|
|
174
|
-
|
|
217
|
+
bind:group={chosen.value}
|
|
175
218
|
disabled={optionDisabled}
|
|
176
219
|
tabindex={tabIndexFor(option)}
|
|
177
|
-
class=
|
|
178
|
-
onchange={handleChange}
|
|
220
|
+
class={SELECTION_CONTROL_INPUT}
|
|
179
221
|
{@attach registerRadio(option.value)}
|
|
180
222
|
/>
|
|
181
223
|
<span class={radioRingOverlayClasses}></span>
|
|
@@ -1,20 +1,33 @@
|
|
|
1
|
+
import type { HTMLFieldsetAttributes } from "svelte/elements";
|
|
1
2
|
export type RadioGroupOption = {
|
|
2
3
|
value: string;
|
|
3
4
|
label: string;
|
|
4
5
|
disabled?: boolean;
|
|
5
6
|
description?: string;
|
|
6
7
|
};
|
|
7
|
-
|
|
8
|
+
/** Other attributes (`id`, `data-*`, `aria-*`, ...) land on the `<fieldset>`. */
|
|
9
|
+
type Props = Omit<HTMLFieldsetAttributes, "class" | "name" | "disabled"> & {
|
|
10
|
+
/** Extra classes for the host element. */
|
|
11
|
+
class?: string;
|
|
8
12
|
options: RadioGroupOption[];
|
|
9
13
|
/** Selected value; `bind:value`. Use `undefined` for no selection. */
|
|
10
14
|
value?: string | undefined;
|
|
11
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* The selection to start with when `value` is `undefined` as the
|
|
17
|
+
* group is created. Applied once: it does not come back when the
|
|
18
|
+
* value is set to `undefined` later, and it never replaces a choice.
|
|
19
|
+
*/
|
|
12
20
|
defaultValue?: string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Name the value is submitted under in a form. Without a name the
|
|
23
|
+
* group is not part of the form around it: it submits nothing and a
|
|
24
|
+
* form reset leaves it alone.
|
|
25
|
+
*/
|
|
13
26
|
name?: string;
|
|
14
27
|
disabled?: boolean;
|
|
15
28
|
legend?: string;
|
|
16
29
|
label?: string;
|
|
17
|
-
}
|
|
30
|
+
};
|
|
18
31
|
declare const RadioGroup: import("svelte").Component<Props, {}, "value">;
|
|
19
32
|
type RadioGroup = ReturnType<typeof RadioGroup>;
|
|
20
33
|
export default RadioGroup;
|