svseeds 0.7.1 → 0.8.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/README.md +1 -1
- package/_svseeds/Accordion.svelte +10 -5
- package/_svseeds/Accordion.svelte.d.ts +3 -3
- package/_svseeds/Calendar.svelte +69 -47
- package/_svseeds/Calendar.svelte.d.ts +37 -35
- package/_svseeds/CheckField.svelte +19 -15
- package/_svseeds/ColorPicker.svelte +8 -4
- package/_svseeds/ColorPicker.svelte.d.ts +6 -3
- package/_svseeds/ComboBox.svelte +5 -7
- package/_svseeds/DarkToggle.svelte +2 -2
- package/_svseeds/DateField.svelte +11 -14
- package/_svseeds/DateInput.svelte +26 -23
- package/_svseeds/DateInput.svelte.d.ts +22 -16
- package/_svseeds/Disclosure.svelte +17 -7
- package/_svseeds/Drawer.svelte +1 -2
- package/_svseeds/Drawer.svelte.d.ts +1 -2
- package/_svseeds/FileField.svelte +19 -15
- package/_svseeds/FileInput.svelte +3 -11
- package/_svseeds/HotkeyCapture.svelte +3 -2
- package/_svseeds/HotkeyCapture.svelte.d.ts +3 -0
- package/_svseeds/Modal.svelte +5 -3
- package/_svseeds/NumberField.svelte +11 -14
- package/_svseeds/NumberInput.svelte +39 -53
- package/_svseeds/NumberInput.svelte.d.ts +11 -21
- package/_svseeds/Pagination.svelte +29 -31
- package/_svseeds/Pagination.svelte.d.ts +16 -13
- package/_svseeds/Popover.svelte +64 -18
- package/_svseeds/Popover.svelte.d.ts +16 -15
- package/_svseeds/SelectField.svelte +10 -13
- package/_svseeds/Sortable.svelte +43 -8
- package/_svseeds/Sortable.svelte.d.ts +8 -3
- package/_svseeds/SortableGroup.svelte +8 -5
- package/_svseeds/SortableGroup.svelte.d.ts +6 -3
- package/_svseeds/Tabs.svelte +22 -19
- package/_svseeds/Tabs.svelte.d.ts +8 -5
- package/_svseeds/TagsInput.svelte +3 -13
- package/_svseeds/TagsInputField.svelte +11 -14
- package/_svseeds/TextField.svelte +10 -13
- package/_svseeds/Toast.svelte +38 -6
- package/_svseeds/Toast.svelte.d.ts +24 -2
- package/_svseeds/Toggle.svelte +1 -1
- package/_svseeds/ToggleGroup.svelte +39 -41
- package/_svseeds/ToggleGroup.svelte.d.ts +13 -10
- package/_svseeds/ToggleGroupField.svelte +29 -29
- package/_svseeds/ToggleGroupField.svelte.d.ts +12 -12
- package/_svseeds/Tooltip.svelte +12 -7
- package/_svseeds/Tooltip.svelte.d.ts +7 -7
- package/_svseeds/WheelPicker.svelte +21 -13
- package/_svseeds/ZSortableA11y.svelte +1082 -0
- package/_svseeds/ZSortableA11y.svelte.d.ts +182 -0
- package/_svseeds/_core.d.ts +37 -1
- package/_svseeds/_core.js +70 -1
- package/index.d.ts +10 -9
- package/index.js +1 -0
- package/package.json +2 -2
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
export const _DATE_FIELD_PRESET = "svs-date-field";
|
|
94
94
|
|
|
95
95
|
import { onMount, untrack } from "svelte";
|
|
96
|
-
import { PARTS, VARIANT, _fnClass, _isNeutral } from "./_core";
|
|
96
|
+
import { PARTS, VARIANT, _fieldAria, _fieldIds, _fieldMessage, _fnClass, _isNeutral, _verify } from "./_core";
|
|
97
97
|
import DateInput, { _DATE_INPUT_PRESET, _setDateInputContext } from "./DateInput.svelte";
|
|
98
98
|
import type { Snippet } from "svelte";
|
|
99
99
|
import type { SVSClass, SVSFieldValidation, SVSVariant } from "./_core";
|
|
@@ -108,12 +108,14 @@
|
|
|
108
108
|
const cls = $derived(_fnClass(_DATE_FIELD_PRESET, styling));
|
|
109
109
|
const uid = $props.id();
|
|
110
110
|
const id = $derived(label?.trim() ? `${uid}-ctrl` : undefined);
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const
|
|
111
|
+
const ids = $derived(_fieldIds(uid, label, bottom));
|
|
112
|
+
const idLabel = $derived(ids.idLabel);
|
|
113
|
+
const idDesc = $derived(ids.idDesc);
|
|
114
|
+
const idErr = $derived(ids.idErr);
|
|
114
115
|
let errmsg = $state("");
|
|
115
|
-
const message = $derived(variant
|
|
116
|
-
const
|
|
116
|
+
const message = $derived(_fieldMessage(variant, errmsg, bottom));
|
|
117
|
+
const aria = $derived(_fieldAria(variant, message, idErr));
|
|
118
|
+
const idMsg = $derived(aria.idMsg);
|
|
117
119
|
let proxyEl = $state<HTMLInputElement>();
|
|
118
120
|
|
|
119
121
|
// *** Initialize Context *** //
|
|
@@ -152,7 +154,7 @@
|
|
|
152
154
|
$effect(() => {
|
|
153
155
|
neutral = _isNeutral(variant) ? variant : neutral;
|
|
154
156
|
});
|
|
155
|
-
const live = $derived(
|
|
157
|
+
const live = $derived(aria.live);
|
|
156
158
|
const validEl = $derived(native ? element : proxyEl);
|
|
157
159
|
function shift(oninvalid?: boolean) {
|
|
158
160
|
const vmsg = validEl?.validationMessage ?? "";
|
|
@@ -160,12 +162,7 @@
|
|
|
160
162
|
errmsg = vmsg;
|
|
161
163
|
}
|
|
162
164
|
function verify() {
|
|
163
|
-
|
|
164
|
-
for (const v of validations) {
|
|
165
|
-
const msg = v({ value, validity: validEl.validity, element: validEl });
|
|
166
|
-
if (msg) return validEl.setCustomValidity(msg);
|
|
167
|
-
}
|
|
168
|
-
validEl.setCustomValidity("");
|
|
165
|
+
_verify(validEl, validations, value);
|
|
169
166
|
}
|
|
170
167
|
|
|
171
168
|
// *** Reactive Handlers *** //
|
|
@@ -229,7 +226,7 @@
|
|
|
229
226
|
{@render participant()}
|
|
230
227
|
</div>
|
|
231
228
|
{#if reserve || message?.trim()}
|
|
232
|
-
<div class={cls(PARTS.BOTTOM, variant)} id={
|
|
229
|
+
<div class={cls(PARTS.BOTTOM, variant)} id={idErr} role={live}>{message}</div>
|
|
233
230
|
{/if}
|
|
234
231
|
</div>
|
|
235
232
|
|
|
@@ -7,10 +7,6 @@
|
|
|
7
7
|
```
|
|
8
8
|
### Types
|
|
9
9
|
```ts
|
|
10
|
-
type TransitionProp = {
|
|
11
|
-
fn?: (node: HTMLElement, params: any, options: { direction: "in" | "out" | "both" }) => import("svelte/transition").TransitionConfig;
|
|
12
|
-
params?: unknown;
|
|
13
|
-
};
|
|
14
10
|
interface DateInputProps extends Omit<HTMLInputAttributes, "type" | "value" | "min" | "max" | "readonly" | "list" | "name"> {
|
|
15
11
|
value?: Temporal.PlainDate; // bindable; undefined = empty
|
|
16
12
|
open?: boolean; // bindable (false)
|
|
@@ -32,6 +28,16 @@
|
|
|
32
28
|
styling?: SVSClass;
|
|
33
29
|
variant?: SVSVariant; // (VARIANT.NEUTRAL)
|
|
34
30
|
}
|
|
31
|
+
type DateInputCtl = {
|
|
32
|
+
toggle: () => void;
|
|
33
|
+
show: () => void;
|
|
34
|
+
hide: () => void;
|
|
35
|
+
clear: () => void;
|
|
36
|
+
};
|
|
37
|
+
type TransitionProp = {
|
|
38
|
+
fn?: (node: HTMLElement, params: any, options: { direction: "in" | "out" | "both" }) => import("svelte/transition").TransitionConfig;
|
|
39
|
+
params?: unknown;
|
|
40
|
+
};
|
|
35
41
|
```
|
|
36
42
|
### Anatomy
|
|
37
43
|
```svelte
|
|
@@ -50,16 +56,6 @@
|
|
|
50
56
|
- `format` and `parse` are caller-coordinated; the default locale display is not necessarily parseable by a supplied parser.
|
|
51
57
|
-->
|
|
52
58
|
<script module lang="ts">
|
|
53
|
-
type DateInputCtl = {
|
|
54
|
-
toggle: () => void;
|
|
55
|
-
show: () => void;
|
|
56
|
-
hide: () => void;
|
|
57
|
-
clear: () => void;
|
|
58
|
-
};
|
|
59
|
-
export type TransitionProp = {
|
|
60
|
-
fn?: (node: HTMLElement, params: any, options: { direction: "in" | "out" | "both" }) => import("svelte/transition").TransitionConfig;
|
|
61
|
-
params?: unknown;
|
|
62
|
-
};
|
|
63
59
|
export interface DateInputProps extends Omit<HTMLInputAttributes, "type" | "value" | "min" | "max" | "readonly" | "list" | "name"> {
|
|
64
60
|
value?: Temporal.PlainDate;
|
|
65
61
|
open?: boolean;
|
|
@@ -81,6 +77,16 @@
|
|
|
81
77
|
styling?: SVSClass;
|
|
82
78
|
variant?: SVSVariant;
|
|
83
79
|
}
|
|
80
|
+
export type DateInputCtl = {
|
|
81
|
+
toggle: () => void;
|
|
82
|
+
show: () => void;
|
|
83
|
+
hide: () => void;
|
|
84
|
+
clear: () => void;
|
|
85
|
+
};
|
|
86
|
+
export type TransitionProp = {
|
|
87
|
+
fn?: (node: HTMLElement, params: any, options: { direction: "in" | "out" | "both" }) => import("svelte/transition").TransitionConfig;
|
|
88
|
+
params?: unknown;
|
|
89
|
+
};
|
|
84
90
|
export type DateInputReqdProps = never;
|
|
85
91
|
export type DateInputBindProps = "value" | "open" | "element";
|
|
86
92
|
|
|
@@ -98,7 +104,7 @@
|
|
|
98
104
|
export const _DATE_INPUT_PRESET = "svs-date-input";
|
|
99
105
|
|
|
100
106
|
import { onDestroy, tick, untrack } from "svelte";
|
|
101
|
-
import { VARIANT, PARTS, _createContext, _fnClass, shouldReduceMotion } from "./_core";
|
|
107
|
+
import { VARIANT, PARTS, _createContext, _detectOverflow, _fnClass, shouldReduceMotion } from "./_core";
|
|
102
108
|
import Calendar from "./Calendar.svelte";
|
|
103
109
|
import type { Snippet } from "svelte";
|
|
104
110
|
import type { Attachment } from "svelte/attachments";
|
|
@@ -122,7 +128,7 @@
|
|
|
122
128
|
const effId = $derived(ctx ? ctx.id : idProp);
|
|
123
129
|
const effDescribedby = $derived(ctx ? ctx.describedby : ariaDescribedbyProp);
|
|
124
130
|
const fmt = $derived.by(() => formatProp ?? ((d: Temporal.PlainDate) => d.toLocaleString(locale, { dateStyle: "medium" })));
|
|
125
|
-
const reduced = $derived(
|
|
131
|
+
const reduced = $derived(shouldReduceMotion());
|
|
126
132
|
const tfn = $derived(!reduced && transition?.fn ? transition.fn : noop);
|
|
127
133
|
const tparams = $derived(transition?.params as any);
|
|
128
134
|
|
|
@@ -152,6 +158,7 @@
|
|
|
152
158
|
let last = $state(format());
|
|
153
159
|
let focused = $state(false);
|
|
154
160
|
let overflow = $state({ x: false, y: false });
|
|
161
|
+
let root = $state<HTMLElement>();
|
|
155
162
|
let overlayElem = $state<HTMLDivElement>();
|
|
156
163
|
let returning = false;
|
|
157
164
|
|
|
@@ -237,16 +244,13 @@
|
|
|
237
244
|
});
|
|
238
245
|
}
|
|
239
246
|
function focusCalendar() {
|
|
240
|
-
|
|
241
|
-
el?.focus();
|
|
247
|
+
overlayElem?.querySelector<HTMLElement>('[tabindex="0"]')?.focus();
|
|
242
248
|
}
|
|
243
249
|
async function observeOverflow() {
|
|
244
250
|
overflow = { x: false, y: false };
|
|
245
251
|
await tick();
|
|
246
252
|
if (!overlayElem || typeof window === "undefined") return;
|
|
247
|
-
|
|
248
|
-
overflow.x = window.innerWidth < rect.right;
|
|
249
|
-
overflow.y = window.innerHeight < rect.bottom;
|
|
253
|
+
overflow = _detectOverflow(overlayElem);
|
|
250
254
|
}
|
|
251
255
|
function stopListening() {
|
|
252
256
|
if (typeof document === "undefined") return;
|
|
@@ -289,7 +293,6 @@
|
|
|
289
293
|
returnFocus();
|
|
290
294
|
};
|
|
291
295
|
const houtside = (ev: PointerEvent) => {
|
|
292
|
-
const root = document.querySelector(`[data-svs-dateinput="${uid}"]`);
|
|
293
296
|
if (root?.contains(ev.target as Node)) return;
|
|
294
297
|
hide();
|
|
295
298
|
};
|
|
@@ -298,7 +301,7 @@
|
|
|
298
301
|
|
|
299
302
|
<!---------------------------------------->
|
|
300
303
|
|
|
301
|
-
<span class={cls(PARTS.WHOLE, effVariant)} data-svs-dateinput={uid} style="position:relative;">
|
|
304
|
+
<span bind:this={root} class={cls(PARTS.WHOLE, effVariant)} data-svs-dateinput={uid} style="position:relative;">
|
|
302
305
|
{#if left}
|
|
303
306
|
<span class={cls(PARTS.LEFT, effVariant)}>{@render left(ctl, open, effVariant)}</span>
|
|
304
307
|
{/if}
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
type DateInputCtl = {
|
|
2
|
-
toggle: () => void;
|
|
3
|
-
show: () => void;
|
|
4
|
-
hide: () => void;
|
|
5
|
-
clear: () => void;
|
|
6
|
-
};
|
|
7
|
-
export type TransitionProp = {
|
|
8
|
-
fn?: (node: HTMLElement, params: any, options: {
|
|
9
|
-
direction: "in" | "out" | "both";
|
|
10
|
-
}) => import("svelte/transition").TransitionConfig;
|
|
11
|
-
params?: unknown;
|
|
12
|
-
};
|
|
13
1
|
export interface DateInputProps extends Omit<HTMLInputAttributes, "type" | "value" | "min" | "max" | "readonly" | "list" | "name"> {
|
|
14
2
|
value?: Temporal.PlainDate;
|
|
15
3
|
open?: boolean;
|
|
@@ -31,6 +19,18 @@ export interface DateInputProps extends Omit<HTMLInputAttributes, "type" | "valu
|
|
|
31
19
|
styling?: SVSClass;
|
|
32
20
|
variant?: SVSVariant;
|
|
33
21
|
}
|
|
22
|
+
export type DateInputCtl = {
|
|
23
|
+
toggle: () => void;
|
|
24
|
+
show: () => void;
|
|
25
|
+
hide: () => void;
|
|
26
|
+
clear: () => void;
|
|
27
|
+
};
|
|
28
|
+
export type TransitionProp = {
|
|
29
|
+
fn?: (node: HTMLElement, params: any, options: {
|
|
30
|
+
direction: "in" | "out" | "both";
|
|
31
|
+
}) => import("svelte/transition").TransitionConfig;
|
|
32
|
+
params?: unknown;
|
|
33
|
+
};
|
|
34
34
|
export type DateInputReqdProps = never;
|
|
35
35
|
export type DateInputBindProps = "value" | "open" | "element";
|
|
36
36
|
export interface DateInputContext extends SVSContext {
|
|
@@ -58,10 +58,6 @@ import type { CalendarProps } from "./Calendar.svelte";
|
|
|
58
58
|
* ```
|
|
59
59
|
* ### Types
|
|
60
60
|
* ```ts
|
|
61
|
-
* type TransitionProp = {
|
|
62
|
-
* fn?: (node: HTMLElement, params: any, options: { direction: "in" | "out" | "both" }) => import("svelte/transition").TransitionConfig;
|
|
63
|
-
* params?: unknown;
|
|
64
|
-
* };
|
|
65
61
|
* interface DateInputProps extends Omit<HTMLInputAttributes, "type" | "value" | "min" | "max" | "readonly" | "list" | "name"> {
|
|
66
62
|
* value?: Temporal.PlainDate; // bindable; undefined = empty
|
|
67
63
|
* open?: boolean; // bindable (false)
|
|
@@ -83,6 +79,16 @@ import type { CalendarProps } from "./Calendar.svelte";
|
|
|
83
79
|
* styling?: SVSClass;
|
|
84
80
|
* variant?: SVSVariant; // (VARIANT.NEUTRAL)
|
|
85
81
|
* }
|
|
82
|
+
* type DateInputCtl = {
|
|
83
|
+
* toggle: () => void;
|
|
84
|
+
* show: () => void;
|
|
85
|
+
* hide: () => void;
|
|
86
|
+
* clear: () => void;
|
|
87
|
+
* };
|
|
88
|
+
* type TransitionProp = {
|
|
89
|
+
* fn?: (node: HTMLElement, params: any, options: { direction: "in" | "out" | "both" }) => import("svelte/transition").TransitionConfig;
|
|
90
|
+
* params?: unknown;
|
|
91
|
+
* };
|
|
86
92
|
* ```
|
|
87
93
|
* ### Anatomy
|
|
88
94
|
* ```svelte
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
|
|
96
96
|
// *** Initialize *** //
|
|
97
97
|
const cls = $derived(_fnClass(_DISCLOSURE_PRESET, styling ?? ctx?.styling));
|
|
98
|
-
const reduced = $derived(
|
|
98
|
+
const reduced = $derived(shouldReduceMotion());
|
|
99
99
|
const dur = $derived(_resolveDuration(duration));
|
|
100
100
|
const tfn = $derived(reduced ? noop : (transition?.fn ?? slide));
|
|
101
101
|
const tparams = $derived(transition?.params ?? { duration: dur });
|
|
@@ -122,16 +122,19 @@
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
// *** Reactive Handlers *** //
|
|
125
|
+
const neutralInput = $derived(ctx ? ctx.variant : variant);
|
|
126
|
+
const desiredBaseVariant = $derived(ctx && !effOpen && !isInactive && prevVariant === undefined ? base : undefined);
|
|
127
|
+
const shouldStoreInactive = $derived(isInactive && _isNeutral(variant));
|
|
128
|
+
|
|
125
129
|
// External variant writes are styling-only; preserve the neutral fallback without changing open state.
|
|
126
130
|
$effect(() => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
$effect(() => {
|
|
130
|
-
if (ctx && !effOpen && !isInactive && prevVariant === undefined) variant = base;
|
|
131
|
+
neutralInput;
|
|
132
|
+
untrack(() => syncNeutral());
|
|
131
133
|
});
|
|
132
134
|
$effect(() => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
desiredBaseVariant;
|
|
136
|
+
shouldStoreInactive;
|
|
137
|
+
untrack(() => syncVariant());
|
|
135
138
|
});
|
|
136
139
|
$effect.pre(() => {
|
|
137
140
|
effOpen;
|
|
@@ -143,6 +146,13 @@
|
|
|
143
146
|
restoreVariant();
|
|
144
147
|
toggleOpen(effOpen);
|
|
145
148
|
}
|
|
149
|
+
function syncNeutral() {
|
|
150
|
+
neutral = _isNeutral(neutralInput) ? neutralInput : neutral;
|
|
151
|
+
}
|
|
152
|
+
function syncVariant() {
|
|
153
|
+
if (shouldStoreInactive) storeVariant();
|
|
154
|
+
else if (desiredBaseVariant !== undefined) variant = desiredBaseVariant;
|
|
155
|
+
}
|
|
146
156
|
function toggleOpen(isOpen: boolean) {
|
|
147
157
|
guard.activate(dur);
|
|
148
158
|
if (isOpen) {
|
package/_svseeds/Drawer.svelte
CHANGED
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
styling?: SVSClass;
|
|
52
52
|
variant?: SVSVariant; // (VARIANT.NEUTRAL)
|
|
53
53
|
}
|
|
54
|
-
export type Position = "top" | "right" | "bottom" | "left";
|
|
55
54
|
export type DrawerCssVar = "duration";
|
|
56
55
|
export type DrawerReqdProps = "children";
|
|
57
56
|
export type DrawerBindProps = "open" | "element";
|
|
@@ -80,7 +79,7 @@
|
|
|
80
79
|
import { VARIANT, PARTS, _fnClass, _resolveDuration } from "./_core";
|
|
81
80
|
import type { Snippet } from "svelte";
|
|
82
81
|
import type { HTMLDialogAttributes, MouseEventHandler, KeyboardEventHandler, ToggleEventHandler } from "svelte/elements";
|
|
83
|
-
import type { SVSClass, SVSVariant } from "./_core";
|
|
82
|
+
import type { SVSClass, SVSVariant, Position } from "./_core";
|
|
84
83
|
</script>
|
|
85
84
|
|
|
86
85
|
<script lang="ts">
|
|
@@ -11,14 +11,13 @@ export interface DrawerProps extends Omit<HTMLDialogAttributes, "children" | "st
|
|
|
11
11
|
styling?: SVSClass;
|
|
12
12
|
variant?: SVSVariant;
|
|
13
13
|
}
|
|
14
|
-
export type Position = "top" | "right" | "bottom" | "left";
|
|
15
14
|
export type DrawerCssVar = "duration";
|
|
16
15
|
export type DrawerReqdProps = "children";
|
|
17
16
|
export type DrawerBindProps = "open" | "element";
|
|
18
17
|
export declare const _DRAWER_PRESET = "svs-drawer";
|
|
19
18
|
import type { Snippet } from "svelte";
|
|
20
19
|
import type { HTMLDialogAttributes } from "svelte/elements";
|
|
21
|
-
import type { SVSClass, SVSVariant } from "./_core";
|
|
20
|
+
import type { SVSClass, SVSVariant, Position } from "./_core";
|
|
22
21
|
/**
|
|
23
22
|
* ### Usage
|
|
24
23
|
* Use standalone.
|
|
@@ -92,11 +92,18 @@
|
|
|
92
92
|
export const _FILE_FIELD_PRESET = "svs-file-field";
|
|
93
93
|
|
|
94
94
|
import { untrack } from "svelte";
|
|
95
|
-
import { VARIANT, PARTS, _fnClass, _isNeutral } from "./_core";
|
|
95
|
+
import { VARIANT, PARTS, _fieldAria, _fieldIds, _fieldMessage, _fnClass, _isNeutral, _verify } from "./_core";
|
|
96
96
|
import FileInput, { _FILE_INPUT_PRESET, _setFileInputContext } from "./FileInput.svelte";
|
|
97
97
|
import type { Snippet } from "svelte";
|
|
98
98
|
import type { SVSClass, SVSVariant, SVSFieldValidation } from "./_core";
|
|
99
|
-
import type {
|
|
99
|
+
import type {
|
|
100
|
+
FileInputContext,
|
|
101
|
+
FileInputProps,
|
|
102
|
+
FileInputReqdProps,
|
|
103
|
+
FileInputBindProps,
|
|
104
|
+
FileRejection,
|
|
105
|
+
FileRejectReason,
|
|
106
|
+
} from "./FileInput.svelte";
|
|
100
107
|
</script>
|
|
101
108
|
|
|
102
109
|
<script lang="ts">
|
|
@@ -107,12 +114,14 @@
|
|
|
107
114
|
const cls = $derived(_fnClass(_FILE_FIELD_PRESET, styling));
|
|
108
115
|
const uid = $props.id();
|
|
109
116
|
const id = $derived(label?.trim() ? `${uid}-ctrl` : undefined);
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
const
|
|
117
|
+
const ids = $derived(_fieldIds(uid, label, bottom));
|
|
118
|
+
const idLabel = $derived(ids.idLabel);
|
|
119
|
+
const idDesc = $derived(ids.idDesc);
|
|
120
|
+
const idErr = $derived(ids.idErr);
|
|
113
121
|
let errmsg = $state("");
|
|
114
|
-
const message = $derived(variant
|
|
115
|
-
const
|
|
122
|
+
const message = $derived(_fieldMessage(variant, errmsg, bottom));
|
|
123
|
+
const aria = $derived(_fieldAria(variant, message, idErr));
|
|
124
|
+
const idMsg = $derived(aria.idMsg);
|
|
116
125
|
|
|
117
126
|
// *** Initialize Context *** //
|
|
118
127
|
const ctx: FileInputContext = {
|
|
@@ -154,7 +163,7 @@
|
|
|
154
163
|
$effect(() => {
|
|
155
164
|
neutral = _isNeutral(variant) ? variant : neutral;
|
|
156
165
|
});
|
|
157
|
-
const live = $derived(
|
|
166
|
+
const live = $derived(aria.live);
|
|
158
167
|
function shift(oninvalid: boolean = false, msg?: string) {
|
|
159
168
|
const vmsg = element?.validationMessage ?? "";
|
|
160
169
|
if (files.length) touched = true;
|
|
@@ -167,12 +176,7 @@
|
|
|
167
176
|
return vmsg ? VARIANT.INACTIVE : VARIANT.ACTIVE;
|
|
168
177
|
}
|
|
169
178
|
function verify() {
|
|
170
|
-
|
|
171
|
-
for (const v of validations) {
|
|
172
|
-
const msg = v({ value: files, validity: element.validity, element });
|
|
173
|
-
if (msg) return element.setCustomValidity(msg);
|
|
174
|
-
}
|
|
175
|
-
element.setCustomValidity("");
|
|
179
|
+
_verify(element, validations, files);
|
|
176
180
|
}
|
|
177
181
|
|
|
178
182
|
// *** Reactive Handlers *** //
|
|
@@ -255,7 +259,7 @@
|
|
|
255
259
|
{@render side(PARTS.RIGHT, right)}
|
|
256
260
|
</div>
|
|
257
261
|
{#if reserve || message?.trim()}
|
|
258
|
-
<div class={cls(PARTS.BOTTOM, variant)} id={
|
|
262
|
+
<div class={cls(PARTS.BOTTOM, variant)} id={idErr} role={live}>{message}</div>
|
|
259
263
|
{/if}
|
|
260
264
|
</div>
|
|
261
265
|
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
export const [_getFileInputContext, _setFileInputContext] = _createContext<FileInputContext>();
|
|
102
102
|
|
|
103
103
|
import { untrack } from "svelte";
|
|
104
|
-
import { VARIANT, PARTS, SR_ONLY, _fnClass, _createContext } from "./_core";
|
|
104
|
+
import { VARIANT, PARTS, SR_ONLY, _commitSubset, _fnClass, _createContext } from "./_core";
|
|
105
105
|
import type { Snippet } from "svelte";
|
|
106
106
|
import type { Attachment } from "svelte/attachments";
|
|
107
107
|
import type { HTMLInputAttributes, MouseEventHandler, ChangeEventHandler, DragEventHandler, EventHandler } from "svelte/elements";
|
|
@@ -183,11 +183,7 @@
|
|
|
183
183
|
else accepted.push(file);
|
|
184
184
|
}
|
|
185
185
|
const detail = { values: effFiles, added: accepted, rejected };
|
|
186
|
-
|
|
187
|
-
const a = events?.onadd?.(detail);
|
|
188
|
-
if (a) committed = committed.filter((f) => a.includes(f));
|
|
189
|
-
const b = ctx?.events?.onadd?.(detail);
|
|
190
|
-
if (b) committed = committed.filter((f) => b.includes(f));
|
|
186
|
+
const committed = _commitSubset(accepted, detail, events?.onadd, ctx?.events?.onadd);
|
|
191
187
|
const next = multiple ? [...current, ...committed] : committed.length ? committed : effFiles;
|
|
192
188
|
if (!sameFileArray(effFiles, next)) setFiles(next);
|
|
193
189
|
else syncInputFiles();
|
|
@@ -195,11 +191,7 @@
|
|
|
195
191
|
}
|
|
196
192
|
const remove = (file: File) => {
|
|
197
193
|
const detail = { values: effFiles, removed: [file] };
|
|
198
|
-
|
|
199
|
-
const a = events?.onremove?.(detail);
|
|
200
|
-
if (a) keep = keep.filter((f) => a.includes(f));
|
|
201
|
-
const b = ctx?.events?.onremove?.(detail);
|
|
202
|
-
if (b) keep = keep.filter((f) => b.includes(f));
|
|
194
|
+
const keep = _commitSubset([file], detail, events?.onremove, ctx?.events?.onremove);
|
|
203
195
|
if (!keep.length) return;
|
|
204
196
|
const next = effFiles.filter((f) => f !== file);
|
|
205
197
|
if (!sameFileArray(effFiles, next)) setFiles(next);
|
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
// Parses a space-separated hotkey string (e.g. "Ctrl Shift A") into its modifier flags and trailing key.
|
|
40
40
|
function parseHotkey(value: string): Omit<HotkeyCaptureDetail, "event" | "kind">;
|
|
41
41
|
```
|
|
42
|
+
### Behavior
|
|
43
|
+
Focus and blur events update `active`, and setting `active` focuses or blurs the input. Guards
|
|
44
|
+
keep focus in place when it is already correct, and `disabled` prevents programmatic focus moves.
|
|
42
45
|
-->
|
|
43
46
|
<script module lang="ts">
|
|
44
47
|
export interface HotkeyCaptureProps extends Omit<
|
|
@@ -109,8 +112,6 @@
|
|
|
109
112
|
});
|
|
110
113
|
$effect(() => {
|
|
111
114
|
active;
|
|
112
|
-
disabled;
|
|
113
|
-
element;
|
|
114
115
|
untrack(() => toggleFocus());
|
|
115
116
|
});
|
|
116
117
|
function toggleFocus() {
|
|
@@ -65,6 +65,9 @@ import type { SVSClass, SVSVariant } from "./_core";
|
|
|
65
65
|
* // Parses a space-separated hotkey string (e.g. "Ctrl Shift A") into its modifier flags and trailing key.
|
|
66
66
|
* function parseHotkey(value: string): Omit<HotkeyCaptureDetail, "event" | "kind">;
|
|
67
67
|
* ```
|
|
68
|
+
* ### Behavior
|
|
69
|
+
* Focus and blur events update `active`, and setting `active` focuses or blurs the input. Guards
|
|
70
|
+
* keep focus in place when it is already correct, and `disabled` prevents programmatic focus moves.
|
|
68
71
|
*/
|
|
69
72
|
declare const HotkeyCapture: import("svelte").Component<HotkeyCaptureProps, {}, "variant" | "active" | "value" | "element">;
|
|
70
73
|
type HotkeyCapture = ReturnType<typeof HotkeyCapture>;
|
package/_svseeds/Modal.svelte
CHANGED
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
export const _NUMBER_FIELD_PRESET = "svs-number-field";
|
|
77
77
|
|
|
78
78
|
import { onMount, untrack } from "svelte";
|
|
79
|
-
import { VARIANT, PARTS, _fnClass, _isNeutral } from "./_core";
|
|
79
|
+
import { VARIANT, PARTS, _fieldAria, _fieldIds, _fieldMessage, _fnClass, _isNeutral, _verify } from "./_core";
|
|
80
80
|
import NumberInput, { _NUMBER_INPUT_PRESET, _setNumberInputContext } from "./NumberInput.svelte";
|
|
81
81
|
import type { Snippet } from "svelte";
|
|
82
82
|
import type { SVSClass, SVSVariant, SVSFieldValidation } from "./_core";
|
|
@@ -91,12 +91,14 @@
|
|
|
91
91
|
const cls = $derived(_fnClass(_NUMBER_FIELD_PRESET, styling));
|
|
92
92
|
const uid = $props.id();
|
|
93
93
|
const id = $derived(label?.trim() ? `${uid}-ctrl` : undefined);
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
const
|
|
94
|
+
const ids = $derived(_fieldIds(uid, label, bottom));
|
|
95
|
+
const idLabel = $derived(ids.idLabel);
|
|
96
|
+
const idDesc = $derived(ids.idDesc);
|
|
97
|
+
const idErr = $derived(ids.idErr);
|
|
97
98
|
let errmsg = $state("");
|
|
98
|
-
const message = $derived(variant
|
|
99
|
-
const
|
|
99
|
+
const message = $derived(_fieldMessage(variant, errmsg, bottom));
|
|
100
|
+
const aria = $derived(_fieldAria(variant, message, idErr));
|
|
101
|
+
const idMsg = $derived(aria.idMsg);
|
|
100
102
|
|
|
101
103
|
// *** Initialize Context *** //
|
|
102
104
|
const ctx: NumberInputContext = {
|
|
@@ -134,19 +136,14 @@
|
|
|
134
136
|
$effect(() => {
|
|
135
137
|
neutral = _isNeutral(variant) ? variant : neutral;
|
|
136
138
|
});
|
|
137
|
-
const live = $derived(
|
|
139
|
+
const live = $derived(aria.live);
|
|
138
140
|
function shift(oninvalid?: boolean) {
|
|
139
141
|
const vmsg = element?.validationMessage ?? "";
|
|
140
142
|
variant = value === undefined && !oninvalid ? neutral : vmsg ? VARIANT.INACTIVE : VARIANT.ACTIVE;
|
|
141
143
|
errmsg = vmsg;
|
|
142
144
|
}
|
|
143
145
|
function verify() {
|
|
144
|
-
|
|
145
|
-
for (const v of validations) {
|
|
146
|
-
const msg = v({ value, validity: element.validity, element });
|
|
147
|
-
if (msg) return element.setCustomValidity(msg);
|
|
148
|
-
}
|
|
149
|
-
element.setCustomValidity("");
|
|
146
|
+
_verify(element, validations, value);
|
|
150
147
|
}
|
|
151
148
|
|
|
152
149
|
// *** Reactive Handlers *** //
|
|
@@ -192,7 +189,7 @@
|
|
|
192
189
|
{@render side(PARTS.RIGHT, right)}
|
|
193
190
|
</div>
|
|
194
191
|
{#if reserve || message?.trim()}
|
|
195
|
-
<div class={cls(PARTS.BOTTOM, variant)} id={
|
|
192
|
+
<div class={cls(PARTS.BOTTOM, variant)} id={idErr} role={live}>{message}</div>
|
|
196
193
|
{/if}
|
|
197
194
|
</div>
|
|
198
195
|
|