@salmexio/ui 1.2.1 → 1.3.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/dist/dialogs/Modal/Modal.svelte +1 -1
- 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/Skeleton/Skeleton.svelte +3 -13
- package/dist/feedback/Skeleton/Skeleton.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/feedback/Toast/Toaster.svelte +9 -8
- package/dist/feedback/Toast/Toaster.svelte.d.ts.map +1 -1
- package/dist/forms/DatePicker/DatePicker.svelte +755 -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/Toggle/Toggle.svelte +0 -2
- package/dist/forms/Toggle/Toggle.svelte.d.ts.map +1 -1
- 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/layout/ThermalBackground/ThermalBackground.svelte +17 -17
- package/dist/layout/ThermalBackground/ThermalBackground.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/styles/tokens.css +78 -46
- 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
|
@@ -147,7 +147,13 @@ function positionTooltip() {
|
|
|
147
147
|
$effect(() => {
|
|
148
148
|
if (tooltipEl && visible) {
|
|
149
149
|
document.body.appendChild(tooltipEl);
|
|
150
|
-
|
|
150
|
+
// Position only after the node is in body and laid out (showcase-style behavior)
|
|
151
|
+
const run = () => {
|
|
152
|
+
tick().then(() => {
|
|
153
|
+
positionTooltip();
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
requestAnimationFrame(run);
|
|
151
157
|
return () => {
|
|
152
158
|
if (tooltipEl?.parentNode === document.body) {
|
|
153
159
|
document.body.removeChild(tooltipEl);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.svelte.d.ts","sourceRoot":"","sources":["../../../src/primitives/Tooltip/Tooltip.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAMtC,KAAK,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAErD,UAAU,KAAK;IACd,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8BAA8B;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"Tooltip.svelte.d.ts","sourceRoot":"","sources":["../../../src/primitives/Tooltip/Tooltip.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAMtC,KAAK,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAErD,UAAU,KAAK;IACd,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8BAA8B;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAsKD;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,OAAO,2CAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
|
package/dist/styles/tokens.css
CHANGED
|
@@ -17,42 +17,42 @@
|
|
|
17
17
|
Raw palette — never use directly in components
|
|
18
18
|
======================================== */
|
|
19
19
|
|
|
20
|
-
--sx-gray-950: #
|
|
21
|
-
--sx-gray-900: #
|
|
20
|
+
--sx-gray-950: #08080c;
|
|
21
|
+
--sx-gray-900: #0f0f14;
|
|
22
22
|
--sx-gray-800: #171720;
|
|
23
|
-
--sx-gray-700: #
|
|
24
|
-
--sx-gray-600: #
|
|
23
|
+
--sx-gray-700: #1f1f2a;
|
|
24
|
+
--sx-gray-600: #2d2d3a;
|
|
25
25
|
--sx-gray-500: #505060;
|
|
26
|
-
--sx-gray-400: #
|
|
27
|
-
--sx-gray-300: #
|
|
28
|
-
--sx-gray-200: #
|
|
29
|
-
--sx-gray-100: #
|
|
30
|
-
--sx-white: #
|
|
26
|
+
--sx-gray-400: #7a7a88;
|
|
27
|
+
--sx-gray-300: #a0a0ab;
|
|
28
|
+
--sx-gray-200: #c5c5cc;
|
|
29
|
+
--sx-gray-100: #e8e6e1;
|
|
30
|
+
--sx-white: #f0eee8;
|
|
31
31
|
|
|
32
32
|
/* Accents — Vermilion (forge heat) */
|
|
33
|
-
--sx-vermilion-500: #
|
|
34
|
-
--sx-vermilion-400: #
|
|
35
|
-
--sx-vermilion-600: #
|
|
33
|
+
--sx-vermilion-500: #ff6b35;
|
|
34
|
+
--sx-vermilion-400: #ff8c5a;
|
|
35
|
+
--sx-vermilion-600: #e05520;
|
|
36
36
|
|
|
37
37
|
/* Accents — Brass (earned authority) */
|
|
38
|
-
--sx-brass-500: #
|
|
39
|
-
--sx-brass-400: #
|
|
40
|
-
--sx-brass-600: #
|
|
38
|
+
--sx-brass-500: #c8a84e;
|
|
39
|
+
--sx-brass-400: #d4b86a;
|
|
40
|
+
--sx-brass-600: #a68b3a;
|
|
41
41
|
|
|
42
42
|
/* Accents — Danger */
|
|
43
|
-
--sx-red-500: #
|
|
44
|
-
--sx-red-400: #
|
|
45
|
-
--sx-red-600: #
|
|
43
|
+
--sx-red-500: #dc2626;
|
|
44
|
+
--sx-red-400: #ef4444;
|
|
45
|
+
--sx-red-600: #b91c1c;
|
|
46
46
|
|
|
47
47
|
/* Accents — Phosphor (operational green) */
|
|
48
|
-
--sx-green-500: #
|
|
49
|
-
--sx-green-400: #
|
|
50
|
-
--sx-green-600: #
|
|
48
|
+
--sx-green-500: #4ade80;
|
|
49
|
+
--sx-green-400: #6ee7a0;
|
|
50
|
+
--sx-green-600: #22c55e;
|
|
51
51
|
|
|
52
52
|
/* Accents — Teal (encrypted channel) */
|
|
53
|
-
--sx-teal-500: #
|
|
54
|
-
--sx-teal-400: #
|
|
55
|
-
--sx-teal-600: #
|
|
53
|
+
--sx-teal-500: #3d8b8b;
|
|
54
|
+
--sx-teal-400: #5aabab;
|
|
55
|
+
--sx-teal-600: #2d6b6b;
|
|
56
56
|
|
|
57
57
|
/* ========================================
|
|
58
58
|
SEMANTIC COLORS
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
--sx-shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.5);
|
|
113
113
|
--sx-shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.6);
|
|
114
114
|
--sx-shadow-glow-primary: 0 0 20px rgba(255, 107, 53, 0.18);
|
|
115
|
-
--sx-shadow-glow-primary-strong: 0 0 30px rgba(255, 107, 53, 0.
|
|
115
|
+
--sx-shadow-glow-primary-strong: 0 0 30px rgba(255, 107, 53, 0.3);
|
|
116
116
|
--sx-shadow-glow-brass: 0 0 20px rgba(200, 168, 78, 0.15);
|
|
117
117
|
--sx-shadow-glow-red: 0 0 20px rgba(220, 38, 38, 0.15);
|
|
118
118
|
--sx-shadow-glow-green: 0 0 20px rgba(74, 222, 128, 0.15);
|
|
@@ -164,9 +164,9 @@
|
|
|
164
164
|
TYPOGRAPHY
|
|
165
165
|
======================================== */
|
|
166
166
|
|
|
167
|
-
--sx-font-body:
|
|
168
|
-
--sx-font-display:
|
|
169
|
-
--sx-font-mono:
|
|
167
|
+
--sx-font-body: "TT Fors", system-ui, -apple-system, sans-serif;
|
|
168
|
+
--sx-font-display: "TT Quaris", Georgia, "Times New Roman", serif;
|
|
169
|
+
--sx-font-mono: "JetBrains Mono", "Consolas", "Courier New", monospace;
|
|
170
170
|
|
|
171
171
|
--sx-text-xs: 0.75rem;
|
|
172
172
|
--sx-text-sm: 0.875rem;
|
|
@@ -251,7 +251,7 @@
|
|
|
251
251
|
======================================== */
|
|
252
252
|
|
|
253
253
|
--sx-z-base: 1;
|
|
254
|
-
--sx-z-dropdown:
|
|
254
|
+
--sx-z-dropdown: 1055;
|
|
255
255
|
--sx-z-sticky: 1020;
|
|
256
256
|
--sx-z-fixed: 1030;
|
|
257
257
|
--sx-z-modal-backdrop: 1040;
|
|
@@ -316,9 +316,11 @@
|
|
|
316
316
|
|
|
317
317
|
body {
|
|
318
318
|
background-color: var(--sx-color-base);
|
|
319
|
-
background-image:
|
|
320
|
-
|
|
321
|
-
|
|
319
|
+
background-image: radial-gradient(
|
|
320
|
+
ellipse at 15% 50%,
|
|
321
|
+
rgba(255, 107, 53, 0.02) 0%,
|
|
322
|
+
transparent 50%
|
|
323
|
+
), radial-gradient(ellipse at 85% 20%, rgba(200, 168, 78, 0.015) 0%, transparent 50%),
|
|
322
324
|
radial-gradient(ellipse at 50% 85%, rgba(61, 139, 139, 0.015) 0%, transparent 50%);
|
|
323
325
|
background-size: 200% 200%;
|
|
324
326
|
animation: sx-ambient-drift 25s ease-in-out infinite;
|
|
@@ -359,23 +361,47 @@ body {
|
|
|
359
361
|
}
|
|
360
362
|
|
|
361
363
|
@keyframes sx-ambient-drift {
|
|
362
|
-
0%
|
|
363
|
-
|
|
364
|
-
|
|
364
|
+
0% {
|
|
365
|
+
background-position: 0% 50%;
|
|
366
|
+
}
|
|
367
|
+
50% {
|
|
368
|
+
background-position: 100% 50%;
|
|
369
|
+
}
|
|
370
|
+
100% {
|
|
371
|
+
background-position: 0% 50%;
|
|
372
|
+
}
|
|
365
373
|
}
|
|
366
374
|
|
|
367
375
|
@keyframes sx-focus-breathe {
|
|
368
|
-
0%,
|
|
369
|
-
|
|
376
|
+
0%,
|
|
377
|
+
100% {
|
|
378
|
+
box-shadow: 0 0 0 3px rgba(255, 107, 53, 0.12);
|
|
379
|
+
}
|
|
380
|
+
50% {
|
|
381
|
+
box-shadow: 0 0 0 3px rgba(255, 107, 53, 0.28);
|
|
382
|
+
}
|
|
370
383
|
}
|
|
371
384
|
|
|
372
385
|
@keyframes sx-error-shake {
|
|
373
|
-
0%,
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
386
|
+
0%,
|
|
387
|
+
100% {
|
|
388
|
+
transform: translateX(0);
|
|
389
|
+
}
|
|
390
|
+
15% {
|
|
391
|
+
transform: translateX(-4px);
|
|
392
|
+
}
|
|
393
|
+
30% {
|
|
394
|
+
transform: translateX(4px);
|
|
395
|
+
}
|
|
396
|
+
45% {
|
|
397
|
+
transform: translateX(-3px);
|
|
398
|
+
}
|
|
399
|
+
60% {
|
|
400
|
+
transform: translateX(2px);
|
|
401
|
+
}
|
|
402
|
+
75% {
|
|
403
|
+
transform: translateX(-1px);
|
|
404
|
+
}
|
|
379
405
|
}
|
|
380
406
|
|
|
381
407
|
@keyframes sx-check-in {
|
|
@@ -390,9 +416,15 @@ body {
|
|
|
390
416
|
}
|
|
391
417
|
|
|
392
418
|
@keyframes sx-badge-pop {
|
|
393
|
-
0%
|
|
394
|
-
|
|
395
|
-
|
|
419
|
+
0% {
|
|
420
|
+
transform: scale(1);
|
|
421
|
+
}
|
|
422
|
+
40% {
|
|
423
|
+
transform: scale(1.15);
|
|
424
|
+
}
|
|
425
|
+
100% {
|
|
426
|
+
transform: scale(1);
|
|
427
|
+
}
|
|
396
428
|
}
|
|
397
429
|
|
|
398
430
|
@keyframes sx-alert-in {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessibility utilities for WCAG 2.1 AA compliance.
|
|
3
|
+
* Focus management, screen reader announcements, media query helpers.
|
|
4
|
+
*/
|
|
5
|
+
/** Check whether an element can receive focus. */
|
|
6
|
+
export declare function isElementFocusable(el: HTMLElement): boolean;
|
|
7
|
+
/** Get all focusable elements within a container, in DOM order. */
|
|
8
|
+
export declare function getFocusableElements(container: HTMLElement): HTMLElement[];
|
|
9
|
+
/**
|
|
10
|
+
* Announce a message to screen readers via an ARIA live region.
|
|
11
|
+
* Creates the region lazily and reuses it across calls.
|
|
12
|
+
*/
|
|
13
|
+
export declare function announce(message: string, priority?: 'polite' | 'assertive'): void;
|
|
14
|
+
/** Check if the user prefers reduced motion. */
|
|
15
|
+
export declare function prefersReducedMotion(): boolean;
|
|
16
|
+
//# sourceMappingURL=accessibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessibility.d.ts","sourceRoot":"","sources":["../../src/utils/accessibility.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH,kDAAkD;AAClD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,CAe3D;AAED,mEAAmE;AACnE,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,EAAE,CAI1E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,QAAQ,GAAG,WAAsB,GAAG,IAAI,CAgC3F;AAED,gDAAgD;AAChD,wBAAgB,oBAAoB,IAAI,OAAO,CAG9C"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessibility utilities for WCAG 2.1 AA compliance.
|
|
3
|
+
* Focus management, screen reader announcements, media query helpers.
|
|
4
|
+
*/
|
|
5
|
+
const FOCUSABLE_SELECTORS = [
|
|
6
|
+
'a[href]:not([tabindex="-1"])',
|
|
7
|
+
'button:not([disabled]):not([tabindex="-1"])',
|
|
8
|
+
'input:not([disabled]):not([tabindex="-1"]):not([type="hidden"])',
|
|
9
|
+
'select:not([disabled]):not([tabindex="-1"])',
|
|
10
|
+
'textarea:not([disabled]):not([tabindex="-1"])',
|
|
11
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
12
|
+
'[contenteditable]:not([tabindex="-1"])'
|
|
13
|
+
];
|
|
14
|
+
const FOCUSABLE_SELECTOR = FOCUSABLE_SELECTORS.join(', ');
|
|
15
|
+
/** Check whether an element can receive focus. */
|
|
16
|
+
export function isElementFocusable(el) {
|
|
17
|
+
if (el.hasAttribute('disabled') || el.disabled)
|
|
18
|
+
return false;
|
|
19
|
+
if (el.getAttribute('tabindex') === '-1')
|
|
20
|
+
return false;
|
|
21
|
+
if (el.hasAttribute('hidden'))
|
|
22
|
+
return false;
|
|
23
|
+
const style = getComputedStyle(el);
|
|
24
|
+
if (style.display === 'none' || style.visibility === 'hidden')
|
|
25
|
+
return false;
|
|
26
|
+
const tag = el.tagName.toLowerCase();
|
|
27
|
+
if (['input', 'select', 'textarea', 'button'].includes(tag)) {
|
|
28
|
+
return !el.disabled;
|
|
29
|
+
}
|
|
30
|
+
if (tag === 'a')
|
|
31
|
+
return el.hasAttribute('href');
|
|
32
|
+
if (el.hasAttribute('tabindex') || el.hasAttribute('contenteditable'))
|
|
33
|
+
return true;
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
/** Get all focusable elements within a container, in DOM order. */
|
|
37
|
+
export function getFocusableElements(container) {
|
|
38
|
+
return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter(isElementFocusable);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Announce a message to screen readers via an ARIA live region.
|
|
42
|
+
* Creates the region lazily and reuses it across calls.
|
|
43
|
+
*/
|
|
44
|
+
export function announce(message, priority = 'polite') {
|
|
45
|
+
if (typeof document === 'undefined')
|
|
46
|
+
return;
|
|
47
|
+
const id = `sx-announce-${priority}`;
|
|
48
|
+
let region = document.getElementById(id);
|
|
49
|
+
if (!region) {
|
|
50
|
+
region = document.createElement('div');
|
|
51
|
+
region.id = id;
|
|
52
|
+
region.setAttribute('role', 'log');
|
|
53
|
+
region.setAttribute('aria-live', priority);
|
|
54
|
+
region.setAttribute('aria-relevant', 'additions');
|
|
55
|
+
region.setAttribute('aria-atomic', 'true');
|
|
56
|
+
Object.assign(region.style, {
|
|
57
|
+
position: 'absolute',
|
|
58
|
+
width: '1px',
|
|
59
|
+
height: '1px',
|
|
60
|
+
padding: '0',
|
|
61
|
+
margin: '-1px',
|
|
62
|
+
overflow: 'hidden',
|
|
63
|
+
clip: 'rect(0, 0, 0, 0)',
|
|
64
|
+
whiteSpace: 'nowrap',
|
|
65
|
+
border: '0'
|
|
66
|
+
});
|
|
67
|
+
document.body.appendChild(region);
|
|
68
|
+
}
|
|
69
|
+
// Clear then re-set to trigger announcement
|
|
70
|
+
region.textContent = '';
|
|
71
|
+
requestAnimationFrame(() => {
|
|
72
|
+
region.textContent = message;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Check if the user prefers reduced motion. */
|
|
76
|
+
export function prefersReducedMotion() {
|
|
77
|
+
if (typeof window === 'undefined')
|
|
78
|
+
return false;
|
|
79
|
+
return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
80
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { cn } from './cn.js';
|
|
2
|
-
export { createFocusTrap, generateId, Keys } from './keyboard.js';
|
|
2
|
+
export { createFocusTrap, generateId, Keys, isKey, isActivationKey, isNavigationKey } from './keyboard.js';
|
|
3
3
|
export type { FocusTrap, Key } from './keyboard.js';
|
|
4
|
+
export { isElementFocusable, getFocusableElements, announce, prefersReducedMotion } from './accessibility.js';
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EACN,eAAe,EACf,UAAU,EACV,IAAI,EACJ,KAAK,EACL,eAAe,EACf,eAAe,EACf,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACN,kBAAkB,EAClB,oBAAoB,EACpB,QAAQ,EACR,oBAAoB,EACpB,MAAM,oBAAoB,CAAC"}
|
package/dist/utils/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { cn } from './cn.js';
|
|
2
|
-
export { createFocusTrap, generateId, Keys } from './keyboard.js';
|
|
2
|
+
export { createFocusTrap, generateId, Keys, isKey, isActivationKey, isNavigationKey } from './keyboard.js';
|
|
3
|
+
export { isElementFocusable, getFocusableElements, announce, prefersReducedMotion } from './accessibility.js';
|
package/dist/utils/keyboard.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ export interface FocusTrap {
|
|
|
23
23
|
* Trap focus within a container (e.g. modal). Tab cycles inside; restores focus on deactivate.
|
|
24
24
|
*/
|
|
25
25
|
export declare function createFocusTrap(container: HTMLElement): FocusTrap;
|
|
26
|
+
/** Check if the key matches one of the provided keys. */
|
|
27
|
+
export declare function isKey(event: KeyboardEvent, ...keys: Key[]): boolean;
|
|
28
|
+
/** Check if the key is an activation key (Enter or Space). */
|
|
29
|
+
export declare function isActivationKey(event: KeyboardEvent): boolean;
|
|
30
|
+
/** Check if the key is a navigation key (arrows, Home, End). */
|
|
31
|
+
export declare function isNavigationKey(event: KeyboardEvent): boolean;
|
|
26
32
|
/** Unique ID for aria attributes (per-instance safe). */
|
|
27
33
|
export declare function generateId(prefix?: string): string;
|
|
28
34
|
//# sourceMappingURL=keyboard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../src/utils/keyboard.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../src/utils/keyboard.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,eAAO,MAAM,IAAI;;;;;;;;;;;CAWP,CAAC;AAEX,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC;AAEnD,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,WAAW,GAAG,SAAS,CAoCjE;AAED,yDAAyD;AACzD,wBAAgB,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAEnE;AAED,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAE7D;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAU7D;AAED,yDAAyD;AACzD,wBAAgB,UAAU,CAAC,MAAM,SAAW,GAAG,MAAM,CAEpD"}
|
package/dist/utils/keyboard.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Keyboard and focus utilities for accessible components.
|
|
3
3
|
* WCAG 2.1 / WAI-ARIA aligned; used by Modal and other dialogs.
|
|
4
4
|
*/
|
|
5
|
+
import { getFocusableElements } from './accessibility.js';
|
|
5
6
|
export const Keys = {
|
|
6
7
|
Enter: 'Enter',
|
|
7
8
|
Space: ' ',
|
|
@@ -19,16 +20,9 @@ export const Keys = {
|
|
|
19
20
|
*/
|
|
20
21
|
export function createFocusTrap(container) {
|
|
21
22
|
let previouslyFocused = null;
|
|
22
|
-
const focusableSelector = [
|
|
23
|
-
'button:not([disabled]):not([tabindex="-1"])',
|
|
24
|
-
'[href]:not([tabindex="-1"])',
|
|
25
|
-
'input:not([disabled]):not([tabindex="-1"])',
|
|
26
|
-
'select:not([disabled]):not([tabindex="-1"])',
|
|
27
|
-
'textarea:not([disabled]):not([tabindex="-1"])',
|
|
28
|
-
'[tabindex]:not([tabindex="-1"])'
|
|
29
|
-
].join(', ');
|
|
30
23
|
function getFocusable() {
|
|
31
|
-
|
|
24
|
+
// Use shared implementation that filters invisible/disabled elements
|
|
25
|
+
return getFocusableElements(container);
|
|
32
26
|
}
|
|
33
27
|
function onKeyDown(e) {
|
|
34
28
|
if (e.key !== Keys.Tab)
|
|
@@ -61,6 +55,18 @@ export function createFocusTrap(container) {
|
|
|
61
55
|
}
|
|
62
56
|
};
|
|
63
57
|
}
|
|
58
|
+
/** Check if the key matches one of the provided keys. */
|
|
59
|
+
export function isKey(event, ...keys) {
|
|
60
|
+
return keys.includes(event.key);
|
|
61
|
+
}
|
|
62
|
+
/** Check if the key is an activation key (Enter or Space). */
|
|
63
|
+
export function isActivationKey(event) {
|
|
64
|
+
return isKey(event, Keys.Enter, Keys.Space);
|
|
65
|
+
}
|
|
66
|
+
/** Check if the key is a navigation key (arrows, Home, End). */
|
|
67
|
+
export function isNavigationKey(event) {
|
|
68
|
+
return isKey(event, Keys.ArrowUp, Keys.ArrowDown, Keys.ArrowLeft, Keys.ArrowRight, Keys.Home, Keys.End);
|
|
69
|
+
}
|
|
64
70
|
/** Unique ID for aria attributes (per-instance safe). */
|
|
65
71
|
export function generateId(prefix = 'salmex') {
|
|
66
72
|
return `${prefix}-${Math.random().toString(36).slice(2, 11)}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salmexio/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Salmex I/O Design System — INFRARED component library for Salmex products",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -39,6 +39,26 @@
|
|
|
39
39
|
"svelte": "./dist/navigation/index.js",
|
|
40
40
|
"default": "./dist/navigation/index.js"
|
|
41
41
|
},
|
|
42
|
+
"./forms": {
|
|
43
|
+
"types": "./dist/forms/index.d.ts",
|
|
44
|
+
"svelte": "./dist/forms/index.js",
|
|
45
|
+
"default": "./dist/forms/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./layout": {
|
|
48
|
+
"types": "./dist/layout/index.d.ts",
|
|
49
|
+
"svelte": "./dist/layout/index.js",
|
|
50
|
+
"default": "./dist/layout/index.js"
|
|
51
|
+
},
|
|
52
|
+
"./feedback": {
|
|
53
|
+
"types": "./dist/feedback/index.d.ts",
|
|
54
|
+
"svelte": "./dist/feedback/index.js",
|
|
55
|
+
"default": "./dist/feedback/index.js"
|
|
56
|
+
},
|
|
57
|
+
"./dialogs": {
|
|
58
|
+
"types": "./dist/dialogs/index.d.ts",
|
|
59
|
+
"svelte": "./dist/dialogs/index.js",
|
|
60
|
+
"default": "./dist/dialogs/index.js"
|
|
61
|
+
},
|
|
42
62
|
"./utils": {
|
|
43
63
|
"types": "./dist/utils/index.d.ts",
|
|
44
64
|
"default": "./dist/utils/index.js"
|