@salmexio/ui 1.2.1 → 1.3.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/dist/feedback/Alert/Alert.svelte +4 -1
- package/dist/feedback/Alert/Alert.svelte.d.ts +1 -0
- package/dist/feedback/Alert/Alert.svelte.d.ts.map +1 -1
- package/dist/feedback/Spinner/Spinner.svelte +4 -1
- package/dist/feedback/Spinner/Spinner.svelte.d.ts +1 -0
- package/dist/feedback/Spinner/Spinner.svelte.d.ts.map +1 -1
- package/dist/forms/DatePicker/DatePicker.svelte +725 -0
- package/dist/forms/DatePicker/DatePicker.svelte.d.ts +48 -0
- package/dist/forms/DatePicker/DatePicker.svelte.d.ts.map +1 -0
- package/dist/forms/DatePicker/index.d.ts +2 -0
- package/dist/forms/DatePicker/index.d.ts.map +1 -0
- package/dist/forms/DatePicker/index.js +1 -0
- package/dist/forms/FormField/FormField.svelte +173 -0
- package/dist/forms/FormField/FormField.svelte.d.ts +46 -0
- package/dist/forms/FormField/FormField.svelte.d.ts.map +1 -0
- package/dist/forms/FormField/index.d.ts +2 -0
- package/dist/forms/FormField/index.d.ts.map +1 -0
- package/dist/forms/FormField/index.js +1 -0
- package/dist/forms/MultiSelect/MultiSelect.svelte +820 -0
- package/dist/forms/MultiSelect/MultiSelect.svelte.d.ts +69 -0
- package/dist/forms/MultiSelect/MultiSelect.svelte.d.ts.map +1 -0
- package/dist/forms/MultiSelect/index.d.ts +3 -0
- package/dist/forms/MultiSelect/index.d.ts.map +1 -0
- package/dist/forms/MultiSelect/index.js +1 -0
- package/dist/forms/PhoneInput/PhoneInput.svelte +591 -0
- package/dist/forms/PhoneInput/PhoneInput.svelte.d.ts +57 -0
- package/dist/forms/PhoneInput/PhoneInput.svelte.d.ts.map +1 -0
- package/dist/forms/PhoneInput/index.d.ts +4 -0
- package/dist/forms/PhoneInput/index.d.ts.map +1 -0
- package/dist/forms/PhoneInput/index.js +2 -0
- package/dist/forms/RadioGroup/RadioGroup.svelte +417 -0
- package/dist/forms/RadioGroup/RadioGroup.svelte.d.ts +62 -0
- package/dist/forms/RadioGroup/RadioGroup.svelte.d.ts.map +1 -0
- package/dist/forms/RadioGroup/index.d.ts +3 -0
- package/dist/forms/RadioGroup/index.d.ts.map +1 -0
- package/dist/forms/RadioGroup/index.js +1 -0
- package/dist/forms/SearchInput/SearchInput.svelte +788 -0
- package/dist/forms/SearchInput/SearchInput.svelte.d.ts +79 -0
- package/dist/forms/SearchInput/SearchInput.svelte.d.ts.map +1 -0
- package/dist/forms/SearchInput/index.d.ts +3 -0
- package/dist/forms/SearchInput/index.d.ts.map +1 -0
- package/dist/forms/SearchInput/index.js +1 -0
- package/dist/forms/Select/Select.svelte +14 -8
- package/dist/forms/Select/Select.svelte.d.ts +2 -0
- package/dist/forms/Select/Select.svelte.d.ts.map +1 -1
- package/dist/forms/TextInput/TextInput.svelte +38 -16
- package/dist/forms/TextInput/TextInput.svelte.d.ts +6 -0
- package/dist/forms/TextInput/TextInput.svelte.d.ts.map +1 -1
- package/dist/forms/Textarea/Textarea.svelte +7 -1
- package/dist/forms/Textarea/Textarea.svelte.d.ts +2 -0
- package/dist/forms/Textarea/Textarea.svelte.d.ts.map +1 -1
- package/dist/forms/TimePicker/TimePicker.svelte +417 -0
- package/dist/forms/TimePicker/TimePicker.svelte.d.ts +53 -0
- package/dist/forms/TimePicker/TimePicker.svelte.d.ts.map +1 -0
- package/dist/forms/TimePicker/index.d.ts +2 -0
- package/dist/forms/TimePicker/index.d.ts.map +1 -0
- package/dist/forms/TimePicker/index.js +1 -0
- package/dist/forms/index.d.ts +12 -0
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +8 -0
- package/dist/layout/Container/Container.svelte +3 -0
- package/dist/layout/Container/Container.svelte.d.ts +1 -0
- package/dist/layout/Container/Container.svelte.d.ts.map +1 -1
- package/dist/primitives/Badge/Badge.svelte +5 -1
- package/dist/primitives/Badge/Badge.svelte.d.ts +1 -0
- package/dist/primitives/Badge/Badge.svelte.d.ts.map +1 -1
- package/dist/primitives/Tooltip/Tooltip.svelte +7 -1
- package/dist/primitives/Tooltip/Tooltip.svelte.d.ts.map +1 -1
- package/dist/utils/accessibility.d.ts +16 -0
- package/dist/utils/accessibility.d.ts.map +1 -0
- package/dist/utils/accessibility.js +80 -0
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/keyboard.d.ts +6 -0
- package/dist/utils/keyboard.d.ts.map +1 -1
- package/dist/utils/keyboard.js +15 -9
- package/package.json +21 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export interface SearchOption {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface SearchGroup {
|
|
8
|
+
label: string;
|
|
9
|
+
options: SearchOption[];
|
|
10
|
+
}
|
|
11
|
+
type SearchSize = 'sm' | 'md' | 'lg';
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Visible label. */
|
|
14
|
+
label: string;
|
|
15
|
+
/** Search query value (bindable). */
|
|
16
|
+
value?: string;
|
|
17
|
+
/** Flat list of options. */
|
|
18
|
+
options?: SearchOption[];
|
|
19
|
+
/** Grouped options. */
|
|
20
|
+
groups?: SearchGroup[];
|
|
21
|
+
/** Placeholder text. */
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
/** Minimum characters before showing suggestions. */
|
|
24
|
+
minChars?: number;
|
|
25
|
+
/** Debounce delay in ms for the onsearch callback. */
|
|
26
|
+
debounceMs?: number;
|
|
27
|
+
/** Show loading spinner in dropdown. */
|
|
28
|
+
loading?: boolean;
|
|
29
|
+
/** Allow clearing the input. */
|
|
30
|
+
clearable?: boolean;
|
|
31
|
+
/** Size variant. */
|
|
32
|
+
size?: SearchSize;
|
|
33
|
+
/** Error message. */
|
|
34
|
+
error?: string;
|
|
35
|
+
/** Hint text. */
|
|
36
|
+
hint?: string;
|
|
37
|
+
/** Disabled state. */
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
/** Required field. */
|
|
40
|
+
required?: boolean;
|
|
41
|
+
/** Hide the visible label. */
|
|
42
|
+
hideLabel?: boolean;
|
|
43
|
+
/** Reserve footer space even when empty. */
|
|
44
|
+
alwaysShowFooter?: boolean;
|
|
45
|
+
/** Additional CSS class. */
|
|
46
|
+
class?: string;
|
|
47
|
+
/** Called when an option is selected. */
|
|
48
|
+
onselect?: (option: SearchOption) => void;
|
|
49
|
+
/** Called when search query changes (debounced). */
|
|
50
|
+
onsearch?: (query: string) => void;
|
|
51
|
+
/** Called when input value changes. */
|
|
52
|
+
oninput?: (event: Event) => void;
|
|
53
|
+
/** Called when input loses focus. */
|
|
54
|
+
onblur?: (event: FocusEvent) => void;
|
|
55
|
+
/** Test ID. */
|
|
56
|
+
testId?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* SearchInput
|
|
60
|
+
*
|
|
61
|
+
* INFRARED — Search input with autocomplete dropdown, match highlighting,
|
|
62
|
+
* grouped results, loading state, and keyboard navigation.
|
|
63
|
+
* Follows WAI-ARIA combobox pattern.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* <SearchInput
|
|
67
|
+
* label="Search models"
|
|
68
|
+
* options={[
|
|
69
|
+
* { value: 'opus', label: 'Claude Opus' },
|
|
70
|
+
* { value: 'sonnet', label: 'Claude Sonnet' },
|
|
71
|
+
* ]}
|
|
72
|
+
* bind:value={query}
|
|
73
|
+
* onselect={(opt) => console.log(opt)}
|
|
74
|
+
* />
|
|
75
|
+
*/
|
|
76
|
+
declare const SearchInput: import("svelte").Component<Props, {}, "value">;
|
|
77
|
+
type SearchInput = ReturnType<typeof SearchInput>;
|
|
78
|
+
export default SearchInput;
|
|
79
|
+
//# sourceMappingURL=SearchInput.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/forms/SearchInput/SearchInput.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;CACxB;AAQD,KAAK,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAErC,UAAU,KAAK;IACd,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,uBAAuB;IACvB,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,oDAAoD;IACpD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,uCAAuC;IACvC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,qCAAqC;IACrC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,eAAe;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAqZD;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,WAAW,gDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/forms/SearchInput/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as SearchInput } from './SearchInput.svelte';
|
|
@@ -71,6 +71,8 @@ interface Props {
|
|
|
71
71
|
onchangemulti?: (values: string[]) => void;
|
|
72
72
|
/** Test ID */
|
|
73
73
|
testId?: string;
|
|
74
|
+
/** Reserve footer space even when empty (prevents layout shift). */
|
|
75
|
+
alwaysShowFooter?: boolean;
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
let {
|
|
@@ -90,7 +92,8 @@ let {
|
|
|
90
92
|
class: className = '',
|
|
91
93
|
onchange,
|
|
92
94
|
onchangemulti,
|
|
93
|
-
testId
|
|
95
|
+
testId,
|
|
96
|
+
alwaysShowFooter = true
|
|
94
97
|
}: Props = $props();
|
|
95
98
|
|
|
96
99
|
const id = `select-${Math.random().toString(36).slice(2, 9)}`;
|
|
@@ -150,6 +153,7 @@ const showError = $derived(hasInteracted && !!error);
|
|
|
150
153
|
const ariaDescribedBy = $derived(
|
|
151
154
|
[showError && errorId, hint && hintId].filter(Boolean).join(' ') || undefined
|
|
152
155
|
);
|
|
156
|
+
const hasFooterContent = $derived(showError || !!hint);
|
|
153
157
|
|
|
154
158
|
function positionDropdown() {
|
|
155
159
|
if (!triggerEl) return;
|
|
@@ -478,13 +482,15 @@ onMount(() => {
|
|
|
478
482
|
</button>
|
|
479
483
|
|
|
480
484
|
<!-- Footer: error / hint -->
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
485
|
+
{#if alwaysShowFooter || hasFooterContent}
|
|
486
|
+
<div class="sx-select-footer">
|
|
487
|
+
{#if showError}
|
|
488
|
+
<p id={errorId} class="sx-select-error" role="alert" aria-live="assertive">{error}</p>
|
|
489
|
+
{:else if hint}
|
|
490
|
+
<p id={hintId} class="sx-select-hint">{hint}</p>
|
|
491
|
+
{/if}
|
|
492
|
+
</div>
|
|
493
|
+
{/if}
|
|
488
494
|
</div>
|
|
489
495
|
|
|
490
496
|
<!-- Dropdown panel -- fixed positioning to escape overflow/stacking contexts -->
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.svelte.d.ts","sourceRoot":"","sources":["../../../src/forms/Select/Select.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;CACxB;AAQD,KAAK,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAErC,UAAU,KAAK;IACd,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,wDAAwD;IACxD,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,6CAA6C;IAC7C,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC3C,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"Select.svelte.d.ts","sourceRoot":"","sources":["../../../src/forms/Select/Select.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;CACxB;AAQD,KAAK,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAErC,UAAU,KAAK;IACd,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,wDAAwD;IACxD,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,6CAA6C;IAC7C,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC3C,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC3B;AA2dD;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,MAAM,2DAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
<script lang="ts">
|
|
8
8
|
import type { Snippet } from 'svelte';
|
|
9
9
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
10
|
+
import { onDestroy } from 'svelte';
|
|
10
11
|
import { cn } from '../../utils/cn.js';
|
|
11
12
|
|
|
12
13
|
type InputSize = 'sm' | 'md' | 'lg';
|
|
@@ -47,6 +48,12 @@ interface Props extends Omit<HTMLInputAttributes, 'class' | 'size' | 'inputmode'
|
|
|
47
48
|
onclear?: () => void;
|
|
48
49
|
testId?: string;
|
|
49
50
|
validateOnMount?: boolean;
|
|
51
|
+
/** Debounce delay in ms. Fires ondebounce after typing pauses. */
|
|
52
|
+
debounceMs?: number;
|
|
53
|
+
/** Called after debounce delay with current value. */
|
|
54
|
+
ondebounce?: (value: string) => void;
|
|
55
|
+
/** Reserve footer space even when empty (prevents layout shift). */
|
|
56
|
+
alwaysShowFooter?: boolean;
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
let {
|
|
@@ -84,6 +91,9 @@ let {
|
|
|
84
91
|
onclear,
|
|
85
92
|
testId,
|
|
86
93
|
validateOnMount = false,
|
|
94
|
+
debounceMs,
|
|
95
|
+
ondebounce,
|
|
96
|
+
alwaysShowFooter = true,
|
|
87
97
|
...restProps
|
|
88
98
|
}: Props = $props();
|
|
89
99
|
|
|
@@ -91,6 +101,9 @@ let inputRef = $state<HTMLInputElement | undefined>();
|
|
|
91
101
|
let isFocused = $state(false);
|
|
92
102
|
let hasInteracted = $state(false);
|
|
93
103
|
let passwordVisible = $state(false);
|
|
104
|
+
let debounceTimer: ReturnType<typeof setTimeout> | undefined;
|
|
105
|
+
|
|
106
|
+
onDestroy(() => clearTimeout(debounceTimer));
|
|
94
107
|
|
|
95
108
|
const shouldValidate = $derived(hasInteracted || validateOnMount);
|
|
96
109
|
const showError = $derived(shouldValidate && !!error);
|
|
@@ -109,11 +122,18 @@ const hasRightContent = $derived(
|
|
|
109
122
|
const ariaDescribedBy = $derived(
|
|
110
123
|
[error && errorId, hint && hintId].filter(Boolean).join(' ') || undefined
|
|
111
124
|
);
|
|
125
|
+
const hasFooterContent = $derived(
|
|
126
|
+
showError || showSuccess || !!hint || (showCharCount && maxLength !== undefined)
|
|
127
|
+
);
|
|
112
128
|
|
|
113
129
|
function handleInput(e: Event) {
|
|
114
130
|
const target = e.target as HTMLInputElement;
|
|
115
131
|
value = target.value;
|
|
116
132
|
oninput?.(e);
|
|
133
|
+
if (debounceMs && ondebounce) {
|
|
134
|
+
clearTimeout(debounceTimer);
|
|
135
|
+
debounceTimer = setTimeout(() => ondebounce!(value), debounceMs);
|
|
136
|
+
}
|
|
117
137
|
}
|
|
118
138
|
|
|
119
139
|
function handleBlur(e: FocusEvent) {
|
|
@@ -272,24 +292,26 @@ function handleKeyDown(e: KeyboardEvent) {
|
|
|
272
292
|
{/if}
|
|
273
293
|
</div>
|
|
274
294
|
|
|
275
|
-
|
|
276
|
-
<div class="sx-input-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
{error
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
295
|
+
{#if alwaysShowFooter || hasFooterContent}
|
|
296
|
+
<div class="sx-input-footer" class:sx-input-footer-empty={!hasFooterContent}>
|
|
297
|
+
<div class="sx-input-messages">
|
|
298
|
+
{#if showError}
|
|
299
|
+
<p id={errorId} class="sx-input-message sx-input-message-error" role="alert" aria-live="assertive">
|
|
300
|
+
{error}
|
|
301
|
+
</p>
|
|
302
|
+
{:else if showSuccess}
|
|
303
|
+
<p class="sx-input-message sx-input-message-success" role="status" aria-live="polite">{successMessage}</p>
|
|
304
|
+
{:else if hint}
|
|
305
|
+
<p id={hintId} class="sx-input-message sx-input-message-hint">{hint}</p>
|
|
306
|
+
{/if}
|
|
307
|
+
</div>
|
|
308
|
+
{#if showCharCount && maxLength !== undefined}
|
|
309
|
+
<span class="sx-input-charcount" class:sx-input-charcount-warn={value.length > maxLength * 0.9}>
|
|
310
|
+
{value.length}/{maxLength}
|
|
311
|
+
</span>
|
|
285
312
|
{/if}
|
|
286
313
|
</div>
|
|
287
|
-
|
|
288
|
-
<span class="sx-input-charcount" class:sx-input-charcount-warn={value.length > maxLength * 0.9}>
|
|
289
|
-
{value.length}/{maxLength}
|
|
290
|
-
</span>
|
|
291
|
-
{/if}
|
|
292
|
-
</div>
|
|
314
|
+
{/if}
|
|
293
315
|
</div>
|
|
294
316
|
|
|
295
317
|
<style>
|
|
@@ -37,6 +37,12 @@ interface Props extends Omit<HTMLInputAttributes, 'class' | 'size' | 'inputmode'
|
|
|
37
37
|
onclear?: () => void;
|
|
38
38
|
testId?: string;
|
|
39
39
|
validateOnMount?: boolean;
|
|
40
|
+
/** Debounce delay in ms. Fires ondebounce after typing pauses. */
|
|
41
|
+
debounceMs?: number;
|
|
42
|
+
/** Called after debounce delay with current value. */
|
|
43
|
+
ondebounce?: (value: string) => void;
|
|
44
|
+
/** Reserve footer space even when empty (prevents layout shift). */
|
|
45
|
+
alwaysShowFooter?: boolean;
|
|
40
46
|
}
|
|
41
47
|
/**
|
|
42
48
|
* TextInput
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/forms/TextInput/TextInput.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"TextInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/forms/TextInput/TextInput.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAK3D,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACpC,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9F,UAAU,KAAM,SAAQ,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,GAAG,cAAc,CAAC;IACjG,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC3B;AAuOD;;;;;GAKG;AACH,QAAA,MAAM,SAAS,gDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
|
@@ -45,6 +45,8 @@ interface Props {
|
|
|
45
45
|
onblur?: (event: FocusEvent) => void;
|
|
46
46
|
onfocus?: (event: FocusEvent) => void;
|
|
47
47
|
testId?: string;
|
|
48
|
+
/** Reserve footer space even when empty (prevents layout shift). */
|
|
49
|
+
alwaysShowFooter?: boolean;
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
let {
|
|
@@ -73,7 +75,8 @@ let {
|
|
|
73
75
|
oninput,
|
|
74
76
|
onblur,
|
|
75
77
|
onfocus,
|
|
76
|
-
testId
|
|
78
|
+
testId,
|
|
79
|
+
alwaysShowFooter = true
|
|
77
80
|
}: Props = $props();
|
|
78
81
|
|
|
79
82
|
let textareaEl = $state<HTMLTextAreaElement | null>(null);
|
|
@@ -95,6 +98,7 @@ const showHandle = $derived(effectiveResize !== 'none' && !disabled);
|
|
|
95
98
|
const resizeVertical = $derived(effectiveResize === 'vertical' || effectiveResize === 'both');
|
|
96
99
|
const resizeHorizontal = $derived(effectiveResize === 'horizontal' || effectiveResize === 'both');
|
|
97
100
|
|
|
101
|
+
const hasFooterContent = $derived(!!error || !!successMessage || !!hint || showCharCount);
|
|
98
102
|
const describedBy = $derived(
|
|
99
103
|
[
|
|
100
104
|
error ? errorId : null,
|
|
@@ -297,6 +301,7 @@ onMount(() => {
|
|
|
297
301
|
{/if}
|
|
298
302
|
</div>
|
|
299
303
|
|
|
304
|
+
{#if alwaysShowFooter || hasFooterContent}
|
|
300
305
|
<div class="sx-textarea-footer">
|
|
301
306
|
<div class="sx-textarea-messages">
|
|
302
307
|
{#if error}
|
|
@@ -332,6 +337,7 @@ onMount(() => {
|
|
|
332
337
|
</span>
|
|
333
338
|
{/if}
|
|
334
339
|
</div>
|
|
340
|
+
{/if}
|
|
335
341
|
</div>
|
|
336
342
|
|
|
337
343
|
<style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.svelte.d.ts","sourceRoot":"","sources":["../../../src/forms/Textarea/Textarea.svelte.ts"],"names":[],"mappings":"AAOA,KAAK,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACvC,KAAK,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;AAE9D,UAAU,KAAK;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gEAAgE;IAChE,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"Textarea.svelte.d.ts","sourceRoot":"","sources":["../../../src/forms/Textarea/Textarea.svelte.ts"],"names":[],"mappings":"AAOA,KAAK,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACvC,KAAK,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;AAE9D,UAAU,KAAK;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gEAAgE;IAChE,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC3B;AA2QD;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,QAAQ,gDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|