@sentropic/design-system-svelte 0.16.0 → 0.18.0

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.
Files changed (41) hide show
  1. package/dist/Calendar.svelte +237 -42
  2. package/dist/Calendar.svelte.d.ts.map +1 -1
  3. package/dist/ComboChart.svelte +620 -0
  4. package/dist/ComboChart.svelte.d.ts +28 -0
  5. package/dist/ComboChart.svelte.d.ts.map +1 -0
  6. package/dist/FunnelChart.svelte +358 -0
  7. package/dist/FunnelChart.svelte.d.ts +21 -0
  8. package/dist/FunnelChart.svelte.d.ts.map +1 -0
  9. package/dist/GaugeChart.svelte +300 -0
  10. package/dist/GaugeChart.svelte.d.ts +36 -0
  11. package/dist/GaugeChart.svelte.d.ts.map +1 -0
  12. package/dist/KpiCard.svelte +318 -0
  13. package/dist/KpiCard.svelte.d.ts +36 -0
  14. package/dist/KpiCard.svelte.d.ts.map +1 -0
  15. package/dist/Popper.svelte +157 -0
  16. package/dist/Popper.svelte.d.ts +17 -0
  17. package/dist/Popper.svelte.d.ts.map +1 -1
  18. package/dist/Rating.svelte +130 -35
  19. package/dist/Rating.svelte.d.ts.map +1 -1
  20. package/dist/SelectableList.svelte +60 -12
  21. package/dist/SelectableList.svelte.d.ts.map +1 -1
  22. package/dist/SelectableRow.svelte +23 -8
  23. package/dist/SelectableRow.svelte.d.ts +5 -4
  24. package/dist/SelectableRow.svelte.d.ts.map +1 -1
  25. package/dist/SlideIndicator.svelte +17 -3
  26. package/dist/SlideIndicator.svelte.d.ts.map +1 -1
  27. package/dist/TimePicker.svelte +176 -13
  28. package/dist/TimePicker.svelte.d.ts.map +1 -1
  29. package/dist/TreemapChart.svelte +448 -0
  30. package/dist/TreemapChart.svelte.d.ts +26 -0
  31. package/dist/TreemapChart.svelte.d.ts.map +1 -0
  32. package/dist/WaterfallChart.svelte +469 -0
  33. package/dist/WaterfallChart.svelte.d.ts +19 -0
  34. package/dist/WaterfallChart.svelte.d.ts.map +1 -0
  35. package/dist/chartContrast.d.ts +6 -0
  36. package/dist/chartContrast.d.ts.map +1 -0
  37. package/dist/chartContrast.js +58 -0
  38. package/dist/index.d.ts +12 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +6 -0
  41. package/package.json +1 -1
@@ -87,24 +87,167 @@
87
87
 
88
88
  let open = $state(false);
89
89
  let hostEl = $state<HTMLDivElement | null>(null);
90
+ let inputEl = $state<HTMLInputElement | null>(null);
91
+ let listEl = $state<HTMLUListElement | null>(null);
92
+
93
+ /** Index de l'option mise en évidence dans la listbox (-1 = aucune). */
94
+ let activeIndex = $state(-1);
90
95
 
91
96
  const displayValue = $derived(value ? display(value) : "");
92
97
 
98
+ /** Id de l'option active, consommé par aria-activedescendant. */
99
+ const activeDescendant = $derived(
100
+ open && activeIndex >= 0 ? `${listId}-opt-${activeIndex}` : undefined
101
+ );
102
+
103
+ function openList() {
104
+ if (disabled) return;
105
+ open = true;
106
+ // À l'ouverture : se positionner sur la valeur sélectionnée ou la première option.
107
+ const idx = value ? slots.indexOf(value) : -1;
108
+ activeIndex = idx >= 0 ? idx : 0;
109
+ // Le focus reste sur l'input (pattern aria-activedescendant).
110
+ }
111
+
112
+ function closeList(returnFocus = true) {
113
+ open = false;
114
+ activeIndex = -1;
115
+ if (returnFocus && inputEl) {
116
+ inputEl.focus();
117
+ }
118
+ }
119
+
93
120
  function toggleOpen() {
94
121
  if (disabled) return;
95
- open = !open;
122
+ if (open) {
123
+ closeList(true);
124
+ } else {
125
+ openList();
126
+ }
96
127
  }
