@salmexio/ui 0.1.1 → 0.2.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.
Files changed (45) hide show
  1. package/dist/dialogs/Modal/Modal.svelte +140 -140
  2. package/dist/dialogs/Modal/Modal.svelte.d.ts.map +1 -1
  3. package/dist/feedback/Alert/Alert.svelte +63 -63
  4. package/dist/feedback/Alert/Alert.svelte.d.ts.map +1 -1
  5. package/dist/feedback/Spinner/Spinner.svelte +55 -55
  6. package/dist/feedback/Spinner/Spinner.svelte.d.ts.map +1 -1
  7. package/dist/forms/Checkbox/Checkbox.svelte +64 -64
  8. package/dist/forms/Checkbox/Checkbox.svelte.d.ts.map +1 -1
  9. package/dist/forms/TextInput/TextInput.svelte +141 -141
  10. package/dist/forms/TextInput/TextInput.svelte.d.ts.map +1 -1
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -0
  14. package/dist/layout/Card/Card.svelte +59 -59
  15. package/dist/layout/Card/Card.svelte.d.ts.map +1 -1
  16. package/dist/layout/Container/Container.svelte +34 -34
  17. package/dist/layout/Container/Container.svelte.d.ts.map +1 -1
  18. package/dist/navigation/Tabs/Tabs.svelte +100 -101
  19. package/dist/navigation/Tabs/Tabs.svelte.d.ts.map +1 -1
  20. package/dist/primitives/Badge/Badge.svelte +35 -42
  21. package/dist/primitives/Badge/Badge.svelte.d.ts.map +1 -1
  22. package/dist/primitives/Button/Button.svelte +47 -47
  23. package/dist/primitives/Button/Button.svelte.d.ts.map +1 -1
  24. package/dist/routes/+layout.svelte +1 -1
  25. package/dist/styles/tokens.css +92 -86
  26. package/dist/utils/keyboard.js +3 -3
  27. package/dist/windowing/Window/Window.svelte +602 -0
  28. package/dist/windowing/Window/Window.svelte.d.ts +65 -0
  29. package/dist/windowing/Window/Window.svelte.d.ts.map +1 -0
  30. package/dist/windowing/Window/index.d.ts +2 -0
  31. package/dist/windowing/Window/index.d.ts.map +1 -0
  32. package/dist/windowing/Window/index.js +1 -0
  33. package/dist/windowing/WindowManager/WindowManager.svelte +410 -0
  34. package/dist/windowing/WindowManager/WindowManager.svelte.d.ts +38 -0
  35. package/dist/windowing/WindowManager/WindowManager.svelte.d.ts.map +1 -0
  36. package/dist/windowing/WindowManager/index.d.ts +2 -0
  37. package/dist/windowing/WindowManager/index.d.ts.map +1 -0
  38. package/dist/windowing/WindowManager/index.js +1 -0
  39. package/dist/windowing/index.d.ts +5 -0
  40. package/dist/windowing/index.d.ts.map +1 -0
  41. package/dist/windowing/index.js +3 -0
  42. package/dist/windowing/windowStore.svelte.d.ts +49 -0
  43. package/dist/windowing/windowStore.svelte.d.ts.map +1 -0
  44. package/dist/windowing/windowStore.svelte.js +170 -0
  45. package/package.json +1 -1
@@ -8,154 +8,154 @@
8
8
  and set inert on main content when modalOpenCount > 0 (see modalStore).
9
9
  -->
10
10
  <script lang="ts">
