@privaty/ui-forms 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.
Files changed (36) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +107 -0
  4. package/dist/components/form-error.svelte +49 -0
  5. package/dist/components/form-error.svelte.d.ts +15 -0
  6. package/dist/components/reset.svelte +49 -0
  7. package/dist/components/reset.svelte.d.ts +19 -0
  8. package/dist/components/submit.svelte +82 -0
  9. package/dist/components/submit.svelte.d.ts +27 -0
  10. package/dist/context.d.ts +23 -0
  11. package/dist/context.js +21 -0
  12. package/dist/form-state.svelte.d.ts +89 -0
  13. package/dist/form-state.svelte.js +139 -0
  14. package/dist/form.svelte +219 -0
  15. package/dist/form.svelte.d.ts +62 -0
  16. package/dist/inputs/checkbox-input.svelte +119 -0
  17. package/dist/inputs/checkbox-input.svelte.d.ts +45 -0
  18. package/dist/inputs/date-input.svelte +132 -0
  19. package/dist/inputs/date-input.svelte.d.ts +61 -0
  20. package/dist/inputs/number-input.svelte +141 -0
  21. package/dist/inputs/number-input.svelte.d.ts +63 -0
  22. package/dist/inputs/select-input.svelte +156 -0
  23. package/dist/inputs/select-input.svelte.d.ts +57 -0
  24. package/dist/inputs/text-input.svelte +126 -0
  25. package/dist/inputs/text-input.svelte.d.ts +59 -0
  26. package/dist/inputs/textarea-input.svelte +135 -0
  27. package/dist/inputs/textarea-input.svelte.d.ts +57 -0
  28. package/dist/inputs/wire-field.d.ts +44 -0
  29. package/dist/inputs/wire-field.js +45 -0
  30. package/dist/testing/fakes.svelte.d.ts +205 -0
  31. package/dist/testing/fakes.svelte.js +346 -0
  32. package/dist/types/field.d.ts +156 -0
  33. package/dist/types/field.js +1 -0
  34. package/dist/types/form.d.ts +27 -0
  35. package/dist/types/form.js +1 -0
  36. package/package.json +52 -0
