@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,210 @@
|
|
|
1
|
+
@layer sv.tokens, sv.base, sv.components, sv.utilities;
|
|
2
|
+
|
|
3
|
+
@layer sv.components {
|
|
4
|
+
/*
|
|
5
|
+
* A label above a box above a hint or an error. The box is as tall as a Button of the same
|
|
6
|
+
* size and density. Its border is --sv-field-border; the accent of a focused or invalid
|
|
7
|
+
* field is a layer in --sv-color whose opacity changes.
|
|
8
|
+
*/
|
|
9
|
+
.sv-field {
|
|
10
|
+
--sv-field-border: var(--sv-color-border-strong);
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
min-inline-size: 0;
|
|
14
|
+
font-family: var(--sv-font-ui);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* The theme's label voice: Heritage and Maison set it in tracked capitals. */
|
|
18
|
+
.sv-field__label {
|
|
19
|
+
align-self: flex-start;
|
|
20
|
+
margin-block-end: var(--sv-space-8);
|
|
21
|
+
color: var(--sv-color-text);
|
|
22
|
+
font-size: var(--sv-label-size);
|
|
23
|
+
font-weight: var(--sv-weight-medium);
|
|
24
|
+
line-height: var(--sv-leading-snug);
|
|
25
|
+
letter-spacing: var(--sv-label-tracking);
|
|
26
|
+
text-transform: var(--sv-label-transform);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.sv-field__required {
|
|
30
|
+
margin-inline-start: 0.236em;
|
|
31
|
+
color: var(--sv-color-error);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.sv-field__box {
|
|
35
|
+
position: relative;
|
|
36
|
+
isolation: isolate;
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
gap: 0.618em;
|
|
40
|
+
box-sizing: border-box;
|
|
41
|
+
min-block-size: calc(var(--sv-size-height) * var(--sv-density));
|
|
42
|
+
padding-inline: calc(var(--sv-size-height) * var(--sv-density) * 0.382);
|
|
43
|
+
border: var(--sv-hairline) solid var(--sv-field-border);
|
|
44
|
+
/* A control that grows to several lines sets --sv-field-radius, so it never turns oval. */
|
|
45
|
+
border-radius: var(--sv-rounded, var(--sv-field-radius, var(--sv-radius-md)));
|
|
46
|
+
color: var(--sv-color-text);
|
|
47
|
+
font-size: var(--sv-size-text);
|
|
48
|
+
line-height: var(--sv-leading-snug);
|
|
49
|
+
cursor: text;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.sv-field__box::after {
|
|
53
|
+
content: '';
|
|
54
|
+
position: absolute;
|
|
55
|
+
inset: calc(var(--sv-hairline) * -1);
|
|
56
|
+
border: var(--sv-focus-width) solid var(--sv-color);
|
|
57
|
+
border-radius: inherit;
|
|
58
|
+
opacity: 0;
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
transition: opacity var(--sv-duration-fast) var(--sv-ease);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.sv-field__box:focus-within::after {
|
|
64
|
+
opacity: 1;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@media (hover: hover) {
|
|
68
|
+
.sv-field:where(:not(.sv-field--disabled, .sv-field--readonly)) .sv-field__box:hover {
|
|
69
|
+
--sv-field-border: var(--sv-color-text-muted);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.sv-field--invalid,
|
|
74
|
+
.sv-field--invalid .sv-field__box:hover {
|
|
75
|
+
--sv-color: var(--sv-color-error);
|
|
76
|
+
--sv-field-border: var(--sv-color-error);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Variants. Tonal is a wash of the text colour, not of the accent. */
|
|
80
|
+
.sv-variant-tonal > .sv-field__box {
|
|
81
|
+
border-width: 0 0 var(--sv-hairline);
|
|
82
|
+
border-end-start-radius: 0;
|
|
83
|
+
border-end-end-radius: 0;
|
|
84
|
+
background-color: color-mix(in oklch, var(--sv-color-text) 5%, transparent);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.sv-variant-text > .sv-field__box {
|
|
88
|
+
border-width: 0 0 var(--sv-hairline);
|
|
89
|
+
border-radius: 0;
|
|
90
|
+
padding-inline: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.sv-variant-tonal > .sv-field__box::after,
|
|
94
|
+
.sv-variant-text > .sv-field__box::after {
|
|
95
|
+
border-width: 0 0 var(--sv-focus-width);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.sv-variant-elevated > .sv-field__box {
|
|
99
|
+
border-color: transparent;
|
|
100
|
+
background-color: var(--sv-color-surface);
|
|
101
|
+
box-shadow: var(--sv-shadow);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.sv-field--invalid.sv-variant-elevated > .sv-field__box {
|
|
105
|
+
border-color: var(--sv-field-border);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.sv-variant-plain > .sv-field__box {
|
|
109
|
+
border-color: transparent;
|
|
110
|
+
padding-inline: 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* A plain field draws no box, so its focus is the theme's ring. */
|
|
114
|
+
.sv-variant-plain > .sv-field__box::after {
|
|
115
|
+
content: none;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.sv-variant-plain > .sv-field__box:focus-within {
|
|
119
|
+
outline: var(--sv-focus-width) solid var(--sv-color);
|
|
120
|
+
outline-offset: var(--sv-focus-offset);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Muted at φ⁻², as a disabled Button. */
|
|
124
|
+
.sv-field--disabled {
|
|
125
|
+
opacity: 0.382;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.sv-field--disabled .sv-field__box {
|
|
129
|
+
cursor: not-allowed;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.sv-field--readonly .sv-field__box {
|
|
133
|
+
cursor: default;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.sv-field__prepend,
|
|
137
|
+
.sv-field__append {
|
|
138
|
+
display: inline-flex;
|
|
139
|
+
flex: none;
|
|
140
|
+
align-items: center;
|
|
141
|
+
color: var(--sv-color-text-muted);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
:where(.sv-field__prepend, .sv-field__append) > svg {
|
|
145
|
+
inline-size: 1.272em;
|
|
146
|
+
block-size: 1.272em;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* Padding, not margin: an app's paragraph reset (p { margin: 0 }) would win over a layer. */
|
|
150
|
+
.sv-field__hint,
|
|
151
|
+
.sv-field__error {
|
|
152
|
+
margin: 0;
|
|
153
|
+
padding-block-start: var(--sv-space-5);
|
|
154
|
+
font-size: var(--sv-text-xs);
|
|
155
|
+
line-height: var(--sv-leading-snug);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.sv-field__hint {
|
|
159
|
+
color: var(--sv-color-text-muted);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.sv-field__error {
|
|
163
|
+
color: var(--sv-color-error);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/*
|
|
167
|
+
* The control fills the box; the box shows focus. Text is at least 16px on touch screens,
|
|
168
|
+
* where smaller text makes iOS zoom into the page on focus.
|
|
169
|
+
*/
|
|
170
|
+
.sv-field__control {
|
|
171
|
+
flex: 1;
|
|
172
|
+
align-self: stretch;
|
|
173
|
+
min-inline-size: 0;
|
|
174
|
+
box-sizing: border-box;
|
|
175
|
+
margin: 0;
|
|
176
|
+
padding: 0;
|
|
177
|
+
border: 0;
|
|
178
|
+
background: none;
|
|
179
|
+
color: inherit;
|
|
180
|
+
font: inherit;
|
|
181
|
+
letter-spacing: inherit;
|
|
182
|
+
appearance: none;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.sv-field__control:focus-visible {
|
|
186
|
+
outline: none;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.sv-field__control::placeholder {
|
|
190
|
+
color: var(--sv-color-text-subtle);
|
|
191
|
+
opacity: 1;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.sv-field__control:disabled {
|
|
195
|
+
cursor: not-allowed;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Autofill keeps the field's colours: the browser's tint is delayed for good. */
|
|
199
|
+
.sv-field__control:autofill {
|
|
200
|
+
transition:
|
|
201
|
+
background-color 0s 600000s,
|
|
202
|
+
color 0s 600000s;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@media (pointer: coarse) {
|
|
206
|
+
.sv-field__control {
|
|
207
|
+
font-size: max(1rem, 1em);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { FieldError } from '../../core/form/types.js';
|
|
4
|
+
import type { ElementProps } from '../../core/props/element.js';
|
|
5
|
+
import type { Color, Density, Rounded, Size } from '../../core/props/types.js';
|
|
6
|
+
/** The variants a boxed field takes, a subset of the shared `VARIANTS`. */
|
|
7
|
+
export declare const FIELD_VARIANTS: readonly ["outlined", "tonal", "elevated", "text", "plain"];
|
|
8
|
+
/**
|
|
9
|
+
* How a field's box is drawn: `outlined` (a border), `tonal` (a wash with a rule under it),
|
|
10
|
+
* `elevated` (a surface with a shadow), `text` (only the rule) and `plain` (nothing, for a field
|
|
11
|
+
* inside another component).
|
|
12
|
+
*/
|
|
13
|
+
export type FieldVariant = (typeof FIELD_VARIANTS)[number];
|
|
14
|
+
/** The Field props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
|
|
15
|
+
export interface FieldDefaults {
|
|
16
|
+
/**
|
|
17
|
+
* How the box is drawn.
|
|
18
|
+
* @default 'outlined'
|
|
19
|
+
*/
|
|
20
|
+
variant: FieldVariant;
|
|
21
|
+
/**
|
|
22
|
+
* The accent of the focused field. An invalid field uses `error`.
|
|
23
|
+
* @default 'primary'
|
|
24
|
+
*/
|
|
25
|
+
color: Color;
|
|
26
|
+
/**
|
|
27
|
+
* Height and text size, matching a Button of the same size.
|
|
28
|
+
* @default 'md'
|
|
29
|
+
*/
|
|
30
|
+
size: Size;
|
|
31
|
+
/**
|
|
32
|
+
* Multiplies the height and padding, never the text.
|
|
33
|
+
* @default 'default'
|
|
34
|
+
*/
|
|
35
|
+
density: Density;
|
|
36
|
+
/**
|
|
37
|
+
* Corner rounding. `true` keeps the theme's radius.
|
|
38
|
+
* @default true
|
|
39
|
+
*/
|
|
40
|
+
rounded: Rounded;
|
|
41
|
+
/**
|
|
42
|
+
* Mutes the field and disables its control.
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
disabled: boolean;
|
|
46
|
+
}
|
|
47
|
+
declare module '../../core/defaults/context.js' {
|
|
48
|
+
interface ComponentDefaults {
|
|
49
|
+
Field: FieldDefaults;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** What a Field passes to the control it wraps. Spread it onto the control element. */
|
|
53
|
+
export interface FieldControlAttributes {
|
|
54
|
+
/** The id the label points at. */
|
|
55
|
+
id: string;
|
|
56
|
+
/** `sv-field__control`: fills the box and takes its text style. */
|
|
57
|
+
class: string;
|
|
58
|
+
/** The hint or the error, whichever is shown. */
|
|
59
|
+
'aria-describedby': string | undefined;
|
|
60
|
+
/** Set while the field shows an error. */
|
|
61
|
+
'aria-invalid': true | undefined;
|
|
62
|
+
required: boolean;
|
|
63
|
+
disabled: boolean;
|
|
64
|
+
readonly: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** The props of a field's label, help and error, shared by every boxed field. */
|
|
67
|
+
export interface FieldContentProps {
|
|
68
|
+
/** The visible label, linked to the control. Without it, name the control with `aria-label`. */
|
|
69
|
+
label?: string;
|
|
70
|
+
/** Help under the field. An error replaces it. */
|
|
71
|
+
hint?: string;
|
|
72
|
+
/**
|
|
73
|
+
* An error from outside the field, such as the server's answer: a message, a list of which
|
|
74
|
+
* the first is shown, or `true` for an invalid state described elsewhere.
|
|
75
|
+
*/
|
|
76
|
+
error?: FieldError;
|
|
77
|
+
/** Content at the start of the box, usually an icon. */
|
|
78
|
+
prepend?: Snippet;
|
|
79
|
+
/** Content at the end of the box: an icon, a unit or a button. */
|
|
80
|
+
append?: Snippet;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A label, a box for a control, and its hint or error. Wrap your own control in it: the
|
|
84
|
+
* children snippet receives the id, ARIA links and state to spread onto the control. Other
|
|
85
|
+
* attributes go to the root element.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* <Field label="Start date" hint="The first payment goes out on this day" required>
|
|
89
|
+
* {#snippet children(attributes)}
|
|
90
|
+
* <input type="date" name="start" {...attributes} bind:value={start} />
|
|
91
|
+
* {/snippet}
|
|
92
|
+
* </Field>
|
|
93
|
+
*/
|
|
94
|
+
export type FieldProps = ElementProps<HTMLDivElement, HTMLAttributes<HTMLDivElement>, Partial<FieldDefaults> & FieldContentProps & {
|
|
95
|
+
/** The id of the control. Generated when not given. */
|
|
96
|
+
id?: string | null;
|
|
97
|
+
/**
|
|
98
|
+
* Adds an asterisk to the label. The control carries `required` itself.
|
|
99
|
+
* @default false
|
|
100
|
+
*/
|
|
101
|
+
required?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* The control can be read and focused but not changed.
|
|
104
|
+
* @default false
|
|
105
|
+
*/
|
|
106
|
+
readonly?: boolean;
|
|
107
|
+
/** The control. Spread the attributes it receives onto it. */
|
|
108
|
+
children: Snippet<[FieldControlAttributes]>;
|
|
109
|
+
}>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// A form that checks its fields on submit. See FormProps for the props.
|
|
3
|
+
import { flushSync } from 'svelte';
|
|
4
|
+
import DefaultsProvider from '../../core/defaults/DefaultsProvider.svelte';
|
|
5
|
+
import type { DefaultsConfig } from '../../core/defaults/context.js';
|
|
6
|
+
import { setFormContext, type FormField } from '../../core/form/context.js';
|
|
7
|
+
import './form.css';
|
|
8
|
+
import type { FormProps } from './types.js';
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
validateOn,
|
|
12
|
+
disabled = false,
|
|
13
|
+
onsubmit,
|
|
14
|
+
onreset,
|
|
15
|
+
children,
|
|
16
|
+
class: className,
|
|
17
|
+
ref = $bindable(null),
|
|
18
|
+
...rest
|
|
19
|
+
}: FormProps = $props();
|
|
20
|
+
|
|
21
|
+
// A registry, not state: nothing renders from it, so a plain Set rather than a SvelteSet.
|
|
22
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- never read reactively
|
|
23
|
+
const fields = new Set<FormField>();
|
|
24
|
+
setFormContext({
|
|
25
|
+
get validateOn() {
|
|
26
|
+
return validateOn;
|
|
27
|
+
},
|
|
28
|
+
register(field) {
|
|
29
|
+
fields.add(field);
|
|
30
|
+
return () => fields.delete(field);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Always rendered, so turning `disabled` on and off never remounts the fields.
|
|
35
|
+
const defaults: DefaultsConfig = $derived(disabled ? { global: { disabled: true } } : {});
|
|
36
|
+
|
|
37
|
+
/** Shows the message of every field. Returns `true` when every field is valid. */
|
|
38
|
+
export function validate(): boolean {
|
|
39
|
+
let valid = true;
|
|
40
|
+
for (const field of fields) if (!field.validate()) valid = false;
|
|
41
|
+
return valid;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Puts every field back to the value it started with, and hides every message. */
|
|
45
|
+
export function reset(): void {
|
|
46
|
+
ref?.reset();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Hides every message and keeps the values. */
|
|
50
|
+
export function resetValidation(): void {
|
|
51
|
+
for (const field of fields) field.resetValidation();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function submit(event: SubmitEvent & { currentTarget: EventTarget & HTMLFormElement }) {
|
|
55
|
+
const invalid = [...fields].filter((field) => !field.validate());
|
|
56
|
+
if (invalid.length === 0) {
|
|
57
|
+
onsubmit?.(event);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Stop here, including listeners added later such as SvelteKit's enhance, which would
|
|
61
|
+
// otherwise send the form anyway.
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
event.stopImmediatePropagation();
|
|
64
|
+
// Focus the first invalid control in document order, once its message is in the DOM, so
|
|
65
|
+
// its label and error are read out together.
|
|
66
|
+
flushSync();
|
|
67
|
+
const controls = invalid
|
|
68
|
+
.map((field) => field.control())
|
|
69
|
+
.filter((control): control is HTMLElement => control != null);
|
|
70
|
+
controls.sort((a, b) =>
|
|
71
|
+
a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
|
|
72
|
+
);
|
|
73
|
+
controls[0]?.focus();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function afterReset(event: Event & { currentTarget: EventTarget & HTMLFormElement }) {
|
|
77
|
+
resetValidation();
|
|
78
|
+
(onreset as ((event: Event) => void) | null | undefined)?.(event);
|
|
79
|
+
}
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<form
|
|
83
|
+
bind:this={ref}
|
|
84
|
+
{...rest}
|
|
85
|
+
novalidate
|
|
86
|
+
class={['sv-form', className]}
|
|
87
|
+
onsubmit={submit}
|
|
88
|
+
onreset={afterReset}
|
|
89
|
+
>
|
|
90
|
+
<DefaultsProvider {defaults}>
|
|
91
|
+
{@render children?.()}
|
|
92
|
+
</DefaultsProvider>
|
|
93
|
+
</form>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
@layer sv.tokens, sv.base, sv.components, sv.utilities;
|
|
2
|
+
|
|
3
|
+
@layer sv.components {
|
|
4
|
+
/*
|
|
5
|
+
* Fields stack at one rhythm and take the full width; buttons keep their own width. A class
|
|
6
|
+
* on the form changes the layout, for example to a row for a search bar.
|
|
7
|
+
*/
|
|
8
|
+
.sv-form {
|
|
9
|
+
display: grid;
|
|
10
|
+
gap: var(--sv-space-21);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.sv-form > :where(.sv-button) {
|
|
14
|
+
justify-self: start;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Form } from './Form.svelte';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLFormAttributes } from 'svelte/elements';
|
|
3
|
+
import type { ValidateOn } from '../../core/form/types.js';
|
|
4
|
+
import type { ElementProps } from '../../core/props/element.js';
|
|
5
|
+
/**
|
|
6
|
+
* A `<form>` that checks its fields when it is submitted. An invalid form does not submit: every
|
|
7
|
+
* field shows its message and the first invalid one takes focus. A valid form calls `onsubmit`,
|
|
8
|
+
* or submits as HTML does when there is no `onsubmit`, so SvelteKit form actions work as they
|
|
9
|
+
* are. Other attributes go to the `<form>`. Through `bind:this` it offers `validate()`,
|
|
10
|
+
* `reset()` and `resetValidation()`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <Form method="POST" onsubmit={(event) => { event.preventDefault(); save(); }}>
|
|
14
|
+
* <TextField label="Email" name="email" type="email" required />
|
|
15
|
+
* <Button type="submit">Sign up</Button>
|
|
16
|
+
* </Form>
|
|
17
|
+
*/
|
|
18
|
+
export type FormProps = ElementProps<HTMLFormElement, HTMLFormAttributes, {
|
|
19
|
+
/**
|
|
20
|
+
* When the fields show their messages, unless a field sets its own.
|
|
21
|
+
* @default 'blur'
|
|
22
|
+
*/
|
|
23
|
+
validateOn?: ValidateOn;
|
|
24
|
+
/**
|
|
25
|
+
* Disables every control inside, Buttons included, for example while a submission runs.
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Called when the form is submitted and every field is valid. Without it, the form submits
|
|
31
|
+
* as HTML does; call `event.preventDefault()` to handle the submission yourself.
|
|
32
|
+
*/
|
|
33
|
+
onsubmit?: (event: SubmitEvent & {
|
|
34
|
+
currentTarget: EventTarget & HTMLFormElement;
|
|
35
|
+
}) => void;
|
|
36
|
+
/** The fields and buttons. */
|
|
37
|
+
children?: Snippet;
|
|
38
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// An icon from path data or any SVG of your own. See IconProps for the props.
|
|
3
|
+
import { sharedClasses } from '../../core/props/classes.js';
|
|
4
|
+
import './icon.css';
|
|
5
|
+
import type { IconProps } from './types.js';
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
path,
|
|
9
|
+
viewBox = '0 0 24 24',
|
|
10
|
+
size,
|
|
11
|
+
color,
|
|
12
|
+
label,
|
|
13
|
+
children,
|
|
14
|
+
class: className,
|
|
15
|
+
ref = $bindable(null),
|
|
16
|
+
...rest
|
|
17
|
+
}: IconProps = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<span
|
|
21
|
+
bind:this={ref}
|
|
22
|
+
{...rest}
|
|
23
|
+
role={label ? 'img' : undefined}
|
|
24
|
+
aria-label={label}
|
|
25
|
+
aria-hidden={label ? undefined : 'true'}
|
|
26
|
+
class={[
|
|
27
|
+
'sv-icon',
|
|
28
|
+
sharedClasses({ size, color }, 'Icon'),
|
|
29
|
+
color && 'sv-icon--colored',
|
|
30
|
+
className
|
|
31
|
+
]}
|
|
32
|
+
>
|
|
33
|
+
{#if path}
|
|
34
|
+
<svg class="sv-icon__paths" {viewBox} aria-hidden="true"><path d={path} /></svg>
|
|
35
|
+
{:else}
|
|
36
|
+
{@render children?.()}
|
|
37
|
+
{/if}
|
|
38
|
+
</span>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
@layer sv.tokens, sv.base, sv.components, sv.utilities;
|
|
2
|
+
|
|
3
|
+
@layer sv.components {
|
|
4
|
+
/* φ^½ of the text: the same proportion as icons in buttons. */
|
|
5
|
+
.sv-icon {
|
|
6
|
+
display: inline-flex;
|
|
7
|
+
flex: none;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
inline-size: 1.272em;
|
|
11
|
+
block-size: 1.272em;
|
|
12
|
+
line-height: 1;
|
|
13
|
+
vertical-align: -0.236em;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Only an icon with its own size reads the shared size; otherwise it follows its text. */
|
|
17
|
+
.sv-icon:is(.sv-size-xs, .sv-size-sm, .sv-size-md, .sv-size-lg, .sv-size-xl) {
|
|
18
|
+
font-size: var(--sv-size-text);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.sv-icon--colored {
|
|
22
|
+
color: var(--sv-color);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.sv-icon > svg {
|
|
26
|
+
inline-size: 100%;
|
|
27
|
+
block-size: 100%;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.sv-icon__paths {
|
|
31
|
+
fill: currentColor;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Icon } from './Icon.svelte';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { ElementProps } from '../../core/props/element.js';
|
|
4
|
+
import type { Color, Size } from '../../core/props/types.js';
|
|
5
|
+
/**
|
|
6
|
+
* An icon: SVG path data, or any icon of your own as `children`. Decorative unless it has a
|
|
7
|
+
* `label`.
|
|
8
|
+
*/
|
|
9
|
+
export type IconProps = ElementProps<HTMLSpanElement, HTMLAttributes<HTMLSpanElement>, {
|
|
10
|
+
/**
|
|
11
|
+
* SVG path data, filled with the current colour: the format of path-based icon sets such
|
|
12
|
+
* as Material Design Icons. Several shapes go in one string (`M… Z M… Z`).
|
|
13
|
+
*/
|
|
14
|
+
path?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The coordinate box of `path`.
|
|
17
|
+
* @default '0 0 24 24'
|
|
18
|
+
*/
|
|
19
|
+
viewBox?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The text size the icon is drawn at, φ^½ larger. Without it, the icon follows the text
|
|
22
|
+
* around it.
|
|
23
|
+
*/
|
|
24
|
+
size?: Size;
|
|
25
|
+
/** The icon's colour. Without it, the icon takes the colour of the text around it. */
|
|
26
|
+
color?: Color;
|
|
27
|
+
/**
|
|
28
|
+
* A name for an icon that means something on its own, for assistive technology. Without
|
|
29
|
+
* it, the icon is decorative and hidden from it.
|
|
30
|
+
*/
|
|
31
|
+
label?: string;
|
|
32
|
+
/** Any other icon (an `<svg>`, an icon component), sized and coloured like a path. */
|
|
33
|
+
children?: Snippet;
|
|
34
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// A list of ListItems. See ListProps for the props.
|
|
3
|
+
import { useDefaults } from '../../core/defaults/context.js';
|
|
4
|
+
import { sharedClasses } from '../../core/props/classes.js';
|
|
5
|
+
import './list.css';
|
|
6
|
+
import type { ListDefaults, ListProps } from './types.js';
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
density,
|
|
10
|
+
color,
|
|
11
|
+
nav,
|
|
12
|
+
children,
|
|
13
|
+
class: className,
|
|
14
|
+
ref = $bindable(null),
|
|
15
|
+
...rest
|
|
16
|
+
}: ListProps = $props();
|
|
17
|
+
|
|
18
|
+
const resolve = useDefaults<ListDefaults>('List', {
|
|
19
|
+
density: 'default',
|
|
20
|
+
color: 'primary',
|
|
21
|
+
nav: false
|
|
22
|
+
});
|
|
23
|
+
const p = $derived(resolve({ density, color, nav }));
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<!-- role="list": Safari drops the list semantics of a list without bullets. -->
|
|
27
|
+
<ul
|
|
28
|
+
bind:this={ref}
|
|
29
|
+
{...rest}
|
|
30
|
+
role="list"
|
|
31
|
+
class={[
|
|
32
|
+
'sv-list',
|
|
33
|
+
sharedClasses({ density: p.density, color: p.color }, 'List'),
|
|
34
|
+
p.nav && 'sv-list--nav',
|
|
35
|
+
className
|
|
36
|
+
]}
|
|
37
|
+
>
|
|
38
|
+
{@render children?.()}
|
|
39
|
+
</ul>
|