@happyvertical/smrt-ui 0.52.0 → 0.53.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/AGENTS.md +11 -1
- package/README.md +300 -2
- package/dist/components/data/DataTable.svelte +60 -15
- package/dist/components/data/DataTable.svelte.d.ts.map +1 -1
- package/dist/components/data/DataTableResponsive.d.ts +4 -0
- package/dist/components/data/DataTableResponsive.d.ts.map +1 -0
- package/dist/components/data/DataTableResponsive.js +22 -0
- package/dist/components/data/__tests__/DataTableResponsive.test.js +80 -0
- package/dist/components/data/__tests__/responsive-table.fixture.svelte +29 -0
- package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts +7 -0
- package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts.map +1 -0
- package/dist/components/data/types.d.ts +8 -0
- package/dist/components/data/types.d.ts.map +1 -1
- package/dist/components/display/DateDisplay.svelte +76 -14
- package/dist/components/display/DateDisplay.svelte.d.ts +2 -0
- package/dist/components/display/DateDisplay.svelte.d.ts.map +1 -1
- package/dist/components/display/Icon.svelte +3 -16
- package/dist/components/display/Icon.svelte.d.ts +0 -9
- package/dist/components/display/Icon.svelte.d.ts.map +1 -1
- package/dist/components/display/StatusBadge.svelte +29 -2
- package/dist/components/display/StatusBadge.svelte.d.ts +4 -2
- package/dist/components/display/StatusBadge.svelte.d.ts.map +1 -1
- package/dist/components/display/__tests__/DateDisplay.test.js +82 -1
- package/dist/components/display/__tests__/Icon.test.js +132 -2
- package/dist/components/display/__tests__/StatusBadge.test.js +78 -0
- package/dist/components/display/icons.svelte.d.ts +11 -0
- package/dist/components/display/icons.svelte.d.ts.map +1 -0
- package/dist/components/display/icons.svelte.js +60 -0
- package/dist/components/display/index.d.ts +3 -1
- package/dist/components/display/index.d.ts.map +1 -1
- package/dist/components/display/index.js +1 -0
- package/dist/components/display/types.d.ts +2 -0
- package/dist/components/display/types.d.ts.map +1 -1
- package/dist/components/feedback/ConfirmDialog.svelte +59 -48
- package/dist/components/feedback/ConfirmDialog.svelte.d.ts +14 -2
- package/dist/components/feedback/ConfirmDialog.svelte.d.ts.map +1 -1
- package/dist/components/feedback/ToastViewport.svelte +156 -8
- package/dist/components/feedback/ToastViewport.svelte.d.ts +5 -1
- package/dist/components/feedback/ToastViewport.svelte.d.ts.map +1 -1
- package/dist/components/feedback/__tests__/ConfirmDialog.test.js +38 -20
- package/dist/components/feedback/__tests__/confirm-message.fixture.svelte +9 -0
- package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts +19 -0
- package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts.map +1 -0
- package/dist/components/feedback/__tests__/toast.test.js +142 -1
- package/dist/components/feedback/index.d.ts +1 -1
- package/dist/components/feedback/index.d.ts.map +1 -1
- package/dist/components/feedback/toast.d.ts +13 -1
- package/dist/components/feedback/toast.d.ts.map +1 -1
- package/dist/components/feedback/toast.js +51 -10
- package/dist/components/forms/CameraCapture.svelte +619 -0
- package/dist/components/forms/CameraCapture.svelte.d.ts +42 -0
- package/dist/components/forms/CameraCapture.svelte.d.ts.map +1 -0
- package/dist/components/forms/Checkbox.svelte +8 -1
- package/dist/components/forms/Checkbox.svelte.d.ts +2 -0
- package/dist/components/forms/Checkbox.svelte.d.ts.map +1 -1
- package/dist/components/forms/Combobox.svelte +40 -0
- package/dist/components/forms/Combobox.svelte.d.ts.map +1 -1
- package/dist/components/forms/Form.svelte +5 -0
- package/dist/components/forms/Form.svelte.d.ts +1 -0
- package/dist/components/forms/Form.svelte.d.ts.map +1 -1
- package/dist/components/forms/Input.svelte +8 -1
- package/dist/components/forms/Input.svelte.d.ts +2 -0
- package/dist/components/forms/Input.svelte.d.ts.map +1 -1
- package/dist/components/forms/Listbox.svelte +39 -1
- package/dist/components/forms/Listbox.svelte.d.ts.map +1 -1
- package/dist/components/forms/MultiSelect.svelte +41 -1
- package/dist/components/forms/MultiSelect.svelte.d.ts.map +1 -1
- package/dist/components/forms/Radio.svelte +1 -0
- package/dist/components/forms/RadioGroup.svelte +7 -1
- package/dist/components/forms/RadioGroup.svelte.d.ts +2 -0
- package/dist/components/forms/RadioGroup.svelte.d.ts.map +1 -1
- package/dist/components/forms/SegmentedControl.svelte +152 -11
- package/dist/components/forms/SegmentedControl.svelte.d.ts +4 -0
- package/dist/components/forms/SegmentedControl.svelte.d.ts.map +1 -1
- package/dist/components/forms/Select.svelte +8 -1
- package/dist/components/forms/Select.svelte.d.ts +2 -0
- package/dist/components/forms/Select.svelte.d.ts.map +1 -1
- package/dist/components/forms/SignaturePad.svelte +436 -0
- package/dist/components/forms/SignaturePad.svelte.d.ts +32 -0
- package/dist/components/forms/SignaturePad.svelte.d.ts.map +1 -0
- package/dist/components/forms/Switch.svelte +8 -1
- package/dist/components/forms/Switch.svelte.d.ts +2 -0
- package/dist/components/forms/Switch.svelte.d.ts.map +1 -1
- package/dist/components/forms/Textarea.svelte +8 -1
- package/dist/components/forms/Textarea.svelte.d.ts +2 -0
- package/dist/components/forms/Textarea.svelte.d.ts.map +1 -1
- package/dist/components/forms/__tests__/CameraCapture.test.js +504 -0
- package/dist/components/forms/__tests__/Combobox.test.js +279 -12
- package/dist/components/forms/__tests__/Form.test.js +46 -0
- package/dist/components/forms/__tests__/Listbox.test.js +303 -0
- package/dist/components/forms/__tests__/MultiSelect.test.js +281 -0
- package/dist/components/forms/__tests__/SignaturePad.test.js +338 -0
- package/dist/components/forms/__tests__/camera-capture-session.test.js +207 -0
- package/dist/components/forms/__tests__/capture-form-retry.test.js +166 -0
- package/dist/components/forms/__tests__/capture-form.fixture.svelte +38 -0
- package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts +10 -0
- package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/capture-test-env.d.ts +70 -0
- package/dist/components/forms/__tests__/capture-test-env.d.ts.map +1 -0
- package/dist/components/forms/__tests__/capture-test-env.js +122 -0
- package/dist/components/forms/__tests__/capture-touch.fixture.svelte +15 -0
- package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/combobox-form.fixture.svelte +29 -0
- package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts +14 -0
- package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-attachment.fixture.svelte +28 -0
- package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts +11 -0
- package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-retry-form.fixture.svelte +31 -0
- package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-retry-form.test.js +107 -0
- package/dist/components/forms/__tests__/hidden-controls-form-retry.test.js +69 -0
- package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte +29 -0
- package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts +9 -0
- package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/listbox-form.fixture.svelte +27 -0
- package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/multiselect-form.fixture.svelte +27 -0
- package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts +13 -0
- package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/native-file-field.test.js +177 -0
- package/dist/components/forms/__tests__/segmented-posting.fixture.svelte +28 -0
- package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts +12 -0
- package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/segmented-posting.test.js +92 -0
- package/dist/components/forms/__tests__/signature-pad-logic.test.js +54 -0
- package/dist/components/forms/__tests__/touch-density.fixture.svelte +34 -0
- package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts +8 -0
- package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/touch-density.test.js +66 -0
- package/dist/components/forms/camera-capture-session.d.ts +81 -0
- package/dist/components/forms/camera-capture-session.d.ts.map +1 -0
- package/dist/components/forms/camera-capture-session.js +130 -0
- package/dist/components/forms/form-retry/__tests__/boundaries.test.js +23 -0
- package/dist/components/forms/form-retry/__tests__/content-digest.test.js +70 -0
- package/dist/components/forms/form-retry/__tests__/controller.test.js +802 -0
- package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts +82 -0
- package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts.map +1 -0
- package/dist/components/forms/form-retry/__tests__/fake-kit.js +180 -0
- package/dist/components/forms/form-retry/__tests__/form-draft.test.js +169 -0
- package/dist/components/forms/form-retry/__tests__/ssr.test.js +37 -0
- package/dist/components/forms/form-retry/__tests__/storage.d.ts +26 -0
- package/dist/components/forms/form-retry/__tests__/storage.d.ts.map +1 -0
- package/dist/components/forms/form-retry/__tests__/storage.js +63 -0
- package/dist/components/forms/form-retry/__tests__/submission-key.test.js +236 -0
- package/dist/components/forms/form-retry/__tests__/submitted-draft.test.js +334 -0
- package/dist/components/forms/form-retry/content-digest.d.ts +54 -0
- package/dist/components/forms/form-retry/content-digest.d.ts.map +1 -0
- package/dist/components/forms/form-retry/content-digest.js +169 -0
- package/dist/components/forms/form-retry/controller.d.ts +214 -0
- package/dist/components/forms/form-retry/controller.d.ts.map +1 -0
- package/dist/components/forms/form-retry/controller.js +404 -0
- package/dist/components/forms/form-retry/form-draft.d.ts +68 -0
- package/dist/components/forms/form-retry/form-draft.d.ts.map +1 -0
- package/dist/components/forms/form-retry/form-draft.js +161 -0
- package/dist/components/forms/form-retry/index.d.ts +19 -0
- package/dist/components/forms/form-retry/index.d.ts.map +1 -0
- package/dist/components/forms/form-retry/index.js +16 -0
- package/dist/components/forms/form-retry/submission-key.d.ts +244 -0
- package/dist/components/forms/form-retry/submission-key.d.ts.map +1 -0
- package/dist/components/forms/form-retry/submission-key.js +342 -0
- package/dist/components/forms/form-retry/submitted-draft.d.ts +112 -0
- package/dist/components/forms/form-retry/submitted-draft.d.ts.map +1 -0
- package/dist/components/forms/form-retry/submitted-draft.js +270 -0
- package/dist/components/forms/form-retry/types.d.ts +84 -0
- package/dist/components/forms/form-retry/types.d.ts.map +1 -0
- package/dist/components/forms/form-retry/types.js +13 -0
- package/dist/components/forms/index.d.ts +7 -1
- package/dist/components/forms/index.d.ts.map +1 -1
- package/dist/components/forms/index.js +8 -0
- package/dist/components/forms/native-file-field.d.ts +94 -0
- package/dist/components/forms/native-file-field.d.ts.map +1 -0
- package/dist/components/forms/native-file-field.js +147 -0
- package/dist/components/forms/signature-pad-logic.d.ts +50 -0
- package/dist/components/forms/signature-pad-logic.d.ts.map +1 -0
- package/dist/components/forms/signature-pad-logic.js +48 -0
- package/dist/components/forms/types.d.ts +41 -0
- package/dist/components/forms/types.d.ts.map +1 -1
- package/dist/components/nav/FilterChips.svelte +8 -1
- package/dist/components/nav/FilterChips.svelte.d.ts +2 -0
- package/dist/components/nav/FilterChips.svelte.d.ts.map +1 -1
- package/dist/components/ui/Button.svelte +9 -2
- package/dist/components/ui/Button.svelte.d.ts +2 -0
- package/dist/components/ui/Button.svelte.d.ts.map +1 -1
- package/dist/i18n/strings.ui.d.ts +24 -0
- package/dist/i18n/strings.ui.d.ts.map +1 -1
- package/dist/i18n/strings.ui.js +26 -0
- package/dist/styles/tokens.css +2 -0
- package/dist/svelte/__tests__/playground.test.js +2 -1
- package/dist/svelte/playground/CapturePreview.svelte +56 -0
- package/dist/svelte/playground/CapturePreview.svelte.d.ts +4 -0
- package/dist/svelte/playground/CapturePreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground.d.ts.map +1 -1
- package/dist/svelte/playground.js +10 -0
- package/dist/themes/ThemeProvider.svelte +9 -0
- package/dist/themes/ThemeProvider.svelte.d.ts +2 -0
- package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -1
- package/dist/themes/css-generator.d.ts.map +1 -1
- package/dist/themes/css-generator.js +3 -0
- package/dist/themes/styles/glass.css +4 -0
- package/dist/themes/styles/happyvertical.css +4 -0
- package/dist/themes/styles/material.css +4 -0
- package/dist/themes/styles/smrt.css +4 -0
- package/dist/themes/styles/studio.css +4 -0
- package/package.json +8 -2
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
2
|
import type { ControlInteractionOptions } from './control-interaction.js';
|
|
3
3
|
export interface Props extends Omit<HTMLInputAttributes, 'type' | 'class' | 'checked'> {
|
|
4
|
+
/** Target density; omit to inherit the ThemeProvider setting. */
|
|
5
|
+
density?: 'comfortable' | 'touch';
|
|
4
6
|
/** Whether the checkbox is checked (bindable). */
|
|
5
7
|
checked?: boolean;
|
|
6
8
|
/** Whether the checkbox shows indeterminate state. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Checkbox.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAM3D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAW1E,MAAM,WAAW,KACf,SAAQ,IAAI,CAAC,mBAAmB,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAC/D,kDAAkD;IAClD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;CACjD;
|
|
1
|
+
{"version":3,"file":"Checkbox.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Checkbox.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAM3D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAW1E,MAAM,WAAW,KACf,SAAQ,IAAI,CAAC,mBAAmB,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAC/D,iEAAiE;IACjE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IAClC,kDAAkD;IAClD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;CACjD;AAmHD,QAAA,MAAM,QAAQ,kDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -69,6 +69,7 @@ const interactionContext = tryGetControlInteractionContext();
|
|
|
69
69
|
let rootEl = $state<HTMLDivElement | null>(null);
|
|
70
70
|
let inputEl = $state<HTMLInputElement | null>(null);
|
|
71
71
|
let open = $state(false);
|
|
72
|
+
const initialValue = untrack(() => value);
|
|
72
73
|
/** The text for a value: its option's label, never a raw id (see valueLabel). */
|
|
73
74
|
function labelForValue(candidate: string): string {
|
|
74
75
|
if (!candidate) return '';
|
|
@@ -178,6 +179,45 @@ function handleKeydown(event: KeyboardEvent) {
|
|
|
178
179
|
closeList();
|
|
179
180
|
}
|
|
180
181
|
}
|
|
182
|
+
$effect(() => {
|
|
183
|
+
const form = inputEl?.form;
|
|
184
|
+
if (!form) return;
|
|
185
|
+
let disposed = false;
|
|
186
|
+
const timers = new Set<ReturnType<typeof setTimeout>>();
|
|
187
|
+
const reset = (event: Event) => {
|
|
188
|
+
const valueAtDispatch = value;
|
|
189
|
+
const queryAtDispatch = query;
|
|
190
|
+
// Native dispatch can checkpoint microtasks between reset listeners.
|
|
191
|
+
// Wait for the next task so later cancellation and edits win.
|
|
192
|
+
const timer = setTimeout(() => {
|
|
193
|
+
timers.delete(timer);
|
|
194
|
+
if (
|
|
195
|
+
disposed ||
|
|
196
|
+
event.defaultPrevented ||
|
|
197
|
+
value !== valueAtDispatch ||
|
|
198
|
+
query !== queryAtDispatch
|
|
199
|
+
)
|
|
200
|
+
return;
|
|
201
|
+
value = initialValue;
|
|
202
|
+
query = labelForValue(initialValue);
|
|
203
|
+
typed = false;
|
|
204
|
+
open = false;
|
|
205
|
+
recordControlUserEdit(
|
|
206
|
+
interactionContext,
|
|
207
|
+
controlId,
|
|
208
|
+
interaction === false ? undefined : interaction?.subject,
|
|
209
|
+
);
|
|
210
|
+
onvaluechange?.(value);
|
|
211
|
+
});
|
|
212
|
+
timers.add(timer);
|
|
213
|
+
};
|
|
214
|
+
form.addEventListener('reset', reset);
|
|
215
|
+
return () => {
|
|
216
|
+
disposed = true;
|
|
217
|
+
form.removeEventListener('reset', reset);
|
|
218
|
+
for (const timer of timers) clearTimeout(timer);
|
|
219
|
+
};
|
|
220
|
+
});
|
|
181
221
|
$effect(() => {
|
|
182
222
|
if (!open) return;
|
|
183
223
|
const dismissPointer = (event: PointerEvent) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Combobox.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,yBAAyB,EACzB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAWlC,MAAM,WAAW,KAAK;IACpB,uCAAuC;IACvC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mDAAmD;IACnD,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;IAChD;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"Combobox.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Combobox.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,yBAAyB,EACzB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAWlC,MAAM,WAAW,KAAK;IACpB,uCAAuC;IACvC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mDAAmD;IACnD,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;IAChD;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAyQD,QAAA,MAAM,QAAQ,gDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -92,6 +92,11 @@ export function getFormId(): string {
|
|
|
92
92
|
return resolvedFormId;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/** Returns the native form while mounted, or null before mount/after unmount. */
|
|
96
|
+
export function getFormElement(): HTMLFormElement | null {
|
|
97
|
+
return formElement;
|
|
98
|
+
}
|
|
99
|
+
|
|
95
100
|
function handleSubmit(event: SubmitEvent & { currentTarget: HTMLFormElement }) {
|
|
96
101
|
if (preventDefault) event.preventDefault();
|
|
97
102
|
onsubmit?.(event);
|
|
@@ -38,6 +38,7 @@ export interface Props extends Omit<HTMLFormAttributes, 'class'> {
|
|
|
38
38
|
declare const Form: import("svelte").Component<Props, {
|
|
39
39
|
getInteractionRegistry: () => ControlInteractionRegistry;
|
|
40
40
|
getFormId: () => string;
|
|
41
|
+
getFormElement: () => HTMLFormElement | null;
|
|
41
42
|
}, "">;
|
|
42
43
|
type Form = ReturnType<typeof Form>;
|
|
43
44
|
export default Form;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Form.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Form.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAEhC,MAAM,0BAA0B,CAAC;AAKlC,MAAM,WAAW,KAAM,SAAQ,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAC9D,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,0BAA0B,CAAC;IACjD,sDAAsD;IACtD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACzD,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"Form.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Form.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAEhC,MAAM,0BAA0B,CAAC;AAKlC,MAAM,WAAW,KAAM,SAAQ,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAC9D,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,0BAA0B,CAAC;IACjD,sDAAsD;IACtD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACzD,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAqHD,QAAA,MAAM,IAAI;kCAnE0B,0BAA0B;qBAIvC,MAAM;0BAKD,eAAe,GAAG,IAAI;MA0DA,CAAC;AACnD,KAAK,IAAI,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;AACpC,eAAe,IAAI,CAAC"}
|
|
@@ -18,6 +18,8 @@ import { tryGetFormGroupContext } from './form-group-context.js';
|
|
|
18
18
|
import { useControlRegistration } from './use-control-registration.svelte.js';
|
|
19
19
|
|
|
20
20
|
export interface Props extends Omit<HTMLInputAttributes, 'class' | 'value'> {
|
|
21
|
+
/** Target density; omit to inherit the ThemeProvider setting. */
|
|
22
|
+
density?: 'comfortable' | 'touch';
|
|
21
23
|
/** Input value as string or number (bindable). */
|
|
22
24
|
value?: string | number;
|
|
23
25
|
/** CSS class to apply to the input element. */
|
|
@@ -40,6 +42,7 @@ let {
|
|
|
40
42
|
'aria-label': ariaLabel,
|
|
41
43
|
'aria-describedby': ariaDescribedby,
|
|
42
44
|
'aria-invalid': ariaInvalid,
|
|
45
|
+
density,
|
|
43
46
|
...rest
|
|
44
47
|
}: Props = $props();
|
|
45
48
|
|
|
@@ -210,7 +213,7 @@ export function getElement(): HTMLInputElement | null {
|
|
|
210
213
|
aria-label={ariaLabel}
|
|
211
214
|
aria-describedby={resolvedDescribedBy}
|
|
212
215
|
aria-invalid={resolvedInvalid}
|
|
213
|
-
class="input {className}"
|
|
216
|
+
data-density={density} class="input {className}"
|
|
214
217
|
data-smrt-control={resolvedControlId}
|
|
215
218
|
data-smrt-form={controlInteraction?.formId}
|
|
216
219
|
data-smrt-subject-type={resolvedInteraction === false ? undefined : resolvedInteraction.subject?.type}
|
|
@@ -271,4 +274,8 @@ export function getElement(): HTMLInputElement | null {
|
|
|
271
274
|
transition: none;
|
|
272
275
|
}
|
|
273
276
|
}
|
|
277
|
+
|
|
278
|
+
.input[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min, 48px); }
|
|
279
|
+
.input[data-density='comfortable'] { --smrt-control-target-min: 0px; }
|
|
280
|
+
.input { min-height: var(--smrt-control-target-min, 0px); }
|
|
274
281
|
</style>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
2
|
import type { ControlInteractionOptions } from './control-interaction.js';
|
|
3
3
|
export interface Props extends Omit<HTMLInputAttributes, 'class' | 'value'> {
|
|
4
|
+
/** Target density; omit to inherit the ThemeProvider setting. */
|
|
5
|
+
density?: 'comfortable' | 'touch';
|
|
4
6
|
/** Input value as string or number (bindable). */
|
|
5
7
|
value?: string | number;
|
|
6
8
|
/** CSS class to apply to the input element. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Input.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAM3D,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,0BAA0B,CAAC;AAUlC,MAAM,WAAW,KAAM,SAAQ,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,OAAO,CAAC;IACzE,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;CACjD;
|
|
1
|
+
{"version":3,"file":"Input.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Input.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAM3D,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,0BAA0B,CAAC;AAUlC,MAAM,WAAW,KAAM,SAAQ,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,OAAO,CAAC;IACzE,iEAAiE;IACjE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IAClC,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;CACjD;AA6LD,QAAA,MAAM,KAAK;iBAvBQ,IAAI;kBAIH,IAAI;6BAIS,MAAM,KAAG,IAAI;sBAItB,gBAAgB,GAAG,IAAI;WAWI,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { untrack } from 'svelte';
|
|
2
3
|
import {
|
|
3
4
|
emitControlChange,
|
|
4
5
|
highlightControl,
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
tryGetControlInteractionContext,
|
|
14
15
|
} from './control-interaction-context.js';
|
|
15
16
|
import {
|
|
17
|
+
matchingOption,
|
|
16
18
|
prepareEnabledOptionValue,
|
|
17
19
|
validatesEnabledOption,
|
|
18
20
|
} from './control-value-validation.js';
|
|
@@ -49,13 +51,14 @@ const instanceId = $props.id();
|
|
|
49
51
|
const interactionContext = tryGetControlInteractionContext();
|
|
50
52
|
let rootEl = $state<HTMLDivElement | null>(null);
|
|
51
53
|
let optionEls = $state<Array<HTMLButtonElement | null>>([]);
|
|
54
|
+
const initialValue = untrack(() => value);
|
|
52
55
|
const controlId = $derived(
|
|
53
56
|
interaction === false
|
|
54
57
|
? undefined
|
|
55
58
|
: (interaction?.id ?? name ?? `listbox-${instanceId}`),
|
|
56
59
|
);
|
|
57
60
|
function select(next: unknown, userEdit = false) {
|
|
58
|
-
const option = options
|
|
61
|
+
const option = matchingOption(options, next);
|
|
59
62
|
if (!option || option.disabled || disabled) return;
|
|
60
63
|
const changed = !Object.is(value, option.value);
|
|
61
64
|
value = option.value;
|
|
@@ -85,6 +88,40 @@ function move(event: KeyboardEvent, index: number) {
|
|
|
85
88
|
: (next + 1) % options.length;
|
|
86
89
|
optionEls[next]?.focus();
|
|
87
90
|
}
|
|
91
|
+
$effect(() => {
|
|
92
|
+
const form = rootEl?.closest('form');
|
|
93
|
+
if (!form) return;
|
|
94
|
+
let disposed = false;
|
|
95
|
+
const timers = new Set<ReturnType<typeof setTimeout>>();
|
|
96
|
+
const reset = (event: Event) => {
|
|
97
|
+
const valueAtDispatch = value;
|
|
98
|
+
// Native dispatch can checkpoint microtasks between reset listeners.
|
|
99
|
+
// Wait for the next task so later cancellation and edits win.
|
|
100
|
+
const timer = setTimeout(() => {
|
|
101
|
+
timers.delete(timer);
|
|
102
|
+
if (
|
|
103
|
+
disposed ||
|
|
104
|
+
event.defaultPrevented ||
|
|
105
|
+
!Object.is(value, valueAtDispatch)
|
|
106
|
+
)
|
|
107
|
+
return;
|
|
108
|
+
value = initialValue;
|
|
109
|
+
recordControlUserEdit(
|
|
110
|
+
interactionContext,
|
|
111
|
+
controlId,
|
|
112
|
+
interaction === false ? undefined : interaction?.subject,
|
|
113
|
+
);
|
|
114
|
+
if (value !== undefined) onvaluechange?.(value);
|
|
115
|
+
});
|
|
116
|
+
timers.add(timer);
|
|
117
|
+
};
|
|
118
|
+
form.addEventListener('reset', reset);
|
|
119
|
+
return () => {
|
|
120
|
+
disposed = true;
|
|
121
|
+
form.removeEventListener('reset', reset);
|
|
122
|
+
for (const timer of timers) clearTimeout(timer);
|
|
123
|
+
};
|
|
124
|
+
});
|
|
88
125
|
useControlRegistration(() => {
|
|
89
126
|
const root = rootEl;
|
|
90
127
|
if (!root || interaction === false) return false;
|
|
@@ -120,6 +157,7 @@ useControlRegistration(() => {
|
|
|
120
157
|
<div bind:this={rootEl} class="listbox {className}" role="listbox" aria-label={label} aria-disabled={disabled} data-smrt-control={controlId} data-smrt-form={interactionContext?.formId}
|
|
121
158
|
data-smrt-subject-type={interaction === false ? undefined : interaction?.subject?.type}
|
|
122
159
|
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id}>
|
|
160
|
+
{#if name}<input type="hidden" {name} value={value ?? ''} disabled={disabled || matchingOption(options, value)?.disabled} />{/if}
|
|
123
161
|
{#each options as option, index (option.value)}<button bind:this={optionEls[index]} type="button" role="option" aria-selected={value === option.value}
|
|
124
162
|
disabled={disabled || option.disabled} tabindex={value === option.value || (value === undefined && index === 0) ? 0 : -1}
|
|
125
163
|
onkeydown={(event) => move(event, index)} onclick={() => select(option.value, true)}>{option.label}</button>{/each}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Listbox.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Listbox.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Listbox.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/Listbox.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,yBAAyB,EACzB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAYlC,MAAM,WAAW,KAAK;IACpB,uCAAuC;IACvC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mDAAmD;IACnD,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;IAChD,gDAAgD;IAChD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACjD,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAsID,QAAA,MAAM,OAAO,gDAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { tick } from 'svelte';
|
|
2
|
+
import { tick, untrack } from 'svelte';
|
|
3
3
|
import {
|
|
4
4
|
emitControlChange,
|
|
5
5
|
highlightControl,
|
|
@@ -59,6 +59,7 @@ let rootEl = $state<HTMLDivElement | null>(null);
|
|
|
59
59
|
let triggerEl = $state<HTMLButtonElement | null>(null);
|
|
60
60
|
let optionEls = $state<Array<HTMLButtonElement | null>>([]);
|
|
61
61
|
let open = $state(false);
|
|
62
|
+
const initialValues = untrack(() => [...values]);
|
|
62
63
|
const controlId = $derived(
|
|
63
64
|
interaction === false ? undefined : (interaction?.id ?? name ?? listId),
|
|
64
65
|
);
|
|
@@ -136,6 +137,44 @@ function handleOptionsKeydown(event: KeyboardEvent) {
|
|
|
136
137
|
enabled.length;
|
|
137
138
|
enabled[next]?.focus();
|
|
138
139
|
}
|
|
140
|
+
$effect(() => {
|
|
141
|
+
const form = triggerEl?.form;
|
|
142
|
+
if (!form) return;
|
|
143
|
+
let disposed = false;
|
|
144
|
+
const timers = new Set<ReturnType<typeof setTimeout>>();
|
|
145
|
+
const reset = (event: Event) => {
|
|
146
|
+
const valuesAtDispatch = values;
|
|
147
|
+
const snapshot = [...values];
|
|
148
|
+
// Native dispatch can checkpoint microtasks between reset listeners.
|
|
149
|
+
// Wait for the next task so later cancellation and edits win.
|
|
150
|
+
const timer = setTimeout(() => {
|
|
151
|
+
timers.delete(timer);
|
|
152
|
+
if (
|
|
153
|
+
disposed ||
|
|
154
|
+
event.defaultPrevented ||
|
|
155
|
+
values !== valuesAtDispatch ||
|
|
156
|
+
values.length !== snapshot.length ||
|
|
157
|
+
values.some((value, index) => !Object.is(value, snapshot[index]))
|
|
158
|
+
)
|
|
159
|
+
return;
|
|
160
|
+
values = [...initialValues];
|
|
161
|
+
closeOptions();
|
|
162
|
+
recordControlUserEdit(
|
|
163
|
+
interactionContext,
|
|
164
|
+
controlId,
|
|
165
|
+
interaction === false ? undefined : interaction?.subject,
|
|
166
|
+
);
|
|
167
|
+
onvalueschange?.(values);
|
|
168
|
+
});
|
|
169
|
+
timers.add(timer);
|
|
170
|
+
};
|
|
171
|
+
form.addEventListener('reset', reset);
|
|
172
|
+
return () => {
|
|
173
|
+
disposed = true;
|
|
174
|
+
form.removeEventListener('reset', reset);
|
|
175
|
+
for (const timer of timers) clearTimeout(timer);
|
|
176
|
+
};
|
|
177
|
+
});
|
|
139
178
|
$effect(() => {
|
|
140
179
|
if (!open) return;
|
|
141
180
|
const dismiss = (event: PointerEvent) => {
|
|
@@ -178,6 +217,7 @@ useControlRegistration(() => {
|
|
|
178
217
|
<div bind:this={rootEl} class="multi-select {className}" data-smrt-control={controlId} data-smrt-form={interactionContext?.formId}
|
|
179
218
|
data-smrt-subject-type={interaction === false ? undefined : interaction?.subject?.type}
|
|
180
219
|
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id}>
|
|
220
|
+
{#if name}{#each canonicalValues as value}<input type="hidden" {name} value={String(value)} disabled={disabled || options.some((option) => Object.is(option.value, value) && option.disabled)} />{/each}{/if}
|
|
181
221
|
<span class="label" id={`${listId}-label`}>{label}</span><button bind:this={triggerEl} id={triggerId} type="button" class="trigger" {disabled} aria-haspopup="listbox" aria-expanded={open} aria-controls={listId} aria-labelledby={`${listId}-label ${triggerId}`} onclick={() => open ? closeOptions() : openOptions()} onkeydown={handleTriggerKeydown}>{selectedLabels.length ? selectedLabels.join(', ') : placeholder}</button>
|
|
182
222
|
{#if open}<div id={listId} class="options" role="listbox" tabindex="-1" aria-multiselectable="true" aria-labelledby={`${listId}-label`} onkeydown={handleOptionsKeydown}>{#each options as option, index (option.value)}<button bind:this={optionEls[index]} type="button" role="option" tabindex="-1" aria-selected={canonicalValues.some((value) => Object.is(value, option.value))} disabled={option.disabled} onclick={() => toggle(option)}><span aria-hidden="true">{canonicalValues.some((value) => Object.is(value, option.value)) ? '✓' : ''}</span>{option.label}</button>{/each}</div>{/if}
|
|
183
223
|
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiSelect.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/MultiSelect.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,yBAAyB,EACzB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAalC,MAAM,WAAW,KAAK;IACpB,uCAAuC;IACvC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,mDAAmD;IACnD,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAChC,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mDAAmD;IACnD,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;IAChD,gDAAgD;IAChD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IAC1D,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"MultiSelect.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/MultiSelect.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,yBAAyB,EACzB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAalC,MAAM,WAAW,KAAK;IACpB,uCAAuC;IACvC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,mDAAmD;IACnD,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAChC,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mDAAmD;IACnD,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;IAChD,gDAAgD;IAChD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IAC1D,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgMD,QAAA,MAAM,WAAW,iDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -42,6 +42,7 @@ function handleChange(event: Event & { currentTarget: HTMLInputElement }) {
|
|
|
42
42
|
input:checked + .radio__mark { border-color: var(--smrt-color-primary); }
|
|
43
43
|
input:checked + .radio__mark::after { transform: scale(1); }
|
|
44
44
|
input:focus-visible + .radio__mark { outline: 2px solid var(--smrt-color-primary); outline-offset: 3px; }
|
|
45
|
+
.radio { min-height: var(--smrt-control-target-min, 0px); min-width: var(--smrt-control-target-min, 0px); }
|
|
45
46
|
|
|
46
47
|
/* Table cells: grow vertically only, never into a neighbouring cell. */
|
|
47
48
|
:global(:is(td, th)) .radio::before { inline-size: var(--_box); margin-inline-start: calc(var(--_box) / -2); }
|
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
import { setRadioGroupContext } from './radio-group-context.js';
|
|
15
15
|
import { useControlRegistration } from './use-control-registration.svelte.js';
|
|
16
16
|
export interface Props {
|
|
17
|
+
/** Target density; omit to inherit the ThemeProvider setting. */
|
|
18
|
+
density?: 'comfortable' | 'touch';
|
|
17
19
|
/** Identifier for this radio group and its form field. */
|
|
18
20
|
name: string;
|
|
19
21
|
/** The currently selected option value. */
|
|
@@ -49,6 +51,7 @@ let {
|
|
|
49
51
|
onvaluechange,
|
|
50
52
|
children,
|
|
51
53
|
class: className = '',
|
|
54
|
+
density,
|
|
52
55
|
}: Props = $props();
|
|
53
56
|
const interactionContext = tryGetControlInteractionContext();
|
|
54
57
|
let fieldsetEl = $state<HTMLFieldSetElement | null>(null);
|
|
@@ -133,7 +136,7 @@ useControlRegistration(() => {
|
|
|
133
136
|
};
|
|
134
137
|
});
|
|
135
138
|
</script>
|
|
136
|
-
<fieldset bind:this={fieldsetEl} class="radio-group {className}" {disabled}
|
|
139
|
+
<fieldset bind:this={fieldsetEl} data-density={density} class="radio-group {className}" {disabled}
|
|
137
140
|
aria-describedby={description ? `${name}-description` : undefined} data-smrt-control={controlId} data-smrt-form={interactionContext?.formId}
|
|
138
141
|
data-smrt-subject-type={interaction === false ? undefined : interaction?.subject?.type}
|
|
139
142
|
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id}>
|
|
@@ -149,4 +152,7 @@ useControlRegistration(() => {
|
|
|
149
152
|
.error { color: var(--smrt-color-error); }
|
|
150
153
|
.options { display: flex; flex-wrap: wrap; gap: var(--smrt-spacing-3); }
|
|
151
154
|
:global(.radio-group[data-smrt-highlighted='true']) { outline: 3px solid var(--smrt-color-tertiary); outline-offset: 4px; border-radius: var(--smrt-radius-small); }
|
|
155
|
+
|
|
156
|
+
.radio-group[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min, 48px); }
|
|
157
|
+
.radio-group[data-density='comfortable'] { --smrt-control-target-min: 0px; }
|
|
152
158
|
</style>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { ControlInteractionOptions } from './control-interaction.js';
|
|
3
3
|
export interface Props {
|
|
4
|
+
/** Target density; omit to inherit the ThemeProvider setting. */
|
|
5
|
+
density?: 'comfortable' | 'touch';
|
|
4
6
|
/** Identifier for this radio group and its form field. */
|
|
5
7
|
name: string;
|
|
6
8
|
/** The currently selected option value. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/RadioGroup.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,0BAA0B,CAAC;AASlC,MAAM,WAAW,KAAK;IACpB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mFAAmF;IACnF,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;IAChD,oDAAoD;IACpD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"RadioGroup.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/RadioGroup.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,0BAA0B,CAAC;AASlC,MAAM,WAAW,KAAK;IACpB,iEAAiE;IACjE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IAClC,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mFAAmF;IACnF,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;IAChD,oDAAoD;IACpD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAsHD,QAAA,MAAM,UAAU,gDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { tick, untrack } from 'svelte';
|
|
2
3
|
import {
|
|
3
4
|
emitControlChange,
|
|
4
5
|
highlightControl,
|
|
@@ -16,6 +17,8 @@ import {
|
|
|
16
17
|
import type { SegmentedControlOption } from './types.js';
|
|
17
18
|
import { useControlRegistration } from './use-control-registration.svelte.js';
|
|
18
19
|
export interface Props {
|
|
20
|
+
/** Target density; omit to inherit the ThemeProvider setting. */
|
|
21
|
+
density?: 'comfortable' | 'touch';
|
|
19
22
|
/** The available segments and their values. */
|
|
20
23
|
options: SegmentedControlOption[];
|
|
21
24
|
/** The currently selected option value. */
|
|
@@ -24,6 +27,8 @@ export interface Props {
|
|
|
24
27
|
label: string;
|
|
25
28
|
/** Form field identifier. */
|
|
26
29
|
name?: string;
|
|
30
|
+
/** Requires an enabled option to be selected before native form submission. */
|
|
31
|
+
required?: boolean;
|
|
27
32
|
/** Blocks interaction and submission of this control. */
|
|
28
33
|
disabled?: boolean;
|
|
29
34
|
/** Makes the control stretch to full container width. */
|
|
@@ -40,13 +45,128 @@ let {
|
|
|
40
45
|
value = $bindable(),
|
|
41
46
|
label,
|
|
42
47
|
name,
|
|
48
|
+
required = false,
|
|
43
49
|
disabled = false,
|
|
44
50
|
fullWidth = false,
|
|
45
51
|
interaction,
|
|
46
52
|
onvaluechange,
|
|
47
53
|
class: className = '',
|
|
54
|
+
density,
|
|
48
55
|
}: Props = $props();
|
|
49
56
|
const instanceId = $props.id();
|
|
57
|
+
const initialValue = untrack(() => value);
|
|
58
|
+
const selectedOption = $derived(
|
|
59
|
+
options.find((option) => option.value === value && !option.disabled),
|
|
60
|
+
);
|
|
61
|
+
const firstEnabledOption = $derived(options.find((option) => !option.disabled));
|
|
62
|
+
const validationOption = $derived(selectedOption ?? firstEnabledOption);
|
|
63
|
+
// Required nameless radio groups need explicit validity in browsers, while
|
|
64
|
+
// remaining unnamed so native FormData never receives a generated field.
|
|
65
|
+
$effect(() => {
|
|
66
|
+
rootEl
|
|
67
|
+
?.querySelectorAll<HTMLInputElement>('input[type="radio"]')
|
|
68
|
+
.forEach((input) => {
|
|
69
|
+
input.setCustomValidity(
|
|
70
|
+
!name &&
|
|
71
|
+
required &&
|
|
72
|
+
!selectedOption &&
|
|
73
|
+
options[Number(input.dataset.optionIndex)] === validationOption
|
|
74
|
+
? 'Please select an option.'
|
|
75
|
+
: '',
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
function initializeRadio(
|
|
80
|
+
node: HTMLInputElement,
|
|
81
|
+
option: SegmentedControlOption,
|
|
82
|
+
) {
|
|
83
|
+
node.defaultChecked = initialValue === option.value && !option.disabled;
|
|
84
|
+
}
|
|
85
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
86
|
+
if (
|
|
87
|
+
!(event.target instanceof HTMLInputElement) ||
|
|
88
|
+
event.target.matches(':disabled')
|
|
89
|
+
)
|
|
90
|
+
return;
|
|
91
|
+
const radios = Array.from(
|
|
92
|
+
rootEl?.querySelectorAll<HTMLInputElement>(
|
|
93
|
+
'input[type="radio"]:not(:disabled)',
|
|
94
|
+
) ?? [],
|
|
95
|
+
);
|
|
96
|
+
const index = radios.indexOf(event.target);
|
|
97
|
+
let next: number;
|
|
98
|
+
switch (event.key) {
|
|
99
|
+
case 'ArrowRight':
|
|
100
|
+
case 'ArrowDown':
|
|
101
|
+
next = (index + 1) % radios.length;
|
|
102
|
+
break;
|
|
103
|
+
case 'ArrowLeft':
|
|
104
|
+
case 'ArrowUp':
|
|
105
|
+
next = (index - 1 + radios.length) % radios.length;
|
|
106
|
+
break;
|
|
107
|
+
case 'Home':
|
|
108
|
+
next = 0;
|
|
109
|
+
break;
|
|
110
|
+
case 'End':
|
|
111
|
+
next = radios.length - 1;
|
|
112
|
+
break;
|
|
113
|
+
default:
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const radio = radios[next];
|
|
117
|
+
if (!radio) return;
|
|
118
|
+
event.preventDefault();
|
|
119
|
+
radio.focus();
|
|
120
|
+
setValue(options[Number(radio.dataset.optionIndex)].value, true);
|
|
121
|
+
}
|
|
122
|
+
$effect(() => {
|
|
123
|
+
const root = rootEl;
|
|
124
|
+
if (!root) return;
|
|
125
|
+
let form: HTMLFormElement | null = null;
|
|
126
|
+
let disposed = false;
|
|
127
|
+
const reset = (event: Event) => {
|
|
128
|
+
const valueAtDispatch = value;
|
|
129
|
+
// Native event dispatch may checkpoint microtasks between listeners; wait
|
|
130
|
+
// for the next task so a later form listener can still cancel the reset.
|
|
131
|
+
setTimeout(async () => {
|
|
132
|
+
if (
|
|
133
|
+
event.defaultPrevented ||
|
|
134
|
+
!rootEl?.isConnected ||
|
|
135
|
+
!Object.is(value, valueAtDispatch)
|
|
136
|
+
)
|
|
137
|
+
return;
|
|
138
|
+
const resetOption = options.find(
|
|
139
|
+
(option) => option.value === initialValue && !option.disabled,
|
|
140
|
+
);
|
|
141
|
+
value = resetOption?.value;
|
|
142
|
+
recordControlUserEdit(
|
|
143
|
+
interactionContext,
|
|
144
|
+
controlId,
|
|
145
|
+
interaction === false ? undefined : interaction?.subject,
|
|
146
|
+
);
|
|
147
|
+
await tick();
|
|
148
|
+
// A canceled reset never reaches this reconciliation; unchanged bound values
|
|
149
|
+
// still need checked properties restored after the browser's native reset.
|
|
150
|
+
rootEl
|
|
151
|
+
?.querySelectorAll<HTMLInputElement>('input[type="radio"]')
|
|
152
|
+
.forEach((input) => {
|
|
153
|
+
input.checked =
|
|
154
|
+
options[Number(input.dataset.optionIndex)]?.value === value &&
|
|
155
|
+
!input.disabled;
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
// Parent form ancestry is complete after the mount flush, including in SSR hydration.
|
|
160
|
+
tick().then(() => {
|
|
161
|
+
if (disposed) return;
|
|
162
|
+
form = root.closest('form');
|
|
163
|
+
form?.addEventListener('reset', reset);
|
|
164
|
+
});
|
|
165
|
+
return () => {
|
|
166
|
+
disposed = true;
|
|
167
|
+
form?.removeEventListener('reset', reset);
|
|
168
|
+
};
|
|
169
|
+
});
|
|
50
170
|
const interactionContext = tryGetControlInteractionContext();
|
|
51
171
|
let rootEl = $state<HTMLDivElement | null>(null);
|
|
52
172
|
const controlId = $derived(
|
|
@@ -54,7 +174,7 @@ const controlId = $derived(
|
|
|
54
174
|
? undefined
|
|
55
175
|
: (interaction?.id ?? name ?? `segment-${instanceId}`),
|
|
56
176
|
);
|
|
57
|
-
function setValue(next: unknown, userEdit = false) {
|
|
177
|
+
function setValue(next: unknown, userEdit = false, emitChange = true) {
|
|
58
178
|
const option = options.find((item) => String(item.value) === String(next));
|
|
59
179
|
if (!option || option.disabled) return;
|
|
60
180
|
const changed = !Object.is(value, option.value);
|
|
@@ -66,7 +186,7 @@ function setValue(next: unknown, userEdit = false) {
|
|
|
66
186
|
controlId,
|
|
67
187
|
interaction === false ? undefined : interaction?.subject,
|
|
68
188
|
);
|
|
69
|
-
if (rootEl) emitControlChange(rootEl);
|
|
189
|
+
if (rootEl && emitChange) emitControlChange(rootEl);
|
|
70
190
|
}
|
|
71
191
|
}
|
|
72
192
|
useControlRegistration(() => {
|
|
@@ -83,6 +203,7 @@ useControlRegistration(() => {
|
|
|
83
203
|
readable: interaction?.readable,
|
|
84
204
|
writable: interaction?.writable,
|
|
85
205
|
options,
|
|
206
|
+
constraints: { required },
|
|
86
207
|
},
|
|
87
208
|
getValue: () => value,
|
|
88
209
|
prepareValue: (next) => prepareEnabledOptionValue(options, next),
|
|
@@ -93,31 +214,51 @@ useControlRegistration(() => {
|
|
|
93
214
|
},
|
|
94
215
|
focus: () =>
|
|
95
216
|
root
|
|
96
|
-
.querySelector<HTMLElement>('[
|
|
217
|
+
.querySelector<HTMLElement>('input[type="radio"]:not(:disabled)')
|
|
97
218
|
?.focus(),
|
|
98
219
|
reveal: () => revealControl(root),
|
|
99
220
|
highlight: (durationMs) => highlightControl(root, durationMs),
|
|
221
|
+
validate: () =>
|
|
222
|
+
root
|
|
223
|
+
.querySelector<HTMLInputElement>('input[type="radio"]:not(:disabled)')
|
|
224
|
+
?.reportValidity() ?? true,
|
|
100
225
|
validateValue: (next) => validatesEnabledOption(options, next),
|
|
101
226
|
getState: () => ({
|
|
102
227
|
disabled: disabled || root.closest('fieldset:disabled') !== null,
|
|
228
|
+
valid:
|
|
229
|
+
!required ||
|
|
230
|
+
!!selectedOption ||
|
|
231
|
+
disabled ||
|
|
232
|
+
root.closest('fieldset:disabled') !== null,
|
|
103
233
|
}),
|
|
104
234
|
};
|
|
105
235
|
});
|
|
106
236
|
</script>
|
|
107
|
-
<div bind:this={rootEl} class="segmented {className}" class:full-width={fullWidth} role="radiogroup" aria-label={label} data-smrt-control={controlId} data-smrt-form={interactionContext?.formId}
|
|
237
|
+
<div bind:this={rootEl} data-density={density} class="segmented {className}" class:full-width={fullWidth} role="radiogroup" tabindex="-1" aria-label={label} aria-required={required} onkeydown={handleKeydown} data-smrt-control={controlId} data-smrt-form={interactionContext?.formId}
|
|
108
238
|
data-smrt-subject-type={interaction === false ? undefined : interaction?.subject?.type}
|
|
109
239
|
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id}>
|
|
110
|
-
{#each options as option (option.value)}
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
240
|
+
{#each options as option, index (option.value)}
|
|
241
|
+
<label class:selected={selectedOption === option} class:disabled={disabled || option.disabled}>
|
|
242
|
+
<input type="radio" {name} value={option.value} disabled={disabled || option.disabled}
|
|
243
|
+
required={required && validationOption === option} aria-label={option.label}
|
|
244
|
+
checked={selectedOption === option} aria-checked={selectedOption === option}
|
|
245
|
+
tabindex={selectedOption === option || (!selectedOption && firstEnabledOption === option) ? 0 : -1}
|
|
246
|
+
data-option-index={index} use:initializeRadio={option}
|
|
247
|
+
onchange={() => setValue(option.value, true, false)} />
|
|
248
|
+
<span>{option.label}</span>
|
|
249
|
+
</label>
|
|
114
250
|
{/each}
|
|
115
251
|
</div>
|
|
116
252
|
<style>
|
|
117
253
|
.segmented { display: inline-flex; border: 1px solid var(--smrt-color-outline); border-radius: var(--smrt-radius-full); overflow: hidden; }
|
|
118
254
|
.segmented.full-width { display: flex; width: 100%; }
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
255
|
+
label { position: relative; display: inline-flex; align-items: center; justify-content: center; flex: 1; min-height: 2.5rem; padding: 0 var(--smrt-spacing-4); border: 0; border-right: 1px solid var(--smrt-color-outline); background: var(--smrt-color-surface); color: var(--smrt-color-on-surface); cursor: pointer; }
|
|
256
|
+
label:last-child { border-right: 0; } label.selected { background: var(--smrt-color-secondary-container); color: var(--smrt-color-on-secondary-container); }
|
|
257
|
+
label:has(input:focus-visible) { outline: 2px solid var(--smrt-color-primary); outline-offset: -3px; } label.disabled, label:has(input:disabled) { opacity: .5; cursor: not-allowed; }
|
|
122
258
|
:global(.segmented[data-smrt-highlighted='true']) { outline: 3px solid var(--smrt-color-tertiary); outline-offset: 4px; }
|
|
259
|
+
|
|
260
|
+
.segmented[data-density='touch'] { --smrt-control-target-min: var(--smrt-touch-target-min, 48px); }
|
|
261
|
+
.segmented[data-density='comfortable'] { --smrt-control-target-min: 0px; }
|
|
262
|
+
label { min-height: max(2.5rem, var(--smrt-control-target-min, 0px)); min-width: var(--smrt-control-target-min, 0px); }
|
|
263
|
+
input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: inherit; }
|
|
123
264
|
</style>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ControlInteractionOptions } from './control-interaction.js';
|
|
2
2
|
import type { SegmentedControlOption } from './types.js';
|
|
3
3
|
export interface Props {
|
|
4
|
+
/** Target density; omit to inherit the ThemeProvider setting. */
|
|
5
|
+
density?: 'comfortable' | 'touch';
|
|
4
6
|
/** The available segments and their values. */
|
|
5
7
|
options: SegmentedControlOption[];
|
|
6
8
|
/** The currently selected option value. */
|
|
@@ -9,6 +11,8 @@ export interface Props {
|
|
|
9
11
|
label: string;
|
|
10
12
|
/** Form field identifier. */
|
|
11
13
|
name?: string;
|
|
14
|
+
/** Requires an enabled option to be selected before native form submission. */
|
|
15
|
+
required?: boolean;
|
|
12
16
|
/** Blocks interaction and submission of this control. */
|
|
13
17
|
disabled?: boolean;
|
|
14
18
|
/** Makes the control stretch to full container width. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedControl.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/SegmentedControl.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SegmentedControl.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/SegmentedControl.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAS1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGzD,MAAM,WAAW,KAAK;IACpB,iEAAiE;IACjE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IAClC,+CAA+C;IAC/C,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;IAChD,+CAA+C;IAC/C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACjD,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAwND,QAAA,MAAM,gBAAgB,gDAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|