@sentropic/design-system-svelte 0.8.0 → 0.10.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 (67) hide show
  1. package/dist/AreaChart.svelte +6 -0
  2. package/dist/Button.svelte +48 -20
  3. package/dist/Card.svelte +6 -4
  4. package/dist/Checkbox.svelte +4 -0
  5. package/dist/Combobox.svelte +17 -6
  6. package/dist/DatePicker.svelte +17 -6
  7. package/dist/DonutChart.svelte +169 -0
  8. package/dist/DonutChart.svelte.d.ts +21 -0
  9. package/dist/DonutChart.svelte.d.ts.map +1 -0
  10. package/dist/Footer.svelte +124 -0
  11. package/dist/Footer.svelte.d.ts +21 -0
  12. package/dist/Footer.svelte.d.ts.map +1 -0
  13. package/dist/Highlight.svelte +63 -0
  14. package/dist/Highlight.svelte.d.ts +15 -0
  15. package/dist/Highlight.svelte.d.ts.map +1 -0
  16. package/dist/Input.svelte +34 -13
  17. package/dist/LanguageSelector.svelte +181 -0
  18. package/dist/LanguageSelector.svelte.d.ts +18 -0
  19. package/dist/LanguageSelector.svelte.d.ts.map +1 -0
  20. package/dist/Link.svelte +18 -10
  21. package/dist/MessageStatusBadge.svelte +11 -7
  22. package/dist/MessageStatusBadge.svelte.d.ts +2 -0
  23. package/dist/MessageStatusBadge.svelte.d.ts.map +1 -1
  24. package/dist/MultiSelect.svelte +17 -7
  25. package/dist/NumberInput.svelte +17 -6
  26. package/dist/OrderedList.svelte +103 -0
  27. package/dist/OrderedList.svelte.d.ts +17 -0
  28. package/dist/OrderedList.svelte.d.ts.map +1 -0
  29. package/dist/OverflowMenu.svelte +5 -2
  30. package/dist/PaginationNav.svelte +5 -2
  31. package/dist/PasswordInput.svelte +17 -6
  32. package/dist/Quote.svelte +72 -0
  33. package/dist/Quote.svelte.d.ts +16 -0
  34. package/dist/Quote.svelte.d.ts.map +1 -0
  35. package/dist/Radio.svelte +4 -0
  36. package/dist/ScatterPlot.svelte +179 -0
  37. package/dist/ScatterPlot.svelte.d.ts +21 -0
  38. package/dist/ScatterPlot.svelte.d.ts.map +1 -0
  39. package/dist/Search.svelte +17 -6
  40. package/dist/Select.svelte +21 -8
  41. package/dist/SkipLink.svelte +50 -0
  42. package/dist/SkipLink.svelte.d.ts +12 -0
  43. package/dist/SkipLink.svelte.d.ts.map +1 -0
  44. package/dist/StackedBarChart.svelte +190 -0
  45. package/dist/StackedBarChart.svelte.d.ts +22 -0
  46. package/dist/StackedBarChart.svelte.d.ts.map +1 -0
  47. package/dist/StreamingMessage.svelte +47 -0
  48. package/dist/StreamingMessage.svelte.d.ts +7 -0
  49. package/dist/StreamingMessage.svelte.d.ts.map +1 -1
  50. package/dist/Switch.svelte +5 -1
  51. package/dist/Tabs.svelte +21 -7
  52. package/dist/Textarea.svelte +36 -9
  53. package/dist/Tile.svelte +165 -0
  54. package/dist/Tile.svelte.d.ts +24 -0
  55. package/dist/Tile.svelte.d.ts.map +1 -0
  56. package/dist/Toggle.svelte +5 -1
  57. package/dist/Toggletip.svelte +5 -2
  58. package/dist/TreeView.svelte +213 -0
  59. package/dist/TreeView.svelte.d.ts +20 -0
  60. package/dist/TreeView.svelte.d.ts.map +1 -0
  61. package/dist/UnorderedList.svelte +4 -3
  62. package/dist/UnorderedList.svelte.d.ts +3 -2
  63. package/dist/UnorderedList.svelte.d.ts.map +1 -1
  64. package/dist/index.d.ts +23 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +13 -0
  67. package/package.json +4 -2
