@juspay/svelte-ui-components 2.61.0 → 2.62.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/BarChart/BarChart.svelte +2 -5
- package/dist/Button/Button.svelte +5 -2
- package/dist/Button/properties.d.ts +7 -0
- package/dist/Card/Card.svelte +1 -1
- package/dist/DateRangePicker/DateRangePicker.svelte +32 -8
- package/dist/Gauge/Gauge.svelte +2 -1
- package/dist/Gauge/properties.d.ts +9 -0
- package/dist/SankeyChart/SankeyChart.svelte +1 -1
- package/dist/Select/Select.svelte +1 -1
- package/dist/Stepper/Step.svelte +165 -16
- package/dist/Stepper/Stepper.svelte +115 -15
- package/dist/Stepper/properties.d.ts +45 -9
- package/dist/Table/Table.svelte +10 -1
- package/package.json +1 -1
|
@@ -413,10 +413,7 @@
|
|
|
413
413
|
return null;
|
|
414
414
|
}
|
|
415
415
|
const title = isMulti ? `${bar.dataPoint.label} — ${bar.seriesName}` : bar.dataPoint.label;
|
|
416
|
-
const displayValue =
|
|
417
|
-
isNormalized && bar.normalizedValue != null
|
|
418
|
-
? normalizedFormat(bar.normalizedValue)
|
|
419
|
-
: format(bar.dataPoint.value);
|
|
416
|
+
const displayValue = getDisplayValue(bar);
|
|
420
417
|
return {
|
|
421
418
|
title,
|
|
422
419
|
items: [{ label: bar.dataPoint.label, value: displayValue, color: bar.color }]
|
|
@@ -574,7 +571,7 @@
|
|
|
574
571
|
y2={isHoriz ? entry.bar.y : entry.bar.y + entry.bar.height}
|
|
575
572
|
gradientUnits="userSpaceOnUse"
|
|
576
573
|
>
|
|
577
|
-
{#each grad.stops as stop (stop.offset)}
|
|
574
|
+
{#each grad.stops as stop, stopIndex (`${stopIndex}-${stop.offset}`)}
|
|
578
575
|
<stop
|
|
579
576
|
offset="{stop.offset * 100}%"
|
|
580
577
|
stop-color={stop.color}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
ariaSelected,
|
|
16
16
|
role,
|
|
17
17
|
onclick,
|
|
18
|
-
onkeydown,
|
|
18
|
+
onkeydown = () => {},
|
|
19
19
|
onkeyup = () => {},
|
|
20
20
|
onmousedown,
|
|
21
21
|
onmouseup,
|
|
@@ -117,7 +117,10 @@
|
|
|
117
117
|
font-weight: var(--disabled-font-weight);
|
|
118
118
|
border: var(--disabled-border);
|
|
119
119
|
background: var(--disabled-background-color, var(--button-color, #3a4550));
|
|
120
|
-
box-shadow: var(
|
|
120
|
+
box-shadow: var(
|
|
121
|
+
--button-disabled-box-shadow,
|
|
122
|
+
var(--disabled-box-shadow, var(--button-box-shadow, none))
|
|
123
|
+
);
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
.button-loader {
|
|
@@ -20,11 +20,18 @@ export type OptionalButtonProperties = {
|
|
|
20
20
|
};
|
|
21
21
|
export type ButtonEventProperties = {
|
|
22
22
|
onclick?: (event: MouseEvent) => void;
|
|
23
|
+
/** Fires when a key is pressed down while the button has focus. */
|
|
23
24
|
onkeydown?: (event: KeyboardEvent) => void;
|
|
25
|
+
/** Fires when a key is released while the button has focus. */
|
|
24
26
|
onkeyup?: (event: KeyboardEvent) => void;
|
|
27
|
+
/** Fires when a mouse button is pressed down on the button. */
|
|
25
28
|
onmousedown?: (event: MouseEvent) => void;
|
|
29
|
+
/** Fires when a mouse button is released over the button. */
|
|
26
30
|
onmouseup?: (event: MouseEvent) => void;
|
|
31
|
+
/** Fires when the pointer leaves the button area. */
|
|
27
32
|
onmouseleave?: (event: MouseEvent) => void;
|
|
33
|
+
/** Fires when a touch point is placed on the button. */
|
|
28
34
|
ontouchstart?: (event: TouchEvent) => void;
|
|
35
|
+
/** Fires when a touch point is removed from the button. */
|
|
29
36
|
ontouchend?: (event: TouchEvent) => void;
|
|
30
37
|
};
|
package/dist/Card/Card.svelte
CHANGED
|
@@ -110,6 +110,32 @@
|
|
|
110
110
|
|
|
111
111
|
let activePresetLabel: string | null = $state(resolvedInitialPresetLabel);
|
|
112
112
|
|
|
113
|
+
// Seed draft from initialPresetLabel whenever presets become available so
|
|
114
|
+
// the calendar shows the preset's date selection when the picker is first
|
|
115
|
+
// opened — even if presets arrive asynchronously after initial render.
|
|
116
|
+
// The draftStart/draftEnd/draftValue guards prevent re-seeding once the
|
|
117
|
+
// user has made a custom selection.
|
|
118
|
+
$effect.pre(() => {
|
|
119
|
+
if (
|
|
120
|
+
resolvedInitialPresetLabel !== null &&
|
|
121
|
+
presets !== null &&
|
|
122
|
+
draftStart === null &&
|
|
123
|
+
draftEnd === null &&
|
|
124
|
+
draftValue === null
|
|
125
|
+
) {
|
|
126
|
+
const matchedPreset = presets.find((p) => p.label === resolvedInitialPresetLabel) ?? null;
|
|
127
|
+
if (matchedPreset !== null) {
|
|
128
|
+
const { start, end } = matchedPreset.getValue();
|
|
129
|
+
if (mode === 'single') {
|
|
130
|
+
draftValue = start;
|
|
131
|
+
} else {
|
|
132
|
+
draftStart = start;
|
|
133
|
+
draftEnd = end;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
113
139
|
const now = new SvelteDate();
|
|
114
140
|
|
|
115
141
|
// Dual-month navigation: track the year+month of the left calendar
|
|
@@ -160,11 +186,11 @@
|
|
|
160
186
|
|
|
161
187
|
function openPicker(): void {
|
|
162
188
|
// Seed draft from current committed values
|
|
163
|
-
draftStart = rangeStart
|
|
164
|
-
draftEnd = rangeEnd
|
|
165
|
-
draftValue = value
|
|
166
|
-
draftCompareStart = compareStart
|
|
167
|
-
draftCompareEnd = compareEnd
|
|
189
|
+
draftStart = rangeStart;
|
|
190
|
+
draftEnd = rangeEnd;
|
|
191
|
+
draftValue = value;
|
|
192
|
+
draftCompareStart = compareStart;
|
|
193
|
+
draftCompareEnd = compareEnd;
|
|
168
194
|
|
|
169
195
|
// Reset preset tracking so each picker session starts clean.
|
|
170
196
|
selectedPresetLabel = null;
|
|
@@ -499,9 +525,7 @@
|
|
|
499
525
|
{#each presets as preset, presetIndex (preset.label)}
|
|
500
526
|
{@const previousPreset = presetIndex > 0 ? presets[presetIndex - 1] : null}
|
|
501
527
|
{@const groupChanged =
|
|
502
|
-
presetIndex > 0 &&
|
|
503
|
-
'group' in preset &&
|
|
504
|
-
(previousPreset === null || previousPreset.group !== preset.group)}
|
|
528
|
+
presetIndex > 0 && (previousPreset?.group ?? '') !== (preset.group ?? '')}
|
|
505
529
|
{#if groupChanged}
|
|
506
530
|
<div class="drp-preset-divider" role="separator" aria-hidden="true">
|
|
507
531
|
{#if preset.group !== ''}
|
package/dist/Gauge/Gauge.svelte
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
max = 100,
|
|
7
7
|
showLabel = true,
|
|
8
8
|
labelFormatter,
|
|
9
|
+
ariaLabel,
|
|
9
10
|
testId,
|
|
10
11
|
classes
|
|
11
12
|
}: GaugeProperties = $props();
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
aria-valuenow={clamped}
|
|
34
35
|
aria-valuemin={0}
|
|
35
36
|
aria-valuemax={100}
|
|
36
|
-
aria-label=
|
|
37
|
+
aria-label={ariaLabel ?? labelText}
|
|
37
38
|
>
|
|
38
39
|
<svg viewBox="0 0 {VIEW_BOX} {VIEW_BOX}">
|
|
39
40
|
<circle class="track" cx={CENTER} cy={CENTER} r={RADIUS} fill="none" />
|
|
@@ -11,6 +11,7 @@ export type OptionalGaugeProperties = {
|
|
|
11
11
|
* @default 100
|
|
12
12
|
*/
|
|
13
13
|
max?: number;
|
|
14
|
+
/** Whether to show the centered percentage label. @default true */
|
|
14
15
|
showLabel?: boolean;
|
|
15
16
|
/**
|
|
16
17
|
* Custom label renderer called with the raw `(value, max)` pair. Return any
|
|
@@ -18,6 +19,14 @@ export type OptionalGaugeProperties = {
|
|
|
18
19
|
* Example: `labelFormatter={(v, m) => \`${v} / ${m}\`}` shows "50 / 200".
|
|
19
20
|
*/
|
|
20
21
|
labelFormatter?: (value: number, max: number) => string;
|
|
22
|
+
/**
|
|
23
|
+
* Accessible label for the gauge element (`role="progressbar"`). Falls back
|
|
24
|
+
* to the computed `labelText` (e.g. `"75%"`) when not provided, so assistive
|
|
25
|
+
* technology announces the current percentage by default.
|
|
26
|
+
*/
|
|
27
|
+
ariaLabel?: string;
|
|
28
|
+
/** Value for the `data-pw` attribute on the root element for E2E test selection. */
|
|
21
29
|
testId?: string;
|
|
30
|
+
/** Extra CSS classes applied to the root element for consumer theming. */
|
|
22
31
|
classes?: string;
|
|
23
32
|
};
|
|
@@ -272,7 +272,7 @@
|
|
|
272
272
|
<ChartContainer bind:width={chartWidth} bind:height={chartHeight} {aspectRatio}>
|
|
273
273
|
<g transform="translate({MARGIN}, {MARGIN})">
|
|
274
274
|
{#if columnLabels != null && columnLabels.length > 0}
|
|
275
|
-
{#each columnLabels as label, ci (ci)}
|
|
275
|
+
{#each columnLabels.slice(0, columnCount) as label, ci (ci)}
|
|
276
276
|
<text
|
|
277
277
|
class="sankey-col-label"
|
|
278
278
|
x={ci * colWidth + nodeWidth / 2}
|
|
@@ -364,7 +364,7 @@
|
|
|
364
364
|
id={`${listboxId}-option-${index}`}
|
|
365
365
|
aria-selected={value.includes(item.id)}
|
|
366
366
|
tabindex="-1"
|
|
367
|
-
{...item.testId
|
|
367
|
+
{...typeof item.testId === 'string'
|
|
368
368
|
? { 'data-pw': item.testId }
|
|
369
369
|
: typeof itemTestId === 'string'
|
|
370
370
|
? { 'data-pw': `${itemTestId}-${item.id}` }
|
package/dist/Stepper/Step.svelte
CHANGED
|
@@ -1,18 +1,77 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { StepProperties } from './properties';
|
|
3
3
|
|
|
4
|
-
let {
|
|
4
|
+
let {
|
|
5
|
+
stepIndex,
|
|
6
|
+
label,
|
|
7
|
+
icon,
|
|
8
|
+
status,
|
|
9
|
+
badge,
|
|
10
|
+
orientation = 'horizontal',
|
|
11
|
+
classes,
|
|
12
|
+
ariaLabel,
|
|
13
|
+
onclick,
|
|
14
|
+
onkeydown
|
|
15
|
+
}: StepProperties = $props();
|
|
5
16
|
|
|
6
|
-
|
|
17
|
+
const handleStepClick = (): void => {
|
|
7
18
|
onclick?.({ selectedIndex: stepIndex });
|
|
8
|
-
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const handleKeydown = (event: KeyboardEvent): void => {
|
|
22
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
23
|
+
event.preventDefault();
|
|
24
|
+
handleStepClick();
|
|
25
|
+
}
|
|
26
|
+
onkeydown?.(event);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
let isVertical = $derived(orientation === 'vertical');
|
|
30
|
+
|
|
31
|
+
let stepClass = $derived(
|
|
32
|
+
['step', isVertical ? 'step-vertical' : '', classes ?? ''].filter((c) => c.length > 0).join(' ')
|
|
33
|
+
);
|
|
9
34
|
</script>
|
|
10
35
|
|
|
11
|
-
<div
|
|
36
|
+
<div
|
|
37
|
+
class={stepClass}
|
|
38
|
+
onclick={handleStepClick}
|
|
39
|
+
onkeydown={handleKeydown}
|
|
40
|
+
role="button"
|
|
41
|
+
tabindex="0"
|
|
42
|
+
aria-label={ariaLabel ?? null}
|
|
43
|
+
aria-labelledby={ariaLabel ? null : `step-label-${stepIndex}`}
|
|
44
|
+
aria-current={status === 'active' ? 'step' : null}
|
|
45
|
+
>
|
|
12
46
|
{#if typeof icon === 'string' && icon.length > 0}
|
|
13
47
|
<div class="step-icon-container">
|
|
14
48
|
<img class="step-icon" src={icon} alt="" />
|
|
15
49
|
</div>
|
|
50
|
+
{:else if status === 'in-progress'}
|
|
51
|
+
<div class="step-index-container">
|
|
52
|
+
<svg
|
|
53
|
+
class="step-spinner"
|
|
54
|
+
viewBox="0 0 24 24"
|
|
55
|
+
fill="none"
|
|
56
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
57
|
+
aria-hidden="true"
|
|
58
|
+
>
|
|
59
|
+
<circle
|
|
60
|
+
cx="12"
|
|
61
|
+
cy="12"
|
|
62
|
+
r="9"
|
|
63
|
+
stroke="currentColor"
|
|
64
|
+
stroke-opacity="0.25"
|
|
65
|
+
stroke-width="3"
|
|
66
|
+
/>
|
|
67
|
+
<path
|
|
68
|
+
d="M12 3a9 9 0 0 1 9 9"
|
|
69
|
+
stroke="currentColor"
|
|
70
|
+
stroke-width="3"
|
|
71
|
+
stroke-linecap="round"
|
|
72
|
+
/>
|
|
73
|
+
</svg>
|
|
74
|
+
</div>
|
|
16
75
|
{:else}
|
|
17
76
|
<div class="step-index-container">
|
|
18
77
|
<div class="step-index-text">
|
|
@@ -20,9 +79,17 @@
|
|
|
20
79
|
</div>
|
|
21
80
|
</div>
|
|
22
81
|
{/if}
|
|
23
|
-
|
|
82
|
+
|
|
83
|
+
<div class="step-text" id="step-label-{stepIndex}">
|
|
24
84
|
{label}
|
|
25
85
|
</div>
|
|
86
|
+
|
|
87
|
+
{#if typeof badge === 'function'}
|
|
88
|
+
<div class="step-badge">
|
|
89
|
+
{@render badge()}
|
|
90
|
+
</div>
|
|
91
|
+
{/if}
|
|
92
|
+
|
|
26
93
|
<div class="separator"></div>
|
|
27
94
|
</div>
|
|
28
95
|
|
|
@@ -33,6 +100,11 @@
|
|
|
33
100
|
align-items: center;
|
|
34
101
|
}
|
|
35
102
|
|
|
103
|
+
.step-vertical {
|
|
104
|
+
--step-flex-direction: column;
|
|
105
|
+
align-items: flex-start;
|
|
106
|
+
}
|
|
107
|
+
|
|
36
108
|
.step-index-container {
|
|
37
109
|
display: flex;
|
|
38
110
|
justify-content: center;
|
|
@@ -41,33 +113,110 @@
|
|
|
41
113
|
width: var(--step-index-container-width, 30px);
|
|
42
114
|
border-radius: var(--step-index-container-radius, 50%);
|
|
43
115
|
background-color: var(--step-index-container-background-color, #798fa5cc);
|
|
116
|
+
color: var(--step-index-color, white);
|
|
117
|
+
flex-shrink: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.step-icon-container {
|
|
121
|
+
display: flex;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
align-items: center;
|
|
124
|
+
height: var(--step-index-container-height, 30px);
|
|
125
|
+
width: var(--step-index-container-width, 30px);
|
|
126
|
+
border-radius: var(--step-index-container-radius, 50%);
|
|
127
|
+
background-color: var(--step-index-container-background-color, #798fa5cc);
|
|
128
|
+
flex-shrink: 0;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.step-icon {
|
|
133
|
+
width: var(--step-icon-size, 18px);
|
|
134
|
+
height: var(--step-icon-size, 18px);
|
|
135
|
+
object-fit: contain;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.step-spinner {
|
|
139
|
+
width: var(--step-spinner-size, 18px);
|
|
140
|
+
height: var(--step-spinner-size, 18px);
|
|
141
|
+
animation: stepper-spin 0.8s linear infinite;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@keyframes stepper-spin {
|
|
145
|
+
from {
|
|
146
|
+
transform: rotate(0deg);
|
|
147
|
+
}
|
|
148
|
+
to {
|
|
149
|
+
transform: rotate(360deg);
|
|
150
|
+
}
|
|
44
151
|
}
|
|
45
152
|
|
|
46
153
|
.separator {
|
|
47
|
-
display: var(--separator-display, block);
|
|
48
|
-
height: var(--separator-height, 1px);
|
|
49
|
-
width: var(--separator-width, 50px);
|
|
50
|
-
margin: var(--separator-margin, 0px 12px 0px 12px);
|
|
154
|
+
display: var(--stepper-separator-display, var(--separator-display, block));
|
|
155
|
+
height: var(--stepper-separator-height, var(--separator-height, 1px));
|
|
156
|
+
width: var(--stepper-separator-width, var(--separator-width, 50px));
|
|
157
|
+
margin: var(--stepper-separator-margin, var(--separator-margin, 0px 12px 0px 12px));
|
|
51
158
|
background-image: var(
|
|
52
|
-
--separator-background-image,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
159
|
+
--stepper-separator-background-image,
|
|
160
|
+
var(
|
|
161
|
+
--separator-background-image,
|
|
162
|
+
repeating-linear-gradient(
|
|
163
|
+
to right,
|
|
164
|
+
var(
|
|
165
|
+
--stepper-separator-background-image-color,
|
|
166
|
+
var(--separator-background-image-color, #798fa5cc)
|
|
167
|
+
),
|
|
168
|
+
var(
|
|
169
|
+
--stepper-separator-background-image-color,
|
|
170
|
+
var(--separator-background-image-color, #798fa5cc)
|
|
171
|
+
)
|
|
172
|
+
6px,
|
|
173
|
+
transparent 6px,
|
|
174
|
+
transparent 10px
|
|
175
|
+
)
|
|
59
176
|
)
|
|
60
177
|
);
|
|
61
178
|
}
|
|
62
179
|
|
|
180
|
+
.step-vertical .separator {
|
|
181
|
+
height: var(--stepper-separator-vertical-height, 32px);
|
|
182
|
+
width: var(--stepper-separator-vertical-width, 1px);
|
|
183
|
+
margin: var(--stepper-separator-vertical-margin, 4px 0px 4px 14px);
|
|
184
|
+
background-image: repeating-linear-gradient(
|
|
185
|
+
to bottom,
|
|
186
|
+
var(
|
|
187
|
+
--stepper-separator-background-image-color,
|
|
188
|
+
var(--separator-background-image-color, #798fa5cc)
|
|
189
|
+
),
|
|
190
|
+
var(
|
|
191
|
+
--stepper-separator-background-image-color,
|
|
192
|
+
var(--separator-background-image-color, #798fa5cc)
|
|
193
|
+
)
|
|
194
|
+
6px,
|
|
195
|
+
transparent 6px,
|
|
196
|
+
transparent 10px
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
63
200
|
.step-text {
|
|
64
201
|
margin: var(--step-text-margin, 0px 0px 0px 12px);
|
|
65
202
|
font-size: var(--step-text-font-size, 12px);
|
|
66
203
|
color: var(--step-text-color, #798fa5cc);
|
|
67
204
|
}
|
|
68
205
|
|
|
206
|
+
.step-vertical .step-text {
|
|
207
|
+
margin: var(--step-text-vertical-margin, 4px 0px 0px 0px);
|
|
208
|
+
}
|
|
209
|
+
|
|
69
210
|
.step-index-text {
|
|
70
211
|
font-size: var(--step-index-font-size, 14px);
|
|
71
212
|
color: var(--step-index-color, white);
|
|
72
213
|
}
|
|
214
|
+
|
|
215
|
+
.step-badge {
|
|
216
|
+
margin: var(--step-badge-margin, 0 0 0 4px);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.step-vertical .step-badge {
|
|
220
|
+
margin: var(--step-badge-vertical-margin, 4px 0 0 0);
|
|
221
|
+
}
|
|
73
222
|
</style>
|
|
@@ -1,22 +1,57 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type { StepperProperties } from './properties';
|
|
2
|
+
import type { StepperProperties, StepStatus } from './properties';
|
|
3
3
|
import Step from './Step.svelte';
|
|
4
4
|
|
|
5
|
-
let {
|
|
5
|
+
let {
|
|
6
|
+
steps,
|
|
7
|
+
currentStepIndex,
|
|
8
|
+
orientation = 'horizontal',
|
|
9
|
+
classes,
|
|
10
|
+
testId,
|
|
11
|
+
onstepclick,
|
|
12
|
+
onhandleStepClick
|
|
13
|
+
}: StepperProperties = $props();
|
|
14
|
+
|
|
15
|
+
const resolveStatus = (stepIndex: number, explicitStatus: StepStatus | null): StepStatus => {
|
|
16
|
+
if (explicitStatus !== null) {
|
|
17
|
+
return explicitStatus;
|
|
18
|
+
}
|
|
19
|
+
if (stepIndex < currentStepIndex) {
|
|
20
|
+
return 'completed';
|
|
21
|
+
}
|
|
22
|
+
if (stepIndex === currentStepIndex) {
|
|
23
|
+
return 'active';
|
|
24
|
+
}
|
|
25
|
+
return 'pending';
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Support the deprecated onhandleStepClick alias — onstepclick takes priority.
|
|
29
|
+
const effectiveStepClick = $derived(onstepclick ?? onhandleStepClick);
|
|
30
|
+
|
|
31
|
+
let containerClass = $derived(
|
|
32
|
+
['container', orientation === 'vertical' ? 'container-vertical' : '', classes ?? '']
|
|
33
|
+
.filter((c) => c.length > 0)
|
|
34
|
+
.join(' ')
|
|
35
|
+
);
|
|
6
36
|
</script>
|
|
7
37
|
|
|
8
|
-
<div class=
|
|
38
|
+
<div class={containerClass} data-pw={typeof testId === 'string' ? testId : null} role="list">
|
|
9
39
|
{#each steps as currentStep, stepIndex (stepIndex)}
|
|
40
|
+
{@const effectiveStatus = resolveStatus(stepIndex, currentStep.status ?? null)}
|
|
10
41
|
<div
|
|
11
|
-
|
|
12
|
-
class
|
|
13
|
-
|
|
42
|
+
role="listitem"
|
|
43
|
+
class="step-container status-{effectiveStatus} {effectiveStatus === 'active'
|
|
44
|
+
? 'active-step'
|
|
45
|
+
: ''} {effectiveStatus === 'completed' ? 'completed-step' : ''}"
|
|
14
46
|
>
|
|
15
47
|
<Step
|
|
16
|
-
onclick={
|
|
48
|
+
onclick={effectiveStepClick}
|
|
17
49
|
label={currentStep.label}
|
|
18
50
|
icon={currentStep.icon}
|
|
19
51
|
stepIndex={stepIndex + 1}
|
|
52
|
+
status={effectiveStatus}
|
|
53
|
+
badge={currentStep.badge}
|
|
54
|
+
{orientation}
|
|
20
55
|
/>
|
|
21
56
|
</div>
|
|
22
57
|
{/each}
|
|
@@ -29,8 +64,13 @@
|
|
|
29
64
|
align-items: center;
|
|
30
65
|
}
|
|
31
66
|
|
|
67
|
+
.container-vertical {
|
|
68
|
+
--container-flex-direction: column;
|
|
69
|
+
align-items: flex-start;
|
|
70
|
+
}
|
|
71
|
+
|
|
32
72
|
.step-container:last-child {
|
|
33
|
-
--separator-display: none;
|
|
73
|
+
--stepper-separator-display: none;
|
|
34
74
|
}
|
|
35
75
|
|
|
36
76
|
.step-container {
|
|
@@ -38,21 +78,81 @@
|
|
|
38
78
|
align-items: center;
|
|
39
79
|
}
|
|
40
80
|
|
|
41
|
-
|
|
81
|
+
/* status-completed */
|
|
82
|
+
.status-completed {
|
|
83
|
+
--step-text-color: var(--step-text-completed-color, #24aa5a);
|
|
84
|
+
--stepper-separator-background-image-color: var(
|
|
85
|
+
--stepper-separator-background-image-completed-color,
|
|
86
|
+
#24aa5a
|
|
87
|
+
);
|
|
88
|
+
--step-index-container-background-color: var(
|
|
89
|
+
--step-index-container-completed-background-color,
|
|
90
|
+
#24aa5a
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* status-active */
|
|
95
|
+
.status-active {
|
|
42
96
|
--step-text-color: var(--step-text-active-color, #2f3841);
|
|
43
|
-
--separator-background-image-color: var(
|
|
97
|
+
--stepper-separator-background-image-color: var(
|
|
98
|
+
--stepper-separator-background-image-active-color,
|
|
99
|
+
#2f3841
|
|
100
|
+
);
|
|
44
101
|
--step-index-container-background-color: var(
|
|
45
102
|
--step-index-container-active-background-color,
|
|
46
103
|
#2f3841
|
|
47
104
|
);
|
|
48
105
|
}
|
|
49
106
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
107
|
+
/* status-pending: no override — falls through to #798fa5cc grey default in Step.svelte */
|
|
108
|
+
|
|
109
|
+
/* status-failure */
|
|
110
|
+
.status-failure {
|
|
111
|
+
--step-text-color: var(--step-text-failure-color, #e53935);
|
|
112
|
+
--stepper-separator-background-image-color: var(
|
|
113
|
+
--stepper-separator-background-image-failure-color,
|
|
114
|
+
#e53935
|
|
115
|
+
);
|
|
53
116
|
--step-index-container-background-color: var(
|
|
54
|
-
--step-index-container-
|
|
55
|
-
#
|
|
117
|
+
--step-index-container-failure-background-color,
|
|
118
|
+
var(--stepper-status-failure-color, #e53935)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* status-in-progress */
|
|
123
|
+
.status-in-progress {
|
|
124
|
+
--step-text-color: var(--step-text-in-progress-color, #f59e0b);
|
|
125
|
+
--stepper-separator-background-image-color: var(
|
|
126
|
+
--stepper-separator-background-image-in-progress-color,
|
|
127
|
+
#f59e0b
|
|
128
|
+
);
|
|
129
|
+
--step-index-container-background-color: var(
|
|
130
|
+
--step-index-container-in-progress-background-color,
|
|
131
|
+
var(--stepper-status-in-progress-color, #f59e0b)
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
:global([theme='dark']) .status-failure {
|
|
136
|
+
--step-text-color: var(--step-text-failure-color, #ef5350);
|
|
137
|
+
--stepper-separator-background-image-color: var(
|
|
138
|
+
--stepper-separator-background-image-failure-color,
|
|
139
|
+
#ef5350
|
|
140
|
+
);
|
|
141
|
+
--step-index-container-background-color: var(
|
|
142
|
+
--step-index-container-failure-background-color,
|
|
143
|
+
var(--stepper-status-failure-color, #ef5350)
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
:global([theme='dark']) .status-in-progress {
|
|
148
|
+
--step-text-color: var(--step-text-in-progress-color, #fbbf24);
|
|
149
|
+
--stepper-separator-background-image-color: var(
|
|
150
|
+
--stepper-separator-background-image-in-progress-color,
|
|
151
|
+
#fbbf24
|
|
152
|
+
);
|
|
153
|
+
--step-index-container-background-color: var(
|
|
154
|
+
--step-index-container-in-progress-background-color,
|
|
155
|
+
var(--stepper-status-in-progress-color, #fbbf24)
|
|
56
156
|
);
|
|
57
157
|
}
|
|
58
158
|
</style>
|
|
@@ -1,21 +1,44 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
export type StepStatus = 'completed' | 'active' | 'pending' | 'failure' | 'in-progress';
|
|
3
|
+
export type Step = {
|
|
4
|
+
label: string;
|
|
5
|
+
/**
|
|
6
|
+
* URL of a custom icon image. When provided, the icon takes precedence over
|
|
7
|
+
* any `status`-driven rendering (including the `in-progress` spinner).
|
|
8
|
+
*/
|
|
9
|
+
icon?: string;
|
|
10
|
+
status?: StepStatus;
|
|
11
|
+
/**
|
|
12
|
+
* Optional Svelte snippet rendered inline after the step label (to its right
|
|
13
|
+
* in horizontal layout, below it in vertical layout). Use it for badges,
|
|
14
|
+
* tags, or other inline metadata — e.g. a count pill, a status chip, or a
|
|
15
|
+
* "New" label.
|
|
16
|
+
*/
|
|
17
|
+
badge?: Snippet;
|
|
18
|
+
};
|
|
19
|
+
export type MandatoryStepperProperties = {
|
|
2
20
|
steps: Array<Step>;
|
|
3
21
|
currentStepIndex: number;
|
|
22
|
+
};
|
|
23
|
+
export type OptionalStepperProperties = {
|
|
24
|
+
orientation?: 'horizontal' | 'vertical';
|
|
4
25
|
classes?: string;
|
|
26
|
+
testId?: string;
|
|
27
|
+
};
|
|
28
|
+
export type StepperEventProperties = {
|
|
29
|
+
onstepclick?: (event: {
|
|
30
|
+
selectedIndex: number;
|
|
31
|
+
}) => void;
|
|
32
|
+
/** @deprecated Use `onstepclick` instead. */
|
|
5
33
|
onhandleStepClick?: (event: {
|
|
6
34
|
selectedIndex: number;
|
|
7
35
|
}) => void;
|
|
8
36
|
};
|
|
9
|
-
export type
|
|
10
|
-
label: string;
|
|
11
|
-
icon?: string;
|
|
12
|
-
};
|
|
13
|
-
export type StepProperties = OptionalStepProperties & StepEventProperties & {
|
|
14
|
-
stepIndex: number;
|
|
15
|
-
label: string;
|
|
16
|
-
};
|
|
37
|
+
export type StepperProperties = MandatoryStepperProperties & OptionalStepperProperties & StepperEventProperties;
|
|
17
38
|
export type OptionalStepProperties = {
|
|
18
39
|
icon?: string;
|
|
40
|
+
status?: StepStatus;
|
|
41
|
+
badge?: Snippet;
|
|
19
42
|
classes?: string;
|
|
20
43
|
};
|
|
21
44
|
export type StepEventProperties = {
|
|
@@ -24,3 +47,16 @@ export type StepEventProperties = {
|
|
|
24
47
|
}) => void;
|
|
25
48
|
onkeydown?: (event: KeyboardEvent) => void;
|
|
26
49
|
};
|
|
50
|
+
export type StepProperties = OptionalStepProperties & StepEventProperties & {
|
|
51
|
+
/** 1-based display index — Stepper passes `stepIndex + 1` so that clicking step 1 returns `selectedIndex: 1`. */
|
|
52
|
+
stepIndex: number;
|
|
53
|
+
label: string;
|
|
54
|
+
orientation?: 'horizontal' | 'vertical';
|
|
55
|
+
/**
|
|
56
|
+
* Accessible label for the step button. When provided, set as `aria-label` on
|
|
57
|
+
* the `role="button"` element, overriding the default `aria-labelledby` association
|
|
58
|
+
* with the visible label text. Use when the visible label alone is insufficient
|
|
59
|
+
* context for screen reader users (e.g. "Step 1 — Cart (completed)").
|
|
60
|
+
*/
|
|
61
|
+
ariaLabel?: string;
|
|
62
|
+
};
|
package/dist/Table/Table.svelte
CHANGED
|
@@ -189,10 +189,16 @@
|
|
|
189
189
|
* stable even when the visible set shrinks or expands as the search term
|
|
190
190
|
* changes — so a row that was "row 2" in the full set keeps ID `"2"` even
|
|
191
191
|
* when it becomes the only visible result.
|
|
192
|
+
*
|
|
193
|
+
* The Map lookup uses object reference equality, so row objects in
|
|
194
|
+
* `filteredTableData` must be the same references as those in
|
|
195
|
+
* `sortedTableData`. When `originalIndex` cannot be found (reference mismatch
|
|
196
|
+
* after a transform), the fallback positional index is used instead.
|
|
192
197
|
*/
|
|
193
198
|
let filteredRowIds = $derived.by((): string[] => {
|
|
199
|
+
const indexMap = new Map(sortedTableData.map((row, index) => [row, index]));
|
|
194
200
|
return filteredTableData.map((row, fallbackIndex) => {
|
|
195
|
-
const originalIndex =
|
|
201
|
+
const originalIndex = indexMap.get(row) ?? -1;
|
|
196
202
|
const stableIndex = originalIndex === -1 ? fallbackIndex : originalIndex;
|
|
197
203
|
if (checkboxSelection && checkboxSelection.enabled !== false) {
|
|
198
204
|
return resolveRowId(checkboxSelection, row, stableIndex);
|
|
@@ -314,6 +320,7 @@
|
|
|
314
320
|
oninput={handleSearchInput}
|
|
315
321
|
data-pw={searchConfig?.testId ?? null}
|
|
316
322
|
aria-label={searchConfig?.placeholder ?? 'Search'}
|
|
323
|
+
autocomplete="off"
|
|
317
324
|
/>
|
|
318
325
|
{#if searchTerm.length > 0}
|
|
319
326
|
<button
|
|
@@ -353,6 +360,7 @@
|
|
|
353
360
|
? 'mixed'
|
|
354
361
|
: headerCheckboxState === 'all'}
|
|
355
362
|
aria-label="Select all rows"
|
|
363
|
+
aria-controls={selectableRowIds.map((rowId) => `row-checkbox-${rowId}`).join(' ')}
|
|
356
364
|
onclick={toggleAllSelection}
|
|
357
365
|
onkeydown={(keyboardEvent) =>
|
|
358
366
|
handleCheckboxKeydown(keyboardEvent, toggleAllSelection)}
|
|
@@ -445,6 +453,7 @@
|
|
|
445
453
|
class:checked={rowSelected}
|
|
446
454
|
class:disabled={rowDisabled}
|
|
447
455
|
role="checkbox"
|
|
456
|
+
id={`row-checkbox-${rowId}`}
|
|
448
457
|
tabindex={rowDisabled ? -1 : 0}
|
|
449
458
|
aria-checked={rowSelected}
|
|
450
459
|
aria-disabled={rowDisabled}
|