@sepale/components 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.md +65 -3
- package/dist/components/Accordion.svelte +48 -0
- package/dist/components/Accordion.svelte.d.ts +24 -0
- package/dist/components/Alert.svelte +107 -0
- package/dist/components/Alert.svelte.d.ts +40 -0
- package/dist/components/Avatar.svelte +75 -0
- package/dist/components/Avatar.svelte.d.ts +37 -0
- package/dist/components/Badge.svelte +46 -0
- package/dist/components/Badge.svelte.d.ts +22 -0
- package/dist/components/Breadcrumbs.svelte +36 -0
- package/dist/components/Breadcrumbs.svelte.d.ts +18 -0
- package/dist/components/Bubble.svelte +43 -0
- package/dist/components/Bubble.svelte.d.ts +23 -0
- package/dist/components/Button.svelte +132 -0
- package/dist/components/Button.svelte.d.ts +40 -0
- package/dist/components/Calendar.svelte +193 -0
- package/dist/components/Calendar.svelte.d.ts +60 -0
- package/dist/components/Card.svelte +69 -0
- package/dist/components/Card.svelte.d.ts +37 -0
- package/dist/components/Carousel.svelte +550 -0
- package/dist/components/Carousel.svelte.d.ts +124 -0
- package/dist/components/Checkbox.svelte +48 -0
- package/dist/components/Checkbox.svelte.d.ts +26 -0
- package/dist/components/Chip.svelte +60 -0
- package/dist/components/Chip.svelte.d.ts +26 -0
- package/dist/components/ChipsInput.svelte +158 -0
- package/dist/components/ChipsInput.svelte.d.ts +64 -0
- package/dist/components/Collapse.svelte +101 -0
- package/dist/components/Collapse.svelte.d.ts +46 -0
- package/dist/components/ColorPicker.svelte +135 -0
- package/dist/components/ColorPicker.svelte.d.ts +44 -0
- package/dist/components/Combobox.svelte +496 -0
- package/dist/components/Combobox.svelte.d.ts +96 -0
- package/dist/components/DataControl.svelte +754 -0
- package/dist/components/DataControl.svelte.d.ts +143 -0
- package/dist/components/DataHandler.svelte +67 -0
- package/dist/components/DataHandler.svelte.d.ts +44 -0
- package/dist/components/DatePicker.svelte +185 -0
- package/dist/components/DatePicker.svelte.d.ts +56 -0
- package/dist/components/Dialog.svelte +194 -0
- package/dist/components/Dialog.svelte.d.ts +51 -0
- package/dist/components/Divider.svelte +54 -0
- package/dist/components/Divider.svelte.d.ts +27 -0
- package/dist/components/Dock.svelte +34 -0
- package/dist/components/Dock.svelte.d.ts +18 -0
- package/dist/components/Drawer.svelte +174 -0
- package/dist/components/Drawer.svelte.d.ts +51 -0
- package/dist/components/Dropdown.svelte +183 -0
- package/dist/components/Dropdown.svelte.d.ts +52 -0
- package/dist/components/Editable.svelte +292 -0
- package/dist/components/Editable.svelte.d.ts +113 -0
- package/dist/components/EmptyState.svelte +64 -0
- package/dist/components/EmptyState.svelte.d.ts +29 -0
- package/dist/components/Fieldset.svelte +42 -0
- package/dist/components/Fieldset.svelte.d.ts +20 -0
- package/dist/components/FileDropzone.svelte +154 -0
- package/dist/components/FileDropzone.svelte.d.ts +45 -0
- package/dist/components/FileExplorer.svelte +643 -0
- package/dist/components/FileExplorer.svelte.d.ts +114 -0
- package/dist/components/FileInput.svelte +125 -0
- package/dist/components/FileInput.svelte.d.ts +51 -0
- package/dist/components/FloatingLabel.svelte +38 -0
- package/dist/components/FloatingLabel.svelte.d.ts +24 -0
- package/dist/components/Footer.svelte +68 -0
- package/dist/components/Footer.svelte.d.ts +37 -0
- package/dist/components/Grid.svelte +122 -0
- package/dist/components/Grid.svelte.d.ts +72 -0
- package/dist/components/Hero.svelte +62 -0
- package/dist/components/Hero.svelte.d.ts +33 -0
- package/dist/components/Input.svelte +184 -0
- package/dist/components/Input.svelte.d.ts +65 -0
- package/dist/components/Join.svelte +38 -0
- package/dist/components/Join.svelte.d.ts +21 -0
- package/dist/components/Kanban.svelte +284 -0
- package/dist/components/Kanban.svelte.d.ts +93 -0
- package/dist/components/Label.svelte +32 -0
- package/dist/components/Label.svelte.d.ts +21 -0
- package/dist/components/LaptopFrame.svelte +44 -0
- package/dist/components/LaptopFrame.svelte.d.ts +21 -0
- package/dist/components/List.svelte +95 -0
- package/dist/components/List.svelte.d.ts +69 -0
- package/dist/components/Loading.svelte +37 -0
- package/dist/components/Loading.svelte.d.ts +17 -0
- package/dist/components/Menu.svelte +144 -0
- package/dist/components/Menu.svelte.d.ts +53 -0
- package/dist/components/MobileFrame.svelte +41 -0
- package/dist/components/MobileFrame.svelte.d.ts +21 -0
- package/dist/components/Navbar.svelte +49 -0
- package/dist/components/Navbar.svelte.d.ts +25 -0
- package/dist/components/NumberInput.svelte +255 -0
- package/dist/components/NumberInput.svelte.d.ts +68 -0
- package/dist/components/Pagination.svelte +169 -0
- package/dist/components/Pagination.svelte.d.ts +50 -0
- package/dist/components/Progress.svelte +65 -0
- package/dist/components/Progress.svelte.d.ts +28 -0
- package/dist/components/RadialProgress.svelte +48 -0
- package/dist/components/RadialProgress.svelte.d.ts +20 -0
- package/dist/components/Radio.svelte +50 -0
- package/dist/components/Radio.svelte.d.ts +28 -0
- package/dist/components/Range.svelte +53 -0
- package/dist/components/Range.svelte.d.ts +26 -0
- package/dist/components/Rating.svelte +90 -0
- package/dist/components/Rating.svelte.d.ts +41 -0
- package/dist/components/Select.svelte +338 -0
- package/dist/components/Select.svelte.d.ts +74 -0
- package/dist/components/Sidebar.svelte +100 -0
- package/dist/components/Sidebar.svelte.d.ts +54 -0
- package/dist/components/Skeleton.svelte +40 -0
- package/dist/components/Skeleton.svelte.d.ts +18 -0
- package/dist/components/Stat.svelte +71 -0
- package/dist/components/Stat.svelte.d.ts +35 -0
- package/dist/components/Stats.svelte +38 -0
- package/dist/components/Stats.svelte.d.ts +22 -0
- package/dist/components/Steps.svelte +204 -0
- package/dist/components/Steps.svelte.d.ts +66 -0
- package/dist/components/Subtitle.svelte +44 -0
- package/dist/components/Subtitle.svelte.d.ts +26 -0
- package/dist/components/Swatch.svelte +61 -0
- package/dist/components/Swatch.svelte.d.ts +27 -0
- package/dist/components/Switch.svelte +105 -0
- package/dist/components/Switch.svelte.d.ts +44 -0
- package/dist/components/Table.svelte +243 -0
- package/dist/components/Table.svelte.d.ts +121 -0
- package/dist/components/Tabs.svelte +142 -0
- package/dist/components/Tabs.svelte.d.ts +80 -0
- package/dist/components/Text.svelte +43 -0
- package/dist/components/Text.svelte.d.ts +25 -0
- package/dist/components/Textarea.svelte +76 -0
- package/dist/components/Textarea.svelte.d.ts +39 -0
- package/dist/components/Title.svelte +46 -0
- package/dist/components/Title.svelte.d.ts +29 -0
- package/dist/components/Toast.svelte +154 -0
- package/dist/components/Toast.svelte.d.ts +49 -0
- package/dist/components/Toggle.svelte +48 -0
- package/dist/components/Toggle.svelte.d.ts +25 -0
- package/dist/components/Tooltip.svelte +70 -0
- package/dist/components/Tooltip.svelte.d.ts +34 -0
- package/dist/components/WindowFrame.svelte +53 -0
- package/dist/components/WindowFrame.svelte.d.ts +24 -0
- package/dist/components/accordion-context.d.ts +8 -0
- package/dist/components/accordion-context.js +25 -0
- package/dist/components/color.d.ts +39 -0
- package/dist/components/color.js +92 -0
- package/dist/components/data-handler.svelte.d.ts +362 -0
- package/dist/components/data-handler.svelte.js +690 -0
- package/dist/components/file-icons.d.ts +25 -0
- package/dist/components/file-icons.js +46 -0
- package/dist/family-types.d.ts +45 -0
- package/dist/family-types.js +73 -0
- package/dist/generated/classes.d.ts +17 -0
- package/dist/generated/classes.js +2511 -0
- package/dist/generated/components.d.ts +39 -0
- package/dist/generated/components.js +28666 -0
- package/dist/generated/registry.d.ts +35 -0
- package/dist/generated/registry.js +2658 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +99 -0
- package/dist/sepale-types.d.ts +8 -0
- package/dist/sepale-types.js +200 -0
- package/dist/theme.d.ts +123 -0
- package/dist/theme.js +226 -0
- package/dist/variants.d.ts +124 -0
- package/dist/variants.js +70 -0
- package/dist/vendor/air-datepicker/LICENSE.md +21 -0
- package/dist/vendor/air-datepicker/README.md +19 -0
- package/dist/vendor/air-datepicker/buttonPresets.d.ts +13 -0
- package/dist/vendor/air-datepicker/buttonPresets.js +12 -0
- package/dist/vendor/air-datepicker/consts.d.ts +18 -0
- package/dist/vendor/air-datepicker/consts.js +35 -0
- package/dist/vendor/air-datepicker/datepicker.d.ts +289 -0
- package/dist/vendor/air-datepicker/datepicker.js +1435 -0
- package/dist/vendor/air-datepicker/datepickerBody.d.ts +46 -0
- package/dist/vendor/air-datepicker/datepickerBody.js +386 -0
- package/dist/vendor/air-datepicker/datepickerButtons.d.ts +25 -0
- package/dist/vendor/air-datepicker/datepickerButtons.js +85 -0
- package/dist/vendor/air-datepicker/datepickerCell.d.ts +35 -0
- package/dist/vendor/air-datepicker/datepickerCell.js +297 -0
- package/dist/vendor/air-datepicker/datepickerKeyboard.d.ts +26 -0
- package/dist/vendor/air-datepicker/datepickerKeyboard.js +207 -0
- package/dist/vendor/air-datepicker/datepickerNav.d.ts +31 -0
- package/dist/vendor/air-datepicker/datepickerNav.js +200 -0
- package/dist/vendor/air-datepicker/datepickerTime.d.ts +60 -0
- package/dist/vendor/air-datepicker/datepickerTime.js +276 -0
- package/dist/vendor/air-datepicker/defaults.d.ts +65 -0
- package/dist/vendor/air-datepicker/defaults.js +79 -0
- package/dist/vendor/air-datepicker/index.d.ts +168 -0
- package/dist/vendor/air-datepicker/index.js +3 -0
- package/dist/vendor/air-datepicker/locale/ar.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/ar.js +14 -0
- package/dist/vendor/air-datepicker/locale/bg.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/bg.js +14 -0
- package/dist/vendor/air-datepicker/locale/ca.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/ca.js +14 -0
- package/dist/vendor/air-datepicker/locale/cs.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/cs.js +14 -0
- package/dist/vendor/air-datepicker/locale/da.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/da.js +14 -0
- package/dist/vendor/air-datepicker/locale/de.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/de.js +14 -0
- package/dist/vendor/air-datepicker/locale/el.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/el.js +14 -0
- package/dist/vendor/air-datepicker/locale/en.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/en.js +14 -0
- package/dist/vendor/air-datepicker/locale/es.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/es.js +14 -0
- package/dist/vendor/air-datepicker/locale/eu.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/eu.js +14 -0
- package/dist/vendor/air-datepicker/locale/fi.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/fi.js +14 -0
- package/dist/vendor/air-datepicker/locale/fr.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/fr.js +14 -0
- package/dist/vendor/air-datepicker/locale/hr.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/hr.js +14 -0
- package/dist/vendor/air-datepicker/locale/hu.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/hu.js +14 -0
- package/dist/vendor/air-datepicker/locale/id.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/id.js +14 -0
- package/dist/vendor/air-datepicker/locale/it.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/it.js +14 -0
- package/dist/vendor/air-datepicker/locale/ja.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/ja.js +14 -0
- package/dist/vendor/air-datepicker/locale/ko.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/ko.js +14 -0
- package/dist/vendor/air-datepicker/locale/nb.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/nb.js +14 -0
- package/dist/vendor/air-datepicker/locale/nl.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/nl.js +14 -0
- package/dist/vendor/air-datepicker/locale/pl.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/pl.js +14 -0
- package/dist/vendor/air-datepicker/locale/pt-BR.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/pt-BR.js +14 -0
- package/dist/vendor/air-datepicker/locale/pt.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/pt.js +14 -0
- package/dist/vendor/air-datepicker/locale/ro.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/ro.js +14 -0
- package/dist/vendor/air-datepicker/locale/ru.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/ru.js +14 -0
- package/dist/vendor/air-datepicker/locale/si.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/si.js +14 -0
- package/dist/vendor/air-datepicker/locale/sk.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/sk.js +14 -0
- package/dist/vendor/air-datepicker/locale/sl.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/sl.js +14 -0
- package/dist/vendor/air-datepicker/locale/sv.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/sv.js +14 -0
- package/dist/vendor/air-datepicker/locale/th.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/th.js +14 -0
- package/dist/vendor/air-datepicker/locale/tr.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/tr.js +16 -0
- package/dist/vendor/air-datepicker/locale/uk.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/uk.js +14 -0
- package/dist/vendor/air-datepicker/locale/zh.d.ts +4 -0
- package/dist/vendor/air-datepicker/locale/zh.js +14 -0
- package/dist/vendor/air-datepicker/typedefs.d.ts +3 -0
- package/dist/vendor/air-datepicker/typedefs.js +15 -0
- package/dist/vendor/air-datepicker/utils.d.ts +155 -0
- package/dist/vendor/air-datepicker/utils.js +395 -0
- package/dist/vendor/air-datepicker/withEvents.d.ts +1 -0
- package/dist/vendor/air-datepicker/withEvents.js +39 -0
- package/package.json +44 -3
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
/** What .select is made of, classified. The props follow the
|
|
3
|
+
families the project registers (variants.ts, ADR 0015). */
|
|
4
|
+
export const PREFIX = 'select';
|
|
5
|
+
|
|
6
|
+
export const AXES = {
|
|
7
|
+
color: ['primary', 'secondary', 'accent', 'neutral', 'info', 'success', 'warning', 'error'],
|
|
8
|
+
size: ['xs', 'sm', 'md', 'lg', 'xl'],
|
|
9
|
+
variant: ['ghost']
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
export const FLAGS = {} as const;
|
|
13
|
+
export const PARTS = [] as const;
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<script lang="ts">
|
|
17
|
+
/**
|
|
18
|
+
* A choice among options. The options are written as children, or given as
|
|
19
|
+
* data (`options`) — objects read through `optionvalue` and `optionname`.
|
|
20
|
+
*
|
|
21
|
+
* One choice is a native `<select>`. Several (`multiple`) is a .select frame
|
|
22
|
+
* that opens a list of checkable rows, because a native multi-select is a
|
|
23
|
+
* tall box nobody knows how to use; a hidden native `<select multiple>`
|
|
24
|
+
* still carries the value into the form and its validation.
|
|
25
|
+
*/
|
|
26
|
+
import type { Snippet } from 'svelte';
|
|
27
|
+
import type { HTMLSelectAttributes } from 'svelte/elements';
|
|
28
|
+
import { applyAxes, cx, type AxisProps } from '../variants.js';
|
|
29
|
+
|
|
30
|
+
// `size` is ours — the HTML attribute of the same name is a character count
|
|
31
|
+
// our CSS overrides anyway.
|
|
32
|
+
interface Props
|
|
33
|
+
extends AxisProps<typeof AXES, typeof FLAGS, typeof PREFIX>,
|
|
34
|
+
Omit<HTMLSelectAttributes, 'size' | 'color' | 'value' | 'multiple'> {
|
|
35
|
+
/**
|
|
36
|
+
* Colour the field by its own validity and reveal `hint` once the
|
|
37
|
+
* browser marks it invalid. The CSS drives this off `:user-invalid`,
|
|
38
|
+
* so it only fires after the visitor has actually had a go.
|
|
39
|
+
*/
|
|
40
|
+
validator?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Shown under the field when it is invalid. It has to be the field's
|
|
43
|
+
* next sibling for the CSS to reach it, which is the whole reason this
|
|
44
|
+
* is a prop and not something you write yourself. Without it, the
|
|
45
|
+
* message is the browser's own.
|
|
46
|
+
*/
|
|
47
|
+
hint?: Snippet;
|
|
48
|
+
/**
|
|
49
|
+
* An error from outside (the server said no): marks the field invalid and
|
|
50
|
+
* shows this, for as long as it is given. The parent owns it — it knows
|
|
51
|
+
* the value and is the one able to test it — so the field never clears it.
|
|
52
|
+
*/
|
|
53
|
+
error?: string | null;
|
|
54
|
+
/** The message of the last check, `false` when the field passed. Bindable. */
|
|
55
|
+
invalid?: string | false;
|
|
56
|
+
/** The options, as data. Written after any `children`. */
|
|
57
|
+
options?: any[];
|
|
58
|
+
/** The key of an option object holding its value. Default `value`. */
|
|
59
|
+
optionvalue?: string;
|
|
60
|
+
/** The key of an option object holding its text. Default `name`. */
|
|
61
|
+
optionname?: string;
|
|
62
|
+
/** How one option is drawn. Defaults to its `optionname` text. */
|
|
63
|
+
option?: Snippet<[any]>;
|
|
64
|
+
/** Shown while nothing is chosen, which is shown empty without it. */
|
|
65
|
+
placeholder?: string;
|
|
66
|
+
/** Nothing can be chosen back, to clear the field. */
|
|
67
|
+
nullable?: boolean;
|
|
68
|
+
/** Several choices: `value` is then an array. */
|
|
69
|
+
multiple?: boolean;
|
|
70
|
+
/** The text of a multiple field with several choices. Default `N selected`. */
|
|
71
|
+
summary?: (chosen: any[]) => string;
|
|
72
|
+
/** Called with the new value after every change. */
|
|
73
|
+
onValue?: (value: any) => void;
|
|
74
|
+
/** The native `<select>`. Bindable. */
|
|
75
|
+
element?: HTMLSelectElement;
|
|
76
|
+
class?: string;
|
|
77
|
+
value?: any;
|
|
78
|
+
children?: Snippet;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// The axes are deliberately NOT destructured: they travel in `axes` and are
|
|
82
|
+
// resolved by name, so an axis a family drops changes nothing down here.
|
|
83
|
+
let {
|
|
84
|
+
validator = false,
|
|
85
|
+
hint,
|
|
86
|
+
error = null,
|
|
87
|
+
invalid = $bindable(false),
|
|
88
|
+
options = [],
|
|
89
|
+
optionvalue = 'value',
|
|
90
|
+
optionname = 'name',
|
|
91
|
+
option,
|
|
92
|
+
placeholder,
|
|
93
|
+
nullable = false,
|
|
94
|
+
multiple = false,
|
|
95
|
+
summary = (chosen: any[]) => `${chosen.length} selected`,
|
|
96
|
+
onValue,
|
|
97
|
+
element = $bindable(),
|
|
98
|
+
value = $bindable(),
|
|
99
|
+
class: klass = '',
|
|
100
|
+
disabled = false,
|
|
101
|
+
children,
|
|
102
|
+
onchange,
|
|
103
|
+
onblur,
|
|
104
|
+
...axes
|
|
105
|
+
}: Props = $props();
|
|
106
|
+
|
|
107
|
+
let applied = $derived(applyAxes(PREFIX, AXES, FLAGS, axes));
|
|
108
|
+
|
|
109
|
+
const uid = $props.id();
|
|
110
|
+
|
|
111
|
+
/** What is shown under the field. A disabled field shows nothing. */
|
|
112
|
+
let message = $derived(disabled ? '' : error || (typeof invalid === 'string' ? invalid : ''));
|
|
113
|
+
|
|
114
|
+
/* An error from outside is the field's validity too: a form holding it
|
|
115
|
+
does not submit. */
|
|
116
|
+
$effect(() => {
|
|
117
|
+
element?.setCustomValidity(disabled || !error ? '' : error);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
let classes = $derived(cx(PREFIX, applied.classes, (validator || !!message) && 'validator', klass));
|
|
121
|
+
|
|
122
|
+
const keyOf = (o: any) => (o !== null && typeof o === 'object' ? o[optionvalue] : o);
|
|
123
|
+
const nameOf = (o: any) => (o !== null && typeof o === 'object' ? o[optionname] : `${o}`);
|
|
124
|
+
|
|
125
|
+
/** Check the field now and show the browser's message if it fails. */
|
|
126
|
+
export function isValid(): boolean {
|
|
127
|
+
if (!element || disabled) return !error;
|
|
128
|
+
invalid = element.validity.valid ? false : element.validationMessage;
|
|
129
|
+
return !error && !invalid;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Open the list of a multiple field. */
|
|
133
|
+
export function show() {
|
|
134
|
+
if (multiple && !disabled) open = true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function changed() {
|
|
138
|
+
if (invalid) isValid();
|
|
139
|
+
onValue?.(value);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function handleChange(e: Event & { currentTarget: EventTarget & HTMLSelectElement }) {
|
|
143
|
+
changed();
|
|
144
|
+
onchange?.(e);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function handleBlur(e: FocusEvent & { currentTarget: EventTarget & HTMLSelectElement }) {
|
|
148
|
+
if (validator) isValid();
|
|
149
|
+
onblur?.(e);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* ── Multiple ─────────────────────────────────────────────────────── */
|
|
153
|
+
|
|
154
|
+
let open = $state(false);
|
|
155
|
+
/** Keyboard position in the list; -1 is the frame itself. */
|
|
156
|
+
let active = $state(-1);
|
|
157
|
+
let frame: HTMLDivElement | undefined = $state();
|
|
158
|
+
|
|
159
|
+
let chosen = $derived(Array.isArray(value) ? value : []);
|
|
160
|
+
let chosenOptions = $derived(options.filter((o) => chosen.includes(keyOf(o))));
|
|
161
|
+
|
|
162
|
+
let text = $derived(
|
|
163
|
+
chosenOptions.length === 0
|
|
164
|
+
? (placeholder ?? '')
|
|
165
|
+
: chosenOptions.length === 1
|
|
166
|
+
? nameOf(chosenOptions[0])
|
|
167
|
+
: summary(chosenOptions)
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
/** Rows the keyboard walks through: the clearing row, then the options. */
|
|
171
|
+
let rows = $derived(options.length + (nullable ? 1 : 0));
|
|
172
|
+
|
|
173
|
+
function toggle(o: any) {
|
|
174
|
+
const k = keyOf(o);
|
|
175
|
+
value = chosen.includes(k) ? chosen.filter((v: any) => v !== k) : [...chosen, k];
|
|
176
|
+
changed();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function reset() {
|
|
180
|
+
value = [];
|
|
181
|
+
changed();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function activate(i: number) {
|
|
185
|
+
if (nullable && i === 0) reset();
|
|
186
|
+
else toggle(options[i - (nullable ? 1 : 0)]);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function close() {
|
|
190
|
+
open = false;
|
|
191
|
+
active = -1;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function frameKeydown(e: KeyboardEvent) {
|
|
195
|
+
if (disabled) return;
|
|
196
|
+
if (e.key === 'ArrowDown') {
|
|
197
|
+
e.preventDefault();
|
|
198
|
+
if (!open) open = true;
|
|
199
|
+
else if (rows) active = (active + 1) % rows;
|
|
200
|
+
} else if (e.key === 'ArrowUp' && open && rows) {
|
|
201
|
+
e.preventDefault();
|
|
202
|
+
active = active <= 0 ? rows - 1 : active - 1;
|
|
203
|
+
} else if (e.key === 'Enter' || e.key === ' ') {
|
|
204
|
+
e.preventDefault();
|
|
205
|
+
if (!open) open = true;
|
|
206
|
+
else if (active >= 0) activate(active);
|
|
207
|
+
} else if (e.key === 'Escape' && open) {
|
|
208
|
+
e.preventDefault();
|
|
209
|
+
close();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function frameClick(e: MouseEvent) {
|
|
214
|
+
// A row already acted on mousedown; its click must not close the list.
|
|
215
|
+
if ((e.target as Element).closest('.list-suggestions') || disabled) return;
|
|
216
|
+
if (open) close();
|
|
217
|
+
else open = true;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function frameFocusout(e: FocusEvent) {
|
|
221
|
+
// Focus moving inside the frame (the hidden select) is not leaving it.
|
|
222
|
+
if (frame?.contains(e.relatedTarget as Node | null)) return;
|
|
223
|
+
close();
|
|
224
|
+
if (validator) isValid();
|
|
225
|
+
}
|
|
226
|
+
</script>
|
|
227
|
+
|
|
228
|
+
{#if multiple}
|
|
229
|
+
<!-- The frame is the control: it takes the focus and the keys. A row
|
|
230
|
+
acts on mousedown and keeps the focus on the frame, so picking never
|
|
231
|
+
closes the list. -->
|
|
232
|
+
<div
|
|
233
|
+
bind:this={frame}
|
|
234
|
+
class={classes}
|
|
235
|
+
role="combobox"
|
|
236
|
+
tabindex={disabled ? -1 : 0}
|
|
237
|
+
aria-expanded={open}
|
|
238
|
+
aria-haspopup="listbox"
|
|
239
|
+
aria-controls="{uid}-list"
|
|
240
|
+
aria-disabled={disabled || undefined}
|
|
241
|
+
aria-invalid={message ? 'true' : undefined}
|
|
242
|
+
aria-activedescendant={open && active >= 0 ? `${uid}-${active}` : undefined}
|
|
243
|
+
onclick={frameClick}
|
|
244
|
+
onkeydown={frameKeydown}
|
|
245
|
+
onfocusout={frameFocusout}
|
|
246
|
+
>
|
|
247
|
+
<span style="overflow: hidden; text-overflow: ellipsis; flex: 1; opacity: {chosenOptions.length ? 1 : 0.6};"
|
|
248
|
+
>{text}</span
|
|
249
|
+
>
|
|
250
|
+
|
|
251
|
+
<!-- Carries the value into the form, and `required` into validation. -->
|
|
252
|
+
<select
|
|
253
|
+
{...applied.rest}
|
|
254
|
+
bind:this={element}
|
|
255
|
+
bind:value
|
|
256
|
+
{disabled}
|
|
257
|
+
multiple
|
|
258
|
+
tabindex="-1"
|
|
259
|
+
aria-hidden="true"
|
|
260
|
+
style="position: absolute; inset: 0; opacity: 0; pointer-events: none;"
|
|
261
|
+
>
|
|
262
|
+
{#each options as o (keyOf(o))}
|
|
263
|
+
<option value={keyOf(o)}>{nameOf(o)}</option>
|
|
264
|
+
{/each}
|
|
265
|
+
</select>
|
|
266
|
+
|
|
267
|
+
{#if open}
|
|
268
|
+
<ul id="{uid}-list" class="list list-suggestions" role="listbox" aria-multiselectable="true">
|
|
269
|
+
{#if nullable}
|
|
270
|
+
<li
|
|
271
|
+
id="{uid}-0"
|
|
272
|
+
class="list-row"
|
|
273
|
+
role="option"
|
|
274
|
+
aria-selected={active === 0}
|
|
275
|
+
onmousedown={(e) => {
|
|
276
|
+
e.preventDefault();
|
|
277
|
+
reset();
|
|
278
|
+
}}
|
|
279
|
+
>
|
|
280
|
+
{placeholder ?? '—'}
|
|
281
|
+
</li>
|
|
282
|
+
{/if}
|
|
283
|
+
{#each options as o, i (keyOf(o))}
|
|
284
|
+
{@const row = i + (nullable ? 1 : 0)}
|
|
285
|
+
<li
|
|
286
|
+
id="{uid}-{row}"
|
|
287
|
+
class="list-row"
|
|
288
|
+
role="option"
|
|
289
|
+
aria-selected={active === row}
|
|
290
|
+
aria-checked={chosen.includes(keyOf(o))}
|
|
291
|
+
onmousedown={(e) => {
|
|
292
|
+
e.preventDefault();
|
|
293
|
+
toggle(o);
|
|
294
|
+
}}
|
|
295
|
+
>
|
|
296
|
+
<input
|
|
297
|
+
type="checkbox"
|
|
298
|
+
class="checkbox checkbox-sm"
|
|
299
|
+
checked={chosen.includes(keyOf(o))}
|
|
300
|
+
tabindex="-1"
|
|
301
|
+
aria-hidden="true"
|
|
302
|
+
style="pointer-events: none;"
|
|
303
|
+
/>
|
|
304
|
+
{#if option}{@render option(o)}{:else}{nameOf(o)}{/if}
|
|
305
|
+
</li>
|
|
306
|
+
{/each}
|
|
307
|
+
</ul>
|
|
308
|
+
{/if}
|
|
309
|
+
</div>
|
|
310
|
+
{:else}
|
|
311
|
+
<!-- Ours first: what the caller writes in the spread still wins. -->
|
|
312
|
+
<select
|
|
313
|
+
aria-invalid={message ? 'true' : undefined}
|
|
314
|
+
{...applied.rest}
|
|
315
|
+
bind:this={element}
|
|
316
|
+
class={classes}
|
|
317
|
+
bind:value
|
|
318
|
+
{disabled}
|
|
319
|
+
onchange={handleChange}
|
|
320
|
+
onblur={handleBlur}
|
|
321
|
+
>
|
|
322
|
+
<!-- Always there : without it, the browser shows the first option as chosen while the value stays undefined -->
|
|
323
|
+
<option value={undefined} disabled={!nullable} hidden={!nullable}>{placeholder ?? ''}</option>
|
|
324
|
+
{@render children?.()}
|
|
325
|
+
{#each options as o (keyOf(o))}
|
|
326
|
+
<option value={keyOf(o)}>{#if option}{@render option(o)}{:else}{nameOf(o)}{/if}</option>
|
|
327
|
+
{/each}
|
|
328
|
+
</select>
|
|
329
|
+
{/if}
|
|
330
|
+
<!-- An error from outside first, then the caller's hint, then the browser's
|
|
331
|
+
own message. -->
|
|
332
|
+
{#if error && !disabled}
|
|
333
|
+
<p class="validator-hint">{error}</p>
|
|
334
|
+
{:else if hint}
|
|
335
|
+
<p class="validator-hint">{@render hint()}</p>
|
|
336
|
+
{:else if message}
|
|
337
|
+
<p class="validator-hint">{message}</p>
|
|
338
|
+
{/if}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** What .select is made of, classified. The props follow the
|
|
2
|
+
families the project registers (variants.ts, ADR 0015). */
|
|
3
|
+
export declare const PREFIX = "select";
|
|
4
|
+
export declare const AXES: {
|
|
5
|
+
readonly color: readonly ["primary", "secondary", "accent", "neutral", "info", "success", "warning", "error"];
|
|
6
|
+
readonly size: readonly ["xs", "sm", "md", "lg", "xl"];
|
|
7
|
+
readonly variant: readonly ["ghost"];
|
|
8
|
+
};
|
|
9
|
+
export declare const FLAGS: {};
|
|
10
|
+
export declare const PARTS: readonly [];
|
|
11
|
+
/**
|
|
12
|
+
* A choice among options. The options are written as children, or given as
|
|
13
|
+
* data (`options`) — objects read through `optionvalue` and `optionname`.
|
|
14
|
+
*
|
|
15
|
+
* One choice is a native `<select>`. Several (`multiple`) is a .select frame
|
|
16
|
+
* that opens a list of checkable rows, because a native multi-select is a
|
|
17
|
+
* tall box nobody knows how to use; a hidden native `<select multiple>`
|
|
18
|
+
* still carries the value into the form and its validation.
|
|
19
|
+
*/
|
|
20
|
+
import type { Snippet } from 'svelte';
|
|
21
|
+
import type { HTMLSelectAttributes } from 'svelte/elements';
|
|
22
|
+
import { type AxisProps } from '../variants.js';
|
|
23
|
+
interface Props extends AxisProps<typeof AXES, typeof FLAGS, typeof PREFIX>, Omit<HTMLSelectAttributes, 'size' | 'color' | 'value' | 'multiple'> {
|
|
24
|
+
/**
|
|
25
|
+
* Colour the field by its own validity and reveal `hint` once the
|
|
26
|
+
* browser marks it invalid. The CSS drives this off `:user-invalid`,
|
|
27
|
+
* so it only fires after the visitor has actually had a go.
|
|
28
|
+
*/
|
|
29
|
+
validator?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Shown under the field when it is invalid. It has to be the field's
|
|
32
|
+
* next sibling for the CSS to reach it, which is the whole reason this
|
|
33
|
+
* is a prop and not something you write yourself. Without it, the
|
|
34
|
+
* message is the browser's own.
|
|
35
|
+
*/
|
|
36
|
+
hint?: Snippet;
|
|
37
|
+
/**
|
|
38
|
+
* An error from outside (the server said no): marks the field invalid and
|
|
39
|
+
* shows this, for as long as it is given. The parent owns it — it knows
|
|
40
|
+
* the value and is the one able to test it — so the field never clears it.
|
|
41
|
+
*/
|
|
42
|
+
error?: string | null;
|
|
43
|
+
/** The message of the last check, `false` when the field passed. Bindable. */
|
|
44
|
+
invalid?: string | false;
|
|
45
|
+
/** The options, as data. Written after any `children`. */
|
|
46
|
+
options?: any[];
|
|
47
|
+
/** The key of an option object holding its value. Default `value`. */
|
|
48
|
+
optionvalue?: string;
|
|
49
|
+
/** The key of an option object holding its text. Default `name`. */
|
|
50
|
+
optionname?: string;
|
|
51
|
+
/** How one option is drawn. Defaults to its `optionname` text. */
|
|
52
|
+
option?: Snippet<[any]>;
|
|
53
|
+
/** Shown while nothing is chosen, which is shown empty without it. */
|
|
54
|
+
placeholder?: string;
|
|
55
|
+
/** Nothing can be chosen back, to clear the field. */
|
|
56
|
+
nullable?: boolean;
|
|
57
|
+
/** Several choices: `value` is then an array. */
|
|
58
|
+
multiple?: boolean;
|
|
59
|
+
/** The text of a multiple field with several choices. Default `N selected`. */
|
|
60
|
+
summary?: (chosen: any[]) => string;
|
|
61
|
+
/** Called with the new value after every change. */
|
|
62
|
+
onValue?: (value: any) => void;
|
|
63
|
+
/** The native `<select>`. Bindable. */
|
|
64
|
+
element?: HTMLSelectElement;
|
|
65
|
+
class?: string;
|
|
66
|
+
value?: any;
|
|
67
|
+
children?: Snippet;
|
|
68
|
+
}
|
|
69
|
+
declare const Select: import("svelte").Component<Props, {
|
|
70
|
+
isValid: () => boolean;
|
|
71
|
+
show: () => void;
|
|
72
|
+
}, "value" | "invalid" | "element">;
|
|
73
|
+
type Select = ReturnType<typeof Select>;
|
|
74
|
+
export default Select;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
/** What .sidebar is made of, classified. The props follow the
|
|
3
|
+
families the project registers (variants.ts, ADR 0015).
|
|
4
|
+
|
|
5
|
+
`.sidebar-layout` is the row it may sit in: written by hand around the
|
|
6
|
+
page, never by the component, so it is a PART too. */
|
|
7
|
+
export const PREFIX = 'sidebar';
|
|
8
|
+
|
|
9
|
+
export const AXES = {
|
|
10
|
+
size: ['xs', 'sm', 'md', 'lg', 'xl'],
|
|
11
|
+
/* The page's side it stands on. The start by default. */
|
|
12
|
+
side: ['end']
|
|
13
|
+
} as const;
|
|
14
|
+
|
|
15
|
+
export const FLAGS = {} as const;
|
|
16
|
+
export const PARTS = ['head', 'body', 'foot', 'toggle', 'collapsed', 'keep', 'layout'] as const;
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
/**
|
|
21
|
+
* An app's side column — a brand, a menu, an account — that folds to a
|
|
22
|
+
* rail. In the flow, unlike a Drawer: the page beside it narrows or
|
|
23
|
+
* widens, it is never covered.
|
|
24
|
+
*
|
|
25
|
+
* `collapsed` is bindable. The toggle sits in the head, after `head`;
|
|
26
|
+
* folded, only the toggle stays (and anything marked `.sidebar-keep`).
|
|
27
|
+
*/
|
|
28
|
+
import type { Snippet } from 'svelte';
|
|
29
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
30
|
+
import { applyAxes, cx, type AxisProps } from '../variants.js';
|
|
31
|
+
|
|
32
|
+
interface Props extends AxisProps<typeof AXES, typeof FLAGS, typeof PREFIX>, Omit<HTMLAttributes<HTMLElement>, 'children'> {
|
|
33
|
+
/** Folded to a rail. Bindable. */
|
|
34
|
+
collapsed?: boolean;
|
|
35
|
+
/** The top of the column: a brand, a picker. The toggle follows it. */
|
|
36
|
+
head?: Snippet<[{ collapsed: boolean }]>;
|
|
37
|
+
/** The bottom of the column: an account, a setting. */
|
|
38
|
+
foot?: Snippet<[{ collapsed: boolean }]>;
|
|
39
|
+
/** Hide the toggle: the app folds it some other way. */
|
|
40
|
+
noToggle?: boolean;
|
|
41
|
+
/** The toggle's accessible name, open and folded. */
|
|
42
|
+
toggleLabel?: { open: string; collapsed: string };
|
|
43
|
+
/** After every fold or unfold. */
|
|
44
|
+
onToggle?: (collapsed: boolean) => void;
|
|
45
|
+
class?: string;
|
|
46
|
+
/** The body: usually a Menu. */
|
|
47
|
+
children?: Snippet<[{ collapsed: boolean }]>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// The axes are deliberately NOT destructured: they travel in `axes` and are
|
|
51
|
+
// resolved by name, so an axis a family drops changes nothing down here.
|
|
52
|
+
let {
|
|
53
|
+
collapsed = $bindable(false),
|
|
54
|
+
head,
|
|
55
|
+
foot,
|
|
56
|
+
noToggle = false,
|
|
57
|
+
toggleLabel = { open: 'Collapse the sidebar', collapsed: 'Expand the sidebar' },
|
|
58
|
+
onToggle,
|
|
59
|
+
class: klass = '',
|
|
60
|
+
children,
|
|
61
|
+
...axes
|
|
62
|
+
}: Props = $props();
|
|
63
|
+
|
|
64
|
+
let applied = $derived(applyAxes(PREFIX, AXES, FLAGS, axes));
|
|
65
|
+
let classes = $derived(cx(PREFIX, applied.classes, collapsed && `${PREFIX}-collapsed`, klass));
|
|
66
|
+
|
|
67
|
+
const uid = $props.id();
|
|
68
|
+
|
|
69
|
+
/** Fold or unfold it. */
|
|
70
|
+
export function toggle(value = !collapsed) {
|
|
71
|
+
if (value === collapsed) return;
|
|
72
|
+
collapsed = value;
|
|
73
|
+
onToggle?.(value);
|
|
74
|
+
}
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<aside {...applied.rest} class={classes}>
|
|
78
|
+
<div class="{PREFIX}-head">
|
|
79
|
+
{@render head?.({ collapsed })}
|
|
80
|
+
{#if !noToggle}
|
|
81
|
+
<button
|
|
82
|
+
type="button"
|
|
83
|
+
class="{PREFIX}-toggle"
|
|
84
|
+
aria-expanded={!collapsed}
|
|
85
|
+
aria-controls="{uid}-body"
|
|
86
|
+
aria-label={collapsed ? toggleLabel.collapsed : toggleLabel.open}
|
|
87
|
+
title={collapsed ? toggleLabel.collapsed : toggleLabel.open}
|
|
88
|
+
onclick={() => toggle()}
|
|
89
|
+
>
|
|
90
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="3" /><path d="M9 4v16M15.5 10l-2 2 2 2" /></svg>
|
|
91
|
+
</button>
|
|
92
|
+
{/if}
|
|
93
|
+
</div>
|
|
94
|
+
<div class="{PREFIX}-body" id="{uid}-body" inert={collapsed}>
|
|
95
|
+
{@render children?.({ collapsed })}
|
|
96
|
+
</div>
|
|
97
|
+
{#if foot}
|
|
98
|
+
<div class="{PREFIX}-foot" inert={collapsed}>{@render foot({ collapsed })}</div>
|
|
99
|
+
{/if}
|
|
100
|
+
</aside>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** What .sidebar is made of, classified. The props follow the
|
|
2
|
+
families the project registers (variants.ts, ADR 0015).
|
|
3
|
+
|
|
4
|
+
`.sidebar-layout` is the row it may sit in: written by hand around the
|
|
5
|
+
page, never by the component, so it is a PART too. */
|
|
6
|
+
export declare const PREFIX = "sidebar";
|
|
7
|
+
export declare const AXES: {
|
|
8
|
+
readonly size: readonly ["xs", "sm", "md", "lg", "xl"];
|
|
9
|
+
readonly side: readonly ["end"];
|
|
10
|
+
};
|
|
11
|
+
export declare const FLAGS: {};
|
|
12
|
+
export declare const PARTS: readonly ["head", "body", "foot", "toggle", "collapsed", "keep", "layout"];
|
|
13
|
+
/**
|
|
14
|
+
* An app's side column — a brand, a menu, an account — that folds to a
|
|
15
|
+
* rail. In the flow, unlike a Drawer: the page beside it narrows or
|
|
16
|
+
* widens, it is never covered.
|
|
17
|
+
*
|
|
18
|
+
* `collapsed` is bindable. The toggle sits in the head, after `head`;
|
|
19
|
+
* folded, only the toggle stays (and anything marked `.sidebar-keep`).
|
|
20
|
+
*/
|
|
21
|
+
import type { Snippet } from 'svelte';
|
|
22
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
23
|
+
import { type AxisProps } from '../variants.js';
|
|
24
|
+
interface Props extends AxisProps<typeof AXES, typeof FLAGS, typeof PREFIX>, Omit<HTMLAttributes<HTMLElement>, 'children'> {
|
|
25
|
+
/** Folded to a rail. Bindable. */
|
|
26
|
+
collapsed?: boolean;
|
|
27
|
+
/** The top of the column: a brand, a picker. The toggle follows it. */
|
|
28
|
+
head?: Snippet<[{
|
|
29
|
+
collapsed: boolean;
|
|
30
|
+
}]>;
|
|
31
|
+
/** The bottom of the column: an account, a setting. */
|
|
32
|
+
foot?: Snippet<[{
|
|
33
|
+
collapsed: boolean;
|
|
34
|
+
}]>;
|
|
35
|
+
/** Hide the toggle: the app folds it some other way. */
|
|
36
|
+
noToggle?: boolean;
|
|
37
|
+
/** The toggle's accessible name, open and folded. */
|
|
38
|
+
toggleLabel?: {
|
|
39
|
+
open: string;
|
|
40
|
+
collapsed: string;
|
|
41
|
+
};
|
|
42
|
+
/** After every fold or unfold. */
|
|
43
|
+
onToggle?: (collapsed: boolean) => void;
|
|
44
|
+
class?: string;
|
|
45
|
+
/** The body: usually a Menu. */
|
|
46
|
+
children?: Snippet<[{
|
|
47
|
+
collapsed: boolean;
|
|
48
|
+
}]>;
|
|
49
|
+
}
|
|
50
|
+
declare const Sidebar: import("svelte").Component<Props, {
|
|
51
|
+
toggle: (value?: boolean) => void;
|
|
52
|
+
}, "collapsed">;
|
|
53
|
+
type Sidebar = ReturnType<typeof Sidebar>;
|
|
54
|
+
export default Sidebar;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
/** What .skeleton is made of, classified. The props follow the
|
|
3
|
+
families the project registers (variants.ts, ADR 0015). */
|
|
4
|
+
export const PREFIX = 'skeleton';
|
|
5
|
+
|
|
6
|
+
export const AXES = {
|
|
7
|
+
/* A block by default; `text` makes it a line of type instead. */
|
|
8
|
+
variant: ['text']
|
|
9
|
+
} as const;
|
|
10
|
+
|
|
11
|
+
export const FLAGS = {} as const;
|
|
12
|
+
export const PARTS = [] as const;
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<script lang="ts">
|
|
16
|
+
import type { Snippet } from 'svelte';
|
|
17
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
18
|
+
import { applyAxes, cx, type AxisProps } from '../variants.js';
|
|
19
|
+
|
|
20
|
+
interface Props extends AxisProps<typeof AXES, typeof FLAGS, typeof PREFIX>, HTMLAttributes<HTMLDivElement> {
|
|
21
|
+
/** Repeat the placeholder this many times, stacked. */
|
|
22
|
+
lines?: number;
|
|
23
|
+
class?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// The axes are deliberately NOT destructured: they travel in `axes` and are
|
|
27
|
+
// resolved by name, so an axis a family drops changes nothing down here.
|
|
28
|
+
let {
|
|
29
|
+
lines = 1,
|
|
30
|
+
class: klass = '',
|
|
31
|
+
...axes
|
|
32
|
+
}: Props = $props();
|
|
33
|
+
|
|
34
|
+
let applied = $derived(applyAxes(PREFIX, AXES, FLAGS, axes));
|
|
35
|
+
let classes = $derived(cx(PREFIX, applied.classes, klass));
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
{#each { length: lines } as _, i (i)}
|
|
39
|
+
<div {...applied.rest} class={classes}></div>
|
|
40
|
+
{/each}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** What .skeleton is made of, classified. The props follow the
|
|
2
|
+
families the project registers (variants.ts, ADR 0015). */
|
|
3
|
+
export declare const PREFIX = "skeleton";
|
|
4
|
+
export declare const AXES: {
|
|
5
|
+
readonly variant: readonly ["text"];
|
|
6
|
+
};
|
|
7
|
+
export declare const FLAGS: {};
|
|
8
|
+
export declare const PARTS: readonly [];
|
|
9
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
10
|
+
import { type AxisProps } from '../variants.js';
|
|
11
|
+
interface Props extends AxisProps<typeof AXES, typeof FLAGS, typeof PREFIX>, HTMLAttributes<HTMLDivElement> {
|
|
12
|
+
/** Repeat the placeholder this many times, stacked. */
|
|
13
|
+
lines?: number;
|
|
14
|
+
class?: string;
|
|
15
|
+
}
|
|
16
|
+
declare const Skeleton: import("svelte").Component<Props, {}, "">;
|
|
17
|
+
type Skeleton = ReturnType<typeof Skeleton>;
|
|
18
|
+
export default Skeleton;
|