@sentropic/design-system-svelte 0.34.0 → 0.34.21
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/AppChrome.svelte +660 -0
- package/dist/AppChrome.svelte.d.ts +74 -0
- package/dist/AppChrome.svelte.d.ts.map +1 -0
- package/dist/AppChrome.test.d.ts +2 -0
- package/dist/AppChrome.test.d.ts.map +1 -0
- package/dist/AppChrome.test.js +122 -0
- package/dist/AppHeader.svelte +159 -1
- package/dist/AppHeader.svelte.d.ts +18 -1
- package/dist/AppHeader.svelte.d.ts.map +1 -1
- package/dist/ArcDiagramChart.svelte +380 -0
- package/dist/ArcDiagramChart.svelte.d.ts +43 -0
- package/dist/ArcDiagramChart.svelte.d.ts.map +1 -0
- package/dist/AreaRangeChart.svelte +487 -0
- package/dist/AreaRangeChart.svelte.d.ts +38 -0
- package/dist/AreaRangeChart.svelte.d.ts.map +1 -0
- package/dist/AreaSplineRangeChart.svelte +478 -0
- package/dist/AreaSplineRangeChart.svelte.d.ts +37 -0
- package/dist/AreaSplineRangeChart.svelte.d.ts.map +1 -0
- package/dist/BellCurveChart.svelte +487 -0
- package/dist/BellCurveChart.svelte.d.ts +40 -0
- package/dist/BellCurveChart.svelte.d.ts.map +1 -0
- package/dist/Calendar.svelte +11 -0
- package/dist/ChatThread.svelte +32 -1
- package/dist/ChatThread.svelte.d.ts +14 -0
- package/dist/ChatThread.svelte.d.ts.map +1 -1
- package/dist/ColumnPyramidChart.svelte +332 -0
- package/dist/ColumnPyramidChart.svelte.d.ts +35 -0
- package/dist/ColumnPyramidChart.svelte.d.ts.map +1 -0
- package/dist/ColumnRangeChart.svelte +432 -0
- package/dist/ColumnRangeChart.svelte.d.ts +42 -0
- package/dist/ColumnRangeChart.svelte.d.ts.map +1 -0
- package/dist/Combobox.svelte +3 -0
- package/dist/ConfigItemCard.svelte +303 -0
- package/dist/ConfigItemCard.svelte.d.ts +37 -0
- package/dist/ConfigItemCard.svelte.d.ts.map +1 -0
- package/dist/ContentSwitcher.svelte +1 -1
- package/dist/DatePicker.svelte +3 -0
- package/dist/DependencyWheelChart.svelte +413 -0
- package/dist/DependencyWheelChart.svelte.d.ts +42 -0
- package/dist/DependencyWheelChart.svelte.d.ts.map +1 -0
- package/dist/DumbbellChart.svelte +403 -0
- package/dist/DumbbellChart.svelte.d.ts +44 -0
- package/dist/DumbbellChart.svelte.d.ts.map +1 -0
- package/dist/ErrorBarChart.svelte +428 -0
- package/dist/ErrorBarChart.svelte.d.ts +40 -0
- package/dist/ErrorBarChart.svelte.d.ts.map +1 -0
- package/dist/FieldCard.svelte +220 -0
- package/dist/FieldCard.svelte.d.ts +28 -0
- package/dist/FieldCard.svelte.d.ts.map +1 -0
- package/dist/GanttChart.svelte +410 -0
- package/dist/GanttChart.svelte.d.ts +39 -0
- package/dist/GanttChart.svelte.d.ts.map +1 -0
- package/dist/HLCChart.svelte +330 -0
- package/dist/HLCChart.svelte.d.ts +32 -0
- package/dist/HLCChart.svelte.d.ts.map +1 -0
- package/dist/HeikinAshiChart.svelte +365 -0
- package/dist/HeikinAshiChart.svelte.d.ts +37 -0
- package/dist/HeikinAshiChart.svelte.d.ts.map +1 -0
- package/dist/HollowCandlestickChart.svelte +357 -0
- package/dist/HollowCandlestickChart.svelte.d.ts +34 -0
- package/dist/HollowCandlestickChart.svelte.d.ts.map +1 -0
- package/dist/Input.svelte +3 -0
- package/dist/ItemChart.svelte +389 -0
- package/dist/ItemChart.svelte.d.ts +67 -0
- package/dist/ItemChart.svelte.d.ts.map +1 -0
- package/dist/LollipopChart.svelte +1 -1
- package/dist/MultiSelect.svelte +3 -0
- package/dist/NumberInput.svelte +3 -0
- package/dist/OHLCChart.svelte +343 -0
- package/dist/OHLCChart.svelte.d.ts +33 -0
- package/dist/OHLCChart.svelte.d.ts.map +1 -0
- package/dist/OrganizationChart.svelte +284 -0
- package/dist/OrganizationChart.svelte.d.ts +19 -0
- package/dist/OrganizationChart.svelte.d.ts.map +1 -0
- package/dist/PasswordInput.svelte +3 -0
- package/dist/PolygonChart.svelte +189 -0
- package/dist/PolygonChart.svelte.d.ts +17 -0
- package/dist/PolygonChart.svelte.d.ts.map +1 -0
- package/dist/ScoreCard.svelte +172 -0
- package/dist/ScoreCard.svelte.d.ts +27 -0
- package/dist/ScoreCard.svelte.d.ts.map +1 -0
- package/dist/Search.svelte +7 -5
- package/dist/Select.svelte +3 -0
- package/dist/StreamgraphChart.svelte +283 -0
- package/dist/StreamgraphChart.svelte.d.ts +23 -0
- package/dist/StreamgraphChart.svelte.d.ts.map +1 -0
- package/dist/StreamingMessage.svelte +44 -2
- package/dist/StreamingMessage.svelte.d.ts +18 -1
- package/dist/StreamingMessage.svelte.d.ts.map +1 -1
- package/dist/TileMapChart.svelte +314 -0
- package/dist/TileMapChart.svelte.d.ts +45 -0
- package/dist/TileMapChart.svelte.d.ts.map +1 -0
- package/dist/TimePicker.svelte +3 -0
- package/dist/TimelineChart.svelte +362 -0
- package/dist/TimelineChart.svelte.d.ts +22 -0
- package/dist/TimelineChart.svelte.d.ts.map +1 -0
- package/dist/TreegraphChart.svelte +281 -0
- package/dist/TreegraphChart.svelte.d.ts +19 -0
- package/dist/TreegraphChart.svelte.d.ts.map +1 -0
- package/dist/VariablePieChart.svelte +313 -0
- package/dist/VariablePieChart.svelte.d.ts +52 -0
- package/dist/VariablePieChart.svelte.d.ts.map +1 -0
- package/dist/VennChart.svelte +348 -0
- package/dist/VennChart.svelte.d.ts +72 -0
- package/dist/VennChart.svelte.d.ts.map +1 -0
- package/dist/WordCloudChart.svelte +279 -0
- package/dist/WordCloudChart.svelte.d.ts +18 -0
- package/dist/WordCloudChart.svelte.d.ts.map +1 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -0
- 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"}
|
package/dist/Calendar.svelte
CHANGED
|
@@ -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;
|
package/dist/ChatThread.svelte
CHANGED
|
@@ -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
|
-
{
|
|
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;
|
|
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"}
|