svseeds 0.3.8 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_svseeds/DarkToggle.svelte +8 -4
- package/_svseeds/TagsInput.svelte +51 -97
- package/_svseeds/TagsInput.svelte.d.ts +13 -12
- package/_svseeds/TagsInputField.svelte +169 -0
- package/_svseeds/TagsInputField.svelte.d.ts +35 -0
- package/_svseeds/ToggleGroupField.svelte +134 -0
- package/_svseeds/ToggleGroupField.svelte.d.ts +30 -0
- package/_svseeds/_CheckField.svelte +30 -34
- package/_svseeds/_CheckField.svelte.d.ts +3 -3
- package/_svseeds/_SelectField.svelte +24 -25
- package/_svseeds/_SelectField.svelte.d.ts +2 -2
- package/_svseeds/_TextField.svelte +24 -27
- package/_svseeds/_TextField.svelte.d.ts +2 -2
- package/_svseeds/_Toggle.svelte +5 -6
- package/_svseeds/_Toggle.svelte.d.ts +0 -1
- package/_svseeds/_ToggleGroup.svelte +78 -0
- package/_svseeds/_ToggleGroup.svelte.d.ts +20 -0
- package/index.d.ts +4 -2
- package/index.js +3 -1
- package/package.json +1 -1
- package/_svseeds/_TogglesField.svelte +0 -146
- package/_svseeds/_TogglesField.svelte.d.ts +0 -27
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
options: SvelteMap<string, string> | Map<string, string>,
|
|
4
4
|
label?: string,
|
|
5
5
|
extra?: string,
|
|
6
|
-
aux?: Snippet<[string, string[], HTMLInputElement[]
|
|
6
|
+
aux?: Snippet<[string, string[], HTMLInputElement[]]>, // Snippet<[status,values,elements]>
|
|
7
7
|
bottom?: string,
|
|
8
|
+
descFirst?: boolean, // <false>
|
|
8
9
|
values?: string[], // bindable
|
|
9
10
|
multiple?: boolean, // <true>
|
|
10
|
-
descFirst?: boolean, // <false>
|
|
11
11
|
validations?: CheckFieldValidation[],
|
|
12
12
|
status?: string, // bindable <STATE.DEFAULT>
|
|
13
13
|
style?: SVSStyle,
|
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
};
|
|
18
18
|
export type CheckFieldReqdProps = "options";
|
|
19
19
|
export type CheckFieldBindProps = "values" | "status" | "elements";
|
|
20
|
-
export type CheckFieldValidation = (values: string[],
|
|
20
|
+
export type CheckFieldValidation = (values: string[], validity: ValidityState) => string;
|
|
21
21
|
|
|
22
|
-
type CheckFieldTarget = { currentTarget: EventTarget & HTMLInputElement };
|
|
23
22
|
const preset = "svs-check-field";
|
|
24
23
|
|
|
25
24
|
import { type Snippet, untrack } from "svelte";
|
|
@@ -45,28 +44,23 @@
|
|
|
45
44
|
let message = $state(bottom);
|
|
46
45
|
|
|
47
46
|
// *** Status *** //
|
|
48
|
-
|
|
49
|
-
let neutral = isNeutral(status) ? status : STATE.DEFAULT;
|
|
47
|
+
let neutral = $state(isNeutral(status) ? status : STATE.DEFAULT);
|
|
50
48
|
$effect(() => { neutral = isNeutral(status) ? status : neutral });
|
|
51
49
|
let live = $derived(status === STATE.INACTIVE ? "alert" : "status");
|
|
52
50
|
let invalid = $derived(status === STATE.INACTIVE ? true : undefined);
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
message = stat === STATE.INACTIVE ? msg ?? bottom : bottom;
|
|
59
|
-
elements[0]?.setCustomValidity(msg ?? "");
|
|
51
|
+
let idMsg = $derived(status === STATE.INACTIVE && message?.trim() ? idErr : undefined);
|
|
52
|
+
function shift(oninvalid?: boolean) {
|
|
53
|
+
const vmsg = elements[0]?.validationMessage ?? "";
|
|
54
|
+
status = oninvalid && vmsg ? STATE.INACTIVE : (!values.length || vmsg) ? neutral : STATE.ACTIVE;
|
|
55
|
+
message = status === STATE.INACTIVE ? vmsg ? vmsg : bottom : bottom;
|
|
60
56
|
}
|
|
61
|
-
function
|
|
62
|
-
if (!
|
|
63
|
-
if (!elements[0] || !validations.length) return;
|
|
64
|
-
const validities = elements.map((x) => x.validity);
|
|
57
|
+
function verify() {
|
|
58
|
+
if (!elements[0]) return;
|
|
65
59
|
for (const v of validations) {
|
|
66
|
-
const msg = v(values,
|
|
67
|
-
if (msg) return
|
|
60
|
+
const msg = v(values, elements[0].validity);
|
|
61
|
+
if (msg) return elements[0].setCustomValidity(msg);
|
|
68
62
|
}
|
|
69
|
-
|
|
63
|
+
elements[0].setCustomValidity("");
|
|
70
64
|
}
|
|
71
65
|
|
|
72
66
|
// *** Bind Handlers *** //
|
|
@@ -75,19 +69,20 @@
|
|
|
75
69
|
values;
|
|
76
70
|
untrack(() => validate());
|
|
77
71
|
});
|
|
72
|
+
function validate() {
|
|
73
|
+
verify();
|
|
74
|
+
shift();
|
|
75
|
+
}
|
|
78
76
|
|
|
79
77
|
// *** Event Handlers *** //
|
|
80
|
-
function onchange(ev: Event
|
|
81
|
-
attributes?.onchange?.(ev);
|
|
82
|
-
values = elements.filter((
|
|
83
|
-
phase.change = true;
|
|
78
|
+
function onchange(ev: Event) {
|
|
79
|
+
attributes?.onchange?.(ev as any);
|
|
80
|
+
values = elements.filter((el) => el.checked).map((el) => el.value);
|
|
84
81
|
}
|
|
85
|
-
function oninvalid(ev: Event
|
|
86
|
-
attributes?.oninvalid?.(ev);
|
|
82
|
+
function oninvalid(ev: Event) {
|
|
83
|
+
attributes?.oninvalid?.(ev as any);
|
|
87
84
|
ev.preventDefault();
|
|
88
|
-
|
|
89
|
-
validate(true);
|
|
90
|
-
toInvalid(elements[0]?.validationMessage);
|
|
85
|
+
shift(true);
|
|
91
86
|
}
|
|
92
87
|
</script>
|
|
93
88
|
|
|
@@ -120,15 +115,16 @@
|
|
|
120
115
|
{/if}
|
|
121
116
|
{/snippet}
|
|
122
117
|
{#snippet main()}
|
|
123
|
-
<div class={cls(AREA.MIDDLE, status)} role={roleGroup} aria-describedby={idDesc} aria-invalid={!multiple ? invalid : undefined} aria-errormessage={!multiple
|
|
118
|
+
<div class={cls(AREA.MIDDLE, status)} role={roleGroup} aria-describedby={idDesc} aria-invalid={!multiple ? invalid : undefined} aria-errormessage={!multiple ? idMsg : undefined}>
|
|
124
119
|
{#each opts as {value, text, checked}, i (value)}
|
|
125
|
-
|
|
120
|
+
{@const stat = checked ? STATE.ACTIVE : neutral}
|
|
121
|
+
<label class={cls(AREA.MAIN, stat)}>
|
|
126
122
|
{#if action}
|
|
127
|
-
<input bind:this={elements[i]} class={cls(AREA.LEFT,
|
|
123
|
+
<input bind:this={elements[i]} class={cls(AREA.LEFT, stat)} aria-invalid={multiple ? invalid : undefined} aria-errormessage={multiple ? idMsg : undefined} {value} {name} {type} {checked} {onchange} {oninvalid} {...attrs} use:action />
|
|
128
124
|
{:else}
|
|
129
|
-
<input bind:this={elements[i]} class={cls(AREA.LEFT,
|
|
125
|
+
<input bind:this={elements[i]} class={cls(AREA.LEFT, stat)} aria-invalid={multiple ? invalid : undefined} aria-errormessage={multiple ? idMsg : undefined} {value} {name} {type} {checked} {onchange} {oninvalid} {...attrs} />
|
|
130
126
|
{/if}
|
|
131
|
-
<span class={cls(AREA.RIGHT,
|
|
127
|
+
<span class={cls(AREA.RIGHT, stat)}>{text}</span>
|
|
132
128
|
</label>
|
|
133
129
|
{/each}
|
|
134
130
|
</div>
|
|
@@ -2,11 +2,11 @@ export type CheckFieldProps = {
|
|
|
2
2
|
options: SvelteMap<string, string> | Map<string, string>;
|
|
3
3
|
label?: string;
|
|
4
4
|
extra?: string;
|
|
5
|
-
aux?: Snippet<[string, string[], HTMLInputElement[]
|
|
5
|
+
aux?: Snippet<[string, string[], HTMLInputElement[]]>;
|
|
6
6
|
bottom?: string;
|
|
7
|
+
descFirst?: boolean;
|
|
7
8
|
values?: string[];
|
|
8
9
|
multiple?: boolean;
|
|
9
|
-
descFirst?: boolean;
|
|
10
10
|
validations?: CheckFieldValidation[];
|
|
11
11
|
status?: string;
|
|
12
12
|
style?: SVSStyle;
|
|
@@ -16,7 +16,7 @@ export type CheckFieldProps = {
|
|
|
16
16
|
};
|
|
17
17
|
export type CheckFieldReqdProps = "options";
|
|
18
18
|
export type CheckFieldBindProps = "values" | "status" | "elements";
|
|
19
|
-
export type CheckFieldValidation = (values: string[],
|
|
19
|
+
export type CheckFieldValidation = (values: string[], validity: ValidityState) => string;
|
|
20
20
|
import { type Snippet } from "svelte";
|
|
21
21
|
import { type Action } from "svelte/action";
|
|
22
22
|
import { type SvelteMap } from "svelte/reactivity";
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
left?: Snippet<[string, string, HTMLSelectElement | undefined]>, // Snippet<[status,value,element]>
|
|
8
8
|
right?: Snippet<[string, string, HTMLSelectElement | undefined]>, // Snippet<[status,value,element]>
|
|
9
9
|
bottom?: string,
|
|
10
|
-
value?: string, // bindable
|
|
11
10
|
descFirst?: boolean, // <false>
|
|
11
|
+
value?: string, // bindable
|
|
12
12
|
validations?: SelectFieldValidation[],
|
|
13
13
|
status?: string, // bindable <STATE.DEFAULT>
|
|
14
14
|
style?: SVSStyle,
|
|
@@ -18,9 +18,8 @@
|
|
|
18
18
|
};
|
|
19
19
|
export type SelectFieldReqdProps = "options";
|
|
20
20
|
export type SelectFieldBindProps = "value" | "status" | "element";
|
|
21
|
-
export type SelectFieldValidation = (value: string, validity
|
|
21
|
+
export type SelectFieldValidation = (value: string, validity: ValidityState) => string;
|
|
22
22
|
|
|
23
|
-
type SelectFieldTarget = { currentTarget: EventTarget & HTMLSelectElement };
|
|
24
23
|
const preset = "svs-select-field";
|
|
25
24
|
|
|
26
25
|
import { type Snippet, untrack } from "svelte";
|
|
@@ -31,7 +30,7 @@
|
|
|
31
30
|
</script>
|
|
32
31
|
|
|
33
32
|
<script lang="ts">
|
|
34
|
-
let { options, label, extra, aux, left, right, bottom, value = $bindable(""),
|
|
33
|
+
let { options, label, extra, aux, left, right, bottom, descFirst = false, value = $bindable(""), validations = [], status = $bindable(""), style, attributes, action, element = $bindable() }: SelectFieldProps = $props();
|
|
35
34
|
|
|
36
35
|
// *** Initialize *** //
|
|
37
36
|
if (!status) status = STATE.DEFAULT;
|
|
@@ -45,25 +44,22 @@
|
|
|
45
44
|
|
|
46
45
|
// *** Status *** //
|
|
47
46
|
let neutral = isNeutral(status) ? status : STATE.DEFAULT;
|
|
48
|
-
$effect(() => { neutral = isNeutral(status) ? status : neutral });
|
|
47
|
+
$effect(() => { neutral = isNeutral(status) ? status : neutral; });
|
|
49
48
|
let live = $derived(status === STATE.INACTIVE ? "alert" : "status");
|
|
50
49
|
let invalid = $derived(status === STATE.INACTIVE ? true : undefined);
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
message = msg ?? bottom;
|
|
57
|
-
element?.setCustomValidity(msg ?? "");
|
|
50
|
+
let idMsg = $derived(status === STATE.INACTIVE && message?.trim() ? idErr : undefined);
|
|
51
|
+
function shift(oninvalid?: boolean) {
|
|
52
|
+
const vmsg = element?.validationMessage ?? "";
|
|
53
|
+
status = !value && !oninvalid ? neutral : vmsg ? STATE.INACTIVE : STATE.ACTIVE;
|
|
54
|
+
message = status === STATE.INACTIVE ? vmsg ? vmsg : bottom : bottom;
|
|
58
55
|
}
|
|
59
|
-
function
|
|
60
|
-
if (!
|
|
61
|
-
if (!element || !validations.length) return;
|
|
56
|
+
function verify() {
|
|
57
|
+
if (!element) return;
|
|
62
58
|
for (const v of validations) {
|
|
63
|
-
const msg = v(value, element
|
|
64
|
-
if (msg) return
|
|
59
|
+
const msg = v(value, element.validity);
|
|
60
|
+
if (msg) return element.setCustomValidity(msg);
|
|
65
61
|
}
|
|
66
|
-
|
|
62
|
+
element.setCustomValidity("");
|
|
67
63
|
}
|
|
68
64
|
|
|
69
65
|
// *** Bind Handlers *** //
|
|
@@ -72,14 +68,18 @@
|
|
|
72
68
|
value;
|
|
73
69
|
untrack(() => validate());
|
|
74
70
|
});
|
|
71
|
+
function validate() {
|
|
72
|
+
verify();
|
|
73
|
+
shift();
|
|
74
|
+
}
|
|
75
75
|
|
|
76
76
|
/*** Handle events ***/
|
|
77
|
-
function oninvalid(ev: Event
|
|
78
|
-
attributes?.oninvalid?.(ev);
|
|
77
|
+
function oninvalid(ev: Event) {
|
|
78
|
+
attributes?.oninvalid?.(ev as any);
|
|
79
79
|
ev.preventDefault();
|
|
80
|
-
|
|
81
|
-
toInvalid(element?.validationMessage);
|
|
80
|
+
shift(true);
|
|
82
81
|
}
|
|
82
|
+
$effect(() => untrack(() => verify()));
|
|
83
83
|
</script>
|
|
84
84
|
|
|
85
85
|
<!---------------------------------------->
|
|
@@ -121,13 +121,12 @@
|
|
|
121
121
|
{/snippet}
|
|
122
122
|
{#snippet main()}
|
|
123
123
|
{@const c = cls(AREA.MAIN, status)}
|
|
124
|
-
{@const msg = message?.trim() ? errMsg : undefined}
|
|
125
124
|
{#if action}
|
|
126
|
-
<select bind:value bind:this={element} class={c} {id} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={
|
|
125
|
+
<select bind:value bind:this={element} class={c} {id} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={idMsg} use:action>
|
|
127
126
|
{@render option()}
|
|
128
127
|
</select>
|
|
129
128
|
{:else}
|
|
130
|
-
<select bind:value bind:this={element} class={c} {id} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={
|
|
129
|
+
<select bind:value bind:this={element} class={c} {id} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={idMsg}>
|
|
131
130
|
{@render option()}
|
|
132
131
|
</select>
|
|
133
132
|
{/if}
|
|
@@ -6,8 +6,8 @@ export type SelectFieldProps = {
|
|
|
6
6
|
left?: Snippet<[string, string, HTMLSelectElement | undefined]>;
|
|
7
7
|
right?: Snippet<[string, string, HTMLSelectElement | undefined]>;
|
|
8
8
|
bottom?: string;
|
|
9
|
-
value?: string;
|
|
10
9
|
descFirst?: boolean;
|
|
10
|
+
value?: string;
|
|
11
11
|
validations?: SelectFieldValidation[];
|
|
12
12
|
status?: string;
|
|
13
13
|
style?: SVSStyle;
|
|
@@ -17,7 +17,7 @@ export type SelectFieldProps = {
|
|
|
17
17
|
};
|
|
18
18
|
export type SelectFieldReqdProps = "options";
|
|
19
19
|
export type SelectFieldBindProps = "value" | "status" | "element";
|
|
20
|
-
export type SelectFieldValidation = (value: string, validity
|
|
20
|
+
export type SelectFieldValidation = (value: string, validity: ValidityState) => string;
|
|
21
21
|
import { type Snippet } from "svelte";
|
|
22
22
|
import { type Action } from "svelte/action";
|
|
23
23
|
import { type SvelteMap } from "svelte/reactivity";
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
left?: Snippet<[string, string, HTMLInputElement | HTMLTextAreaElement | undefined]>, // Snippet<[status,value,element]>
|
|
7
7
|
right?: Snippet<[string, string, HTMLInputElement | HTMLTextAreaElement | undefined]>, // Snippet<[status,value,element]>
|
|
8
8
|
bottom?: string,
|
|
9
|
+
descFirst?: boolean, // <false>
|
|
9
10
|
value?: string, // bindable
|
|
10
11
|
type?: "text" | "area" | "email" | "password" | "search" | "tel" | "url" | "number", // bindable <"text">
|
|
11
12
|
options?: SvelteSet<string> | Set<string>,
|
|
12
|
-
descFirst?: boolean, // <false>
|
|
13
13
|
validations?: TextFieldValidation[],
|
|
14
14
|
status?: string, // bindable <STATE.DEFAULT>
|
|
15
15
|
style?: SVSStyle,
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
};
|
|
20
20
|
export type TextFieldReqdProps = never;
|
|
21
21
|
export type TextFieldBindProps = "value" | "type" | "status" | "element";
|
|
22
|
-
export type TextFieldValidation = (value: string, validity
|
|
22
|
+
export type TextFieldValidation = (value: string, validity: ValidityState) => string;
|
|
23
23
|
|
|
24
24
|
const preset = "svs-text-field";
|
|
25
25
|
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
</script>
|
|
32
32
|
|
|
33
33
|
<script lang="ts">
|
|
34
|
-
let { label, extra, aux, left, right, bottom, value = $bindable(""), type = $bindable("text"), options,
|
|
34
|
+
let { label, extra, aux, left, right, bottom, descFirst = false, value = $bindable(""), type = $bindable("text"), options, validations = [], status = $bindable(""), style, attributes, action, element = $bindable() }: TextFieldProps = $props();
|
|
35
35
|
|
|
36
36
|
// *** Initialize *** //
|
|
37
37
|
if (!status) status = STATE.DEFAULT;
|
|
@@ -49,32 +49,30 @@
|
|
|
49
49
|
$effect(() => { neutral = isNeutral(status) ? status : neutral });
|
|
50
50
|
let live = $derived(status === STATE.INACTIVE ? "alert" : "status");
|
|
51
51
|
let invalid = $derived(status === STATE.INACTIVE ? true : undefined);
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
message = msg ?? bottom;
|
|
58
|
-
element?.setCustomValidity(msg ?? "");
|
|
52
|
+
let idMsg = $derived(status === STATE.INACTIVE && message?.trim() ? idErr : undefined);
|
|
53
|
+
function shift(oninvalid?: boolean) {
|
|
54
|
+
const vmsg = element?.validationMessage ?? "";
|
|
55
|
+
status = !value && !oninvalid ? neutral : vmsg ? STATE.INACTIVE : STATE.ACTIVE;
|
|
56
|
+
message = status === STATE.INACTIVE ? vmsg ? vmsg : bottom : bottom;
|
|
59
57
|
}
|
|
60
|
-
function
|
|
61
|
-
if (!
|
|
62
|
-
if (!element || !validations.length) return;
|
|
58
|
+
function verify() {
|
|
59
|
+
if (!element) return;
|
|
63
60
|
for (const v of validations) {
|
|
64
|
-
const msg = v(value, element
|
|
65
|
-
if (msg) return
|
|
61
|
+
const msg = v(value, element.validity);
|
|
62
|
+
if (msg) return element.setCustomValidity(msg);
|
|
66
63
|
}
|
|
67
|
-
|
|
64
|
+
element.setCustomValidity("");
|
|
68
65
|
}
|
|
69
66
|
|
|
70
67
|
// *** Bind Handlers *** //
|
|
71
68
|
$effect.pre(() => {
|
|
72
69
|
value;
|
|
73
|
-
untrack(() =>
|
|
70
|
+
untrack(() => validate(true));
|
|
74
71
|
});
|
|
75
|
-
function
|
|
76
|
-
if (isNeutral(status)) return;
|
|
77
|
-
|
|
72
|
+
function validate(effect?: boolean) {
|
|
73
|
+
if (effect && isNeutral(status)) return;
|
|
74
|
+
verify();
|
|
75
|
+
shift();
|
|
78
76
|
}
|
|
79
77
|
|
|
80
78
|
// *** Event Handlers *** //
|
|
@@ -85,9 +83,9 @@
|
|
|
85
83
|
function oninvalid(ev: Event) {
|
|
86
84
|
attributes?.oninvalid?.(ev as any);
|
|
87
85
|
ev.preventDefault();
|
|
88
|
-
|
|
89
|
-
toInvalid(element?.validationMessage);
|
|
86
|
+
shift(true);
|
|
90
87
|
}
|
|
88
|
+
$effect(() => untrack(() => verify()));
|
|
91
89
|
</script>
|
|
92
90
|
|
|
93
91
|
<!---------------------------------------->
|
|
@@ -127,18 +125,17 @@
|
|
|
127
125
|
{/snippet}
|
|
128
126
|
{#snippet main()}
|
|
129
127
|
{@const c = cls(AREA.MAIN, status)}
|
|
130
|
-
{@const msg = message?.trim() ? errMsg : undefined}
|
|
131
128
|
{#if type === "area"}
|
|
132
129
|
{#if action}
|
|
133
|
-
<textarea bind:value bind:this={element} class={c} {id} {onchange} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={
|
|
130
|
+
<textarea bind:value bind:this={element} class={c} {id} {onchange} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={idMsg} use:action></textarea>
|
|
134
131
|
{:else}
|
|
135
|
-
<textarea bind:value bind:this={element} class={c} {id} {onchange} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={
|
|
132
|
+
<textarea bind:value bind:this={element} class={c} {id} {onchange} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={idMsg}></textarea>
|
|
136
133
|
{/if}
|
|
137
134
|
{:else}
|
|
138
135
|
{#if action}
|
|
139
|
-
<input bind:value bind:this={element} class={c} list={idList} {id} {type} {onchange} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={
|
|
136
|
+
<input bind:value bind:this={element} class={c} list={idList} {id} {type} {onchange} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={idMsg} use:action />
|
|
140
137
|
{:else}
|
|
141
|
-
<input bind:value bind:this={element} class={c} list={idList} {id} {type} {onchange} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={
|
|
138
|
+
<input bind:value bind:this={element} class={c} list={idList} {id} {type} {onchange} {oninvalid} {...attrs} aria-describedby={idDesc} aria-invalid={invalid} aria-errormessage={idMsg} />
|
|
142
139
|
{/if}
|
|
143
140
|
{#if options?.size}
|
|
144
141
|
<datalist id={idList}>
|
|
@@ -5,10 +5,10 @@ export type TextFieldProps = {
|
|
|
5
5
|
left?: Snippet<[string, string, HTMLInputElement | HTMLTextAreaElement | undefined]>;
|
|
6
6
|
right?: Snippet<[string, string, HTMLInputElement | HTMLTextAreaElement | undefined]>;
|
|
7
7
|
bottom?: string;
|
|
8
|
+
descFirst?: boolean;
|
|
8
9
|
value?: string;
|
|
9
10
|
type?: "text" | "area" | "email" | "password" | "search" | "tel" | "url" | "number";
|
|
10
11
|
options?: SvelteSet<string> | Set<string>;
|
|
11
|
-
descFirst?: boolean;
|
|
12
12
|
validations?: TextFieldValidation[];
|
|
13
13
|
status?: string;
|
|
14
14
|
style?: SVSStyle;
|
|
@@ -18,7 +18,7 @@ export type TextFieldProps = {
|
|
|
18
18
|
};
|
|
19
19
|
export type TextFieldReqdProps = never;
|
|
20
20
|
export type TextFieldBindProps = "value" | "type" | "status" | "element";
|
|
21
|
-
export type TextFieldValidation = (value: string, validity
|
|
21
|
+
export type TextFieldValidation = (value: string, validity: ValidityState) => string;
|
|
22
22
|
import { type Snippet } from "svelte";
|
|
23
23
|
import { type Action } from "svelte/action";
|
|
24
24
|
import { type SvelteSet } from "svelte/reactivity";
|
package/_svseeds/_Toggle.svelte
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
export type ToggleProps = {
|
|
3
|
-
label?: string, // for aria-label; should be used if no label tag or no text in main
|
|
4
3
|
main?: Snippet<[string, boolean, HTMLButtonElement | undefined]>, // Snippet<[status,value,element]>
|
|
5
4
|
left?: Snippet<[string, boolean, HTMLButtonElement | undefined]>, // Snippet<[status,value,element]>
|
|
6
5
|
right?: Snippet<[string, boolean, HTMLButtonElement | undefined]>, // Snippet<[status,value,element]>
|
|
@@ -25,7 +24,7 @@
|
|
|
25
24
|
</script>
|
|
26
25
|
|
|
27
26
|
<script lang="ts">
|
|
28
|
-
let {
|
|
27
|
+
let { main, left, right, value = $bindable(false), type = "button", status = $bindable(""), style, attributes, action, element = $bindable() }: ToggleProps = $props();
|
|
29
28
|
|
|
30
29
|
// *** Initialize *** //
|
|
31
30
|
if (!status) status = STATE.DEFAULT;
|
|
@@ -75,22 +74,22 @@
|
|
|
75
74
|
{@const c = cls(AREA.MAIN, status)}
|
|
76
75
|
{#if role === "button"}
|
|
77
76
|
{#if action}
|
|
78
|
-
<button bind:this={element} class={c} type="button" aria-pressed={value}
|
|
77
|
+
<button bind:this={element} class={c} type="button" aria-pressed={value} {onclick} {...attrs} use:action>
|
|
79
78
|
{@render contents()}
|
|
80
79
|
</button>
|
|
81
80
|
{:else}
|
|
82
|
-
<button bind:this={element} class={c} type="button" aria-pressed={value}
|
|
81
|
+
<button bind:this={element} class={c} type="button" aria-pressed={value} {onclick} {...attrs}>
|
|
83
82
|
{@render contents()}
|
|
84
83
|
</button>
|
|
85
84
|
{/if}
|
|
86
85
|
{:else}
|
|
87
86
|
{@const style = "position: relative;"}
|
|
88
87
|
{#if action}
|
|
89
|
-
<button bind:this={element} class={c} {style} type="button" {role} aria-checked={value}
|
|
88
|
+
<button bind:this={element} class={c} {style} type="button" {role} aria-checked={value} {onclick} {...attrs} use:action>
|
|
90
89
|
{@render thumb()}
|
|
91
90
|
</button>
|
|
92
91
|
{:else}
|
|
93
|
-
<button bind:this={element} class={c} {style} type="button" {role} aria-checked={value}
|
|
92
|
+
<button bind:this={element} class={c} {style} type="button" {role} aria-checked={value} {onclick} {...attrs}>
|
|
94
93
|
{@render thumb()}
|
|
95
94
|
</button>
|
|
96
95
|
{/if}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
export type ToggleGroupProps = {
|
|
3
|
+
options: SvelteMap<string, string> | Map<string, string>,
|
|
4
|
+
values?: string[], // bindable
|
|
5
|
+
multiple?: boolean, // <true>
|
|
6
|
+
ariaDescId?: string,
|
|
7
|
+
ariaErrMsgId?: string, // bindable
|
|
8
|
+
status?: string, // bindable <STATE.DEFAULT>
|
|
9
|
+
style?: SVSStyle,
|
|
10
|
+
action?: Action,
|
|
11
|
+
[key: string]: unknown | Snippet<[string]>,
|
|
12
|
+
};
|
|
13
|
+
export type ToggleGroupReqdProps = "options";
|
|
14
|
+
export type ToggleGroupBindProps = "values" | "ariaErrMsgId" | "status";
|
|
15
|
+
|
|
16
|
+
const preset = "svs-toggle-group";
|
|
17
|
+
|
|
18
|
+
function getSnippet(text: string, rest: Record<string, unknown>): Snippet<[string]> | undefined {
|
|
19
|
+
if (!Object.hasOwn(rest, text)) return;
|
|
20
|
+
if (typeof rest[text] !== "function") return;
|
|
21
|
+
return rest[text] as Snippet<[string]>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
import { type Snippet } from "svelte";
|
|
25
|
+
import { type Action } from "svelte/action";
|
|
26
|
+
import { type SvelteMap } from "svelte/reactivity";
|
|
27
|
+
import { type SVSStyle, STATE, AREA, fnClass } from "./core";
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<script lang="ts">
|
|
31
|
+
let { options, values = $bindable([]), multiple = true, ariaDescId, ariaErrMsgId = $bindable(), status = $bindable(""), style, attributes, action, ...rest }: ToggleGroupProps = $props();
|
|
32
|
+
|
|
33
|
+
// *** Initialize *** //
|
|
34
|
+
if (!status) status = STATE.DEFAULT;
|
|
35
|
+
const cls = fnClass(preset, style);
|
|
36
|
+
const role = multiple ? "checkbox" : "radio";
|
|
37
|
+
const roleGroup = multiple ? "group" : "radiogroup";
|
|
38
|
+
|
|
39
|
+
// *** Bind Handlers *** //
|
|
40
|
+
let opts = $derived([...options.entries().map(([value, text]) => ({ value, text, checked: values.includes(value) }))]);
|
|
41
|
+
let invalid = $derived(ariaErrMsgId ? true : undefined);
|
|
42
|
+
|
|
43
|
+
// *** Event Handlers *** //
|
|
44
|
+
const update = multiple
|
|
45
|
+
? (value: string) => (values.includes(value) ? values.filter((x) => x !== value) : opts.map((x) => x.value).filter((x) => [...values, value].includes(x)))
|
|
46
|
+
: (value: string) => (values.includes(value) ? [] : [value]);
|
|
47
|
+
function updateValues(value: string): () => void {
|
|
48
|
+
return () => values = update(value);
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<!---------------------------------------->
|
|
53
|
+
|
|
54
|
+
{#if opts.length}
|
|
55
|
+
<span class={cls(AREA.WHOLE, status)} role={roleGroup} aria-describedby={ariaDescId} aria-invalid={!multiple ? invalid : undefined} aria-errormessage={!multiple ? ariaErrMsgId : undefined}>
|
|
56
|
+
{#each opts as { value, text, checked } (value)}
|
|
57
|
+
{@const c = cls(AREA.MAIN, checked ? STATE.ACTIVE : status)}
|
|
58
|
+
{#if action}
|
|
59
|
+
<button class={c} aria-checked={checked} aria-invalid={multiple ? invalid : undefined} aria-errormessage={multiple ? ariaErrMsgId : undefined} onclick={updateValues(value)} type="button" {role} use:action>
|
|
60
|
+
{@render content(value, text)}
|
|
61
|
+
</button>
|
|
62
|
+
{:else}
|
|
63
|
+
<button class={c} aria-checked={checked} aria-invalid={multiple ? invalid : undefined} aria-errormessage={multiple ? ariaErrMsgId : undefined} onclick={updateValues(value)} type="button" {role}>
|
|
64
|
+
{@render content(value, text)}
|
|
65
|
+
</button>
|
|
66
|
+
{/if}
|
|
67
|
+
{/each}
|
|
68
|
+
</span>
|
|
69
|
+
{/if}
|
|
70
|
+
|
|
71
|
+
{#snippet content(value: string, text: string)}
|
|
72
|
+
{@const snippet = getSnippet(text, rest)}
|
|
73
|
+
{#if snippet}
|
|
74
|
+
{@render snippet(value)}
|
|
75
|
+
{:else}
|
|
76
|
+
{text}
|
|
77
|
+
{/if}
|
|
78
|
+
{/snippet}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type ToggleGroupProps = {
|
|
2
|
+
options: SvelteMap<string, string> | Map<string, string>;
|
|
3
|
+
values?: string[];
|
|
4
|
+
multiple?: boolean;
|
|
5
|
+
ariaDescId?: string;
|
|
6
|
+
ariaErrMsgId?: string;
|
|
7
|
+
status?: string;
|
|
8
|
+
style?: SVSStyle;
|
|
9
|
+
action?: Action;
|
|
10
|
+
[key: string]: unknown | Snippet<[string]>;
|
|
11
|
+
};
|
|
12
|
+
export type ToggleGroupReqdProps = "options";
|
|
13
|
+
export type ToggleGroupBindProps = "values" | "ariaErrMsgId" | "status";
|
|
14
|
+
import { type Snippet } from "svelte";
|
|
15
|
+
import { type Action } from "svelte/action";
|
|
16
|
+
import { type SvelteMap } from "svelte/reactivity";
|
|
17
|
+
import { type SVSStyle } from "./core";
|
|
18
|
+
declare const ToggleGroup: import("svelte").Component<ToggleGroupProps, {}, "status" | "values" | "ariaErrMsgId">;
|
|
19
|
+
type ToggleGroup = ReturnType<typeof ToggleGroup>;
|
|
20
|
+
export default ToggleGroup;
|
package/index.d.ts
CHANGED
|
@@ -15,8 +15,10 @@ export { default as Sortable, type SortableProps, type SortableReqdProps, type S
|
|
|
15
15
|
export { default as Tabs, type TabsProps, type TabsReqdProps, type TabsBindProps } from "./_svseeds/_Tabs.svelte";
|
|
16
16
|
export { default as TextField, type TextFieldProps, type TextFieldReqdProps, type TextFieldBindProps, type TextFieldValidation } from "./_svseeds/_TextField.svelte";
|
|
17
17
|
export { default as Toggle, type ToggleProps, type ToggleReqdProps, type ToggleBindProps } from "./_svseeds/_Toggle.svelte";
|
|
18
|
-
export { default as
|
|
18
|
+
export { default as ToggleGroup, type ToggleGroupProps, type ToggleGroupReqdProps, type ToggleGroupBindProps } from "./_svseeds/_ToggleGroup.svelte";
|
|
19
19
|
export { default as Tooltip, type TooltipProps, type TooltipReqdProps, type TooltipBindProps, type Vector, type Position, type Align, tooltip, tooltipAction } from "./_svseeds/_Tooltip.svelte";
|
|
20
20
|
export { default as Accordion, type AccordionProps, type AccordionDeps, type AccordionReqdProps, type AccordionBindProps } from "./_svseeds/Accordion.svelte";
|
|
21
21
|
export { default as DarkToggle, type DarkToggleProps, type DarkToggleDeps, type DarkToggleReqdProps, type DarkToggleBindProps } from "./_svseeds/DarkToggle.svelte";
|
|
22
|
-
export { default as TagsInput, type TagsInputProps, type TagsInputDeps, type TagsInputReqdProps, type TagsInputBindProps, type
|
|
22
|
+
export { default as TagsInput, type TagsInputProps, type TagsInputDeps, type TagsInputReqdProps, type TagsInputBindProps, type TagsInputEvents } from "./_svseeds/TagsInput.svelte";
|
|
23
|
+
export { default as TagsInputField, type TagsInputFieldProps, type TagsInputFieldDeps, type TagsInputFieldReqdProps, type TagsInputFieldBindProps, type TagsInputFieldConstraint, type TagsInputFieldValidation, type TagsInputFieldCountValidation } from "./_svseeds/TagsInputField.svelte";
|
|
24
|
+
export { default as ToggleGroupField, type ToggleGroupFieldProps, type ToggleGroupFieldDeps, type ToggleGroupFieldReqdProps, type ToggleGroupFieldBindProps, type ToggleGroupFieldValidation } from "./_svseeds/ToggleGroupField.svelte";
|
package/index.js
CHANGED
|
@@ -15,8 +15,10 @@ export { default as Sortable, SortableItems } from "./_svseeds/_Sortable.svelte"
|
|
|
15
15
|
export { default as Tabs } from "./_svseeds/_Tabs.svelte";
|
|
16
16
|
export { default as TextField } from "./_svseeds/_TextField.svelte";
|
|
17
17
|
export { default as Toggle } from "./_svseeds/_Toggle.svelte";
|
|
18
|
-
export { default as
|
|
18
|
+
export { default as ToggleGroup } from "./_svseeds/_ToggleGroup.svelte";
|
|
19
19
|
export { default as Tooltip, tooltip, tooltipAction } from "./_svseeds/_Tooltip.svelte";
|
|
20
20
|
export { default as Accordion } from "./_svseeds/Accordion.svelte";
|
|
21
21
|
export { default as DarkToggle } from "./_svseeds/DarkToggle.svelte";
|
|
22
22
|
export { default as TagsInput } from "./_svseeds/TagsInput.svelte";
|
|
23
|
+
export { default as TagsInputField } from "./_svseeds/TagsInputField.svelte";
|
|
24
|
+
export { default as ToggleGroupField } from "./_svseeds/ToggleGroupField.svelte";
|