11
- import type { Snippet } from 'svelte';
12
- import { createFocusTrap, Keys, generateId } from '../../utils/keyboard.js';
13
- import { modalOpenCount } from '../modalStore.js';
14
-
15
- type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';
16
- type ModalPosition = 'center' | 'top';
17
- type ScrollBehavior = 'inside' | 'outside';
18
- /** APG: 'first' = first focusable in body; 'title' = dialog title (for long content so AT reads title first). */
19
- type InitialFocusStrategy = 'first' | 'title';
20
-
21
- interface Props {
22
- open?: boolean;
23
- id?: string;
24
- title?: string;
25
- size?: ModalSize;
26
- position?: ModalPosition;
27
- scrollBehavior?: ScrollBehavior;
28
- showCloseButton?: boolean;
29
- closeOnBackdrop?: boolean;
30
- closeOnEscape?: boolean;
31
- preventClose?: boolean;
32
- /** Element to focus when opening (overrides initialFocusStrategy). */
33
- initialFocus?: HTMLElement | null;
34
- /** APG: 'first' = first focusable; 'title' = focus title (tabindex="-1") so screen readers announce it first. */
35
- initialFocusStrategy?: InitialFocusStrategy;
36
- enableFocusTrap?: boolean;
37
- header?: Snippet;
38
- footer?: Snippet;
39
- children?: Snippet;
40
- class?: string;
41
- onclose?: () => void;
42
- closeBtnAriaLabel?: string;
43
- testId?: string;
44
- }
45
-
46
- let {
47
- open = false,
48
- id,
49
- title = 'Dialog',
50
- size = 'md',
51
- position = 'center',
52
- scrollBehavior = 'inside',
53
- showCloseButton = true,
54
- closeOnBackdrop = true,
55
- closeOnEscape = true,
56
- preventClose = false,
57
- initialFocus,
58
- initialFocusStrategy = 'first',
59
- enableFocusTrap = true,
60
- header,
61
- footer,
62
- children,
63
- class: className = '',
64
- onclose,
65
- closeBtnAriaLabel,
66
- testId,
67
- }: Props = $props();
68
-
69
- const modalId = $derived(id ?? generateId('modal'));
70
- const titleId = $derived(`${modalId}-title`);
71
- const descriptionId = $derived(`${modalId}-description`);
72
-
73
- let dialogElement = $state<HTMLDivElement | null>(null);
74
- let focusTrap: ReturnType<typeof createFocusTrap> | null = null;
75
- let previouslyFocusedElement: HTMLElement | null = null;
76
- let hasActivated = $state(false);
77
-
78
- function getScrollbarWidth(): number {
79
- return window.innerWidth - document.documentElement.clientWidth;
80
- }
81
-
82
- const FOCUSABLE =
83
- 'button:not([disabled]):not([tabindex="-1"]), [href]:not([tabindex="-1"]), input:not([disabled]):not([tabindex="-1"]), select:not([disabled]):not([tabindex="-1"]), textarea:not([disabled]):not([tabindex="-1"]), [tabindex]:not([tabindex="-1"])';
84
-
85
- function setInitialFocus() {
86
- if (initialFocus) {
87
- initialFocus.focus();
88
- return;
89
- }
90
- if (!dialogElement) return;
91
- const titleEl = dialogElement.querySelector<HTMLElement>('.salmex-modal-title-wrap');
92
- const body = dialogElement.querySelector('.salmex-modal-body');
93
- const first = body?.querySelector<HTMLElement>(FOCUSABLE);
94
- const closeBtn = dialogElement.querySelector<HTMLElement>('.salmex-modal-close');
95
-
96
- if (initialFocusStrategy === 'title' && titleEl) {
97
- titleEl.focus();
98
- return;
99
- }
100
- if (first) {
101
- first.focus();
102
- } else if (closeBtn) {
103
- closeBtn.focus();
104
- } else if (titleEl) {
105
- titleEl.focus();
106
- }
107
- }
108
-
109
- $effect(() => {
110
- if (open) {
111
- if (!hasActivated && dialogElement) {
112
- previouslyFocusedElement = document.activeElement as HTMLElement | null;
113
- modalOpenCount.update((n) => n + 1);
114
- if (enableFocusTrap) {
115
- focusTrap = createFocusTrap(dialogElement);
116
- focusTrap.activate();
117
- }
118
- const scrollbarWidth = getScrollbarWidth();
119
- document.body.style.overflow = 'hidden';
120
- if (scrollbarWidth > 0) {
121
- document.body.style.paddingRight = `${scrollbarWidth}px`;
122
- }
123
- hasActivated = true;
124
- setTimeout(setInitialFocus, 0);
11
+ import type { Snippet } from 'svelte';
12
+ import { createFocusTrap, Keys, generateId } from '../../utils/keyboard.js';
13
+ import { modalOpenCount } from '../modalStore.js';
14
+
15
+ type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';
16
+ type ModalPosition = 'center' | 'top';
17
+ type ScrollBehavior = 'inside' | 'outside';
18
+ /** APG: 'first' = first focusable in body; 'title' = dialog title (for long content so AT reads title first). */
19
+ type InitialFocusStrategy = 'first' | 'title';
20
+
21
+ interface Props {
22
+ open?: boolean;
23
+ id?: string;
24
+ title?: string;
25
+ size?: ModalSize;
26
+ position?: ModalPosition;
27
+ scrollBehavior?: ScrollBehavior;
28
+ showCloseButton?: boolean;
29
+ closeOnBackdrop?: boolean;
30
+ closeOnEscape?: boolean;
31
+ preventClose?: boolean;
32
+ /** Element to focus when opening (overrides initialFocusStrategy). */
33
+ initialFocus?: HTMLElement | null;
34
+ /** APG: 'first' = first focusable; 'title' = focus title (tabindex="-1") so screen readers announce it first. */
35
+ initialFocusStrategy?: InitialFocusStrategy;
36
+ enableFocusTrap?: boolean;
37
+ header?: Snippet;
38
+ footer?: Snippet;
39
+ children?: Snippet;
40
+ class?: string;
41
+ onclose?: () => void;
42
+ closeBtnAriaLabel?: string;
43
+ testId?: string;
44
+ }
45
+
46
+ let {
47
+ open = false,
48
+ id,
49
+ title = 'Dialog',
50
+ size = 'md',
51
+ position = 'center',
52
+ scrollBehavior = 'inside',
53
+ showCloseButton = true,
54
+ closeOnBackdrop = true,
55
+ closeOnEscape = true,
56
+ preventClose = false,
57
+ initialFocus,
58
+ initialFocusStrategy = 'first',
59
+ enableFocusTrap = true,
60
+ header,
61
+ footer,
62
+ children,
63
+ class: className = '',
64
+ onclose,
65
+ closeBtnAriaLabel,
66
+ testId
67
+ }: Props = $props();
68
+
69
+ const modalId = $derived(id ?? generateId('modal'));
70
+ const titleId = $derived(`${modalId}-title`);
71
+ const descriptionId = $derived(`${modalId}-description`);
72
+
73
+ let dialogElement = $state<HTMLDivElement | null>(null);
74
+ let focusTrap: ReturnType<typeof createFocusTrap> | null = null;
75
+ let previouslyFocusedElement: HTMLElement | null = null;
76
+ let hasActivated = $state(false);
77
+
78
+ function getScrollbarWidth(): number {
79
+ return window.innerWidth - document.documentElement.clientWidth;
80
+ }
81
+
82
+ const FOCUSABLE =
83
+ 'button:not([disabled]):not([tabindex="-1"]), [href]:not([tabindex="-1"]), input:not([disabled]):not([tabindex="-1"]), select:not([disabled]):not([tabindex="-1"]), textarea:not([disabled]):not([tabindex="-1"]), [tabindex]:not([tabindex="-1"])';
84
+
85
+ function setInitialFocus() {
86
+ if (initialFocus) {
87
+ initialFocus.focus();
88
+ return;
89
+ }
90
+ if (!dialogElement) return;
91
+ const titleEl = dialogElement.querySelector<HTMLElement>('.salmex-modal-title-wrap');
92
+ const body = dialogElement.querySelector('.salmex-modal-body');
93
+ const first = body?.querySelector<HTMLElement>(FOCUSABLE);
94
+ const closeBtn = dialogElement.querySelector<HTMLElement>('.salmex-modal-close');
95
+
96
+ if (initialFocusStrategy === 'title' && titleEl) {
97
+ titleEl.focus();
98
+ return;
99
+ }
100
+ if (first) {
101
+ first.focus();
102
+ } else if (closeBtn) {
103
+ closeBtn.focus();
104
+ } else if (titleEl) {
105
+ titleEl.focus();
106
+ }
107
+ }
108
+
109
+ $effect(() => {
110
+ if (open) {
111
+ if (!hasActivated && dialogElement) {
112
+ previouslyFocusedElement = document.activeElement as HTMLElement | null;
113
+ modalOpenCount.update((n) => n + 1);
114
+ if (enableFocusTrap) {
115
+ focusTrap = createFocusTrap(dialogElement);
116
+ focusTrap.activate();
125
117
  }
126
- } else {
127
- if (hasActivated) {
128
- modalOpenCount.update((n) => Math.max(0, n - 1));
129
- focusTrap?.deactivate();
130
- focusTrap = null;
131
- hasActivated = false;
132
- document.body.style.overflow = '';
133
- document.body.style.paddingRight = '';
134
- if (previouslyFocusedElement?.focus) {
135
- const el = previouslyFocusedElement;
136
- setTimeout(() => el.focus(), 0);
137
- }
138
- previouslyFocusedElement = null;
118
+ const scrollbarWidth = getScrollbarWidth();
119
+ document.body.style.overflow = 'hidden';
120
+ if (scrollbarWidth > 0) {
121
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
139
122
  }
123
+ hasActivated = true;
124
+ setTimeout(setInitialFocus, 0);
125
+ }
126
+ } else {
127
+ if (hasActivated) {
128
+ modalOpenCount.update((n) => Math.max(0, n - 1));
129
+ focusTrap?.deactivate();
130
+ focusTrap = null;
131
+ hasActivated = false;
132
+ document.body.style.overflow = '';
133
+ document.body.style.paddingRight = '';
134
+ if (previouslyFocusedElement?.focus) {
135
+ const el = previouslyFocusedElement;
136
+ setTimeout(() => el.focus(), 0);
137
+ }
138
+ previouslyFocusedElement = null;
140
139
  }
141
- });
142
-
143
- function handleClose() {
144
- if (!preventClose) onclose?.();
145
140
  }
141
+ });
146
142
 
147
- function handleBackdropClick(e: MouseEvent) {
148
- if (closeOnBackdrop && e.target === e.currentTarget) handleClose();
149
- }
143
+ function handleClose() {
144
+ if (!preventClose) onclose?.();
145
+ }
150
146
 
151
- function handleKeyDown(e: KeyboardEvent) {
152
- if (closeOnEscape && e.key === Keys.Escape) {
153
- e.preventDefault();
154
- handleClose();
155
- }
147
+ function handleBackdropClick(e: MouseEvent) {
148
+ if (closeOnBackdrop && e.target === e.currentTarget) handleClose();
149
+ }
150
+
151
+ function handleKeyDown(e: KeyboardEvent) {
152
+ if (closeOnEscape && e.key === Keys.Escape) {
153
+ e.preventDefault();
154
+ handleClose();
156
155
  }
156
+ }
157
157
 
158
- const closeLabel = $derived(closeBtnAriaLabel ?? 'Close dialog');
158
+ const closeLabel = $derived(closeBtnAriaLabel ?? 'Close dialog');
159
159
  </script>
160
160
 
161
161
  <svelte:window onkeydown={open ? handleKeyDown : undefined} />
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/dialogs/Modal/Modal.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAKrC,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AACpD,KAAK,aAAa,GAAG,QAAQ,GAAG,KAAK,CAAC;AACtC,KAAK,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC3C,iHAAiH;AACjH,KAAK,oBAAoB,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9C,UAAU,KAAK;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sEAAsE;IACtE,YAAY,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAClC,iHAAiH;IACjH,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AA0KF;;;;;;;;GAQG;AACH,QAAA,MAAM,KAAK,2CAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/dialogs/Modal/Modal.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAKtC,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AACpD,KAAK,aAAa,GAAG,QAAQ,GAAG,KAAK,CAAC;AACtC,KAAK,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC3C,iHAAiH;AACjH,KAAK,oBAAoB,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9C,UAAU,KAAK;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sEAAsE;IACtE,YAAY,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAClC,iHAAiH;IACjH,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AA0KD;;;;;;;;GAQG;AACH,QAAA,MAAM,KAAK,2CAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -5,69 +5,69 @@
5
5
  Dismissible, expandable, optional title; role="alert" for errors.
6
6
  -->
7
7
  <script lang="ts">
8
- import type { Snippet } from 'svelte';
9
- import { cn } from '../../utils/cn.js';
10
-
11
- type AlertType = 'success' | 'error' | 'warning' | 'info' | 'neutral';
12
- type AlertVariant = 'standard' | 'slim' | 'bordered';
13
- type HeadingLevel = 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p';
14
-
15
- interface Props {
16
- type?: AlertType;
17
- variant?: AlertVariant;
18
- title?: string;
19
- headingLevel?: HeadingLevel;
20
- dismissible?: boolean;
21
- showIcon?: boolean;
22
- expandable?: boolean;
23
- defaultExpanded?: boolean;
24
- class?: string;
25
- children?: Snippet;
26
- actions?: Snippet;
27
- onclose?: () => void;
28
- closeBtnAriaLabel?: string;
29
- id?: string;
30
- }
31
-
32
- let {
33
- type = 'info',
34
- variant = 'standard',
35
- title = '',
36
- headingLevel = 'h3',
37
- dismissible = false,
38
- showIcon = true,
39
- expandable = false,
40
- defaultExpanded = true,
41
- class: className = '',
42
- children,
43
- actions,
44
- onclose,
45
- closeBtnAriaLabel,
46
- id
47
- }: Props = $props();
48
-
49
- let isExpanded = $state(true);
50
-
51
- $effect(() => {
52
- isExpanded = defaultExpanded;
53
- });
54
-
55
- const generatedId = `alert-${Math.random().toString(36).slice(2, 9)}`;
56
- const alertId = $derived(id ?? generatedId);
57
- const contentId = $derived(`${alertId}-content`);
58
- const titleId = $derived(`${alertId}-title`);
59
-
60
- const ariaRole = $derived(type === 'error' || type === 'warning' ? 'alert' : 'status');
61
- const ariaLive = $derived(type === 'error' ? 'assertive' : 'polite');
62
- const closeLabel = $derived(closeBtnAriaLabel ?? `Close ${title || type} notification`);
63
-
64
- function handleDismiss() {
65
- onclose?.();
66
- }
67
-
68
- function toggleExpanded() {
69
- isExpanded = !isExpanded;
70
- }
8
+ import type { Snippet } from 'svelte';
9
+ import { cn } from '../../utils/cn.js';
10
+
11
+ type AlertType = 'success' | 'error' | 'warning' | 'info' | 'neutral';
12
+ type AlertVariant = 'standard' | 'slim' | 'bordered';
13
+ type HeadingLevel = 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p';
14
+
15
+ interface Props {
16
+ type?: AlertType;
17
+ variant?: AlertVariant;
18
+ title?: string;
19
+ headingLevel?: HeadingLevel;
20
+ dismissible?: boolean;
21
+ showIcon?: boolean;
22
+ expandable?: boolean;
23
+ defaultExpanded?: boolean;
24
+ class?: string;
25
+ children?: Snippet;
26
+ actions?: Snippet;
27
+ onclose?: () => void;
28
+ closeBtnAriaLabel?: string;
29
+ id?: string;
30
+ }
31
+
32
+ let {
33
+ type = 'info',
34
+ variant = 'standard',
35
+ title = '',
36
+ headingLevel = 'h3',
37
+ dismissible = false,
38
+ showIcon = true,
39
+ expandable = false,
40
+ defaultExpanded = true,
41
+ class: className = '',
42
+ children,
43
+ actions,
44
+ onclose,
45
+ closeBtnAriaLabel,
46
+ id
47
+ }: Props = $props();
48
+
49
+ let isExpanded = $state(true);
50
+
51
+ $effect(() => {
52
+ isExpanded = defaultExpanded;
53
+ });
54
+
55
+ const generatedId = `alert-${Math.random().toString(36).slice(2, 9)}`;
56
+ const alertId = $derived(id ?? generatedId);
57
+ const contentId = $derived(`${alertId}-content`);
58
+ const titleId = $derived(`${alertId}-title`);
59
+
60
+ const ariaRole = $derived(type === 'error' || type === 'warning' ? 'alert' : 'status');
61
+ const ariaLive = $derived(type === 'error' ? 'assertive' : 'polite');
62
+ const closeLabel = $derived(closeBtnAriaLabel ?? `Close ${title || type} notification`);
63
+
64
+ function handleDismiss() {
65
+ onclose?.();
66
+ }
67
+
68
+ function toggleExpanded() {
69
+ isExpanded = !isExpanded;
70
+ }
71
71
  </script>
72
72
 
73
73
  <div
@@ -1 +1 @@
1
- {"version":3,"file":"Alert.svelte.d.ts","sourceRoot":"","sources":["../../../src/feedback/Alert/Alert.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIrC,KAAK,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AACtE,KAAK,YAAY,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;AACrD,KAAK,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC;AAE3D,UAAU,KAAK;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ;AAmHF;;;;;GAKG;AACH,QAAA,MAAM,KAAK,2CAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Alert.svelte.d.ts","sourceRoot":"","sources":["../../../src/feedback/Alert/Alert.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAItC,KAAK,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AACtE,KAAK,YAAY,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;AACrD,KAAK,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC;AAE3D,UAAU,KAAK;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ;AAmHD;;;;;GAKG;AACH,QAAA,MAAM,KAAK,2CAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -6,62 +6,62 @@
6
6
  role="status", aria-label, delay, overlay. prefers-reduced-motion respected.
7
7
  -->
8
8
  <script lang="ts">
9
- import { cn } from '../../utils/cn.js';
10
-
11
- type SpinnerSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
12
- type SpinnerVariant = 'primary' | 'secondary' | 'white';
13
- type SpinnerStyle = 'ring' | 'bars' | 'segment' | 'dots' | 'pulse';
14
-
15
- interface Props {
16
- size?: SpinnerSize;
17
- variant?: SpinnerVariant;
18
- style?: SpinnerStyle;
19
- label?: string;
20
- showLabel?: boolean;
21
- delay?: number;
22
- overlay?: boolean;
23
- class?: string;
24
- id?: string;
9
+ import { cn } from '../../utils/cn.js';
10
+
11
+ type SpinnerSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
12
+ type SpinnerVariant = 'primary' | 'secondary' | 'white';
13
+ type SpinnerStyle = 'ring' | 'bars' | 'segment' | 'dots' | 'pulse';
14
+
15
+ interface Props {
16
+ size?: SpinnerSize;
17
+ variant?: SpinnerVariant;
18
+ style?: SpinnerStyle;
19
+ label?: string;
20
+ showLabel?: boolean;
21
+ delay?: number;
22
+ overlay?: boolean;
23
+ class?: string;
24
+ id?: string;
25
+ }
26
+
27
+ let {
28
+ size = 'md',
29
+ variant = 'primary',
30
+ style = 'ring',
31
+ label = 'Loading...',
32
+ showLabel = false,
33
+ delay = 0,
34
+ overlay = false,
35
+ class: className = '',
36
+ id
37
+ }: Props = $props();
38
+
39
+ let isVisible = $state(false);
40
+
41
+ $effect(() => {
42
+ if (delay === 0) {
43
+ isVisible = true;
44
+ return;
25
45
  }
26
-
27
- let {
28
- size = 'md',
29
- variant = 'primary',
30
- style = 'ring',
31
- label = 'Loading...',
32
- showLabel = false,
33
- delay = 0,
34
- overlay = false,
35
- class: className = '',
36
- id
37
- }: Props = $props();
38
-
39
- let isVisible = $state(false);
40
-
41
- $effect(() => {
42
- if (delay === 0) {
43
- isVisible = true;
44
- return;
45
- }
46
- isVisible = false;
47
- const t = setTimeout(() => {
48
- isVisible = true;
49
- }, delay);
50
- return () => clearTimeout(t);
51
- });
52
-
53
- const sizeConfig: Record<
54
- SpinnerSize,
55
- { dimension: number; stroke: number; fontSize: string; dotSize: number }
56
- > = {
57
- xs: { dimension: 16, stroke: 2.5, fontSize: 'var(--salmex-font-size-xs)', dotSize: 4 },
58
- sm: { dimension: 20, stroke: 3, fontSize: 'var(--salmex-font-size-sm)', dotSize: 5 },
59
- md: { dimension: 28, stroke: 4, fontSize: 'var(--salmex-font-size-sm)', dotSize: 6 },
60
- lg: { dimension: 40, stroke: 5, fontSize: 'var(--salmex-font-size-base)', dotSize: 8 },
61
- xl: { dimension: 56, stroke: 6, fontSize: 'var(--salmex-font-size-md)', dotSize: 10 }
62
- };
63
-
64
- const config = $derived(sizeConfig[size]);
46
+ isVisible = false;
47
+ const t = setTimeout(() => {
48
+ isVisible = true;
49
+ }, delay);
50
+ return () => clearTimeout(t);
51
+ });
52
+
53
+ const sizeConfig: Record<
54
+ SpinnerSize,
55
+ { dimension: number; stroke: number; fontSize: string; dotSize: number }
56
+ > = {
57
+ xs: { dimension: 16, stroke: 2.5, fontSize: 'var(--salmex-font-size-xs)', dotSize: 4 },
58
+ sm: { dimension: 20, stroke: 3, fontSize: 'var(--salmex-font-size-sm)', dotSize: 5 },
59
+ md: { dimension: 28, stroke: 4, fontSize: 'var(--salmex-font-size-sm)', dotSize: 6 },
60
+ lg: { dimension: 40, stroke: 5, fontSize: 'var(--salmex-font-size-base)', dotSize: 8 },
61
+ xl: { dimension: 56, stroke: 6, fontSize: 'var(--salmex-font-size-md)', dotSize: 10 }
62
+ };
63
+
64
+ const config = $derived(sizeConfig[size]);
65
65
  </script>
66
66
 
67
67
  {#if isVisible}
@@ -1 +1 @@
1
- {"version":3,"file":"Spinner.svelte.d.ts","sourceRoot":"","sources":["../../../src/feedback/Spinner/Spinner.svelte.ts"],"names":[],"mappings":"AAMC,KAAK,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACpD,KAAK,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AACxD,KAAK,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnE,UAAU,KAAK;IACd,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ;AA2GF;;;;;;GAMG;AACH,QAAA,MAAM,OAAO,2CAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"Spinner.svelte.d.ts","sourceRoot":"","sources":["../../../src/feedback/Spinner/Spinner.svelte.ts"],"names":[],"mappings":"AAMA,KAAK,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACpD,KAAK,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AACxD,KAAK,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnE,UAAU,KAAK;IACd,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ;AA2GD;;;;;;GAMG;AACH,QAAA,MAAM,OAAO,2CAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}