97
128
 
98
129
  function pick(slot: string) {
99
130
  value = slot;
100
131
  onChange?.(slot);
101
- open = false;
132
+ closeList(true);
102
133
  }
103
134
 
104
- function onPanelKeyDown(event: KeyboardEvent) {
105
- if (event.key === "Escape" && open) {
106
- event.preventDefault();
107
- open = false;
135
+ /** Fait défiler la listbox pour que l'option active soit visible. */
136
+ function scrollActiveIntoView() {
137
+ if (!listEl || activeIndex < 0) return;
138
+ const optEl = listEl.querySelector<HTMLElement>(`#${listId}-opt-${activeIndex}`);
139
+ if (optEl && typeof optEl.scrollIntoView === "function") {
140
+ optEl.scrollIntoView({ block: "nearest" });
141
+ }
142
+ }
143
+
144
+ function onInputKeyDown(event: KeyboardEvent) {
145
+ if (disabled) return;
146
+ switch (event.key) {
147
+ case "ArrowDown": {
148
+ event.preventDefault();
149
+ if (!open) {
150
+ openList();
151
+ } else {
152
+ // ArrowDown avec liste déjà ouverte → descendre d'une option.
153
+ activeIndex = Math.min(activeIndex + 1, slots.length - 1);
154
+ scrollActiveIntoView();
155
+ }
156
+ break;
157
+ }
158
+ case "ArrowUp": {
159
+ event.preventDefault();
160
+ if (!open) {
161
+ openList();
162
+ } else {
163
+ // ArrowUp avec liste déjà ouverte → remonter d'une option.
164
+ activeIndex = Math.max(activeIndex - 1, 0);
165
+ scrollActiveIntoView();
166
+ }
167
+ break;
168
+ }
169
+ case "Home": {
170
+ event.preventDefault();
171
+ if (!open) {
172
+ openList();
173
+ } else {
174
+ activeIndex = 0;
175
+ scrollActiveIntoView();
176
+ }
177
+ break;
178
+ }
179
+ case "End": {
180
+ event.preventDefault();
181
+ if (!open) {
182
+ openList();
183
+ } else {
184
+ activeIndex = slots.length - 1;
185
+ scrollActiveIntoView();
186
+ }
187
+ break;
188
+ }
189
+ case "Enter":
190
+ case " ": {
191
+ event.preventDefault();
192
+ if (!open) {
193
+ openList();
194
+ } else {
195
+ // Enter / Space sur l'input avec liste déjà ouverte → sélectionner l'actif.
196
+ if (activeIndex >= 0 && activeIndex < slots.length) {
197
+ pick(slots[activeIndex]);
198
+ }
199
+ }
200
+ break;
201
+ }
202
+ case "Escape": {
203
+ if (open) {
204
+ event.preventDefault();
205
+ closeList(true);
206
+ }
207
+ break;
208
+ }
209
+ }
210
+ }
211
+
212
+ function onListKeyDown(event: KeyboardEvent) {
213
+ switch (event.key) {
214
+ case "ArrowDown": {
215
+ event.preventDefault();
216
+ activeIndex = Math.min(activeIndex + 1, slots.length - 1);
217
+ scrollActiveIntoView();
218
+ break;
219
+ }
220
+ case "ArrowUp": {
221
+ event.preventDefault();
222
+ activeIndex = Math.max(activeIndex - 1, 0);
223
+ scrollActiveIntoView();
224
+ break;
225
+ }
226
+ case "Home": {
227
+ event.preventDefault();
228
+ activeIndex = 0;
229
+ scrollActiveIntoView();
230
+ break;
231
+ }
232
+ case "End": {
233
+ event.preventDefault();
234
+ activeIndex = slots.length - 1;
235
+ scrollActiveIntoView();
236
+ break;
237
+ }
238
+ case "Enter":
239
+ case " ": {
240
+ event.preventDefault();
241
+ if (activeIndex >= 0 && activeIndex < slots.length) {
242
+ pick(slots[activeIndex]);
243
+ }
244
+ break;
245
+ }
246
+ case "Escape": {
247
+ event.preventDefault();
248
+ closeList(true);
249
+ break;
250
+ }
108
251
  }
109
252
  }
110
253
 
@@ -112,7 +255,7 @@
112
255
  if (!open) return;
113
256
  const target = event.target as Node | null;
114
257
  if (hostEl && target && !hostEl.contains(target)) {
115
- open = false;
258
+ closeList(false);
116
259
  }
117
260
  }
118
261
 
@@ -129,6 +272,7 @@
129
272
  <span class={groupClasses}>
130
273
  <input
131
274
  id={fieldId}
275
+ bind:this={inputEl}
132
276
  type="text"
133
277
  readonly
134
278
  class="st-timepicker__control"
@@ -139,7 +283,10 @@
139
283
  aria-haspopup="listbox"
140
284
  aria-controls={listId}
141
285
  aria-expanded={open ? "true" : "false"}
286
+ aria-activedescendant={activeDescendant}
287
+ aria-autocomplete="none"
142
288
  onclick={toggleOpen}
289
+ onkeydown={onInputKeyDown}
143
290
  />
144
291
  <button
145
292
  type="button"
@@ -147,6 +294,7 @@
147
294
  aria-label="Ouvrir la liste des horaires"
148
295
  aria-haspopup="listbox"
149
296
  aria-expanded={open ? "true" : "false"}
297
+ tabindex="-1"
150
298
  {disabled}
151
299
  onclick={toggleOpen}
152
300
  >
@@ -157,24 +305,33 @@
157
305
  {#if open}
158
306
  <ul
159
307
  id={listId}
308
+ bind:this={listEl}
160
309
  class="st-timepicker__list"
161
310
  role="listbox"
162
311
  aria-label={label ?? "Horaires"}
163
312
  tabindex="-1"
164
- onkeydown={onPanelKeyDown}
313
+ onkeydown={onListKeyDown}
165
314
  >
166
- {#each slots as slot (slot)}
315
+ {#each slots as slot, i (slot)}
167
316
  <li role="presentation">
168
- <button
169
- type="button"
317
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
318
+ <!-- Faux positif : la navigation clavier est gérée par le combobox via
319
+ aria-activedescendant + onkeydown sur le listbox parent (onListKeyDown).
320
+ Les options n'ont pas besoin de leur propre gestionnaire keydown. -->
321
+ <div
322
+ id="{listId}-opt-{i}"
170
323
  class="st-timepicker__option"
171
324
  class:st-timepicker__option--selected={slot === value}
325
+ class:st-timepicker__option--active={i === activeIndex}
172
326
  role="option"
173
327
  aria-selected={slot === value ? "true" : "false"}
174
- onclick={() => pick(slot)}
328
+ tabindex="-1"
329
+ onmousedown={(e) => { e.preventDefault(); }}
330
+ onclick={() => { pick(slot); }}
331
+ onmouseenter={() => { activeIndex = i; }}
175
332
  >
176
333
  {display(slot)}
177
- </button>
334
+ </div>
178
335
  </li>
179
336
  {/each}
180
337
  </ul>
@@ -332,4 +489,10 @@
332
489
  background: var(--st-component-dropdown-selectedBackground, var(--st-semantic-action-primary));
333
490
  color: var(--st-component-dropdown-selectedText, var(--st-semantic-action-primaryText));
334
491
  }
492
+
493
+ .st-timepicker__option--active:not(.st-timepicker__option--selected) {
494
+ background: var(--st-component-control-hoverBackground, var(--st-semantic-surface-subtle));
495
+ outline: 2px solid var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
496
+ outline-offset: -2px;
497
+ }
335
498
  </style>
@@ -1 +1 @@
1
- {"version":3,"file":"TimePicker.svelte.d.ts","sourceRoot":"","sources":["../src/lib/TimePicker.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,CAAC;AAI7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG;IAClF,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAoIJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"TimePicker.svelte.d.ts","sourceRoot":"","sources":["../src/lib/TimePicker.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,CAAC;AAI7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG;IAClF,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAqRJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}