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
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
<script module lang="ts">
|
|
2
|
-
export type TogglesFieldProps = {
|
|
3
|
-
options: SvelteMap<string, string> | Map<string, string>,
|
|
4
|
-
label?: string,
|
|
5
|
-
extra?: string,
|
|
6
|
-
aux?: Snippet<[string, string[], HTMLButtonElement[] | undefined]>, // Snippet<[status,values,elements]>
|
|
7
|
-
bottom?: string,
|
|
8
|
-
values?: string[], // bindable
|
|
9
|
-
multiple?: boolean, // <true>
|
|
10
|
-
descFirst?: boolean, // <false>
|
|
11
|
-
validations?: TogglesFieldValidation[],
|
|
12
|
-
status?: string, // bindable <STATE.DEFAULT>
|
|
13
|
-
style?: SVSStyle,
|
|
14
|
-
attributes?: HTMLButtonAttributes;
|
|
15
|
-
action?: Action,
|
|
16
|
-
elements?: HTMLButtonElement[], // bindable
|
|
17
|
-
};
|
|
18
|
-
export type TogglesFieldReqdProps = "options";
|
|
19
|
-
export type TogglesFieldBindProps = "values" | "status" | "elements";
|
|
20
|
-
export type TogglesFieldValidation = (values: string[], validities?: ValidityState[]) => string;
|
|
21
|
-
|
|
22
|
-
type TogglesFieldTarget = { currentTarget: EventTarget & HTMLButtonElement };
|
|
23
|
-
const preset = "svs-toggles-field";
|
|
24
|
-
|
|
25
|
-
import { type Snippet, untrack } from "svelte";
|
|
26
|
-
import { type Action } from "svelte/action";
|
|
27
|
-
import { type SvelteMap } from "svelte/reactivity";
|
|
28
|
-
import { type HTMLButtonAttributes } from "svelte/elements";
|
|
29
|
-
import { type SVSStyle, STATE, AREA, elemId, fnClass, isNeutral, omit } from "./core";
|
|
30
|
-
</script>
|
|
31
|
-
|
|
32
|
-
<script lang="ts">
|
|
33
|
-
let { options, label, extra, aux, bottom, values = $bindable([]), multiple = true, descFirst = false, validations = [], status = $bindable(""), style, attributes, action, elements = $bindable([]) }: TogglesFieldProps = $props();
|
|
34
|
-
|
|
35
|
-
// *** Initialize *** //
|
|
36
|
-
if (!status) status = STATE.DEFAULT;
|
|
37
|
-
const cls = fnClass(preset, style);
|
|
38
|
-
const role = multiple ? "checkbox" : "radio";
|
|
39
|
-
const idLabel = elemId.get(label?.trim());
|
|
40
|
-
const idDesc = elemId.get(bottom?.trim());
|
|
41
|
-
const idErr = idDesc ?? elemId.id;
|
|
42
|
-
const attrs = omit(attributes, "class", "id", "type", "role", "aria-checked", "onclick", "oninvalid");
|
|
43
|
-
const roleGroup = multiple ? "group" : "radiogroup";
|
|
44
|
-
let message = $state(bottom);
|
|
45
|
-
let elem: HTMLInputElement | undefined = $state();
|
|
46
|
-
|
|
47
|
-
// *** Status *** //
|
|
48
|
-
const phase = { change: false, submit: false };
|
|
49
|
-
let neutral = isNeutral(status) ? status : STATE.DEFAULT;
|
|
50
|
-
$effect(() => { neutral = isNeutral(status) ? status : neutral });
|
|
51
|
-
let live = $derived(status === STATE.INACTIVE ? "alert" : "status");
|
|
52
|
-
let invalid = $derived(status === STATE.INACTIVE ? true : undefined);
|
|
53
|
-
let errMsg = $derived(status === STATE.INACTIVE ? idErr : undefined);
|
|
54
|
-
const toInvalid = (msg?: string) => shiftStatus(phase.submit ? STATE.INACTIVE : neutral, msg);
|
|
55
|
-
const toNonInvalid = () => shiftStatus(phase.change && values.length ? STATE.ACTIVE : neutral);
|
|
56
|
-
function shiftStatus(stat: string, msg?: string) {
|
|
57
|
-
status = stat;
|
|
58
|
-
message = stat === STATE.INACTIVE ? msg ?? bottom : bottom;
|
|
59
|
-
elem?.setCustomValidity(msg ?? "");
|
|
60
|
-
}
|
|
61
|
-
function validate(oninvalid?: boolean) {
|
|
62
|
-
if (!values.length && !oninvalid) return toNonInvalid();
|
|
63
|
-
if (!elem || !validations.length) return;
|
|
64
|
-
const validities = elements.map((x) => x.validity);
|
|
65
|
-
for (const v of validations) {
|
|
66
|
-
const msg = v(values, validities);
|
|
67
|
-
if (msg) return toInvalid(msg);
|
|
68
|
-
}
|
|
69
|
-
toNonInvalid();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// *** Bind Handlers *** //
|
|
73
|
-
let opts = $derived([...options.entries().map(([value, text]) => ({ value, text, checked: values.includes(value) }))]);
|
|
74
|
-
$effect.pre(() => {
|
|
75
|
-
values;
|
|
76
|
-
untrack(() => validate());
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// *** Event Handlers *** //
|
|
80
|
-
function updateValues(value: string): (ev: MouseEvent & TogglesFieldTarget) => void {
|
|
81
|
-
return (ev) => {
|
|
82
|
-
if (!multiple) return values = [value];
|
|
83
|
-
values = values.includes(value) ? values.filter((x) => x !== value) : opts.map((x) => x.value).filter((x) => [...values, value].includes(x));
|
|
84
|
-
attributes?.onclick?.(ev);
|
|
85
|
-
phase.change = true;
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
function oninvalid(ev: Event) {
|
|
89
|
-
attributes?.oninvalid?.(ev as any);
|
|
90
|
-
ev.preventDefault();
|
|
91
|
-
phase.submit = true;
|
|
92
|
-
validate(true);
|
|
93
|
-
toInvalid(elem?.validationMessage);
|
|
94
|
-
}
|
|
95
|
-
</script>
|
|
96
|
-
|
|
97
|
-
<!---------------------------------------->
|
|
98
|
-
|
|
99
|
-
{#if opts.length}
|
|
100
|
-
<div class={cls(AREA.WHOLE, status)} role="group" aria-labelledby={idLabel}>
|
|
101
|
-
{#if aux}
|
|
102
|
-
<div class={cls(AREA.TOP, status)}>
|
|
103
|
-
{@render lbl()}
|
|
104
|
-
<span class={cls(AREA.AUX, status)}>{@render aux(status, values, elements)}</span>
|
|
105
|
-
</div>
|
|
106
|
-
{:else}
|
|
107
|
-
{@render lbl()}
|
|
108
|
-
{/if}
|
|
109
|
-
{@render desc(descFirst)}
|
|
110
|
-
{@render main()}
|
|
111
|
-
{@render desc(!descFirst)}
|
|
112
|
-
</div>
|
|
113
|
-
{/if}
|
|
114
|
-
|
|
115
|
-
{#snippet lbl()}
|
|
116
|
-
{#if label?.trim()}
|
|
117
|
-
<span class={cls(AREA.LABEL, status)} id={idLabel}>
|
|
118
|
-
{label}
|
|
119
|
-
{#if extra?.trim()}
|
|
120
|
-
<span class={cls(AREA.EXTRA, status)}>{extra}</span>
|
|
121
|
-
{/if}
|
|
122
|
-
</span>
|
|
123
|
-
{/if}
|
|
124
|
-
{/snippet}
|
|
125
|
-
{#snippet main()}
|
|
126
|
-
{@const c = cls(AREA.MAIN, status)}
|
|
127
|
-
<input bind:this={elem} style="display: none;" aria-hidden="true" {oninvalid} />
|
|
128
|
-
<div class={cls(AREA.MIDDLE, status)} role={roleGroup} aria-describedby={idDesc} aria-invalid={!multiple ? invalid : undefined} aria-errormessage={!multiple && message?.trim() ? errMsg : undefined}>
|
|
129
|
-
{#each opts as { value, text, checked }, i (value)}
|
|
130
|
-
{#if action}
|
|
131
|
-
<button bind:this={elements[i]} class={c} aria-checked={checked} aria-invalid={multiple ? invalid : undefined} onclick={updateValues(value)} type="button" {role} {...attrs} use:action>
|
|
132
|
-
{text}
|
|
133
|
-
</button>
|
|
134
|
-
{:else}
|
|
135
|
-
<button bind:this={elements[i]} class={c} aria-checked={checked} aria-invalid={multiple ? invalid : undefined} onclick={updateValues(value)} type="button" {role} {...attrs}>
|
|
136
|
-
{text}
|
|
137
|
-
</button>
|
|
138
|
-
{/if}
|
|
139
|
-
{/each}
|
|
140
|
-
</div>
|
|
141
|
-
{/snippet}
|
|
142
|
-
{#snippet desc(show: boolean)}
|
|
143
|
-
{#if show && message?.trim()}
|
|
144
|
-
<div class={cls(AREA.BOTTOM, status)} id={idDesc ?? idErr} role={live}>{message}</div>
|
|
145
|
-
{/if}
|
|
146
|
-
{/snippet}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export type TogglesFieldProps = {
|
|
2
|
-
options: SvelteMap<string, string> | Map<string, string>;
|
|
3
|
-
label?: string;
|
|
4
|
-
extra?: string;
|
|
5
|
-
aux?: Snippet<[string, string[], HTMLButtonElement[] | undefined]>;
|
|
6
|
-
bottom?: string;
|
|
7
|
-
values?: string[];
|
|
8
|
-
multiple?: boolean;
|
|
9
|
-
descFirst?: boolean;
|
|
10
|
-
validations?: TogglesFieldValidation[];
|
|
11
|
-
status?: string;
|
|
12
|
-
style?: SVSStyle;
|
|
13
|
-
attributes?: HTMLButtonAttributes;
|
|
14
|
-
action?: Action;
|
|
15
|
-
elements?: HTMLButtonElement[];
|
|
16
|
-
};
|
|
17
|
-
export type TogglesFieldReqdProps = "options";
|
|
18
|
-
export type TogglesFieldBindProps = "values" | "status" | "elements";
|
|
19
|
-
export type TogglesFieldValidation = (values: string[], validities?: ValidityState[]) => string;
|
|
20
|
-
import { type Snippet } from "svelte";
|
|
21
|
-
import { type Action } from "svelte/action";
|
|
22
|
-
import { type SvelteMap } from "svelte/reactivity";
|
|
23
|
-
import { type HTMLButtonAttributes } from "svelte/elements";
|
|
24
|
-
import { type SVSStyle } from "./core";
|
|
25
|
-
declare const TogglesField: import("svelte").Component<TogglesFieldProps, {}, "elements" | "status" | "values">;
|
|
26
|
-
type TogglesField = ReturnType<typeof TogglesField>;
|
|
27
|
-
export default TogglesField;
|