@sveltier/ui 0.0.0-stage → 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +82 -2
- package/dist/components/Accordion/Accordion.svelte +74 -0
- package/dist/components/Accordion/Accordion.svelte.d.ts +25 -0
- package/dist/components/Accordion/accordion.css +88 -0
- package/dist/components/Accordion/index.d.ts +2 -0
- package/dist/components/Accordion/index.js +1 -0
- package/dist/components/Accordion/types.d.ts +64 -0
- package/dist/components/Accordion/types.js +1 -0
- package/dist/components/Alert/Alert.svelte +88 -0
- package/dist/components/Alert/Alert.svelte.d.ts +4 -0
- package/dist/components/Alert/alert.css +78 -0
- package/dist/components/Alert/index.d.ts +2 -0
- package/dist/components/Alert/index.js +1 -0
- package/dist/components/Alert/types.d.ts +67 -0
- package/dist/components/Alert/types.js +1 -0
- package/dist/components/Avatar/Avatar.svelte +47 -0
- package/dist/components/Avatar/Avatar.svelte.d.ts +4 -0
- package/dist/components/Avatar/avatar.css +34 -0
- package/dist/components/Avatar/index.d.ts +2 -0
- package/dist/components/Avatar/index.js +1 -0
- package/dist/components/Avatar/types.d.ts +47 -0
- package/dist/components/Avatar/types.js +1 -0
- package/dist/components/Badge/Badge.svelte +53 -0
- package/dist/components/Badge/Badge.svelte.d.ts +4 -0
- package/dist/components/Badge/badge.css +57 -0
- package/dist/components/Badge/index.d.ts +2 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Badge/types.d.ts +43 -0
- package/dist/components/Badge/types.js +1 -0
- package/dist/components/Button/Button.svelte +85 -0
- package/dist/components/Button/Button.svelte.d.ts +4 -0
- package/dist/components/Button/button.css +132 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Button/types.d.ts +76 -0
- package/dist/components/Button/types.js +1 -0
- package/dist/components/ButtonGroup/ButtonGroup.svelte +61 -0
- package/dist/components/ButtonGroup/ButtonGroup.svelte.d.ts +4 -0
- package/dist/components/ButtonGroup/button-group.css +39 -0
- package/dist/components/ButtonGroup/index.d.ts +2 -0
- package/dist/components/ButtonGroup/index.js +1 -0
- package/dist/components/ButtonGroup/types.d.ts +48 -0
- package/dist/components/ButtonGroup/types.js +1 -0
- package/dist/components/Card/Card.svelte +53 -0
- package/dist/components/Card/Card.svelte.d.ts +4 -0
- package/dist/components/Card/card.css +62 -0
- package/dist/components/Card/index.d.ts +2 -0
- package/dist/components/Card/index.js +1 -0
- package/dist/components/Card/types.d.ts +56 -0
- package/dist/components/Card/types.js +1 -0
- package/dist/components/Checkbox/Checkbox.svelte +105 -0
- package/dist/components/Checkbox/Checkbox.svelte.d.ts +4 -0
- package/dist/components/Checkbox/checkbox.css +138 -0
- package/dist/components/Checkbox/index.d.ts +2 -0
- package/dist/components/Checkbox/index.js +1 -0
- package/dist/components/Checkbox/types.d.ts +76 -0
- package/dist/components/Checkbox/types.js +1 -0
- package/dist/components/Chip/Chip.svelte +109 -0
- package/dist/components/Chip/Chip.svelte.d.ts +4 -0
- package/dist/components/Chip/chip.css +101 -0
- package/dist/components/Chip/index.d.ts +2 -0
- package/dist/components/Chip/index.js +1 -0
- package/dist/components/Chip/types.d.ts +69 -0
- package/dist/components/Chip/types.js +1 -0
- package/dist/components/Choice/Choice.svelte +60 -0
- package/dist/components/Choice/Choice.svelte.d.ts +4 -0
- package/dist/components/Choice/choice.css +75 -0
- package/dist/components/Choice/types.d.ts +43 -0
- package/dist/components/Choice/types.js +1 -0
- package/dist/components/Dialog/Dialog.svelte +36 -0
- package/dist/components/Dialog/Dialog.svelte.d.ts +4 -0
- package/dist/components/Dialog/index.d.ts +2 -0
- package/dist/components/Dialog/index.js +1 -0
- package/dist/components/Dialog/types.d.ts +50 -0
- package/dist/components/Dialog/types.js +1 -0
- package/dist/components/Divider/Divider.svelte +19 -0
- package/dist/components/Divider/Divider.svelte.d.ts +4 -0
- package/dist/components/Divider/divider.css +23 -0
- package/dist/components/Divider/index.d.ts +2 -0
- package/dist/components/Divider/index.js +1 -0
- package/dist/components/Divider/types.d.ts +10 -0
- package/dist/components/Divider/types.js +1 -0
- package/dist/components/Field/Field.svelte +95 -0
- package/dist/components/Field/Field.svelte.d.ts +4 -0
- package/dist/components/Field/field.css +210 -0
- package/dist/components/Field/index.d.ts +3 -0
- package/dist/components/Field/index.js +2 -0
- package/dist/components/Field/types.d.ts +109 -0
- package/dist/components/Field/types.js +2 -0
- package/dist/components/Form/Form.svelte +93 -0
- package/dist/components/Form/Form.svelte.d.ts +8 -0
- package/dist/components/Form/form.css +16 -0
- package/dist/components/Form/index.d.ts +2 -0
- package/dist/components/Form/index.js +1 -0
- package/dist/components/Form/types.d.ts +38 -0
- package/dist/components/Form/types.js +1 -0
- package/dist/components/Icon/Icon.svelte +38 -0
- package/dist/components/Icon/Icon.svelte.d.ts +4 -0
- package/dist/components/Icon/icon.css +33 -0
- package/dist/components/Icon/index.d.ts +2 -0
- package/dist/components/Icon/index.js +1 -0
- package/dist/components/Icon/types.d.ts +34 -0
- package/dist/components/Icon/types.js +1 -0
- package/dist/components/List/List.svelte +39 -0
- package/dist/components/List/List.svelte.d.ts +4 -0
- package/dist/components/List/ListItem.svelte +57 -0
- package/dist/components/List/ListItem.svelte.d.ts +4 -0
- package/dist/components/List/index.d.ts +3 -0
- package/dist/components/List/index.js +2 -0
- package/dist/components/List/list.css +127 -0
- package/dist/components/List/types.d.ts +67 -0
- package/dist/components/List/types.js +1 -0
- package/dist/components/Menu/Menu.svelte +195 -0
- package/dist/components/Menu/Menu.svelte.d.ts +4 -0
- package/dist/components/Menu/index.d.ts +2 -0
- package/dist/components/Menu/index.js +1 -0
- package/dist/components/Menu/menu.css +103 -0
- package/dist/components/Menu/types.d.ts +90 -0
- package/dist/components/Menu/types.js +1 -0
- package/dist/components/Modal/Modal.svelte +146 -0
- package/dist/components/Modal/Modal.svelte.d.ts +4 -0
- package/dist/components/Modal/modal.css +150 -0
- package/dist/components/Modal/types.d.ts +54 -0
- package/dist/components/Modal/types.js +1 -0
- package/dist/components/NativeSelect/NativeSelect.svelte +110 -0
- package/dist/components/NativeSelect/NativeSelect.svelte.d.ts +25 -0
- package/dist/components/NativeSelect/index.d.ts +2 -0
- package/dist/components/NativeSelect/index.js +1 -0
- package/dist/components/NativeSelect/native-select.css +45 -0
- package/dist/components/NativeSelect/types.d.ts +58 -0
- package/dist/components/NativeSelect/types.js +1 -0
- package/dist/components/NumberField/NumberField.svelte +246 -0
- package/dist/components/NumberField/NumberField.svelte.d.ts +4 -0
- package/dist/components/NumberField/index.d.ts +2 -0
- package/dist/components/NumberField/index.js +1 -0
- package/dist/components/NumberField/number-field.css +74 -0
- package/dist/components/NumberField/types.d.ts +73 -0
- package/dist/components/NumberField/types.js +1 -0
- package/dist/components/Popover/Popover.svelte +115 -0
- package/dist/components/Popover/Popover.svelte.d.ts +4 -0
- package/dist/components/Popover/index.d.ts +2 -0
- package/dist/components/Popover/index.js +1 -0
- package/dist/components/Popover/popover.css +67 -0
- package/dist/components/Popover/types.d.ts +83 -0
- package/dist/components/Popover/types.js +1 -0
- package/dist/components/Progress/ProgressCircular.svelte +61 -0
- package/dist/components/Progress/ProgressCircular.svelte.d.ts +4 -0
- package/dist/components/Progress/ProgressLinear.svelte +44 -0
- package/dist/components/Progress/ProgressLinear.svelte.d.ts +4 -0
- package/dist/components/Progress/index.d.ts +3 -0
- package/dist/components/Progress/index.js +2 -0
- package/dist/components/Progress/progress-circular.css +61 -0
- package/dist/components/Progress/progress-linear.css +67 -0
- package/dist/components/Progress/types.d.ts +53 -0
- package/dist/components/Progress/types.js +1 -0
- package/dist/components/RadioGroup/RadioGroup.svelte +149 -0
- package/dist/components/RadioGroup/RadioGroup.svelte.d.ts +25 -0
- package/dist/components/RadioGroup/index.d.ts +2 -0
- package/dist/components/RadioGroup/index.js +1 -0
- package/dist/components/RadioGroup/radio-group.css +139 -0
- package/dist/components/RadioGroup/types.d.ts +93 -0
- package/dist/components/RadioGroup/types.js +1 -0
- package/dist/components/SegmentedControl/SegmentedControl.svelte +70 -0
- package/dist/components/SegmentedControl/SegmentedControl.svelte.d.ts +25 -0
- package/dist/components/SegmentedControl/index.d.ts +2 -0
- package/dist/components/SegmentedControl/index.js +1 -0
- package/dist/components/SegmentedControl/segmented-control.css +68 -0
- package/dist/components/SegmentedControl/types.d.ts +60 -0
- package/dist/components/SegmentedControl/types.js +1 -0
- package/dist/components/Sheet/Sheet.svelte +56 -0
- package/dist/components/Sheet/Sheet.svelte.d.ts +4 -0
- package/dist/components/Sheet/index.d.ts +2 -0
- package/dist/components/Sheet/index.js +2 -0
- package/dist/components/Sheet/sheet.css +61 -0
- package/dist/components/Sheet/types.d.ts +51 -0
- package/dist/components/Sheet/types.js +1 -0
- package/dist/components/Skeleton/Skeleton.svelte +33 -0
- package/dist/components/Skeleton/Skeleton.svelte.d.ts +4 -0
- package/dist/components/Skeleton/index.d.ts +2 -0
- package/dist/components/Skeleton/index.js +1 -0
- package/dist/components/Skeleton/skeleton.css +70 -0
- package/dist/components/Skeleton/types.d.ts +25 -0
- package/dist/components/Skeleton/types.js +1 -0
- package/dist/components/Slider/Slider.svelte +153 -0
- package/dist/components/Slider/Slider.svelte.d.ts +4 -0
- package/dist/components/Slider/index.d.ts +2 -0
- package/dist/components/Slider/index.js +1 -0
- package/dist/components/Slider/slider.css +206 -0
- package/dist/components/Slider/types.d.ts +102 -0
- package/dist/components/Slider/types.js +1 -0
- package/dist/components/Switch/Switch.svelte +94 -0
- package/dist/components/Switch/Switch.svelte.d.ts +4 -0
- package/dist/components/Switch/index.d.ts +2 -0
- package/dist/components/Switch/index.js +1 -0
- package/dist/components/Switch/switch.css +118 -0
- package/dist/components/Switch/types.d.ts +67 -0
- package/dist/components/Switch/types.js +1 -0
- package/dist/components/Tabs/Tabs.svelte +93 -0
- package/dist/components/Tabs/Tabs.svelte.d.ts +25 -0
- package/dist/components/Tabs/index.d.ts +2 -0
- package/dist/components/Tabs/index.js +1 -0
- package/dist/components/Tabs/tabs.css +73 -0
- package/dist/components/Tabs/types.d.ts +59 -0
- package/dist/components/Tabs/types.js +1 -0
- package/dist/components/TextField/TextField.svelte +115 -0
- package/dist/components/TextField/TextField.svelte.d.ts +4 -0
- package/dist/components/TextField/index.d.ts +2 -0
- package/dist/components/TextField/index.js +1 -0
- package/dist/components/TextField/types.d.ts +57 -0
- package/dist/components/TextField/types.js +1 -0
- package/dist/components/Textarea/Textarea.svelte +116 -0
- package/dist/components/Textarea/Textarea.svelte.d.ts +4 -0
- package/dist/components/Textarea/index.d.ts +2 -0
- package/dist/components/Textarea/index.js +1 -0
- package/dist/components/Textarea/textarea.css +35 -0
- package/dist/components/Textarea/types.d.ts +60 -0
- package/dist/components/Textarea/types.js +1 -0
- package/dist/components/Tooltip/Tooltip.svelte +161 -0
- package/dist/components/Tooltip/Tooltip.svelte.d.ts +4 -0
- package/dist/components/Tooltip/index.d.ts +2 -0
- package/dist/components/Tooltip/index.js +1 -0
- package/dist/components/Tooltip/tooltip.css +44 -0
- package/dist/components/Tooltip/types.d.ts +55 -0
- package/dist/components/Tooltip/types.js +1 -0
- package/dist/core/defaults/DefaultsProvider.svelte +30 -0
- package/dist/core/defaults/DefaultsProvider.svelte.d.ts +13 -0
- package/dist/core/defaults/context.d.ts +45 -0
- package/dist/core/defaults/context.js +38 -0
- package/dist/core/display/display.d.ts +39 -0
- package/dist/core/display/display.js +53 -0
- package/dist/core/errors/codes.d.ts +124 -0
- package/dist/core/errors/codes.js +108 -0
- package/dist/core/errors/errors.d.ts +8 -0
- package/dist/core/errors/errors.js +7 -0
- package/dist/core/form/constraints.d.ts +15 -0
- package/dist/core/form/constraints.js +42 -0
- package/dist/core/form/context.d.ts +19 -0
- package/dist/core/form/context.js +4 -0
- package/dist/core/form/field.svelte.d.ts +34 -0
- package/dist/core/form/field.svelte.js +66 -0
- package/dist/core/form/number.d.ts +24 -0
- package/dist/core/form/number.js +71 -0
- package/dist/core/form/types.d.ts +22 -0
- package/dist/core/form/types.js +1 -0
- package/dist/core/locale/locale.d.ts +56 -0
- package/dist/core/locale/locale.js +82 -0
- package/dist/core/overlay/types.d.ts +33 -0
- package/dist/core/overlay/types.js +1 -0
- package/dist/core/props/classes.d.ts +21 -0
- package/dist/core/props/classes.js +44 -0
- package/dist/core/props/element.d.ts +18 -0
- package/dist/core/props/element.js +1 -0
- package/dist/core/props/types.d.ts +47 -0
- package/dist/core/props/types.js +16 -0
- package/dist/core/provider/UIProvider.svelte +63 -0
- package/dist/core/provider/UIProvider.svelte.d.ts +29 -0
- package/dist/core/theme/ThemeProvider.svelte +178 -0
- package/dist/core/theme/ThemeProvider.svelte.d.ts +25 -0
- package/dist/core/theme/color.d.ts +23 -0
- package/dist/core/theme/color.js +54 -0
- package/dist/core/theme/context.d.ts +25 -0
- package/dist/core/theme/context.js +14 -0
- package/dist/core/theme/css.d.ts +25 -0
- package/dist/core/theme/css.js +73 -0
- package/dist/core/theme/define.d.ts +11 -0
- package/dist/core/theme/define.js +21 -0
- package/dist/core/theme/resolve.d.ts +6 -0
- package/dist/core/theme/resolve.js +18 -0
- package/dist/core/theme/theme-provider.css +13 -0
- package/dist/core/theme/types.d.ts +35 -0
- package/dist/core/theme/types.js +61 -0
- package/dist/core/toast/ToastOutlet.svelte +192 -0
- package/dist/core/toast/ToastOutlet.svelte.d.ts +11 -0
- package/dist/core/toast/ToastProvider.svelte +39 -0
- package/dist/core/toast/ToastProvider.svelte.d.ts +19 -0
- package/dist/core/toast/toast.css +134 -0
- package/dist/core/toast/toast.svelte.d.ts +117 -0
- package/dist/core/toast/toast.svelte.js +133 -0
- package/dist/dev/off.d.ts +5 -0
- package/dist/dev/off.js +4 -0
- package/dist/dev/on.d.ts +20 -0
- package/dist/dev/on.js +49 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +83 -0
- package/dist/primitives/anchored/anchored.d.ts +39 -0
- package/dist/primitives/anchored/anchored.js +104 -0
- package/dist/primitives/anchored/fallback.d.ts +31 -0
- package/dist/primitives/anchored/fallback.js +73 -0
- package/dist/primitives/focus/focus-trap.d.ts +25 -0
- package/dist/primitives/focus/focus-trap.js +86 -0
- package/dist/primitives/focus/roving-focus.d.ts +22 -0
- package/dist/primitives/focus/roving-focus.js +86 -0
- package/dist/primitives/focus/tabbable.d.ts +9 -0
- package/dist/primitives/focus/tabbable.js +75 -0
- package/dist/primitives/inert/inert-others.d.ts +12 -0
- package/dist/primitives/inert/inert-others.js +44 -0
- package/dist/primitives/keyboard/keymap.d.ts +17 -0
- package/dist/primitives/keyboard/keymap.js +39 -0
- package/dist/primitives/keyboard/typeahead.d.ts +18 -0
- package/dist/primitives/keyboard/typeahead.js +50 -0
- package/dist/primitives/layer/dismissable.d.ts +32 -0
- package/dist/primitives/layer/dismissable.js +91 -0
- package/dist/primitives/motion/easing.d.ts +9 -0
- package/dist/primitives/motion/easing.js +46 -0
- package/dist/primitives/motion/motion.d.ts +59 -0
- package/dist/primitives/motion/motion.js +80 -0
- package/dist/primitives/portal/Portal.svelte +37 -0
- package/dist/primitives/portal/Portal.svelte.d.ts +9 -0
- package/dist/primitives/portal/PortalContent.svelte +15 -0
- package/dist/primitives/portal/PortalContent.svelte.d.ts +9 -0
- package/dist/primitives/portal/portal.css +8 -0
- package/dist/primitives/scroll-lock/scroll-lock.d.ts +10 -0
- package/dist/primitives/scroll-lock/scroll-lock.js +33 -0
- package/dist/primitives/virtual/virtual-list.svelte.d.ts +65 -0
- package/dist/primitives/virtual/virtual-list.svelte.js +291 -0
- package/dist/styles/base.css +44 -0
- package/dist/styles/props.css +140 -0
- package/dist/styles/tokens.css +84 -0
- package/dist/styles/visually-hidden.css +16 -0
- package/dist/themes/aurora.d.ts +13 -0
- package/dist/themes/aurora.js +103 -0
- package/dist/themes/heritage.d.ts +13 -0
- package/dist/themes/heritage.js +102 -0
- package/dist/themes/maison.d.ts +13 -0
- package/dist/themes/maison.js +99 -0
- package/dist/themes/milano.d.ts +13 -0
- package/dist/themes/milano.js +101 -0
- package/dist/themes/monolith.d.ts +13 -0
- package/dist/themes/monolith.js +101 -0
- package/package.json +87 -5
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// A number picked along a track, with its label, its value and validation. See SliderProps.
|
|
3
|
+
import { untrack } from 'svelte';
|
|
4
|
+
import { DEV, warnUnnamed } from '#dev';
|
|
5
|
+
import { useDefaults } from '../../core/defaults/context.js';
|
|
6
|
+
import { createField } from '../../core/form/field.svelte.js';
|
|
7
|
+
import { useLocale } from '../../core/locale/locale.js';
|
|
8
|
+
import { sharedClasses } from '../../core/props/classes.js';
|
|
9
|
+
import './slider.css';
|
|
10
|
+
import type { SliderDefaults, SliderProps } from './types.js';
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
color,
|
|
14
|
+
size,
|
|
15
|
+
density,
|
|
16
|
+
disabled,
|
|
17
|
+
value = $bindable(),
|
|
18
|
+
min = 0,
|
|
19
|
+
max = 100,
|
|
20
|
+
step = 1,
|
|
21
|
+
ticks,
|
|
22
|
+
format,
|
|
23
|
+
label,
|
|
24
|
+
hint,
|
|
25
|
+
error,
|
|
26
|
+
rules,
|
|
27
|
+
validateOn,
|
|
28
|
+
id: idProp,
|
|
29
|
+
'aria-describedby': describedBy,
|
|
30
|
+
class: className,
|
|
31
|
+
style,
|
|
32
|
+
ref = $bindable(null),
|
|
33
|
+
...rest
|
|
34
|
+
}: SliderProps = $props();
|
|
35
|
+
|
|
36
|
+
const uid = $props.id();
|
|
37
|
+
const id = $derived(idProp ?? uid);
|
|
38
|
+
const resolve = useDefaults<SliderDefaults>('Slider', {
|
|
39
|
+
color: 'primary',
|
|
40
|
+
size: 'md',
|
|
41
|
+
density: 'default',
|
|
42
|
+
disabled: false
|
|
43
|
+
});
|
|
44
|
+
const p = $derived(resolve({ color, size, density, disabled }));
|
|
45
|
+
const locale = useLocale();
|
|
46
|
+
|
|
47
|
+
const current = $derived(value ?? min);
|
|
48
|
+
// A form reset goes back to the value the slider started at.
|
|
49
|
+
const initial = untrack(() => value ?? min);
|
|
50
|
+
// Where a value sits along the track, from 0 to 1.
|
|
51
|
+
const along = (at: number) =>
|
|
52
|
+
max > min ? Math.min(1, Math.max(0, (at - min) / (max - min))) : 0;
|
|
53
|
+
|
|
54
|
+
// Steps in decimals add up with float errors (0.1 + 0.2), so tick values are rounded to the
|
|
55
|
+
// decimals of min and step, the same values the input stops at.
|
|
56
|
+
const decimals = (at: number) => `${at}`.split('.')[1]?.length ?? 0;
|
|
57
|
+
const marks = $derived.by((): Array<{ value: number; label?: string }> => {
|
|
58
|
+
if (!ticks) return [];
|
|
59
|
+
if (ticks !== true) {
|
|
60
|
+
return ticks.map((tick) => (typeof tick === 'number' ? { value: tick } : tick));
|
|
61
|
+
}
|
|
62
|
+
if (!(step > 0) || max <= min) return [];
|
|
63
|
+
const places = Math.max(decimals(min), decimals(step));
|
|
64
|
+
const count = Math.floor((max - min) / step + 1e-9);
|
|
65
|
+
return Array.from({ length: count + 1 }, (_, index) => ({
|
|
66
|
+
value: Number((min + index * step).toFixed(places))
|
|
67
|
+
}));
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const tickLabel = $derived(marks.find((mark) => mark.value === current && mark.label)?.label);
|
|
71
|
+
const text = $derived(format?.(current) ?? tickLabel ?? locale.formatNumber(current));
|
|
72
|
+
|
|
73
|
+
const field = createField<number>({
|
|
74
|
+
value: () => current,
|
|
75
|
+
// A range always holds a value; the browser keeps it between min and max, on a step.
|
|
76
|
+
empty: () => false,
|
|
77
|
+
check: () => undefined,
|
|
78
|
+
rules: () => rules,
|
|
79
|
+
error: () => error,
|
|
80
|
+
validateOn: () => validateOn,
|
|
81
|
+
control: () => ref
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const message = $derived(typeof field.error === 'string' ? field.error : undefined);
|
|
85
|
+
|
|
86
|
+
if (DEV) $effect(() => warnUnnamed('Slider', ref));
|
|
87
|
+
|
|
88
|
+
// Letting go of the thumb, or a key step, finishes an edit, so it also counts as leaving.
|
|
89
|
+
function committed() {
|
|
90
|
+
field.changed();
|
|
91
|
+
field.left();
|
|
92
|
+
}
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<div
|
|
96
|
+
class={[
|
|
97
|
+
'sv-slider',
|
|
98
|
+
sharedClasses(p, 'Slider'),
|
|
99
|
+
field.error !== false && 'sv-slider--invalid',
|
|
100
|
+
p.disabled && 'sv-slider--disabled',
|
|
101
|
+
className
|
|
102
|
+
]}
|
|
103
|
+
{style}
|
|
104
|
+
style:--sv-slider-fraction={along(current)}
|
|
105
|
+
oninput={field.changed}
|
|
106
|
+
onchange={committed}
|
|
107
|
+
>
|
|
108
|
+
{#if label}
|
|
109
|
+
<div class="sv-slider__header">
|
|
110
|
+
<label class="sv-slider__label" for={id}>{label}</label>
|
|
111
|
+
<!-- Shown for sight; screen readers hear the slider's own value. -->
|
|
112
|
+
<span class="sv-slider__value" aria-hidden="true">{text}</span>
|
|
113
|
+
</div>
|
|
114
|
+
{/if}
|
|
115
|
+
<input
|
|
116
|
+
bind:this={ref}
|
|
117
|
+
defaultValue={initial}
|
|
118
|
+
{...rest}
|
|
119
|
+
{id}
|
|
120
|
+
type="range"
|
|
121
|
+
class="sv-slider__input"
|
|
122
|
+
{min}
|
|
123
|
+
{max}
|
|
124
|
+
{step}
|
|
125
|
+
disabled={p.disabled}
|
|
126
|
+
aria-describedby={[describedBy, message ? `${id}-error` : hint ? `${id}-hint` : undefined]
|
|
127
|
+
.filter(Boolean)
|
|
128
|
+
.join(' ') || undefined}
|
|
129
|
+
aria-invalid={field.error !== false || undefined}
|
|
130
|
+
aria-valuetext={format || tickLabel ? text : undefined}
|
|
131
|
+
bind:value={() => current, (next: number) => (value = next)}
|
|
132
|
+
/>
|
|
133
|
+
{#if marks.length}
|
|
134
|
+
<div class="sv-slider__ticks" aria-hidden="true">
|
|
135
|
+
{#each marks as mark (mark.value)}
|
|
136
|
+
<span
|
|
137
|
+
class={[
|
|
138
|
+
'sv-slider__tick',
|
|
139
|
+
mark.value <= min && 'sv-slider__tick--start',
|
|
140
|
+
mark.value >= max && 'sv-slider__tick--end'
|
|
141
|
+
]}
|
|
142
|
+
style:--sv-slider-at={along(mark.value)}
|
|
143
|
+
>{#if mark.label}<span class="sv-slider__tick-label">{mark.label}</span>{/if}</span
|
|
144
|
+
>
|
|
145
|
+
{/each}
|
|
146
|
+
</div>
|
|
147
|
+
{/if}
|
|
148
|
+
{#if hint && !message}<p class="sv-slider__hint" id="{id}-hint">{hint}</p>{/if}
|
|
149
|
+
<!-- Announces an error that appears after the user has moved on. -->
|
|
150
|
+
<div aria-live="polite">
|
|
151
|
+
{#if message}<p class="sv-slider__error" id="{id}-error">{message}</p>{/if}
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Slider } from './Slider.svelte';
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
@layer sv.tokens, sv.base, sv.components, sv.utilities;
|
|
2
|
+
|
|
3
|
+
@layer sv.components {
|
|
4
|
+
/*
|
|
5
|
+
* A label row with the value at its end, the platform's range input, ticks and a hint or an
|
|
6
|
+
* error. The thumb is φ⁻¹·⁵ of the control height and the track a quarter of the thumb. The
|
|
7
|
+
* filled part ends under the thumb's centre, which travels the track less one thumb.
|
|
8
|
+
*/
|
|
9
|
+
.sv-slider {
|
|
10
|
+
--sv-slider-thumb: calc(var(--sv-size-height) * 0.472);
|
|
11
|
+
--sv-slider-track: calc(var(--sv-slider-thumb) * 0.236);
|
|
12
|
+
--sv-slider-fill: calc(
|
|
13
|
+
var(--sv-slider-thumb) / 2 + var(--sv-slider-fraction) * (100% - var(--sv-slider-thumb))
|
|
14
|
+
);
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
min-inline-size: 0;
|
|
18
|
+
color: var(--sv-color-text);
|
|
19
|
+
font-family: var(--sv-font-ui);
|
|
20
|
+
font-size: var(--sv-size-text);
|
|
21
|
+
line-height: var(--sv-leading-snug);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.sv-slider--invalid {
|
|
25
|
+
--sv-color: var(--sv-color-error);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.sv-slider__header {
|
|
29
|
+
display: flex;
|
|
30
|
+
gap: var(--sv-space-8);
|
|
31
|
+
align-items: baseline;
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* The theme's label voice, as a field's label. */
|
|
36
|
+
.sv-slider__label {
|
|
37
|
+
font-size: var(--sv-label-size);
|
|
38
|
+
font-weight: var(--sv-weight-medium);
|
|
39
|
+
letter-spacing: var(--sv-label-tracking);
|
|
40
|
+
text-transform: var(--sv-label-transform);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.sv-slider__value {
|
|
44
|
+
font-weight: var(--sv-weight-medium);
|
|
45
|
+
font-variant-numeric: tabular-nums;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* The input is the press target, at least 24px tall. */
|
|
49
|
+
.sv-slider__input {
|
|
50
|
+
box-sizing: border-box;
|
|
51
|
+
inline-size: 100%;
|
|
52
|
+
block-size: max(1.5rem, var(--sv-size-height) * var(--sv-density) * 0.618);
|
|
53
|
+
margin: 0;
|
|
54
|
+
padding: 0;
|
|
55
|
+
border-radius: var(--sv-radius-sm);
|
|
56
|
+
background: transparent;
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
appearance: none;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.sv-slider__input:focus-visible {
|
|
62
|
+
outline-color: var(--sv-color);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.sv-slider__input:disabled {
|
|
66
|
+
cursor: not-allowed;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Chromium and Safari: the filled part is a gradient on the track. */
|
|
70
|
+
.sv-slider__input::-webkit-slider-runnable-track {
|
|
71
|
+
block-size: var(--sv-slider-track);
|
|
72
|
+
border-radius: var(--sv-radius-full);
|
|
73
|
+
background: linear-gradient(
|
|
74
|
+
to right,
|
|
75
|
+
var(--sv-color) var(--sv-slider-fill),
|
|
76
|
+
var(--sv-color-border-strong) var(--sv-slider-fill)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* An attribute selector, as minifiers rewrite :dir() into language guesses. */
|
|
81
|
+
:where([dir='rtl']) .sv-slider__input::-webkit-slider-runnable-track {
|
|
82
|
+
background: linear-gradient(
|
|
83
|
+
to left,
|
|
84
|
+
var(--sv-color) var(--sv-slider-fill),
|
|
85
|
+
var(--sv-color-border-strong) var(--sv-slider-fill)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.sv-slider__input::-webkit-slider-thumb {
|
|
90
|
+
box-sizing: border-box;
|
|
91
|
+
inline-size: var(--sv-slider-thumb);
|
|
92
|
+
block-size: var(--sv-slider-thumb);
|
|
93
|
+
margin-block-start: calc((var(--sv-slider-track) - var(--sv-slider-thumb)) / 2);
|
|
94
|
+
border: calc(var(--sv-hairline) * 2) solid var(--sv-color);
|
|
95
|
+
border-radius: var(--sv-radius-full);
|
|
96
|
+
background: var(--sv-color-surface);
|
|
97
|
+
appearance: none;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* Firefox draws the filled part itself. */
|
|
101
|
+
.sv-slider__input::-moz-range-track {
|
|
102
|
+
block-size: var(--sv-slider-track);
|
|
103
|
+
border-radius: var(--sv-radius-full);
|
|
104
|
+
background: var(--sv-color-border-strong);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.sv-slider__input::-moz-range-progress {
|
|
108
|
+
block-size: var(--sv-slider-track);
|
|
109
|
+
border-radius: var(--sv-radius-full);
|
|
110
|
+
background: var(--sv-color);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.sv-slider__input::-moz-range-thumb {
|
|
114
|
+
box-sizing: border-box;
|
|
115
|
+
inline-size: var(--sv-slider-thumb);
|
|
116
|
+
block-size: var(--sv-slider-thumb);
|
|
117
|
+
border: calc(var(--sv-hairline) * 2) solid var(--sv-color);
|
|
118
|
+
border-radius: var(--sv-radius-full);
|
|
119
|
+
background: var(--sv-color-surface);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Hover and press: a halo in the accent around the thumb. */
|
|
123
|
+
@media (hover: hover) {
|
|
124
|
+
.sv-slider__input:enabled:hover::-webkit-slider-thumb {
|
|
125
|
+
box-shadow: 0 0 0 calc(var(--sv-slider-thumb) * 0.382)
|
|
126
|
+
color-mix(in oklch, var(--sv-color) var(--sv-state-hover), transparent);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.sv-slider__input:enabled:hover::-moz-range-thumb {
|
|
130
|
+
box-shadow: 0 0 0 calc(var(--sv-slider-thumb) * 0.382)
|
|
131
|
+
color-mix(in oklch, var(--sv-color) var(--sv-state-hover), transparent);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.sv-slider__input:enabled:active::-webkit-slider-thumb {
|
|
136
|
+
box-shadow: 0 0 0 calc(var(--sv-slider-thumb) * 0.382)
|
|
137
|
+
color-mix(in oklch, var(--sv-color) var(--sv-state-press), transparent);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.sv-slider__input:enabled:active::-moz-range-thumb {
|
|
141
|
+
box-shadow: 0 0 0 calc(var(--sv-slider-thumb) * 0.382)
|
|
142
|
+
color-mix(in oklch, var(--sv-color) var(--sv-state-press), transparent);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* Ticks share one grid cell, each pushed along by the same distance as the thumb's centre.
|
|
147
|
+
* They are as wide as nothing, so a label centres on its tick; the end labels lean inwards.
|
|
148
|
+
*/
|
|
149
|
+
.sv-slider__ticks {
|
|
150
|
+
display: grid;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.sv-slider__tick {
|
|
154
|
+
display: flex;
|
|
155
|
+
flex-direction: column;
|
|
156
|
+
grid-area: 1 / 1;
|
|
157
|
+
align-items: center;
|
|
158
|
+
inline-size: 0;
|
|
159
|
+
margin-inline-start: calc(
|
|
160
|
+
var(--sv-slider-thumb) / 2 + var(--sv-slider-at) * (100% - var(--sv-slider-thumb))
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.sv-slider__tick--start {
|
|
165
|
+
align-items: flex-start;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.sv-slider__tick--end {
|
|
169
|
+
align-items: flex-end;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.sv-slider__tick::before {
|
|
173
|
+
content: '';
|
|
174
|
+
inline-size: var(--sv-hairline);
|
|
175
|
+
block-size: 0.382em;
|
|
176
|
+
background-color: var(--sv-color-border-strong);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.sv-slider__tick-label {
|
|
180
|
+
margin-block-start: var(--sv-space-3);
|
|
181
|
+
color: var(--sv-color-text-muted);
|
|
182
|
+
font-size: var(--sv-text-xs);
|
|
183
|
+
white-space: nowrap;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* Padding, not margin: an app's paragraph reset (p { margin: 0 }) would win over a layer. */
|
|
187
|
+
.sv-slider__hint,
|
|
188
|
+
.sv-slider__error {
|
|
189
|
+
margin: 0;
|
|
190
|
+
padding-block-start: var(--sv-space-5);
|
|
191
|
+
font-size: var(--sv-text-xs);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.sv-slider__hint {
|
|
195
|
+
color: var(--sv-color-text-muted);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.sv-slider__error {
|
|
199
|
+
color: var(--sv-color-error);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* The hint stays legible when the slider is off: it often says why. */
|
|
203
|
+
.sv-slider--disabled > :is(.sv-slider__header, .sv-slider__input, .sv-slider__ticks) {
|
|
204
|
+
opacity: 0.382;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
+
import type { FieldError, Rule, ValidateOn } from '../../core/form/types.js';
|
|
3
|
+
import type { ElementProps } from '../../core/props/element.js';
|
|
4
|
+
import type { Color, Density, Size } from '../../core/props/types.js';
|
|
5
|
+
/** The Slider props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
|
|
6
|
+
export interface SliderDefaults {
|
|
7
|
+
/**
|
|
8
|
+
* The colour of the filled part of the track and of the thumb's ring. An invalid slider uses
|
|
9
|
+
* `error`.
|
|
10
|
+
* @default 'primary'
|
|
11
|
+
*/
|
|
12
|
+
color: Color;
|
|
13
|
+
/**
|
|
14
|
+
* The size of the thumb, the track and the text.
|
|
15
|
+
* @default 'md'
|
|
16
|
+
*/
|
|
17
|
+
size: Size;
|
|
18
|
+
/**
|
|
19
|
+
* Multiplies the height of the slider's row, never the text.
|
|
20
|
+
* @default 'default'
|
|
21
|
+
*/
|
|
22
|
+
density: Density;
|
|
23
|
+
/**
|
|
24
|
+
* Mutes the slider and disables its input.
|
|
25
|
+
* @default false
|
|
26
|
+
*/
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
}
|
|
29
|
+
declare module '../../core/defaults/context.js' {
|
|
30
|
+
interface ComponentDefaults {
|
|
31
|
+
Slider: SliderDefaults;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** A labelled tick under a Slider's track. */
|
|
35
|
+
export interface SliderTick {
|
|
36
|
+
value: number;
|
|
37
|
+
/** What the tick says. Read out as the slider's value while it sits on the tick. */
|
|
38
|
+
label: string;
|
|
39
|
+
}
|
|
40
|
+
type SliderOwnProps = Partial<SliderDefaults> & {
|
|
41
|
+
/**
|
|
42
|
+
* The value, between `min` and `max`, on a step. Bindable.
|
|
43
|
+
* @default min
|
|
44
|
+
*/
|
|
45
|
+
value?: number;
|
|
46
|
+
/** @default 0 */
|
|
47
|
+
min?: number;
|
|
48
|
+
/** @default 100 */
|
|
49
|
+
max?: number;
|
|
50
|
+
/**
|
|
51
|
+
* The distance between the values the slider stops at.
|
|
52
|
+
* @default 1
|
|
53
|
+
*/
|
|
54
|
+
step?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Marks under the track: `true` for every step, a list of values, or values with labels such
|
|
57
|
+
* as `{ value: 50, label: 'Balanced' }`.
|
|
58
|
+
*/
|
|
59
|
+
ticks?: boolean | readonly number[] | readonly SliderTick[];
|
|
60
|
+
/**
|
|
61
|
+
* How the value reads, beside the label and to screen readers, for example
|
|
62
|
+
* `(value) => value + '%'`. Defaults to the number in the locale's format, or the label of the
|
|
63
|
+
* tick the slider sits on.
|
|
64
|
+
*/
|
|
65
|
+
format?: (value: number) => string;
|
|
66
|
+
/** The visible label, linked to the input. Without it, name the slider with `aria-label`. */
|
|
67
|
+
label?: string;
|
|
68
|
+
/** Help under the slider. An error replaces it. */
|
|
69
|
+
hint?: string;
|
|
70
|
+
/**
|
|
71
|
+
* An error from outside the slider, such as the server's answer: a message, a list of which
|
|
72
|
+
* the first is shown, or `true` for an invalid state described elsewhere.
|
|
73
|
+
*/
|
|
74
|
+
error?: FieldError;
|
|
75
|
+
/** Checks run in order on the value. The first message is shown. */
|
|
76
|
+
rules?: readonly Rule<number>[];
|
|
77
|
+
/** When the message shows. Defaults to the form's setting, else `'blur'`. */
|
|
78
|
+
validateOn?: ValidateOn;
|
|
79
|
+
/** Inline style of the slider's root element. */
|
|
80
|
+
style?: string | null;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* A number picked by dragging a thumb along a track: the platform's own range input, so the
|
|
84
|
+
* keyboard, touch, forms and right-to-left pages work as they always do. The value shows beside
|
|
85
|
+
* the label. A range always holds a value, so it takes no `required`. `class` and `style` apply
|
|
86
|
+
* to the root; `id`, `ref`, `name` and every other attribute go to the `<input type="range">`.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* <Slider
|
|
90
|
+
* label="Risk"
|
|
91
|
+
* name="risk"
|
|
92
|
+
* step={25}
|
|
93
|
+
* ticks={[
|
|
94
|
+
* { value: 0, label: 'Careful' },
|
|
95
|
+
* { value: 50, label: 'Balanced' },
|
|
96
|
+
* { value: 100, label: 'Bold' }
|
|
97
|
+
* ]}
|
|
98
|
+
* bind:value={risk}
|
|
99
|
+
* />
|
|
100
|
+
*/
|
|
101
|
+
export type SliderProps = ElementProps<HTMLInputElement, Omit<HTMLInputAttributes, 'type' | 'children' | 'required'>, SliderOwnProps>;
|
|
102
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// A setting that is on or off, with its label beside it and validation. See SwitchProps.
|
|
3
|
+
import { untrack } from 'svelte';
|
|
4
|
+
import { DEV, warnUnnamed } from '#dev';
|
|
5
|
+
import { useDefaults } from '../../core/defaults/context.js';
|
|
6
|
+
import { createField } from '../../core/form/field.svelte.js';
|
|
7
|
+
import { useLocale } from '../../core/locale/locale.js';
|
|
8
|
+
import { sharedClasses } from '../../core/props/classes.js';
|
|
9
|
+
import Choice from '../Choice/Choice.svelte';
|
|
10
|
+
import './switch.css';
|
|
11
|
+
import type { SwitchDefaults, SwitchProps } from './types.js';
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
color,
|
|
15
|
+
size,
|
|
16
|
+
density,
|
|
17
|
+
disabled,
|
|
18
|
+
checked = $bindable(false),
|
|
19
|
+
label,
|
|
20
|
+
hint,
|
|
21
|
+
error,
|
|
22
|
+
rules,
|
|
23
|
+
validateOn,
|
|
24
|
+
required = false,
|
|
25
|
+
id,
|
|
26
|
+
'aria-describedby': describedBy,
|
|
27
|
+
class: className,
|
|
28
|
+
style,
|
|
29
|
+
ref = $bindable(null),
|
|
30
|
+
...rest
|
|
31
|
+
}: SwitchProps = $props();
|
|
32
|
+
|
|
33
|
+
const resolve = useDefaults<SwitchDefaults>('Switch', {
|
|
34
|
+
color: 'primary',
|
|
35
|
+
size: 'md',
|
|
36
|
+
density: 'default',
|
|
37
|
+
disabled: false
|
|
38
|
+
});
|
|
39
|
+
const p = $derived(resolve({ color, size, density, disabled }));
|
|
40
|
+
const locale = useLocale();
|
|
41
|
+
// A form reset goes back to the state the switch started in.
|
|
42
|
+
const initial = untrack(() => checked ?? false);
|
|
43
|
+
|
|
44
|
+
const field = createField<boolean>({
|
|
45
|
+
value: () => checked ?? false,
|
|
46
|
+
// Rules run on a switch that is on only, as they run on a filled field only.
|
|
47
|
+
empty: (on) => !on,
|
|
48
|
+
check: (on) => (!on && required ? locale.t('required') : undefined),
|
|
49
|
+
rules: () => rules,
|
|
50
|
+
error: () => error,
|
|
51
|
+
validateOn: () => validateOn,
|
|
52
|
+
control: () => ref
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (DEV) $effect(() => warnUnnamed('Switch', ref));
|
|
56
|
+
|
|
57
|
+
// A toggle is a whole edit, so it also counts as leaving: the message shows at once, even in
|
|
58
|
+
// Safari, where a click does not focus the input.
|
|
59
|
+
function toggled() {
|
|
60
|
+
field.changed();
|
|
61
|
+
field.left();
|
|
62
|
+
}
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<Choice
|
|
66
|
+
{id}
|
|
67
|
+
{label}
|
|
68
|
+
{hint}
|
|
69
|
+
error={field.error}
|
|
70
|
+
{required}
|
|
71
|
+
disabled={p.disabled}
|
|
72
|
+
class={['sv-switch', sharedClasses(p, 'Switch'), className]}
|
|
73
|
+
{style}
|
|
74
|
+
onchange={toggled}
|
|
75
|
+
>
|
|
76
|
+
{#snippet children(attributes)}
|
|
77
|
+
<span class="sv-switch__control">
|
|
78
|
+
<input
|
|
79
|
+
bind:this={ref}
|
|
80
|
+
defaultChecked={initial}
|
|
81
|
+
{...rest}
|
|
82
|
+
{...attributes}
|
|
83
|
+
aria-describedby={[describedBy, attributes['aria-describedby']].filter(Boolean).join(' ') ||
|
|
84
|
+
undefined}
|
|
85
|
+
type="checkbox"
|
|
86
|
+
role="switch"
|
|
87
|
+
class="sv-switch__input"
|
|
88
|
+
bind:checked
|
|
89
|
+
/>
|
|
90
|
+
<span class="sv-switch__track" aria-hidden="true"><span class="sv-switch__thumb"></span></span
|
|
91
|
+
>
|
|
92
|
+
</span>
|
|
93
|
+
{/snippet}
|
|
94
|
+
</Choice>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Switch } from './Switch.svelte';
|