@sentropic/design-system-svelte 0.33.0 → 0.34.20

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 (101) hide show
  1. package/dist/AppHeader.svelte +159 -1
  2. package/dist/AppHeader.svelte.d.ts +18 -1
  3. package/dist/AppHeader.svelte.d.ts.map +1 -1
  4. package/dist/ArcDiagramChart.svelte +380 -0
  5. package/dist/ArcDiagramChart.svelte.d.ts +43 -0
  6. package/dist/ArcDiagramChart.svelte.d.ts.map +1 -0
  7. package/dist/AreaRangeChart.svelte +487 -0
  8. package/dist/AreaRangeChart.svelte.d.ts +38 -0
  9. package/dist/AreaRangeChart.svelte.d.ts.map +1 -0
  10. package/dist/AreaSplineRangeChart.svelte +478 -0
  11. package/dist/AreaSplineRangeChart.svelte.d.ts +37 -0
  12. package/dist/AreaSplineRangeChart.svelte.d.ts.map +1 -0
  13. package/dist/BellCurveChart.svelte +487 -0
  14. package/dist/BellCurveChart.svelte.d.ts +40 -0
  15. package/dist/BellCurveChart.svelte.d.ts.map +1 -0
  16. package/dist/Calendar.svelte +11 -0
  17. package/dist/ChatThread.svelte +32 -1
  18. package/dist/ChatThread.svelte.d.ts +14 -0
  19. package/dist/ChatThread.svelte.d.ts.map +1 -1
  20. package/dist/ColumnPyramidChart.svelte +332 -0
  21. package/dist/ColumnPyramidChart.svelte.d.ts +35 -0
  22. package/dist/ColumnPyramidChart.svelte.d.ts.map +1 -0
  23. package/dist/ColumnRangeChart.svelte +432 -0
  24. package/dist/ColumnRangeChart.svelte.d.ts +42 -0
  25. package/dist/ColumnRangeChart.svelte.d.ts.map +1 -0
  26. package/dist/Combobox.svelte +3 -0
  27. package/dist/ContentSwitcher.svelte +1 -1
  28. package/dist/DataTable.svelte.d.ts +1 -1
  29. package/dist/DatePicker.svelte +3 -0
  30. package/dist/DependencyWheelChart.svelte +413 -0
  31. package/dist/DependencyWheelChart.svelte.d.ts +42 -0
  32. package/dist/DependencyWheelChart.svelte.d.ts.map +1 -0
  33. package/dist/DumbbellChart.svelte +403 -0
  34. package/dist/DumbbellChart.svelte.d.ts +44 -0
  35. package/dist/DumbbellChart.svelte.d.ts.map +1 -0
  36. package/dist/ErrorBarChart.svelte +428 -0
  37. package/dist/ErrorBarChart.svelte.d.ts +40 -0
  38. package/dist/ErrorBarChart.svelte.d.ts.map +1 -0
  39. package/dist/GanttChart.svelte +410 -0
  40. package/dist/GanttChart.svelte.d.ts +39 -0
  41. package/dist/GanttChart.svelte.d.ts.map +1 -0
  42. package/dist/HLCChart.svelte +330 -0
  43. package/dist/HLCChart.svelte.d.ts +32 -0
  44. package/dist/HLCChart.svelte.d.ts.map +1 -0
  45. package/dist/HeikinAshiChart.svelte +365 -0
  46. package/dist/HeikinAshiChart.svelte.d.ts +37 -0
  47. package/dist/HeikinAshiChart.svelte.d.ts.map +1 -0
  48. package/dist/HollowCandlestickChart.svelte +357 -0
  49. package/dist/HollowCandlestickChart.svelte.d.ts +34 -0
  50. package/dist/HollowCandlestickChart.svelte.d.ts.map +1 -0
  51. package/dist/Input.svelte +3 -0
  52. package/dist/ItemChart.svelte +389 -0
  53. package/dist/ItemChart.svelte.d.ts +67 -0
  54. package/dist/ItemChart.svelte.d.ts.map +1 -0
  55. package/dist/Link.svelte +12 -1
  56. package/dist/Link.svelte.d.ts +4 -0
  57. package/dist/Link.svelte.d.ts.map +1 -1
  58. package/dist/LollipopChart.svelte +1 -1
  59. package/dist/MultiSelect.svelte +3 -0
  60. package/dist/NumberInput.svelte +3 -0
  61. package/dist/OHLCChart.svelte +343 -0
  62. package/dist/OHLCChart.svelte.d.ts +33 -0
  63. package/dist/OHLCChart.svelte.d.ts.map +1 -0
  64. package/dist/OrganizationChart.svelte +284 -0
  65. package/dist/OrganizationChart.svelte.d.ts +19 -0
  66. package/dist/OrganizationChart.svelte.d.ts.map +1 -0
  67. package/dist/PasswordInput.svelte +3 -0
  68. package/dist/PolygonChart.svelte +189 -0
  69. package/dist/PolygonChart.svelte.d.ts +17 -0
  70. package/dist/PolygonChart.svelte.d.ts.map +1 -0
  71. package/dist/Search.svelte +7 -5
  72. package/dist/Select.svelte +3 -0
  73. package/dist/StreamgraphChart.svelte +283 -0
  74. package/dist/StreamgraphChart.svelte.d.ts +23 -0
  75. package/dist/StreamgraphChart.svelte.d.ts.map +1 -0
  76. package/dist/StreamingMessage.svelte +44 -2
  77. package/dist/StreamingMessage.svelte.d.ts +18 -1
  78. package/dist/StreamingMessage.svelte.d.ts.map +1 -1
  79. package/dist/TileMapChart.svelte +314 -0
  80. package/dist/TileMapChart.svelte.d.ts +45 -0
  81. package/dist/TileMapChart.svelte.d.ts.map +1 -0
  82. package/dist/TimePicker.svelte +3 -0
  83. package/dist/TimelineChart.svelte +362 -0
  84. package/dist/TimelineChart.svelte.d.ts +22 -0
  85. package/dist/TimelineChart.svelte.d.ts.map +1 -0
  86. package/dist/TreegraphChart.svelte +281 -0
  87. package/dist/TreegraphChart.svelte.d.ts +19 -0
  88. package/dist/TreegraphChart.svelte.d.ts.map +1 -0
  89. package/dist/VariablePieChart.svelte +313 -0
  90. package/dist/VariablePieChart.svelte.d.ts +52 -0
  91. package/dist/VariablePieChart.svelte.d.ts.map +1 -0
  92. package/dist/VennChart.svelte +348 -0
  93. package/dist/VennChart.svelte.d.ts +72 -0
  94. package/dist/VennChart.svelte.d.ts.map +1 -0
  95. package/dist/WordCloudChart.svelte +279 -0
  96. package/dist/WordCloudChart.svelte.d.ts +18 -0
  97. package/dist/WordCloudChart.svelte.d.ts.map +1 -0
  98. package/dist/index.d.ts +48 -0
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +24 -0
  101. package/package.json +5 -3