@@ -0,0 +1,132 @@
1
+ <!-- @component
2
+ Date-family input (date, datetime-local, month, time, week) wired to a
3
+ SvelteKit remote form field — must render inside a <Form>, whose context it
4
+ registers with. Values are ISO-style strings in the chosen type's format.
5
+ Shows resolver-translated validation errors once the form state reveals them,
6
+ plus a majority-aware required/optional marker, and turns readonly while the
7
+ form submits.
8
+ -->
9
+ <script lang="ts">
10
+ import { cn } from "@privaty/ui/cn.js";
11
+ import Input from "@privaty/ui/components/input.svelte";
12
+ import type { LabelStyle } from "@privaty/ui/components/types.js";
13
+ import type { HTMLInputAttributes } from "svelte/elements";
14
+ import type { DateField, DateFieldType } from "../types/field";
15
+ import { wireField } from "./wire-field";
16
+
17
+ interface Props {
18
+ /** The SvelteKit remote form field to bind. Structural — anything
19
+ * satisfying the DateField slice works, e.g. a fake from the public
20
+ * testing subpath. */
21
+ field: DateField;
22
+ /** Visible label text for the control. */
23
+ label: string;
24
+ /** Which date-family input to render: "date" (default),
25
+ * "datetime-local", "month", "time", or "week". */
26
+ type?: DateFieldType;
27
+
28
+ /** Label placement: "top" (default), "left", or "hidden". No floating:
29
+ * date-family inputs render their format scaffold even when empty, so
30
+ * :placeholder-shown never behaves. */
31
+ labelStyle?: Exclude<LabelStyle, "floating">;
32
+
33
+ /** Marks the field required: feeds the majority-aware required/optional
34
+ * marker (required markers styled red) — forms where at least half the
35
+ * fields are required mark the optional ones instead. Validation itself
36
+ * comes from the field's schema, not this flag, and it is not forwarded
37
+ * as a native `required` attribute. */
38
+ required?: boolean;
39
+ /** Disables the control. Disabled controls are excluded from FormData —
40
+ * never disable to lock the form during submit; the input already turns
41
+ * readonly while submitting. */
42
+ disabled?: boolean;
43
+ /** Renders the input readonly. Also forced on while the form is
44
+ * submitting, independent of this prop. */
45
+ readonly?: boolean;
46
+
47
+ /** ISO-style string in the chosen type's format (e.g. "2026-08" for
48
+ * month, "2026-08-18" for date). */
49
+ initialValue?: string;
50
+
51
+ /** Native lower bound, in the same format as the value. */
52
+ min?: string;
53
+ /** Native upper bound, in the same format as the value. */
54
+ max?: string;
55
+
56
+ /** Passed through to the native autocomplete attribute (e.g. "bday"). */
57
+ autocomplete?: HTMLInputAttributes["autocomplete"];
58
+
59
+ /** Extra classes for the outer field wrapper. */
60
+ class?: string;
61
+ /** Extra classes for the <label> element. */
62
+ labelClass?: string;
63
+ /** Extra classes for the <input> element. */
64
+ inputClass?: string;
65
+ /** Extra classes for the required/optional marker. */
66
+ markerClass?: string;
67
+ /** Extra classes for the error <ul>. */
68
+ errorClass?: string;
69
+ }
70
+
71
+ const {
72
+ field,
73
+ label,
74
+ type = "date",
75
+
76
+ labelStyle,
77
+
78
+ required = false,
79
+ disabled = false,
80
+ readonly = false,
81
+
82
+ initialValue = "",
83
+
84
+ min,
85
+ max,
86
+
87
+ autocomplete,
88
+
89
+ class: classes,
90
+ labelClass,
91
+ inputClass,
92
+ markerClass,
93
+ errorClass,
94
+ }: Props = $props();
95
+
96
+ const attributes = $derived(field.as(type, initialValue));
97
+
98
+ // The field, type, and initialValue are stable for the component's lifetime,
99
+ // so capturing the initial name and registration is intentional.
100
+ // svelte-ignore state_referenced_locally
101
+ const name = attributes.name;
102
+
103
+ // svelte-ignore state_referenced_locally
104
+ const wired = wireField({
105
+ name,
106
+ initialValue,
107
+ required,
108
+ issues: () => field.issues(),
109
+ getValue: () => field.value(),
110
+ setValue: (value) => field.set(value as string),
111
+ normalize: (value) => (value == null ? "" : String(value)),
112
+ });
113
+ </script>
114
+
115
+ <Input
116
+ {...attributes}
117
+ {label}
118
+ {labelStyle}
119
+ errors={wired.errors}
120
+ marker={wired.marker}
121
+ aria-invalid={wired.errors.length > 0 ? true : undefined}
122
+ {disabled}
123
+ readonly={readonly || wired.state.isSubmitting}
124
+ {min}
125
+ {max}
126
+ {autocomplete}
127
+ class={classes}
128
+ {labelClass}
129
+ {inputClass}
130
+ markerClass={cn(required && "text-red-700 dark:text-red-500", markerClass)}
131
+ {errorClass}
132
+ />
@@ -0,0 +1,61 @@
1
+ import type { LabelStyle } from "@privaty/ui/components/types.js";
2
+ import type { HTMLInputAttributes } from "svelte/elements";
3
+ import type { DateField, DateFieldType } from "../types/field";
4
+ interface Props {
5
+ /** The SvelteKit remote form field to bind. Structural — anything
6
+ * satisfying the DateField slice works, e.g. a fake from the public
7
+ * testing subpath. */
8
+ field: DateField;
9
+ /** Visible label text for the control. */
10
+ label: string;
11
+ /** Which date-family input to render: "date" (default),
12
+ * "datetime-local", "month", "time", or "week". */
13
+ type?: DateFieldType;
14
+ /** Label placement: "top" (default), "left", or "hidden". No floating:
15
+ * date-family inputs render their format scaffold even when empty, so
16
+ * :placeholder-shown never behaves. */
17
+ labelStyle?: Exclude<LabelStyle, "floating">;
18
+ /** Marks the field required: feeds the majority-aware required/optional
19
+ * marker (required markers styled red) — forms where at least half the
20
+ * fields are required mark the optional ones instead. Validation itself
21
+ * comes from the field's schema, not this flag, and it is not forwarded
22
+ * as a native `required` attribute. */
23
+ required?: boolean;
24
+ /** Disables the control. Disabled controls are excluded from FormData —
25
+ * never disable to lock the form during submit; the input already turns
26
+ * readonly while submitting. */
27
+ disabled?: boolean;
28
+ /** Renders the input readonly. Also forced on while the form is
29
+ * submitting, independent of this prop. */
30
+ readonly?: boolean;
31
+ /** ISO-style string in the chosen type's format (e.g. "2026-08" for
32
+ * month, "2026-08-18" for date). */
33
+ initialValue?: string;
34
+ /** Native lower bound, in the same format as the value. */
35
+ min?: string;
36
+ /** Native upper bound, in the same format as the value. */
37
+ max?: string;
38
+ /** Passed through to the native autocomplete attribute (e.g. "bday"). */
39
+ autocomplete?: HTMLInputAttributes["autocomplete"];
40
+ /** Extra classes for the outer field wrapper. */
41
+ class?: string;
42
+ /** Extra classes for the <label> element. */
43
+ labelClass?: string;
44
+ /** Extra classes for the <input> element. */
45
+ inputClass?: string;
46
+ /** Extra classes for the required/optional marker. */
47
+ markerClass?: string;
48
+ /** Extra classes for the error <ul>. */
49
+ errorClass?: string;
50
+ }
51
+ /**
52
+ * Date-family input (date, datetime-local, month, time, week) wired to a
53
+ * SvelteKit remote form field — must render inside a <Form>, whose context it
54
+ * registers with. Values are ISO-style strings in the chosen type's format.
55
+ * Shows resolver-translated validation errors once the form state reveals them,
56
+ * plus a majority-aware required/optional marker, and turns readonly while the
57
+ * form submits.
58
+ */
59
+ declare const DateInput: import("svelte").Component<Props, {}, "">;
60
+ type DateInput = ReturnType<typeof DateInput>;
61
+ export default DateInput;
@@ -0,0 +1,141 @@
1
+ <!-- @component
2
+ Number input wired to a SvelteKit remote form number field — must render
3
+ inside a <Form>, whose context it registers with. Shows resolver-translated
4
+ validation errors once the form state reveals them, plus a majority-aware
5
+ required/optional marker, and turns readonly while the form submits.
6
+ Mid-edit the field holds the raw DOM string — Kit only coerces to number at
7
+ submit/reset — and a cleared input counts as unset.
8
+ -->
9
+ <script lang="ts">
10
+ import { cn } from "@privaty/ui/cn.js";
11
+ import Input from "@privaty/ui/components/input.svelte";
12
+ import type { LabelStyle } from "@privaty/ui/components/types.js";
13
+ import type { NumberField } from "../types/field";
14
+ import { wireField } from "./wire-field";
15
+
16
+ interface Props {
17
+ /** The SvelteKit remote form field to bind. Structural — anything
18
+ * satisfying the NumberField slice works, e.g. a fake from the public
19
+ * testing subpath. */
20
+ field: NumberField;
21
+ /** Visible label text. In the floating label style it doubles as the
22
+ * placeholder. */
23
+ label: string;
24
+
25
+ /** Label placement: "top" (default), "left", "floating", or "hidden"
26
+ * (visually hidden, still read by screen readers). */
27
+ labelStyle?: LabelStyle;
28
+
29
+ /** Marks the field required: feeds the majority-aware required/optional
30
+ * marker (required markers styled red) — forms where at least half the
31
+ * fields are required mark the optional ones instead. Validation itself
32
+ * comes from the field's schema, not this flag, and it is not forwarded
33
+ * as a native `required` attribute. */
34
+ required?: boolean;
35
+ /** Disables the control. Disabled controls are excluded from FormData —
36
+ * never disable to lock the form during submit; the input already turns
37
+ * readonly while submitting. */
38
+ disabled?: boolean;
39
+ /** Renders the input readonly. Also forced on while the form is
40
+ * submitting, independent of this prop. */
41
+ readonly?: boolean;
42
+
43
+ /** Seed handed to Kit's `as()` — the value native form reset restores
44
+ * and the baseline for dirty tracking (a cleared input compares as
45
+ * unset). Omitted means unseeded. Assumed stable for the component's
46
+ * lifetime. */
47
+ initialValue?: number;
48
+
49
+ /** Native `min` constraint, forwarded to the input. */
50
+ min?: number;
51
+ /** Native `max` constraint, forwarded to the input. */
52
+ max?: number;
53
+ /** Native `step` granularity, forwarded to the input — "any" permits any
54
+ * decimal. */
55
+ step?: number | "any";
56
+
57
+ /** Placeholder text — ignored in the floating label style, where the
58
+ * label plays that role. */
59
+ placeholder?: string;
60
+
61
+ /** Extra classes for the outer field wrapper. */
62
+ class?: string;
63
+ /** Extra classes for the <label> element. */
64
+ labelClass?: string;
65
+ /** Extra classes for the <input> element. */
66
+ inputClass?: string;
67
+ /** Extra classes for the required/optional marker. */
68
+ markerClass?: string;
69
+ /** Extra classes for the error <ul>. */
70
+ errorClass?: string;
71
+ }
72
+
73
+ const {
74
+ field,
75
+ label,
76
+
77
+ labelStyle,
78
+
79
+ required = false,
80
+ disabled = false,
81
+ readonly = false,
82
+
83
+ initialValue,
84
+
85
+ min,
86
+ max,
87
+ step,
88
+
89
+ placeholder,
90
+
91
+ class: classes,
92
+ labelClass,
93
+ inputClass,
94
+ markerClass,
95
+ errorClass,
96
+ }: Props = $props();
97
+
98
+ const attributes = $derived(
99
+ initialValue === undefined
100
+ ? field.as("number")
101
+ : field.as("number", initialValue),
102
+ );
103
+
104
+ // The field and initialValue are stable for the component's lifetime, so
105
+ // capturing the initial name and registration is intentional.
106
+ // svelte-ignore state_referenced_locally
107
+ const name = attributes.name;
108
+
109
+ // svelte-ignore state_referenced_locally
110
+ const wired = wireField({
111
+ name,
112
+ initialValue,
113
+ required,
114
+ issues: () => field.issues(),
115
+ getValue: () => field.value(),
116
+ setValue: (value) => field.set(value as number),
117
+ // Kit stores the raw DOM string mid-edit; "" (cleared) means unset.
118
+ normalize: (value) =>
119
+ value === "" || value == null ? undefined : Number(value),
120
+ });
121
+ </script>
122
+
123
+ <Input
124
+ {...attributes}
125
+ {label}
126
+ {labelStyle}
127
+ errors={wired.errors}
128
+ marker={wired.marker}
129
+ aria-invalid={wired.errors.length > 0 ? true : undefined}
130
+ {disabled}
131
+ readonly={readonly || wired.state.isSubmitting}
132
+ {min}
133
+ {max}
134
+ {step}
135
+ {placeholder}
136
+ class={classes}
137
+ {labelClass}
138
+ {inputClass}
139
+ markerClass={cn(required && "text-red-700 dark:text-red-500", markerClass)}
140
+ {errorClass}
141
+ />
@@ -0,0 +1,63 @@
1
+ import type { LabelStyle } from "@privaty/ui/components/types.js";
2
+ import type { NumberField } from "../types/field";
3
+ interface Props {
4
+ /** The SvelteKit remote form field to bind. Structural — anything
5
+ * satisfying the NumberField slice works, e.g. a fake from the public
6
+ * testing subpath. */
7
+ field: NumberField;
8
+ /** Visible label text. In the floating label style it doubles as the
9
+ * placeholder. */
10
+ label: string;
11
+ /** Label placement: "top" (default), "left", "floating", or "hidden"
12
+ * (visually hidden, still read by screen readers). */
13
+ labelStyle?: LabelStyle;
14
+ /** Marks the field required: feeds the majority-aware required/optional
15
+ * marker (required markers styled red) — forms where at least half the
16
+ * fields are required mark the optional ones instead. Validation itself
17
+ * comes from the field's schema, not this flag, and it is not forwarded
18
+ * as a native `required` attribute. */
19
+ required?: boolean;
20
+ /** Disables the control. Disabled controls are excluded from FormData —
21
+ * never disable to lock the form during submit; the input already turns
22
+ * readonly while submitting. */
23
+ disabled?: boolean;
24
+ /** Renders the input readonly. Also forced on while the form is
25
+ * submitting, independent of this prop. */
26
+ readonly?: boolean;
27
+ /** Seed handed to Kit's `as()` — the value native form reset restores
28
+ * and the baseline for dirty tracking (a cleared input compares as
29
+ * unset). Omitted means unseeded. Assumed stable for the component's
30
+ * lifetime. */
31
+ initialValue?: number;
32
+ /** Native `min` constraint, forwarded to the input. */
33
+ min?: number;
34
+ /** Native `max` constraint, forwarded to the input. */
35
+ max?: number;
36
+ /** Native `step` granularity, forwarded to the input — "any" permits any
37
+ * decimal. */
38
+ step?: number | "any";
39
+ /** Placeholder text — ignored in the floating label style, where the
40
+ * label plays that role. */
41
+ placeholder?: string;
42
+ /** Extra classes for the outer field wrapper. */
43
+ class?: string;
44
+ /** Extra classes for the <label> element. */
45
+ labelClass?: string;
46
+ /** Extra classes for the <input> element. */
47
+ inputClass?: string;
48
+ /** Extra classes for the required/optional marker. */
49
+ markerClass?: string;
50
+ /** Extra classes for the error <ul>. */
51
+ errorClass?: string;
52
+ }
53
+ /**
54
+ * Number input wired to a SvelteKit remote form number field — must render
55
+ * inside a <Form>, whose context it registers with. Shows resolver-translated
56
+ * validation errors once the form state reveals them, plus a majority-aware
57
+ * required/optional marker, and turns readonly while the form submits.
58
+ * Mid-edit the field holds the raw DOM string — Kit only coerces to number at
59
+ * submit/reset — and a cleared input counts as unset.
60
+ */
61
+ declare const NumberInput: import("svelte").Component<Props, {}, "">;
62
+ type NumberInput = ReturnType<typeof NumberInput>;
63
+ export default NumberInput;
@@ -0,0 +1,156 @@
1
+ <!-- @component
2
+ Select wired to a SvelteKit remote form field — must render inside a <Form>,
3
+ whose context it registers with. Shows resolver-translated validation errors
4
+ once the form state reveals them, plus a majority-aware required/optional
5
+ marker. While submitting it locks interaction with CSS and key swallowing
6
+ instead of disabling — a disabled select is excluded from FormData.
7
+ -->
8
+ <script lang="ts">
9
+ import { cn } from "@privaty/ui/cn.js";
10
+ import Select from "@privaty/ui/components/select.svelte";
11
+ import type {
12
+ LabelStyle,
13
+ SelectOption,
14
+ } from "@privaty/ui/components/types.js";
15
+ import type { SelectField } from "../types/field";
16
+ import { wireField } from "./wire-field";
17
+
18
+ interface Props {
19
+ /** The SvelteKit remote form field to bind. Structural — anything
20
+ * satisfying the SelectField slice works, e.g. a fake from the public
21
+ * testing subpath. */
22
+ field: SelectField;
23
+ /** Visible label text for the control. */
24
+ label: string;
25
+
26
+ /** Options to render, in order. A plain string is shorthand for
27
+ * `{ value: s, label: s }`; values must be unique — they key the
28
+ * rendered list. */
29
+ options: readonly (string | SelectOption)[];
30
+ /** Rendered as a disabled empty option, shown until a value is chosen.
31
+ * Its presence also makes "" the default seed for an unseeded field. */
32
+ placeholder?: string;
33
+
34
+ /** Label placement: "top" (default), "left", or "hidden" — floating is
35
+ * not offered for selects. */
36
+ labelStyle?: Exclude<LabelStyle, "floating">;
37
+
38
+ /** Marks the field required: feeds the majority-aware required/optional
39
+ * marker (required markers styled red) — forms where at least half the
40
+ * fields are required mark the optional ones instead. Validation itself
41
+ * comes from the field's schema, not this flag, and it is not forwarded
42
+ * as a native `required` attribute. */
43
+ required?: boolean;
44
+ /**
45
+ * Selects have no native readonly, so submitting locks interaction with
46
+ * CSS instead. NEVER disable while submitting: disabled controls are
47
+ * excluded from FormData, and Kit validates live form data mid-submission
48
+ * — a disabled select vanishes from it and fails its own validation.
49
+ */
50
+ disabled?: boolean;
51
+
52
+ /** Seeds the field and marks the matching option `selected`, so native
53
+ * reset restores it. Omitted with a placeholder present, the field is
54
+ * seeded with "" and the placeholder is the initial state. */
55
+ initialValue?: string;
56
+
57
+ /** Extra classes for the outer field wrapper. */
58
+ class?: string;
59
+ /** Extra classes for the <label> element. */
60
+ labelClass?: string;
61
+ /** Extra classes for the <select> element. */
62
+ selectClass?: string;
63
+ /** Extra classes for the required/optional marker. */
64
+ markerClass?: string;
65
+ /** Extra classes for the error <ul>. */
66
+ errorClass?: string;
67
+ }
68
+
69
+ const {
70
+ field,
71
+ label,
72
+
73
+ options,
74
+ placeholder,
75
+
76
+ labelStyle,
77
+
78
+ required = false,
79
+ disabled = false,
80
+
81
+ initialValue,
82
+
83
+ class: classes,
84
+ labelClass,
85
+ selectClass,
86
+ markerClass,
87
+ errorClass,
88
+ }: Props = $props();
89
+
90
+ // With a placeholder, the natural empty state is the placeholder option —
91
+ // so an unseeded field is seeded with "". Without the seed, browsers select
92
+ // the first enabled option (skipping the disabled placeholder) while the
93
+ // field state stays unset, so the submission would carry no value at all.
94
+ // svelte-ignore state_referenced_locally
95
+ const seed = initialValue ?? (placeholder !== undefined ? "" : undefined);
96
+
97
+ const attributes = $derived(
98
+ seed === undefined ? field.as("select") : field.as("select", seed),
99
+ );
100
+
101
+ // The field and seed are stable for the component's lifetime, so capturing
102
+ // the initial name and registration is intentional.
103
+ // svelte-ignore state_referenced_locally
104
+ const name = attributes.name;
105
+
106
+ // svelte-ignore state_referenced_locally
107
+ const wired = wireField({
108
+ name,
109
+ initialValue: seed,
110
+ required,
111
+ issues: () => field.issues(),
112
+ getValue: () => field.value(),
113
+ setValue: (value) => field.set(value as never),
114
+ normalize: (value) => (value == null ? "" : String(value)),
115
+ });
116
+
117
+ // pointer-events-none blocks the mouse while submitting but not the
118
+ // keyboard — swallow value-changing keys too (Tab stays free).
119
+ function lockKeysWhileSubmitting(event: KeyboardEvent) {
120
+ if (!wired.state.isSubmitting) return;
121
+ if (
122
+ [
123
+ "ArrowUp",
124
+ "ArrowDown",
125
+ "ArrowLeft",
126
+ "ArrowRight",
127
+ " ",
128
+ "Enter",
129
+ ].includes(event.key)
130
+ ) {
131
+ event.preventDefault();
132
+ }
133
+ }
134
+ </script>
135
+
136
+ <Select
137
+ {...attributes}
138
+ {label}
139
+ {labelStyle}
140
+ {options}
141
+ {placeholder}
142
+ errors={wired.errors}
143
+ marker={wired.marker}
144
+ aria-invalid={wired.errors.length > 0 ? true : undefined}
145
+ defaultValue={seed}
146
+ onkeydown={lockKeysWhileSubmitting}
147
+ {disabled}
148
+ class={classes}
149
+ {labelClass}
150
+ selectClass={cn(
151
+ wired.state.isSubmitting && "pointer-events-none",
152
+ selectClass,
153
+ )}
154
+ markerClass={cn(required && "text-red-700 dark:text-red-500", markerClass)}
155
+ {errorClass}
156
+ />
@@ -0,0 +1,57 @@
1
+ import type { LabelStyle, SelectOption } from "@privaty/ui/components/types.js";
2
+ import type { SelectField } from "../types/field";
3
+ interface Props {
4
+ /** The SvelteKit remote form field to bind. Structural — anything
5
+ * satisfying the SelectField slice works, e.g. a fake from the public
6
+ * testing subpath. */
7
+ field: SelectField;
8
+ /** Visible label text for the control. */
9
+ label: string;
10
+ /** Options to render, in order. A plain string is shorthand for
11
+ * `{ value: s, label: s }`; values must be unique — they key the
12
+ * rendered list. */
13
+ options: readonly (string | SelectOption)[];
14
+ /** Rendered as a disabled empty option, shown until a value is chosen.
15
+ * Its presence also makes "" the default seed for an unseeded field. */
16
+ placeholder?: string;
17
+ /** Label placement: "top" (default), "left", or "hidden" — floating is
18
+ * not offered for selects. */
19
+ labelStyle?: Exclude<LabelStyle, "floating">;
20
+ /** Marks the field required: feeds the majority-aware required/optional
21
+ * marker (required markers styled red) — forms where at least half the
22
+ * fields are required mark the optional ones instead. Validation itself
23
+ * comes from the field's schema, not this flag, and it is not forwarded
24
+ * as a native `required` attribute. */
25
+ required?: boolean;
26
+ /**
27
+ * Selects have no native readonly, so submitting locks interaction with
28
+ * CSS instead. NEVER disable while submitting: disabled controls are
29
+ * excluded from FormData, and Kit validates live form data mid-submission
30
+ * — a disabled select vanishes from it and fails its own validation.
31
+ */
32
+ disabled?: boolean;
33
+ /** Seeds the field and marks the matching option `selected`, so native
34
+ * reset restores it. Omitted with a placeholder present, the field is
35
+ * seeded with "" and the placeholder is the initial state. */
36
+ initialValue?: string;
37
+ /** Extra classes for the outer field wrapper. */
38
+ class?: string;
39
+ /** Extra classes for the <label> element. */
40
+ labelClass?: string;
41
+ /** Extra classes for the <select> element. */
42
+ selectClass?: string;
43
+ /** Extra classes for the required/optional marker. */
44
+ markerClass?: string;
45
+ /** Extra classes for the error <ul>. */
46
+ errorClass?: string;
47
+ }
48
+ /**
49
+ * Select wired to a SvelteKit remote form field — must render inside a <Form>,
50
+ * whose context it registers with. Shows resolver-translated validation errors
51
+ * once the form state reveals them, plus a majority-aware required/optional
52
+ * marker. While submitting it locks interaction with CSS and key swallowing
53
+ * instead of disabling — a disabled select is excluded from FormData.
54
+ */
55
+ declare const SelectInput: import("svelte").Component<Props, {}, "">;
56
+ type SelectInput = ReturnType<typeof SelectInput>;
57
+ export default SelectInput;