@sentropic/design-system-svelte 0.22.0 → 0.22.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.svelte +106 -30
- package/dist/BarChart.svelte.d.ts +6 -3
- package/dist/BarChart.svelte.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/BarChart.svelte
CHANGED
|
@@ -33,9 +33,12 @@
|
|
|
33
33
|
*/
|
|
34
34
|
selectedKeys?: string[];
|
|
35
35
|
/**
|
|
36
|
-
* Called
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* Called with the bar's key (its `label`) when the user selects it. When
|
|
37
|
+
* provided, an ACCESSIBLE row of filter chips (real <button>s) is rendered
|
|
38
|
+
* OUTSIDE the aria-hidden SVG — that is the keyboard + screen-reader surface.
|
|
39
|
+
* The SVG bars themselves stay decorative (aria-hidden) and only offer a
|
|
40
|
+
* mouse click shortcut for sighted pointer users. When omitted the chart is
|
|
41
|
+
* purely presentational (no interactivity, unchanged).
|
|
39
42
|
*/
|
|
40
43
|
onSelect?: (key: string) => void;
|
|
41
44
|
class?: string;
|
|
@@ -96,14 +99,6 @@
|
|
|
96
99
|
const hasSelection = $derived(selectedSet.size > 0);
|
|
97
100
|
const interactive = $derived(typeof onSelect === "function");
|
|
98
101
|
|
|
99
|
-
function handleBarKeydown(key: string, e: KeyboardEvent) {
|
|
100
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
101
|
-
// preventDefault on Space so it activates rather than scrolling the page.
|
|
102
|
-
e.preventDefault();
|
|
103
|
-
onSelect?.(key);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
102
|
const scales = $derived.by(() => {
|
|
108
103
|
const values = data.map((d) => d.value);
|
|
109
104
|
const minRaw = Math.min(0, ...values);
|
|
@@ -301,12 +296,18 @@
|
|
|
301
296
|
{/each}
|
|
302
297
|
|
|
303
298
|
<!-- bars -->
|
|
304
|
-
<!--
|
|
305
|
-
|
|
306
|
-
|
|
299
|
+
<!-- The bars live inside an aria-hidden SVG, so they are NEVER an accessible
|
|
300
|
+
surface. When `onSelect` is provided they only carry a mouse click
|
|
301
|
+
shortcut (cursor:pointer) for sighted pointer users — keyboard + screen
|
|
302
|
+
readers use the filter-chip buttons rendered below, outside this SVG. -->
|
|
307
303
|
{#each bars as bar, i (bar.datum.label)}
|
|
308
304
|
{@const isSelected = selectedSet.has(bar.datum.label)}
|
|
309
|
-
<!--
|
|
305
|
+
<!-- The mouse click is a deliberate sighted-pointer-only shortcut on a
|
|
306
|
+
decorative element inside an aria-hidden SVG; the real keyboard + AT
|
|
307
|
+
path is the filter-chip <button>s below. No ARIA role/keyboard here
|
|
308
|
+
on purpose (it would be a lie under aria-hidden). -->
|
|
309
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
310
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
310
311
|
<rect
|
|
311
312
|
class="st-barChart__bar st-barChart__bar--{bar.tone}"
|
|
312
313
|
class:st-barChart__bar--selected={isSelected}
|
|
@@ -318,17 +319,32 @@
|
|
|
318
319
|
height={bar.height}
|
|
319
320
|
rx="2"
|
|
320
321
|
data-chart-index={i}
|
|
321
|
-
role={interactive ? "button" : undefined}
|
|
322
|
-
tabindex={interactive ? 0 : undefined}
|
|
323
|
-
aria-pressed={interactive ? isSelected : undefined}
|
|
324
|
-
aria-label={interactive ? `${bar.datum.label}: ${bar.datum.value}` : undefined}
|
|
325
322
|
onclick={interactive ? () => onSelect?.(bar.datum.label) : undefined}
|
|
326
|
-
onkeydown={interactive ? (e) => handleBarKeydown(bar.datum.label, e) : undefined}
|
|
327
323
|
/>
|
|
328
324
|
{/each}
|
|
329
325
|
</svg>
|
|
330
326
|
</div>
|
|
331
327
|
|
|
328
|
+
{#if interactive}
|
|
329
|
+
<!-- Accessible selection surface — real <button>s OUTSIDE the aria-hidden
|
|
330
|
+
SVG. This is the keyboard + screen-reader path for filtering. -->
|
|
331
|
+
<div class="st-barChart__filters" role="group" aria-label={`Filtrer par ${label}`}>
|
|
332
|
+
{#each bars as bar (bar.datum.label)}
|
|
333
|
+
{@const isSelected = selectedSet.has(bar.datum.label)}
|
|
334
|
+
<button
|
|
335
|
+
type="button"
|
|
336
|
+
class="st-barChart__filterChip st-barChart__filterChip--{bar.tone}"
|
|
337
|
+
class:st-barChart__filterChip--selected={isSelected}
|
|
338
|
+
aria-pressed={isSelected}
|
|
339
|
+
onclick={() => onSelect?.(bar.datum.label)}
|
|
340
|
+
>
|
|
341
|
+
<span class="st-barChart__filterSwatch" aria-hidden="true"></span>
|
|
342
|
+
{bar.datum.label}: {bar.datum.value}
|
|
343
|
+
</button>
|
|
344
|
+
{/each}
|
|
345
|
+
</div>
|
|
346
|
+
{/if}
|
|
347
|
+
|
|
332
348
|
<ChartDataList {label} items={dataValueItems} />
|
|
333
349
|
|
|
334
350
|
{#if hoveredIndex !== null && bars[hoveredIndex]}
|
|
@@ -389,19 +405,16 @@
|
|
|
389
405
|
opacity: 0.82;
|
|
390
406
|
}
|
|
391
407
|
|
|
392
|
-
/*
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/* Non-selected bars are dimmed while a selection is active. */
|
|
408
|
+
/* Non-selected bars are dimmed while a selection is active. Floor kept high
|
|
409
|
+
(0.6) so the colour stays distinguishable — opacity is never the sole cue;
|
|
410
|
+
selection also adds a stroke (shape), and the values stay in the chips +
|
|
411
|
+
ChartDataList. */
|
|
399
412
|
.st-barChart__bar--dim {
|
|
400
|
-
opacity: 0.
|
|
413
|
+
opacity: 0.6;
|
|
401
414
|
}
|
|
402
415
|
/* Hover still lifts a dimmed bar so it stays explorable. */
|
|
403
416
|
.st-barChart__bar--dim:hover {
|
|
404
|
-
opacity: 0.
|
|
417
|
+
opacity: 0.8;
|
|
405
418
|
}
|
|
406
419
|
|
|
407
420
|
/* Selected bar: full opacity + a contrast-safe accent stroke (two signals,
|
|
@@ -423,6 +436,68 @@
|
|
|
423
436
|
.st-barChart__bar--category7 { fill: var(--st-semantic-data-category7); }
|
|
424
437
|
.st-barChart__bar--category8 { fill: var(--st-semantic-data-category8); }
|
|
425
438
|
|
|
439
|
+
/* Accessible filter chips — keyboard + screen-reader selection surface,
|
|
440
|
+
rendered outside the aria-hidden SVG. */
|
|
441
|
+
.st-barChart__filters {
|
|
442
|
+
display: flex;
|
|
443
|
+
flex-wrap: wrap;
|
|
444
|
+
gap: var(--st-spacing-2, 0.5rem);
|
|
445
|
+
margin-top: var(--st-spacing-2, 0.5rem);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.st-barChart__filterChip {
|
|
449
|
+
align-items: center;
|
|
450
|
+
background: var(--st-semantic-surface-subtle, #f8fafc);
|
|
451
|
+
border: 1px solid var(--st-semantic-border-interactive, #cbd5e1);
|
|
452
|
+
border-radius: var(--st-radius-pill, 999px);
|
|
453
|
+
color: var(--st-semantic-text-secondary, #475569);
|
|
454
|
+
cursor: var(--st-cursor-interactive, pointer);
|
|
455
|
+
display: inline-flex;
|
|
456
|
+
font: inherit;
|
|
457
|
+
font-size: 0.8125rem;
|
|
458
|
+
font-weight: 500;
|
|
459
|
+
gap: var(--st-spacing-1, 0.25rem);
|
|
460
|
+
line-height: 1;
|
|
461
|
+
padding: 0.3125rem var(--st-spacing-2, 0.5rem);
|
|
462
|
+
transition:
|
|
463
|
+
background-color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease),
|
|
464
|
+
color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease),
|
|
465
|
+
border-color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
.st-barChart__filterChip:hover {
|
|
469
|
+
background: var(--st-semantic-surface-hover, #eef2f7);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.st-barChart__filterChip:focus-visible {
|
|
473
|
+
outline: 2px solid var(--st-semantic-border-interactive, var(--st-semantic-action-primary));
|
|
474
|
+
outline-offset: 2px;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/* Selected chip: solid accent fill + matching text — signalled by colour AND
|
|
478
|
+
by aria-pressed, never by opacity alone. */
|
|
479
|
+
.st-barChart__filterChip--selected {
|
|
480
|
+
background: var(--st-semantic-action-primary, #2563eb);
|
|
481
|
+
border-color: var(--st-semantic-action-primary, #2563eb);
|
|
482
|
+
color: var(--st-semantic-text-inverse, #fff);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/* Colour swatch echoing the bar tone, for quick visual mapping chip↔bar. */
|
|
486
|
+
.st-barChart__filterSwatch {
|
|
487
|
+
border-radius: var(--st-radius-sm, 0.25rem);
|
|
488
|
+
display: inline-block;
|
|
489
|
+
height: 0.625rem;
|
|
490
|
+
width: 0.625rem;
|
|
491
|
+
}
|
|
492
|
+
.st-barChart__filterChip--category1 .st-barChart__filterSwatch { background: var(--st-semantic-data-category1); }
|
|
493
|
+
.st-barChart__filterChip--category2 .st-barChart__filterSwatch { background: var(--st-semantic-data-category2); }
|
|
494
|
+
.st-barChart__filterChip--category3 .st-barChart__filterSwatch { background: var(--st-semantic-data-category3); }
|
|
495
|
+
.st-barChart__filterChip--category4 .st-barChart__filterSwatch { background: var(--st-semantic-data-category4); }
|
|
496
|
+
.st-barChart__filterChip--category5 .st-barChart__filterSwatch { background: var(--st-semantic-data-category5); }
|
|
497
|
+
.st-barChart__filterChip--category6 .st-barChart__filterSwatch { background: var(--st-semantic-data-category6); }
|
|
498
|
+
.st-barChart__filterChip--category7 .st-barChart__filterSwatch { background: var(--st-semantic-data-category7); }
|
|
499
|
+
.st-barChart__filterChip--category8 .st-barChart__filterSwatch { background: var(--st-semantic-data-category8); }
|
|
500
|
+
|
|
426
501
|
.st-barChart__tooltip {
|
|
427
502
|
background: var(--st-component-barChart-tooltipBackground, var(--st-semantic-surface-inverse));
|
|
428
503
|
border-radius: var(--st-radius-sm, 0.25rem);
|
|
@@ -449,6 +524,7 @@
|
|
|
449
524
|
}
|
|
450
525
|
|
|
451
526
|
@media (prefers-reduced-motion: reduce) {
|
|
452
|
-
.st-barChart__bar
|
|
527
|
+
.st-barChart__bar,
|
|
528
|
+
.st-barChart__filterChip { transition: none; }
|
|
453
529
|
}
|
|
454
530
|
</style>
|
|
@@ -18,9 +18,12 @@ type BarChartProps = {
|
|
|
18
18
|
*/
|
|
19
19
|
selectedKeys?: string[];
|
|
20
20
|
/**
|
|
21
|
-
* Called
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* Called with the bar's key (its `label`) when the user selects it. When
|
|
22
|
+
* provided, an ACCESSIBLE row of filter chips (real <button>s) is rendered
|
|
23
|
+
* OUTSIDE the aria-hidden SVG — that is the keyboard + screen-reader surface.
|
|
24
|
+
* The SVG bars themselves stay decorative (aria-hidden) and only offer a
|
|
25
|
+
* mouse click shortcut for sighted pointer users. When omitted the chart is
|
|
26
|
+
* purely presentational (no interactivity, unchanged).
|
|
24
27
|
*/
|
|
25
28
|
onSelect?: (key: string) => void;
|
|
26
29
|
class?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BarChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/BarChart.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,CAAC;AAEhB,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB,CAAC;AAMF,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB
|
|
1
|
+
{"version":3,"file":"BarChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/BarChart.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,CAAC;AAEhB,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB,CAAC;AAMF,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA+OJ,QAAA,MAAM,QAAQ,mDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|