@@ -0,0 +1,487 @@
1
+ <script lang="ts" module>
2
+ /**
3
+ * BellCurveChart — chart STATISTIQUE. À partir d'un échantillon de nombres
4
+ * bruts (`number[]`), calcule la moyenne μ et l'écart-type d'échantillon σ
5
+ * (n-1), puis trace la densité de la loi normale
6
+ * pdf(x) = exp(-((x-μ)²/(2σ²))) / (σ·√(2π))
7
+ * sur l'intervalle μ-4σ → μ+4σ, sous forme d'aire lissée + ligne.
8
+ * Repères : ligne verticale à μ et marques à μ±σ, μ±2σ.
9
+ * API canonique (référence Svelte ; React/Vue s'alignent).
10
+ *
11
+ * Props obligatoires :
12
+ * data number[] - échantillon de valeurs brutes
13
+ * label string - aria-label du graphique
14
+ *
15
+ * Props optionnelles :
16
+ * tone "category1".."category8" (défaut "category1")
17
+ * width number (défaut 480)
18
+ * height number (défaut 240)
19
+ * smooth boolean (défaut true) - courbe lissée vs polyligne
20
+ * intervals number (défaut 64) - points d'échantillonnage de la courbe
21
+ * class string
22
+ *
23
+ * Si l'échantillon contient moins de 2 valeurs finies, ou si σ vaut 0
24
+ * (toutes les valeurs identiques), un état vide accessible est rendu sans
25
+ * planter (aucune courbe, message dans la liste accessible).
26
+ */
27
+ export type BellCurveChartTone =
28
+ | "category1"
29
+ | "category2"
30
+ | "category3"
31
+ | "category4"
32
+ | "category5"
33
+ | "category6"
34
+ | "category7"
35
+ | "category8";
36
+ </script>
37
+
38
+ <script lang="ts">
39
+ import ChartDataList from "./ChartDataList.svelte";
40
+
41
+ type BellCurveChartProps = {
42
+ data: number[];
43
+ width?: number;
44
+ height?: number;
45
+ tone?: BellCurveChartTone;
46
+ smooth?: boolean;
47
+ intervals?: number;
48
+ label: string;
49
+ class?: string;
50
+ };
51
+
52
+ let {
53
+ data = [],
54
+ width = 480,
55
+ height = 240,
56
+ tone = "category1",
57
+ smooth = true,
58
+ intervals = 64,
59
+ label,
60
+ class: className
61
+ }: BellCurveChartProps = $props();
62
+
63
+ const MARGIN = { top: 12, right: 16, bottom: 32, left: 44 };
64
+ const SQRT_2PI = Math.sqrt(2 * Math.PI);
65
+
66
+ function niceTicks(min: number, max: number, target = 5): number[] {
67
+ if (!Number.isFinite(min) || !Number.isFinite(max) || min === max) {
68
+ const base = Number.isFinite(max) ? max : 0;
69
+ return [base];
70
+ }
71
+ const range = max - min;
72
+ const rough = range / Math.max(target - 1, 1);
73
+ const pow = Math.pow(10, Math.floor(Math.log10(rough)));
74
+ const norm = rough / pow;
75
+ let step: number;
76
+ if (norm < 1.5) step = 1 * pow;
77
+ else if (norm < 3) step = 2 * pow;
78
+ else if (norm < 7) step = 5 * pow;
79
+ else step = 10 * pow;
80
+ const start = Math.floor(min / step) * step;
81
+ const end = Math.ceil(max / step) * step;
82
+ const ticks: number[] = [];
83
+ for (let v = start; v <= end + step / 2; v += step) {
84
+ ticks.push(Number(v.toFixed(10)));
85
+ }
86
+ return ticks;
87
+ }
88
+
89
+ function scaleLinear(v: number, d0: number, d1: number, r0: number, r1: number) {
90
+ if (d1 === d0) return r0;
91
+ return r0 + ((v - d0) * (r1 - r0)) / (d1 - d0);
92
+ }
93
+
94
+ function formatTick(v: number): string {
95
+ if (Math.abs(v) >= 1000) return `${(v / 1000).toFixed(v % 1000 === 0 ? 0 : 1)}k`;
96
+ if (Number.isInteger(v)) return String(v);
97
+ return v.toFixed(1);
98
+ }
99
+
100
+ function buildLinearPath(pts: { x: number; y: number }[]): string {
101
+ return pts.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(2)},${p.y.toFixed(2)}`).join(" ");
102
+ }
103
+
104
+ function buildSmoothPath(pts: { x: number; y: number }[]): string {
105
+ if (pts.length < 2) return buildLinearPath(pts);
106
+ const t = 0.18;
107
+ let d = `M${pts[0].x.toFixed(2)},${pts[0].y.toFixed(2)}`;
108
+ for (let i = 0; i < pts.length - 1; i++) {
109
+ const p0 = pts[i - 1] ?? pts[i];
110
+ const p1 = pts[i];
111
+ const p2 = pts[i + 1];
112
+ const p3 = pts[i + 2] ?? p2;
113
+ const c1x = p1.x + (p2.x - p0.x) * t;
114
+ const c1y = p1.y + (p2.y - p0.y) * t;
115
+ const c2x = p2.x - (p3.x - p1.x) * t;
116
+ const c2y = p2.y - (p3.y - p1.y) * t;
117
+ d += ` C${c1x.toFixed(2)},${c1y.toFixed(2)} ${c2x.toFixed(2)},${c2y.toFixed(2)} ${p2.x.toFixed(2)},${p2.y.toFixed(2)}`;
118
+ }
119
+ return d;
120
+ }
121
+
122
+ // Valeurs finies seulement.
123
+ const sample = $derived(data.filter((d) => Number.isFinite(d)));
124
+
125
+ // Statistiques : μ = moyenne, σ = écart-type d'échantillon (n-1).
126
+ const stats = $derived.by(() => {
127
+ const n = sample.length;
128
+ if (n < 2) return null;
129
+ const mean = sample.reduce((a, b) => a + b, 0) / n;
130
+ const variance = sample.reduce((a, b) => a + (b - mean) * (b - mean), 0) / (n - 1);
131
+ const sd = Math.sqrt(variance);
132
+ if (!(sd > 0) || !Number.isFinite(sd)) return null;
133
+ return { mean, sd, n };
134
+ });
135
+
136
+ function pdf(x: number, mean: number, sd: number): number {
137
+ const z = (x - mean) / sd;
138
+ return Math.exp(-(z * z) / 2) / (sd * SQRT_2PI);
139
+ }
140
+
141
+ const plotWidth = $derived(Math.max(width - MARGIN.left - MARGIN.right, 1));
142
+ const plotHeight = $derived(Math.max(height - MARGIN.top - MARGIN.bottom, 1));
143
+
144
+ const sampleCount = $derived(Math.max(8, Math.floor(intervals) || 64));
145
+
146
+ const xDomain = $derived.by(() => {
147
+ if (!stats) return { min: 0, max: 1 };
148
+ return { min: stats.mean - 4 * stats.sd, max: stats.mean + 4 * stats.sd };
149
+ });
150
+
151
+ // Densité maximale = pic en x=μ : pdf(μ) = 1/(σ·√(2π)).
152
+ const yMax = $derived(stats ? pdf(stats.mean, stats.mean, stats.sd) : 1);
153
+
154
+ const yDomain = $derived({ min: 0, max: yMax * 1.08 });
155
+
156
+ const xTicks = $derived.by(() => {
157
+ if (!stats) return [0];
158
+ return niceTicks(xDomain.min, xDomain.max, 5);
159
+ });
160
+
161
+ const curvePoints = $derived.by(() => {
162
+ if (!stats) return [];
163
+ const pts: { x: number; y: number; vx: number }[] = [];
164
+ for (let i = 0; i <= sampleCount; i++) {
165
+ const vx = xDomain.min + ((xDomain.max - xDomain.min) * i) / sampleCount;
166
+ const vy = pdf(vx, stats.mean, stats.sd);
167
+ pts.push({
168
+ x: MARGIN.left + scaleLinear(vx, xDomain.min, xDomain.max, 0, plotWidth),
169
+ y: MARGIN.top + scaleLinear(vy, yDomain.min, yDomain.max, plotHeight, 0),
170
+ vx
171
+ });
172
+ }
173
+ return pts;
174
+ });
175
+
176
+ const linePath = $derived(
177
+ curvePoints.length === 0 ? "" : smooth ? buildSmoothPath(curvePoints) : buildLinearPath(curvePoints)
178
+ );
179
+
180
+ const areaPath = $derived.by(() => {
181
+ if (curvePoints.length === 0) return "";
182
+ const base = MARGIN.top + plotHeight;
183
+ const first = curvePoints[0];
184
+ const last = curvePoints[curvePoints.length - 1];
185
+ return `${linePath} L${last.x.toFixed(2)},${base.toFixed(2)} L${first.x.toFixed(2)},${base.toFixed(2)} Z`;
186
+ });
187
+
188
+ const baseY = $derived(MARGIN.top + plotHeight);
189
+
190
+ // Repères verticaux : μ (mean) et μ±σ, μ±2σ (sd markers).
191
+ const meanMark = $derived.by(() => {
192
+ if (!stats) return null;
193
+ return {
194
+ x: MARGIN.left + scaleLinear(stats.mean, xDomain.min, xDomain.max, 0, plotWidth),
195
+ yTop: MARGIN.top + scaleLinear(yMax, yDomain.min, yDomain.max, plotHeight, 0)
196
+ };
197
+ });
198
+
199
+ const sdMarks = $derived.by(() => {
200
+ if (!stats) return [];
201
+ const offsets = [-2, -1, 1, 2];
202
+ return offsets.map((k) => {
203
+ const vx = stats.mean + k * stats.sd;
204
+ const vy = pdf(vx, stats.mean, stats.sd);
205
+ return {
206
+ k,
207
+ x: MARGIN.left + scaleLinear(vx, xDomain.min, xDomain.max, 0, plotWidth),
208
+ yTop: MARGIN.top + scaleLinear(vy, yDomain.min, yDomain.max, plotHeight, 0)
209
+ };
210
+ });
211
+ });
212
+
213
+ const gridLines = $derived(
214
+ xTicks.map((tick) => ({
215
+ value: tick,
216
+ x: MARGIN.left + scaleLinear(tick, xDomain.min, xDomain.max, 0, plotWidth)
217
+ }))
218
+ );
219
+
220
+ function roundStat(v: number): number {
221
+ return Math.round(v * 100) / 100;
222
+ }
223
+
224
+ const dataValueItems = $derived.by(() => {
225
+ if (!stats) {
226
+ return [
227
+ sample.length < 2
228
+ ? "Échantillon insuffisant (au moins 2 valeurs requises)"
229
+ : "Écart-type nul (valeurs identiques)"
230
+ ];
231
+ }
232
+ return [
233
+ `Moyenne (μ): ${roundStat(stats.mean)}`,
234
+ `Écart-type (σ): ${roundStat(stats.sd)}`,
235
+ `Taille de l'échantillon (n): ${stats.n}`
236
+ ];
237
+ });
238
+
239
+ const ariaLabel = $derived(
240
+ stats
241
+ ? `${label} — μ ${roundStat(stats.mean)}, σ ${roundStat(stats.sd)}, n ${stats.n}`
242
+ : label
243
+ );
244
+
245
+ let hoveredIndex: number | null = $state(null);
246
+
247
+ function handleLeave() {
248
+ hoveredIndex = null;
249
+ }
250
+ function handleVisualPointerMove(event: PointerEvent) {
251
+ const target = event.target;
252
+ if (!(target instanceof Element)) {
253
+ hoveredIndex = null;
254
+ return;
255
+ }
256
+ const index = Number(target.getAttribute("data-chart-index"));
257
+ hoveredIndex = Number.isInteger(index) ? index : null;
258
+ }
259
+
260
+ // Identifiant de dégradé unique pour éviter les conflits entre plusieurs charts.
261
+ const gradientId = $derived(`st-bellcurve-gradient-${Math.random().toString(36).substring(2, 9)}`);
262
+
263
+ const classes = () =>
264
+ ["st-bellCurveChart", `st-bellCurveChart--${tone}`, className].filter(Boolean).join(" ");
265
+ </script>
266
+
267
+ <div class={classes()}>
268
+ <div
269
+ class="st-bellCurveChart__visual"
270
+ role="img"
271
+ aria-label={ariaLabel}
272
+ onpointermove={handleVisualPointerMove}
273
+ onpointerleave={handleLeave}
274
+ >
275
+ <svg
276
+ viewBox="0 0 {width} {height}"
277
+ preserveAspectRatio="xMidYMid meet"
278
+ width="100%"
279
+ height="100%"
280
+ focusable="false"
281
+ aria-hidden="true"
282
+ >
283
+ <defs>
284
+ <linearGradient id={gradientId} x1="0" y1="0" x2="0" y2="1">
285
+ <stop offset="0%" stop-color="currentColor" stop-opacity="0.3" />
286
+ <stop offset="100%" stop-color="currentColor" stop-opacity="0.0" />
287
+ </linearGradient>
288
+ </defs>
289
+
290
+ <!-- gridlines + X axis ticks -->
291
+ {#each gridLines as g (g.value)}
292
+ <line
293
+ class="st-bellCurveChart__grid"
294
+ x1={g.x}
295
+ x2={g.x}
296
+ y1={MARGIN.top}
297
+ y2={baseY}
298
+ />
299
+ <text
300
+ class="st-bellCurveChart__tickLabel"
301
+ x={g.x}
302
+ y={baseY + 16}
303
+ text-anchor="middle"
304
+ >
305
+ {formatTick(g.value)}
306
+ </text>
307
+ {/each}
308
+
309
+ <!-- axes -->
310
+ <line class="st-bellCurveChart__axis" x1={MARGIN.left} x2={MARGIN.left} y1={MARGIN.top} y2={baseY} />
311
+ <line class="st-bellCurveChart__axis" x1={MARGIN.left} x2={width - MARGIN.right} y1={baseY} y2={baseY} />
312
+
313
+ {#if areaPath}
314
+ <path class="st-bellCurveChart__area" d={areaPath} fill="url(#{gradientId})" />
315
+ {/if}
316
+ {#if linePath}
317
+ <path
318
+ class="st-bellCurveChart__line"
319
+ d={linePath}
320
+ fill="none"
321
+ stroke-width="2"
322
+ stroke-linecap="round"
323
+ stroke-linejoin="round"
324
+ />
325
+ {/if}
326
+
327
+ <!-- σ marks at μ±σ, μ±2σ -->
328
+ {#each sdMarks as m (m.k)}
329
+ <line
330
+ class="st-bellCurveChart__sdMark"
331
+ x1={m.x}
332
+ x2={m.x}
333
+ y1={m.yTop}
334
+ y2={baseY}
335
+ />
336
+ {/each}
337
+
338
+ <!-- mean (μ) reference line -->
339
+ {#if meanMark}
340
+ <line
341
+ class="st-bellCurveChart__mean"
342
+ x1={meanMark.x}
343
+ x2={meanMark.x}
344
+ y1={meanMark.yTop}
345
+ y2={baseY}
346
+ />
347
+ <text
348
+ class="st-bellCurveChart__meanLabel"
349
+ x={meanMark.x}
350
+ y={MARGIN.top - 2}
351
+ text-anchor="middle"
352
+ >
353
+ μ
354
+ </text>
355
+ {/if}
356
+
357
+ <!-- hover hit-points along the curve -->
358
+ {#each curvePoints as p, i (i)}
359
+ <circle
360
+ class="st-bellCurveChart__hit"
361
+ cx={p.x}
362
+ cy={p.y}
363
+ r="6"
364
+ data-chart-index={i}
365
+ />
366
+ {/each}
367
+ </svg>
368
+ </div>
369
+
370
+ <ChartDataList label={ariaLabel} items={dataValueItems} />
371
+
372
+ {#if hoveredIndex !== null && curvePoints[hoveredIndex] && stats}
373
+ {@const p = curvePoints[hoveredIndex]}
374
+ <div
375
+ class="st-bellCurveChart__tooltip"
376
+ role="presentation"
377
+ style="left: {(p.x / width) * 100}%; top: {(p.y / height) * 100}%"
378
+ >
379
+ <span class="st-bellCurveChart__tooltipLabel">x ≈ {roundStat(p.vx)}</span>
380
+ <span class="st-bellCurveChart__tooltipValue">densité {p.y === baseY ? 0 : roundStat(pdf(p.vx, stats.mean, stats.sd))}</span>
381
+ </div>
382
+ {/if}
383
+ </div>
384
+
385
+ <style>
386
+ .st-bellCurveChart {
387
+ color: var(--st-semantic-data-category1);
388
+ display: block;
389
+ font-family: inherit;
390
+ position: relative;
391
+ width: 100%;
392
+ }
393
+
394
+ .st-bellCurveChart--category1 { color: var(--st-semantic-data-category1); }
395
+ .st-bellCurveChart--category2 { color: var(--st-semantic-data-category2); }
396
+ .st-bellCurveChart--category3 { color: var(--st-semantic-data-category3); }
397
+ .st-bellCurveChart--category4 { color: var(--st-semantic-data-category4); }
398
+ .st-bellCurveChart--category5 { color: var(--st-semantic-data-category5); }
399
+ .st-bellCurveChart--category6 { color: var(--st-semantic-data-category6); }
400
+ .st-bellCurveChart--category7 { color: var(--st-semantic-data-category7); }
401
+ .st-bellCurveChart--category8 { color: var(--st-semantic-data-category8); }
402
+
403
+ .st-bellCurveChart svg {
404
+ display: block;
405
+ overflow: visible;
406
+ }
407
+
408
+ .st-bellCurveChart__visual {
409
+ display: block;
410
+ position: relative;
411
+ }
412
+
413
+ .st-bellCurveChart__grid {
414
+ stroke: var(--st-component-bellCurveChart-gridStroke, var(--st-semantic-border-subtle));
415
+ stroke-dasharray: 2 3;
416
+ stroke-width: 1;
417
+ opacity: 0.7;
418
+ }
419
+
420
+ .st-bellCurveChart__axis {
421
+ stroke: var(--st-component-bellCurveChart-axisStroke, var(--st-semantic-border-subtle));
422
+ stroke-width: 1;
423
+ }
424
+
425
+ .st-bellCurveChart__tickLabel {
426
+ fill: var(--st-component-bellCurveChart-labelColor, var(--st-semantic-text-secondary));
427
+ font-size: 0.6875rem;
428
+ }
429
+
430
+ .st-bellCurveChart__line {
431
+ stroke: currentColor;
432
+ }
433
+
434
+ .st-bellCurveChart__area {
435
+ stroke: none;
436
+ }
437
+
438
+ .st-bellCurveChart__sdMark {
439
+ stroke: currentColor;
440
+ stroke-dasharray: 2 3;
441
+ stroke-width: 1;
442
+ opacity: 0.5;
443
+ }
444
+
445
+ .st-bellCurveChart__mean {
446
+ stroke: currentColor;
447
+ stroke-dasharray: 4 3;
448
+ stroke-width: 1.5;
449
+ opacity: 0.85;
450
+ }
451
+
452
+ .st-bellCurveChart__meanLabel {
453
+ fill: currentColor;
454
+ font-size: 0.6875rem;
455
+ font-weight: 600;
456
+ }
457
+
458
+ .st-bellCurveChart__hit {
459
+ fill: transparent;
460
+ cursor: pointer;
461
+ }
462
+
463
+ .st-bellCurveChart__tooltip {
464
+ background: var(--st-component-bellCurveChart-tooltipBackground, var(--st-semantic-surface-inverse));
465
+ border-radius: var(--st-radius-sm, 0.25rem);
466
+ color: var(--st-component-bellCurveChart-tooltipText, var(--st-semantic-text-inverse));
467
+ display: inline-flex;
468
+ flex-direction: column;
469
+ font-size: 0.75rem;
470
+ gap: 0.125rem;
471
+ line-height: 1.2;
472
+ padding: 0.375rem 0.5rem;
473
+ pointer-events: none;
474
+ position: absolute;
475
+ transform: translate(-50%, calc(-100% - 8px));
476
+ white-space: nowrap;
477
+ z-index: 1;
478
+ }
479
+
480
+ .st-bellCurveChart__tooltipLabel {
481
+ font-weight: 600;
482
+ }
483
+
484
+ .st-bellCurveChart__tooltipValue {
485
+ opacity: 0.85;
486
+ }
487
+ </style>
@@ -0,0 +1,40 @@
1
+ /**
2
+ * BellCurveChart — chart STATISTIQUE. À partir d'un échantillon de nombres
3
+ * bruts (`number[]`), calcule la moyenne μ et l'écart-type d'échantillon σ
4
+ * (n-1), puis trace la densité de la loi normale
5
+ * pdf(x) = exp(-((x-μ)²/(2σ²))) / (σ·√(2π))
6
+ * sur l'intervalle μ-4σ → μ+4σ, sous forme d'aire lissée + ligne.
7
+ * Repères : ligne verticale à μ et marques à μ±σ, μ±2σ.
8
+ * API canonique (référence Svelte ; React/Vue s'alignent).
9
+ *
10
+ * Props obligatoires :
11
+ * data number[] - échantillon de valeurs brutes
12
+ * label string - aria-label du graphique
13
+ *
14
+ * Props optionnelles :
15
+ * tone "category1".."category8" (défaut "category1")
16
+ * width number (défaut 480)
17
+ * height number (défaut 240)
18
+ * smooth boolean (défaut true) - courbe lissée vs polyligne
19
+ * intervals number (défaut 64) - points d'échantillonnage de la courbe
20
+ * class string
21
+ *
22
+ * Si l'échantillon contient moins de 2 valeurs finies, ou si σ vaut 0
23
+ * (toutes les valeurs identiques), un état vide accessible est rendu sans
24
+ * planter (aucune courbe, message dans la liste accessible).
25
+ */
26
+ export type BellCurveChartTone = "category1" | "category2" | "category3" | "category4" | "category5" | "category6" | "category7" | "category8";
27
+ type BellCurveChartProps = {
28
+ data: number[];
29
+ width?: number;
30
+ height?: number;
31
+ tone?: BellCurveChartTone;
32
+ smooth?: boolean;
33
+ intervals?: number;
34
+ label: string;
35
+ class?: string;
36
+ };
37
+ declare const BellCurveChart: import("svelte").Component<BellCurveChartProps, {}, "">;
38
+ type BellCurveChart = ReturnType<typeof BellCurveChart>;
39
+ export default BellCurveChart;
40
+ //# sourceMappingURL=BellCurveChart.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BellCurveChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/BellCurveChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,CAAC;AAMhB,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA8RJ,QAAA,MAAM,cAAc,yDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -593,6 +593,17 @@
593
593
  color: var(--st-component-dropdown-selectedText, var(--st-semantic-action-primaryText));
594
594
  }
595
595
 
596
+ /* Jour sélectionné survolé : garder un fond FONCÉ (sinon le :hover générique
597
+ met surface-subtle clair sous le texte blanc -> texte invisible). Spécificité
598
+ (0,4,0) > le :hover générique (0,3,0). Bug récurrent de contraste hover. */
599
+ .st-calendar__day--selected:hover:not(:disabled) {
600
+ background: var(
601
+ --st-semantic-action-primaryHover,
602
+ var(--st-component-dropdown-selectedBackground, var(--st-semantic-action-primary))
603
+ );
604
+ color: var(--st-component-dropdown-selectedText, var(--st-semantic-action-primaryText));
605
+ }
606
+
596
607
  .st-calendar__day:disabled {
597
608
  color: var(--st-semantic-text-muted);
598
609
  cursor: not-allowed;
@@ -1,10 +1,28 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
3
  import type { HTMLAttributes } from "svelte/elements";
4
+ import ChatMessage, {
5
+ type ChatMessageRole,
6
+ type ChatMessageStatus
7
+ } from "./ChatMessage.svelte";
8
+
9
+ export type ChatThreadMessage = {
10
+ id: string;
11
+ role?: ChatMessageRole;
12
+ content: string;
13
+ status?: ChatMessageStatus;
14
+ };
4
15
 
5
16
  type ChatThreadProps = Omit<HTMLAttributes<HTMLElement>, "class" | "aria-label"> & {
6
17
  label: string;
7
18
  autoScroll?: boolean;
19
+ /**
20
+ * Data-driven messages (cross-framework parity with React/Vue). When
21
+ * provided, each entry is rendered internally as a `ChatMessage`. The
22
+ * canonical `children` slot still works; `messages` takes precedence when
23
+ * both are supplied.
24
+ */
25
+ messages?: ChatThreadMessage[];
8
26
  class?: string;
9
27
  children?: Snippet;
10
28
  emptyState?: Snippet;
@@ -13,12 +31,15 @@
13
31
  let {
14
32
  label,
15
33
  autoScroll = true,
34
+ messages,
16
35
  class: className,
17
36
  children,
18
37
  emptyState,
19
38
  ...rest
20
39
  }: ChatThreadProps = $props();
21
40
 
41
+ const hasMessages = () => Array.isArray(messages) && messages.length > 0;
42
+
22
43
  let scrollEl: HTMLElement | undefined = $state();
23
44
  let listEl: HTMLElement | undefined = $state();
24
45
  let hasChildren = $state(true);
@@ -70,7 +91,17 @@
70
91
  aria-relevant="additions text"
71
92
  >
72
93
  <div bind:this={listEl} class="st-chatThread__list">
73
- {@render children?.()}
94
+ {#if hasMessages()}
95
+ {#each messages! as message (message.id)}
96
+ <ChatMessage
97
+ role={message.role ?? "assistant"}
98
+ status={message.status}
99
+ content={message.content}
100
+ />
101
+ {/each}
102
+ {:else}
103
+ {@render children?.()}
104
+ {/if}
74
105
  </div>
75
106
  {#if emptyState && !hasChildren}
76
107
  <div class="st-chatThread__empty">
@@ -1,8 +1,22 @@
1
1
  import type { Snippet } from "svelte";
2
2
  import type { HTMLAttributes } from "svelte/elements";
3
+ import { type ChatMessageRole, type ChatMessageStatus } from "./ChatMessage.svelte";
4
+ export type ChatThreadMessage = {
5
+ id: string;
6
+ role?: ChatMessageRole;
7
+ content: string;
8
+ status?: ChatMessageStatus;
9
+ };
3
10
  type ChatThreadProps = Omit<HTMLAttributes<HTMLElement>, "class" | "aria-label"> & {
4
11
  label: string;
5
12
  autoScroll?: boolean;
13
+ /**
14
+ * Data-driven messages (cross-framework parity with React/Vue). When
15
+ * provided, each entry is rendered internally as a `ChatMessage`. The
16
+ * canonical `children` slot still works; `messages` takes precedence when
17
+ * both are supplied.
18
+ */
19
+ messages?: ChatThreadMessage[];
6
20
  class?: string;
7
21
  children?: Snippet;
8
22
  emptyState?: Snippet;
@@ -1 +1 @@
1
- {"version":3,"file":"ChatThread.svelte.d.ts","sourceRoot":"","sources":["../src/lib/ChatThread.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC,GAAG;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAuEJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ChatThread.svelte.d.ts","sourceRoot":"","sources":["../src/lib/ChatThread.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAoB,EAChB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAG9B,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B,CAAC;AAEF,KAAK,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC,GAAG;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAkFJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}