zabi-components 8.0.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2935 -0
- package/README.md +243 -10
- package/THEME.md +162 -332
- package/THEMING.md +1419 -259
- package/dist/atoms/ActionPanel.svelte +15 -5
- package/dist/atoms/Avatar.svelte +120 -0
- package/dist/atoms/Avatar.svelte.d.ts +46 -0
- package/dist/atoms/Badge.svelte +71 -13
- package/dist/atoms/Badge.svelte.d.ts +8 -2
- package/dist/atoms/Block.svelte +74 -0
- package/dist/atoms/Block.svelte.d.ts +29 -0
- package/dist/atoms/Button.svelte +217 -30
- package/dist/atoms/Button.svelte.d.ts +33 -4
- package/dist/atoms/Card.svelte +182 -26
- package/dist/atoms/Card.svelte.d.ts +55 -3
- package/dist/atoms/CardHeader.svelte +16 -4
- package/dist/atoms/Checkbox.svelte +81 -21
- package/dist/atoms/Checkbox.svelte.d.ts +31 -2
- package/dist/atoms/Chip.svelte +351 -0
- package/dist/atoms/Chip.svelte.d.ts +57 -0
- package/dist/atoms/CodeBlock.svelte +20 -2
- package/dist/atoms/CodeBlock.svelte.d.ts +4 -0
- package/dist/atoms/CodeField.svelte +385 -0
- package/dist/atoms/CodeField.svelte.d.ts +61 -0
- package/dist/atoms/ColorPicker.svelte +260 -49
- package/dist/atoms/ColorPicker.svelte.d.ts +3 -0
- package/dist/atoms/Container.svelte +16 -8
- package/dist/atoms/DateField.svelte +145 -0
- package/dist/atoms/DateField.svelte.d.ts +81 -0
- package/dist/atoms/FieldMessages.svelte +69 -0
- package/dist/atoms/FieldMessages.svelte.d.ts +23 -0
- package/dist/atoms/FloatingActionButton.svelte +176 -0
- package/dist/atoms/FloatingActionButton.svelte.d.ts +51 -0
- package/dist/atoms/Heading.svelte +63 -5
- package/dist/atoms/Heading.svelte.d.ts +14 -0
- package/dist/atoms/IconButton.svelte +294 -26
- package/dist/atoms/IconButton.svelte.d.ts +62 -4
- package/dist/atoms/Input.svelte +259 -53
- package/dist/atoms/Input.svelte.d.ts +33 -2
- package/dist/atoms/List.svelte +5 -1
- package/dist/atoms/ListItem.svelte +70 -13
- package/dist/atoms/ListItem.svelte.d.ts +11 -0
- package/dist/atoms/PickerField.svelte +239 -0
- package/dist/atoms/PickerField.svelte.d.ts +67 -0
- package/dist/atoms/Progress.svelte +99 -19
- package/dist/atoms/Progress.svelte.d.ts +15 -1
- package/dist/atoms/Radio.svelte +51 -3
- package/dist/atoms/Radio.svelte.d.ts +30 -2
- package/dist/atoms/Rating.svelte +620 -0
- package/dist/atoms/Rating.svelte.d.ts +77 -0
- package/dist/atoms/Select.svelte +438 -98
- package/dist/atoms/Select.svelte.d.ts +61 -3
- package/dist/atoms/SelectionControl.svelte +193 -23
- package/dist/atoms/SelectionControl.svelte.d.ts +29 -3
- package/dist/atoms/Skeleton.svelte +114 -18
- package/dist/atoms/Skeleton.svelte.d.ts +30 -3
- package/dist/atoms/SkeletonGroup.svelte +43 -0
- package/dist/atoms/SkeletonGroup.svelte.d.ts +20 -0
- package/dist/atoms/Slider.svelte +344 -0
- package/dist/atoms/Slider.svelte.d.ts +40 -0
- package/dist/atoms/Sparkline.svelte +109 -0
- package/dist/atoms/Sparkline.svelte.d.ts +27 -0
- package/dist/atoms/SpeechBubble.svelte +187 -0
- package/dist/atoms/SpeechBubble.svelte.d.ts +33 -0
- package/dist/atoms/Spinner.svelte +57 -0
- package/dist/atoms/Spinner.svelte.d.ts +19 -0
- package/dist/atoms/Stat.svelte +72 -0
- package/dist/atoms/Stat.svelte.d.ts +19 -0
- package/dist/atoms/Table.svelte +151 -6
- package/dist/atoms/Table.svelte.d.ts +15 -3
- package/dist/atoms/TemporalField.svelte +472 -0
- package/dist/atoms/TemporalField.svelte.d.ts +48 -0
- package/dist/atoms/Text.svelte +23 -11
- package/dist/atoms/Text.svelte.d.ts +6 -3
- package/dist/atoms/Textarea.svelte +150 -44
- package/dist/atoms/Textarea.svelte.d.ts +35 -2
- package/dist/atoms/ThemeToggle.svelte +223 -44
- package/dist/atoms/ThemeToggle.svelte.d.ts +26 -3
- package/dist/atoms/TimeColumn.svelte +150 -0
- package/dist/atoms/TimeColumn.svelte.d.ts +25 -0
- package/dist/atoms/TimeField.svelte +151 -0
- package/dist/atoms/TimeField.svelte.d.ts +85 -0
- package/dist/atoms/Toast.svelte +22 -8
- package/dist/atoms/Toast.svelte.d.ts +2 -0
- package/dist/atoms/Toggle.svelte +98 -14
- package/dist/atoms/Toggle.svelte.d.ts +26 -2
- package/dist/atoms/Tooltip.svelte +528 -24
- package/dist/atoms/Tooltip.svelte.d.ts +18 -0
- package/dist/atoms/ZabiStringsProvider.svelte +45 -0
- package/dist/atoms/ZabiStringsProvider.svelte.d.ts +27 -0
- package/dist/atoms/index.d.ts +38 -0
- package/dist/atoms/index.js +29 -0
- package/dist/atoms/selection-control.styles.d.ts +47 -5
- package/dist/atoms/selection-control.styles.js +52 -10
- package/dist/components/atoms/index.d.ts +38 -0
- package/dist/components/atoms/index.d.ts.map +1 -1
- package/dist/components/atoms/selection-control.styles.d.ts +47 -5
- package/dist/components/atoms/selection-control.styles.d.ts.map +1 -1
- package/dist/components/index.d.ts +104 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/map.d.ts +11 -0
- package/dist/components/map.d.ts.map +1 -0
- package/dist/components/molecules/index.d.ts +51 -0
- package/dist/components/molecules/index.d.ts.map +1 -1
- package/dist/components/molecules/toast-store.d.ts +83 -7
- package/dist/components/molecules/toast-store.d.ts.map +1 -1
- package/dist/components/organisms/index.d.ts +10 -0
- package/dist/components/organisms/index.d.ts.map +1 -1
- package/dist/components/types/variants.d.ts +24 -1
- package/dist/components/types/variants.d.ts.map +1 -1
- package/dist/components/util/app-shell.d.ts +79 -0
- package/dist/components/util/app-shell.d.ts.map +1 -0
- package/dist/components/util/avatar.d.ts +39 -0
- package/dist/components/util/avatar.d.ts.map +1 -0
- package/dist/components/util/bottom-sheet.d.ts +30 -0
- package/dist/components/util/bottom-sheet.d.ts.map +1 -0
- package/dist/components/util/bottom-tab-bar.d.ts +41 -0
- package/dist/components/util/bottom-tab-bar.d.ts.map +1 -0
- package/dist/components/util/calendar.d.ts +56 -0
- package/dist/components/util/calendar.d.ts.map +1 -0
- package/dist/components/util/chart.d.ts +140 -0
- package/dist/components/util/chart.d.ts.map +1 -0
- package/dist/components/util/chip.d.ts +66 -0
- package/dist/components/util/chip.d.ts.map +1 -0
- package/dist/components/util/cn.d.ts.map +1 -1
- package/dist/components/util/code-field.d.ts +63 -0
- package/dist/components/util/code-field.d.ts.map +1 -0
- package/dist/components/util/collapsible.d.ts +64 -0
- package/dist/components/util/collapsible.d.ts.map +1 -0
- package/dist/components/util/confirm-dialog.d.ts +12 -0
- package/dist/components/util/confirm-dialog.d.ts.map +1 -0
- package/dist/components/util/date.d.ts +96 -0
- package/dist/components/util/date.d.ts.map +1 -0
- package/dist/components/util/display-voice.d.ts +10 -0
- package/dist/components/util/display-voice.d.ts.map +1 -0
- package/dist/components/util/drawer.d.ts +13 -0
- package/dist/components/util/drawer.d.ts.map +1 -0
- package/dist/components/util/dropdown.d.ts +47 -0
- package/dist/components/util/dropdown.d.ts.map +1 -0
- package/dist/components/util/field-control.d.ts +30 -0
- package/dist/components/util/field-control.d.ts.map +1 -0
- package/dist/components/util/field.d.ts +45 -0
- package/dist/components/util/field.d.ts.map +1 -0
- package/dist/components/util/fit-in-viewport.d.ts +201 -0
- package/dist/components/util/fit-in-viewport.d.ts.map +1 -0
- package/dist/components/util/focus-utils.d.ts +77 -2
- package/dist/components/util/focus-utils.d.ts.map +1 -1
- package/dist/components/util/hydration.d.ts +45 -0
- package/dist/components/util/hydration.d.ts.map +1 -0
- package/dist/components/util/keyboard-inset.d.ts +18 -0
- package/dist/components/util/keyboard-inset.d.ts.map +1 -0
- package/dist/components/util/map-view.d.ts +144 -0
- package/dist/components/util/map-view.d.ts.map +1 -0
- package/dist/components/util/media-grid.d.ts +51 -0
- package/dist/components/util/media-grid.d.ts.map +1 -0
- package/dist/components/util/media.d.ts +6 -0
- package/dist/components/util/media.d.ts.map +1 -0
- package/dist/components/util/overlay-chrome.d.ts +53 -0
- package/dist/components/util/overlay-chrome.d.ts.map +1 -0
- package/dist/components/util/overlay.d.ts +72 -0
- package/dist/components/util/overlay.d.ts.map +1 -0
- package/dist/components/util/photo.d.ts +234 -0
- package/dist/components/util/photo.d.ts.map +1 -0
- package/dist/components/util/portal.d.ts +23 -0
- package/dist/components/util/portal.d.ts.map +1 -0
- package/dist/components/util/progress.d.ts +19 -0
- package/dist/components/util/progress.d.ts.map +1 -0
- package/dist/components/util/pull-to-refresh.d.ts +27 -0
- package/dist/components/util/pull-to-refresh.d.ts.map +1 -0
- package/dist/components/util/radio-keys.d.ts +25 -0
- package/dist/components/util/radio-keys.d.ts.map +1 -0
- package/dist/components/util/rating.d.ts +23 -0
- package/dist/components/util/rating.d.ts.map +1 -0
- package/dist/components/util/ready-made-strings.d.ts +77 -0
- package/dist/components/util/ready-made-strings.d.ts.map +1 -0
- package/dist/components/util/scroll-edge.d.ts +33 -0
- package/dist/components/util/scroll-edge.d.ts.map +1 -0
- package/dist/components/util/scroll-padding.d.ts +20 -0
- package/dist/components/util/scroll-padding.d.ts.map +1 -0
- package/dist/components/util/segmented-control.d.ts +16 -0
- package/dist/components/util/segmented-control.d.ts.map +1 -0
- package/dist/components/util/select.d.ts +41 -0
- package/dist/components/util/select.d.ts.map +1 -0
- package/dist/components/util/sheet-drag.d.ts +84 -0
- package/dist/components/util/sheet-drag.d.ts.map +1 -0
- package/dist/components/util/sidebar.d.ts +63 -0
- package/dist/components/util/sidebar.d.ts.map +1 -0
- package/dist/components/util/skeleton.d.ts +15 -0
- package/dist/components/util/skeleton.d.ts.map +1 -0
- package/dist/components/util/sliding-indicator.d.ts +25 -0
- package/dist/components/util/sliding-indicator.d.ts.map +1 -0
- package/dist/components/util/sortable-list.d.ts +65 -0
- package/dist/components/util/sortable-list.d.ts.map +1 -0
- package/dist/components/util/stepper.d.ts +40 -0
- package/dist/components/util/stepper.d.ts.map +1 -0
- package/dist/components/util/swipeable-list-item.d.ts +36 -0
- package/dist/components/util/swipeable-list-item.d.ts.map +1 -0
- package/dist/components/util/temporal-field.d.ts +89 -0
- package/dist/components/util/temporal-field.d.ts.map +1 -0
- package/dist/components/util/theme-mode.d.ts +80 -0
- package/dist/components/util/theme-mode.d.ts.map +1 -0
- package/dist/components/util/toaster.d.ts +133 -0
- package/dist/components/util/toaster.d.ts.map +1 -0
- package/dist/components/util/tone-surface.d.ts +34 -0
- package/dist/components/util/tone-surface.d.ts.map +1 -0
- package/dist/components/util/tooltip.d.ts +10 -0
- package/dist/components/util/tooltip.d.ts.map +1 -0
- package/dist/components/util/top-navbar.d.ts +35 -0
- package/dist/components/util/top-navbar.d.ts.map +1 -0
- package/dist/components/util/touch-target.d.ts +31 -0
- package/dist/components/util/touch-target.d.ts.map +1 -0
- package/dist/components/util/zabi-strings.d.ts +142 -0
- package/dist/components/util/zabi-strings.d.ts.map +1 -0
- package/dist/create-theme/cli.js +173 -0
- package/dist/create-theme/index.d.ts +190 -0
- package/dist/create-theme/index.js +1034 -0
- package/dist/create-theme/lib/ramp-math.js +128 -0
- package/dist/create-theme/lib/resolve.js +238 -0
- package/dist/create-theme/theme-data.js +2644 -0
- package/dist/index.d.ts +104 -2
- package/dist/index.js +75 -2
- package/dist/map.d.ts +10 -0
- package/dist/map.js +9 -0
- package/dist/molecules/Alert.svelte +63 -16
- package/dist/molecules/Alert.svelte.d.ts +14 -1
- package/dist/molecules/AppBar.svelte +674 -0
- package/dist/molecules/AppBar.svelte.d.ts +131 -0
- package/dist/molecules/AvatarGroup.svelte +116 -0
- package/dist/molecules/AvatarGroup.svelte.d.ts +40 -0
- package/dist/molecules/BarChart.svelte +381 -0
- package/dist/molecules/BarChart.svelte.d.ts +45 -0
- package/dist/molecules/BottomSheet.svelte +608 -0
- package/dist/molecules/BottomSheet.svelte.d.ts +109 -0
- package/dist/molecules/BottomTabBar.svelte +403 -0
- package/dist/molecules/BottomTabBar.svelte.d.ts +98 -0
- package/dist/molecules/Calendar.svelte +597 -0
- package/dist/molecules/Calendar.svelte.d.ts +72 -0
- package/dist/molecules/ChipGroup.svelte +325 -0
- package/dist/molecules/ChipGroup.svelte.d.ts +41 -0
- package/dist/molecules/Collapsible.svelte +347 -0
- package/dist/molecules/Collapsible.svelte.d.ts +61 -0
- package/dist/molecules/CollapsibleGroup.svelte +136 -0
- package/dist/molecules/CollapsibleGroup.svelte.d.ts +14 -0
- package/dist/molecules/ComponentDemo.svelte +16 -4
- package/dist/molecules/ComponentDemo.svelte.d.ts +3 -0
- package/dist/molecules/ConfirmDialog.svelte +257 -0
- package/dist/molecules/ConfirmDialog.svelte.d.ts +58 -0
- package/dist/molecules/ContactForm.svelte +34 -17
- package/dist/molecules/ContactForm.svelte.d.ts +8 -0
- package/dist/molecules/Drawer.svelte +415 -0
- package/dist/molecules/Drawer.svelte.d.ts +55 -0
- package/dist/molecules/Dropdown.svelte +517 -48
- package/dist/molecules/Dropdown.svelte.d.ts +47 -6
- package/dist/molecules/DropdownItem.svelte +122 -0
- package/dist/molecules/DropdownItem.svelte.d.ts +28 -0
- package/dist/molecules/EmptyState.svelte +55 -10
- package/dist/molecules/EmptyState.svelte.d.ts +8 -0
- package/dist/molecules/FormField.svelte +9 -1
- package/dist/molecules/FormField.svelte.d.ts +2 -0
- package/dist/molecules/Header.svelte +1 -1
- package/dist/molecules/ImageUpload.svelte +492 -69
- package/dist/molecules/ImageUpload.svelte.d.ts +82 -2
- package/dist/molecules/LineChart.svelte +459 -0
- package/dist/molecules/LineChart.svelte.d.ts +53 -0
- package/dist/molecules/MapView.svelte +565 -0
- package/dist/molecules/MapView.svelte.d.ts +88 -0
- package/dist/molecules/MediaGrid.svelte +527 -0
- package/dist/molecules/MediaGrid.svelte.d.ts +77 -0
- package/dist/molecules/Modal.svelte +293 -72
- package/dist/molecules/Modal.svelte.d.ts +51 -2
- package/dist/molecules/NavigationMenuContent.svelte +58 -1
- package/dist/molecules/NavigationMenuItem.svelte +0 -1
- package/dist/molecules/NavigationMenuLink.svelte +1 -1
- package/dist/molecules/NavigationMenuList.svelte +10 -3
- package/dist/molecules/NavigationMenuTrigger.svelte +2 -2
- package/dist/molecules/Page.svelte +32 -2
- package/dist/molecules/Page.svelte.d.ts +11 -0
- package/dist/molecules/PhotoGrid.svelte +523 -0
- package/dist/molecules/PhotoGrid.svelte.d.ts +73 -0
- package/dist/molecules/PhotoViewer.svelte +1213 -0
- package/dist/molecules/PhotoViewer.svelte.d.ts +74 -0
- package/dist/molecules/PieChart.svelte +421 -0
- package/dist/molecules/PieChart.svelte.d.ts +51 -0
- package/dist/molecules/PropsTable.svelte +22 -10
- package/dist/molecules/PropsTable.svelte.d.ts +3 -0
- package/dist/molecules/PullToRefresh.svelte +263 -0
- package/dist/molecules/PullToRefresh.svelte.d.ts +52 -0
- package/dist/molecules/RadioGroup.svelte +72 -18
- package/dist/molecules/RadioGroup.svelte.d.ts +19 -3
- package/dist/molecules/Section.svelte +1 -1
- package/dist/molecules/SegmentedControl.svelte +456 -0
- package/dist/molecules/SegmentedControl.svelte.d.ts +40 -0
- package/dist/molecules/SidebarBrandHeader.svelte +11 -1
- package/dist/molecules/SidebarBrandHeader.svelte.d.ts +3 -0
- package/dist/molecules/SidebarFooter.svelte +30 -7
- package/dist/molecules/SidebarFooter.svelte.d.ts +3 -0
- package/dist/molecules/SidebarNavSection.svelte +1 -1
- package/dist/molecules/SlideUp.svelte +220 -61
- package/dist/molecules/SlideUp.svelte.d.ts +26 -0
- package/dist/molecules/SortableList.svelte +633 -0
- package/dist/molecules/SortableList.svelte.d.ts +69 -0
- package/dist/molecules/Stepper.svelte +562 -0
- package/dist/molecules/Stepper.svelte.d.ts +39 -0
- package/dist/molecules/StickyActionBar.svelte +250 -0
- package/dist/molecules/StickyActionBar.svelte.d.ts +78 -0
- package/dist/molecules/SwipeableListItem.svelte +334 -0
- package/dist/molecules/SwipeableListItem.svelte.d.ts +54 -0
- package/dist/molecules/Tabs.svelte +310 -9
- package/dist/molecules/Tabs.svelte.d.ts +7 -0
- package/dist/molecules/Toaster.svelte +514 -5
- package/dist/molecules/Toaster.svelte.d.ts +153 -2
- package/dist/molecules/ToasterToast.svelte +495 -77
- package/dist/molecules/ToasterToast.svelte.d.ts +15 -0
- package/dist/molecules/UnsavedChangesBar.svelte +223 -0
- package/dist/molecules/UnsavedChangesBar.svelte.d.ts +43 -0
- package/dist/molecules/index.d.ts +51 -0
- package/dist/molecules/index.js +31 -0
- package/dist/molecules/toast-store.d.ts +83 -7
- package/dist/molecules/toast-store.js +25 -1
- package/dist/organisms/AppNavigation.svelte +440 -0
- package/dist/organisms/AppNavigation.svelte.d.ts +72 -0
- package/dist/organisms/AppShell.svelte +696 -0
- package/dist/organisms/AppShell.svelte.d.ts +157 -0
- package/dist/organisms/AppShellHeaderPart.svelte +163 -0
- package/dist/organisms/AppShellHeaderPart.svelte.d.ts +57 -0
- package/dist/organisms/SidebarAccountPanel.svelte +107 -12
- package/dist/organisms/SidebarAccountPanel.svelte.d.ts +19 -0
- package/dist/organisms/SidebarNavigation.svelte +111 -43
- package/dist/organisms/SidebarNavigation.svelte.d.ts +29 -1
- package/dist/organisms/SidebarPanel.svelte +34 -17
- package/dist/organisms/SidebarPanel.svelte.d.ts +1 -0
- package/dist/organisms/SidebarShell.svelte +164 -14
- package/dist/organisms/SidebarShell.svelte.d.ts +56 -2
- package/dist/organisms/TopNavbar.svelte +353 -39
- package/dist/organisms/TopNavbar.svelte.d.ts +47 -0
- package/dist/organisms/TopNavbarSheetContent.svelte +145 -0
- package/dist/organisms/TopNavbarSheetContent.svelte.d.ts +24 -0
- package/dist/organisms/index.d.ts +10 -0
- package/dist/organisms/index.js +7 -0
- package/dist/types/components.d.ts +21 -1
- package/dist/types/components.d.ts.map +1 -1
- package/dist/types/index.d.ts +1093 -26
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/variants.ts +28 -1
- package/dist/util/app-shell.d.ts +78 -0
- package/dist/util/app-shell.js +97 -0
- package/dist/util/avatar.d.ts +38 -0
- package/dist/util/avatar.js +52 -0
- package/dist/util/bottom-sheet.d.ts +29 -0
- package/dist/util/bottom-sheet.js +43 -0
- package/dist/util/bottom-tab-bar.d.ts +40 -0
- package/dist/util/bottom-tab-bar.js +54 -0
- package/dist/util/calendar.d.ts +55 -0
- package/dist/util/calendar.js +74 -0
- package/dist/util/chart.d.ts +139 -0
- package/dist/util/chart.js +305 -0
- package/dist/util/chip.d.ts +65 -0
- package/dist/util/chip.js +58 -0
- package/dist/util/cn.js +28 -2
- package/dist/util/code-field.d.ts +62 -0
- package/dist/util/code-field.js +112 -0
- package/dist/util/collapsible.d.ts +63 -0
- package/dist/util/collapsible.js +23 -0
- package/dist/util/confirm-dialog.d.ts +11 -0
- package/dist/util/confirm-dialog.js +2 -0
- package/dist/util/date.d.ts +95 -0
- package/dist/util/date.js +237 -0
- package/dist/util/display-voice.d.ts +9 -0
- package/dist/util/display-voice.js +9 -0
- package/dist/util/drawer.d.ts +12 -0
- package/dist/util/drawer.js +7 -0
- package/dist/util/dropdown.d.ts +46 -0
- package/dist/util/dropdown.js +21 -0
- package/dist/util/field-control.d.ts +29 -0
- package/dist/util/field-control.js +32 -0
- package/dist/util/field.d.ts +44 -0
- package/dist/util/field.js +38 -0
- package/dist/util/fit-in-viewport.d.ts +200 -0
- package/dist/util/fit-in-viewport.js +399 -0
- package/dist/util/focus-utils.d.ts +77 -2
- package/dist/util/focus-utils.js +186 -9
- package/dist/util/hydration.d.ts +44 -0
- package/dist/util/hydration.js +58 -0
- package/dist/util/keyboard-inset.d.ts +17 -0
- package/dist/util/keyboard-inset.js +53 -0
- package/dist/util/map-view.d.ts +143 -0
- package/dist/util/map-view.js +121 -0
- package/dist/util/media-grid.d.ts +50 -0
- package/dist/util/media-grid.js +81 -0
- package/dist/util/media.d.ts +5 -0
- package/dist/util/media.js +10 -0
- package/dist/util/overlay-chrome.d.ts +52 -0
- package/dist/util/overlay-chrome.js +56 -0
- package/dist/util/overlay.d.ts +71 -0
- package/dist/util/overlay.js +240 -0
- package/dist/util/photo.d.ts +233 -0
- package/dist/util/photo.js +209 -0
- package/dist/util/portal.d.ts +22 -0
- package/dist/util/portal.js +50 -0
- package/dist/util/progress.d.ts +18 -0
- package/dist/util/progress.js +17 -0
- package/dist/util/pull-to-refresh.d.ts +26 -0
- package/dist/util/pull-to-refresh.js +30 -0
- package/dist/util/radio-keys.d.ts +24 -0
- package/dist/util/radio-keys.js +49 -0
- package/dist/util/rating.d.ts +22 -0
- package/dist/util/rating.js +26 -0
- package/dist/util/ready-made-strings.d.ts +76 -0
- package/dist/util/ready-made-strings.js +67 -0
- package/dist/util/scroll-edge.d.ts +32 -0
- package/dist/util/scroll-edge.js +87 -0
- package/dist/util/scroll-padding.d.ts +19 -0
- package/dist/util/scroll-padding.js +44 -0
- package/dist/util/segmented-control.d.ts +15 -0
- package/dist/util/segmented-control.js +1 -0
- package/dist/util/select.d.ts +40 -0
- package/dist/util/select.js +63 -0
- package/dist/util/sheet-drag.d.ts +83 -0
- package/dist/util/sheet-drag.js +311 -0
- package/dist/util/sidebar.d.ts +62 -0
- package/dist/util/sidebar.js +38 -0
- package/dist/util/skeleton.d.ts +14 -0
- package/dist/util/skeleton.js +22 -0
- package/dist/util/sliding-indicator.d.ts +24 -0
- package/dist/util/sliding-indicator.js +44 -0
- package/dist/util/sortable-list.d.ts +64 -0
- package/dist/util/sortable-list.js +53 -0
- package/dist/util/stepper.d.ts +39 -0
- package/dist/util/stepper.js +38 -0
- package/dist/util/swipeable-list-item.d.ts +35 -0
- package/dist/util/swipeable-list-item.js +32 -0
- package/dist/util/temporal-field.d.ts +88 -0
- package/dist/util/temporal-field.js +136 -0
- package/dist/util/theme-mode.d.ts +79 -0
- package/dist/util/theme-mode.js +121 -0
- package/dist/util/toaster.d.ts +132 -0
- package/dist/util/toaster.js +130 -0
- package/dist/util/tone-surface.d.ts +33 -0
- package/dist/util/tone-surface.js +35 -0
- package/dist/util/tooltip.d.ts +9 -0
- package/dist/util/tooltip.js +18 -0
- package/dist/util/top-navbar.d.ts +34 -0
- package/dist/util/top-navbar.js +28 -0
- package/dist/util/touch-target.d.ts +30 -0
- package/dist/util/touch-target.js +30 -0
- package/dist/util/zabi-strings.d.ts +141 -0
- package/dist/util/zabi-strings.js +105 -0
- package/dist/zabi-components-colors.css +11 -2
- package/dist/zabi-components-theme-dark-only.css +870 -258
- package/dist/zabi-components-theme-dark.css +870 -258
- package/dist/zabi-components-theme-only.css +2419 -368
- package/dist/zabi-components-theme.css +2419 -368
- package/dist/zabi-components.css +6032 -711
- package/docs/lucide-icons.md +40 -17
- package/docs/theme-imports.md +81 -11
- package/package.json +45 -8
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps a floating box (a menu, a panel, a tooltip) where it can be seen.
|
|
3
|
+
*
|
|
4
|
+
* One module for everything that opens next to a trigger. Two layers:
|
|
5
|
+
*
|
|
6
|
+
* - `pickSide` and `shiftIntoViewport` are the two decisions every such box
|
|
7
|
+
* needs: which side of its trigger it opens on, and how far it has to move
|
|
8
|
+
* along that side to stay on screen. Tooltip uses them as they are.
|
|
9
|
+
* - `fitPanel` builds on them for a panel that hangs from one edge of its
|
|
10
|
+
* anchor (Dropdown, Select's list, NavigationMenuContent): it also narrows
|
|
11
|
+
* and shortens a panel too large for the screen. `measurePlacement` reads
|
|
12
|
+
* the layout for it, and `watchViewport` re-runs it while the panel is open.
|
|
13
|
+
*
|
|
14
|
+
* The arithmetic is pure, so it can be tested without a layout.
|
|
15
|
+
*
|
|
16
|
+
* The screen is not the only thing that cuts a panel off. Inside a box that
|
|
17
|
+
* scrolls (a Modal's body, a list with its own scrollbar) the box clips it
|
|
18
|
+
* first. `measurePlacement` takes the nearest such box into account: it
|
|
19
|
+
* decides which side the panel opens on, and when the panel fits on neither
|
|
20
|
+
* side it says where to put the panel with `position: fixed`, which a
|
|
21
|
+
* scrolling ancestor does not clip.
|
|
22
|
+
*/
|
|
23
|
+
/** The viewport less its margin, and less whatever `clip` cuts off. */
|
|
24
|
+
function boundsOf(viewport, margin, clip) {
|
|
25
|
+
const view = {
|
|
26
|
+
left: margin,
|
|
27
|
+
top: margin,
|
|
28
|
+
right: viewport.width - margin,
|
|
29
|
+
bottom: viewport.height - margin,
|
|
30
|
+
};
|
|
31
|
+
if (!clip)
|
|
32
|
+
return view;
|
|
33
|
+
return {
|
|
34
|
+
left: Math.max(view.left, clip.left),
|
|
35
|
+
top: Math.max(view.top, clip.top),
|
|
36
|
+
right: Math.min(view.right, clip.right),
|
|
37
|
+
bottom: Math.min(view.bottom, clip.bottom),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const OPPOSITE = {
|
|
41
|
+
top: "bottom",
|
|
42
|
+
bottom: "top",
|
|
43
|
+
left: "right",
|
|
44
|
+
right: "left",
|
|
45
|
+
};
|
|
46
|
+
/** The room, in px, between each side of `trigger` and the matching edge of `bounds`. */
|
|
47
|
+
function roomAround(trigger, bounds) {
|
|
48
|
+
return {
|
|
49
|
+
top: trigger.top - bounds.top,
|
|
50
|
+
bottom: bounds.bottom - trigger.bottom,
|
|
51
|
+
left: trigger.left - bounds.left,
|
|
52
|
+
right: bounds.right - trigger.right,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The side a floating box of `size` opens on: the preferred one when it fits
|
|
57
|
+
* there, the opposite one when only that fits, and otherwise whichever of the
|
|
58
|
+
* two has more room.
|
|
59
|
+
*
|
|
60
|
+
* `gap` is the distance between trigger and box; `margin` is how close to the
|
|
61
|
+
* viewport edge the box may come. `clip` is the inside of an ancestor that
|
|
62
|
+
* cuts the box off, when there is one: the box then has to fit in what both
|
|
63
|
+
* leave.
|
|
64
|
+
*/
|
|
65
|
+
export function pickSide(preferred, trigger, size, viewport, { gap = 8, margin = 8, clip = null, } = {}) {
|
|
66
|
+
const room = roomAround(trigger, boundsOf(viewport, margin, clip));
|
|
67
|
+
const needed = (preferred === "top" || preferred === "bottom" ? size.height : size.width) + gap;
|
|
68
|
+
const opposite = OPPOSITE[preferred];
|
|
69
|
+
if (room[preferred] >= needed)
|
|
70
|
+
return preferred;
|
|
71
|
+
if (room[opposite] >= needed)
|
|
72
|
+
return opposite;
|
|
73
|
+
return room[opposite] > room[preferred] ? opposite : preferred;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Where a box `extent` long that starts at `start` ends up when it has to lie
|
|
77
|
+
* between `from` and `to`. A box longer than that is put at `from`, where its
|
|
78
|
+
* text begins.
|
|
79
|
+
*/
|
|
80
|
+
function slideInto(start, extent, from, to) {
|
|
81
|
+
if (extent > to - from)
|
|
82
|
+
return from;
|
|
83
|
+
return Math.min(Math.max(start, from), to - extent);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* How far `box` has to move, in px, to lie inside the viewport with `margin`
|
|
87
|
+
* to spare. Zero on an axis where it already does. A box larger than the
|
|
88
|
+
* viewport is aligned to the start edge (top, left), where its text begins.
|
|
89
|
+
*/
|
|
90
|
+
export function shiftIntoViewport(box, viewport, margin = 8) {
|
|
91
|
+
const view = boundsOf(viewport, margin);
|
|
92
|
+
return {
|
|
93
|
+
x: slideInto(box.left, box.right - box.left, view.left, view.right) - box.left,
|
|
94
|
+
y: slideInto(box.top, box.bottom - box.top, view.top, view.bottom) - box.top,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* True when `point` lies in the triangle `a`, `b`, `c`, edges included. For
|
|
99
|
+
* the path a pointer takes from a trigger to its floating box: as long as it
|
|
100
|
+
* stays in the triangle between where it left and the near edge of the box,
|
|
101
|
+
* it is on its way there.
|
|
102
|
+
*/
|
|
103
|
+
export function insideTriangle(point, a, b, c) {
|
|
104
|
+
const side = (p, q, r) => (p.x - r.x) * (q.y - r.y) - (q.x - r.x) * (p.y - r.y);
|
|
105
|
+
const first = side(point, a, b);
|
|
106
|
+
const second = side(point, b, c);
|
|
107
|
+
const third = side(point, c, a);
|
|
108
|
+
const negative = first < 0 || second < 0 || third < 0;
|
|
109
|
+
const positive = first > 0 || second > 0 || third > 0;
|
|
110
|
+
return !(negative && positive);
|
|
111
|
+
}
|
|
112
|
+
/** Where the panel fits, starting from the side asked for. */
|
|
113
|
+
export function fitPanel(input) {
|
|
114
|
+
const { anchor, panel, viewport, rtl = false, margin = 8, gap = 8, flipBlock = true, flipInline = true, clip = null, } = input;
|
|
115
|
+
const view = boundsOf(viewport, margin);
|
|
116
|
+
// What the panel has to be inside to be seen: the same as `view` unless something clips.
|
|
117
|
+
const within = boundsOf(viewport, margin, clip);
|
|
118
|
+
// Width first: a panel wider than the screen is narrowed, whichever side it is on.
|
|
119
|
+
const widest = Math.max(0, view.right - view.left);
|
|
120
|
+
const width = Math.min(panel.width, widest);
|
|
121
|
+
const maxWidth = panel.width > widest ? widest : null;
|
|
122
|
+
// `start` grows from the anchor's left edge (its right one when right-to-left).
|
|
123
|
+
const growsRight = (side) => (side === "start") !== rtl;
|
|
124
|
+
const leftFor = (side) => growsRight(side) ? anchor.left : anchor.right - width;
|
|
125
|
+
const fitsInline = (side) => {
|
|
126
|
+
const left = leftFor(side);
|
|
127
|
+
return left >= within.left && left + width <= within.right;
|
|
128
|
+
};
|
|
129
|
+
const other = input.inline === "start" ? "end" : "start";
|
|
130
|
+
const inline = !flipInline || fitsInline(input.inline) || !fitsInline(other) ? input.inline : other;
|
|
131
|
+
// Neither side fits: stay on the side asked for and slide back inside. A
|
|
132
|
+
// panel too wide for a clipping box cannot be slid into it; the screen is
|
|
133
|
+
// then all there is to stay inside.
|
|
134
|
+
const start = leftFor(inline);
|
|
135
|
+
const lane = width <= within.right - within.left ? within : view;
|
|
136
|
+
const left = slideInto(start, width, lane.left, lane.right);
|
|
137
|
+
const inlineOffset = growsRight(inline) ? left - start : start - left;
|
|
138
|
+
const roomIn = (bounds, side) => side === "bottom" ? bounds.bottom - anchor.bottom - gap : anchor.top - gap - bounds.top;
|
|
139
|
+
// The other side if the panel fits only there, else whichever has more room.
|
|
140
|
+
const block = flipBlock
|
|
141
|
+
? pickSide(input.block, anchor, panel, viewport, { gap, margin, clip })
|
|
142
|
+
: input.block;
|
|
143
|
+
// The size limit is the screen's, whatever clips: a menu squeezed into a
|
|
144
|
+
// 160px box would be worse than one that reaches out of it.
|
|
145
|
+
const maxHeight = panel.height > roomIn(view, block) ? Math.max(0, roomIn(view, block)) : null;
|
|
146
|
+
const height = maxHeight ?? panel.height;
|
|
147
|
+
const top = block === "bottom" ? anchor.bottom + gap : anchor.top - gap - height;
|
|
148
|
+
const slack = 0.5;
|
|
149
|
+
const visible = left >= within.left - slack &&
|
|
150
|
+
left + width <= within.right + slack &&
|
|
151
|
+
top >= within.top - slack &&
|
|
152
|
+
top + height <= within.bottom + slack;
|
|
153
|
+
return {
|
|
154
|
+
block,
|
|
155
|
+
inline,
|
|
156
|
+
// -0 would print as "-0px".
|
|
157
|
+
inlineOffset: inlineOffset === 0 ? 0 : inlineOffset,
|
|
158
|
+
maxWidth,
|
|
159
|
+
maxHeight,
|
|
160
|
+
left,
|
|
161
|
+
top,
|
|
162
|
+
width,
|
|
163
|
+
visible,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/** A fit that changes nothing: the panel where the CSS puts it, with no limits. */
|
|
167
|
+
export function unfitted(block, inline) {
|
|
168
|
+
return {
|
|
169
|
+
block,
|
|
170
|
+
inline,
|
|
171
|
+
inlineOffset: 0,
|
|
172
|
+
maxWidth: null,
|
|
173
|
+
maxHeight: null,
|
|
174
|
+
left: 0,
|
|
175
|
+
top: 0,
|
|
176
|
+
width: 0,
|
|
177
|
+
visible: true,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Notes how far `panel` and whatever scrolls inside it are scrolled, and
|
|
182
|
+
* returns the function that puts it back. The part of a panel that scrolls is
|
|
183
|
+
* often a list inside it (Dropdown's, Select's), not the panel.
|
|
184
|
+
*/
|
|
185
|
+
function rememberScroll(panel) {
|
|
186
|
+
const scrolled = [panel, ...panel.querySelectorAll("*")]
|
|
187
|
+
.filter((element) => element.scrollTop !== 0 || element.scrollLeft !== 0)
|
|
188
|
+
.map((element) => ({ element, top: element.scrollTop, left: element.scrollLeft }));
|
|
189
|
+
return () => {
|
|
190
|
+
for (const { element, top, left } of scrolled) {
|
|
191
|
+
element.scrollTop = top;
|
|
192
|
+
element.scrollLeft = left;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Measures `panel` against `anchor` and returns its fit. Any limit already on
|
|
198
|
+
* the panel is lifted for the measurement, so the answer does not depend on
|
|
199
|
+
* the previous one. Call it before paint (from an effect) and apply the result.
|
|
200
|
+
*/
|
|
201
|
+
export function measureFit(anchor, panel, preferred, options = {}) {
|
|
202
|
+
const { maxWidth, maxHeight } = panel.style;
|
|
203
|
+
// Without its limit the panel has nothing to scroll, and the browser
|
|
204
|
+
// forgets how far it was scrolled: put that back as well.
|
|
205
|
+
const restoreScroll = rememberScroll(panel);
|
|
206
|
+
panel.style.maxWidth = "none";
|
|
207
|
+
panel.style.maxHeight = "none";
|
|
208
|
+
const natural = panel.getBoundingClientRect();
|
|
209
|
+
let height = natural.height;
|
|
210
|
+
// A panel that will be narrowed wraps its text and grows taller: the
|
|
211
|
+
// height that has to fit is the one it has at that width.
|
|
212
|
+
const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
|
|
213
|
+
const widest = Math.max(0, viewportWidth - (options.margin ?? 8) * 2);
|
|
214
|
+
if (natural.width > widest) {
|
|
215
|
+
const { minWidth } = panel.style;
|
|
216
|
+
panel.style.maxWidth = `${widest}px`;
|
|
217
|
+
panel.style.minWidth = `${widest}px`;
|
|
218
|
+
height = panel.getBoundingClientRect().height;
|
|
219
|
+
panel.style.minWidth = minWidth;
|
|
220
|
+
}
|
|
221
|
+
const size = { width: natural.width, height };
|
|
222
|
+
panel.style.maxWidth = maxWidth;
|
|
223
|
+
panel.style.maxHeight = maxHeight;
|
|
224
|
+
restoreScroll();
|
|
225
|
+
// Nothing is laid out (a hidden ancestor, or a test without a layout engine).
|
|
226
|
+
if (size.width === 0 && size.height === 0)
|
|
227
|
+
return unfitted(preferred.block, preferred.inline);
|
|
228
|
+
const box = anchor.getBoundingClientRect();
|
|
229
|
+
return fitPanel({
|
|
230
|
+
anchor: { left: box.left, right: box.right, top: box.top, bottom: box.bottom },
|
|
231
|
+
panel: { width: size.width, height: size.height },
|
|
232
|
+
// The layout viewport, without a scrollbar's width.
|
|
233
|
+
viewport: {
|
|
234
|
+
width: viewportWidth,
|
|
235
|
+
height: document.documentElement.clientHeight || window.innerHeight,
|
|
236
|
+
},
|
|
237
|
+
...preferred,
|
|
238
|
+
rtl: getComputedStyle(anchor).direction === "rtl",
|
|
239
|
+
...options,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* The nearest ancestor of `element` that clips what reaches outside it (any
|
|
244
|
+
* `overflow` but `visible`), with the box it clips to: its inside, without
|
|
245
|
+
* borders or scrollbars, in viewport coordinates. Null when only the viewport
|
|
246
|
+
* clips.
|
|
247
|
+
*/
|
|
248
|
+
export function clippingAncestor(element) {
|
|
249
|
+
for (let current = element.parentElement; current && current !== document.body && current !== document.documentElement; current = current.parentElement) {
|
|
250
|
+
const style = getComputedStyle(current);
|
|
251
|
+
if (style.overflowX === "visible" && style.overflowY === "visible")
|
|
252
|
+
continue;
|
|
253
|
+
const outer = current.getBoundingClientRect();
|
|
254
|
+
const left = outer.left + current.clientLeft;
|
|
255
|
+
const top = outer.top + current.clientTop;
|
|
256
|
+
return {
|
|
257
|
+
element: current,
|
|
258
|
+
box: {
|
|
259
|
+
left,
|
|
260
|
+
top,
|
|
261
|
+
right: left + current.clientWidth,
|
|
262
|
+
bottom: top + current.clientHeight,
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Whether `element` is the containing block of `position: fixed` descendants:
|
|
270
|
+
* such a descendant is placed against it, not the viewport, and is clipped by
|
|
271
|
+
* it like any other child.
|
|
272
|
+
*/
|
|
273
|
+
function containsFixed(element) {
|
|
274
|
+
const style = getComputedStyle(element);
|
|
275
|
+
const set = (value) => !!value && value !== "none";
|
|
276
|
+
return (set(style.transform) ||
|
|
277
|
+
set(style.filter) ||
|
|
278
|
+
set(style.perspective) ||
|
|
279
|
+
set(style.backdropFilter) ||
|
|
280
|
+
/paint|layout|strict|content/.test(style.contain ?? "") ||
|
|
281
|
+
/transform|filter|perspective/.test(style.willChange ?? "") ||
|
|
282
|
+
(!!style.containerType && style.containerType !== "normal"));
|
|
283
|
+
}
|
|
284
|
+
/** Whether a fixed `panel` would get out of `clipper`: nothing from the panel up to it holds fixed descendants. */
|
|
285
|
+
function escapes(panel, clipper) {
|
|
286
|
+
for (let current = panel.parentElement; current; current = current.parentElement) {
|
|
287
|
+
if (containsFixed(current))
|
|
288
|
+
return false;
|
|
289
|
+
if (current === clipper)
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Where `position: fixed; top: 0; left: 0` puts `panel`. That is the viewport's
|
|
296
|
+
* corner unless an ancestor further up holds fixed descendants, in which case
|
|
297
|
+
* coordinates have to be given from its corner instead.
|
|
298
|
+
*/
|
|
299
|
+
function fixedOrigin(panel) {
|
|
300
|
+
const saved = panel.style.cssText;
|
|
301
|
+
panel.style.position = "fixed";
|
|
302
|
+
panel.style.inset = "0 auto auto 0";
|
|
303
|
+
panel.style.margin = "0";
|
|
304
|
+
panel.style.translate = "none";
|
|
305
|
+
const box = panel.getBoundingClientRect();
|
|
306
|
+
panel.style.cssText = saved;
|
|
307
|
+
return { left: box.left, top: box.top };
|
|
308
|
+
}
|
|
309
|
+
/** The inline styles `fixed` is applied with. Lifted while the panel is measured. */
|
|
310
|
+
const FIXED_STYLES = ["position", "top", "left", "right", "bottom", "margin", "width"];
|
|
311
|
+
/** Runs `measure` with the panel where the CSS puts it, whatever an earlier placement set on it. */
|
|
312
|
+
function asPlaced(panel, measure) {
|
|
313
|
+
const saved = FIXED_STYLES.map((name) => panel.style[name]);
|
|
314
|
+
const restoreScroll = rememberScroll(panel);
|
|
315
|
+
for (const name of FIXED_STYLES)
|
|
316
|
+
panel.style[name] = "";
|
|
317
|
+
try {
|
|
318
|
+
return measure();
|
|
319
|
+
}
|
|
320
|
+
finally {
|
|
321
|
+
FIXED_STYLES.forEach((name, index) => (panel.style[name] = saved[index]));
|
|
322
|
+
restoreScroll();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* The fit of `panel`, with the nearest clipping ancestor of `anchor` taken
|
|
327
|
+
* into account.
|
|
328
|
+
*
|
|
329
|
+
* - The panel fits inside that ancestor on the side asked for: nothing changes.
|
|
330
|
+
* - It fits on the other side: it opens there.
|
|
331
|
+
* - It fits on neither: it is placed against the viewport with `fixed`, on the
|
|
332
|
+
* side the viewport has room for, and reaches out of the ancestor. Only
|
|
333
|
+
* while some of the anchor can be seen in the ancestor: scrolled out of it,
|
|
334
|
+
* the anchor takes the panel with it.
|
|
335
|
+
* - It cannot be: something between the panel and that ancestor is the
|
|
336
|
+
* containing block of fixed descendants (a `transform`, a `filter`). It then
|
|
337
|
+
* opens on the side of the ancestor with more room, and is cut where that
|
|
338
|
+
* ends. That is the limit of what a panel can do without leaving its place
|
|
339
|
+
* in the DOM, and it stays there so that the keyboard, focus and a dialog's
|
|
340
|
+
* focus trap treat it as part of what opened it.
|
|
341
|
+
*/
|
|
342
|
+
export function measurePlacement(anchor, panel, preferred, options = {}) {
|
|
343
|
+
const clipper = clippingAncestor(anchor);
|
|
344
|
+
if (!clipper)
|
|
345
|
+
return { ...measureFit(anchor, panel, preferred, options), fixed: null };
|
|
346
|
+
const inside = asPlaced(panel, () => measureFit(anchor, panel, preferred, { ...options, clip: clipper.box }));
|
|
347
|
+
if (inside.visible || !escapes(panel, clipper.element))
|
|
348
|
+
return { ...inside, fixed: null };
|
|
349
|
+
// The anchor itself is scrolled out of the box: the panel goes with it. Left
|
|
350
|
+
// fixed, it would float over the page with nothing to show what it belongs to.
|
|
351
|
+
const box = anchor.getBoundingClientRect();
|
|
352
|
+
const { box: clip } = clipper;
|
|
353
|
+
if (box.bottom <= clip.top || box.top >= clip.bottom || box.right <= clip.left || box.left >= clip.right) {
|
|
354
|
+
return { ...inside, fixed: null };
|
|
355
|
+
}
|
|
356
|
+
// Out of the box: only the viewport decides now.
|
|
357
|
+
const free = asPlaced(panel, () => measureFit(anchor, panel, preferred, options));
|
|
358
|
+
// Out of the box it would still not be on screen (a panel that may not
|
|
359
|
+
// flip, under an anchor near the bottom of the page's own scroller): it
|
|
360
|
+
// stays where it is, and scrolling brings it into view as it always did.
|
|
361
|
+
// Fixed, it would hang below the screen until the anchor was scrolled up.
|
|
362
|
+
if (!free.visible)
|
|
363
|
+
return { ...inside, fixed: null };
|
|
364
|
+
const origin = fixedOrigin(panel);
|
|
365
|
+
return {
|
|
366
|
+
...free,
|
|
367
|
+
fixed: { left: free.left - origin.left, top: free.top - origin.top, width: free.width },
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Calls `update` when the viewport changes size or anything outside `panel`
|
|
372
|
+
* scrolls, at most once a frame. Returns the function that stops it.
|
|
373
|
+
*/
|
|
374
|
+
export function watchViewport(update, panel) {
|
|
375
|
+
if (typeof window === "undefined")
|
|
376
|
+
return () => { };
|
|
377
|
+
let frame = 0;
|
|
378
|
+
const schedule = (event) => {
|
|
379
|
+
// The panel scrolling its own content moves nothing it is placed against.
|
|
380
|
+
if (panel && event?.type === "scroll" && event.target instanceof Node && panel.contains(event.target)) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
if (frame)
|
|
384
|
+
return;
|
|
385
|
+
frame = requestAnimationFrame(() => {
|
|
386
|
+
frame = 0;
|
|
387
|
+
update();
|
|
388
|
+
});
|
|
389
|
+
};
|
|
390
|
+
window.addEventListener("resize", schedule);
|
|
391
|
+
// Capture: a scroll inside any ancestor moves the anchor too, and scroll does not bubble.
|
|
392
|
+
window.addEventListener("scroll", schedule, true);
|
|
393
|
+
return () => {
|
|
394
|
+
if (frame)
|
|
395
|
+
cancelAnimationFrame(frame);
|
|
396
|
+
window.removeEventListener("resize", schedule);
|
|
397
|
+
window.removeEventListener("scroll", schedule, true);
|
|
398
|
+
};
|
|
399
|
+
}
|
|
@@ -2,10 +2,85 @@
|
|
|
2
2
|
/** From `app.css` `@layer components` — import the library/app stylesheet. */
|
|
3
3
|
export declare const FOCUS_BRAND_CLASS = "focus-brand";
|
|
4
4
|
export declare const FOCUS_NAV_CLASS = "focus-nav";
|
|
5
|
+
/** Every dialog panel: `dialog` and `alertdialog` are both dialogs to a focus trap. */
|
|
6
|
+
export declare const DIALOG_SELECTOR = "[role=\"dialog\"], [role=\"alertdialog\"]";
|
|
5
7
|
export declare function getFocusableElements(container: HTMLElement): HTMLElement[];
|
|
8
|
+
/** The region a `Toaster` renders its toasts in. */
|
|
9
|
+
export declare const TOAST_REGION_SELECTOR = "[data-zabi-toaster]";
|
|
10
|
+
/**
|
|
11
|
+
* Whether an event's target is in a toast. A toast is drawn over whatever is
|
|
12
|
+
* open, and a press on it is for the toast (to hold it, read it, dismiss it):
|
|
13
|
+
* a menu or a panel that closes on a press outside itself asks this first,
|
|
14
|
+
* and leaves a press on a toast alone.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isInsideToastRegion(target: unknown): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The controls of the toasts on screen. A toast is drawn over a modal
|
|
19
|
+
* overlay and can cover its buttons, so a focus trap that kept the keyboard
|
|
20
|
+
* out of it would leave no way to dismiss it: the trap takes these in, after
|
|
21
|
+
* the overlay's own controls.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getToastFocusables(): HTMLElement[];
|
|
24
|
+
/**
|
|
25
|
+
* One step of the Tab cycle of a modal overlay: through the controls of
|
|
26
|
+
* `container`, then through the toasts on screen, and round again. Focusables
|
|
27
|
+
* are looked up on every Tab, so what is added while the overlay is open is
|
|
28
|
+
* in the cycle. Focus that is nowhere in it goes to the first control.
|
|
29
|
+
*/
|
|
30
|
+
export declare function cycleTrappedFocus(container: HTMLElement, event: KeyboardEvent): void;
|
|
6
31
|
/** Tab wraps first↔last inside `container`. Caller should pair with `saveFocus` / `returnFocus`. */
|
|
7
32
|
export declare function trapFocus(container: HTMLElement): () => void;
|
|
8
33
|
export declare function saveFocus(): void;
|
|
9
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Restores focus from the last `saveFocus`. If that element has left the
|
|
36
|
+
* document, the element that now has its id takes the focus instead (a
|
|
37
|
+
* dropzone swapped for its Change button, say); with neither, nothing happens.
|
|
38
|
+
*/
|
|
10
39
|
export declare function returnFocus(): void;
|
|
11
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Moves focus into an overlay: to its first focusable element, or to the
|
|
42
|
+
* container itself when it has none (give the container `tabindex="-1"`), so
|
|
43
|
+
* focus never stays on the opener behind the backdrop.
|
|
44
|
+
*
|
|
45
|
+
* `preferred` is a CSS selector, looked up inside the container: the matching
|
|
46
|
+
* control takes focus instead of the first one, if it can take focus.
|
|
47
|
+
*/
|
|
48
|
+
export declare function focusFirstElement(container: HTMLElement, preferred?: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Joins the stack of open modal overlays (Modal, SlideUp, a drawer).
|
|
51
|
+
*
|
|
52
|
+
* Every overlay shares one z-index, so without this the paint order is the
|
|
53
|
+
* DOM order, and an overlay opened later but placed earlier in the document
|
|
54
|
+
* opens behind the first. `depth` is 0 for the first overlay and one more than
|
|
55
|
+
* the highest open one after that: put it on the overlay root as
|
|
56
|
+
* `z-index: calc(var(--z-modal) + depth)`.
|
|
57
|
+
*
|
|
58
|
+
* `panel` is the element with the dialog role. Call this when the overlay
|
|
59
|
+
* opens, in the browser, and `leave()` when it closes.
|
|
60
|
+
*/
|
|
61
|
+
export declare function joinOverlayStack(panel: HTMLElement): {
|
|
62
|
+
depth: number;
|
|
63
|
+
leave: () => void;
|
|
64
|
+
};
|
|
65
|
+
/** Whether `panel` is the overlay on top of the stack: the one opened last. */
|
|
66
|
+
export declare function isTopOverlay(panel: HTMLElement): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Keeps a modal overlay in charge of the keyboard when focus has left it
|
|
69
|
+
* without a Tab: the focused control was disabled or removed and the browser
|
|
70
|
+
* dropped focus on `<body>`, where the overlay's own key handlers never hear
|
|
71
|
+
* the key, and Tab would walk the page behind it.
|
|
72
|
+
*
|
|
73
|
+
* While installed, a Tab pressed with focus outside every dialog moves focus
|
|
74
|
+
* to the first focusable element of `container` (or to `container` itself),
|
|
75
|
+
* and Escape calls `onEscape`. Only the overlay on top of the stack acts (the
|
|
76
|
+
* one opened last), so every open overlay can install its own. An overlay that
|
|
77
|
+
* has not called `joinOverlayStack` is added to the stack for as long as the
|
|
78
|
+
* recovery is installed.
|
|
79
|
+
*
|
|
80
|
+
* `container` is the panel with `role="dialog"` or `"alertdialog"` and
|
|
81
|
+
* `aria-modal="true"`. Call it when the overlay opens, in the browser, and call
|
|
82
|
+
* the returned function when it closes.
|
|
83
|
+
*/
|
|
84
|
+
export declare function recoverStrayFocus(container: HTMLElement, options?: {
|
|
85
|
+
onEscape?: (event: KeyboardEvent) => void;
|
|
86
|
+
}): () => void;
|