zabi-components 7.0.2 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1924 -0
- package/README.md +287 -11
- package/THEME.md +149 -332
- package/THEMING.md +1329 -163
- package/dist/atoms/ActionPanel.svelte +24 -9
- package/dist/atoms/ActionPanel.svelte.d.ts +2 -0
- package/dist/atoms/Avatar.svelte +104 -0
- package/dist/atoms/Avatar.svelte.d.ts +34 -0
- package/dist/atoms/Badge.svelte +124 -58
- package/dist/atoms/Badge.svelte.d.ts +17 -5
- package/dist/atoms/Button.svelte +212 -62
- package/dist/atoms/Button.svelte.d.ts +33 -2
- package/dist/atoms/Card.svelte +31 -28
- package/dist/atoms/Card.svelte.d.ts +5 -2
- package/dist/atoms/CardContent.svelte +10 -2
- package/dist/atoms/CardContent.svelte.d.ts +2 -0
- package/dist/atoms/CardFooter.svelte +10 -2
- package/dist/atoms/CardFooter.svelte.d.ts +2 -0
- package/dist/atoms/CardHeader.svelte +26 -6
- package/dist/atoms/CardHeader.svelte.d.ts +2 -0
- package/dist/atoms/Checkbox.svelte +52 -21
- package/dist/atoms/Checkbox.svelte.d.ts +6 -2
- package/dist/atoms/CodeBlock.svelte +35 -9
- package/dist/atoms/CodeBlock.svelte.d.ts +13 -3
- package/dist/atoms/ColorPicker.svelte +272 -52
- package/dist/atoms/ColorPicker.svelte.d.ts +6 -1
- package/dist/atoms/Container.svelte +17 -10
- package/dist/atoms/DateField.svelte +107 -0
- package/dist/atoms/DateField.svelte.d.ts +53 -0
- package/dist/atoms/Divider.svelte +4 -4
- package/dist/atoms/FeatureCard.svelte +4 -3
- package/dist/atoms/FieldMessages.svelte +69 -0
- package/dist/atoms/FieldMessages.svelte.d.ts +23 -0
- package/dist/atoms/FloatingActionButton.svelte +174 -0
- package/dist/atoms/FloatingActionButton.svelte.d.ts +51 -0
- package/dist/atoms/Heading.svelte +93 -32
- package/dist/atoms/Heading.svelte.d.ts +24 -4
- package/dist/atoms/IconButton.svelte +242 -53
- package/dist/atoms/IconButton.svelte.d.ts +49 -4
- package/dist/atoms/Input.svelte +267 -74
- package/dist/atoms/Input.svelte.d.ts +32 -2
- package/dist/atoms/List.svelte +13 -2
- package/dist/atoms/List.svelte.d.ts +2 -0
- package/dist/atoms/ListItem.svelte +44 -11
- package/dist/atoms/ListItem.svelte.d.ts +5 -0
- package/dist/atoms/ListItemLeading.svelte +4 -2
- package/dist/atoms/ListItemLeading.svelte.d.ts +1 -1
- package/dist/atoms/OptimizedImage.svelte +11 -2
- package/dist/atoms/OptimizedImage.svelte.d.ts +2 -0
- package/dist/atoms/Progress.svelte +31 -9
- package/dist/atoms/Progress.svelte.d.ts +6 -0
- package/dist/atoms/Radio.svelte +23 -3
- package/dist/atoms/Radio.svelte.d.ts +6 -2
- package/dist/atoms/Rating.svelte +494 -0
- package/dist/atoms/Rating.svelte.d.ts +56 -0
- package/dist/atoms/Select.svelte +475 -135
- package/dist/atoms/Select.svelte.d.ts +52 -2
- package/dist/atoms/SelectionControl.svelte +99 -18
- package/dist/atoms/SelectionControl.svelte.d.ts +6 -3
- package/dist/atoms/Skeleton.svelte +5 -3
- package/dist/atoms/Slider.svelte +309 -0
- package/dist/atoms/Slider.svelte.d.ts +40 -0
- package/dist/atoms/Spinner.svelte +57 -0
- package/dist/atoms/Spinner.svelte.d.ts +19 -0
- package/dist/atoms/Table.svelte +152 -6
- package/dist/atoms/Table.svelte.d.ts +15 -3
- package/dist/atoms/TemporalField.svelte +140 -0
- package/dist/atoms/TemporalField.svelte.d.ts +32 -0
- package/dist/atoms/Text.svelte +56 -15
- package/dist/atoms/Text.svelte.d.ts +13 -4
- package/dist/atoms/Textarea.svelte +57 -45
- package/dist/atoms/Textarea.svelte.d.ts +14 -2
- package/dist/atoms/ThemeToggle.svelte +238 -56
- package/dist/atoms/ThemeToggle.svelte.d.ts +28 -3
- package/dist/atoms/TimeField.svelte +108 -0
- package/dist/atoms/TimeField.svelte.d.ts +54 -0
- package/dist/atoms/Toast.svelte +25 -10
- package/dist/atoms/Toast.svelte.d.ts +2 -0
- package/dist/atoms/Toggle.svelte +60 -19
- package/dist/atoms/Toggle.svelte.d.ts +18 -2
- package/dist/atoms/Tooltip.svelte +583 -40
- package/dist/atoms/Tooltip.svelte.d.ts +26 -0
- package/dist/atoms/ZabiStringsProvider.svelte +45 -0
- package/dist/atoms/ZabiStringsProvider.svelte.d.ts +27 -0
- package/dist/atoms/index.d.ts +17 -0
- package/dist/atoms/index.js +12 -0
- package/dist/atoms/selection-control.styles.d.ts +36 -5
- package/dist/atoms/selection-control.styles.js +40 -9
- package/dist/components/atoms/index.d.ts +17 -0
- package/dist/components/atoms/index.d.ts.map +1 -1
- package/dist/components/atoms/selection-control.styles.d.ts +36 -5
- package/dist/components/atoms/selection-control.styles.d.ts.map +1 -1
- package/dist/components/index.d.ts +83 -3
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/molecules/index.d.ts +46 -0
- package/dist/components/molecules/index.d.ts.map +1 -1
- package/dist/components/molecules/toast-store.d.ts +53 -7
- package/dist/components/molecules/toast-store.d.ts.map +1 -1
- package/dist/components/organisms/index.d.ts +6 -0
- package/dist/components/organisms/index.d.ts.map +1 -1
- package/dist/components/types/variants.d.ts +15 -1
- package/dist/components/types/variants.d.ts.map +1 -1
- package/dist/components/util/app-shell.d.ts +28 -0
- package/dist/components/util/app-shell.d.ts.map +1 -0
- package/dist/components/util/avatar.d.ts +36 -0
- package/dist/components/util/avatar.d.ts.map +1 -0
- package/dist/components/util/bottom-sheet.d.ts +30 -0
- package/dist/components/util/bottom-sheet.d.ts.map +1 -0
- package/dist/components/util/bottom-tab-bar.d.ts +35 -0
- package/dist/components/util/bottom-tab-bar.d.ts.map +1 -0
- package/dist/components/util/calendar.d.ts +56 -0
- package/dist/components/util/calendar.d.ts.map +1 -0
- package/dist/components/util/cn.d.ts +8 -0
- package/dist/components/util/cn.d.ts.map +1 -0
- package/dist/components/util/collapsible.d.ts +58 -0
- package/dist/components/util/collapsible.d.ts.map +1 -0
- package/dist/components/util/confirm-dialog.d.ts +12 -0
- package/dist/components/util/confirm-dialog.d.ts.map +1 -0
- package/dist/components/util/date.d.ts +96 -0
- package/dist/components/util/date.d.ts.map +1 -0
- package/dist/components/util/drawer.d.ts +13 -0
- package/dist/components/util/drawer.d.ts.map +1 -0
- package/dist/components/util/dropdown.d.ts +47 -0
- package/dist/components/util/dropdown.d.ts.map +1 -0
- package/dist/components/util/field.d.ts +39 -0
- package/dist/components/util/field.d.ts.map +1 -0
- package/dist/components/util/fit-in-viewport.d.ts +201 -0
- package/dist/components/util/fit-in-viewport.d.ts.map +1 -0
- package/dist/components/util/focus-utils.d.ts +75 -2
- package/dist/components/util/focus-utils.d.ts.map +1 -1
- package/dist/components/util/hydration.d.ts +45 -0
- package/dist/components/util/hydration.d.ts.map +1 -0
- package/dist/components/util/keyboard-inset.d.ts +18 -0
- package/dist/components/util/keyboard-inset.d.ts.map +1 -0
- package/dist/components/util/media-grid.d.ts +51 -0
- package/dist/components/util/media-grid.d.ts.map +1 -0
- package/dist/components/util/media.d.ts +6 -0
- package/dist/components/util/media.d.ts.map +1 -0
- package/dist/components/util/overlay-chrome.d.ts +53 -0
- package/dist/components/util/overlay-chrome.d.ts.map +1 -0
- package/dist/components/util/overlay.d.ts +72 -0
- package/dist/components/util/overlay.d.ts.map +1 -0
- package/dist/components/util/photo.d.ts +215 -0
- package/dist/components/util/photo.d.ts.map +1 -0
- package/dist/components/util/portal.d.ts +23 -0
- package/dist/components/util/portal.d.ts.map +1 -0
- package/dist/components/util/pull-to-refresh.d.ts +27 -0
- package/dist/components/util/pull-to-refresh.d.ts.map +1 -0
- package/dist/components/util/radio-keys.d.ts +25 -0
- package/dist/components/util/radio-keys.d.ts.map +1 -0
- package/dist/components/util/rating.d.ts +23 -0
- package/dist/components/util/rating.d.ts.map +1 -0
- package/dist/components/util/ready-made-strings.d.ts +77 -0
- package/dist/components/util/ready-made-strings.d.ts.map +1 -0
- package/dist/components/util/scroll-padding.d.ts +20 -0
- package/dist/components/util/scroll-padding.d.ts.map +1 -0
- package/dist/components/util/segmented-control.d.ts +16 -0
- package/dist/components/util/segmented-control.d.ts.map +1 -0
- package/dist/components/util/select.d.ts +41 -0
- package/dist/components/util/select.d.ts.map +1 -0
- package/dist/components/util/sheet-drag.d.ts +60 -0
- package/dist/components/util/sheet-drag.d.ts.map +1 -0
- package/dist/components/util/sidebar.d.ts +63 -0
- package/dist/components/util/sidebar.d.ts.map +1 -0
- package/dist/components/util/sortable-list.d.ts +65 -0
- package/dist/components/util/sortable-list.d.ts.map +1 -0
- package/dist/components/util/ssr-safe.d.ts +4 -4
- package/dist/components/util/ssr-safe.d.ts.map +1 -1
- package/dist/components/util/stepper.d.ts +40 -0
- package/dist/components/util/stepper.d.ts.map +1 -0
- package/dist/components/util/swipeable-list-item.d.ts +36 -0
- package/dist/components/util/swipeable-list-item.d.ts.map +1 -0
- package/dist/components/util/theme-mode.d.ts +80 -0
- package/dist/components/util/theme-mode.d.ts.map +1 -0
- package/dist/components/util/toaster.d.ts +93 -0
- package/dist/components/util/toaster.d.ts.map +1 -0
- package/dist/components/util/tooltip.d.ts +10 -0
- package/dist/components/util/tooltip.d.ts.map +1 -0
- package/dist/components/util/top-navbar.d.ts +11 -0
- package/dist/components/util/top-navbar.d.ts.map +1 -0
- package/dist/components/util/touch-target.d.ts +31 -0
- package/dist/components/util/touch-target.d.ts.map +1 -0
- package/dist/components/util/zabi-strings.d.ts +133 -0
- package/dist/components/util/zabi-strings.d.ts.map +1 -0
- package/dist/create-theme/cli.js +169 -0
- package/dist/create-theme/index.d.ts +176 -0
- package/dist/create-theme/index.js +817 -0
- package/dist/create-theme/lib/ramp-math.js +128 -0
- package/dist/create-theme/lib/resolve.js +141 -0
- package/dist/create-theme/theme-data.js +1116 -0
- package/dist/index.d.ts +83 -3
- package/dist/index.js +60 -8
- package/dist/molecules/Alert.svelte +73 -66
- package/dist/molecules/Alert.svelte.d.ts +9 -1
- package/dist/molecules/AppBar.svelte +415 -0
- package/dist/molecules/AppBar.svelte.d.ts +69 -0
- package/dist/molecules/AvatarGroup.svelte +116 -0
- package/dist/molecules/AvatarGroup.svelte.d.ts +40 -0
- package/dist/molecules/BottomSheet.svelte +540 -0
- package/dist/molecules/BottomSheet.svelte.d.ts +93 -0
- package/dist/molecules/BottomTabBar.svelte +297 -0
- package/dist/molecules/BottomTabBar.svelte.d.ts +64 -0
- package/dist/molecules/Calendar.svelte +597 -0
- package/dist/molecules/Calendar.svelte.d.ts +72 -0
- package/dist/molecules/Collapsible.svelte +243 -0
- package/dist/molecules/Collapsible.svelte.d.ts +44 -0
- package/dist/molecules/CollapsibleGroup.svelte +126 -0
- package/dist/molecules/CollapsibleGroup.svelte.d.ts +14 -0
- package/dist/molecules/ComponentDemo.svelte +25 -5
- package/dist/molecules/ComponentDemo.svelte.d.ts +5 -0
- package/dist/molecules/ConfirmDialog.svelte +253 -0
- package/dist/molecules/ConfirmDialog.svelte.d.ts +55 -0
- package/dist/molecules/ContactForm.svelte +46 -19
- package/dist/molecules/ContactForm.svelte.d.ts +10 -0
- package/dist/molecules/Drawer.svelte +394 -0
- package/dist/molecules/Drawer.svelte.d.ts +55 -0
- package/dist/molecules/Dropdown.svelte +540 -50
- package/dist/molecules/Dropdown.svelte.d.ts +49 -6
- package/dist/molecules/DropdownItem.svelte +122 -0
- package/dist/molecules/DropdownItem.svelte.d.ts +28 -0
- package/dist/molecules/EmptyState.svelte +56 -10
- package/dist/molecules/EmptyState.svelte.d.ts +8 -0
- package/dist/molecules/Form.svelte +25 -14
- package/dist/molecules/Form.svelte.d.ts +13 -5
- package/dist/molecules/FormField.svelte +11 -2
- package/dist/molecules/FormField.svelte.d.ts +2 -0
- package/dist/molecules/Header.svelte +13 -3
- package/dist/molecules/Header.svelte.d.ts +2 -0
- package/dist/molecules/ImageUpload.svelte +422 -70
- package/dist/molecules/ImageUpload.svelte.d.ts +61 -5
- package/dist/molecules/MediaGrid.svelte +527 -0
- package/dist/molecules/MediaGrid.svelte.d.ts +77 -0
- package/dist/molecules/Modal.svelte +340 -45
- package/dist/molecules/Modal.svelte.d.ts +59 -7
- package/dist/molecules/NavigationMenu.svelte +15 -3
- package/dist/molecules/NavigationMenu.svelte.d.ts +4 -0
- package/dist/molecules/NavigationMenuContent.svelte +91 -36
- package/dist/molecules/NavigationMenuContent.svelte.d.ts +2 -0
- package/dist/molecules/NavigationMenuItem.svelte +10 -3
- package/dist/molecules/NavigationMenuItem.svelte.d.ts +2 -0
- package/dist/molecules/NavigationMenuLink.svelte +10 -2
- package/dist/molecules/NavigationMenuLink.svelte.d.ts +2 -0
- package/dist/molecules/NavigationMenuList.svelte +19 -4
- package/dist/molecules/NavigationMenuList.svelte.d.ts +2 -0
- package/dist/molecules/NavigationMenuTrigger.svelte +16 -3
- package/dist/molecules/NavigationMenuTrigger.svelte.d.ts +2 -0
- package/dist/molecules/Page.svelte +38 -2
- package/dist/molecules/Page.svelte.d.ts +13 -0
- package/dist/molecules/PhotoGrid.svelte +433 -0
- package/dist/molecules/PhotoGrid.svelte.d.ts +62 -0
- package/dist/molecules/PhotoViewer.svelte +1116 -0
- package/dist/molecules/PhotoViewer.svelte.d.ts +56 -0
- package/dist/molecules/PropsTable.svelte +26 -11
- package/dist/molecules/PropsTable.svelte.d.ts +5 -0
- package/dist/molecules/PullToRefresh.svelte +263 -0
- package/dist/molecules/PullToRefresh.svelte.d.ts +52 -0
- package/dist/molecules/RadioGroup.svelte +57 -15
- package/dist/molecules/RadioGroup.svelte.d.ts +16 -3
- package/dist/molecules/Section.svelte +13 -5
- package/dist/molecules/Section.svelte.d.ts +3 -1
- package/dist/molecules/SegmentedControl.svelte +323 -0
- package/dist/molecules/SegmentedControl.svelte.d.ts +34 -0
- package/dist/molecules/SidebarBrandHeader.svelte +24 -5
- package/dist/molecules/SidebarBrandHeader.svelte.d.ts +5 -0
- package/dist/molecules/SidebarFooter.svelte +39 -8
- package/dist/molecules/SidebarFooter.svelte.d.ts +5 -0
- package/dist/molecules/SidebarNavSection.svelte +12 -4
- package/dist/molecules/SidebarNavSection.svelte.d.ts +2 -0
- package/dist/molecules/SlideUp.svelte +253 -30
- package/dist/molecules/SlideUp.svelte.d.ts +31 -4
- package/dist/molecules/SortableList.svelte +632 -0
- package/dist/molecules/SortableList.svelte.d.ts +69 -0
- package/dist/molecules/Stepper.svelte +548 -0
- package/dist/molecules/Stepper.svelte.d.ts +39 -0
- package/dist/molecules/StickyActionBar.svelte +191 -0
- package/dist/molecules/StickyActionBar.svelte.d.ts +65 -0
- package/dist/molecules/SwipeableListItem.svelte +334 -0
- package/dist/molecules/SwipeableListItem.svelte.d.ts +54 -0
- package/dist/molecules/Tabs.svelte +254 -24
- package/dist/molecules/Tabs.svelte.d.ts +15 -4
- package/dist/molecules/Toaster.svelte +352 -6
- package/dist/molecules/Toaster.svelte.d.ts +95 -2
- package/dist/molecules/ToasterToast.svelte +279 -62
- package/dist/molecules/ToasterToast.svelte.d.ts +11 -0
- package/dist/molecules/UnsavedChangesBar.svelte +212 -0
- package/dist/molecules/UnsavedChangesBar.svelte.d.ts +43 -0
- package/dist/molecules/index.d.ts +46 -0
- package/dist/molecules/index.js +27 -0
- package/dist/molecules/toast-store.d.ts +53 -7
- package/dist/molecules/toast-store.js +21 -0
- package/dist/organisms/AppShell.svelte +196 -0
- package/dist/organisms/AppShell.svelte.d.ts +61 -0
- package/dist/organisms/SidebarAccountPanel.svelte +111 -12
- package/dist/organisms/SidebarAccountPanel.svelte.d.ts +21 -0
- package/dist/organisms/SidebarNavigation.svelte +193 -69
- package/dist/organisms/SidebarNavigation.svelte.d.ts +31 -1
- package/dist/organisms/SidebarPanel.svelte +45 -16
- package/dist/organisms/SidebarPanel.svelte.d.ts +2 -0
- package/dist/organisms/SidebarShell.svelte +263 -0
- package/dist/organisms/SidebarShell.svelte.d.ts +106 -0
- package/dist/organisms/TopNavbar.svelte +329 -33
- package/dist/organisms/TopNavbar.svelte.d.ts +28 -0
- package/dist/organisms/index.d.ts +6 -0
- package/dist/organisms/index.js +4 -0
- package/dist/routes/lib/variant-utils.d.ts +26 -0
- package/dist/routes/lib/{variant-utils.ts → variant-utils.js} +15 -46
- package/dist/types/components.d.ts +4 -0
- package/dist/types/components.d.ts.map +1 -1
- package/dist/types/events.js +1 -0
- package/dist/types/index.d.ts +605 -25
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -0
- package/dist/types/variants.ts +17 -1
- package/dist/util/app-shell.d.ts +27 -0
- package/dist/util/app-shell.js +72 -0
- package/dist/util/avatar.d.ts +35 -0
- package/dist/util/avatar.js +52 -0
- package/dist/util/bottom-sheet.d.ts +29 -0
- package/dist/util/bottom-sheet.js +43 -0
- package/dist/util/bottom-tab-bar.d.ts +34 -0
- package/dist/util/bottom-tab-bar.js +54 -0
- package/dist/util/calendar.d.ts +55 -0
- package/dist/util/calendar.js +74 -0
- package/dist/util/cn.d.ts +7 -0
- package/dist/util/cn.js +48 -0
- package/dist/util/collapsible.d.ts +57 -0
- package/dist/util/collapsible.js +23 -0
- package/dist/util/confirm-dialog.d.ts +11 -0
- package/dist/util/confirm-dialog.js +2 -0
- package/dist/util/date.d.ts +95 -0
- package/dist/util/date.js +237 -0
- package/dist/util/drawer.d.ts +12 -0
- package/dist/util/drawer.js +7 -0
- package/dist/util/dropdown.d.ts +46 -0
- package/dist/util/dropdown.js +21 -0
- package/dist/util/field.d.ts +38 -0
- package/dist/util/field.js +38 -0
- package/dist/util/fit-in-viewport.d.ts +200 -0
- package/dist/util/fit-in-viewport.js +399 -0
- package/dist/util/focus-utils.d.ts +75 -2
- package/dist/util/focus-utils.js +182 -9
- package/dist/util/hydration.d.ts +44 -0
- package/dist/util/hydration.js +58 -0
- package/dist/util/keyboard-inset.d.ts +17 -0
- package/dist/util/keyboard-inset.js +53 -0
- package/dist/util/media-grid.d.ts +50 -0
- package/dist/util/media-grid.js +81 -0
- package/dist/util/media.d.ts +5 -0
- package/dist/util/media.js +10 -0
- package/dist/util/overlay-chrome.d.ts +52 -0
- package/dist/util/overlay-chrome.js +56 -0
- package/dist/util/overlay.d.ts +71 -0
- package/dist/util/overlay.js +240 -0
- package/dist/util/photo.d.ts +214 -0
- package/dist/util/photo.js +206 -0
- package/dist/util/portal.d.ts +22 -0
- package/dist/util/portal.js +50 -0
- package/dist/util/pull-to-refresh.d.ts +26 -0
- package/dist/util/pull-to-refresh.js +30 -0
- package/dist/util/radio-keys.d.ts +24 -0
- package/dist/util/radio-keys.js +49 -0
- package/dist/util/rating.d.ts +22 -0
- package/dist/util/rating.js +26 -0
- package/dist/util/ready-made-strings.d.ts +76 -0
- package/dist/util/ready-made-strings.js +67 -0
- package/dist/util/scroll-padding.d.ts +19 -0
- package/dist/util/scroll-padding.js +44 -0
- package/dist/util/segmented-control.d.ts +15 -0
- package/dist/util/segmented-control.js +1 -0
- package/dist/util/select.d.ts +40 -0
- package/dist/util/select.js +63 -0
- package/dist/util/sheet-drag.d.ts +59 -0
- package/dist/util/sheet-drag.js +241 -0
- package/dist/util/sidebar.d.ts +62 -0
- package/dist/util/sidebar.js +38 -0
- package/dist/util/sortable-list.d.ts +64 -0
- package/dist/util/sortable-list.js +53 -0
- package/dist/util/ssr-safe.d.ts +4 -4
- package/dist/util/stepper.d.ts +39 -0
- package/dist/util/stepper.js +38 -0
- package/dist/util/swipeable-list-item.d.ts +35 -0
- package/dist/util/swipeable-list-item.js +32 -0
- package/dist/util/theme-mode.d.ts +79 -0
- package/dist/util/theme-mode.js +121 -0
- package/dist/util/toaster.d.ts +92 -0
- package/dist/util/toaster.js +75 -0
- package/dist/util/tooltip.d.ts +9 -0
- package/dist/util/tooltip.js +18 -0
- package/dist/util/top-navbar.d.ts +10 -0
- package/dist/util/top-navbar.js +5 -0
- package/dist/util/touch-target.d.ts +30 -0
- package/dist/util/touch-target.js +30 -0
- package/dist/util/zabi-strings.d.ts +132 -0
- package/dist/util/zabi-strings.js +105 -0
- package/dist/zabi-components-colors.css +5 -2
- package/dist/zabi-components-theme-dark-only.css +574 -225
- package/dist/zabi-components-theme-dark.css +574 -225
- package/dist/zabi-components-theme-only.css +1680 -317
- package/dist/zabi-components-theme.css +1680 -317
- package/dist/zabi-components.css +4473 -1158
- package/docs/lucide-icons.md +41 -16
- package/docs/theme-imports.md +81 -11
- package/package.json +51 -29
- package/dist/lib/layout-width-tokens.d.ts +0 -17
- package/dist/lib/layout-width-tokens.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Button.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Button.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Input.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Input.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/List.d.ts +0 -3
- package/dist/lib/showcase/component-docs/List.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Modal.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Modal.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Radio.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Radio.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts +0 -3
- package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/Skeleton.d.ts +0 -3
- package/dist/lib/showcase/component-docs/Skeleton.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/_shared.d.ts +0 -12
- package/dist/lib/showcase/component-docs/_shared.d.ts.map +0 -1
- package/dist/lib/showcase/component-docs/index.d.ts +0 -4
- package/dist/lib/showcase/component-docs/index.d.ts.map +0 -1
- package/dist/lib/showcase/components-catalog.d.ts +0 -3
- package/dist/lib/showcase/components-catalog.d.ts.map +0 -1
- package/dist/lib/showcase/components-showcase-constants.d.ts +0 -89
- package/dist/lib/showcase/components-showcase-constants.d.ts.map +0 -1
- package/dist/lib/showcase/docs-sidebar-helpers.d.ts +0 -15
- package/dist/lib/showcase/docs-sidebar-helpers.d.ts.map +0 -1
- package/dist/routes/lib/focus-utils.d.ts +0 -12
- package/dist/routes/lib/focus-utils.ts +0 -110
- package/dist/routes/lib/ssr-safe.ts +0 -58
- package/scripts/fix-lucide-svelte-icon-dts.js +0 -35
|
@@ -1,28 +1,99 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { mergeStrings } from "../util/ready-made-strings.js";
|
|
3
|
+
import { zabiStringsFor } from "../util/zabi-strings.js";
|
|
2
4
|
import Input from "./Input.svelte";
|
|
3
|
-
import { onMount,
|
|
5
|
+
import { onMount, tick } from "svelte";
|
|
6
|
+
import { isInsideToastRegion } from "../util/focus-utils.js";
|
|
7
|
+
import {
|
|
8
|
+
measurePlacement,
|
|
9
|
+
watchViewport,
|
|
10
|
+
type PanelPlacement,
|
|
11
|
+
} from "../util/fit-in-viewport.js";
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_COLOR_PICKER_STRINGS,
|
|
14
|
+
type ColorPickerStrings,
|
|
15
|
+
} from "../util/ready-made-strings.js";
|
|
4
16
|
|
|
5
17
|
interface Props {
|
|
18
|
+
/** Extra classes for the host element. */
|
|
19
|
+
class?: string;
|
|
6
20
|
value?: string;
|
|
7
21
|
label?: string;
|
|
8
22
|
disabled?: boolean;
|
|
9
23
|
placeholder?: string;
|
|
24
|
+
/** The accessible names of its parts, for another language. */
|
|
25
|
+
strings?: Partial<ColorPickerStrings>;
|
|
10
26
|
onchange?: (event: Event) => void;
|
|
11
27
|
}
|
|
12
28
|
|
|
13
29
|
let {
|
|
14
|
-
|
|
30
|
+
class: className = "",
|
|
31
|
+
value = $bindable<Exclude<Props["value"], undefined>>(),
|
|
15
32
|
label = "",
|
|
16
33
|
disabled = false,
|
|
17
34
|
placeholder = "#000000",
|
|
35
|
+
strings,
|
|
18
36
|
onchange,
|
|
19
37
|
...restProps
|
|
20
38
|
}: Props = $props();
|
|
21
39
|
|
|
40
|
+
// No fallback on a bindable prop: Svelte refuses `bind:…={undefined}` on
|
|
41
|
+
// one that has a fallback (`props_invalid_value`), and a page that throws
|
|
42
|
+
// while it hydrates never becomes interactive. The default is applied
|
|
43
|
+
// here instead: at once, for the server and the first render, and again
|
|
44
|
+
// whenever a parent hands back `undefined`.
|
|
45
|
+
const applyDefaults = () => {
|
|
46
|
+
if (value === undefined) value = "";
|
|
47
|
+
};
|
|
48
|
+
applyDefaults();
|
|
49
|
+
$effect.pre(applyDefaults);
|
|
50
|
+
|
|
51
|
+
/** The app-wide words for this component, from a `ZabiStringsProvider` above it, if there is one. */
|
|
52
|
+
const provided = zabiStringsFor("colorPicker");
|
|
53
|
+
const text = $derived(mergeStrings(DEFAULT_COLOR_PICKER_STRINGS, provided(), strings));
|
|
54
|
+
|
|
22
55
|
let isOpen = $state(false);
|
|
23
|
-
|
|
56
|
+
/** The pointer that is down on the colour map, if one is. */
|
|
57
|
+
let dragPointer: number | null = null;
|
|
24
58
|
let pickerContainer: HTMLDivElement | undefined;
|
|
25
|
-
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Where the popover is. It hangs from the right edge of the swatch and is
|
|
62
|
+
* 20rem wide, so with the swatch in the left half of a phone screen it ran
|
|
63
|
+
* off the left edge. It is slid back to 8px from the edge, narrowed when
|
|
64
|
+
* it is wider than the screen, and placed against the viewport when a box
|
|
65
|
+
* that scrolls around it would cut it off (`fixed`). A popover that fits
|
|
66
|
+
* is not touched.
|
|
67
|
+
*/
|
|
68
|
+
let popoverElement = $state<HTMLDivElement | null>(null);
|
|
69
|
+
let placed = $state<PanelPlacement | null>(null);
|
|
70
|
+
|
|
71
|
+
$effect(() => {
|
|
72
|
+
const panel = popoverElement;
|
|
73
|
+
const anchor = panel?.parentElement;
|
|
74
|
+
if (!isOpen || !panel || !anchor) {
|
|
75
|
+
placed = null;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const update = () => {
|
|
79
|
+
// `top-12` is 3rem from the top of the box around the swatch,
|
|
80
|
+
// which can be a little taller than the swatch: the gap is what
|
|
81
|
+
// is left under that box, so the popover is where the class puts it.
|
|
82
|
+
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
|
|
83
|
+
const gap = rem * 3 - anchor.getBoundingClientRect().height;
|
|
84
|
+
placed = measurePlacement(
|
|
85
|
+
anchor,
|
|
86
|
+
panel,
|
|
87
|
+
{ block: "bottom", inline: "end" },
|
|
88
|
+
// Placed with `right`, in either writing direction, and always below.
|
|
89
|
+
{ margin: 8, gap, flipBlock: false, flipInline: false, rtl: false },
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
update();
|
|
93
|
+
return watchViewport(update, panel);
|
|
94
|
+
});
|
|
95
|
+
let colorMap = $state<HTMLCanvasElement | undefined>();
|
|
96
|
+
let swatchButton: HTMLButtonElement | undefined;
|
|
26
97
|
let colorMapContainer: HTMLDivElement | undefined;
|
|
27
98
|
|
|
28
99
|
// Working color in HSL (h: 0–360; s, l: 0–100).
|
|
@@ -35,7 +106,14 @@
|
|
|
35
106
|
return hexPattern.test(hex);
|
|
36
107
|
}
|
|
37
108
|
|
|
38
|
-
|
|
109
|
+
/** `#f00` → `#ff0000`; 6-digit input is returned unchanged. */
|
|
110
|
+
function expandHex(hex: string): string {
|
|
111
|
+
if (hex.length !== 4) return hex;
|
|
112
|
+
return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function hexToHsl(rawHex: string): [number, number, number] {
|
|
116
|
+
const hex = expandHex(rawHex);
|
|
39
117
|
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
40
118
|
const g = parseInt(hex.slice(3, 5), 16) / 255;
|
|
41
119
|
const b = parseInt(hex.slice(5, 7), 16) / 255;
|
|
@@ -98,9 +176,7 @@
|
|
|
98
176
|
const variant = $derived(value && !isValidHex(value) ? "error" : "default");
|
|
99
177
|
|
|
100
178
|
const message = $derived(
|
|
101
|
-
value && !isValidHex(value)
|
|
102
|
-
? "Please enter a valid hex color (e.g., #ff0000 or #f00)"
|
|
103
|
-
: "",
|
|
179
|
+
value && !isValidHex(value) ? text.invalidHex : "",
|
|
104
180
|
);
|
|
105
181
|
|
|
106
182
|
function handleInput(event: Event) {
|
|
@@ -132,7 +208,7 @@
|
|
|
132
208
|
commitCurrentValue(event);
|
|
133
209
|
}
|
|
134
210
|
|
|
135
|
-
async function togglePicker() {
|
|
211
|
+
async function togglePicker(event?: MouseEvent) {
|
|
136
212
|
if (!disabled) {
|
|
137
213
|
if (isOpen) {
|
|
138
214
|
commitCurrentValue(new Event("change"));
|
|
@@ -141,13 +217,41 @@
|
|
|
141
217
|
if (isOpen && value && isValidHex(value)) {
|
|
142
218
|
updateFromHex(value);
|
|
143
219
|
}
|
|
144
|
-
|
|
220
|
+
// A click from the keyboard has no pointer (`detail` is 0): focus
|
|
221
|
+
// goes in, to the first stop of the popover. A press keeps it.
|
|
222
|
+
if (isOpen && event && event.detail === 0) {
|
|
145
223
|
await tick();
|
|
146
|
-
|
|
224
|
+
saturationInput?.focus({ preventScroll: true });
|
|
147
225
|
}
|
|
148
226
|
}
|
|
149
227
|
}
|
|
150
228
|
|
|
229
|
+
/** Escape inside the popover, or on the swatch while it is open: close, and back to the swatch. */
|
|
230
|
+
function handleEscape(event: KeyboardEvent) {
|
|
231
|
+
if (event.key !== "Escape" || !isOpen) return;
|
|
232
|
+
// Consumed here: a Modal or Drawer around the picker stays open.
|
|
233
|
+
event.stopPropagation();
|
|
234
|
+
event.preventDefault();
|
|
235
|
+
commitCurrentValue(new Event("change"));
|
|
236
|
+
isOpen = false;
|
|
237
|
+
swatchButton?.focus({ preventScroll: true });
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// The map is drawn for the hue it is open at, and again for any change of
|
|
241
|
+
// it: the hue slider, a typed hex, or a `value` set from outside.
|
|
242
|
+
$effect(() => {
|
|
243
|
+
void hue;
|
|
244
|
+
if (isOpen && colorMap) drawColorMap();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// A `value` changed from outside while open (not the one the sliders just made).
|
|
248
|
+
$effect(() => {
|
|
249
|
+
if (!isOpen || !value || !isValidHex(value)) return;
|
|
250
|
+
if (expandHex(value).toLowerCase() !== hslToHex(hue, saturation, lightness)) {
|
|
251
|
+
updateFromHex(value);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
151
255
|
function drawColorMap() {
|
|
152
256
|
if (!colorMap) return;
|
|
153
257
|
const ctx = colorMap.getContext("2d");
|
|
@@ -167,34 +271,93 @@
|
|
|
167
271
|
}
|
|
168
272
|
}
|
|
169
273
|
|
|
170
|
-
|
|
171
|
-
|
|
274
|
+
/**
|
|
275
|
+
* The colour map: saturation across, lightness up.
|
|
276
|
+
*
|
|
277
|
+
* It is two sliders on one surface, and is built as that: two visually
|
|
278
|
+
* hidden `<input type="range">`, which is what a screen reader, a switch
|
|
279
|
+
* and a voice command already know how to name, read and set ("Saturation,
|
|
280
|
+
* slider, 50%"). A single element cannot say it: `role="slider"` has one
|
|
281
|
+
* value, and an unnamed `role="button"`, which this was, has none.
|
|
282
|
+
*
|
|
283
|
+
* For the keyboard the two act as one map. Left and right move
|
|
284
|
+
* saturation and up and down lightness, from whichever slider has focus,
|
|
285
|
+
* and focus goes to the one that moved, so its new value is what is
|
|
286
|
+
* read out. Shift moves by ten. Only the first is a Tab stop.
|
|
287
|
+
*
|
|
288
|
+
* The surface takes pointer events, so a finger and a pen work as a mouse
|
|
289
|
+
* does; it used to listen for `mousedown` alone. The whole surface is the
|
|
290
|
+
* target (the mark on it is not something to hit), and `touch-none`
|
|
291
|
+
* keeps a drag on it from scrolling the page.
|
|
292
|
+
*/
|
|
293
|
+
let saturationInput = $state<HTMLInputElement | null>(null);
|
|
294
|
+
let lightnessInput = $state<HTMLInputElement | null>(null);
|
|
295
|
+
|
|
296
|
+
const percent = (value: number) => Math.max(0, Math.min(100, Math.round(value)));
|
|
297
|
+
|
|
298
|
+
function setFromPoint(event: PointerEvent) {
|
|
299
|
+
if (!colorMapContainer) return;
|
|
172
300
|
const rect = colorMapContainer.getBoundingClientRect();
|
|
173
|
-
|
|
174
|
-
|
|
301
|
+
if (rect.width === 0 || rect.height === 0) return;
|
|
302
|
+
saturation = percent(((event.clientX - rect.left) / rect.width) * 100);
|
|
303
|
+
lightness = percent(100 - ((event.clientY - rect.top) / rect.height) * 100);
|
|
304
|
+
updateHexFromHsl();
|
|
305
|
+
}
|
|
175
306
|
|
|
176
|
-
|
|
177
|
-
|
|
307
|
+
function handleMapPointerDown(event: PointerEvent) {
|
|
308
|
+
if (event.pointerType === "mouse" && event.button !== 0) return;
|
|
309
|
+
dragPointer = event.pointerId;
|
|
310
|
+
try {
|
|
311
|
+
colorMapContainer?.setPointerCapture(event.pointerId);
|
|
312
|
+
} catch {
|
|
313
|
+
/* a test DOM, or a pointer that is already gone */
|
|
314
|
+
}
|
|
315
|
+
setFromPoint(event);
|
|
316
|
+
// The keys carry on from where the pointer left it.
|
|
317
|
+
saturationInput?.focus({ preventScroll: true });
|
|
318
|
+
// Not a text selection, and not a second focus change from the press itself.
|
|
319
|
+
event.preventDefault();
|
|
320
|
+
}
|
|
178
321
|
|
|
179
|
-
|
|
180
|
-
|
|
322
|
+
function handleMapPointerMove(event: PointerEvent) {
|
|
323
|
+
if (dragPointer !== event.pointerId) return;
|
|
324
|
+
setFromPoint(event);
|
|
181
325
|
}
|
|
182
326
|
|
|
183
|
-
function
|
|
184
|
-
if (
|
|
185
|
-
|
|
327
|
+
function handleMapPointerUp(event: PointerEvent) {
|
|
328
|
+
if (dragPointer !== event.pointerId) return;
|
|
329
|
+
dragPointer = null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function handleMapKeydown(event: KeyboardEvent) {
|
|
333
|
+
const step = event.shiftKey ? 10 : 1;
|
|
334
|
+
const across = event.key === "ArrowRight" ? step : event.key === "ArrowLeft" ? -step : 0;
|
|
335
|
+
const up = event.key === "ArrowUp" ? step : event.key === "ArrowDown" ? -step : 0;
|
|
336
|
+
if (across === 0 && up === 0) return;
|
|
337
|
+
// The slider's own handling would move the focused one for all four keys.
|
|
338
|
+
event.preventDefault();
|
|
339
|
+
if (across !== 0) {
|
|
340
|
+
saturation = percent(saturation + across);
|
|
341
|
+
saturationInput?.focus({ preventScroll: true });
|
|
342
|
+
} else {
|
|
343
|
+
lightness = percent(lightness + up);
|
|
344
|
+
lightnessInput?.focus({ preventScroll: true });
|
|
186
345
|
}
|
|
346
|
+
updateHexFromHsl();
|
|
187
347
|
}
|
|
188
348
|
|
|
189
|
-
|
|
190
|
-
|
|
349
|
+
/** Home, End, Page Up and Down, and what assistive technology sets: the slider's own value. */
|
|
350
|
+
function handleMapInput(axis: "saturation" | "lightness", event: Event) {
|
|
351
|
+
const next = percent(Number((event.currentTarget as HTMLInputElement).value));
|
|
352
|
+
if (axis === "saturation") saturation = next;
|
|
353
|
+
else lightness = next;
|
|
354
|
+
updateHexFromHsl();
|
|
191
355
|
}
|
|
192
356
|
|
|
193
357
|
function handleHueChange(event: Event) {
|
|
194
358
|
const target = event.target as HTMLInputElement;
|
|
195
359
|
hue = parseInt(target.value);
|
|
196
360
|
updateHexFromHsl();
|
|
197
|
-
drawColorMap();
|
|
198
361
|
}
|
|
199
362
|
|
|
200
363
|
function setPickerContainer(node: HTMLDivElement) {
|
|
@@ -231,11 +394,13 @@
|
|
|
231
394
|
}
|
|
232
395
|
|
|
233
396
|
function handleClickOutside(event: MouseEvent) {
|
|
397
|
+
// A toast lies over the panel; a press on it is for the toast.
|
|
398
|
+
if (isInsideToastRegion(event.target)) return;
|
|
234
399
|
if (
|
|
235
400
|
pickerContainer &&
|
|
236
401
|
!pickerContainer.contains(event.target as Node) &&
|
|
237
402
|
!(event.target as HTMLElement).closest(
|
|
238
|
-
|
|
403
|
+
"[data-color-picker-open]",
|
|
239
404
|
)
|
|
240
405
|
) {
|
|
241
406
|
commitCurrentValue(new Event("change"));
|
|
@@ -248,22 +413,25 @@
|
|
|
248
413
|
updateFromHex(value);
|
|
249
414
|
}
|
|
250
415
|
window.addEventListener("mousedown", handleClickOutside);
|
|
251
|
-
window.addEventListener("mouseup", handleMouseUp);
|
|
252
|
-
window.addEventListener("mousemove", handleColorMapDrag);
|
|
253
|
-
});
|
|
254
416
|
|
|
255
|
-
|
|
256
|
-
window.
|
|
257
|
-
|
|
258
|
-
|
|
417
|
+
// Teardown is returned from onMount rather than registered with
|
|
418
|
+
// onDestroy: onDestroy also runs on the server, where there is no window.
|
|
419
|
+
return () => {
|
|
420
|
+
window.removeEventListener("mousedown", handleClickOutside);
|
|
421
|
+
};
|
|
259
422
|
});
|
|
260
423
|
|
|
261
424
|
const displayColor = $derived(value && isValidHex(value) ? value : placeholder);
|
|
262
425
|
const pickerIndicatorX = $derived(`${saturation}%`);
|
|
263
426
|
const pickerIndicatorY = $derived(`${100 - lightness}%`);
|
|
427
|
+
/** What a slider of the map says: its own value, and the colour the two make. */
|
|
428
|
+
const mapValueText = (value: number) => `${Math.round(value)}%, ${hslToHex(hue, saturation, lightness)}`;
|
|
429
|
+
/** A ring around a surface whose slider has keyboard focus: the sliders themselves are not drawn. */
|
|
430
|
+
const RING_WITHIN =
|
|
431
|
+
"has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-focus-ring";
|
|
264
432
|
</script>
|
|
265
433
|
|
|
266
|
-
<div {...restProps}>
|
|
434
|
+
<div class={className} {...restProps}>
|
|
267
435
|
<div class="flex items-start gap-2">
|
|
268
436
|
<div class="flex-1">
|
|
269
437
|
<Input
|
|
@@ -275,7 +443,7 @@
|
|
|
275
443
|
{message}
|
|
276
444
|
oninput={handleInput}
|
|
277
445
|
onblur={handleBlur}
|
|
278
|
-
aria-label=
|
|
446
|
+
aria-label={label ? undefined : text.hexInput}
|
|
279
447
|
/>
|
|
280
448
|
</div>
|
|
281
449
|
<div class="relative shrink-0 mt-6">
|
|
@@ -283,48 +451,100 @@
|
|
|
283
451
|
type="button"
|
|
284
452
|
onclick={togglePicker}
|
|
285
453
|
{disabled}
|
|
286
|
-
class="focus-ring w-11 h-11 rounded-
|
|
454
|
+
class="focus-ring w-11 h-11 rounded-control border-2 border-card shrink-0 cursor-pointer hover:ring-2 hover:ring-border active:ring-2 active:ring-border-strong transition-colors disabled:cursor-not-allowed disabled:opacity-50"
|
|
287
455
|
style="background-color: {displayColor};"
|
|
288
|
-
aria-label=
|
|
456
|
+
aria-label={label ? `${label}, ${text.open}` : text.open}
|
|
457
|
+
bind:this={swatchButton}
|
|
458
|
+
onkeydown={handleEscape}
|
|
289
459
|
aria-expanded={isOpen}
|
|
460
|
+
data-color-picker-open
|
|
290
461
|
></button>
|
|
291
462
|
|
|
292
463
|
{#if isOpen}
|
|
293
464
|
<div
|
|
294
465
|
use:setPickerContainer
|
|
295
|
-
|
|
466
|
+
bind:this={popoverElement}
|
|
467
|
+
class="absolute top-12 right-0 z-popover border border-border-overlay bg-surface-overlay rounded-overlay shadow-lg p-4 w-80"
|
|
468
|
+
style:position={placed?.fixed ? "fixed" : undefined}
|
|
469
|
+
style:top={placed?.fixed ? `${placed.fixed.top}px` : undefined}
|
|
470
|
+
style:left={placed?.fixed ? `${placed.fixed.left}px` : undefined}
|
|
471
|
+
style:right={placed?.fixed
|
|
472
|
+
? "auto"
|
|
473
|
+
: placed && placed.inlineOffset !== 0
|
|
474
|
+
? `${placed.inlineOffset}px`
|
|
475
|
+
: undefined}
|
|
476
|
+
style:width={placed?.fixed ? `${placed.fixed.width}px` : undefined}
|
|
477
|
+
style:max-width={placed && placed.maxWidth !== null ? `${placed.maxWidth}px` : undefined}
|
|
296
478
|
role="dialog"
|
|
297
|
-
aria-label=
|
|
479
|
+
aria-label={text.picker}
|
|
480
|
+
tabindex="-1"
|
|
481
|
+
onkeydown={handleEscape}
|
|
298
482
|
>
|
|
299
483
|
<div class="space-y-4">
|
|
484
|
+
<!-- The sliders inside are the controls; the pointer
|
|
485
|
+
handlers are on the surface they share. -->
|
|
486
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
300
487
|
<div
|
|
301
488
|
use:setColorMapContainer
|
|
302
|
-
class="relative w-full h-48 rounded-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
|
|
489
|
+
class="relative w-full h-48 rounded-container cursor-crosshair touch-none select-none {RING_WITHIN}"
|
|
490
|
+
role="group"
|
|
491
|
+
aria-label={text.area}
|
|
492
|
+
onpointerdown={handleMapPointerDown}
|
|
493
|
+
onpointermove={handleMapPointerMove}
|
|
494
|
+
onpointerup={handleMapPointerUp}
|
|
495
|
+
onpointercancel={handleMapPointerUp}
|
|
309
496
|
>
|
|
310
497
|
<canvas
|
|
311
498
|
use:setColorMap
|
|
312
499
|
width={256}
|
|
313
500
|
height={192}
|
|
314
|
-
class="w-full h-full"
|
|
501
|
+
class="w-full h-full rounded-container"
|
|
315
502
|
></canvas>
|
|
503
|
+
<input
|
|
504
|
+
bind:this={saturationInput}
|
|
505
|
+
type="range"
|
|
506
|
+
min="0"
|
|
507
|
+
max="100"
|
|
508
|
+
step="1"
|
|
509
|
+
value={saturation}
|
|
510
|
+
class="sr-only"
|
|
511
|
+
aria-label={text.saturation}
|
|
512
|
+
aria-valuetext={mapValueText(saturation)}
|
|
513
|
+
oninput={(event) => handleMapInput("saturation", event)}
|
|
514
|
+
onkeydown={handleMapKeydown}
|
|
515
|
+
/>
|
|
516
|
+
<input
|
|
517
|
+
bind:this={lightnessInput}
|
|
518
|
+
type="range"
|
|
519
|
+
min="0"
|
|
520
|
+
max="100"
|
|
521
|
+
step="1"
|
|
522
|
+
value={lightness}
|
|
523
|
+
tabindex="-1"
|
|
524
|
+
class="sr-only"
|
|
525
|
+
aria-label={text.lightness}
|
|
526
|
+
aria-orientation="vertical"
|
|
527
|
+
aria-valuetext={mapValueText(lightness)}
|
|
528
|
+
oninput={(event) => handleMapInput("lightness", event)}
|
|
529
|
+
onkeydown={handleMapKeydown}
|
|
530
|
+
/>
|
|
531
|
+
<!-- White with a dark edge: seen on the white corner of the map as on the black. -->
|
|
316
532
|
<div
|
|
317
|
-
class="absolute w-4 h-4 border-2 border-white rounded-full shadow-
|
|
533
|
+
class="absolute w-4 h-4 border-2 border-white rounded-full shadow-[0_0_0_1px_rgba(0,0,0,0.6)] pointer-events-none transform -translate-x-1/2 -translate-y-1/2"
|
|
318
534
|
style="left: {pickerIndicatorX}; top: {pickerIndicatorY};"
|
|
319
535
|
></div>
|
|
320
536
|
</div>
|
|
321
537
|
|
|
322
538
|
<div class="space-y-2">
|
|
539
|
+
<!-- A real slider, drawn by the two layers around
|
|
540
|
+
it. It is transparent, so the ring for keyboard
|
|
541
|
+
focus is on this box; and the box is a finger tall
|
|
542
|
+
on a touch screen, where 24px was not. -->
|
|
323
543
|
<div
|
|
324
|
-
class="relative h-6 rounded-
|
|
544
|
+
class="relative h-6 pointer-coarse:h-11 rounded-control {RING_WITHIN}"
|
|
325
545
|
>
|
|
326
546
|
<div
|
|
327
|
-
class="absolute inset-0"
|
|
547
|
+
class="absolute inset-0 rounded-control"
|
|
328
548
|
style="background: linear-gradient(to right, hsl(0,100%,50%), hsl(60,100%,50%), hsl(120,100%,50%), hsl(180,100%,50%), hsl(240,100%,50%), hsl(300,100%,50%), hsl(360,100%,50%));"
|
|
329
549
|
></div>
|
|
330
550
|
<input
|
|
@@ -334,10 +554,10 @@
|
|
|
334
554
|
value={hue}
|
|
335
555
|
oninput={handleHueChange}
|
|
336
556
|
class="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
|
|
337
|
-
aria-label=
|
|
557
|
+
aria-label={text.hue}
|
|
338
558
|
/>
|
|
339
559
|
<div
|
|
340
|
-
class="absolute top-0 bottom-0 w-3 bg-card shadow-
|
|
560
|
+
class="absolute top-0 bottom-0 w-3 bg-card shadow-sm pointer-events-none my-px rounded-full border border-base-950"
|
|
341
561
|
style="left: {(hue / 360) * 100}%;"
|
|
342
562
|
></div>
|
|
343
563
|
</div>
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { type ColorPickerStrings } from "../util/ready-made-strings.js";
|
|
1
2
|
interface Props {
|
|
3
|
+
/** Extra classes for the host element. */
|
|
4
|
+
class?: string;
|
|
2
5
|
value?: string;
|
|
3
6
|
label?: string;
|
|
4
7
|
disabled?: boolean;
|
|
5
8
|
placeholder?: string;
|
|
9
|
+
/** The accessible names of its parts, for another language. */
|
|
10
|
+
strings?: Partial<ColorPickerStrings>;
|
|
6
11
|
onchange?: (event: Event) => void;
|
|
7
12
|
}
|
|
8
|
-
declare const ColorPicker: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
declare const ColorPicker: import("svelte").Component<Props, {}, "value">;
|
|
9
14
|
type ColorPicker = ReturnType<typeof ColorPicker>;
|
|
10
15
|
export default ColorPicker;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
|
|
4
|
+
import { cn } from "../util/cn.js";
|
|
4
5
|
type MaxWidth = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
@@ -27,15 +28,21 @@
|
|
|
27
28
|
'2xl': 'max-w-screen-2xl',
|
|
28
29
|
full: 'max-w-full',
|
|
29
30
|
};
|
|
31
|
+
|
|
32
|
+
const classes = $derived(
|
|
33
|
+
cn('mx-auto w-full', maxClass[maxWidth], padded ? 'px-4 sm:px-6' : '', className),
|
|
34
|
+
);
|
|
30
35
|
</script>
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
|
|
37
|
+
<!-- One branch per tag, not `<svelte:element>`: hydration takes a dynamic
|
|
38
|
+
element out and puts it back, which blurs a control inside it that the user
|
|
39
|
+
had already tabbed to. -->
|
|
40
|
+
{#if Tag === 'section'}
|
|
41
|
+
<section class={classes}>{@render children?.()}</section>
|
|
42
|
+
{:else if Tag === 'main'}
|
|
43
|
+
<main class={classes}>{@render children?.()}</main>
|
|
44
|
+
{:else if Tag === 'article'}
|
|
45
|
+
<article class={classes}>{@render children?.()}</article>
|
|
46
|
+
{:else}
|
|
47
|
+
<div class={classes}>{@render children?.()}</div>
|
|
48
|
+
{/if}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLInputAttributes } from "svelte/elements";
|
|
3
|
+
import type { SizeVariant } from "../types/variants.js";
|
|
4
|
+
import TemporalField from "./TemporalField.svelte";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A date, picked with the device's own date picker and styled like Input.
|
|
8
|
+
*
|
|
9
|
+
* It is a native `<input type="date">`: an iPhone shows its wheels or
|
|
10
|
+
* calendar, Android its calendar, a desktop browser its own. `value` is
|
|
11
|
+
* always `YYYY-MM-DD`, or `""` while empty, whatever the field shows.
|
|
12
|
+
*
|
|
13
|
+
* What the field shows is the browser's decision: the date in the format
|
|
14
|
+
* of the browser or device, not of the page, and no attribute changes
|
|
15
|
+
* that. To show a date as text in the page's language, use `formatDate`:
|
|
16
|
+
*
|
|
17
|
+
* ```svelte
|
|
18
|
+
* <DateField label="Date" bind:value={date} min="2026-01-01" />
|
|
19
|
+
* <p>{formatDate(date, "sv")}</p> <!-- 6 okt. 2026 -->
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Other attributes (`autocomplete`, `data-*`, `onchange`, ...) land on the
|
|
23
|
+
* `<input>`.
|
|
24
|
+
*/
|
|
25
|
+
type Props = Omit<
|
|
26
|
+
HTMLInputAttributes,
|
|
27
|
+
"class" | "type" | "value" | "size" | "min" | "max" | "step" | "required" | "disabled" | "readonly" | "id" | "name"
|
|
28
|
+
> & {
|
|
29
|
+
/** Omit to auto-generate; pair with FormField's `id` when used inside FormField. */
|
|
30
|
+
id?: string;
|
|
31
|
+
/** The date as `YYYY-MM-DD`, or `""` while empty. Supports `bind:value`. */
|
|
32
|
+
value?: string;
|
|
33
|
+
/** Name the value is submitted under in a form. */
|
|
34
|
+
name?: string;
|
|
35
|
+
label?: string;
|
|
36
|
+
/** True when FormField supplies the visible `<label>`. */
|
|
37
|
+
hideLabel?: boolean;
|
|
38
|
+
/** Help text under the field, read out with it. */
|
|
39
|
+
hint?: string;
|
|
40
|
+
/** An error under the field. It marks the field invalid and is announced. */
|
|
41
|
+
error?: string;
|
|
42
|
+
/** Earliest date that can be picked, as `YYYY-MM-DD`. */
|
|
43
|
+
min?: string;
|
|
44
|
+
/** Latest date that can be picked, as `YYYY-MM-DD`. */
|
|
45
|
+
max?: string;
|
|
46
|
+
/** Steps between dates that can be picked, in days. */
|
|
47
|
+
step?: number | "any";
|
|
48
|
+
required?: boolean;
|
|
49
|
+
disabled?: boolean;
|
|
50
|
+
/** Shows the value without letting it be changed; it is still submitted. */
|
|
51
|
+
readonly?: boolean;
|
|
52
|
+
/** Height, on the scale Input and Button use. At least 44px on a touch screen. */
|
|
53
|
+
size?: SizeVariant;
|
|
54
|
+
/** Extra classes for the `<input>`. */
|
|
55
|
+
class?: string;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
let {
|
|
59
|
+
id,
|
|
60
|
+
value = $bindable<Exclude<Props["value"], undefined>>(),
|
|
61
|
+
name = "",
|
|
62
|
+
label = "",
|
|
63
|
+
hideLabel = false,
|
|
64
|
+
hint = "",
|
|
65
|
+
error = "",
|
|
66
|
+
min,
|
|
67
|
+
max,
|
|
68
|
+
step,
|
|
69
|
+
required = false,
|
|
70
|
+
disabled = false,
|
|
71
|
+
readonly = false,
|
|
72
|
+
size = "md",
|
|
73
|
+
class: className = "",
|
|
74
|
+
...restProps
|
|
75
|
+
}: Props = $props();
|
|
76
|
+
|
|
77
|
+
// No fallback on a bindable prop: Svelte refuses `bind:…={undefined}` on
|
|
78
|
+
// one that has a fallback (`props_invalid_value`), and a page that throws
|
|
79
|
+
// while it hydrates never becomes interactive. The default is applied
|
|
80
|
+
// here instead: at once, for the server and the first render, and again
|
|
81
|
+
// whenever a parent hands back `undefined`.
|
|
82
|
+
const applyDefaults = () => {
|
|
83
|
+
if (value === undefined) value = "";
|
|
84
|
+
};
|
|
85
|
+
applyDefaults();
|
|
86
|
+
$effect.pre(applyDefaults);
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<TemporalField
|
|
90
|
+
kind="date"
|
|
91
|
+
{id}
|
|
92
|
+
bind:value
|
|
93
|
+
{name}
|
|
94
|
+
{label}
|
|
95
|
+
{hideLabel}
|
|
96
|
+
{hint}
|
|
97
|
+
{error}
|
|
98
|
+
{min}
|
|
99
|
+
{max}
|
|
100
|
+
{step}
|
|
101
|
+
{required}
|
|
102
|
+
{disabled}
|
|
103
|
+
{readonly}
|
|
104
|
+
{size}
|
|
105
|
+
class={className}
|
|
106
|
+
{...restProps}
|
|
107
|
+
/>
|