@juspay/svelte-ui-components 4.51.0 → 4.52.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/Animations/tokenizedFly.js +9 -2
- package/dist/AreaChart/AreaChart.svelte +41 -13
- package/dist/AreaChart/properties.d.ts +12 -0
- package/dist/AttachmentChipRow/AttachmentChipRow.svelte +7 -6
- package/dist/BarChart/BarChart.svelte +54 -6
- package/dist/BarChart/properties.d.ts +12 -0
- package/dist/Calendar/Calendar.svelte +124 -51
- package/dist/Card/Card.svelte +5 -0
- package/dist/ChatSuggestions/ChatSuggestions.svelte +1 -0
- package/dist/CheckListItem/CheckListItem.svelte +27 -5
- package/dist/ColorPicker/ColorPicker.svelte +40 -9
- package/dist/ColorPicker/properties.d.ts +8 -0
- package/dist/Combobox/Combobox.svelte +34 -2
- package/dist/CommandMenu/CommandMenu.svelte +35 -8
- package/dist/CommandMenu/properties.d.ts +6 -0
- package/dist/DateRangePicker/DateRangePicker.svelte +5 -5
- package/dist/DualAxisBarChart/DualAxisBarChart.svelte +41 -7
- package/dist/DualAxisBarChart/properties.d.ts +4 -0
- package/dist/FileDropzoneTrigger/FileDropzoneTrigger.svelte +104 -10
- package/dist/FileDropzoneTrigger/properties.d.ts +14 -4
- package/dist/FileInput/FileInput.svelte +38 -9
- package/dist/FileInput/context.d.ts +20 -0
- package/dist/FileInput/context.js +8 -0
- package/dist/FileInput/properties.d.ts +25 -1
- package/dist/FunnelChart/FunnelChart.svelte +20 -1
- package/dist/FunnelChart/properties.d.ts +4 -0
- package/dist/Gallery/Gallery.svelte +72 -27
- package/dist/HITL/HITL.svelte +64 -14
- package/dist/HITL/properties.d.ts +5 -0
- package/dist/LineChart/LineChart.svelte +105 -33
- package/dist/LineChart/properties.d.ts +12 -0
- package/dist/MediaPlayer/MediaPlayer.svelte +172 -2
- package/dist/MediaPlayer/MediaPlayer.svelte.d.ts +1 -1
- package/dist/MediaPlayer/properties.d.ts +31 -0
- package/dist/Menu/Menu.svelte +6 -4
- package/dist/Modal/Modal.svelte +15 -12
- package/dist/Modal/properties.d.ts +29 -1
- package/dist/Pagination/Pagination.svelte +1 -0
- package/dist/PieChart/PieChart.svelte +51 -29
- package/dist/PieChart/properties.d.ts +4 -0
- package/dist/Pill/Pill.svelte +5 -0
- package/dist/Radio/Radio.svelte +11 -2
- package/dist/Radio/properties.d.ts +7 -2
- package/dist/SankeyChart/SankeyChart.svelte +339 -211
- package/dist/SankeyChart/properties.d.ts +4 -0
- package/dist/Scroller/Scroller.svelte +236 -4
- package/dist/Scroller/properties.d.ts +8 -0
- package/dist/Select/Select.svelte +46 -8
- package/dist/Select/properties.d.ts +17 -1
- package/dist/Sheet/Sheet.svelte +31 -4
- package/dist/Sheet/properties.d.ts +6 -0
- package/dist/SplitInput/SplitInput.svelte +17 -0
- package/dist/SplitInput/field-name.d.ts +29 -0
- package/dist/SplitInput/field-name.js +50 -0
- package/dist/SplitInput/properties.d.ts +18 -4
- package/dist/Status/Status.svelte +24 -12
- package/dist/Status/properties.d.ts +11 -0
- package/dist/Table/BuiltinCell.svelte +13 -5
- package/dist/Table/BuiltinCell.svelte.d.ts +1 -0
- package/dist/Table/Table.svelte +78 -20
- package/dist/Table/a11y.d.ts +7 -0
- package/dist/Table/a11y.js +71 -0
- package/dist/Table/cellData.js +3 -0
- package/dist/Table/properties.d.ts +13 -5
- package/dist/ThemeSwitcher/ThemeSwitcher.svelte +4 -0
- package/dist/ThinkingIndicator/ThinkingIndicator.svelte +48 -9
- package/dist/Toast/Toast.svelte +70 -4
- package/dist/Toggle/Toggle.svelte +2 -0
- package/dist/Toggle/properties.d.ts +2 -0
- package/dist/_chart/Axis.svelte +10 -0
- package/dist/_chart/ChartContainer.svelte +32 -1
- package/dist/_chart/ChartTooltip.svelte +18 -3
- package/dist/_chart/LabelPlate.svelte +116 -0
- package/dist/_chart/LabelPlate.svelte.d.ts +7 -0
- package/dist/_chart/a11y.d.ts +29 -0
- package/dist/_chart/a11y.js +44 -0
- package/dist/_chart/measure.d.ts +2 -0
- package/dist/_chart/measure.js +4 -0
- package/dist/_chart/tooltipPosition.d.ts +6 -0
- package/dist/_chart/tooltipPosition.js +30 -2
- package/dist/_chart/types.d.ts +22 -0
- package/dist/_interaction/focusable.d.ts +47 -0
- package/dist/_interaction/focusable.js +139 -0
- package/dist/assets/captions-on.svg +3 -0
- package/dist/assets/captions.svg +5 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/styles/theme-dark.css +9 -1
- package/dist/types.d.ts +2 -0
- package/dist/utils.d.ts +18 -2
- package/dist/utils.js +73 -28
- package/dist-codemod/codemod/migrate-audit.js +9 -7
- package/dist-codemod/codemod/migration-assets/legacy-palette.css +9 -1
- package/dist-codemod/codemod/migration-assets-layout.js +61 -0
- package/dist-wc/index.js +5872 -4333
- package/package.json +4 -2
package/dist/Modal/Modal.svelte
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { onMount, onDestroy, tick } from 'svelte';
|
|
4
4
|
import ModalAnimation from '../Animations/ModalAnimation.svelte';
|
|
5
5
|
import OverlayAnimation from '../Animations/OverlayAnimation.svelte';
|
|
6
|
-
import { createDebouncer,
|
|
6
|
+
import { createDebouncer, acquireScrollLock, resolveScrollContainer } from '../utils';
|
|
7
7
|
import { focusEntryPoint, focusTrapTabTarget, getActiveElement } from '../_interaction/focus';
|
|
8
8
|
import { registerDismissible } from '../_interaction/dismissal';
|
|
9
9
|
import Button from '../Button/Button.svelte';
|
|
@@ -46,8 +46,10 @@
|
|
|
46
46
|
overlayFadeIn = false,
|
|
47
47
|
usePortal = false,
|
|
48
48
|
lockScroll = true,
|
|
49
|
+
scrollContainer,
|
|
49
50
|
autoDismissAfter = null,
|
|
50
51
|
ariaLabel,
|
|
52
|
+
ariaDescribedby,
|
|
51
53
|
role,
|
|
52
54
|
overlayAriaLabel
|
|
53
55
|
}: ModalProperties = $props();
|
|
@@ -64,10 +66,13 @@
|
|
|
64
66
|
|
|
65
67
|
let dismissTimer: ReturnType<typeof setTimeout> | null = null;
|
|
66
68
|
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
|
|
69
|
+
// One plain const, so the debouncer keeps its lastCallTime across re-renders and every
|
|
70
|
+
// dismissal path (overlay click, Escape, back-press) measures against the same history.
|
|
71
|
+
// $derived would rebuild it on every change and forget when it last fired. The delay is
|
|
72
|
+
// passed as a getter instead of the value: a value is captured when this line runs, so a
|
|
73
|
+
// `debounceTime` changed while the modal is open would never be seen. Reading the prop
|
|
74
|
+
// inside the closure picks up the current one on each dismissal.
|
|
75
|
+
const debounce = createDebouncer(() => debounceTime);
|
|
71
76
|
|
|
72
77
|
/**
|
|
73
78
|
* Where a portalled node is allowed to land. Svelte scopes a custom element's
|
|
@@ -233,7 +238,7 @@
|
|
|
233
238
|
// prop changed while the modal was open: turned off, the count never comes back
|
|
234
239
|
// down and the page stays frozen; turned on, this modal releases a hold another
|
|
235
240
|
// component is still relying on. Release exactly what was taken.
|
|
236
|
-
let
|
|
241
|
+
let releaseScrollLock: (() => void) | null = null;
|
|
237
242
|
|
|
238
243
|
// Set once in onMount, cleared once in onDestroy -- registerDismissible's
|
|
239
244
|
// own release function already tolerates a repeat call, but this still
|
|
@@ -249,8 +254,7 @@
|
|
|
249
254
|
onEscape: handleEscape
|
|
250
255
|
});
|
|
251
256
|
if (lockScroll) {
|
|
252
|
-
|
|
253
|
-
heldScrollLock = true;
|
|
257
|
+
releaseScrollLock = acquireScrollLock(resolveScrollContainer(modalContent, scrollContainer));
|
|
254
258
|
}
|
|
255
259
|
if (typeof autoDismissAfter === 'number') {
|
|
256
260
|
dismissTimer = setTimeout(() => onclose?.(), autoDismissAfter);
|
|
@@ -280,10 +284,8 @@
|
|
|
280
284
|
clearTimeout(dismissTimer);
|
|
281
285
|
}
|
|
282
286
|
if (typeof window !== 'undefined') {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
heldScrollLock = false;
|
|
286
|
-
}
|
|
287
|
+
releaseScrollLock?.();
|
|
288
|
+
releaseScrollLock = null;
|
|
287
289
|
if (supportHardwareBackPress) {
|
|
288
290
|
if (!backPressed) {
|
|
289
291
|
history.back();
|
|
@@ -328,6 +330,7 @@
|
|
|
328
330
|
role={role ?? null}
|
|
329
331
|
aria-modal={role != null ? 'true' : null}
|
|
330
332
|
aria-label={ariaLabel ?? null}
|
|
333
|
+
aria-describedby={ariaDescribedby ?? null}
|
|
331
334
|
tabindex="-1"
|
|
332
335
|
>
|
|
333
336
|
{#if (typeof header?.leftImage === 'string' && header.leftImage.length > 0) || (typeof header?.text === 'string' && header.text.length > 0) || (typeof header?.rightImage === 'string' && header.rightImage.length > 0)}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ScrollContainer } from '../types';
|
|
1
2
|
import type { ButtonProperties } from '../Button/properties';
|
|
2
3
|
import type { ModalTransition } from '../types';
|
|
3
4
|
import type { Snippet } from 'svelte';
|
|
@@ -19,6 +20,11 @@ export type ModalEntryAnimation = 'fade' | 'slide-up' | 'slide-down';
|
|
|
19
20
|
export type ModalRole = 'dialog' | 'alertdialog';
|
|
20
21
|
export type ModalProperties = OptionalModalProperties & ModalEventProperties;
|
|
21
22
|
export type OptionalModalProperties = {
|
|
23
|
+
/** Scroll owner, resolved once per open span. Omit for the overlay's ownerDocument.body.
|
|
24
|
+
* Supply the embedded scroll element or a getter; explicit null means no lock.
|
|
25
|
+
* Changing ownership while open takes effect on the next open, and teardown
|
|
26
|
+
* always releases the originally acquired container. */
|
|
27
|
+
scrollContainer?: ScrollContainer;
|
|
22
28
|
size?: ModalSize;
|
|
23
29
|
align?: ModalAlign;
|
|
24
30
|
showOverlay?: boolean;
|
|
@@ -40,6 +46,13 @@ export type OptionalModalProperties = {
|
|
|
40
46
|
primaryButton?: ButtonProperties;
|
|
41
47
|
secondaryButton?: ButtonProperties;
|
|
42
48
|
};
|
|
49
|
+
/**
|
|
50
|
+
* Milliseconds during which a repeat dismissal (overlay click, Escape, hardware
|
|
51
|
+
* back-press) is dropped after one has fired. One window is shared by all three
|
|
52
|
+
* paths. Read when each dismissal arrives, so a value changed while the modal
|
|
53
|
+
* is open applies to the next one, without forgetting when the last fired.
|
|
54
|
+
* Default: 700.
|
|
55
|
+
*/
|
|
43
56
|
debounceTime?: number;
|
|
44
57
|
leftImageTestId?: string;
|
|
45
58
|
/** Accessible name for the left header image's role="button" wrapper (e.g. a back control). Rendered as aria-label. */
|
|
@@ -63,7 +76,7 @@ export type OptionalModalProperties = {
|
|
|
63
76
|
overlayFadeIn?: boolean;
|
|
64
77
|
/** When true, mounts the overlay at document.body to escape clipping/stacking contexts. Default: false. */
|
|
65
78
|
usePortal?: boolean;
|
|
66
|
-
/** When true, locks
|
|
79
|
+
/** When true, locks the selected scrollContainer (default: ownerDocument.body) while the modal is mounted, restoring it on unmount. Default: true (matches prior unconditional behavior). Set false for a non-blocking modal that should allow background scroll. */
|
|
67
80
|
lockScroll?: boolean;
|
|
68
81
|
/** Milliseconds after mount to automatically fire onclose, e.g. for a transient success/confirmation modal. null (default) disables auto-dismiss. */
|
|
69
82
|
autoDismissAfter?: number | null;
|
|
@@ -75,6 +88,21 @@ export type OptionalModalProperties = {
|
|
|
75
88
|
* accessible name at all.
|
|
76
89
|
*/
|
|
77
90
|
ariaLabel?: string;
|
|
91
|
+
/**
|
|
92
|
+
* `id` of the element that describes the modal, rendered as `aria-describedby`
|
|
93
|
+
* on the modal content panel (the element carrying `role`/`aria-modal` when
|
|
94
|
+
* `role` is set). An `alertdialog`'s message belongs here: without it a screen
|
|
95
|
+
* reader announces the name and role but not what the dialog is asking.
|
|
96
|
+
* Default: unset -- no `aria-describedby` is rendered, so an existing consumer
|
|
97
|
+
* sees no DOM/ARIA change.
|
|
98
|
+
*
|
|
99
|
+
* The browser resolves the id inside the panel's own root, so the described
|
|
100
|
+
* element must live in the same tree as the panel. In the web-component build
|
|
101
|
+
* that means content supplied through the `content` snippet property, not
|
|
102
|
+
* light-DOM content passed through the default `<slot>`, which sits outside
|
|
103
|
+
* the shadow root and cannot be reached by id.
|
|
104
|
+
*/
|
|
105
|
+
ariaDescribedby?: string;
|
|
78
106
|
/**
|
|
79
107
|
* ARIA role for the modal content panel. Default: unset -- the panel
|
|
80
108
|
* renders no `role` and no `aria-modal` at all, byte-for-byte matching
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import { DEFAULT_CHART_MAX_HEIGHT } from '../_chart/types';
|
|
4
4
|
import type { PieChartProperties } from './properties';
|
|
5
5
|
import ChartContainer from '../_chart/ChartContainer.svelte';
|
|
6
|
+
import LabelPlate from '../_chart/LabelPlate.svelte';
|
|
7
|
+
import { defaultChartName, resolveChartName } from '../_chart/a11y';
|
|
6
8
|
import ChartTooltip from '../_chart/ChartTooltip.svelte';
|
|
7
9
|
import Legend from '../_chart/Legend.svelte';
|
|
8
10
|
import DeltaIndicator from '../DeltaIndicator/DeltaIndicator.svelte';
|
|
@@ -38,6 +40,8 @@
|
|
|
38
40
|
empty,
|
|
39
41
|
onsliceclick,
|
|
40
42
|
onslicehover,
|
|
43
|
+
ariaLabel,
|
|
44
|
+
ariaDescription,
|
|
41
45
|
testId,
|
|
42
46
|
classes,
|
|
43
47
|
tooltipPortal = false,
|
|
@@ -62,6 +66,7 @@
|
|
|
62
66
|
let chartHeight = $state(0);
|
|
63
67
|
let hoveredIndex = $state<number | null>(null);
|
|
64
68
|
let focusedIndex = $state<number | null>(null);
|
|
69
|
+
let focusedSlice = $state(false);
|
|
65
70
|
let programmaticIndex = $state<number | null>(null);
|
|
66
71
|
let mouseX = $state(0);
|
|
67
72
|
let mouseY = $state(0);
|
|
@@ -135,6 +140,13 @@
|
|
|
135
140
|
`${format(v)}\u00A0${pctFormat(v)}`
|
|
136
141
|
);
|
|
137
142
|
let isEmpty = $derived(data.length === 0 || total === 0);
|
|
143
|
+
let chartName = $derived(
|
|
144
|
+
resolveChartName(ariaLabel, defaultChartName('pie', { seriesNames: data.map((d) => d.label) }))
|
|
145
|
+
);
|
|
146
|
+
let hasMarks = $derived.by(() => !isEmpty && slices.length > 0);
|
|
147
|
+
// A center snippet can contain a real action even when the data is empty.
|
|
148
|
+
// Keep that child exposed; the empty slice geometry itself stays out of Tab.
|
|
149
|
+
let interactiveDrawing = $derived(hasMarks || typeof center === 'function');
|
|
138
150
|
|
|
139
151
|
// When semiCircle is true the effective aspect ratio is driven by:
|
|
140
152
|
// 1. The explicit `aspectRatio` prop (highest priority — always wins).
|
|
@@ -386,21 +398,20 @@
|
|
|
386
398
|
};
|
|
387
399
|
});
|
|
388
400
|
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
//
|
|
392
|
-
//
|
|
393
|
-
// activeIndex rather than hoveredIndex, it also announces the declarative
|
|
394
|
-
// highlightedIndex prop and the imperative ChartHighlightAPI, neither of
|
|
395
|
-
// which fires a focus event of its own.
|
|
401
|
+
// A focused slice is spoken once, by its complete name. The shared status
|
|
402
|
+
// region is not a point description: that gave every unfocused slice the
|
|
403
|
+
// last-announced slice's text, and echoed it on focus. Keep the live region
|
|
404
|
+
// for pointer/legend and programmatic highlights, which lack that name.
|
|
396
405
|
const statusId = `pie-status-${instanceId}`;
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
406
|
+
function sliceAriaLabel(index: number): string {
|
|
407
|
+
const slice = sliceAt(index);
|
|
408
|
+
return slice === null
|
|
409
|
+
? ''
|
|
410
|
+
: `${slice.label}: ${format(slice.value)} (${pctFormat(slice.value)})`;
|
|
411
|
+
}
|
|
412
|
+
let statusText = $derived(
|
|
413
|
+
activeIndex === null || focusedSlice ? '' : sliceAriaLabel(activeIndex)
|
|
414
|
+
);
|
|
404
415
|
|
|
405
416
|
// ── Interactions ───────────────────────────────────────────────
|
|
406
417
|
// Family-wide contract shared with BarChart/FunnelChart/DualAxisBarChart:
|
|
@@ -457,8 +468,9 @@
|
|
|
457
468
|
}
|
|
458
469
|
|
|
459
470
|
// Wired to focus on both slices and legend rows.
|
|
460
|
-
function handleFocus(i: number) {
|
|
471
|
+
function handleFocus(i: number, slice = false) {
|
|
461
472
|
focusedIndex = i;
|
|
473
|
+
focusedSlice = slice;
|
|
462
474
|
notifyHoverChange();
|
|
463
475
|
}
|
|
464
476
|
|
|
@@ -467,6 +479,7 @@
|
|
|
467
479
|
// hovered.
|
|
468
480
|
function handleBlur() {
|
|
469
481
|
focusedIndex = null;
|
|
482
|
+
focusedSlice = false;
|
|
470
483
|
notifyHoverChange();
|
|
471
484
|
}
|
|
472
485
|
|
|
@@ -539,6 +552,9 @@
|
|
|
539
552
|
aspectRatio={effectiveAspectRatio}
|
|
540
553
|
{maxHeight}
|
|
541
554
|
{minHeight}
|
|
555
|
+
ariaLabel={chartName}
|
|
556
|
+
{ariaDescription}
|
|
557
|
+
interactive={interactiveDrawing}
|
|
542
558
|
>
|
|
543
559
|
<g transform="translate({cx}, {cy})">
|
|
544
560
|
{#each slices as slice (slice.index)}
|
|
@@ -548,28 +564,18 @@
|
|
|
548
564
|
class:dimmed={activeIndex !== null && activeIndex !== slice.index}
|
|
549
565
|
d={slice.path}
|
|
550
566
|
fill={slice.color}
|
|
551
|
-
tabindex=
|
|
567
|
+
tabindex={hasMarks ? 0 : null}
|
|
552
568
|
role="button"
|
|
553
|
-
aria-
|
|
554
|
-
aria-
|
|
569
|
+
aria-hidden={hasMarks ? null : 'true'}
|
|
570
|
+
aria-label={sliceAriaLabel(slice.index)}
|
|
555
571
|
onmouseenter={(e) => handlePointerEnter(e, slice.index)}
|
|
556
572
|
onmousemove={trackMouse}
|
|
557
573
|
onmouseleave={handlePointerLeave}
|
|
558
|
-
onfocus={() => handleFocus(slice.index)}
|
|
574
|
+
onfocus={() => handleFocus(slice.index, true)}
|
|
559
575
|
onblur={handleBlur}
|
|
560
576
|
onkeydown={(e) => handleKeydown(e, slice.index)}
|
|
561
577
|
onclick={() => onsliceclick?.({ index: slice.index, slice: data[slice.index] })}
|
|
562
578
|
/>
|
|
563
|
-
{#if visibleSliceLabels.has(slice.index)}
|
|
564
|
-
<text
|
|
565
|
-
class="slice-label"
|
|
566
|
-
class:label-outside={labelPosition === 'outside'}
|
|
567
|
-
x={slice.labelX}
|
|
568
|
-
y={slice.labelY}
|
|
569
|
-
text-anchor="middle"
|
|
570
|
-
dominant-baseline="middle">{visibleSliceLabels.get(slice.index)}</text
|
|
571
|
-
>
|
|
572
|
-
{/if}
|
|
573
579
|
{/each}
|
|
574
580
|
|
|
575
581
|
{#if innerR > 0 && typeof center === 'function' && centerBoxSize > 0}
|
|
@@ -584,6 +590,22 @@
|
|
|
584
590
|
</div>
|
|
585
591
|
</foreignObject>
|
|
586
592
|
{/if}
|
|
593
|
+
<!-- Labels and their plates paint after every slice and center surface. -->
|
|
594
|
+
{#each slices as slice (slice.index)}
|
|
595
|
+
{#if visibleSliceLabels.has(slice.index)}
|
|
596
|
+
<LabelPlate>
|
|
597
|
+
<text
|
|
598
|
+
class="slice-label"
|
|
599
|
+
aria-hidden="true"
|
|
600
|
+
class:label-outside={labelPosition === 'outside'}
|
|
601
|
+
x={slice.labelX}
|
|
602
|
+
y={slice.labelY}
|
|
603
|
+
text-anchor="middle"
|
|
604
|
+
dominant-baseline="middle">{visibleSliceLabels.get(slice.index)}</text
|
|
605
|
+
>
|
|
606
|
+
</LabelPlate>
|
|
607
|
+
{/if}
|
|
608
|
+
{/each}
|
|
587
609
|
</g>
|
|
588
610
|
</ChartContainer>
|
|
589
611
|
|
|
@@ -40,6 +40,10 @@ export type OptionalPieChartProperties = {
|
|
|
40
40
|
tooltipPortal?: boolean;
|
|
41
41
|
center?: Snippet;
|
|
42
42
|
empty?: Snippet;
|
|
43
|
+
/** Accessible name of the drawing; omit to derive one from the plotted data. */
|
|
44
|
+
ariaLabel?: string;
|
|
45
|
+
/** Longer chart description, resolved inside the drawing's own DOM/shadow root. */
|
|
46
|
+
ariaDescription?: string;
|
|
43
47
|
testId?: string;
|
|
44
48
|
classes?: string;
|
|
45
49
|
semiCircle?: boolean;
|
package/dist/Pill/Pill.svelte
CHANGED
|
@@ -39,6 +39,11 @@
|
|
|
39
39
|
* once per mounted instance is what a consumer needs to act on, and it costs
|
|
40
40
|
* nothing on subsequent updates.
|
|
41
41
|
*/
|
|
42
|
+
// Reading `attrs` once is the point of this block: it is a dev notice about what the consumer
|
|
43
|
+
// passed at mount, not state. Rendering reads `attrs` live in the spread on the root element
|
|
44
|
+
// below, so an `attrs` that changes afterwards is still applied; only the notice is not
|
|
45
|
+
// repeated. The ignore is on this one block, whose only reference is that read.
|
|
46
|
+
// svelte-ignore state_referenced_locally
|
|
42
47
|
if (import.meta.env?.DEV === true) {
|
|
43
48
|
for (const message of discardedAttrWarnings('Pill', PILL_MANAGED_ATTRS, attrs)) {
|
|
44
49
|
console.warn(message);
|
package/dist/Radio/Radio.svelte
CHANGED
|
@@ -23,7 +23,16 @@
|
|
|
23
23
|
rejected. `describeField` composes the reference from the messages that are
|
|
24
24
|
actually rendered, so aria-describedby never points at an id that is not in
|
|
25
25
|
the DOM -- which passes an attribute assertion and resolves to nothing in a
|
|
26
|
-
real reader.
|
|
26
|
+
real reader.
|
|
27
|
+
|
|
28
|
+
`aria-invalid` is deliberately NOT put on the input. WAI-ARIA 1.2 supports it on
|
|
29
|
+
radiogroup (and checkbox, textbox, ...) but not on role="radio", where the
|
|
30
|
+
attribute is deprecated, so emitting it was an unsupported attribute that the
|
|
31
|
+
compiler flagged and some assistive technology ignores. The error is reachable
|
|
32
|
+
the way FileInput's is -- aria-describedby on the control plus role="alert" on
|
|
33
|
+
the message -- and the state is exposed as `data-invalid` for styling. A group
|
|
34
|
+
is invalid as a whole, so that state belongs on the consumer's
|
|
35
|
+
role="radiogroup" wrapper (see docs/Radio.md). */
|
|
27
36
|
const fieldUid = $props.id();
|
|
28
37
|
const field = $derived(
|
|
29
38
|
describeField(fieldUid, { error: errorMessage, info: infoMessage, invalid })
|
|
@@ -49,7 +58,6 @@
|
|
|
49
58
|
<input
|
|
50
59
|
type="radio"
|
|
51
60
|
aria-describedby={field.describedBy}
|
|
52
|
-
aria-invalid={field.ariaInvalid}
|
|
53
61
|
class="radio-input"
|
|
54
62
|
{name}
|
|
55
63
|
{value}
|
|
@@ -59,6 +67,7 @@
|
|
|
59
67
|
form={typeof form === 'string' ? form : null}
|
|
60
68
|
data-state={checked ? 'checked' : 'unchecked'}
|
|
61
69
|
data-disabled={disabled ? '' : null}
|
|
70
|
+
data-invalid={field.ariaInvalid === null ? null : ''}
|
|
62
71
|
onchange={handleChange}
|
|
63
72
|
/>
|
|
64
73
|
<span class="radio-indicator" class:checked class:disabled>
|
|
@@ -6,7 +6,10 @@ export type MandatoryRadioProperties = {
|
|
|
6
6
|
export type OptionalRadioProperties = {
|
|
7
7
|
/**
|
|
8
8
|
* Text shown, and announced, when the control is in error. Linked to the
|
|
9
|
-
* control through `aria-describedby
|
|
9
|
+
* control through `aria-describedby` and announced through `role="alert"`;
|
|
10
|
+
* the input carries `data-invalid` while present. It does not set
|
|
11
|
+
* `aria-invalid`, which WAI-ARIA 1.2 does not support on `role="radio"` --
|
|
12
|
+
* put that on the `role="radiogroup"` that wraps the group.
|
|
10
13
|
*/
|
|
11
14
|
errorMessage?: string | null;
|
|
12
15
|
/**
|
|
@@ -17,7 +20,9 @@ export type OptionalRadioProperties = {
|
|
|
17
20
|
infoMessage?: string | null;
|
|
18
21
|
/**
|
|
19
22
|
* Marks the control invalid without supplying a message, for a consumer
|
|
20
|
-
* driving validity from a server or its own rules.
|
|
23
|
+
* driving validity from a server or its own rules. Sets `data-invalid` on
|
|
24
|
+
* the input; the announced group state is the wrapping `role="radiogroup"`'s
|
|
25
|
+
* `aria-invalid`.
|
|
21
26
|
*/
|
|
22
27
|
invalid?: boolean;
|
|
23
28
|
selectedValue?: string;
|