@sentropic/design-system-svelte 0.18.0 → 0.20.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 (43) hide show
  1. package/dist/BoxPlotChart.svelte +302 -0
  2. package/dist/BoxPlotChart.svelte.d.ts +40 -0
  3. package/dist/BoxPlotChart.svelte.d.ts.map +1 -0
  4. package/dist/BulletChart.svelte +479 -0
  5. package/dist/BulletChart.svelte.d.ts +32 -0
  6. package/dist/BulletChart.svelte.d.ts.map +1 -0
  7. package/dist/BumpChart.svelte +387 -0
  8. package/dist/BumpChart.svelte.d.ts +35 -0
  9. package/dist/BumpChart.svelte.d.ts.map +1 -0
  10. package/dist/CalendarHeatmapChart.svelte +345 -0
  11. package/dist/CalendarHeatmapChart.svelte.d.ts +28 -0
  12. package/dist/CalendarHeatmapChart.svelte.d.ts.map +1 -0
  13. package/dist/CandlestickChart.svelte +333 -0
  14. package/dist/CandlestickChart.svelte.d.ts +31 -0
  15. package/dist/CandlestickChart.svelte.d.ts.map +1 -0
  16. package/dist/HeatmapChart.svelte +337 -0
  17. package/dist/HeatmapChart.svelte.d.ts +35 -0
  18. package/dist/HeatmapChart.svelte.d.ts.map +1 -0
  19. package/dist/HistogramChart.svelte +294 -0
  20. package/dist/HistogramChart.svelte.d.ts +38 -0
  21. package/dist/HistogramChart.svelte.d.ts.map +1 -0
  22. package/dist/MarimekkoChart.svelte +319 -0
  23. package/dist/MarimekkoChart.svelte.d.ts +35 -0
  24. package/dist/MarimekkoChart.svelte.d.ts.map +1 -0
  25. package/dist/ParallelCoordinatesChart.svelte +315 -0
  26. package/dist/ParallelCoordinatesChart.svelte.d.ts +35 -0
  27. package/dist/ParallelCoordinatesChart.svelte.d.ts.map +1 -0
  28. package/dist/RadarChart.svelte +340 -0
  29. package/dist/RadarChart.svelte.d.ts +43 -0
  30. package/dist/RadarChart.svelte.d.ts.map +1 -0
  31. package/dist/SankeyChart.svelte +364 -0
  32. package/dist/SankeyChart.svelte.d.ts +45 -0
  33. package/dist/SankeyChart.svelte.d.ts.map +1 -0
  34. package/dist/SunburstChart.svelte +388 -0
  35. package/dist/SunburstChart.svelte.d.ts +39 -0
  36. package/dist/SunburstChart.svelte.d.ts.map +1 -0
  37. package/dist/chartContrast.d.ts +0 -4
  38. package/dist/chartContrast.d.ts.map +1 -1
  39. package/dist/chartContrast.js +4 -56
  40. package/dist/index.d.ts +24 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +12 -0
  43. package/package.json +1 -1
