ui-svelte 0.2.18 → 0.2.19
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/control/Audio.svelte +3 -2
- package/dist/control/Button.svelte +11 -2
- package/dist/control/Button.svelte.d.ts +1 -0
- package/dist/control/Fab.svelte +11 -2
- package/dist/control/Fab.svelte.d.ts +1 -0
- package/dist/control/IconButton.svelte +5 -2
- package/dist/control/IconButton.svelte.d.ts +1 -0
- package/dist/control/Image.svelte +2 -0
- package/dist/control/Record.svelte +8 -0
- package/dist/control/ToggleGroup.svelte +6 -3
- package/dist/control/ToggleGroup.svelte.d.ts +1 -0
- package/dist/control/ToggleTheme.svelte +1 -0
- package/dist/control/Video.svelte +4 -0
- package/dist/display/Icon.svelte +6 -1
- package/dist/form/Select.svelte +27 -4
- package/dist/form/TextField.svelte +3 -1
- package/dist/form/Toggle.svelte +2 -0
- package/dist/layout/Provider.svelte +1 -1
- package/dist/navigation/NavMenu.svelte +7 -0
- package/package.json +1 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { PauseFilledIcon, PlayFilledIcon } from '../icons/index.js';
|
|
3
|
+
import { Avatar, IconButton } from '../index.js';
|
|
3
4
|
import { cn } from '../utils/class-names.js';
|
|
4
|
-
import IconButton from './IconButton.svelte';
|
|
5
|
-
import Avatar from '../display/Avatar.svelte';
|
|
6
5
|
|
|
7
6
|
type Props = {
|
|
8
7
|
class?: string;
|
|
@@ -207,6 +206,7 @@
|
|
|
207
206
|
variant={variant === 'solid' ? 'soft' : 'solid'}
|
|
208
207
|
{color}
|
|
209
208
|
onclick={togglePlay}
|
|
209
|
+
ariaLabel={isPlaying ? 'Pause audio' : 'Play audio'}
|
|
210
210
|
/>
|
|
211
211
|
|
|
212
212
|
<div class="media-content">
|
|
@@ -218,6 +218,7 @@
|
|
|
218
218
|
aria-valuenow={Math.round((currentTime / duration) * 100) || 0}
|
|
219
219
|
aria-valuemin="0"
|
|
220
220
|
aria-valuemax="100"
|
|
221
|
+
aria-label="Audio progress"
|
|
221
222
|
>
|
|
222
223
|
<div class="media-bars" class:loading={isAnalyzing} class:loaded={!isAnalyzing}>
|
|
223
224
|
{#if isAnalyzing}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
isWide?: boolean;
|
|
22
22
|
isDisabled?: boolean;
|
|
23
23
|
isSolid?: boolean;
|
|
24
|
+
ariaLabel?: string;
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
const {
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
endIcon,
|
|
38
39
|
isLoading,
|
|
39
40
|
isWide,
|
|
40
|
-
isDisabled
|
|
41
|
+
isDisabled,
|
|
42
|
+
ariaLabel
|
|
41
43
|
}: Props = $props();
|
|
42
44
|
|
|
43
45
|
const colors = {
|
|
@@ -82,7 +84,13 @@
|
|
|
82
84
|
{/snippet}
|
|
83
85
|
|
|
84
86
|
{#if href}
|
|
85
|
-
<a
|
|
87
|
+
<a
|
|
88
|
+
class={baseClasses}
|
|
89
|
+
{href}
|
|
90
|
+
{target}
|
|
91
|
+
aria-label={ariaLabel}
|
|
92
|
+
aria-disabled={isDisabled || undefined}
|
|
93
|
+
>
|
|
86
94
|
{@render content()}
|
|
87
95
|
</a>
|
|
88
96
|
{:else}
|
|
@@ -92,6 +100,7 @@
|
|
|
92
100
|
disabled={isDisabled || isLoading}
|
|
93
101
|
class={baseClasses}
|
|
94
102
|
aria-busy={isLoading}
|
|
103
|
+
aria-label={ariaLabel}
|
|
95
104
|
>
|
|
96
105
|
{#if isLoading}
|
|
97
106
|
<span class="btn-loading">
|
package/dist/control/Fab.svelte
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
offsetY?: string;
|
|
27
27
|
onclick?: () => void;
|
|
28
28
|
children?: Snippet;
|
|
29
|
+
ariaLabel?: string;
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
const {
|
|
@@ -40,7 +41,8 @@
|
|
|
40
41
|
offsetX,
|
|
41
42
|
offsetY,
|
|
42
43
|
onclick,
|
|
43
|
-
children
|
|
44
|
+
children,
|
|
45
|
+
ariaLabel
|
|
44
46
|
}: Props = $props();
|
|
45
47
|
|
|
46
48
|
let isOpen = $state(false);
|
|
@@ -97,7 +99,14 @@
|
|
|
97
99
|
{#if children}
|
|
98
100
|
{@render children()}
|
|
99
101
|
{:else}
|
|
100
|
-
<IconButton
|
|
102
|
+
<IconButton
|
|
103
|
+
{icon}
|
|
104
|
+
{color}
|
|
105
|
+
{variant}
|
|
106
|
+
{size}
|
|
107
|
+
onclick={handleTriggerClick}
|
|
108
|
+
ariaLabel={ariaLabel || (actions.length > 0 ? 'Open actions menu' : undefined)}
|
|
109
|
+
/>
|
|
101
110
|
{/if}
|
|
102
111
|
</div>
|
|
103
112
|
</div>
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
isLoading?: boolean;
|
|
17
17
|
icon: IconData;
|
|
18
18
|
isDisabled?: boolean;
|
|
19
|
+
ariaLabel?: string;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
const {
|
|
@@ -29,7 +30,8 @@
|
|
|
29
30
|
class: className,
|
|
30
31
|
icon,
|
|
31
32
|
isLoading,
|
|
32
|
-
isDisabled
|
|
33
|
+
isDisabled,
|
|
34
|
+
ariaLabel
|
|
33
35
|
}: Props = $props();
|
|
34
36
|
|
|
35
37
|
const colors = {
|
|
@@ -68,7 +70,7 @@
|
|
|
68
70
|
{/snippet}
|
|
69
71
|
|
|
70
72
|
{#if href}
|
|
71
|
-
<a class={baseClasses} {href} {target}>
|
|
73
|
+
<a class={baseClasses} {href} {target} aria-label={ariaLabel}>
|
|
72
74
|
{@render content()}
|
|
73
75
|
</a>
|
|
74
76
|
{:else}
|
|
@@ -78,6 +80,7 @@
|
|
|
78
80
|
disabled={isDisabled || isLoading}
|
|
79
81
|
class={baseClasses}
|
|
80
82
|
aria-busy={isLoading}
|
|
83
|
+
aria-label={ariaLabel}
|
|
81
84
|
>
|
|
82
85
|
{#if isLoading}
|
|
83
86
|
<span class="btn-loading">
|
|
@@ -109,6 +109,7 @@
|
|
|
109
109
|
{color}
|
|
110
110
|
variant="overlay"
|
|
111
111
|
size="sm"
|
|
112
|
+
ariaLabel="Download image"
|
|
112
113
|
/>
|
|
113
114
|
<IconButton
|
|
114
115
|
onclick={handleToggleMaximize}
|
|
@@ -116,6 +117,7 @@
|
|
|
116
117
|
{color}
|
|
117
118
|
variant="overlay"
|
|
118
119
|
size="sm"
|
|
120
|
+
ariaLabel="Toggle fullscreen"
|
|
119
121
|
/>
|
|
120
122
|
</div>
|
|
121
123
|
</div>
|
|
@@ -357,6 +357,7 @@
|
|
|
357
357
|
{color}
|
|
358
358
|
variant={variant === 'solid' ? 'soft' : 'solid'}
|
|
359
359
|
size="md"
|
|
360
|
+
ariaLabel={isPlaying ? 'Pause playback' : 'Play recording'}
|
|
360
361
|
/>
|
|
361
362
|
|
|
362
363
|
<div class="media-content">
|
|
@@ -382,6 +383,7 @@
|
|
|
382
383
|
color="danger"
|
|
383
384
|
variant="ghost"
|
|
384
385
|
size="sm"
|
|
386
|
+
ariaLabel="Discard recording"
|
|
385
387
|
/>
|
|
386
388
|
<IconButton
|
|
387
389
|
onclick={confirmRecording}
|
|
@@ -390,6 +392,7 @@
|
|
|
390
392
|
variant="ghost"
|
|
391
393
|
size="sm"
|
|
392
394
|
isLoading={isUploading}
|
|
395
|
+
ariaLabel="Confirm recording"
|
|
393
396
|
/>
|
|
394
397
|
</div>
|
|
395
398
|
{:else if !isRecording}
|
|
@@ -399,6 +402,7 @@
|
|
|
399
402
|
{color}
|
|
400
403
|
variant={variant === 'solid' ? 'soft' : 'solid'}
|
|
401
404
|
size="md"
|
|
405
|
+
ariaLabel="Start recording"
|
|
402
406
|
/>
|
|
403
407
|
|
|
404
408
|
<div class="media-content">
|
|
@@ -421,6 +425,7 @@
|
|
|
421
425
|
{color}
|
|
422
426
|
variant={variant === 'solid' ? 'soft' : 'solid'}
|
|
423
427
|
size="md"
|
|
428
|
+
ariaLabel="Resume recording"
|
|
424
429
|
/>
|
|
425
430
|
{:else}
|
|
426
431
|
<IconButton
|
|
@@ -429,6 +434,7 @@
|
|
|
429
434
|
{color}
|
|
430
435
|
variant={variant === 'solid' ? 'soft' : 'solid'}
|
|
431
436
|
size="md"
|
|
437
|
+
ariaLabel="Pause recording"
|
|
432
438
|
/>
|
|
433
439
|
{/if}
|
|
434
440
|
|
|
@@ -456,6 +462,7 @@
|
|
|
456
462
|
color="danger"
|
|
457
463
|
variant="ghost"
|
|
458
464
|
size="sm"
|
|
465
|
+
ariaLabel="Discard recording"
|
|
459
466
|
/>
|
|
460
467
|
<IconButton
|
|
461
468
|
onclick={stopRecording}
|
|
@@ -463,6 +470,7 @@
|
|
|
463
470
|
{color}
|
|
464
471
|
variant="ghost"
|
|
465
472
|
size="sm"
|
|
473
|
+
ariaLabel="Stop recording"
|
|
466
474
|
/>
|
|
467
475
|
</div>
|
|
468
476
|
{/if}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
isWide?: boolean;
|
|
21
21
|
isVertical?: boolean;
|
|
22
22
|
isDisabled?: boolean;
|
|
23
|
+
ariaLabel?: string;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
let {
|
|
@@ -33,7 +34,8 @@
|
|
|
33
34
|
class: className,
|
|
34
35
|
isWide,
|
|
35
36
|
isVertical,
|
|
36
|
-
isDisabled
|
|
37
|
+
isDisabled,
|
|
38
|
+
ariaLabel
|
|
37
39
|
}: Props = $props();
|
|
38
40
|
|
|
39
41
|
const colors = {
|
|
@@ -78,14 +80,15 @@
|
|
|
78
80
|
}
|
|
79
81
|
</script>
|
|
80
82
|
|
|
81
|
-
<div class={groupClasses} role="
|
|
83
|
+
<div class={groupClasses} role="radiogroup" aria-label={ariaLabel}>
|
|
82
84
|
{#each items as item}
|
|
83
85
|
<button
|
|
84
86
|
type="button"
|
|
85
87
|
class={cn('toggle-group-item', sizes[size], value === item.id && 'is-active')}
|
|
86
88
|
onclick={() => handleClick(item.id)}
|
|
87
89
|
disabled={isDisabled}
|
|
88
|
-
|
|
90
|
+
role="radio"
|
|
91
|
+
aria-checked={value === item.id}
|
|
89
92
|
>
|
|
90
93
|
{#if item.icon}
|
|
91
94
|
<Icon icon={item.icon} />
|
|
@@ -181,6 +181,7 @@
|
|
|
181
181
|
{color}
|
|
182
182
|
variant="overlay"
|
|
183
183
|
size="sm"
|
|
184
|
+
ariaLabel={videoParams.paused ? 'Play video' : 'Pause video'}
|
|
184
185
|
/>
|
|
185
186
|
|
|
186
187
|
<Chip variant="overlay" {color}>
|
|
@@ -217,6 +218,7 @@
|
|
|
217
218
|
{color}
|
|
218
219
|
variant="overlay"
|
|
219
220
|
size="sm"
|
|
221
|
+
ariaLabel={videoParams.muted ? 'Unmute video' : 'Mute video'}
|
|
220
222
|
/>
|
|
221
223
|
</div>
|
|
222
224
|
<IconButton
|
|
@@ -225,6 +227,7 @@
|
|
|
225
227
|
{color}
|
|
226
228
|
variant="overlay"
|
|
227
229
|
size="sm"
|
|
230
|
+
ariaLabel="Toggle picture-in-picture"
|
|
228
231
|
/>
|
|
229
232
|
<IconButton
|
|
230
233
|
onclick={handleToggleMaximize}
|
|
@@ -232,6 +235,7 @@
|
|
|
232
235
|
{color}
|
|
233
236
|
variant="overlay"
|
|
234
237
|
size="sm"
|
|
238
|
+
ariaLabel="Toggle fullscreen"
|
|
235
239
|
/>
|
|
236
240
|
</div>
|
|
237
241
|
</div>
|
package/dist/display/Icon.svelte
CHANGED
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
const { icon, class: className }: Props = $props();
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
|
-
<svg
|
|
18
|
+
<svg
|
|
19
|
+
viewBox={icon.viewbox}
|
|
20
|
+
class={cn('icon', className)}
|
|
21
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
22
|
+
aria-hidden="true"
|
|
23
|
+
>
|
|
19
24
|
{@html icon.body}
|
|
20
25
|
</svg>
|
package/dist/form/Select.svelte
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
import { cn } from '../utils/class-names.js';
|
|
5
5
|
import { onMount } from 'svelte';
|
|
6
6
|
|
|
7
|
+
const instanceId = Math.random().toString(36).substring(2, 9);
|
|
8
|
+
const listboxId = `select-listbox-${instanceId}`;
|
|
9
|
+
const labelId = `select-label-${instanceId}`;
|
|
10
|
+
const helpTextId = `select-help-${instanceId}`;
|
|
11
|
+
|
|
7
12
|
type Option = {
|
|
8
13
|
id: string | number;
|
|
9
14
|
label: string;
|
|
@@ -273,7 +278,7 @@
|
|
|
273
278
|
<input type="text" {name} bind:value hidden />
|
|
274
279
|
|
|
275
280
|
{#if !isFloatLabel && label}
|
|
276
|
-
<div class="field-label">{label}</div>
|
|
281
|
+
<div class="field-label" id={labelId}>{label}</div>
|
|
277
282
|
{/if}
|
|
278
283
|
|
|
279
284
|
<button
|
|
@@ -291,6 +296,16 @@
|
|
|
291
296
|
onclick={toggleDropdown}
|
|
292
297
|
onmouseenter={() => (isActive = true)}
|
|
293
298
|
onmouseleave={() => (isActive = false)}
|
|
299
|
+
role="combobox"
|
|
300
|
+
aria-haspopup="listbox"
|
|
301
|
+
aria-expanded={isOpen}
|
|
302
|
+
aria-controls={listboxId}
|
|
303
|
+
aria-activedescendant={isOpen && focusedIndex >= 0
|
|
304
|
+
? `${listboxId}-option-${focusedIndex}`
|
|
305
|
+
: undefined}
|
|
306
|
+
aria-labelledby={label ? labelId : undefined}
|
|
307
|
+
aria-label={!label ? placeholder : undefined}
|
|
308
|
+
aria-describedby={errorText || helpText ? helpTextId : undefined}
|
|
294
309
|
>
|
|
295
310
|
{#if isFloatLabel && label}
|
|
296
311
|
<span
|
|
@@ -325,13 +340,21 @@
|
|
|
325
340
|
</button>
|
|
326
341
|
|
|
327
342
|
{#if errorText || helpText}
|
|
328
|
-
<div class={cn('field-help', errorText && 'is-danger')}>
|
|
343
|
+
<div id={helpTextId} class={cn('field-help', errorText && 'is-danger')}>
|
|
344
|
+
{errorText || helpText}
|
|
345
|
+
</div>
|
|
329
346
|
{/if}
|
|
330
347
|
|
|
331
348
|
<div class:is-active={isOpen} class="select-popover" bind:this={contentEl} {style}>
|
|
332
|
-
<ul
|
|
349
|
+
<ul
|
|
350
|
+
class="select-options"
|
|
351
|
+
bind:this={optionsEl}
|
|
352
|
+
role="listbox"
|
|
353
|
+
id={listboxId}
|
|
354
|
+
aria-label={label}
|
|
355
|
+
>
|
|
333
356
|
{#each options as item, index}
|
|
334
|
-
<li>
|
|
357
|
+
<li id={`${listboxId}-option-${index}`} role="option" aria-selected={value === item.id}>
|
|
335
358
|
<Item
|
|
336
359
|
label={item.label}
|
|
337
360
|
src={item.src}
|
|
@@ -165,6 +165,8 @@
|
|
|
165
165
|
oninput={(e) => oninput?.((e.target as HTMLInputElement).value)}
|
|
166
166
|
onfocusin={() => (isFocused = true)}
|
|
167
167
|
onfocusout={() => (isFocused = false)}
|
|
168
|
+
aria-describedby={errorText || helpText ? `${uid}-help` : undefined}
|
|
169
|
+
aria-invalid={!!errorText}
|
|
168
170
|
/>
|
|
169
171
|
|
|
170
172
|
{#if endContent}
|
|
@@ -181,7 +183,7 @@
|
|
|
181
183
|
</label>
|
|
182
184
|
|
|
183
185
|
{#if errorText || helpText}
|
|
184
|
-
<div class={cn('field-help', errorText && 'is-danger')}>
|
|
186
|
+
<div id={`${uid}-help`} class={cn('field-help', errorText && 'is-danger')}>
|
|
185
187
|
{errorText || helpText}
|
|
186
188
|
</div>
|
|
187
189
|
{/if}
|
package/dist/form/Toggle.svelte
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
<svelte:head>
|
|
50
50
|
<meta
|
|
51
51
|
name="viewport"
|
|
52
|
-
content="width=device-width, initial-scale=1, maximum-scale=
|
|
52
|
+
content="width=device-width, initial-scale=1, maximum-scale=5, viewport-fit=cover, interactive-widget=resizes-content"
|
|
53
53
|
/>
|
|
54
54
|
<script>
|
|
55
55
|
let themeState = 'light';
|
|
@@ -254,6 +254,9 @@
|
|
|
254
254
|
)}
|
|
255
255
|
bind:this={triggerElements[index]}
|
|
256
256
|
onclick={() => handleItemClick(item, index)}
|
|
257
|
+
aria-haspopup={!!(item.subitems || item.megamenu)}
|
|
258
|
+
aria-expanded={openSubmenuIndex === index}
|
|
259
|
+
aria-controls={openSubmenuIndex === index ? `navmenu-popover-${index}` : undefined}
|
|
257
260
|
>
|
|
258
261
|
{#if item.icon}
|
|
259
262
|
<Icon icon={item.icon} class="navmenu-icon" />
|
|
@@ -273,6 +276,7 @@
|
|
|
273
276
|
{#if openSubmenuIndex !== null}
|
|
274
277
|
{@const currentItem = items[openSubmenuIndex]}
|
|
275
278
|
<div
|
|
279
|
+
id={`navmenu-popover-${openSubmenuIndex}`}
|
|
276
280
|
class={cn(
|
|
277
281
|
'navmenu-popover',
|
|
278
282
|
sizeClasses[size],
|
|
@@ -281,6 +285,7 @@
|
|
|
281
285
|
)}
|
|
282
286
|
bind:this={popoverElement}
|
|
283
287
|
{style}
|
|
288
|
+
role="menu"
|
|
284
289
|
>
|
|
285
290
|
{#if currentItem?.megamenu}
|
|
286
291
|
{@render currentItem.megamenu()}
|
|
@@ -295,6 +300,7 @@
|
|
|
295
300
|
openSubmenuIndex = null;
|
|
296
301
|
stopEventListeners();
|
|
297
302
|
}}
|
|
303
|
+
role="menuitem"
|
|
298
304
|
>
|
|
299
305
|
{#if subitem.icon}
|
|
300
306
|
<Icon icon={subitem.icon} class="navmenu-submenu-icon" />
|
|
@@ -311,6 +317,7 @@
|
|
|
311
317
|
type="button"
|
|
312
318
|
class="navmenu-submenu-item"
|
|
313
319
|
onclick={() => handleSubmenuItemClick(subitem)}
|
|
320
|
+
role="menuitem"
|
|
314
321
|
>
|
|
315
322
|
{#if subitem.icon}
|
|
316
323
|
<Icon icon={subitem.icon} class="navmenu-submenu-icon" />
|