zabi-components 8.0.0 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1924 -0
- package/README.md +243 -10
- package/THEME.md +149 -332
- package/THEMING.md +1192 -266
- package/dist/atoms/ActionPanel.svelte +15 -5
- package/dist/atoms/Avatar.svelte +104 -0
- package/dist/atoms/Avatar.svelte.d.ts +34 -0
- package/dist/atoms/Badge.svelte +36 -7
- package/dist/atoms/Badge.svelte.d.ts +2 -2
- package/dist/atoms/Button.svelte +177 -27
- package/dist/atoms/Button.svelte.d.ts +30 -2
- package/dist/atoms/Card.svelte +4 -4
- package/dist/atoms/CardHeader.svelte +16 -4
- package/dist/atoms/Checkbox.svelte +48 -21
- package/dist/atoms/Checkbox.svelte.d.ts +4 -2
- package/dist/atoms/CodeBlock.svelte +20 -2
- package/dist/atoms/CodeBlock.svelte.d.ts +4 -0
- package/dist/atoms/ColorPicker.svelte +259 -49
- package/dist/atoms/ColorPicker.svelte.d.ts +3 -0
- package/dist/atoms/Container.svelte +16 -8
- package/dist/atoms/DateField.svelte +107 -0
- package/dist/atoms/DateField.svelte.d.ts +53 -0
- 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 +37 -5
- package/dist/atoms/Heading.svelte.d.ts +7 -0
- package/dist/atoms/IconButton.svelte +220 -24
- package/dist/atoms/IconButton.svelte.d.ts +49 -4
- package/dist/atoms/Input.svelte +253 -52
- package/dist/atoms/Input.svelte.d.ts +32 -2
- package/dist/atoms/List.svelte +4 -1
- package/dist/atoms/ListItem.svelte +44 -11
- package/dist/atoms/ListItem.svelte.d.ts +5 -0
- package/dist/atoms/Progress.svelte +27 -8
- package/dist/atoms/Progress.svelte.d.ts +4 -0
- package/dist/atoms/Radio.svelte +19 -3
- package/dist/atoms/Radio.svelte.d.ts +4 -2
- package/dist/atoms/Rating.svelte +494 -0
- package/dist/atoms/Rating.svelte.d.ts +56 -0
- package/dist/atoms/Select.svelte +433 -91
- package/dist/atoms/Select.svelte.d.ts +49 -3
- package/dist/atoms/SelectionControl.svelte +94 -17
- package/dist/atoms/SelectionControl.svelte.d.ts +4 -3
- package/dist/atoms/Skeleton.svelte +1 -1
- 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 +151 -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 +23 -11
- package/dist/atoms/Text.svelte.d.ts +6 -3
- package/dist/atoms/Textarea.svelte +55 -44
- package/dist/atoms/Textarea.svelte.d.ts +14 -2
- package/dist/atoms/ThemeToggle.svelte +223 -44
- package/dist/atoms/ThemeToggle.svelte.d.ts +26 -3
- package/dist/atoms/TimeField.svelte +108 -0
- package/dist/atoms/TimeField.svelte.d.ts +54 -0
- package/dist/atoms/Toast.svelte +17 -4
- package/dist/atoms/Toast.svelte.d.ts +2 -0
- package/dist/atoms/Toggle.svelte +41 -8
- package/dist/atoms/Toggle.svelte.d.ts +11 -2
- package/dist/atoms/Tooltip.svelte +508 -23
- package/dist/atoms/Tooltip.svelte.d.ts +11 -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 +80 -2
- 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 +5 -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/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/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 +80 -2
- package/dist/index.js +57 -2
- package/dist/molecules/Alert.svelte +33 -5
- package/dist/molecules/Alert.svelte.d.ts +2 -0
- 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 +16 -4
- package/dist/molecules/ComponentDemo.svelte.d.ts +3 -0
- package/dist/molecules/ConfirmDialog.svelte +253 -0
- package/dist/molecules/ConfirmDialog.svelte.d.ts +55 -0
- package/dist/molecules/ContactForm.svelte +34 -17
- package/dist/molecules/ContactForm.svelte.d.ts +8 -0
- package/dist/molecules/Drawer.svelte +394 -0
- package/dist/molecules/Drawer.svelte.d.ts +55 -0
- package/dist/molecules/Dropdown.svelte +509 -48
- package/dist/molecules/Dropdown.svelte.d.ts +45 -6
- package/dist/molecules/DropdownItem.svelte +122 -0
- package/dist/molecules/DropdownItem.svelte.d.ts +28 -0
- package/dist/molecules/EmptyState.svelte +55 -10
- package/dist/molecules/EmptyState.svelte.d.ts +8 -0
- package/dist/molecules/FormField.svelte +9 -1
- package/dist/molecules/FormField.svelte.d.ts +2 -0
- package/dist/molecules/Header.svelte +1 -1
- package/dist/molecules/ImageUpload.svelte +383 -70
- package/dist/molecules/ImageUpload.svelte.d.ts +47 -2
- package/dist/molecules/MediaGrid.svelte +527 -0
- package/dist/molecules/MediaGrid.svelte.d.ts +77 -0
- package/dist/molecules/Modal.svelte +288 -72
- package/dist/molecules/Modal.svelte.d.ts +51 -2
- package/dist/molecules/NavigationMenuContent.svelte +58 -1
- package/dist/molecules/NavigationMenuItem.svelte +0 -1
- package/dist/molecules/NavigationMenuLink.svelte +1 -1
- package/dist/molecules/NavigationMenuList.svelte +10 -3
- package/dist/molecules/NavigationMenuTrigger.svelte +2 -2
- package/dist/molecules/Page.svelte +32 -2
- package/dist/molecules/Page.svelte.d.ts +11 -0
- package/dist/molecules/PhotoGrid.svelte +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 +22 -10
- package/dist/molecules/PropsTable.svelte.d.ts +3 -0
- package/dist/molecules/PullToRefresh.svelte +263 -0
- package/dist/molecules/PullToRefresh.svelte.d.ts +52 -0
- package/dist/molecules/RadioGroup.svelte +52 -14
- package/dist/molecules/RadioGroup.svelte.d.ts +14 -3
- package/dist/molecules/Section.svelte +1 -1
- package/dist/molecules/SegmentedControl.svelte +323 -0
- package/dist/molecules/SegmentedControl.svelte.d.ts +34 -0
- package/dist/molecules/SidebarBrandHeader.svelte +11 -1
- package/dist/molecules/SidebarBrandHeader.svelte.d.ts +3 -0
- package/dist/molecules/SidebarFooter.svelte +29 -6
- package/dist/molecules/SidebarFooter.svelte.d.ts +3 -0
- package/dist/molecules/SlideUp.svelte +220 -61
- package/dist/molecules/SlideUp.svelte.d.ts +26 -0
- 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 +233 -9
- package/dist/molecules/Tabs.svelte.d.ts +7 -0
- package/dist/molecules/Toaster.svelte +350 -5
- package/dist/molecules/Toaster.svelte.d.ts +95 -2
- package/dist/molecules/ToasterToast.svelte +253 -67
- package/dist/molecules/ToasterToast.svelte.d.ts +9 -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 +107 -12
- package/dist/organisms/SidebarAccountPanel.svelte.d.ts +19 -0
- package/dist/organisms/SidebarNavigation.svelte +96 -15
- package/dist/organisms/SidebarNavigation.svelte.d.ts +29 -1
- package/dist/organisms/SidebarPanel.svelte +31 -10
- package/dist/organisms/SidebarShell.svelte +162 -11
- package/dist/organisms/SidebarShell.svelte.d.ts +56 -2
- package/dist/organisms/TopNavbar.svelte +256 -31
- package/dist/organisms/TopNavbar.svelte.d.ts +26 -0
- package/dist/organisms/index.d.ts +5 -0
- package/dist/organisms/index.js +3 -0
- package/dist/types/components.d.ts +4 -0
- package/dist/types/components.d.ts.map +1 -1
- package/dist/types/index.d.ts +605 -25
- package/dist/types/index.d.ts.map +1 -1
- 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/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/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 +543 -241
- package/dist/zabi-components-theme-dark.css +543 -241
- package/dist/zabi-components-theme-only.css +1584 -367
- package/dist/zabi-components-theme.css +1584 -367
- package/dist/zabi-components.css +3885 -518
- package/docs/lucide-icons.md +40 -17
- package/docs/theme-imports.md +81 -11
- package/package.json +35 -8
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Component } from "svelte";
|
|
2
|
+
/** An icon component, as `@lucide/svelte` icons are. */
|
|
3
|
+
export type SegmentedControlIcon = Component<{
|
|
4
|
+
size?: number;
|
|
5
|
+
class?: string;
|
|
6
|
+
}>;
|
|
7
|
+
/** One entry of SegmentedControl's `options`. */
|
|
8
|
+
export interface SegmentedControlOption {
|
|
9
|
+
value: string;
|
|
10
|
+
label: string;
|
|
11
|
+
/** Rendered before the label. Decorative: the label names the segment. */
|
|
12
|
+
icon?: SegmentedControlIcon;
|
|
13
|
+
/** A disabled segment cannot be chosen, and the arrow keys skip it. */
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every word a `Select` says by itself, shown or only read out. An app in
|
|
3
|
+
* another language passes its own through `strings`; what it leaves out stays
|
|
4
|
+
* as it is here. The older props for six of them (`placeholder`,
|
|
5
|
+
* `searchPlaceholder`, `noResultsText`, `loadingText`, `emptyStateTitle`,
|
|
6
|
+
* `emptyStateDescription`) still work, and win over `strings`.
|
|
7
|
+
*/
|
|
8
|
+
export interface SelectStrings {
|
|
9
|
+
/** Shown in the field while nothing is chosen, and the first, empty option of the native select. */
|
|
10
|
+
placeholder: string;
|
|
11
|
+
/** Placeholder and accessible name of the search field above the options. */
|
|
12
|
+
searchPlaceholder: string;
|
|
13
|
+
/** Shown in the list when the search matches nothing. */
|
|
14
|
+
noResults: string;
|
|
15
|
+
/** Shown in the field and in the list while `isLoading`. */
|
|
16
|
+
loading: string;
|
|
17
|
+
/** Heading of the box shown in the list when there are no options at all. */
|
|
18
|
+
emptyTitle: string;
|
|
19
|
+
/** The line under that heading. */
|
|
20
|
+
emptyDescription: string;
|
|
21
|
+
/** Accessible name of the list of options. */
|
|
22
|
+
listLabel: string;
|
|
23
|
+
/** Accessible name of the close button of the sheet the list opens in on a phone. */
|
|
24
|
+
closeLabel: string;
|
|
25
|
+
/** Accessible name of that sheet's grip while its button takes the sheet up to full height. */
|
|
26
|
+
expandLabel: string;
|
|
27
|
+
/** The same, while it takes the sheet back down. */
|
|
28
|
+
collapseLabel: string;
|
|
29
|
+
}
|
|
30
|
+
export declare const DEFAULT_SELECT_STRINGS: SelectStrings;
|
|
31
|
+
/** How a Select shows its options. See the `presentation` prop. */
|
|
32
|
+
export type SelectPresentation = "auto" | "popover" | "sheet" | "native";
|
|
33
|
+
/** Marks the native `<select>` a Select renders, so a choice made in it before the page hydrates can be found. */
|
|
34
|
+
export declare const NATIVE_SELECT_ATTRIBUTE = "data-zabi-select";
|
|
35
|
+
/**
|
|
36
|
+
* What the visitor (or the browser, restoring a form) chose in `element`
|
|
37
|
+
* before its component mounted; `undefined` when it still has the value the
|
|
38
|
+
* server rendered, and for an element this module never saw.
|
|
39
|
+
*/
|
|
40
|
+
export declare function choiceBeforeMount(element: Element): string | undefined;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export const DEFAULT_SELECT_STRINGS = {
|
|
2
|
+
placeholder: "Select an option",
|
|
3
|
+
searchPlaceholder: "Search options",
|
|
4
|
+
noResults: "No results found",
|
|
5
|
+
loading: "Loading options...",
|
|
6
|
+
emptyTitle: "No options available",
|
|
7
|
+
emptyDescription: "Add an option to start making selections.",
|
|
8
|
+
listLabel: "Select options",
|
|
9
|
+
closeLabel: "Close",
|
|
10
|
+
expandLabel: "Expand",
|
|
11
|
+
collapseLabel: "Collapse",
|
|
12
|
+
};
|
|
13
|
+
/** Marks the native `<select>` a Select renders, so a choice made in it before the page hydrates can be found. */
|
|
14
|
+
export const NATIVE_SELECT_ATTRIBUTE = "data-zabi-select";
|
|
15
|
+
/**
|
|
16
|
+
* What a visitor chose in each server-rendered native select before the
|
|
17
|
+
* component took it over.
|
|
18
|
+
*
|
|
19
|
+
* The server's HTML carries a real `<select>`, and it works at once: a
|
|
20
|
+
* visitor can choose from it while the scripts are still on their way, and
|
|
21
|
+
* the browser may put an earlier choice back into it after a reload or a
|
|
22
|
+
* step back. When the component then hydrates it renders the value it was
|
|
23
|
+
* given, which would silently undo that. So when this module loads, which is
|
|
24
|
+
* before anything hydrates, each select's value is noted beside the value
|
|
25
|
+
* the server rendered it with (its `selected` option, or else its first),
|
|
26
|
+
* and every change after that is noted too. The component asks for its own
|
|
27
|
+
* element's when it mounts.
|
|
28
|
+
*
|
|
29
|
+
* Only a value that differs from the rendered one is a choice. A select that
|
|
30
|
+
* nobody touched is not, whatever it shows: it used to be compared with the
|
|
31
|
+
* component's prop instead, and a value with no option of its own (its
|
|
32
|
+
* options still loading, or simply not among them) was replaced by whatever
|
|
33
|
+
* the select happened to fall back to.
|
|
34
|
+
*/
|
|
35
|
+
const seenBeforeMount = new WeakMap();
|
|
36
|
+
/** The value a select has when nobody has touched it: that of the option with the `selected` attribute, or of the first. */
|
|
37
|
+
function renderedValue(element) {
|
|
38
|
+
const options = [...element.options];
|
|
39
|
+
return (options.find((option) => option.defaultSelected) ?? options[0])?.value ?? "";
|
|
40
|
+
}
|
|
41
|
+
if (typeof document !== "undefined") {
|
|
42
|
+
const selector = `select[${NATIVE_SELECT_ATTRIBUTE}]`;
|
|
43
|
+
for (const element of document.querySelectorAll(selector)) {
|
|
44
|
+
seenBeforeMount.set(element, { rendered: renderedValue(element), value: element.value });
|
|
45
|
+
}
|
|
46
|
+
document.addEventListener("change", (event) => {
|
|
47
|
+
const target = event.target;
|
|
48
|
+
if (target instanceof HTMLSelectElement && target.matches(selector)) {
|
|
49
|
+
const seen = seenBeforeMount.get(target);
|
|
50
|
+
if (seen)
|
|
51
|
+
seen.value = target.value;
|
|
52
|
+
}
|
|
53
|
+
}, true);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* What the visitor (or the browser, restoring a form) chose in `element`
|
|
57
|
+
* before its component mounted; `undefined` when it still has the value the
|
|
58
|
+
* server rendered, and for an element this module never saw.
|
|
59
|
+
*/
|
|
60
|
+
export function choiceBeforeMount(element) {
|
|
61
|
+
const seen = seenBeforeMount.get(element);
|
|
62
|
+
return seen && seen.value !== seen.rendered ? seen.value : undefined;
|
|
63
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dragging a bottom sheet with a finger or a pointer. Shared by `BottomSheet`
|
|
3
|
+
* and `SlideUp`, so the two cannot disagree on what a swipe is.
|
|
4
|
+
*
|
|
5
|
+
* It only reports the gesture: how far the pointer has travelled since the
|
|
6
|
+
* drag began and how fast it was going at the end. What that means (move the
|
|
7
|
+
* panel, snap, close) is the caller's.
|
|
8
|
+
*/
|
|
9
|
+
export interface SheetDragCallbacks {
|
|
10
|
+
/** Asked when a gesture could begin. Return false to leave it alone. */
|
|
11
|
+
canStart?: () => boolean;
|
|
12
|
+
onStart?: () => void;
|
|
13
|
+
/** `distance` in px since the drag began; positive is down. */
|
|
14
|
+
onMove: (distance: number) => void;
|
|
15
|
+
/** `velocity` in px per ms over the last moments of the drag; positive is down. */
|
|
16
|
+
onEnd: (distance: number, velocity: number, event: Event) => void;
|
|
17
|
+
/** The browser took the gesture back (a call came in, the pointer was lost). */
|
|
18
|
+
onCancel?: () => void;
|
|
19
|
+
}
|
|
20
|
+
export interface SheetDragTargets {
|
|
21
|
+
/**
|
|
22
|
+
* The grip and the area around it. A drag that starts here moves the
|
|
23
|
+
* sheet in either direction. Give it `touch-action: none`.
|
|
24
|
+
*/
|
|
25
|
+
handleZone: HTMLElement;
|
|
26
|
+
/**
|
|
27
|
+
* The scrolling content. A touch that starts here scrolls it; only a
|
|
28
|
+
* downward swipe that begins with the content at its top moves the sheet.
|
|
29
|
+
*/
|
|
30
|
+
scroller?: HTMLElement | null;
|
|
31
|
+
}
|
|
32
|
+
/** Movement under this many px is a press, not a drag. */
|
|
33
|
+
export declare const DRAG_SLOP = 6;
|
|
34
|
+
/**
|
|
35
|
+
* When a pointer or touch event happened: its own `timeStamp`, which is when
|
|
36
|
+
* the finger moved. The time the handler runs is later by however busy the
|
|
37
|
+
* page is, and unevenly so, which made a flick on a janky frame (or a loaded
|
|
38
|
+
* machine) measure slower than it was and spring back. An event without a
|
|
39
|
+
* usable stamp gets the clock.
|
|
40
|
+
*/
|
|
41
|
+
export declare function timeOf(event: Event): number;
|
|
42
|
+
/**
|
|
43
|
+
* How fast a pointer was moving over the last moments of a gesture, on one
|
|
44
|
+
* axis. Also used by `PhotoViewer`, for both axes.
|
|
45
|
+
*/
|
|
46
|
+
export declare function createVelocityTracker(): {
|
|
47
|
+
reset(y: number, time: number): void;
|
|
48
|
+
add(y: number, time: number): void;
|
|
49
|
+
velocity(): number;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Listens for drags on a sheet. Call it when the sheet is open, in the
|
|
53
|
+
* browser, and call the returned function when it closes.
|
|
54
|
+
*/
|
|
55
|
+
export declare function attachSheetDrag({ handleZone, scroller }: SheetDragTargets, callbacks: SheetDragCallbacks): () => void;
|
|
56
|
+
/** A flick: faster than this, in px per ms, and the direction decides, not the distance. */
|
|
57
|
+
export declare const FLICK_VELOCITY = 0.5;
|
|
58
|
+
/** True where the user has asked for less motion, or where that cannot be asked. */
|
|
59
|
+
export declare function prefersReducedMotion(): boolean;
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dragging a bottom sheet with a finger or a pointer. Shared by `BottomSheet`
|
|
3
|
+
* and `SlideUp`, so the two cannot disagree on what a swipe is.
|
|
4
|
+
*
|
|
5
|
+
* It only reports the gesture: how far the pointer has travelled since the
|
|
6
|
+
* drag began and how fast it was going at the end. What that means (move the
|
|
7
|
+
* panel, snap, close) is the caller's.
|
|
8
|
+
*/
|
|
9
|
+
/** Movement under this many px is a press, not a drag. */
|
|
10
|
+
export const DRAG_SLOP = 6;
|
|
11
|
+
/** Controls in the handle zone that keep their own press, except the grip itself. */
|
|
12
|
+
const INTERACTIVE = "button, a[href], input, select, textarea, [data-sheet-no-drag]";
|
|
13
|
+
const GRIP = "[data-sheet-grip]";
|
|
14
|
+
/** The clock of this page, for when an event's own time cannot be used. */
|
|
15
|
+
const now = () => (typeof performance !== "undefined" ? performance.now() : Date.now());
|
|
16
|
+
/**
|
|
17
|
+
* When a pointer or touch event happened: its own `timeStamp`, which is when
|
|
18
|
+
* the finger moved. The time the handler runs is later by however busy the
|
|
19
|
+
* page is, and unevenly so, which made a flick on a janky frame (or a loaded
|
|
20
|
+
* machine) measure slower than it was and spring back. An event without a
|
|
21
|
+
* usable stamp gets the clock.
|
|
22
|
+
*/
|
|
23
|
+
export function timeOf(event) {
|
|
24
|
+
const stamp = event.timeStamp;
|
|
25
|
+
return typeof stamp === "number" && stamp > 0 ? stamp : now();
|
|
26
|
+
}
|
|
27
|
+
/** How far back the velocity looks, in ms. */
|
|
28
|
+
const VELOCITY_WINDOW = 100;
|
|
29
|
+
/**
|
|
30
|
+
* How fast a pointer was moving over the last moments of a gesture, on one
|
|
31
|
+
* axis. Also used by `PhotoViewer`, for both axes.
|
|
32
|
+
*/
|
|
33
|
+
export function createVelocityTracker() {
|
|
34
|
+
/** `time` is the event's; `clock` is when it was handled. */
|
|
35
|
+
let samples = [];
|
|
36
|
+
return {
|
|
37
|
+
reset(y, time) {
|
|
38
|
+
samples = [{ time, clock: now(), y }];
|
|
39
|
+
},
|
|
40
|
+
add(y, time) {
|
|
41
|
+
samples.push({ time, clock: now(), y });
|
|
42
|
+
while (samples.length > 2 && time - samples[0].time > VELOCITY_WINDOW)
|
|
43
|
+
samples.shift();
|
|
44
|
+
},
|
|
45
|
+
velocity() {
|
|
46
|
+
if (samples.length < 2)
|
|
47
|
+
return 0;
|
|
48
|
+
const first = samples[0];
|
|
49
|
+
const last = samples[samples.length - 1];
|
|
50
|
+
// Some browsers hand every event of one frame the same stamp:
|
|
51
|
+
// such a flick has no duration by the events, and is timed by
|
|
52
|
+
// the clock instead.
|
|
53
|
+
const byEvents = last.time - first.time;
|
|
54
|
+
const elapsed = byEvents > 0 ? byEvents : last.clock - first.clock;
|
|
55
|
+
return elapsed > 0 ? (last.y - first.y) / elapsed : 0;
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Listens for drags on a sheet. Call it when the sheet is open, in the
|
|
61
|
+
* browser, and call the returned function when it closes.
|
|
62
|
+
*/
|
|
63
|
+
export function attachSheetDrag({ handleZone, scroller }, callbacks) {
|
|
64
|
+
const tracker = createVelocityTracker();
|
|
65
|
+
const allowed = () => callbacks.canStart?.() ?? true;
|
|
66
|
+
// --- The handle zone: pointer events, so a mouse and a pen drag it too.
|
|
67
|
+
let pointerId = null;
|
|
68
|
+
let pointerStart = 0;
|
|
69
|
+
let pointerDragging = false;
|
|
70
|
+
function swallowClick(event) {
|
|
71
|
+
// The click that ends a drag on the grip is not a press of the grip.
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
event.stopPropagation();
|
|
74
|
+
}
|
|
75
|
+
function onPointerDown(event) {
|
|
76
|
+
if (pointerId !== null || touchDragging)
|
|
77
|
+
return;
|
|
78
|
+
if (event.pointerType === "mouse" && event.button !== 0)
|
|
79
|
+
return;
|
|
80
|
+
const target = event.target;
|
|
81
|
+
if (target?.closest(INTERACTIVE) && !target.closest(GRIP))
|
|
82
|
+
return;
|
|
83
|
+
if (!allowed())
|
|
84
|
+
return;
|
|
85
|
+
pointerId = event.pointerId;
|
|
86
|
+
pointerStart = event.clientY;
|
|
87
|
+
pointerDragging = false;
|
|
88
|
+
tracker.reset(event.clientY, timeOf(event));
|
|
89
|
+
// Not captured yet. A captured pointer delivers its `pointerup` and
|
|
90
|
+
// the click that follows to the handle zone, not to what was
|
|
91
|
+
// pressed: a mouse click on the grip then never reached the grip's
|
|
92
|
+
// button. It is captured once the press has become a drag. A mouse
|
|
93
|
+
// can leave the zone before that, so its moves are followed on the
|
|
94
|
+
// window meanwhile; a finger stays with the element it went down on.
|
|
95
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
96
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
97
|
+
window.addEventListener("pointercancel", onPointerCancel);
|
|
98
|
+
}
|
|
99
|
+
function stopFollowing() {
|
|
100
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
101
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
102
|
+
window.removeEventListener("pointercancel", onPointerCancel);
|
|
103
|
+
}
|
|
104
|
+
function onPointerMove(event) {
|
|
105
|
+
if (event.pointerId !== pointerId)
|
|
106
|
+
return;
|
|
107
|
+
const distance = event.clientY - pointerStart;
|
|
108
|
+
if (!pointerDragging) {
|
|
109
|
+
if (Math.abs(distance) < DRAG_SLOP)
|
|
110
|
+
return;
|
|
111
|
+
pointerDragging = true;
|
|
112
|
+
try {
|
|
113
|
+
handleZone.setPointerCapture(event.pointerId);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
/* a test DOM, or a pointer that is already gone */
|
|
117
|
+
}
|
|
118
|
+
// Measured from where the drag was recognised, so the sheet does
|
|
119
|
+
// not jump by the slop.
|
|
120
|
+
pointerStart = event.clientY;
|
|
121
|
+
tracker.reset(event.clientY, timeOf(event));
|
|
122
|
+
callbacks.onStart?.();
|
|
123
|
+
callbacks.onMove(0);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
tracker.add(event.clientY, timeOf(event));
|
|
127
|
+
callbacks.onMove(distance);
|
|
128
|
+
}
|
|
129
|
+
function finishPointer(event, cancelled) {
|
|
130
|
+
if (event.pointerId !== pointerId)
|
|
131
|
+
return;
|
|
132
|
+
const wasDragging = pointerDragging;
|
|
133
|
+
const distance = event.clientY - pointerStart;
|
|
134
|
+
pointerId = null;
|
|
135
|
+
pointerDragging = false;
|
|
136
|
+
stopFollowing();
|
|
137
|
+
try {
|
|
138
|
+
handleZone.releasePointerCapture(event.pointerId);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
/* never captured */
|
|
142
|
+
}
|
|
143
|
+
if (!wasDragging)
|
|
144
|
+
return;
|
|
145
|
+
if (cancelled) {
|
|
146
|
+
callbacks.onCancel?.();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
tracker.add(event.clientY, timeOf(event));
|
|
150
|
+
handleZone.addEventListener("click", swallowClick, { capture: true, once: true });
|
|
151
|
+
// No click follows a drag that ends off the element it began on.
|
|
152
|
+
setTimeout(() => handleZone.removeEventListener("click", swallowClick, true), 0);
|
|
153
|
+
callbacks.onEnd(distance, tracker.velocity(), event);
|
|
154
|
+
}
|
|
155
|
+
const onPointerUp = (event) => finishPointer(event, false);
|
|
156
|
+
const onPointerCancel = (event) => finishPointer(event, true);
|
|
157
|
+
// --- The content: touch events, because here the browser owns the
|
|
158
|
+
// gesture (it scrolls) until we take it, and only a touch listener that
|
|
159
|
+
// is not passive can take it.
|
|
160
|
+
let touchId = null;
|
|
161
|
+
let touchStart = 0;
|
|
162
|
+
let touchDragging = false;
|
|
163
|
+
let startedAtTop = false;
|
|
164
|
+
const touchOf = (event, list) => Array.from(list).find((touch) => touch.identifier === touchId);
|
|
165
|
+
function onTouchStart(event) {
|
|
166
|
+
if (touchId !== null || pointerId !== null || event.touches.length !== 1)
|
|
167
|
+
return;
|
|
168
|
+
const touch = event.touches[0];
|
|
169
|
+
touchId = touch.identifier;
|
|
170
|
+
touchStart = touch.clientY;
|
|
171
|
+
touchDragging = false;
|
|
172
|
+
startedAtTop = (scroller?.scrollTop ?? 0) <= 0;
|
|
173
|
+
}
|
|
174
|
+
function onTouchMove(event) {
|
|
175
|
+
const touch = touchOf(event, event.touches);
|
|
176
|
+
if (!touch)
|
|
177
|
+
return;
|
|
178
|
+
const distance = touch.clientY - touchStart;
|
|
179
|
+
if (!touchDragging) {
|
|
180
|
+
// Content that has scrolled, or a swipe upwards: the content's.
|
|
181
|
+
if (!startedAtTop || (scroller?.scrollTop ?? 0) > 0)
|
|
182
|
+
return;
|
|
183
|
+
if (distance < DRAG_SLOP || !allowed())
|
|
184
|
+
return;
|
|
185
|
+
touchDragging = true;
|
|
186
|
+
touchStart = touch.clientY;
|
|
187
|
+
tracker.reset(touch.clientY, timeOf(event));
|
|
188
|
+
callbacks.onStart?.();
|
|
189
|
+
if (event.cancelable)
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
callbacks.onMove(0);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// Ours now: no scrolling, no pull-to-refresh.
|
|
195
|
+
if (event.cancelable)
|
|
196
|
+
event.preventDefault();
|
|
197
|
+
tracker.add(touch.clientY, timeOf(event));
|
|
198
|
+
callbacks.onMove(distance);
|
|
199
|
+
}
|
|
200
|
+
function finishTouch(event, cancelled) {
|
|
201
|
+
const touch = touchOf(event, event.changedTouches);
|
|
202
|
+
if (!touch)
|
|
203
|
+
return;
|
|
204
|
+
const wasDragging = touchDragging;
|
|
205
|
+
const distance = touch.clientY - touchStart;
|
|
206
|
+
touchId = null;
|
|
207
|
+
touchDragging = false;
|
|
208
|
+
if (!wasDragging)
|
|
209
|
+
return;
|
|
210
|
+
if (cancelled) {
|
|
211
|
+
callbacks.onCancel?.();
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
tracker.add(touch.clientY, timeOf(event));
|
|
215
|
+
callbacks.onEnd(distance, tracker.velocity(), event);
|
|
216
|
+
}
|
|
217
|
+
const onTouchEnd = (event) => finishTouch(event, false);
|
|
218
|
+
const onTouchCancel = (event) => finishTouch(event, true);
|
|
219
|
+
handleZone.addEventListener("pointerdown", onPointerDown);
|
|
220
|
+
scroller?.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
221
|
+
scroller?.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
222
|
+
scroller?.addEventListener("touchend", onTouchEnd);
|
|
223
|
+
scroller?.addEventListener("touchcancel", onTouchCancel);
|
|
224
|
+
return () => {
|
|
225
|
+
handleZone.removeEventListener("pointerdown", onPointerDown);
|
|
226
|
+
stopFollowing();
|
|
227
|
+
handleZone.removeEventListener("click", swallowClick, true);
|
|
228
|
+
scroller?.removeEventListener("touchstart", onTouchStart);
|
|
229
|
+
scroller?.removeEventListener("touchmove", onTouchMove);
|
|
230
|
+
scroller?.removeEventListener("touchend", onTouchEnd);
|
|
231
|
+
scroller?.removeEventListener("touchcancel", onTouchCancel);
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/** A flick: faster than this, in px per ms, and the direction decides, not the distance. */
|
|
235
|
+
export const FLICK_VELOCITY = 0.5;
|
|
236
|
+
/** True where the user has asked for less motion, or where that cannot be asked. */
|
|
237
|
+
export function prefersReducedMotion() {
|
|
238
|
+
return (typeof window === "undefined" ||
|
|
239
|
+
typeof window.matchMedia !== "function" ||
|
|
240
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches);
|
|
241
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The words the sidebar components say by themselves. Each takes its own as
|
|
3
|
+
* `strings`; `SidebarNavigation` takes them all and hands the footer and the
|
|
4
|
+
* brand header theirs.
|
|
5
|
+
*/
|
|
6
|
+
/** `SidebarBrandHeader`. */
|
|
7
|
+
export interface SidebarBrandHeaderStrings {
|
|
8
|
+
/** The logo's alt text when neither `logoAlt` nor `brandName` is given. */
|
|
9
|
+
brandAlt: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const DEFAULT_SIDEBAR_BRAND_HEADER_STRINGS: SidebarBrandHeaderStrings;
|
|
12
|
+
/** `SidebarFooter`. */
|
|
13
|
+
export interface SidebarFooterStrings {
|
|
14
|
+
/** Accessible name of the footer. */
|
|
15
|
+
accountAndSettings: string;
|
|
16
|
+
/** Accessible name of the profile button in a collapsed rail. */
|
|
17
|
+
openAccountPanel: string;
|
|
18
|
+
/** The same button in an expanded sidebar, with the profile's name. */
|
|
19
|
+
openAccountPanelFor: (name: string) => string;
|
|
20
|
+
}
|
|
21
|
+
export declare const DEFAULT_SIDEBAR_FOOTER_STRINGS: SidebarFooterStrings;
|
|
22
|
+
/** `SidebarAccountPanel`. */
|
|
23
|
+
export interface SidebarAccountPanelStrings {
|
|
24
|
+
/** Accessible name of the panel. */
|
|
25
|
+
panelLabel: string;
|
|
26
|
+
/** The panel's heading. */
|
|
27
|
+
title: string;
|
|
28
|
+
/** Accessible name of the close button. */
|
|
29
|
+
closeLabel: string;
|
|
30
|
+
/** Accessible name of the list of rows. */
|
|
31
|
+
listLabel: string;
|
|
32
|
+
/** The first row, above the profile's name. */
|
|
33
|
+
account: string;
|
|
34
|
+
/** The row that switches the theme. */
|
|
35
|
+
theme: string;
|
|
36
|
+
/** That row's second line, in each mode. */
|
|
37
|
+
lightMode: string;
|
|
38
|
+
darkMode: string;
|
|
39
|
+
/** With `themeModes="three"`: the mode that follows the system. */
|
|
40
|
+
systemMode: string;
|
|
41
|
+
/** The badge on that row, in each mode. */
|
|
42
|
+
light: string;
|
|
43
|
+
dark: string;
|
|
44
|
+
system: string;
|
|
45
|
+
/** The second line of the log-out row. Its first line is `logoutLabel`. */
|
|
46
|
+
signOut: string;
|
|
47
|
+
}
|
|
48
|
+
export declare const DEFAULT_SIDEBAR_ACCOUNT_PANEL_STRINGS: SidebarAccountPanelStrings;
|
|
49
|
+
/** `SidebarNavigation`: its own words, and those of the footer and the brand header in it. */
|
|
50
|
+
export interface SidebarNavigationStrings extends SidebarFooterStrings, SidebarBrandHeaderStrings {
|
|
51
|
+
/** Accessible name of the main list of links, when it has no section heading. */
|
|
52
|
+
primaryNavigation: string;
|
|
53
|
+
/** Accessible name of the second list of links. */
|
|
54
|
+
secondaryNavigation: string;
|
|
55
|
+
/** Accessible name of a list under a section heading, from the heading. */
|
|
56
|
+
sectionNavigation: (section: string) => string;
|
|
57
|
+
/** Shown when a search matches no link: the heading. */
|
|
58
|
+
noMatchesTitle: string;
|
|
59
|
+
/** And the line under it, with what was searched for. */
|
|
60
|
+
noMatchesDescription: (term: string) => string;
|
|
61
|
+
}
|
|
62
|
+
export declare const DEFAULT_SIDEBAR_NAVIGATION_STRINGS: SidebarNavigationStrings;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The words the sidebar components say by themselves. Each takes its own as
|
|
3
|
+
* `strings`; `SidebarNavigation` takes them all and hands the footer and the
|
|
4
|
+
* brand header theirs.
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_SIDEBAR_BRAND_HEADER_STRINGS = {
|
|
7
|
+
brandAlt: "Brand",
|
|
8
|
+
};
|
|
9
|
+
export const DEFAULT_SIDEBAR_FOOTER_STRINGS = {
|
|
10
|
+
accountAndSettings: "Account and settings",
|
|
11
|
+
openAccountPanel: "Open account panel",
|
|
12
|
+
openAccountPanelFor: (name) => `Open account panel for ${name}`,
|
|
13
|
+
};
|
|
14
|
+
export const DEFAULT_SIDEBAR_ACCOUNT_PANEL_STRINGS = {
|
|
15
|
+
panelLabel: "Account panel",
|
|
16
|
+
title: "Account",
|
|
17
|
+
closeLabel: "Close account panel",
|
|
18
|
+
listLabel: "Select item",
|
|
19
|
+
account: "Account",
|
|
20
|
+
theme: "Theme",
|
|
21
|
+
lightMode: "Light mode",
|
|
22
|
+
darkMode: "Dark mode",
|
|
23
|
+
// Not "System": the badge beside it says that, and the row read "Theme System System".
|
|
24
|
+
systemMode: "Follows the system",
|
|
25
|
+
light: "Light",
|
|
26
|
+
dark: "Dark",
|
|
27
|
+
system: "System",
|
|
28
|
+
signOut: "Sign out of this account",
|
|
29
|
+
};
|
|
30
|
+
export const DEFAULT_SIDEBAR_NAVIGATION_STRINGS = {
|
|
31
|
+
...DEFAULT_SIDEBAR_FOOTER_STRINGS,
|
|
32
|
+
...DEFAULT_SIDEBAR_BRAND_HEADER_STRINGS,
|
|
33
|
+
primaryNavigation: "Primary navigation",
|
|
34
|
+
secondaryNavigation: "Secondary navigation",
|
|
35
|
+
sectionNavigation: (section) => `${section} navigation`,
|
|
36
|
+
noMatchesTitle: "No matching navigation items",
|
|
37
|
+
noMatchesDescription: (term) => `No results found for "${term}". Try another keyword.`,
|
|
38
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Types and pure helpers for `SortableList`. Kept out of the component so they can be tested without a DOM. */
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
/** Payload of `onreorder`: which item moved, and between which zero-based indexes. */
|
|
4
|
+
export interface SortableListReorderDetail<T> {
|
|
5
|
+
item: T;
|
|
6
|
+
from: number;
|
|
7
|
+
to: number;
|
|
8
|
+
/** The list in its new order (the same array `bind:items` receives). */
|
|
9
|
+
items: T[];
|
|
10
|
+
}
|
|
11
|
+
/** What a live-region message is built from. `position` is one-based. */
|
|
12
|
+
export interface SortableListAnnouncement {
|
|
13
|
+
label: string;
|
|
14
|
+
position: number;
|
|
15
|
+
total: number;
|
|
16
|
+
}
|
|
17
|
+
/** Second argument of the `item` snippet. */
|
|
18
|
+
export interface SortableListRow {
|
|
19
|
+
/** Zero-based index in the current order. */
|
|
20
|
+
index: number;
|
|
21
|
+
/** True while this row is being dragged with a pointer. */
|
|
22
|
+
dragging: boolean;
|
|
23
|
+
/** True when the list or this item is disabled. */
|
|
24
|
+
disabled: boolean;
|
|
25
|
+
/** The drag handle. Render it yourself when `controls="manual"`. */
|
|
26
|
+
handle: Snippet;
|
|
27
|
+
/** The move up / move down buttons. Render them yourself when `controls="manual"`. */
|
|
28
|
+
moveButtons: Snippet;
|
|
29
|
+
}
|
|
30
|
+
/** Every built-in string. Pass a partial object to `strings` to translate. */
|
|
31
|
+
export interface SortableListStrings {
|
|
32
|
+
/** Accessible name of the drag handle. */
|
|
33
|
+
handleLabel: (label: string) => string;
|
|
34
|
+
/** How to use the handle; referenced by every handle through `aria-describedby`. */
|
|
35
|
+
handleDescription: string;
|
|
36
|
+
moveUp: (label: string) => string;
|
|
37
|
+
moveDown: (label: string) => string;
|
|
38
|
+
/** Announced after every move. */
|
|
39
|
+
moved: (detail: SortableListAnnouncement) => string;
|
|
40
|
+
/** Announced when Escape (or a cancelled pointer) abandons a drag. */
|
|
41
|
+
cancelled: (detail: SortableListAnnouncement) => string;
|
|
42
|
+
/** Announced when Arrow Up or Home is pressed on the first item. */
|
|
43
|
+
atStart: (detail: SortableListAnnouncement) => string;
|
|
44
|
+
/** Announced when Arrow Down or End is pressed on the last item. */
|
|
45
|
+
atEnd: (detail: SortableListAnnouncement) => string;
|
|
46
|
+
}
|
|
47
|
+
export declare const SORTABLE_LIST_STRINGS: SortableListStrings;
|
|
48
|
+
/** A copy of `items` with the entry at `from` moved to `to`. Out-of-range indexes are clamped. */
|
|
49
|
+
export declare function moveItem<T>(items: readonly T[], from: number, to: number): T[];
|
|
50
|
+
/** Top edge and height of a row, measured once when a drag starts. */
|
|
51
|
+
export interface SortableSlot {
|
|
52
|
+
top: number;
|
|
53
|
+
height: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Index the dragged row would land on, given how far it has travelled.
|
|
57
|
+
*
|
|
58
|
+
* A row below counts as passed once the dragged row's bottom edge crosses its
|
|
59
|
+
* centre, and a row above once the top edge does. Both are read from the
|
|
60
|
+
* positions measured at drag start, so the answer depends on the pointer
|
|
61
|
+
* alone: rows sliding out of the way cannot feed back into it and make the
|
|
62
|
+
* target flicker, which is what happens when the live positions are compared.
|
|
63
|
+
*/
|
|
64
|
+
export declare function dropIndex(slots: readonly SortableSlot[], from: number, offset: number): number;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Types and pure helpers for `SortableList`. Kept out of the component so they can be tested without a DOM. */
|
|
2
|
+
export const SORTABLE_LIST_STRINGS = {
|
|
3
|
+
handleLabel: (label) => `Reorder ${label}`,
|
|
4
|
+
// Kept short: a screen reader reads it after the name each time the
|
|
5
|
+
// handle takes focus, and a move down can hand focus back to the handle.
|
|
6
|
+
handleDescription: "Arrow keys move this item. Home and End move it to the start or the end.",
|
|
7
|
+
moveUp: (label) => `Move ${label} up`,
|
|
8
|
+
moveDown: (label) => `Move ${label} down`,
|
|
9
|
+
moved: ({ label, position, total }) => `${label}, moved to position ${position} of ${total}`,
|
|
10
|
+
cancelled: ({ label, position, total }) => `${label}, move cancelled, still at position ${position} of ${total}`,
|
|
11
|
+
atStart: ({ label }) => `${label}, already first`,
|
|
12
|
+
atEnd: ({ label }) => `${label}, already last`,
|
|
13
|
+
};
|
|
14
|
+
/** A copy of `items` with the entry at `from` moved to `to`. Out-of-range indexes are clamped. */
|
|
15
|
+
export function moveItem(items, from, to) {
|
|
16
|
+
const next = [...items];
|
|
17
|
+
if (from < 0 || from >= next.length)
|
|
18
|
+
return next;
|
|
19
|
+
const target = Math.max(0, Math.min(next.length - 1, to));
|
|
20
|
+
const [moved] = next.splice(from, 1);
|
|
21
|
+
next.splice(target, 0, moved);
|
|
22
|
+
return next;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Index the dragged row would land on, given how far it has travelled.
|
|
26
|
+
*
|
|
27
|
+
* A row below counts as passed once the dragged row's bottom edge crosses its
|
|
28
|
+
* centre, and a row above once the top edge does. Both are read from the
|
|
29
|
+
* positions measured at drag start, so the answer depends on the pointer
|
|
30
|
+
* alone: rows sliding out of the way cannot feed back into it and make the
|
|
31
|
+
* target flicker, which is what happens when the live positions are compared.
|
|
32
|
+
*/
|
|
33
|
+
export function dropIndex(slots, from, offset) {
|
|
34
|
+
const dragged = slots[from];
|
|
35
|
+
if (!dragged)
|
|
36
|
+
return from;
|
|
37
|
+
const top = dragged.top + offset;
|
|
38
|
+
const bottom = top + dragged.height;
|
|
39
|
+
let to = from;
|
|
40
|
+
for (let i = from + 1; i < slots.length; i += 1) {
|
|
41
|
+
if (bottom > slots[i].top + slots[i].height / 2)
|
|
42
|
+
to = i;
|
|
43
|
+
else
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
for (let i = from - 1; i >= 0; i -= 1) {
|
|
47
|
+
if (top < slots[i].top + slots[i].height / 2)
|
|
48
|
+
to = i;
|
|
49
|
+
else
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
return to;
|
|
53
|
+
}
|