sveltacular 1.0.33 → 1.0.36
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/forms/button/button.svelte +111 -10
- package/dist/forms/button/button.svelte.d.ts +8 -2
- package/dist/forms/check-box/check-box-group.svelte +2 -2
- package/dist/forms/combo/new-or-existing-combo.svelte +3 -3
- package/dist/forms/combo/new-or-existing-combo.svelte.d.ts +2 -2
- package/dist/forms/form-field/form-field.svelte +1 -2
- package/dist/forms/form.svelte +1 -1
- package/dist/forms/index.d.ts +4 -5
- package/dist/forms/index.js +5 -6
- package/dist/forms/list-box/list-box.svelte +23 -14
- package/dist/forms/list-box/list-box.svelte.d.ts +3 -3
- package/dist/forms/reference-box/index.d.ts +1 -1
- package/dist/forms/reference-box/reference-box.d.ts +3 -2
- package/dist/forms/reference-box/reference-box.svelte +6 -11
- package/dist/forms/reference-box/reference-box.svelte.d.ts +4 -3
- package/dist/forms/tag-box/tag-box.svelte +0 -1
- package/dist/forms/text-box/text-box.svelte +1 -1
- package/dist/generic/empty/empty.svelte +137 -53
- package/dist/generic/empty/empty.svelte.d.ts +11 -4
- package/dist/generic/menu/menu.svelte +1 -1
- package/dist/generic/overlay.svelte +3 -1
- package/dist/generic/overlay.svelte.d.ts +1 -0
- package/dist/generic/section/section.svelte +1 -1
- package/dist/modals/alert.svelte +5 -5
- package/dist/modals/confirm.svelte +6 -6
- package/dist/modals/modal.svelte +1 -1
- package/dist/modals/prompt.svelte +7 -7
- package/dist/navigation/drawer/drawer.svelte +1 -1
- package/dist/tables/data-grid.svelte +1 -4
- package/dist/types/form.d.ts +17 -3
- package/dist/types/size.d.ts +26 -2
- package/dist/types/size.js +20 -2
- package/package.json +1 -1
|
@@ -5,19 +5,24 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { Snippet } from 'svelte';
|
|
7
7
|
import { navigateTo } from '../../helpers/navigate-to.js';
|
|
8
|
-
import type { ButtonVariant, FormFieldSizeOptions } from '../../types/form.js';
|
|
8
|
+
import type { ButtonVariant, ComponentWidth, FormFieldSizeOptions } from '../../types/form.js';
|
|
9
|
+
import type { IconType } from '../../icons/types.js';
|
|
9
10
|
import Spinner from '../../generic/spinner/spinner.svelte';
|
|
11
|
+
import Icon from '../../icons/icon.svelte';
|
|
12
|
+
import type { ComponentSize } from '../../types';
|
|
10
13
|
|
|
11
14
|
let {
|
|
12
15
|
/** Optional href for navigation */
|
|
13
16
|
href = undefined,
|
|
14
|
-
/** Button size */
|
|
17
|
+
/** Button size (controls font size and padding) */
|
|
15
18
|
size = 'md',
|
|
19
|
+
/** Button width */
|
|
20
|
+
width = 'md',
|
|
16
21
|
/** Button variant/style */
|
|
17
22
|
variant = 'secondary',
|
|
18
23
|
/** HTML button type */
|
|
19
24
|
type = 'button',
|
|
20
|
-
/** Display as block (full width) */
|
|
25
|
+
/** Display as block (full width) - DEPRECATED: use width="full" instead */
|
|
21
26
|
block = false,
|
|
22
27
|
/** Allow flex growth */
|
|
23
28
|
flex = false,
|
|
@@ -33,6 +38,11 @@
|
|
|
33
38
|
collapse = false,
|
|
34
39
|
/** Delay before re-enabling after click (prevents double-clicks) */
|
|
35
40
|
repeatSubmitDelay = 500,
|
|
41
|
+
/** Icon to display */
|
|
42
|
+
icon = undefined,
|
|
43
|
+
/** Icon alignment */
|
|
44
|
+
iconAlign = 'left',
|
|
45
|
+
iconSize = 'default',
|
|
36
46
|
/** Click handler */
|
|
37
47
|
onClick = undefined,
|
|
38
48
|
/** Button content */
|
|
@@ -40,6 +50,7 @@
|
|
|
40
50
|
}: {
|
|
41
51
|
href?: string | undefined;
|
|
42
52
|
size?: FormFieldSizeOptions;
|
|
53
|
+
width?: ComponentWidth;
|
|
43
54
|
variant?: ButtonVariant;
|
|
44
55
|
type?: 'button' | 'submit' | 'reset';
|
|
45
56
|
block?: boolean;
|
|
@@ -50,8 +61,11 @@
|
|
|
50
61
|
noMargin?: boolean;
|
|
51
62
|
collapse?: boolean;
|
|
52
63
|
repeatSubmitDelay?: number | 'infinite';
|
|
64
|
+
icon?: IconType | undefined;
|
|
65
|
+
iconAlign?: 'left' | 'right' | 'above' | 'below';
|
|
66
|
+
iconSize?: 'default' | ComponentSize;
|
|
53
67
|
onClick?: ((e?: Event) => void) | undefined;
|
|
54
|
-
children
|
|
68
|
+
children?: Snippet;
|
|
55
69
|
} = $props();
|
|
56
70
|
|
|
57
71
|
let isDisabled = $derived(disabled || loading);
|
|
@@ -73,16 +87,19 @@
|
|
|
73
87
|
navigateTo(href);
|
|
74
88
|
}
|
|
75
89
|
};
|
|
90
|
+
|
|
91
|
+
const _iconSize = $derived<ComponentSize>(iconSize === 'default' ? size : iconSize);
|
|
76
92
|
</script>
|
|
77
93
|
|
|
78
94
|
<button
|
|
79
95
|
{type}
|
|
80
96
|
onclick={handleClick}
|
|
81
|
-
class="{size} {variant} {flex ? 'flex' : ''}"
|
|
97
|
+
class="{size} w-{width} {variant} {flex ? 'flex' : ''} icon-{iconAlign}"
|
|
82
98
|
class:block
|
|
83
99
|
class:noMargin
|
|
84
100
|
class:collapse
|
|
85
101
|
class:loading
|
|
102
|
+
class:has-icon={!!icon}
|
|
86
103
|
disabled={isDisabled}
|
|
87
104
|
aria-label={ariaLabel}
|
|
88
105
|
aria-busy={loading}
|
|
@@ -93,12 +110,25 @@
|
|
|
93
110
|
<Spinner {size} variant={variant === 'outline' ? 'secondary' : 'primary'} />
|
|
94
111
|
</span>
|
|
95
112
|
{/if}
|
|
96
|
-
{
|
|
113
|
+
{#if icon && (iconAlign === 'above' || iconAlign === 'left')}
|
|
114
|
+
<span class="icon-wrapper" aria-hidden="true">
|
|
115
|
+
<Icon type={icon} size={_iconSize} fill="currentColor" />
|
|
116
|
+
</span>
|
|
117
|
+
{/if}
|
|
118
|
+
{#if children}
|
|
119
|
+
<span class="button-content">
|
|
120
|
+
{@render children()}
|
|
121
|
+
</span>
|
|
122
|
+
{/if}
|
|
123
|
+
{#if icon && (iconAlign === 'below' || iconAlign === 'right')}
|
|
124
|
+
<span class="icon-wrapper" aria-hidden="true">
|
|
125
|
+
<Icon type={icon} size={_iconSize} fill="currentColor" />
|
|
126
|
+
</span>
|
|
127
|
+
{/if}
|
|
97
128
|
</button>
|
|
98
129
|
|
|
99
130
|
<style>button {
|
|
100
131
|
display: inline-block;
|
|
101
|
-
min-width: 10rem;
|
|
102
132
|
cursor: pointer;
|
|
103
133
|
margin-top: var(--spacing-sm);
|
|
104
134
|
margin-bottom: var(--spacing-sm);
|
|
@@ -117,6 +147,9 @@
|
|
|
117
147
|
white-space: nowrap;
|
|
118
148
|
font-family: var(--base-font-family);
|
|
119
149
|
text-shadow: 0 0 0.125rem rgba(0, 0, 0, 0.5);
|
|
150
|
+
display: inline-flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
justify-content: center;
|
|
120
153
|
}
|
|
121
154
|
button[disabled] {
|
|
122
155
|
opacity: 0.5;
|
|
@@ -136,27 +169,60 @@ button.block {
|
|
|
136
169
|
display: block;
|
|
137
170
|
width: 100%;
|
|
138
171
|
}
|
|
172
|
+
button.xs {
|
|
173
|
+
font-size: var(--font-xs);
|
|
174
|
+
line-height: 0.875rem;
|
|
175
|
+
padding: var(--spacing-xs) var(--spacing-sm);
|
|
176
|
+
gap: 0;
|
|
177
|
+
}
|
|
139
178
|
button.sm {
|
|
140
179
|
font-size: var(--font-sm);
|
|
141
180
|
line-height: 1rem;
|
|
142
181
|
padding: var(--spacing-xs) var(--spacing-sm);
|
|
182
|
+
gap: 0;
|
|
183
|
+
}
|
|
184
|
+
button.md {
|
|
185
|
+
font-size: var(--font-base);
|
|
186
|
+
line-height: 1.25rem;
|
|
187
|
+
padding: var(--spacing-sm) var(--spacing-base);
|
|
188
|
+
gap: var(--spacing-xs);
|
|
143
189
|
}
|
|
144
190
|
button.lg {
|
|
145
191
|
font-size: var(--font-md);
|
|
146
192
|
line-height: 1.5rem;
|
|
147
193
|
padding: var(--spacing-md) var(--spacing-lg);
|
|
194
|
+
gap: var(--spacing-sm);
|
|
148
195
|
}
|
|
149
196
|
button.xl {
|
|
150
197
|
font-size: var(--font-xl);
|
|
151
198
|
line-height: 1.75rem;
|
|
152
199
|
padding: var(--spacing-base) var(--spacing-xl);
|
|
200
|
+
gap: var(--spacing-md);
|
|
201
|
+
}
|
|
202
|
+
button.w-auto {
|
|
203
|
+
min-width: auto;
|
|
204
|
+
width: auto;
|
|
205
|
+
}
|
|
206
|
+
button.w-sm {
|
|
207
|
+
min-width: 5rem;
|
|
208
|
+
display: inline-block;
|
|
209
|
+
}
|
|
210
|
+
button.w-md {
|
|
211
|
+
min-width: 10rem;
|
|
212
|
+
display: inline-block;
|
|
213
|
+
}
|
|
214
|
+
button.w-lg {
|
|
215
|
+
min-width: 20rem;
|
|
216
|
+
display: inline-block;
|
|
153
217
|
}
|
|
154
|
-
button.
|
|
218
|
+
button.w-xl {
|
|
219
|
+
min-width: 30rem;
|
|
220
|
+
display: inline-block;
|
|
221
|
+
}
|
|
222
|
+
button.w-full {
|
|
155
223
|
width: 100%;
|
|
156
|
-
padding: var(--spacing-sm) 0;
|
|
157
224
|
display: block;
|
|
158
225
|
min-width: auto;
|
|
159
|
-
flex-grow: 1;
|
|
160
226
|
}
|
|
161
227
|
button:hover {
|
|
162
228
|
background-color: var(--gray-600);
|
|
@@ -225,9 +291,44 @@ button.link {
|
|
|
225
291
|
button.link:hover {
|
|
226
292
|
color: var(--base-link-hover-fg);
|
|
227
293
|
}
|
|
294
|
+
button.ghost {
|
|
295
|
+
background-color: transparent;
|
|
296
|
+
border-color: transparent;
|
|
297
|
+
color: var(--body-fg);
|
|
298
|
+
text-shadow: none;
|
|
299
|
+
}
|
|
300
|
+
button.ghost:hover {
|
|
301
|
+
background-color: var(--button-secondary-bg);
|
|
302
|
+
border-color: var(--button-secondary-border);
|
|
303
|
+
color: var(--button-secondary-fg);
|
|
304
|
+
text-shadow: 0 0 0.125rem rgba(0, 0, 0, 0.5);
|
|
305
|
+
}
|
|
228
306
|
button .spinner-wrapper {
|
|
229
307
|
display: inline-flex;
|
|
230
308
|
align-items: center;
|
|
231
309
|
margin-right: var(--spacing-xs);
|
|
232
310
|
vertical-align: middle;
|
|
311
|
+
}
|
|
312
|
+
button .button-content {
|
|
313
|
+
display: inline;
|
|
314
|
+
}
|
|
315
|
+
button .icon-wrapper {
|
|
316
|
+
display: inline-flex;
|
|
317
|
+
align-items: center;
|
|
318
|
+
vertical-align: middle;
|
|
319
|
+
}
|
|
320
|
+
button.icon-left .icon-wrapper {
|
|
321
|
+
margin-right: var(--spacing-xs);
|
|
322
|
+
}
|
|
323
|
+
button.icon-right .icon-wrapper {
|
|
324
|
+
margin-left: var(--spacing-xs);
|
|
325
|
+
}
|
|
326
|
+
button.icon-above, button.icon-below {
|
|
327
|
+
display: inline-flex;
|
|
328
|
+
flex-direction: column;
|
|
329
|
+
align-items: center;
|
|
330
|
+
gap: var(--spacing-xs);
|
|
331
|
+
}
|
|
332
|
+
button.icon-above .icon-wrapper {
|
|
333
|
+
order: -1;
|
|
233
334
|
}</style>
|
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
* @component
|
|
4
4
|
*/
|
|
5
5
|
import type { Snippet } from 'svelte';
|
|
6
|
-
import type { ButtonVariant, FormFieldSizeOptions } from '../../types/form.js';
|
|
6
|
+
import type { ButtonVariant, ComponentWidth, FormFieldSizeOptions } from '../../types/form.js';
|
|
7
|
+
import type { IconType } from '../../icons/types.js';
|
|
8
|
+
import type { ComponentSize } from '../../types';
|
|
7
9
|
type $$ComponentProps = {
|
|
8
10
|
href?: string | undefined;
|
|
9
11
|
size?: FormFieldSizeOptions;
|
|
12
|
+
width?: ComponentWidth;
|
|
10
13
|
variant?: ButtonVariant;
|
|
11
14
|
type?: 'button' | 'submit' | 'reset';
|
|
12
15
|
block?: boolean;
|
|
@@ -17,8 +20,11 @@ type $$ComponentProps = {
|
|
|
17
20
|
noMargin?: boolean;
|
|
18
21
|
collapse?: boolean;
|
|
19
22
|
repeatSubmitDelay?: number | 'infinite';
|
|
23
|
+
icon?: IconType | undefined;
|
|
24
|
+
iconAlign?: 'left' | 'right' | 'above' | 'below';
|
|
25
|
+
iconSize?: 'default' | ComponentSize;
|
|
20
26
|
onClick?: ((e?: Event) => void) | undefined;
|
|
21
|
-
children
|
|
27
|
+
children?: Snippet;
|
|
22
28
|
};
|
|
23
29
|
declare const Button: import("svelte").Component<$$ComponentProps, {}, "disabled">;
|
|
24
30
|
type Button = ReturnType<typeof Button>;
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
// Reassign instead of mutate to avoid circular dependency
|
|
42
42
|
const newItems = currentItems.map((item) => ({
|
|
43
43
|
...item,
|
|
44
|
-
isChecked: currentGroup.includes(item.value
|
|
44
|
+
isChecked: currentGroup.includes(item.value != null ? String(item.value) : '')
|
|
45
45
|
}));
|
|
46
46
|
itemsWithState = newItems;
|
|
47
47
|
});
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
{#each itemsWithState as item}
|
|
66
66
|
<CheckBox
|
|
67
67
|
{disabled}
|
|
68
|
-
value={item.value
|
|
68
|
+
value={item.value != null ? String(item.value) : undefined}
|
|
69
69
|
bind:isChecked={item.isChecked}
|
|
70
70
|
onChange={handleCheckboxChange}
|
|
71
71
|
label={item.name}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
TextBox
|
|
9
9
|
} from '../../index.js';
|
|
10
10
|
import FlexCol from '../../layout/flex-col.svelte';
|
|
11
|
-
import type { SearchFunction } from '
|
|
11
|
+
import type { SearchFunction } from '../../types/form.js';
|
|
12
12
|
|
|
13
13
|
let {
|
|
14
14
|
mode = $bindable('existing' as 'new' | 'existing'),
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
disabled = false,
|
|
20
20
|
required = false,
|
|
21
21
|
searchable = false,
|
|
22
|
-
search = undefined
|
|
22
|
+
search = undefined,
|
|
23
23
|
searchPlaceholder = 'Search',
|
|
24
24
|
newPlaceholder = 'New'
|
|
25
25
|
}: {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
disabled?: boolean;
|
|
32
32
|
required?: boolean;
|
|
33
33
|
searchable?: boolean;
|
|
34
|
-
search?: SearchFunction | undefined;
|
|
34
|
+
search?: SearchFunction<DropdownOption> | undefined;
|
|
35
35
|
searchPlaceholder?: string;
|
|
36
36
|
newPlaceholder?: string;
|
|
37
37
|
} = $props();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type DropdownOption, type FormFieldSizeOptions } from '../../index.js';
|
|
2
|
-
import type { SearchFunction } from '
|
|
2
|
+
import type { SearchFunction } from '../../types/form.js';
|
|
3
3
|
type $$ComponentProps = {
|
|
4
4
|
mode?: 'new' | 'existing';
|
|
5
5
|
newValue?: string | null;
|
|
@@ -9,7 +9,7 @@ type $$ComponentProps = {
|
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
required?: boolean;
|
|
11
11
|
searchable?: boolean;
|
|
12
|
-
search?: SearchFunction | undefined;
|
|
12
|
+
search?: SearchFunction<DropdownOption> | undefined;
|
|
13
13
|
searchPlaceholder?: string;
|
|
14
14
|
newPlaceholder?: string;
|
|
15
15
|
};
|
package/dist/forms/form.svelte
CHANGED
package/dist/forms/index.d.ts
CHANGED
|
@@ -17,11 +17,7 @@ export { default as TextArea } from './text-area/text-area.svelte';
|
|
|
17
17
|
export { default as TextBox } from './text-box/text-box.svelte';
|
|
18
18
|
export { default as TimeBox } from './time-box/time-box.svelte';
|
|
19
19
|
export { default as UrlBox } from './url-box/url-box.svelte';
|
|
20
|
-
export
|
|
21
|
-
export * from './list-box/index.js';
|
|
22
|
-
export * from './phone-box/index.js';
|
|
23
|
-
export * from './radio-group/index.js';
|
|
24
|
-
export * from './reference-box/index.js';
|
|
20
|
+
export { default as ListBox } from './list-box/list-box.svelte';
|
|
25
21
|
export { default as Form } from './form.svelte';
|
|
26
22
|
export { default as FormActions } from './form-actions/form-actions.svelte';
|
|
27
23
|
export { default as FormField } from './form-field/form-field.svelte';
|
|
@@ -31,4 +27,7 @@ export { default as FormLabel } from './form-label/form-label.svelte';
|
|
|
31
27
|
export { default as FormSection } from './form-section/form-section.svelte';
|
|
32
28
|
export { default as FormRow } from './form-row/form-row.svelte';
|
|
33
29
|
export type { AdditionalButton } from './form-actions/form-actions.svelte';
|
|
30
|
+
export * from './check-box/index.js';
|
|
31
|
+
export * from './phone-box/index.js';
|
|
32
|
+
export * from './radio-group/index.js';
|
|
34
33
|
export * from './validation.js';
|
package/dist/forms/index.js
CHANGED
|
@@ -18,12 +18,7 @@ export { default as TextArea } from './text-area/text-area.svelte';
|
|
|
18
18
|
export { default as TextBox } from './text-box/text-box.svelte';
|
|
19
19
|
export { default as TimeBox } from './time-box/time-box.svelte';
|
|
20
20
|
export { default as UrlBox } from './url-box/url-box.svelte';
|
|
21
|
-
|
|
22
|
-
export * from './check-box/index.js';
|
|
23
|
-
export * from './list-box/index.js';
|
|
24
|
-
export * from './phone-box/index.js';
|
|
25
|
-
export * from './radio-group/index.js';
|
|
26
|
-
export * from './reference-box/index.js';
|
|
21
|
+
export { default as ListBox } from './list-box/list-box.svelte';
|
|
27
22
|
// Form structure components
|
|
28
23
|
export { default as Form } from './form.svelte';
|
|
29
24
|
export { default as FormActions } from './form-actions/form-actions.svelte';
|
|
@@ -33,5 +28,9 @@ export { default as FormHeader } from './form-header.svelte';
|
|
|
33
28
|
export { default as FormLabel } from './form-label/form-label.svelte';
|
|
34
29
|
export { default as FormSection } from './form-section/form-section.svelte';
|
|
35
30
|
export { default as FormRow } from './form-row/form-row.svelte';
|
|
31
|
+
// Form components with barrel files
|
|
32
|
+
export * from './check-box/index.js';
|
|
33
|
+
export * from './phone-box/index.js';
|
|
34
|
+
export * from './radio-group/index.js';
|
|
36
35
|
// Validation utilities
|
|
37
36
|
export * from './validation.js';
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
import debounce from '../../helpers/debounce.js';
|
|
8
8
|
import { browser } from '$app/environment';
|
|
9
9
|
import { onMount, untrack } from 'svelte';
|
|
10
|
-
import type { SearchFunction, CreateNewFunction } from './list-box.js';
|
|
11
10
|
import Prompt from '../../modals/prompt.svelte';
|
|
12
11
|
import { ucfirst } from '../../helpers/ucfirst.js';
|
|
12
|
+
import type { CreateNewFunction, SearchFunction } from '../../types/form.js';
|
|
13
13
|
|
|
14
14
|
let {
|
|
15
15
|
value = $bindable(null as string | null),
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
required = false,
|
|
20
20
|
readonly = false,
|
|
21
21
|
searchable = false,
|
|
22
|
-
search = undefined
|
|
22
|
+
search = undefined,
|
|
23
23
|
placeholder = '',
|
|
24
24
|
onChange = undefined,
|
|
25
25
|
onFocus = undefined,
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
feedback = undefined,
|
|
30
30
|
virtualScroll = false,
|
|
31
31
|
itemHeight = 40,
|
|
32
|
-
createNew = undefined
|
|
32
|
+
createNew = undefined,
|
|
33
33
|
resourceName = undefined
|
|
34
34
|
}: {
|
|
35
35
|
value?: string | null;
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
required?: boolean;
|
|
40
40
|
readonly?: boolean;
|
|
41
41
|
searchable?: boolean;
|
|
42
|
-
search?: SearchFunction | undefined;
|
|
42
|
+
search?: SearchFunction<DropdownOption> | undefined;
|
|
43
43
|
placeholder?: string;
|
|
44
44
|
onChange?: ((value: string | null) => void) | undefined;
|
|
45
45
|
onFocus?: ((e: FocusEvent) => void) | undefined;
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
feedback?: FormFieldFeedback;
|
|
50
50
|
virtualScroll?: boolean;
|
|
51
51
|
itemHeight?: number;
|
|
52
|
-
createNew?: CreateNewFunction | undefined;
|
|
52
|
+
createNew?: CreateNewFunction<DropdownOption> | undefined;
|
|
53
53
|
resourceName?: string;
|
|
54
54
|
} = $props();
|
|
55
55
|
|
|
@@ -113,7 +113,9 @@
|
|
|
113
113
|
});
|
|
114
114
|
|
|
115
115
|
// Check if there are no results when searching
|
|
116
|
-
let hasNoResults = $derived(
|
|
116
|
+
let hasNoResults = $derived(
|
|
117
|
+
isSearchable && text.trim() && filteredItems.length === 0 && !isLoading
|
|
118
|
+
);
|
|
117
119
|
|
|
118
120
|
// Get the ID of the highlighted option for ARIA
|
|
119
121
|
let activeDescendant = $derived(
|
|
@@ -139,7 +141,7 @@
|
|
|
139
141
|
// When an item is selected from the dropdown menu
|
|
140
142
|
const onSelect = (item: MenuOption) => {
|
|
141
143
|
isUserTyping = false;
|
|
142
|
-
value = item.value;
|
|
144
|
+
value = item.value != null ? String(item.value) : null;
|
|
143
145
|
onChange?.(value);
|
|
144
146
|
text = getText();
|
|
145
147
|
isMenuOpen = false;
|
|
@@ -216,7 +218,12 @@
|
|
|
216
218
|
|
|
217
219
|
if (e.key === 'Enter') {
|
|
218
220
|
e.preventDefault();
|
|
219
|
-
if (
|
|
221
|
+
if (
|
|
222
|
+
isMenuOpen &&
|
|
223
|
+
highlightIndex >= 0 &&
|
|
224
|
+
highlightIndex < filteredItems.length &&
|
|
225
|
+
filteredItems[highlightIndex]
|
|
226
|
+
) {
|
|
220
227
|
onSelect(filteredItems[highlightIndex]);
|
|
221
228
|
} else if (isMenuOpen && createNew && highlightIndex === filteredItems.length) {
|
|
222
229
|
// "Create new..." is highlighted
|
|
@@ -231,7 +238,12 @@
|
|
|
231
238
|
}
|
|
232
239
|
|
|
233
240
|
if (e.key === 'Tab') {
|
|
234
|
-
if (
|
|
241
|
+
if (
|
|
242
|
+
isMenuOpen &&
|
|
243
|
+
highlightIndex >= 0 &&
|
|
244
|
+
highlightIndex < filteredItems.length &&
|
|
245
|
+
filteredItems[highlightIndex]
|
|
246
|
+
) {
|
|
235
247
|
e.preventDefault();
|
|
236
248
|
onSelect(filteredItems[highlightIndex]);
|
|
237
249
|
} else if (isMenuOpen && createNew && highlightIndex === filteredItems.length) {
|
|
@@ -325,7 +337,7 @@
|
|
|
325
337
|
localItems = [...localItems, result];
|
|
326
338
|
|
|
327
339
|
// Select the newly created item
|
|
328
|
-
value = result.value;
|
|
340
|
+
value = result.value != null ? String(result.value) : null;
|
|
329
341
|
onChange?.(value);
|
|
330
342
|
text = result.name;
|
|
331
343
|
isMenuOpen = false;
|
|
@@ -458,7 +470,6 @@
|
|
|
458
470
|
closeAfterSelect={true}
|
|
459
471
|
searchText={isSearchable ? text : ''}
|
|
460
472
|
{onSelect}
|
|
461
|
-
size="full"
|
|
462
473
|
bind:highlightIndex
|
|
463
474
|
bind:value
|
|
464
475
|
{listboxId}
|
|
@@ -509,9 +520,7 @@
|
|
|
509
520
|
</div>
|
|
510
521
|
{/if}
|
|
511
522
|
{#if isCreating}
|
|
512
|
-
<div class="creating-indicator" aria-live="polite">
|
|
513
|
-
Creating...
|
|
514
|
-
</div>
|
|
523
|
+
<div class="creating-indicator" aria-live="polite">Creating...</div>
|
|
515
524
|
{/if}
|
|
516
525
|
</Prompt>
|
|
517
526
|
{/key}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DropdownOption, FormFieldSizeOptions } from '../../types/form.js';
|
|
2
2
|
import { type FormFieldFeedback } from '../form-field/form-field.svelte';
|
|
3
|
-
import type {
|
|
3
|
+
import type { CreateNewFunction, SearchFunction } from '../../types/form.js';
|
|
4
4
|
type $$ComponentProps = {
|
|
5
5
|
value?: string | null;
|
|
6
6
|
items?: DropdownOption[];
|
|
@@ -9,7 +9,7 @@ type $$ComponentProps = {
|
|
|
9
9
|
required?: boolean;
|
|
10
10
|
readonly?: boolean;
|
|
11
11
|
searchable?: boolean;
|
|
12
|
-
search?: SearchFunction | undefined;
|
|
12
|
+
search?: SearchFunction<DropdownOption> | undefined;
|
|
13
13
|
placeholder?: string;
|
|
14
14
|
onChange?: ((value: string | null) => void) | undefined;
|
|
15
15
|
onFocus?: ((e: FocusEvent) => void) | undefined;
|
|
@@ -19,7 +19,7 @@ type $$ComponentProps = {
|
|
|
19
19
|
feedback?: FormFieldFeedback;
|
|
20
20
|
virtualScroll?: boolean;
|
|
21
21
|
itemHeight?: number;
|
|
22
|
-
createNew?: CreateNewFunction | undefined;
|
|
22
|
+
createNew?: CreateNewFunction<DropdownOption> | undefined;
|
|
23
23
|
resourceName?: string;
|
|
24
24
|
};
|
|
25
25
|
declare const ListBox: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default as ReferenceBox } from './reference-box.svelte';
|
|
2
|
-
export type { ReferenceItem, SearchFunction, CreateNewFunction } from './reference-box.js';
|
|
2
|
+
export type { ReferenceItem, SearchFunction, CreateNewFunction, LinkBuilderFunction } from './reference-box.js';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { SearchFunction as BaseSearchFunction, CreateNewFunction as BaseCreateNewFunction } from '../../types/form.js';
|
|
1
2
|
export type ReferenceItem = {
|
|
2
3
|
id: string | number;
|
|
3
4
|
name: string;
|
|
4
5
|
description?: string;
|
|
5
6
|
};
|
|
6
|
-
export type SearchFunction =
|
|
7
|
-
export type CreateNewFunction =
|
|
7
|
+
export type SearchFunction = BaseSearchFunction<ReferenceItem>;
|
|
8
|
+
export type CreateNewFunction = BaseCreateNewFunction<ReferenceItem>;
|
|
8
9
|
export type LinkBuilderFunction = (item: ReferenceItem) => string | undefined;
|
|
@@ -7,15 +7,11 @@
|
|
|
7
7
|
import { onMount } from 'svelte';
|
|
8
8
|
import { browser } from '$app/environment';
|
|
9
9
|
import debounce from '../../helpers/debounce.js';
|
|
10
|
-
import type {
|
|
11
|
-
ReferenceItem,
|
|
12
|
-
SearchFunction,
|
|
13
|
-
CreateNewFunction,
|
|
14
|
-
LinkBuilderFunction
|
|
15
|
-
} from './reference-box.js';
|
|
16
10
|
import Prompt from '../../modals/prompt.svelte';
|
|
17
11
|
import { ucfirst } from '../../helpers/ucfirst.js';
|
|
18
12
|
import Icon from '../../icons/icon.svelte';
|
|
13
|
+
import type { SearchFunction, CreateNewFunction } from '../../types/form.js';
|
|
14
|
+
import type { ReferenceItem, LinkBuilderFunction } from './reference-box.js';
|
|
19
15
|
|
|
20
16
|
const id = uniqueId();
|
|
21
17
|
const listboxId = `${id}-listbox`;
|
|
@@ -23,8 +19,8 @@
|
|
|
23
19
|
let {
|
|
24
20
|
value = $bindable([] as ReferenceItem[]),
|
|
25
21
|
items = [] as ReferenceItem[],
|
|
26
|
-
search = undefined
|
|
27
|
-
createNew = undefined
|
|
22
|
+
search = undefined,
|
|
23
|
+
createNew = undefined,
|
|
28
24
|
linkBuilder = undefined as LinkBuilderFunction | undefined,
|
|
29
25
|
resourceName = undefined as string | undefined,
|
|
30
26
|
placeholder = 'Search and add items...',
|
|
@@ -39,8 +35,8 @@
|
|
|
39
35
|
}: {
|
|
40
36
|
value?: ReferenceItem[];
|
|
41
37
|
items?: ReferenceItem[];
|
|
42
|
-
search?: SearchFunction | undefined;
|
|
43
|
-
createNew?: CreateNewFunction | undefined;
|
|
38
|
+
search?: SearchFunction<ReferenceItem> | undefined;
|
|
39
|
+
createNew?: CreateNewFunction<ReferenceItem> | undefined;
|
|
44
40
|
linkBuilder?: LinkBuilderFunction | undefined;
|
|
45
41
|
resourceName?: string | undefined;
|
|
46
42
|
placeholder?: string;
|
|
@@ -433,7 +429,6 @@
|
|
|
433
429
|
closeAfterSelect={true}
|
|
434
430
|
{searchText}
|
|
435
431
|
onSelect={onSelectFromMenu}
|
|
436
|
-
size="full"
|
|
437
432
|
bind:highlightIndex
|
|
438
433
|
{listboxId}
|
|
439
434
|
/>
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { type FormFieldFeedback } from '../form-field/form-field.svelte';
|
|
2
2
|
import type { FormFieldSizeOptions } from '../../types/form.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { SearchFunction, CreateNewFunction } from '../../types/form.js';
|
|
4
|
+
import type { ReferenceItem, LinkBuilderFunction } from './reference-box.js';
|
|
4
5
|
type $$ComponentProps = {
|
|
5
6
|
value?: ReferenceItem[];
|
|
6
7
|
items?: ReferenceItem[];
|
|
7
|
-
search?: SearchFunction | undefined;
|
|
8
|
-
createNew?: CreateNewFunction | undefined;
|
|
8
|
+
search?: SearchFunction<ReferenceItem> | undefined;
|
|
9
|
+
createNew?: CreateNewFunction<ReferenceItem> | undefined;
|
|
9
10
|
linkBuilder?: LinkBuilderFunction | undefined;
|
|
10
11
|
resourceName?: string | undefined;
|
|
11
12
|
placeholder?: string;
|
|
@@ -1,32 +1,65 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Empty state component for displaying messages when no data is available.
|
|
4
|
+
* Supports icons, messages, descriptions, and custom content.
|
|
5
|
+
* @component
|
|
6
|
+
*/
|
|
2
7
|
import type { Snippet } from 'svelte';
|
|
8
|
+
import type { IconType } from '../../icons/types.js';
|
|
9
|
+
import Icon from '../../icons/icon.svelte';
|
|
3
10
|
|
|
4
11
|
let {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
/** Primary title/heading */
|
|
13
|
+
title = undefined,
|
|
14
|
+
/** Main message text (required if no title) */
|
|
15
|
+
message = 'No data to display',
|
|
16
|
+
/** Optional secondary description */
|
|
17
|
+
description = undefined,
|
|
18
|
+
/** Built-in icon type */
|
|
19
|
+
icon = undefined,
|
|
20
|
+
/** Icon size */
|
|
21
|
+
iconSize = 'xl',
|
|
22
|
+
/** Component size affects padding and text sizing */
|
|
23
|
+
size = 'md',
|
|
24
|
+
/** Custom content (buttons, links, etc.) */
|
|
10
25
|
children = undefined
|
|
11
26
|
}: {
|
|
12
|
-
|
|
27
|
+
title?: string;
|
|
28
|
+
message?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
icon?: IconType;
|
|
31
|
+
iconSize?: 'sm' | 'md' | 'lg' | 'xl';
|
|
13
32
|
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
14
|
-
orientation?: 'horizontal' | 'vertical';
|
|
15
|
-
reverse?: boolean;
|
|
16
|
-
align?: 'center' | 'start' | 'end';
|
|
17
33
|
children?: Snippet;
|
|
18
34
|
} = $props();
|
|
19
35
|
</script>
|
|
20
36
|
|
|
21
|
-
<div class="empty {size}
|
|
22
|
-
{#if
|
|
23
|
-
<div class="icon">
|
|
24
|
-
{
|
|
37
|
+
<div class="empty {size}">
|
|
38
|
+
{#if icon}
|
|
39
|
+
<div class="icon-wrapper">
|
|
40
|
+
<Icon type={icon} size={iconSize} variant="secondary" />
|
|
25
41
|
</div>
|
|
26
42
|
{/if}
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
|
|
44
|
+
<div class="content">
|
|
45
|
+
{#if title}
|
|
46
|
+
<h3 class="title">{title}</h3>
|
|
47
|
+
{/if}
|
|
48
|
+
|
|
49
|
+
{#if message}
|
|
50
|
+
<p class="message">{message}</p>
|
|
51
|
+
{/if}
|
|
52
|
+
|
|
53
|
+
{#if description}
|
|
54
|
+
<p class="description">{description}</p>
|
|
55
|
+
{/if}
|
|
29
56
|
</div>
|
|
57
|
+
|
|
58
|
+
{#if children}
|
|
59
|
+
<div class="actions">
|
|
60
|
+
{@render children()}
|
|
61
|
+
</div>
|
|
62
|
+
{/if}
|
|
30
63
|
</div>
|
|
31
64
|
|
|
32
65
|
<style>.empty {
|
|
@@ -35,80 +68,131 @@
|
|
|
35
68
|
align-items: center;
|
|
36
69
|
justify-content: center;
|
|
37
70
|
text-align: center;
|
|
38
|
-
color: var(--gray-500);
|
|
39
|
-
font-weight: 500;
|
|
40
71
|
padding: var(--spacing-2xl);
|
|
72
|
+
gap: var(--spacing-lg);
|
|
41
73
|
}
|
|
42
74
|
|
|
43
|
-
.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
justify-content:
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.horizontal {
|
|
52
|
-
flex-direction: row;
|
|
53
|
-
gap: var(--spacing-lg);
|
|
75
|
+
.icon-wrapper {
|
|
76
|
+
color: var(--gray-400);
|
|
77
|
+
opacity: 0.8;
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
justify-content: center;
|
|
54
81
|
}
|
|
55
|
-
.
|
|
56
|
-
|
|
82
|
+
.icon-wrapper :global(svg) {
|
|
83
|
+
width: 100%;
|
|
84
|
+
height: 100%;
|
|
57
85
|
}
|
|
58
86
|
|
|
59
|
-
.
|
|
60
|
-
|
|
87
|
+
.content {
|
|
88
|
+
display: flex;
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
gap: var(--spacing-sm);
|
|
91
|
+
max-width: 32rem;
|
|
61
92
|
}
|
|
62
93
|
|
|
63
|
-
.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
94
|
+
.title {
|
|
95
|
+
color: var(--gray-700);
|
|
96
|
+
font-size: var(--font-lg);
|
|
97
|
+
font-weight: 600;
|
|
98
|
+
line-height: 1.4;
|
|
99
|
+
margin: 0;
|
|
67
100
|
}
|
|
68
101
|
|
|
69
|
-
.
|
|
102
|
+
.message {
|
|
70
103
|
color: var(--gray-600);
|
|
71
104
|
font-size: var(--font-md);
|
|
105
|
+
font-weight: 500;
|
|
72
106
|
line-height: 1.6;
|
|
107
|
+
margin: 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.description {
|
|
111
|
+
color: var(--gray-500);
|
|
112
|
+
font-size: var(--font-base);
|
|
113
|
+
line-height: 1.5;
|
|
114
|
+
margin: 0;
|
|
73
115
|
}
|
|
74
116
|
|
|
117
|
+
.actions {
|
|
118
|
+
display: flex;
|
|
119
|
+
flex-wrap: wrap;
|
|
120
|
+
gap: var(--spacing-sm);
|
|
121
|
+
justify-content: center;
|
|
122
|
+
align-items: center;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Size variants */
|
|
75
126
|
.sm {
|
|
76
127
|
padding: var(--spacing-lg);
|
|
128
|
+
gap: var(--spacing-base);
|
|
77
129
|
}
|
|
78
|
-
.sm .
|
|
79
|
-
font-size:
|
|
130
|
+
.sm .icon-wrapper {
|
|
131
|
+
font-size: 2rem;
|
|
80
132
|
}
|
|
81
|
-
.sm .icon {
|
|
82
|
-
height: 2rem;
|
|
133
|
+
.sm .icon-wrapper :global(.icon) {
|
|
83
134
|
width: 2rem;
|
|
135
|
+
height: 2rem;
|
|
84
136
|
}
|
|
85
|
-
|
|
86
|
-
.md .text {
|
|
137
|
+
.sm .title {
|
|
87
138
|
font-size: var(--font-md);
|
|
88
139
|
}
|
|
89
|
-
.
|
|
90
|
-
|
|
140
|
+
.sm .message {
|
|
141
|
+
font-size: var(--font-base);
|
|
142
|
+
}
|
|
143
|
+
.sm .description {
|
|
144
|
+
font-size: var(--font-sm);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.md .icon-wrapper {
|
|
148
|
+
font-size: 3rem;
|
|
149
|
+
}
|
|
150
|
+
.md .icon-wrapper :global(.icon) {
|
|
91
151
|
width: 3rem;
|
|
152
|
+
height: 3rem;
|
|
92
153
|
}
|
|
93
154
|
|
|
94
155
|
.lg {
|
|
95
156
|
padding: var(--spacing-2xl) var(--spacing-xl);
|
|
157
|
+
gap: var(--spacing-xl);
|
|
96
158
|
}
|
|
97
|
-
.lg .
|
|
98
|
-
font-size:
|
|
159
|
+
.lg .icon-wrapper {
|
|
160
|
+
font-size: 4rem;
|
|
99
161
|
}
|
|
100
|
-
.lg .icon {
|
|
101
|
-
height: 4rem;
|
|
162
|
+
.lg .icon-wrapper :global(.icon) {
|
|
102
163
|
width: 4rem;
|
|
164
|
+
height: 4rem;
|
|
165
|
+
}
|
|
166
|
+
.lg .title {
|
|
167
|
+
font-size: var(--font-xl);
|
|
168
|
+
}
|
|
169
|
+
.lg .message {
|
|
170
|
+
font-size: var(--font-lg);
|
|
171
|
+
}
|
|
172
|
+
.lg .description {
|
|
173
|
+
font-size: var(--font-md);
|
|
103
174
|
}
|
|
104
175
|
|
|
105
176
|
.xl {
|
|
106
177
|
padding: 4rem var(--spacing-2xl);
|
|
178
|
+
gap: var(--spacing-2xl);
|
|
107
179
|
}
|
|
108
|
-
.xl .
|
|
109
|
-
font-size:
|
|
180
|
+
.xl .icon-wrapper {
|
|
181
|
+
font-size: 5rem;
|
|
110
182
|
}
|
|
111
|
-
.xl .icon {
|
|
112
|
-
height: 5rem;
|
|
183
|
+
.xl .icon-wrapper :global(.icon) {
|
|
113
184
|
width: 5rem;
|
|
185
|
+
height: 5rem;
|
|
186
|
+
}
|
|
187
|
+
.xl .title {
|
|
188
|
+
font-size: var(--font-2xl);
|
|
189
|
+
}
|
|
190
|
+
.xl .message {
|
|
191
|
+
font-size: var(--font-xl);
|
|
192
|
+
}
|
|
193
|
+
.xl .description {
|
|
194
|
+
font-size: var(--font-lg);
|
|
195
|
+
}
|
|
196
|
+
.xl .actions {
|
|
197
|
+
gap: var(--spacing-base);
|
|
114
198
|
}</style>
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Empty state component for displaying messages when no data is available.
|
|
3
|
+
* Supports icons, messages, descriptions, and custom content.
|
|
4
|
+
* @component
|
|
5
|
+
*/
|
|
1
6
|
import type { Snippet } from 'svelte';
|
|
7
|
+
import type { IconType } from '../../icons/types.js';
|
|
2
8
|
type $$ComponentProps = {
|
|
3
|
-
|
|
9
|
+
title?: string;
|
|
10
|
+
message?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
icon?: IconType;
|
|
13
|
+
iconSize?: 'sm' | 'md' | 'lg' | 'xl';
|
|
4
14
|
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
5
|
-
orientation?: 'horizontal' | 'vertical';
|
|
6
|
-
reverse?: boolean;
|
|
7
|
-
align?: 'center' | 'start' | 'end';
|
|
8
15
|
children?: Snippet;
|
|
9
16
|
};
|
|
10
17
|
declare const Empty: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
let {
|
|
5
5
|
show = true,
|
|
6
6
|
onClick = undefined,
|
|
7
|
+
onEscape = undefined,
|
|
7
8
|
blur = false,
|
|
8
9
|
children
|
|
9
10
|
}: {
|
|
10
11
|
show?: boolean;
|
|
11
12
|
onClick?: (() => void) | undefined;
|
|
13
|
+
onEscape?: (() => void) | undefined;
|
|
12
14
|
blur?: boolean;
|
|
13
15
|
children?: Snippet;
|
|
14
16
|
} = $props();
|
|
@@ -22,7 +24,7 @@
|
|
|
22
24
|
|
|
23
25
|
const onKeyPress = (event: KeyboardEvent) => {
|
|
24
26
|
if (event.key === 'Escape') {
|
|
25
|
-
|
|
27
|
+
onEscape?.();
|
|
26
28
|
}
|
|
27
29
|
};
|
|
28
30
|
</script>
|
package/dist/modals/alert.svelte
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
</script>
|
|
38
38
|
|
|
39
39
|
{#if open}
|
|
40
|
-
<Overlay
|
|
40
|
+
<Overlay onEscape={close}>
|
|
41
41
|
<Dialog
|
|
42
42
|
{size}
|
|
43
43
|
role="alertdialog"
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
<DialogBody>
|
|
55
55
|
{@render children?.()}
|
|
56
56
|
</DialogBody>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
<Divider />
|
|
58
|
+
<DialogFooter>
|
|
59
|
+
<Button onClick={close} variant={buttonVariant}>{buttonText}</Button>
|
|
60
|
+
</DialogFooter>
|
|
61
61
|
</Dialog>
|
|
62
62
|
</Overlay>
|
|
63
63
|
{/if}
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
</script>
|
|
49
49
|
|
|
50
50
|
{#if open}
|
|
51
|
-
<Overlay
|
|
51
|
+
<Overlay onEscape={no}>
|
|
52
52
|
<Dialog
|
|
53
53
|
{size}
|
|
54
54
|
role="alertdialog"
|
|
@@ -65,11 +65,11 @@
|
|
|
65
65
|
<DialogBody>
|
|
66
66
|
{@render children?.()}
|
|
67
67
|
</DialogBody>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
<Divider />
|
|
69
|
+
<DialogFooter>
|
|
70
|
+
<Button onClick={no} variant={noVariant}>{noText}</Button>
|
|
71
|
+
<Button onClick={yes} variant={yesVariant}>{yesText}</Button>
|
|
72
|
+
</DialogFooter>
|
|
73
73
|
</Dialog>
|
|
74
74
|
</Overlay>
|
|
75
75
|
{/if}
|
package/dist/modals/modal.svelte
CHANGED
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
</script>
|
|
81
81
|
|
|
82
82
|
{#if open}
|
|
83
|
-
<Overlay {blur}
|
|
83
|
+
<Overlay {blur} onEscape={dismissable ? close : undefined}>
|
|
84
84
|
<div bind:this={dialogElement}>
|
|
85
85
|
<Dialog {size} {glass} role="dialog" aria-modal="true" aria-labelledby={titleId}>
|
|
86
86
|
<DialogCloseButton show={_showCloseButton} onClick={close} />
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
</script>
|
|
59
59
|
|
|
60
60
|
{#if open}
|
|
61
|
-
<Overlay
|
|
61
|
+
<Overlay onEscape={no}>
|
|
62
62
|
<Dialog
|
|
63
63
|
{size}
|
|
64
64
|
role="dialog"
|
|
@@ -73,16 +73,16 @@
|
|
|
73
73
|
{/if}
|
|
74
74
|
<DialogCloseButton show={showCloseButton} onClick={no} />
|
|
75
75
|
<DialogBody>
|
|
76
|
-
<TextBox bind:value {placeholder} {type} {required}
|
|
76
|
+
<TextBox bind:value {placeholder} {type} {required} />
|
|
77
77
|
{#if children}
|
|
78
78
|
{@render children()}
|
|
79
79
|
{/if}
|
|
80
80
|
</DialogBody>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
<Divider />
|
|
82
|
+
<DialogFooter>
|
|
83
|
+
<Button onClick={no} variant={cancelVariant}>{cancelText}</Button>
|
|
84
|
+
<Button onClick={yes} variant={okVariant}>{okText}</Button>
|
|
85
|
+
</DialogFooter>
|
|
86
86
|
</Dialog>
|
|
87
87
|
</Overlay>
|
|
88
88
|
{/if}
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
RowActions
|
|
13
13
|
} from '../types/data.js';
|
|
14
14
|
import Empty from '../generic/empty/empty.svelte';
|
|
15
|
-
import Icon from '../icons/icon.svelte';
|
|
16
15
|
import Pagination from '../navigation/pagination/pagination.svelte';
|
|
17
16
|
import Loading from '../placeholders/loading.svelte';
|
|
18
17
|
import TableCaption from './table-caption.svelte';
|
|
@@ -254,9 +253,7 @@
|
|
|
254
253
|
{#if rows === undefined}
|
|
255
254
|
<Loading />
|
|
256
255
|
{:else}
|
|
257
|
-
<Empty
|
|
258
|
-
<Icon type="folder-open" size="lg" />
|
|
259
|
-
</Empty>
|
|
256
|
+
<Empty icon="folder-open" iconSize="lg" />
|
|
260
257
|
{/if}
|
|
261
258
|
</div>
|
|
262
259
|
</TableCell>
|
package/dist/types/form.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export type { ComponentSize as FormFieldSizeOptions } from './size.js';
|
|
1
|
+
export type { ComponentSize as FormFieldSizeOptions, ComponentWidth } from './size.js';
|
|
2
2
|
/**
|
|
3
3
|
* Button variant options
|
|
4
4
|
*/
|
|
5
|
-
export type ButtonVariant = 'primary' | 'secondary' | 'positive' | 'danger' | 'outline' | 'link';
|
|
5
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'positive' | 'danger' | 'outline' | 'link' | 'ghost';
|
|
6
6
|
/**
|
|
7
7
|
* Dropdown option structure
|
|
8
8
|
*/
|
|
9
9
|
export type DropdownOption = {
|
|
10
|
-
value: string | null;
|
|
10
|
+
value: string | number | null;
|
|
11
11
|
name: string;
|
|
12
12
|
id?: string;
|
|
13
13
|
label?: string;
|
|
@@ -27,3 +27,17 @@ export type AllowedTextInputTypes = 'text' | 'email' | 'password' | 'search' | '
|
|
|
27
27
|
* Radio button value type
|
|
28
28
|
*/
|
|
29
29
|
export type RadioButtonValue = string | number | boolean | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Generic search function type
|
|
32
|
+
* @template T The type of item returned (e.g., DropdownOption, ReferenceItem)
|
|
33
|
+
*/
|
|
34
|
+
export type SearchFunction<T extends {
|
|
35
|
+
name: string;
|
|
36
|
+
} = DropdownOption> = (text: string) => Promise<T[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Generic create new function type
|
|
39
|
+
* @template T The type of item returned (e.g., DropdownOption, ReferenceItem)
|
|
40
|
+
*/
|
|
41
|
+
export type CreateNewFunction<T extends {
|
|
42
|
+
name: string;
|
|
43
|
+
} = DropdownOption> = (inputName: string) => Promise<T | null>;
|
package/dist/types/size.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Unified size type for all components
|
|
3
|
+
* Controls font size, padding, and general component scale
|
|
3
4
|
*/
|
|
4
|
-
export type ComponentSize = 'sm' | 'md' | 'lg' | 'xl'
|
|
5
|
+
export type ComponentSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
6
|
+
/**
|
|
7
|
+
* Width options for components
|
|
8
|
+
* auto: content-based width (no min-width)
|
|
9
|
+
* xs-xl: fixed minimum widths
|
|
10
|
+
* full: fills available space (100%)
|
|
11
|
+
*/
|
|
12
|
+
export type ComponentWidth = 'auto' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
5
13
|
/**
|
|
6
14
|
* Size utility functions for consistent spacing and sizing
|
|
7
15
|
*/
|
|
@@ -12,11 +20,27 @@ export declare const sizeMap: {
|
|
|
12
20
|
readonly xl: "auto";
|
|
13
21
|
readonly full: "100%";
|
|
14
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* Width map for component widths
|
|
25
|
+
*/
|
|
26
|
+
export declare const widthMap: {
|
|
27
|
+
readonly auto: "auto";
|
|
28
|
+
readonly xs: "10rem";
|
|
29
|
+
readonly sm: "15rem";
|
|
30
|
+
readonly md: "20rem";
|
|
31
|
+
readonly lg: "25rem";
|
|
32
|
+
readonly xl: "30rem";
|
|
33
|
+
readonly full: "100%";
|
|
34
|
+
};
|
|
15
35
|
/**
|
|
16
36
|
* Get max width for a given size
|
|
17
37
|
*/
|
|
18
38
|
export declare const getMaxWidth: (size: ComponentSize) => string;
|
|
19
39
|
/**
|
|
20
|
-
* Get display type for a given size (block for xl
|
|
40
|
+
* Get display type for a given size (block for xl, inline-block for others)
|
|
21
41
|
*/
|
|
22
42
|
export declare const getDisplayType: (size: ComponentSize) => "block" | "inline-block";
|
|
43
|
+
/**
|
|
44
|
+
* Get min-width for a given width option
|
|
45
|
+
*/
|
|
46
|
+
export declare const getMinWidth: (width: ComponentWidth) => string;
|
package/dist/types/size.js
CHANGED
|
@@ -8,6 +8,18 @@ export const sizeMap = {
|
|
|
8
8
|
xl: 'auto',
|
|
9
9
|
full: '100%'
|
|
10
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* Width map for component widths
|
|
13
|
+
*/
|
|
14
|
+
export const widthMap = {
|
|
15
|
+
auto: 'auto',
|
|
16
|
+
xs: '10rem',
|
|
17
|
+
sm: '15rem',
|
|
18
|
+
md: '20rem',
|
|
19
|
+
lg: '25rem',
|
|
20
|
+
xl: '30rem',
|
|
21
|
+
full: '100%'
|
|
22
|
+
};
|
|
11
23
|
/**
|
|
12
24
|
* Get max width for a given size
|
|
13
25
|
*/
|
|
@@ -15,8 +27,14 @@ export const getMaxWidth = (size) => {
|
|
|
15
27
|
return sizeMap[size];
|
|
16
28
|
};
|
|
17
29
|
/**
|
|
18
|
-
* Get display type for a given size (block for xl
|
|
30
|
+
* Get display type for a given size (block for xl, inline-block for others)
|
|
19
31
|
*/
|
|
20
32
|
export const getDisplayType = (size) => {
|
|
21
|
-
return
|
|
33
|
+
return size === 'xl' ? 'block' : 'inline-block';
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Get min-width for a given width option
|
|
37
|
+
*/
|
|
38
|
+
export const getMinWidth = (width) => {
|
|
39
|
+
return widthMap[width];
|
|
22
40
|
};
|