@@ -0,0 +1,190 @@
1
+ <script lang="ts" module>
2
+ export type StackedBarTone =
3
+ | "category1" | "category2" | "category3" | "category4"
4
+ | "category5" | "category6" | "category7" | "category8";
5
+
6
+ export type StackedBarSegment = {
7
+ label: string;
8
+ value: number;
9
+ tone?: StackedBarTone;
10
+ };
11
+
12
+ export type StackedBarDatum = {
13
+ label: string;
14
+ segments: StackedBarSegment[];
15
+ };
16
+ </script>
17
+
18
+ <script lang="ts">
19
+ type StackedBarChartProps = {
20
+ data: StackedBarDatum[];
21
+ width?: number;
22
+ height?: number;
23
+ label: string;
24
+ showLegend?: boolean;
25
+ class?: string;
26
+ };
27
+
28
+ let {
29
+ data,
30
+ width = 480,
31
+ height = 260,
32
+ label,
33
+ showLegend = true,
34
+ class: className
35
+ }: StackedBarChartProps = $props();
36
+
37
+ const MARGIN = { top: 14, right: 16, bottom: 34, left: 44 };
38
+ const TONES = ["category1","category2","category3","category4","category5","category6","category7","category8"] as const;
39
+
40
+ function niceTicks(min: number, max: number, target = 5): number[] {
41
+ if (!Number.isFinite(min) || !Number.isFinite(max) || min === max) return [Number.isFinite(max) ? max : 0];
42
+ const range = max - min;
43
+ const rough = range / Math.max(target - 1, 1);
44
+ const pow = Math.pow(10, Math.floor(Math.log10(rough)));
45
+ const norm = rough / pow;
46
+ const step = norm < 1.5 ? pow : norm < 3 ? 2 * pow : norm < 7 ? 5 * pow : 10 * pow;
47
+ const start = Math.floor(min / step) * step;
48
+ const end = Math.ceil(max / step) * step;
49
+ const ticks: number[] = [];
50
+ for (let v = start; v <= end + step / 2; v += step) ticks.push(Number(v.toFixed(10)));
51
+ return ticks;
52
+ }
53
+ const scaleLinear = (v: number, d0: number, d1: number, r0: number, r1: number) =>
54
+ d1 === d0 ? r0 : r0 + ((v - d0) * (r1 - r0)) / (d1 - d0);
55
+ const fmt = (v: number) => (Math.abs(v) >= 1000 ? `${(v / 1000).toFixed(v % 1000 === 0 ? 0 : 1)}k` : Number.isInteger(v) ? String(v) : v.toFixed(1));
56
+
57
+ // Légende : tones par label de série (ordre de la 1re barre).
58
+ const legend = $derived.by(() => {
59
+ const seen = new Map<string, StackedBarTone>();
60
+ data.forEach((bar) => bar.segments.forEach((seg, i) => {
61
+ if (!seen.has(seg.label)) seen.set(seg.label, seg.tone ?? TONES[i % TONES.length]);
62
+ }));
63
+ return [...seen.entries()].map(([seriesLabel, tone]) => ({ seriesLabel, tone }));
64
+ });
65
+
66
+ let hovered: { bar: number; seg: number } | null = $state(null);
67
+
68
+ const scales = $derived.by(() => {
69
+ const totals = data.map((b) => b.segments.reduce((s, x) => s + Math.max(x.value, 0), 0));
70
+ const ticks = niceTicks(0, Math.max(0, ...totals));
71
+ return {
72
+ ticks, domainMax: ticks[ticks.length - 1],
73
+ plotW: Math.max(width - MARGIN.left - MARGIN.right, 1),
74
+ plotH: Math.max(height - MARGIN.top - MARGIN.bottom, 1)
75
+ };
76
+ });
77
+
78
+ const bars = $derived.by(() => {
79
+ const { domainMax, plotW, plotH } = scales;
80
+ if (data.length === 0) return [];
81
+ const band = plotW / data.length;
82
+ const barWidth = band * 0.6;
83
+ return data.map((bar, bi) => {
84
+ const x = MARGIN.left + band * bi + (band - barWidth) / 2;
85
+ let acc = 0;
86
+ const segs = bar.segments.map((seg, si) => {
87
+ const v = Math.max(seg.value, 0);
88
+ const yTop = MARGIN.top + scaleLinear(acc + v, 0, domainMax, plotH, 0);
89
+ const yBottom = MARGIN.top + scaleLinear(acc, 0, domainMax, plotH, 0);
90
+ acc += v;
91
+ return {
92
+ x, y: yTop, width: barWidth, height: Math.max(yBottom - yTop, 0),
93
+ seg, tone: seg.tone ?? TONES[si % TONES.length],
94
+ cx: x + barWidth / 2, cy: yTop + (yBottom - yTop) / 2
95
+ };
96
+ });
97
+ return { x, band, label: bar.label, segs, cxLabel: MARGIN.left + band * (bi + 0.5) };
98
+ });
99
+ });
100
+
101
+ const classes = () => ["st-stackedBar", className].filter(Boolean).join(" ");
102
+ </script>
103
+
104
+ <div class={classes()} role="img" aria-label={label}>
105
+ <svg viewBox="0 0 {width} {height}" preserveAspectRatio="xMidYMid meet" width="100%" height="100%" focusable="false" aria-hidden="true">
106
+ {#each scales.ticks as t (t)}
107
+ {@const y = MARGIN.top + scaleLinear(t, 0, scales.domainMax, scales.plotH, 0)}
108
+ <line class="st-stackedBar__grid" x1={MARGIN.left} x2={width - MARGIN.right} y1={y} y2={y} />
109
+ <text class="st-stackedBar__tick" x={MARGIN.left - 6} y={y} text-anchor="end" dominant-baseline="middle">{fmt(t)}</text>
110
+ {/each}
111
+
112
+ <line class="st-stackedBar__axis" x1={MARGIN.left} x2={MARGIN.left} y1={MARGIN.top} y2={height - MARGIN.bottom} />
113
+ <line class="st-stackedBar__axis" x1={MARGIN.left} x2={width - MARGIN.right} y1={height - MARGIN.bottom} y2={height - MARGIN.bottom} />
114
+
115
+ {#each bars as bar, bi (bar.label)}
116
+ <text class="st-stackedBar__categoryLabel" x={bar.cxLabel} y={height - MARGIN.bottom + 16} text-anchor="middle">{bar.label}</text>
117
+ {#each bar.segs as s, si (s.seg.label)}
118
+ <rect
119
+ class="st-stackedBar__seg st-stackedBar__seg--{s.tone}"
120
+ class:st-stackedBar__seg--dim={hovered !== null && !(hovered.bar === bi && hovered.seg === si)}
121
+ x={s.x} y={s.y} width={s.width} height={s.height}
122
+ tabindex="0"
123
+ role="img"
124
+ aria-label="{bar.label} — {s.seg.label}: {s.seg.value}"
125
+ onmouseenter={() => (hovered = { bar: bi, seg: si })}
126
+ onmouseleave={() => (hovered = null)}
127
+ onfocus={() => (hovered = { bar: bi, seg: si })}
128
+ onblur={() => (hovered = null)}
129
+ />
130
+ {/each}
131
+ {/each}
132
+ </svg>
133
+
134
+ {#if hovered && bars[hovered.bar]?.segs[hovered.seg]}
135
+ {@const s = bars[hovered.bar].segs[hovered.seg]}
136
+ <div class="st-stackedBar__tooltip" role="presentation" style="left: {(s.cx / width) * 100}%; top: {(s.cy / height) * 100}%">
137
+ <span class="st-stackedBar__tooltipLabel">{s.seg.label}</span>
138
+ <span class="st-stackedBar__tooltipValue">{s.seg.value}</span>
139
+ </div>
140
+ {/if}
141
+
142
+ {#if showLegend && legend.length > 0}
143
+ <ul class="st-stackedBar__legend">
144
+ {#each legend as item (item.seriesLabel)}
145
+ <li class="st-stackedBar__legendItem">
146
+ <span class="st-stackedBar__legendSwatch st-stackedBar__legendSwatch--{item.tone}" aria-hidden="true"></span>
147
+ {item.seriesLabel}
148
+ </li>
149
+ {/each}
150
+ </ul>
151
+ {/if}
152
+ </div>
153
+
154
+ <style>
155
+ .st-stackedBar { color: var(--st-semantic-text-secondary); display: block; font-family: inherit; position: relative; width: 100%; }
156
+ .st-stackedBar svg { display: block; overflow: visible; }
157
+ .st-stackedBar__grid { stroke: var(--st-semantic-border-subtle); stroke-dasharray: 2 3; stroke-width: 1; opacity: 0.7; }
158
+ .st-stackedBar__axis { stroke: var(--st-semantic-border-subtle); stroke-width: 1; }
159
+ .st-stackedBar__tick, .st-stackedBar__categoryLabel { fill: var(--st-semantic-text-secondary); font-size: 0.6875rem; }
160
+ .st-stackedBar__seg { cursor: pointer; stroke: var(--st-semantic-surface-default, #fff); stroke-width: 1; transition: opacity 120ms ease; }
161
+ .st-stackedBar__seg--dim { opacity: 0.45; }
162
+ .st-stackedBar__seg:focus-visible { outline: 2px solid var(--st-semantic-border-interactive); outline-offset: 1px; }
163
+ .st-stackedBar__seg--category1 { fill: var(--st-semantic-data-category1); }
164
+ .st-stackedBar__seg--category2 { fill: var(--st-semantic-data-category2); }
165
+ .st-stackedBar__seg--category3 { fill: var(--st-semantic-data-category3); }
166
+ .st-stackedBar__seg--category4 { fill: var(--st-semantic-data-category4); }
167
+ .st-stackedBar__seg--category5 { fill: var(--st-semantic-data-category5); }
168
+ .st-stackedBar__seg--category6 { fill: var(--st-semantic-data-category6); }
169
+ .st-stackedBar__seg--category7 { fill: var(--st-semantic-data-category7); }
170
+ .st-stackedBar__seg--category8 { fill: var(--st-semantic-data-category8); }
171
+ .st-stackedBar__tooltip {
172
+ background: var(--st-semantic-surface-inverse); border-radius: var(--st-radius-sm, 0.25rem);
173
+ color: var(--st-semantic-text-inverse); display: inline-flex; flex-direction: column; font-size: 0.75rem;
174
+ gap: 0.125rem; line-height: 1.2; padding: 0.375rem 0.5rem; pointer-events: none; position: absolute;
175
+ transform: translate(-50%, calc(-100% - 8px)); white-space: nowrap; z-index: 1;
176
+ }
177
+ .st-stackedBar__tooltipLabel { font-weight: 600; }
178
+ .st-stackedBar__tooltipValue { opacity: 0.85; }
179
+ .st-stackedBar__legend { display: flex; flex-wrap: wrap; gap: 0.75rem; list-style: none; margin: 0.5rem 0 0; padding: 0; }
180
+ .st-stackedBar__legendItem { align-items: center; color: var(--st-semantic-text-secondary); display: inline-flex; font-size: 0.75rem; gap: 0.35rem; }
181
+ .st-stackedBar__legendSwatch { border-radius: 2px; height: 0.7rem; width: 0.7rem; }
182
+ .st-stackedBar__legendSwatch--category1 { background: var(--st-semantic-data-category1); }
183
+ .st-stackedBar__legendSwatch--category2 { background: var(--st-semantic-data-category2); }
184
+ .st-stackedBar__legendSwatch--category3 { background: var(--st-semantic-data-category3); }
185
+ .st-stackedBar__legendSwatch--category4 { background: var(--st-semantic-data-category4); }
186
+ .st-stackedBar__legendSwatch--category5 { background: var(--st-semantic-data-category5); }
187
+ .st-stackedBar__legendSwatch--category6 { background: var(--st-semantic-data-category6); }
188
+ .st-stackedBar__legendSwatch--category7 { background: var(--st-semantic-data-category7); }
189
+ .st-stackedBar__legendSwatch--category8 { background: var(--st-semantic-data-category8); }
190
+ </style>
@@ -0,0 +1,22 @@
1
+ export type StackedBarTone = "category1" | "category2" | "category3" | "category4" | "category5" | "category6" | "category7" | "category8";
2
+ export type StackedBarSegment = {
3
+ label: string;
4
+ value: number;
5
+ tone?: StackedBarTone;
6
+ };
7
+ export type StackedBarDatum = {
8
+ label: string;
9
+ segments: StackedBarSegment[];
10
+ };
11
+ type StackedBarChartProps = {
12
+ data: StackedBarDatum[];
13
+ width?: number;
14
+ height?: number;
15
+ label: string;
16
+ showLegend?: boolean;
17
+ class?: string;
18
+ };
19
+ declare const StackedBarChart: import("svelte").Component<StackedBarChartProps, {}, "">;
20
+ type StackedBarChart = ReturnType<typeof StackedBarChart>;
21
+ export default StackedBarChart;
22
+ //# sourceMappingURL=StackedBarChart.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StackedBarChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/StackedBarChart.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,MAAM,cAAc,GACtB,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACrD,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAE1D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA6HJ,QAAA,MAAM,eAAe,0DAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -9,6 +9,8 @@
9
9
  export type StreamingMessageEvent =
10
10
  | { type: "message.delta"; messageId?: string; delta: string }
11
11
  | { type: "message.completed"; messageId?: string }
12
+ | { type: "reasoning.delta"; messageId?: string; delta: string }
13
+ | { type: "reasoning.completed"; messageId?: string }
12
14
  | { type: "tool.started"; toolCallId: string; toolName: string; messageId?: string }
13
15
  | {
14
16
  type: "tool.completed";
@@ -84,6 +86,15 @@
84
86
  .join("");
85
87
  };
86
88
 
89
+ const resolvedReasoning = () =>
90
+ mergedEvents()
91
+ .filter((event) => event.type === "reasoning.delta")
92
+ .map((event) => event.delta)
93
+ .join("");
94
+
95
+ const reasoningCompleted = () =>
96
+ mergedEvents().some((event) => event.type === "reasoning.completed");
97
+
87
98
  const hasAnyEvent = () => mergedEvents().length > 0;
88
99
 
89
100
  const toolCalls = (): ToolCallState[] => {
@@ -129,6 +140,10 @@
129
140
  return "message.delta";
130
141
  case "message.completed":
131
142
  return "message.completed";
143
+ case "reasoning.delta":
144
+ return "reasoning.delta";
145
+ case "reasoning.completed":
146
+ return "reasoning.completed";
132
147
  case "tool.started":
133
148
  return `${event.toolName} démarré (${event.toolCallId})`;
134
149
  case "tool.completed":
@@ -155,6 +170,15 @@
155
170
  footer={footer}
156
171
  actions={actions}
157
172
  >
173
+ {#if resolvedReasoning()}
174
+ <details class="st-streamingMessage__reasoning" open={!reasoningCompleted()}>
175
+ <summary class="st-streamingMessage__reasoningToggle">
176
+ Raisonnement{reasoningCompleted() ? "" : "…"}
177
+ </summary>
178
+ <p class="st-streamingMessage__reasoningText">{resolvedReasoning()}</p>
179
+ </details>
180
+ {/if}
181
+
158
182
  {#if resolvedContent()}
159
183
  <p class="st-streamingMessage__text">{resolvedContent()}</p>
160
184
  {:else}
@@ -236,6 +260,29 @@
236
260
  font-style: italic;
237
261
  }
238
262
 
263
+ .st-streamingMessage__reasoning {
264
+ background: var(--st-component-chatMessage-reasoningBackground, var(--st-semantic-surface-subtle));
265
+ border-left: 2px solid var(--st-semantic-border-subtle);
266
+ border-radius: var(--st-component-control-radius, 0.375rem);
267
+ margin: 0 0 0.5rem;
268
+ padding: 0.4rem 0.6rem;
269
+ }
270
+
271
+ .st-streamingMessage__reasoningToggle {
272
+ color: var(--st-semantic-text-muted);
273
+ cursor: pointer;
274
+ font-size: 0.75rem;
275
+ font-weight: 600;
276
+ }
277
+
278
+ .st-streamingMessage__reasoningText {
279
+ color: var(--st-semantic-text-secondary);
280
+ font-size: 0.8125rem;
281
+ font-style: italic;
282
+ margin: 0.35rem 0 0;
283
+ white-space: pre-wrap;
284
+ }
285
+
239
286
  .st-streamingMessage__meta {
240
287
  color: var(--st-semantic-text-muted);
241
288
  font-size: 0.75rem;
@@ -8,6 +8,13 @@ export type StreamingMessageEvent = {
8
8
  } | {
9
9
  type: "message.completed";
10
10
  messageId?: string;
11
+ } | {
12
+ type: "reasoning.delta";
13
+ messageId?: string;
14
+ delta: string;
15
+ } | {
16
+ type: "reasoning.completed";
17
+ messageId?: string;
11
18
  } | {
12
19
  type: "tool.started";
13
20
  toolCallId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"StreamingMessage.svelte.d.ts","sourceRoot":"","sources":["../src/lib/StreamingMessage.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,qBAAqB,GAC7B;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAClF;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,sBAAsB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,sBAAsB,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEN,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAAC;AAQtD,KAAK,qBAAqB,GAAG,IAAI,CAC/B,cAAc,CAAC,WAAW,CAAC,EAC3B,OAAO,GAAG,UAAU,GAAG,MAAM,CAC9B,GAAG;IACF,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACxC,MAAM,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AA0KJ,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"StreamingMessage.svelte.d.ts","sourceRoot":"","sources":["../src/lib/StreamingMessage.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,qBAAqB,GAC7B;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAClF;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,sBAAsB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,sBAAsB,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEN,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAAC;AAQtD,KAAK,qBAAqB,GAAG,IAAI,CAC/B,cAAc,CAAC,WAAW,CAAC,EAC3B,OAAO,GAAG,UAAU,GAAG,MAAM,CAC9B,GAAG;IACF,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACxC,MAAM,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAgMJ,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
@@ -68,8 +68,12 @@
68
68
  transform: translateX(1rem);
69
69
  }
70
70
 
71
+ /* Focus = stratégie d'anatomie partagée (outline DSFR / inset Carbon / ring base). */
71
72
  .st-switch__input:focus-visible + .st-switch__track {
72
- box-shadow: 0 0 0 2px var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
73
+ outline: var(--st-component-control-anatomy-focus-outline, none);
74
+ outline-offset: var(--st-component-control-anatomy-focus-offset, 0);
75
+ box-shadow: var(--st-component-control-anatomy-focus-boxShadow,
76
+ 0 0 0 2px var(--st-component-control-focusRing, var(--st-semantic-border-interactive)));
73
77
  }
74
78
 
75
79
  .st-switch__content {
package/dist/Tabs.svelte CHANGED
@@ -77,22 +77,36 @@
77
77
  .st-tabs__tab {
78
78
  background: transparent;
79
79
  border: 0;
80
- border-bottom: 2px solid transparent;
80
+ border-bottom-width: var(--st-component-tabs-anatomy-shape-borderWidth, 2px);
81
+ border-bottom-style: var(--st-component-tabs-anatomy-shape-borderStyle, solid);
82
+ border-bottom-color: transparent;
81
83
  color: var(--st-component-tabs-inactiveText, var(--st-semantic-text-secondary));
82
- cursor: pointer;
83
- font: inherit;
84
- font-weight: 600;
84
+ cursor: var(--st-cursor-interactive, pointer);
85
+ font-family: var(--st-component-tabs-anatomy-typography-family, inherit);
86
+ font-weight: var(--st-component-tabs-anatomy-typography-weight, 600);
87
+ line-height: var(--st-component-tabs-anatomy-typography-lineHeight, 1.2);
88
+ letter-spacing: var(--st-component-tabs-anatomy-typography-letterSpacing, 0);
89
+ text-transform: var(--st-component-tabs-anatomy-typography-textTransform, none);
85
90
  padding: 0.75rem 0.25rem;
86
91
  }
87
92
 
88
93
  .st-tabs__tab--active {
89
94
  border-bottom-color: var(--st-component-tabs-indicator, var(--st-semantic-action-primary));
90
- color: var(--st-component-tabs-activeText, var(--st-semantic-text-primary));
95
+ color: var(--st-component-tabs-anatomy-states-hover-text, var(--st-component-tabs-activeText, var(--st-semantic-text-primary)));
96
+ }
97
+
98
+ /* a11y (non-negotiable): tabs previously had NO visible focus ring. The
99
+ shared focus mixin restores keyboard visibility per theme. */
100
+ .st-tabs__tab:focus-visible {
101
+ outline: var(--st-component-tabs-anatomy-focus-outline, 2px solid var(--st-semantic-border-interactive));
102
+ outline-offset: var(--st-component-tabs-anatomy-focus-offset, 2px);
103
+ box-shadow: var(--st-component-tabs-anatomy-focus-boxShadow, none);
104
+ border-radius: var(--st-component-tabs-anatomy-shape-radius, 0);
91
105
  }
92
106
 
93
107
  .st-tabs__tab:disabled {
94
- cursor: not-allowed;
95
- opacity: 0.55;
108
+ cursor: var(--st-cursor-disabled, not-allowed);
109
+ opacity: var(--st-component-tabs-anatomy-states-disabled-opacity, 0.55);
96
110
  }
97
111
 
98
112
  .st-tabs__panel {
@@ -55,8 +55,12 @@
55
55
  }
56
56
 
57
57
  .st-field__label {
58
- font-size: 0.875rem;
59
- font-weight: 600;
58
+ font-family: var(--st-component-field-labelTypography-family, inherit);
59
+ font-size: var(--st-component-field-labelTypography-size, 0.875rem);
60
+ font-weight: var(--st-component-field-labelTypography-weight, 600);
61
+ line-height: var(--st-component-field-labelTypography-lineHeight, 1.4);
62
+ letter-spacing: var(--st-component-field-labelTypography-letterSpacing, 0);
63
+ text-transform: var(--st-component-field-labelTypography-textTransform, none);
60
64
  }
61
65
 
62
66
  .st-field__help,
@@ -73,23 +77,46 @@
73
77
  color: var(--st-component-field-errorText, var(--st-semantic-feedback-error));
74
78
  }
75
79
 
80
+ /* Field style (anatomy v1.2.0) — same resolved field anatomy as Input:
81
+ outline (base) = surface fill + 4 equal borders; filled-underline
82
+ (DSFR/Carbon) = filled bg + bottom rule only. Multiline keeps its own
83
+ vertical padding (block padding can't be 0 like a single-line control). */
76
84
  .st-textarea {
77
- background: var(--st-component-control-background, var(--st-semantic-surface-default));
78
- border: 1px solid var(--st-component-control-border, var(--st-semantic-border-subtle));
79
- border-radius: var(--st-component-control-radius, 0.375rem);
85
+ background: var(--st-component-control-anatomy-field-fillBg, var(--st-component-control-background, var(--st-semantic-surface-default)));
86
+ border-top: var(--st-component-control-anatomy-field-borderTop, var(--st-component-control-anatomy-shape-borderWidth, 1px) var(--st-component-control-anatomy-shape-borderStyle, solid) var(--st-component-control-border, var(--st-semantic-border-subtle)));
87
+ border-right: var(--st-component-control-anatomy-field-borderRight, var(--st-component-control-anatomy-shape-borderWidth, 1px) var(--st-component-control-anatomy-shape-borderStyle, solid) var(--st-component-control-border, var(--st-semantic-border-subtle)));
88
+ border-bottom: var(--st-component-control-anatomy-field-borderBottom, var(--st-component-control-anatomy-shape-borderWidth, 1px) var(--st-component-control-anatomy-shape-borderStyle, solid) var(--st-component-control-border, var(--st-semantic-border-subtle)));
89
+ border-left: var(--st-component-control-anatomy-field-borderLeft, var(--st-component-control-anatomy-shape-borderWidth, 1px) var(--st-component-control-anatomy-shape-borderStyle, solid) var(--st-component-control-border, var(--st-semantic-border-subtle)));
90
+ border-radius: var(--st-component-control-anatomy-shape-radius, 0.375rem);
80
91
  color: var(--st-component-control-text, var(--st-semantic-text-primary));
81
- font: inherit;
92
+ font-family: var(--st-component-control-anatomy-typography-family, inherit);
93
+ font-size: var(--st-component-control-anatomy-typography-size, inherit);
94
+ font-weight: var(--st-component-control-anatomy-typography-weight, 400);
95
+ line-height: var(--st-component-control-anatomy-typography-lineHeight, 1.5);
82
96
  min-height: 6rem;
83
97
  min-width: 0;
84
- padding: 0.625rem 0.75rem;
98
+ padding: 0.625rem var(--st-component-control-anatomy-density-sm-paddingInline, 0.75rem);
85
99
  resize: vertical;
100
+ transition:
101
+ border-color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease),
102
+ box-shadow var(--st-motion-fast, 120ms) var(--st-motion-easing, ease);
86
103
  width: 100%;
87
104
  }
88
105
 
106
+ .st-textarea::placeholder {
107
+ color: var(--st-component-control-placeholderText, var(--st-semantic-text-muted));
108
+ }
109
+
110
+ .st-textarea:hover:not(:disabled) {
111
+ border-color: var(--st-component-control-hoverBorder, var(--st-semantic-border-strong));
112
+ }
113
+
89
114
  .st-textarea:focus-visible {
90
115
  border-color: var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
91
- box-shadow: 0 0 0 2px var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
92
- outline: none;
116
+ outline: var(--st-component-control-anatomy-focus-outline, none);
117
+ outline-offset: var(--st-component-control-anatomy-focus-offset, 0);
118
+ box-shadow: var(--st-component-control-anatomy-focus-boxShadow,
119
+ 0 0 0 2px var(--st-component-control-focusRing, var(--st-semantic-border-interactive)));
93
120
  }
94
121
 
95
122
  .st-textarea[aria-invalid="true"] {
@@ -0,0 +1,165 @@
1
+ <script lang="ts" module>
2
+ export type TileVariant = "static" | "clickable" | "selectable";
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import type { Snippet } from "svelte";
7
+ import type { HTMLAttributes } from "svelte/elements";
8
+
9
+ type TileProps = Omit<HTMLAttributes<HTMLElement>, "class" | "title"> & {
10
+ /** `static` (présentation), `clickable` (lien/bouton), `selectable` (case unitaire). */
11
+ variant?: TileVariant;
12
+ /** Pour `clickable` : si fourni, rend un `<a>`, sinon un `<button>`. */
13
+ href?: string;
14
+ /** Pour `selectable` : état coché (bindable). */
15
+ selected?: boolean;
16
+ disabled?: boolean;
17
+ /** Titre rapide (sinon utiliser le slot `children`). */
18
+ title?: string;
19
+ description?: string;
20
+ class?: string;
21
+ onclick?: (event: MouseEvent) => void;
22
+ /** Pour `selectable` : notifié au changement d'état. */
23
+ onselect?: (selected: boolean) => void;
24
+ children?: Snippet;
25
+ };
26
+
27
+ let {
28
+ variant = "static",
29
+ href,
30
+ selected = $bindable(false),
31
+ disabled = false,
32
+ title,
33
+ description,
34
+ class: className,
35
+ onclick,
36
+ onselect,
37
+ children,
38
+ ...rest
39
+ }: TileProps = $props();
40
+
41
+ const classes = () =>
42
+ [
43
+ "st-tile",
44
+ `st-tile--${variant}`,
45
+ variant === "selectable" && selected ? "st-tile--selected" : null,
46
+ disabled ? "st-tile--disabled" : null,
47
+ className
48
+ ]
49
+ .filter(Boolean)
50
+ .join(" ");
51
+
52
+ function toggle() {
53
+ if (disabled) return;
54
+ selected = !selected;
55
+ onselect?.(selected);
56
+ }
57
+ </script>
58
+
59
+ {#snippet body()}
60
+ {#if children}
61
+ {@render children()}
62
+ {:else}
63
+ {#if title}<span class="st-tile__title">{title}</span>{/if}
64
+ {#if description}<span class="st-tile__description">{description}</span>{/if}
65
+ {/if}
66
+ {/snippet}
67
+
68
+ {#if variant === "clickable" && href}
69
+ <a {...rest} class={classes()} {href} aria-disabled={disabled} {onclick}>
70
+ <span class="st-tile__content">{@render body()}</span>
71
+ </a>
72
+ {:else if variant === "clickable"}
73
+ <button {...rest} type="button" class={classes()} {disabled} {onclick}>
74
+ <span class="st-tile__content">{@render body()}</span>
75
+ </button>
76
+ {:else if variant === "selectable"}
77
+ <label class={classes()}>
78
+ <input
79
+ type="checkbox"
80
+ class="st-tile__input"
81
+ checked={selected}
82
+ {disabled}
83
+ onchange={toggle}
84
+ />
85
+ <span class="st-tile__content">{@render body()}</span>
86
+ </label>
87
+ {:else}
88
+ <div {...rest} class={classes()}>
89
+ <span class="st-tile__content">{@render body()}</span>
90
+ </div>
91
+ {/if}
92
+
93
+ <style>
94
+ .st-tile {
95
+ background: var(--st-component-card-background, var(--st-semantic-surface-raised));
96
+ border: 1px solid var(--st-component-card-border, var(--st-semantic-border-subtle));
97
+ border-radius: var(--st-component-card-radius, 0.5rem);
98
+ color: var(--st-semantic-text-primary);
99
+ display: block;
100
+ padding: var(--st-spacing-4, 1rem);
101
+ text-align: left;
102
+ text-decoration: none;
103
+ width: 100%;
104
+ }
105
+
106
+ /* clickable: <a>/<button> reset + interactivity */
107
+ a.st-tile,
108
+ button.st-tile {
109
+ cursor: pointer;
110
+ font: inherit;
111
+ transition:
112
+ border-color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease),
113
+ box-shadow var(--st-motion-fast, 120ms) var(--st-motion-easing, ease);
114
+ }
115
+
116
+ .st-tile--clickable:hover:not(.st-tile--disabled),
117
+ .st-tile--selectable:hover:not(.st-tile--disabled) {
118
+ border-color: var(--st-component-control-hoverBorder, var(--st-semantic-border-strong));
119
+ }
120
+
121
+ .st-tile--clickable:focus-visible,
122
+ .st-tile--selectable:focus-within {
123
+ border-color: var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
124
+ box-shadow: 0 0 0 2px var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
125
+ outline: none;
126
+ }
127
+
128
+ .st-tile--selectable {
129
+ align-items: start;
130
+ cursor: pointer;
131
+ display: grid;
132
+ gap: var(--st-spacing-2, 0.5rem);
133
+ grid-template-columns: auto 1fr;
134
+ }
135
+
136
+ .st-tile--selected {
137
+ border-color: var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
138
+ box-shadow: 0 0 0 1px var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
139
+ }
140
+
141
+ .st-tile--disabled {
142
+ cursor: not-allowed;
143
+ opacity: 0.55;
144
+ }
145
+
146
+ .st-tile__input {
147
+ accent-color: var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
148
+ margin: 0.2rem 0 0;
149
+ }
150
+
151
+ .st-tile__content {
152
+ display: grid;
153
+ gap: 0.25rem;
154
+ }
155
+
156
+ .st-tile__title {
157
+ font-size: 0.9375rem;
158
+ font-weight: 600;
159
+ }
160
+
161
+ .st-tile__description {
162
+ color: var(--st-component-field-helpText, var(--st-semantic-text-secondary));
163
+ font-size: 0.8125rem;
164
+ }
165
+ </style>
@@ -0,0 +1,24 @@
1
+ export type TileVariant = "static" | "clickable" | "selectable";
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+ type TileProps = Omit<HTMLAttributes<HTMLElement>, "class" | "title"> & {
5
+ /** `static` (présentation), `clickable` (lien/bouton), `selectable` (case unitaire). */
6
+ variant?: TileVariant;
7
+ /** Pour `clickable` : si fourni, rend un `<a>`, sinon un `<button>`. */
8
+ href?: string;
9
+ /** Pour `selectable` : état coché (bindable). */
10
+ selected?: boolean;
11
+ disabled?: boolean;
12
+ /** Titre rapide (sinon utiliser le slot `children`). */
13
+ title?: string;
14
+ description?: string;
15
+ class?: string;
16
+ onclick?: (event: MouseEvent) => void;
17
+ /** Pour `selectable` : notifié au changement d'état. */
18
+ onselect?: (selected: boolean) => void;
19
+ children?: Snippet;
20
+ };
21
+ declare const Tile: import("svelte").Component<TileProps, {}, "selected">;
22
+ type Tile = ReturnType<typeof Tile>;
23
+ export default Tile;
24
+ //# sourceMappingURL=Tile.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tile.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Tile.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,CAAC;AAGlE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG;IACtE,wFAAwF;IACxF,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAwEJ,QAAA,MAAM,IAAI,uDAAwC,CAAC;AACnD,KAAK,IAAI,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;AACpC,eAAe,IAAI,CAAC"}
@@ -101,8 +101,12 @@
101
101
  transform: translateX(calc(var(--st-toggle-trackWidth, 2.25rem) - var(--st-toggle-thumbSize, 1rem) - 0.25rem));
102
102
  }
103
103
 
104
+ /* Focus = stratégie d'anatomie partagée (outline DSFR / inset Carbon / ring base). */
104
105
  .st-toggle__input:focus-visible + .st-toggle__track {
105
- box-shadow: 0 0 0 2px var(--st-component-control-focusRing, var(--st-semantic-border-interactive));
106
+ outline: var(--st-component-control-anatomy-focus-outline, none);
107
+ outline-offset: var(--st-component-control-anatomy-focus-offset, 0);
108
+ box-shadow: var(--st-component-control-anatomy-focus-boxShadow,
109
+ 0 0 0 2px var(--st-component-control-focusRing, var(--st-semantic-border-interactive)));
106
110
  }
107
111
 
108
112
  .st-toggle__input:disabled + .st-toggle__track {