@@ -0,0 +1,302 @@
1
+ <script lang="ts" module>
2
+ /**
3
+ * BoxPlotChart - API canonique (référence Svelte, React/Vue doivent s'aligner)
4
+ *
5
+ * Props obligatoires :
6
+ * data BoxPlotChartDatum[] - tableau {label, min, q1, median, q3, max, outliers?, tone?}
7
+ * label string - aria-label du graphique
8
+ *
9
+ * Props optionnelles :
10
+ * width number (défaut 480) - largeur du viewBox en px
11
+ * height number (défaut 260) - hauteur du viewBox en px
12
+ * class string - classe CSS supplémentaire
13
+ *
14
+ * NaN/vide : les valeurs non-finies sont exclues du domaine (filter Number.isFinite).
15
+ * Tableau vide → rendu vide sans crash.
16
+ * Note : l'ordre min≤q1≤median≤q3≤max n'est pas imposé par clamp mais rendu
17
+ * tel quel (abs() sur la hauteur de boîte) ; les données incohérentes produisent
18
+ * un rendu plausible mais peuvent induire en erreur.
19
+ */
20
+ export type BoxPlotChartTone =
21
+ | "category1"
22
+ | "category2"
23
+ | "category3"
24
+ | "category4"
25
+ | "category5"
26
+ | "category6"
27
+ | "category7"
28
+ | "category8";
29
+
30
+ export type BoxPlotChartDatum = {
31
+ label: string;
32
+ min: number;
33
+ q1: number;
34
+ median: number;
35
+ q3: number;
36
+ max: number;
37
+ outliers?: number[];
38
+ tone?: BoxPlotChartTone;
39
+ };
40
+ </script>
41
+
42
+ <script lang="ts">
43
+ import ChartDataList from "./ChartDataList.svelte";
44
+
45
+ type BoxPlotChartProps = {
46
+ data: BoxPlotChartDatum[];
47
+ label: string;
48
+ width?: number;
49
+ height?: number;
50
+ class?: string;
51
+ };
52
+
53
+ let {
54
+ data,
55
+ label,
56
+ width = 480,
57
+ height = 260,
58
+ class: className
59
+ }: BoxPlotChartProps = $props();
60
+
61
+ const MARGIN = { top: 16, right: 20, bottom: 38, left: 48 };
62
+ const TONES = [
63
+ "category1",
64
+ "category2",
65
+ "category3",
66
+ "category4",
67
+ "category5",
68
+ "category6",
69
+ "category7",
70
+ "category8"
71
+ ] as const;
72
+
73
+ function formatNumber(value: number): string {
74
+ if (!Number.isFinite(value)) return "0";
75
+ if (Number.isInteger(value)) return String(value);
76
+ return value.toFixed(2).replace(/\.?0+$/, "");
77
+ }
78
+
79
+ function scaleLinear(v: number, d0: number, d1: number, r0: number, r1: number) {
80
+ if (d1 === d0) return r0;
81
+ return r0 + ((v - d0) * (r1 - r0)) / (d1 - d0);
82
+ }
83
+
84
+ let hoveredIndex: number | null = $state(null);
85
+
86
+ const plotWidth = $derived(Math.max(width - MARGIN.left - MARGIN.right, 1));
87
+ const plotHeight = $derived(Math.max(height - MARGIN.top - MARGIN.bottom, 1));
88
+
89
+ const domain = $derived.by(() => {
90
+ const values = data.flatMap((datum) => [
91
+ datum.min,
92
+ datum.q1,
93
+ datum.median,
94
+ datum.q3,
95
+ datum.max,
96
+ ...(datum.outliers ?? [])
97
+ ]).filter(Number.isFinite);
98
+ if (values.length === 0) return { min: 0, max: 1 };
99
+ const min = Math.min(...values);
100
+ const max = Math.max(...values);
101
+ const pad = (max - min) * 0.08 || Math.max(Math.abs(max), 1) * 0.1;
102
+ return { min: min - pad, max: max + pad };
103
+ });
104
+
105
+ const plots = $derived.by(() => {
106
+ const band = data.length > 0 ? plotWidth / data.length : plotWidth;
107
+ const boxWidth = Math.min(54, Math.max(18, band * 0.44));
108
+
109
+ return data.map((datum, index) => {
110
+ const cx = MARGIN.left + band * (index + 0.5);
111
+ const y = (value: number) => MARGIN.top + scaleLinear(value, domain.min, domain.max, plotHeight, 0);
112
+ const q1Y = y(datum.q1);
113
+ const q3Y = y(datum.q3);
114
+ const minY = y(datum.min);
115
+ const maxY = y(datum.max);
116
+ return {
117
+ datum,
118
+ tone: datum.tone ?? TONES[index % TONES.length],
119
+ cx,
120
+ boxX: cx - boxWidth / 2,
121
+ boxY: Math.min(q1Y, q3Y),
122
+ boxWidth,
123
+ boxHeight: Math.max(Math.abs(q1Y - q3Y), 1),
124
+ medianY: y(datum.median),
125
+ minY,
126
+ maxY,
127
+ capWidth: boxWidth * 0.72,
128
+ outliers: (datum.outliers ?? []).filter(Number.isFinite).map((value) => ({ value, y: y(value) }))
129
+ };
130
+ });
131
+ });
132
+
133
+ const dataValueItems = $derived(
134
+ data.map((datum) => {
135
+ const summary = `${datum.label}: min ${formatNumber(datum.min)}, q1 ${formatNumber(datum.q1)}, median ${formatNumber(datum.median)}, q3 ${formatNumber(datum.q3)}, max ${formatNumber(datum.max)}`;
136
+ const outliers = datum.outliers?.length ? `, outliers ${datum.outliers.map(formatNumber).join(", ")}` : "";
137
+ return `${summary}${outliers}`;
138
+ })
139
+ );
140
+
141
+ function handleVisualPointerMove(event: PointerEvent) {
142
+ const target = event.target;
143
+ if (!(target instanceof Element)) {
144
+ hoveredIndex = null;
145
+ return;
146
+ }
147
+ const index = Number(target.getAttribute("data-chart-index"));
148
+ hoveredIndex = Number.isInteger(index) ? index : null;
149
+ }
150
+
151
+ const classes = () => ["st-boxPlotChart", className].filter(Boolean).join(" ");
152
+ </script>
153
+
154
+ <div class={classes()}>
155
+ <div
156
+ class="st-boxPlotChart__visual"
157
+ role="img"
158
+ aria-label={label}
159
+ onpointermove={handleVisualPointerMove}
160
+ onpointerleave={() => (hoveredIndex = null)}
161
+ >
162
+ <svg
163
+ viewBox="0 0 {width} {height}"
164
+ preserveAspectRatio="xMidYMid meet"
165
+ width="100%"
166
+ height="100%"
167
+ focusable="false"
168
+ aria-hidden="true"
169
+ >
170
+ <line class="st-boxPlotChart__axis" x1={MARGIN.left} x2={MARGIN.left} y1={MARGIN.top} y2={height - MARGIN.bottom} />
171
+ <line class="st-boxPlotChart__axis" x1={MARGIN.left} x2={width - MARGIN.right} y1={height - MARGIN.bottom} y2={height - MARGIN.bottom} />
172
+
173
+ {#each plots as plot, i (plot.datum.label)}
174
+ <line class="st-boxPlotChart__whisker" x1={plot.cx} x2={plot.cx} y1={plot.minY} y2={plot.maxY} data-chart-index={i} />
175
+ <line class="st-boxPlotChart__whiskerCap" x1={plot.cx - plot.capWidth / 2} x2={plot.cx + plot.capWidth / 2} y1={plot.minY} y2={plot.minY} data-chart-index={i} />
176
+ <line class="st-boxPlotChart__whiskerCap" x1={plot.cx - plot.capWidth / 2} x2={plot.cx + plot.capWidth / 2} y1={plot.maxY} y2={plot.maxY} data-chart-index={i} />
177
+ <rect
178
+ class="st-boxPlotChart__box st-boxPlotChart__box--{plot.tone}"
179
+ class:st-boxPlotChart__box--dim={hoveredIndex !== null && hoveredIndex !== i}
180
+ x={plot.boxX}
181
+ y={plot.boxY}
182
+ width={plot.boxWidth}
183
+ height={plot.boxHeight}
184
+ data-chart-index={i}
185
+ />
186
+ <line class="st-boxPlotChart__median" x1={plot.boxX} x2={plot.boxX + plot.boxWidth} y1={plot.medianY} y2={plot.medianY} data-chart-index={i} />
187
+ {#each plot.outliers as outlier (`${plot.datum.label}-${outlier.value}`)}
188
+ <circle class="st-boxPlotChart__outlier" cx={plot.cx} cy={outlier.y} r="3" data-chart-index={i} />
189
+ {/each}
190
+ <text class="st-boxPlotChart__label" x={plot.cx} y={height - MARGIN.bottom + 16} text-anchor="middle">
191
+ {plot.datum.label}
192
+ </text>
193
+ {/each}
194
+ </svg>
195
+ </div>
196
+
197
+ <ChartDataList {label} items={dataValueItems} />
198
+
199
+ {#if hoveredIndex !== null && plots[hoveredIndex]}
200
+ {@const plot = plots[hoveredIndex]}
201
+ <div
202
+ class="st-boxPlotChart__tooltip"
203
+ role="presentation"
204
+ style="left: {(plot.cx / width) * 100}%; top: {(plot.medianY / height) * 100}%"
205
+ >
206
+ <span class="st-boxPlotChart__tooltipLabel">{plot.datum.label}</span>
207
+ <span class="st-boxPlotChart__tooltipValue">Median {formatNumber(plot.datum.median)}</span>
208
+ </div>
209
+ {/if}
210
+ </div>
211
+
212
+ <style>
213
+ .st-boxPlotChart {
214
+ color: var(--st-semantic-text-secondary);
215
+ display: block;
216
+ font-family: inherit;
217
+ max-width: 100%;
218
+ position: relative;
219
+ width: 100%;
220
+ }
221
+
222
+ .st-boxPlotChart svg,
223
+ .st-boxPlotChart__visual {
224
+ display: block;
225
+ overflow: visible;
226
+ }
227
+
228
+ .st-boxPlotChart__axis,
229
+ .st-boxPlotChart__whisker,
230
+ .st-boxPlotChart__whiskerCap {
231
+ stroke: var(--st-semantic-border-subtle);
232
+ stroke-width: 1;
233
+ }
234
+
235
+ .st-boxPlotChart__median {
236
+ stroke: var(--st-semantic-text-primary);
237
+ stroke-width: 2;
238
+ }
239
+
240
+ .st-boxPlotChart__box {
241
+ cursor: pointer;
242
+ fill-opacity: 0.72;
243
+ stroke: var(--st-semantic-surface-default, Canvas);
244
+ stroke-width: 1;
245
+ transition: opacity 120ms ease;
246
+ }
247
+
248
+ .st-boxPlotChart__box--dim {
249
+ opacity: 0.45;
250
+ }
251
+
252
+ @media (prefers-reduced-motion: reduce) {
253
+ .st-boxPlotChart__box {
254
+ transition: none;
255
+ }
256
+ }
257
+
258
+ .st-boxPlotChart__box--category1 { fill: var(--st-semantic-data-category1); }
259
+ .st-boxPlotChart__box--category2 { fill: var(--st-semantic-data-category2); }
260
+ .st-boxPlotChart__box--category3 { fill: var(--st-semantic-data-category3); }
261
+ .st-boxPlotChart__box--category4 { fill: var(--st-semantic-data-category4); }
262
+ .st-boxPlotChart__box--category5 { fill: var(--st-semantic-data-category5); }
263
+ .st-boxPlotChart__box--category6 { fill: var(--st-semantic-data-category6); }
264
+ .st-boxPlotChart__box--category7 { fill: var(--st-semantic-data-category7); }
265
+ .st-boxPlotChart__box--category8 { fill: var(--st-semantic-data-category8); }
266
+
267
+ .st-boxPlotChart__outlier {
268
+ fill: var(--st-semantic-surface-default, Canvas);
269
+ stroke: var(--st-semantic-text-secondary);
270
+ stroke-width: 1.5;
271
+ }
272
+
273
+ .st-boxPlotChart__label {
274
+ fill: var(--st-semantic-text-secondary);
275
+ font-size: 0.75rem;
276
+ }
277
+
278
+ .st-boxPlotChart__tooltip {
279
+ background: var(--st-semantic-surface-inverse);
280
+ border-radius: var(--st-radius-sm, 0.25rem);
281
+ color: var(--st-semantic-text-inverse);
282
+ display: inline-flex;
283
+ flex-direction: column;
284
+ font-size: 0.75rem;
285
+ gap: 0.125rem;
286
+ line-height: 1.2;
287
+ padding: 0.375rem 0.5rem;
288
+ pointer-events: none;
289
+ position: absolute;
290
+ transform: translate(-50%, -115%);
291
+ white-space: nowrap;
292
+ z-index: 1;
293
+ }
294
+
295
+ .st-boxPlotChart__tooltipLabel {
296
+ font-weight: 600;
297
+ }
298
+
299
+ .st-boxPlotChart__tooltipValue {
300
+ opacity: 0.85;
301
+ }
302
+ </style>
@@ -0,0 +1,40 @@
1
+ /**
2
+ * BoxPlotChart - API canonique (référence Svelte, React/Vue doivent s'aligner)
3
+ *
4
+ * Props obligatoires :
5
+ * data BoxPlotChartDatum[] - tableau {label, min, q1, median, q3, max, outliers?, tone?}
6
+ * label string - aria-label du graphique
7
+ *
8
+ * Props optionnelles :
9
+ * width number (défaut 480) - largeur du viewBox en px
10
+ * height number (défaut 260) - hauteur du viewBox en px
11
+ * class string - classe CSS supplémentaire
12
+ *
13
+ * NaN/vide : les valeurs non-finies sont exclues du domaine (filter Number.isFinite).
14
+ * Tableau vide → rendu vide sans crash.
15
+ * Note : l'ordre min≤q1≤median≤q3≤max n'est pas imposé par clamp mais rendu
16
+ * tel quel (abs() sur la hauteur de boîte) ; les données incohérentes produisent
17
+ * un rendu plausible mais peuvent induire en erreur.
18
+ */
19
+ export type BoxPlotChartTone = "category1" | "category2" | "category3" | "category4" | "category5" | "category6" | "category7" | "category8";
20
+ export type BoxPlotChartDatum = {
21
+ label: string;
22
+ min: number;
23
+ q1: number;
24
+ median: number;
25
+ q3: number;
26
+ max: number;
27
+ outliers?: number[];
28
+ tone?: BoxPlotChartTone;
29
+ };
30
+ type BoxPlotChartProps = {
31
+ data: BoxPlotChartDatum[];
32
+ label: string;
33
+ width?: number;
34
+ height?: number;
35
+ class?: string;
36
+ };
37
+ declare const BoxPlotChart: import("svelte").Component<BoxPlotChartProps, {}, "">;
38
+ type BoxPlotChart = ReturnType<typeof BoxPlotChart>;
39
+ export default BoxPlotChart;
40
+ //# sourceMappingURL=BoxPlotChart.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoxPlotChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/BoxPlotChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,gBAAgB,GACxB,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,CAAC;AAEhB,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB,CAAC;AAMF,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAiJJ,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}