@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,44 @@
|
|
|
1
|
+
/** What .color-picker is made of, classified. The props follow the
|
|
2
|
+
families the project registers (variants.ts, ADR 0015). */
|
|
3
|
+
export declare const PREFIX = "color-picker";
|
|
4
|
+
export declare const AXES: {
|
|
5
|
+
readonly size: readonly ["xs", "sm", "md", "lg", "xl"];
|
|
6
|
+
};
|
|
7
|
+
export declare const FLAGS: {
|
|
8
|
+
readonly flat: "No box of its own: the host — a dropdown, a card — draws it.";
|
|
9
|
+
};
|
|
10
|
+
export declare const PARTS: readonly ["head", "preview", "value", "channel", "track", "presets"];
|
|
11
|
+
/**
|
|
12
|
+
* One colour, edited in OKLCH: lightness, chroma, hue, each a slider
|
|
13
|
+
* whose track is the gradient it moves along, plus the raw value for
|
|
14
|
+
* anything the sliders cannot say (`color-mix(…)`, a `var()`).
|
|
15
|
+
*
|
|
16
|
+
* A panel, not a popover: put it in a Dropdown to float it.
|
|
17
|
+
*
|
|
18
|
+
* The three numbers are state, seeded from `value` and then only written:
|
|
19
|
+
* reading them back from the colour on every drag goes through a lossy
|
|
20
|
+
* conversion, and moving the hue would nudge the lightness.
|
|
21
|
+
*/
|
|
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<HTMLDivElement>, 'onchange'> {
|
|
25
|
+
/** Any CSS colour. Bindable; written back as `oklch(…)`. */
|
|
26
|
+
value?: string;
|
|
27
|
+
/** Colours one click away, drawn as swatches. */
|
|
28
|
+
presets?: string[];
|
|
29
|
+
/** Hide the raw value field. */
|
|
30
|
+
noInput?: boolean;
|
|
31
|
+
/** The channels' accessible names. */
|
|
32
|
+
labels?: {
|
|
33
|
+
l?: string;
|
|
34
|
+
c?: string;
|
|
35
|
+
h?: string;
|
|
36
|
+
value?: string;
|
|
37
|
+
};
|
|
38
|
+
/** After every change. */
|
|
39
|
+
onChange?: (value: string) => void;
|
|
40
|
+
class?: string;
|
|
41
|
+
}
|
|
42
|
+
declare const ColorPicker: import("svelte").Component<Props, {}, "value">;
|
|
43
|
+
type ColorPicker = ReturnType<typeof ColorPicker>;
|
|
44
|
+
export default ColorPicker;
|
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
/** What .combobox is made of, classified. The props follow the
|
|
3
|
+
families the project registers (variants.ts, ADR 0015).
|
|
4
|
+
|
|
5
|
+
`.combobox-multiple` is a PART: the wrapper writes it from `multiple`. */
|
|
6
|
+
export const PREFIX = 'combobox';
|
|
7
|
+
|
|
8
|
+
export const AXES = {
|
|
9
|
+
size: ['xs', 'sm', 'md', 'lg', 'xl']
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
export const FLAGS = {} as const;
|
|
13
|
+
export const PARTS = ['option', 'multiple'] as const;
|
|
14
|
+
|
|
15
|
+
/** Where the options come from: a list, a function, or an address answering JSON. */
|
|
16
|
+
export type ComboboxSource =
|
|
17
|
+
| any[]
|
|
18
|
+
| ((query: string) => any[] | Promise<any[]>)
|
|
19
|
+
| string
|
|
20
|
+
| { uri: string | ((query: string) => string); options?: RequestInit | ((query: string) => RequestInit) };
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<script lang="ts">
|
|
24
|
+
/**
|
|
25
|
+
* A field whose value is looked up in a list of options while typing.
|
|
26
|
+
*
|
|
27
|
+
* **Strict** (default): the value is a picked option, never the typed
|
|
28
|
+
* text. A hidden `<select name>` carries it for a form, so the DOM says what
|
|
29
|
+
* was chosen. The field shows two things over time: the search being typed,
|
|
30
|
+
* and the label of the pick. Typing drops the pick; leaving a search
|
|
31
|
+
* unfinished brings the last pick back.
|
|
32
|
+
*
|
|
33
|
+
* **Free** (`strict={false}`): the value is the text — the options only
|
|
34
|
+
* complete it (autocompletion). The `<input>` itself carries `name`.
|
|
35
|
+
*
|
|
36
|
+
* **Multiple** (implies strict): the field shows a summary of the picks,
|
|
37
|
+
* the list stays open while ticking, and a hidden `<select multiple>`
|
|
38
|
+
* carries them. To collect free values as chips, see ChipsInput.
|
|
39
|
+
*
|
|
40
|
+
* Options come from a list (filtered here), a function of the query, or an
|
|
41
|
+
* address answering JSON (`then` reshapes the answer). The frame is the
|
|
42
|
+
* family's `.input`, the list its `.list-suggestions`.
|
|
43
|
+
*/
|
|
44
|
+
import { untrack, type Snippet } from 'svelte';
|
|
45
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
46
|
+
import { applyAxes, cx, type AxisProps } from '../variants.js';
|
|
47
|
+
|
|
48
|
+
interface Props extends AxisProps<typeof AXES, typeof FLAGS, typeof PREFIX>, Omit<HTMLInputAttributes, 'size' | 'value'> {
|
|
49
|
+
/** The options, or where to fetch them. */
|
|
50
|
+
options: ComboboxSource;
|
|
51
|
+
/** Reshape what a function or an address answered into the list. */
|
|
52
|
+
then?: (answer: any) => any[];
|
|
53
|
+
/** The text an option stands for: in the list, and in the field once picked. */
|
|
54
|
+
show?: (option: any) => string;
|
|
55
|
+
/** What identifies an option, and what the hidden select submits. Defaults to `id`, `value`, then the label. */
|
|
56
|
+
key?: (option: any) => string | number;
|
|
57
|
+
/** The value is a picked option (default), or the text (`false`). */
|
|
58
|
+
strict?: boolean;
|
|
59
|
+
/** Pick several. Implies strict. */
|
|
60
|
+
multiple?: boolean;
|
|
61
|
+
/** The pick(s) — the text, when not strict. Followed when changed from outside. */
|
|
62
|
+
value?: any;
|
|
63
|
+
/** A pick changed: the option, `undefined` when dropped, or the list with `multiple`. */
|
|
64
|
+
onSelect?: (value: any) => void;
|
|
65
|
+
/** The text changed, typed or completed. */
|
|
66
|
+
onInput?: (text: string) => void;
|
|
67
|
+
/** Milliseconds without typing before the source is asked. Default 100. */
|
|
68
|
+
wait?: number;
|
|
69
|
+
/** Open the list as soon as the field takes the focus. */
|
|
70
|
+
eager?: boolean;
|
|
71
|
+
/** Draw the list over scrolling ancestors, at fixed coordinates. */
|
|
72
|
+
float?: boolean;
|
|
73
|
+
/** A last row, "create what is being typed", once something is typed. */
|
|
74
|
+
add?: { show?: (text: string) => string; max?: number; onAdd: (text: string) => void };
|
|
75
|
+
/** The field's text for several picks. Defaults to the labels joined, or "n selected". */
|
|
76
|
+
summary?: (picks: any[]) => string;
|
|
77
|
+
/** How one option is drawn in the list. Defaults to its label. */
|
|
78
|
+
option?: Snippet<[any]>;
|
|
79
|
+
/** Inside the frame, before and after the text. */
|
|
80
|
+
start?: Snippet;
|
|
81
|
+
end?: Snippet;
|
|
82
|
+
/** What the list says when nothing matches. */
|
|
83
|
+
noresult?: string;
|
|
84
|
+
/** Extra classes on the `.input` frame: `input-ghost`, `input-primary`… */
|
|
85
|
+
field?: string;
|
|
86
|
+
/** Colour the field by its validity and reveal `hint` once the browser
|
|
87
|
+
marks it invalid. A strict field holding typed text but no pick is
|
|
88
|
+
invalid, with `unpickedLabel` as its message. */
|
|
89
|
+
validator?: boolean;
|
|
90
|
+
/** Shown under the field when it is invalid. */
|
|
91
|
+
hint?: Snippet;
|
|
92
|
+
/** The validity message of a strict field left with text but no pick. */
|
|
93
|
+
unpickedLabel?: string;
|
|
94
|
+
class?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// The axes are deliberately NOT destructured: they travel in `axes` and are
|
|
98
|
+
// resolved by name, so an axis a family drops changes nothing down here.
|
|
99
|
+
let {
|
|
100
|
+
options,
|
|
101
|
+
then,
|
|
102
|
+
show,
|
|
103
|
+
key,
|
|
104
|
+
strict: strictProp = true,
|
|
105
|
+
multiple = false,
|
|
106
|
+
value: initial,
|
|
107
|
+
onSelect,
|
|
108
|
+
onInput,
|
|
109
|
+
wait = 100,
|
|
110
|
+
eager = false,
|
|
111
|
+
float = false,
|
|
112
|
+
add,
|
|
113
|
+
summary,
|
|
114
|
+
option,
|
|
115
|
+
start,
|
|
116
|
+
end,
|
|
117
|
+
noresult = 'No results',
|
|
118
|
+
field = '',
|
|
119
|
+
validator = false,
|
|
120
|
+
hint,
|
|
121
|
+
unpickedLabel = 'Pick an option from the list',
|
|
122
|
+
name,
|
|
123
|
+
disabled = false,
|
|
124
|
+
class: klass = '',
|
|
125
|
+
onfocus,
|
|
126
|
+
onblur,
|
|
127
|
+
onkeydown,
|
|
128
|
+
...axes
|
|
129
|
+
}: Props = $props();
|
|
130
|
+
|
|
131
|
+
let applied = $derived(applyAxes(PREFIX, AXES, FLAGS, axes));
|
|
132
|
+
let classes = $derived(cx(PREFIX, applied.classes, multiple && `${PREFIX}-multiple`, klass));
|
|
133
|
+
|
|
134
|
+
const uid = $props.id();
|
|
135
|
+
let strict = $derived(strictProp || multiple);
|
|
136
|
+
|
|
137
|
+
/* ── What an option is ────────────────────────────────────────────── */
|
|
138
|
+
|
|
139
|
+
function label(o: any): string {
|
|
140
|
+
if (o == null) return '';
|
|
141
|
+
if (show) return show(o);
|
|
142
|
+
if (typeof o !== 'object') return `${o}`;
|
|
143
|
+
return `${o.label ?? o.name ?? o.value ?? o.id ?? ''}`;
|
|
144
|
+
}
|
|
145
|
+
function keyOf(o: any): string | number {
|
|
146
|
+
if (key) return key(o);
|
|
147
|
+
if (o !== null && typeof o === 'object') return o.id ?? o.value ?? label(o);
|
|
148
|
+
return o;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* ── State ────────────────────────────────────────────────────────── */
|
|
152
|
+
|
|
153
|
+
/* Where it starts, read once: afterwards the visitor owns it. */
|
|
154
|
+
const start0 = untrack(() => initial);
|
|
155
|
+
const many = untrack(() => multiple);
|
|
156
|
+
const picks = untrack(() => strictProp || multiple);
|
|
157
|
+
/** The text in the field. */
|
|
158
|
+
let text = $state(picks ? (many ? '' : label(start0)) : `${start0 ?? ''}`);
|
|
159
|
+
/** The pick (single), or the picks (multiple). */
|
|
160
|
+
let picked: any = $state(many ? (Array.isArray(start0) ? [...start0] : []) : picks ? start0 : undefined);
|
|
161
|
+
/** The search being typed, in strict mode. `undefined` when not searching. */
|
|
162
|
+
let query: string | undefined = $state();
|
|
163
|
+
/** The last pick, for a search left unfinished to fall back to. */
|
|
164
|
+
let lastPicked: any = $state(start0);
|
|
165
|
+
|
|
166
|
+
let open = $state(false);
|
|
167
|
+
let loading = $state(false);
|
|
168
|
+
let items: any[] = $state([]);
|
|
169
|
+
/** Keyboard position in the list; -1 is the field itself. */
|
|
170
|
+
let active = $state(-1);
|
|
171
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
172
|
+
/** Answers can arrive out of order: only the latest request may write. */
|
|
173
|
+
let ticket = 0;
|
|
174
|
+
|
|
175
|
+
let input: HTMLInputElement | undefined = $state();
|
|
176
|
+
|
|
177
|
+
/* A `value` changed from outside (a form reset, another field) replaces
|
|
178
|
+
the pick(s). A value echoing the current pick changes nothing, so a
|
|
179
|
+
parent writing back what `onSelect` gave it does not disturb a search. */
|
|
180
|
+
const same = (a: any, b: any) => (a == null || b == null ? a == b : keyOf(a) === keyOf(b));
|
|
181
|
+
$effect(() => {
|
|
182
|
+
const next = initial;
|
|
183
|
+
untrack(() => {
|
|
184
|
+
if (many) {
|
|
185
|
+
const list = Array.isArray(next) ? next : [];
|
|
186
|
+
const now = picked as any[];
|
|
187
|
+
if (list.length === now.length && list.every((o, i) => same(o, now[i]))) return;
|
|
188
|
+
picked = [...list];
|
|
189
|
+
} else if (picks) {
|
|
190
|
+
if (same(next, picked)) return;
|
|
191
|
+
picked = next;
|
|
192
|
+
lastPicked = next;
|
|
193
|
+
query = undefined;
|
|
194
|
+
} else if (`${next ?? ''}` !== text) text = `${next ?? ''}`;
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
/* A strict field's text is only a search: left with text but no pick, it
|
|
199
|
+
holds nothing, and says so to the form (an empty one is `required`'s). */
|
|
200
|
+
$effect(() => {
|
|
201
|
+
input?.setCustomValidity(strict && !multiple && picked == null && shown.trim() !== '' ? unpickedLabel : '');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const isPicked = (o: any) =>
|
|
205
|
+
multiple ? (picked as any[]).some((p) => keyOf(p) === keyOf(o)) : picked != null && keyOf(picked) === keyOf(o);
|
|
206
|
+
|
|
207
|
+
function summarize(list: any[]): string {
|
|
208
|
+
if (summary) return summary(list);
|
|
209
|
+
if (!list.length) return '';
|
|
210
|
+
const joined = list.map(label).join(', ');
|
|
211
|
+
return joined.length <= 32 ? joined : `${list.length} selected`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Not searching: a strict field shows its pick, a multiple one its summary. */
|
|
215
|
+
let shown = $derived(
|
|
216
|
+
!strict ? text : query !== undefined ? query : multiple ? summarize(picked) : label(picked)
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
/* ── The source ───────────────────────────────────────────────────── */
|
|
220
|
+
|
|
221
|
+
async function search() {
|
|
222
|
+
const mine = ++ticket;
|
|
223
|
+
open = true;
|
|
224
|
+
loading = true;
|
|
225
|
+
const q = strict ? (query ?? '') : text;
|
|
226
|
+
|
|
227
|
+
let answer: any = [];
|
|
228
|
+
try {
|
|
229
|
+
if (Array.isArray(options)) {
|
|
230
|
+
const needle = q.trim().toLowerCase();
|
|
231
|
+
answer = needle ? options.filter((o) => label(o).toLowerCase().includes(needle)) : options;
|
|
232
|
+
} else if (typeof options === 'function') answer = await options(q);
|
|
233
|
+
else {
|
|
234
|
+
const src = typeof options === 'string' ? { uri: options } : options;
|
|
235
|
+
const uri = typeof src.uri === 'function' ? src.uri(q) : src.uri;
|
|
236
|
+
const init = typeof src.options === 'function' ? src.options(q) : src.options;
|
|
237
|
+
const res = await fetch(uri, init ?? { credentials: 'include', headers: { Accept: 'application/json' } });
|
|
238
|
+
answer = res.ok ? await res.json() : [];
|
|
239
|
+
}
|
|
240
|
+
} catch {
|
|
241
|
+
answer = [];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (mine !== ticket) return;
|
|
245
|
+
const list = then && !Array.isArray(options) ? then(answer) : answer;
|
|
246
|
+
// Never undefined: a source that answers nothing leaves an empty list.
|
|
247
|
+
items = Array.isArray(list) ? list : [];
|
|
248
|
+
active = -1;
|
|
249
|
+
loading = false;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function close() {
|
|
253
|
+
clearTimeout(timer);
|
|
254
|
+
ticket++;
|
|
255
|
+
open = false;
|
|
256
|
+
loading = false;
|
|
257
|
+
active = -1;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* ── Picking ──────────────────────────────────────────────────────── */
|
|
261
|
+
|
|
262
|
+
function choose(o: any) {
|
|
263
|
+
if (multiple) {
|
|
264
|
+
picked = isPicked(o) ? (picked as any[]).filter((p) => keyOf(p) !== keyOf(o)) : [...picked, o];
|
|
265
|
+
onSelect?.(picked);
|
|
266
|
+
return; // the list stays open while ticking
|
|
267
|
+
}
|
|
268
|
+
query = undefined;
|
|
269
|
+
if (strict) {
|
|
270
|
+
picked = o;
|
|
271
|
+
lastPicked = o;
|
|
272
|
+
} else {
|
|
273
|
+
text = label(o);
|
|
274
|
+
onInput?.(text);
|
|
275
|
+
}
|
|
276
|
+
onSelect?.(o);
|
|
277
|
+
close();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** What "+ Create …" would create: the text as typed. */
|
|
281
|
+
let typed = $derived((strict ? (query ?? '') : text).trim());
|
|
282
|
+
let addLabel = $derived(
|
|
283
|
+
add && typed !== '' && (add.max === undefined || items.length < add.max)
|
|
284
|
+
? (add.show?.(typed) ?? `+ Create ${typed}`)
|
|
285
|
+
: undefined
|
|
286
|
+
);
|
|
287
|
+
/** Rows the keyboard walks through: the options, then the add row. */
|
|
288
|
+
let rows = $derived(items.length + (addLabel ? 1 : 0));
|
|
289
|
+
|
|
290
|
+
function create() {
|
|
291
|
+
const t = typed;
|
|
292
|
+
close();
|
|
293
|
+
query = undefined;
|
|
294
|
+
add?.onAdd(t);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** Empty the field and drop the pick(s). */
|
|
298
|
+
export function clear() {
|
|
299
|
+
query = undefined;
|
|
300
|
+
text = '';
|
|
301
|
+
lastPicked = undefined;
|
|
302
|
+
if (multiple) {
|
|
303
|
+
if ((picked as any[]).length) onSelect?.((picked = []));
|
|
304
|
+
} else if (strict && picked != null) onSelect?.((picked = undefined));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export function focus() {
|
|
308
|
+
input?.focus();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* ── A list at fixed coordinates follows its field ────────────────── */
|
|
312
|
+
|
|
313
|
+
let frame: HTMLLabelElement | undefined = $state();
|
|
314
|
+
let floatStyle = $state('');
|
|
315
|
+
|
|
316
|
+
function place() {
|
|
317
|
+
if (!frame) return;
|
|
318
|
+
const box = frame.getBoundingClientRect();
|
|
319
|
+
floatStyle = `position: fixed; top: ${box.bottom + 4}px; left: ${box.left}px; min-width: ${box.width}px;`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
$effect(() => {
|
|
323
|
+
if (!float || !open || !frame) return;
|
|
324
|
+
place();
|
|
325
|
+
// Capture: the scroll of an inner container does not bubble.
|
|
326
|
+
window.addEventListener('scroll', place, true);
|
|
327
|
+
window.addEventListener('resize', place);
|
|
328
|
+
return () => {
|
|
329
|
+
window.removeEventListener('scroll', place, true);
|
|
330
|
+
window.removeEventListener('resize', place);
|
|
331
|
+
};
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
/* ── Events ───────────────────────────────────────────────────────── */
|
|
335
|
+
|
|
336
|
+
function handleInput(e: Event & { currentTarget: HTMLInputElement }) {
|
|
337
|
+
const t = e.currentTarget.value;
|
|
338
|
+
if (strict) {
|
|
339
|
+
// Typing, pasting or an autofill: the text is a search again, and no
|
|
340
|
+
// longer stands for the pick.
|
|
341
|
+
query = t;
|
|
342
|
+
if (!multiple && picked != null) onSelect?.((picked = undefined));
|
|
343
|
+
} else {
|
|
344
|
+
text = t;
|
|
345
|
+
onInput?.(t);
|
|
346
|
+
}
|
|
347
|
+
clearTimeout(timer);
|
|
348
|
+
timer = setTimeout(search, wait);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* The caller's own focus, blur and keydown run after ours: a key the list
|
|
352
|
+
used (an arrow moving in it, Enter picking) reaches them prevented. */
|
|
353
|
+
function handleFocus(e: FocusEvent & { currentTarget: EventTarget & HTMLInputElement }) {
|
|
354
|
+
// A multiple field shows its summary at rest, and an empty search when in use.
|
|
355
|
+
if (multiple) query = '';
|
|
356
|
+
if (eager) search();
|
|
357
|
+
onfocus?.(e);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function handleBlur(e: FocusEvent & { currentTarget: EventTarget & HTMLInputElement }) {
|
|
361
|
+
blurred();
|
|
362
|
+
onblur?.(e);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function blurred() {
|
|
366
|
+
close();
|
|
367
|
+
if (multiple) {
|
|
368
|
+
query = undefined;
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
// Leaving a strict field on an unfinished search: the leftover text
|
|
372
|
+
// stands for nothing, so the last pick comes back. An emptied field is
|
|
373
|
+
// a deliberate reset and stays empty.
|
|
374
|
+
if (strict && picked == null) {
|
|
375
|
+
const searching = query !== undefined && query.trim() !== '';
|
|
376
|
+
if (searching && lastPicked != null) onSelect?.((picked = lastPicked));
|
|
377
|
+
else if (!searching) lastPicked = undefined;
|
|
378
|
+
}
|
|
379
|
+
query = undefined;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function handleKeydown(e: KeyboardEvent & { currentTarget: EventTarget & HTMLInputElement }) {
|
|
383
|
+
listKeydown(e);
|
|
384
|
+
onkeydown?.(e);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function listKeydown(e: KeyboardEvent) {
|
|
388
|
+
if (e.key === 'ArrowDown') {
|
|
389
|
+
e.preventDefault();
|
|
390
|
+
if (!open) search();
|
|
391
|
+
else if (rows) active = (active + 1) % rows;
|
|
392
|
+
} else if (e.key === 'ArrowUp' && open && rows) {
|
|
393
|
+
e.preventDefault();
|
|
394
|
+
active = active <= 0 ? rows - 1 : active - 1;
|
|
395
|
+
} else if (e.key === 'Enter' && open && active >= 0) {
|
|
396
|
+
e.preventDefault();
|
|
397
|
+
if (active < items.length) choose(items[active]);
|
|
398
|
+
else create();
|
|
399
|
+
} else if (e.key === 'Escape' && open) {
|
|
400
|
+
e.preventDefault();
|
|
401
|
+
close();
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
</script>
|
|
405
|
+
|
|
406
|
+
<div class={classes}>
|
|
407
|
+
<label bind:this={frame} class={cx('input', field, validator && 'validator')}>
|
|
408
|
+
{@render start?.()}
|
|
409
|
+
<!-- Password managers fill a field without going through the list,
|
|
410
|
+
which would leave a value with no pick: keep them away. -->
|
|
411
|
+
<input
|
|
412
|
+
{...applied.rest}
|
|
413
|
+
bind:this={input}
|
|
414
|
+
type="text"
|
|
415
|
+
role="combobox"
|
|
416
|
+
name={strict ? undefined : name}
|
|
417
|
+
value={shown}
|
|
418
|
+
{disabled}
|
|
419
|
+
autocomplete="off"
|
|
420
|
+
data-1p-ignore
|
|
421
|
+
data-lpignore="true"
|
|
422
|
+
data-bwignore="true"
|
|
423
|
+
data-form-type="other"
|
|
424
|
+
aria-autocomplete="list"
|
|
425
|
+
aria-expanded={open}
|
|
426
|
+
aria-controls="{uid}-list"
|
|
427
|
+
aria-activedescendant={open && active >= 0 ? `${uid}-${active}` : undefined}
|
|
428
|
+
oninput={handleInput}
|
|
429
|
+
onfocus={handleFocus}
|
|
430
|
+
onblur={handleBlur}
|
|
431
|
+
onkeydown={handleKeydown}
|
|
432
|
+
/>
|
|
433
|
+
{@render end?.()}
|
|
434
|
+
|
|
435
|
+
{#if open}
|
|
436
|
+
<!-- A row is picked on mousedown, before the field can lose the focus:
|
|
437
|
+
a blur first would close the list and, in strict mode, undo the
|
|
438
|
+
pick. The keyboard goes through the field (aria-activedescendant). -->
|
|
439
|
+
<ul
|
|
440
|
+
id="{uid}-list"
|
|
441
|
+
class="list list-suggestions"
|
|
442
|
+
role="listbox"
|
|
443
|
+
aria-multiselectable={multiple || undefined}
|
|
444
|
+
style={float ? floatStyle : undefined}
|
|
445
|
+
>
|
|
446
|
+
{#if loading}
|
|
447
|
+
<li class="list-row"><span class="loading loading-dots loading-sm"></span></li>
|
|
448
|
+
{:else}
|
|
449
|
+
{#each items as o, i (i)}
|
|
450
|
+
<li
|
|
451
|
+
id="{uid}-{i}"
|
|
452
|
+
class="list-row combobox-option"
|
|
453
|
+
role="option"
|
|
454
|
+
aria-selected={multiple ? isPicked(o) : active === i}
|
|
455
|
+
data-active={multiple && active === i ? '' : undefined}
|
|
456
|
+
onmousedown={(e) => {
|
|
457
|
+
e.preventDefault();
|
|
458
|
+
choose(o);
|
|
459
|
+
}}
|
|
460
|
+
>
|
|
461
|
+
{#if option}{@render option(o)}{:else}{label(o)}{/if}
|
|
462
|
+
</li>
|
|
463
|
+
{/each}
|
|
464
|
+
|
|
465
|
+
{#if addLabel}
|
|
466
|
+
<!-- Always last: the way out when nothing in the list fits. -->
|
|
467
|
+
<li
|
|
468
|
+
id="{uid}-{items.length}"
|
|
469
|
+
class="list-row"
|
|
470
|
+
role="option"
|
|
471
|
+
aria-selected={active === items.length}
|
|
472
|
+
onmousedown={(e) => {
|
|
473
|
+
e.preventDefault();
|
|
474
|
+
create();
|
|
475
|
+
}}
|
|
476
|
+
>
|
|
477
|
+
{addLabel}
|
|
478
|
+
</li>
|
|
479
|
+
{:else if items.length === 0}
|
|
480
|
+
<li class="list-row" role="option" aria-selected="false" aria-disabled="true">{noresult}</li>
|
|
481
|
+
{/if}
|
|
482
|
+
{/if}
|
|
483
|
+
</ul>
|
|
484
|
+
{/if}
|
|
485
|
+
</label>
|
|
486
|
+
{#if hint}<p class="validator-hint">{@render hint()}</p>{/if}
|
|
487
|
+
|
|
488
|
+
{#if strict}
|
|
489
|
+
<!-- What was chosen, for a form and for whoever reads the DOM. -->
|
|
490
|
+
<select {name} {disabled} multiple={multiple || undefined} hidden aria-hidden="true" tabindex="-1">
|
|
491
|
+
{#each multiple ? picked : picked != null ? [picked] : [] as p (keyOf(p))}
|
|
492
|
+
<option value={keyOf(p)} selected>{label(p)}</option>
|
|
493
|
+
{/each}
|
|
494
|
+
</select>
|
|
495
|
+
{/if}
|
|
496
|
+
</div>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** What .combobox is made of, classified. The props follow the
|
|
2
|
+
families the project registers (variants.ts, ADR 0015).
|
|
3
|
+
|
|
4
|
+
`.combobox-multiple` is a PART: the wrapper writes it from `multiple`. */
|
|
5
|
+
export declare const PREFIX = "combobox";
|
|
6
|
+
export declare const AXES: {
|
|
7
|
+
readonly size: readonly ["xs", "sm", "md", "lg", "xl"];
|
|
8
|
+
};
|
|
9
|
+
export declare const FLAGS: {};
|
|
10
|
+
export declare const PARTS: readonly ["option", "multiple"];
|
|
11
|
+
/** Where the options come from: a list, a function, or an address answering JSON. */
|
|
12
|
+
export type ComboboxSource = any[] | ((query: string) => any[] | Promise<any[]>) | string | {
|
|
13
|
+
uri: string | ((query: string) => string);
|
|
14
|
+
options?: RequestInit | ((query: string) => RequestInit);
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A field whose value is looked up in a list of options while typing.
|
|
18
|
+
*
|
|
19
|
+
* **Strict** (default): the value is a picked option, never the typed
|
|
20
|
+
* text. A hidden `<select name>` carries it for a form, so the DOM says what
|
|
21
|
+
* was chosen. The field shows two things over time: the search being typed,
|
|
22
|
+
* and the label of the pick. Typing drops the pick; leaving a search
|
|
23
|
+
* unfinished brings the last pick back.
|
|
24
|
+
*
|
|
25
|
+
* **Free** (`strict={false}`): the value is the text — the options only
|
|
26
|
+
* complete it (autocompletion). The `<input>` itself carries `name`.
|
|
27
|
+
*
|
|
28
|
+
* **Multiple** (implies strict): the field shows a summary of the picks,
|
|
29
|
+
* the list stays open while ticking, and a hidden `<select multiple>`
|
|
30
|
+
* carries them. To collect free values as chips, see ChipsInput.
|
|
31
|
+
*
|
|
32
|
+
* Options come from a list (filtered here), a function of the query, or an
|
|
33
|
+
* address answering JSON (`then` reshapes the answer). The frame is the
|
|
34
|
+
* family's `.input`, the list its `.list-suggestions`.
|
|
35
|
+
*/
|
|
36
|
+
import { type Snippet } from 'svelte';
|
|
37
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
38
|
+
import { type AxisProps } from '../variants.js';
|
|
39
|
+
interface Props extends AxisProps<typeof AXES, typeof FLAGS, typeof PREFIX>, Omit<HTMLInputAttributes, 'size' | 'value'> {
|
|
40
|
+
/** The options, or where to fetch them. */
|
|
41
|
+
options: ComboboxSource;
|
|
42
|
+
/** Reshape what a function or an address answered into the list. */
|
|
43
|
+
then?: (answer: any) => any[];
|
|
44
|
+
/** The text an option stands for: in the list, and in the field once picked. */
|
|
45
|
+
show?: (option: any) => string;
|
|
46
|
+
/** What identifies an option, and what the hidden select submits. Defaults to `id`, `value`, then the label. */
|
|
47
|
+
key?: (option: any) => string | number;
|
|
48
|
+
/** The value is a picked option (default), or the text (`false`). */
|
|
49
|
+
strict?: boolean;
|
|
50
|
+
/** Pick several. Implies strict. */
|
|
51
|
+
multiple?: boolean;
|
|
52
|
+
/** The pick(s) — the text, when not strict. Followed when changed from outside. */
|
|
53
|
+
value?: any;
|
|
54
|
+
/** A pick changed: the option, `undefined` when dropped, or the list with `multiple`. */
|
|
55
|
+
onSelect?: (value: any) => void;
|
|
56
|
+
/** The text changed, typed or completed. */
|
|
57
|
+
onInput?: (text: string) => void;
|
|
58
|
+
/** Milliseconds without typing before the source is asked. Default 100. */
|
|
59
|
+
wait?: number;
|
|
60
|
+
/** Open the list as soon as the field takes the focus. */
|
|
61
|
+
eager?: boolean;
|
|
62
|
+
/** Draw the list over scrolling ancestors, at fixed coordinates. */
|
|
63
|
+
float?: boolean;
|
|
64
|
+
/** A last row, "create what is being typed", once something is typed. */
|
|
65
|
+
add?: {
|
|
66
|
+
show?: (text: string) => string;
|
|
67
|
+
max?: number;
|
|
68
|
+
onAdd: (text: string) => void;
|
|
69
|
+
};
|
|
70
|
+
/** The field's text for several picks. Defaults to the labels joined, or "n selected". */
|
|
71
|
+
summary?: (picks: any[]) => string;
|
|
72
|
+
/** How one option is drawn in the list. Defaults to its label. */
|
|
73
|
+
option?: Snippet<[any]>;
|
|
74
|
+
/** Inside the frame, before and after the text. */
|
|
75
|
+
start?: Snippet;
|
|
76
|
+
end?: Snippet;
|
|
77
|
+
/** What the list says when nothing matches. */
|
|
78
|
+
noresult?: string;
|
|
79
|
+
/** Extra classes on the `.input` frame: `input-ghost`, `input-primary`… */
|
|
80
|
+
field?: string;
|
|
81
|
+
/** Colour the field by its validity and reveal `hint` once the browser
|
|
82
|
+
marks it invalid. A strict field holding typed text but no pick is
|
|
83
|
+
invalid, with `unpickedLabel` as its message. */
|
|
84
|
+
validator?: boolean;
|
|
85
|
+
/** Shown under the field when it is invalid. */
|
|
86
|
+
hint?: Snippet;
|
|
87
|
+
/** The validity message of a strict field left with text but no pick. */
|
|
88
|
+
unpickedLabel?: string;
|
|
89
|
+
class?: string;
|
|
90
|
+
}
|
|
91
|
+
declare const Combobox: import("svelte").Component<Props, {
|
|
92
|
+
clear: () => void;
|
|
93
|
+
focus: () => void;
|
|
94
|
+
}, "">;
|
|
95
|
+
type Combobox = ReturnType<typeof Combobox>;
|
|
96
|
+
export default Combobox;
|