@sentropic/design-system-svelte 0.19.0 → 0.21.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.
- package/dist/BulletChart.svelte +479 -0
- package/dist/BulletChart.svelte.d.ts +32 -0
- package/dist/BulletChart.svelte.d.ts.map +1 -0
- package/dist/BumpChart.svelte +387 -0
- package/dist/BumpChart.svelte.d.ts +35 -0
- package/dist/BumpChart.svelte.d.ts.map +1 -0
- package/dist/CalendarHeatmapChart.svelte +345 -0
- package/dist/CalendarHeatmapChart.svelte.d.ts +28 -0
- package/dist/CalendarHeatmapChart.svelte.d.ts.map +1 -0
- package/dist/CandlestickChart.svelte +333 -0
- package/dist/CandlestickChart.svelte.d.ts +31 -0
- package/dist/CandlestickChart.svelte.d.ts.map +1 -0
- package/dist/FilterBar.svelte +95 -0
- package/dist/FilterBar.svelte.d.ts +15 -0
- package/dist/FilterBar.svelte.d.ts.map +1 -0
- package/dist/FilterPill.svelte +369 -0
- package/dist/FilterPill.svelte.d.ts +22 -0
- package/dist/FilterPill.svelte.d.ts.map +1 -0
- package/dist/MarimekkoChart.svelte +319 -0
- package/dist/MarimekkoChart.svelte.d.ts +35 -0
- package/dist/MarimekkoChart.svelte.d.ts.map +1 -0
- package/dist/ParallelCoordinatesChart.svelte +315 -0
- package/dist/ParallelCoordinatesChart.svelte.d.ts +35 -0
- package/dist/ParallelCoordinatesChart.svelte.d.ts.map +1 -0
- package/dist/SelectionChip.svelte +158 -0
- package/dist/SelectionChip.svelte.d.ts +16 -0
- package/dist/SelectionChip.svelte.d.ts.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CandlestickChart - OHLC (open/high/low/close), bougies vertes/rouges.
|
|
3
|
+
* API canonique (référence Svelte, React/Vue doivent s'aligner)
|
|
4
|
+
*
|
|
5
|
+
* Props obligatoires :
|
|
6
|
+
* data CandlestickChartDatum[] - tableau {label, open, high, low, close}
|
|
7
|
+
* label string
|
|
8
|
+
*
|
|
9
|
+
* Props optionnelles :
|
|
10
|
+
* width number (défaut 480)
|
|
11
|
+
* height number (défaut 240)
|
|
12
|
+
* class string
|
|
13
|
+
*/
|
|
14
|
+
export type CandlestickChartDatum = {
|
|
15
|
+
label: string;
|
|
16
|
+
open: number;
|
|
17
|
+
high: number;
|
|
18
|
+
low: number;
|
|
19
|
+
close: number;
|
|
20
|
+
};
|
|
21
|
+
type CandlestickChartProps = {
|
|
22
|
+
data: CandlestickChartDatum[];
|
|
23
|
+
label: string;
|
|
24
|
+
width?: number;
|
|
25
|
+
height?: number;
|
|
26
|
+
class?: string;
|
|
27
|
+
};
|
|
28
|
+
declare const CandlestickChart: import("svelte").Component<CandlestickChartProps, {}, "">;
|
|
29
|
+
type CandlestickChart = ReturnType<typeof CandlestickChart>;
|
|
30
|
+
export default CandlestickChart;
|
|
31
|
+
//# sourceMappingURL=CandlestickChart.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CandlestickChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/CandlestickChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAMF,KAAK,qBAAqB,GAAG;IAC3B,IAAI,EAAE,qBAAqB,EAAE,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAgLJ,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
export type FilterBarProps = {
|
|
5
|
+
/** Aria-label du groupe de filtres, ex "Filtres actifs". */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Callback "tout effacer" — le bouton n'est rendu que si ce callback est fourni. */
|
|
8
|
+
onClearAll?: () => void;
|
|
9
|
+
/** Libellé du bouton "tout effacer". Défaut "Tout effacer". */
|
|
10
|
+
clearAllLabel?: string;
|
|
11
|
+
children?: Snippet;
|
|
12
|
+
class?: string;
|
|
13
|
+
};
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<script lang="ts">
|
|
17
|
+
let {
|
|
18
|
+
label,
|
|
19
|
+
onClearAll,
|
|
20
|
+
clearAllLabel = "Tout effacer",
|
|
21
|
+
children,
|
|
22
|
+
class: className
|
|
23
|
+
}: FilterBarProps = $props();
|
|
24
|
+
|
|
25
|
+
const classes = $derived(
|
|
26
|
+
["st-filterBar", className].filter(Boolean).join(" ")
|
|
27
|
+
);
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<div class={classes} role="group" aria-label={label}>
|
|
31
|
+
<div class="st-filterBar__pills">
|
|
32
|
+
{@render children?.()}
|
|
33
|
+
</div>
|
|
34
|
+
{#if onClearAll}
|
|
35
|
+
<button
|
|
36
|
+
type="button"
|
|
37
|
+
class="st-filterBar__clearAll"
|
|
38
|
+
onclick={onClearAll}
|
|
39
|
+
>
|
|
40
|
+
{clearAllLabel}
|
|
41
|
+
</button>
|
|
42
|
+
{/if}
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<style>
|
|
46
|
+
.st-filterBar {
|
|
47
|
+
align-items: flex-start;
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-wrap: wrap;
|
|
50
|
+
gap: var(--st-spacing-2, 0.5rem);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.st-filterBar__pills {
|
|
54
|
+
align-items: center;
|
|
55
|
+
display: flex;
|
|
56
|
+
flex: 1 1 auto;
|
|
57
|
+
flex-wrap: wrap;
|
|
58
|
+
gap: var(--st-spacing-2, 0.5rem);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Bouton "tout effacer" — variant discret (ghost-like, texte seul) */
|
|
62
|
+
.st-filterBar__clearAll {
|
|
63
|
+
align-items: center;
|
|
64
|
+
background: transparent;
|
|
65
|
+
border: 0;
|
|
66
|
+
border-radius: var(--st-radius-md, 0.375rem);
|
|
67
|
+
color: var(--st-semantic-text-link, #2563eb);
|
|
68
|
+
cursor: var(--st-cursor-interactive, pointer);
|
|
69
|
+
display: inline-flex;
|
|
70
|
+
font: inherit;
|
|
71
|
+
font-size: 0.8125rem;
|
|
72
|
+
gap: var(--st-spacing-1, 0.25rem);
|
|
73
|
+
padding: 0.3125rem var(--st-spacing-2, 0.5rem);
|
|
74
|
+
transition:
|
|
75
|
+
background-color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease),
|
|
76
|
+
color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease);
|
|
77
|
+
white-space: nowrap;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.st-filterBar__clearAll:hover {
|
|
81
|
+
background: var(--st-semantic-surface-subtle, #f8fafc);
|
|
82
|
+
color: var(--st-semantic-action-primaryHover, #1d4ed8);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.st-filterBar__clearAll:focus-visible {
|
|
86
|
+
outline: 2px solid var(--st-semantic-border-interactive, #2563eb);
|
|
87
|
+
outline-offset: 2px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@media (prefers-reduced-motion: reduce) {
|
|
91
|
+
.st-filterBar__clearAll {
|
|
92
|
+
transition: none;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
export type FilterBarProps = {
|
|
3
|
+
/** Aria-label du groupe de filtres, ex "Filtres actifs". */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Callback "tout effacer" — le bouton n'est rendu que si ce callback est fourni. */
|
|
6
|
+
onClearAll?: () => void;
|
|
7
|
+
/** Libellé du bouton "tout effacer". Défaut "Tout effacer". */
|
|
8
|
+
clearAllLabel?: string;
|
|
9
|
+
children?: Snippet;
|
|
10
|
+
class?: string;
|
|
11
|
+
};
|
|
12
|
+
declare const FilterBar: import("svelte").Component<FilterBarProps, {}, "">;
|
|
13
|
+
type FilterBar = ReturnType<typeof FilterBar>;
|
|
14
|
+
export default FilterBar;
|
|
15
|
+
//# sourceMappingURL=FilterBar.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterBar.svelte.d.ts","sourceRoot":"","sources":["../src/lib/FilterBar.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,MAAM,cAAc,GAAG;IAC3B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAiCJ,QAAA,MAAM,SAAS,oDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export type FilterPillTone = "neutral" | "success" | "warning" | "error" | "info";
|
|
3
|
+
|
|
4
|
+
export type FilterPillProps = {
|
|
5
|
+
/** Nom du champ/dimension affiché à gauche. */
|
|
6
|
+
field: string;
|
|
7
|
+
/** Résumé de la valeur sélectionnée, ex "France, Italie" ou "> 100". */
|
|
8
|
+
value: string;
|
|
9
|
+
/** Opérateur optionnel affiché entre field et value, ex "=", "in", "entre". */
|
|
10
|
+
operator?: string;
|
|
11
|
+
/** Pilule active (aria-pressed). Défaut true. */
|
|
12
|
+
active?: boolean;
|
|
13
|
+
/** Affiche le bouton ✕. Défaut true. */
|
|
14
|
+
removable?: boolean;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
tone?: FilterPillTone;
|
|
17
|
+
onClick?: () => void;
|
|
18
|
+
onRemove?: () => void;
|
|
19
|
+
class?: string;
|
|
20
|
+
};
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<script lang="ts">
|
|
24
|
+
import { X } from "@lucide/svelte";
|
|
25
|
+
|
|
26
|
+
let {
|
|
27
|
+
field,
|
|
28
|
+
value,
|
|
29
|
+
operator,
|
|
30
|
+
active = true,
|
|
31
|
+
removable = true,
|
|
32
|
+
disabled = false,
|
|
33
|
+
tone = "neutral",
|
|
34
|
+
onClick,
|
|
35
|
+
onRemove,
|
|
36
|
+
class: className
|
|
37
|
+
}: FilterPillProps = $props();
|
|
38
|
+
|
|
39
|
+
let bodyEl: HTMLButtonElement | null = $state(null);
|
|
40
|
+
|
|
41
|
+
const groupClasses = $derived(
|
|
42
|
+
[
|
|
43
|
+
"st-filterPill",
|
|
44
|
+
`st-filterPill--${tone}`,
|
|
45
|
+
active ? "st-filterPill--active" : null,
|
|
46
|
+
disabled ? "st-filterPill--disabled" : null,
|
|
47
|
+
className
|
|
48
|
+
]
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
.join(" ")
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Fix #5 : transfert de focus quand le corps-bouton focalisé devient disabled.
|
|
54
|
+
$effect(() => {
|
|
55
|
+
if (typeof document === "undefined") return;
|
|
56
|
+
if (!disabled || !bodyEl) return;
|
|
57
|
+
const container = bodyEl.closest(".st-filterPill");
|
|
58
|
+
if (container && container.contains(document.activeElement)) {
|
|
59
|
+
// Trouver le prochain élément focusable en dehors du composant, sinon body.
|
|
60
|
+
const focusable = document.querySelectorAll<HTMLElement>(
|
|
61
|
+
'a[href], button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
62
|
+
);
|
|
63
|
+
let transferred = false;
|
|
64
|
+
for (const el of Array.from(focusable)) {
|
|
65
|
+
if (!container.contains(el)) {
|
|
66
|
+
el.focus();
|
|
67
|
+
transferred = true;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!transferred) {
|
|
72
|
+
(document.body as HTMLElement).focus();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
function handleClick() {
|
|
78
|
+
if (disabled) return;
|
|
79
|
+
onClick?.();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function handleRemove() {
|
|
83
|
+
if (disabled) return;
|
|
84
|
+
onRemove?.();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Suppr/Backspace sur le corps-bouton → onRemove (si removable).
|
|
88
|
+
// Enter/Space sont gérés nativement par <button> → pas de double-fire.
|
|
89
|
+
function handleBodyKeydown(e: KeyboardEvent) {
|
|
90
|
+
if (disabled) return;
|
|
91
|
+
if ((e.key === "Delete" || e.key === "Backspace") && removable) {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
onRemove?.();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<!--
|
|
99
|
+
Fix #1 : conteneur <span role="group"> NON focusable + deux <button> FRÈRES.
|
|
100
|
+
Plus d'imbrication role="button" avec <button> enfant.
|
|
101
|
+
-->
|
|
102
|
+
<span class={groupClasses} role="group" aria-label={`Filtre ${field}`}>
|
|
103
|
+
{#if onClick}
|
|
104
|
+
<button
|
|
105
|
+
bind:this={bodyEl}
|
|
106
|
+
type="button"
|
|
107
|
+
class="st-filterPill__body"
|
|
108
|
+
aria-pressed={active}
|
|
109
|
+
disabled={disabled || undefined}
|
|
110
|
+
onclick={handleClick}
|
|
111
|
+
onkeydown={handleBodyKeydown}
|
|
112
|
+
>
|
|
113
|
+
<span class="st-filterPill__field">{field}</span>
|
|
114
|
+
{#if operator}
|
|
115
|
+
<span class="st-filterPill__operator" aria-hidden="true">{operator}</span>
|
|
116
|
+
{/if}
|
|
117
|
+
<span class="st-filterPill__value">{value}</span>
|
|
118
|
+
</button>
|
|
119
|
+
{:else}
|
|
120
|
+
<span class="st-filterPill__body st-filterPill__body--static">
|
|
121
|
+
<span class="st-filterPill__field">{field}</span>
|
|
122
|
+
{#if operator}
|
|
123
|
+
<span class="st-filterPill__operator" aria-hidden="true">{operator}</span>
|
|
124
|
+
{/if}
|
|
125
|
+
<span class="st-filterPill__value">{value}</span>
|
|
126
|
+
</span>
|
|
127
|
+
{/if}
|
|
128
|
+
{#if removable}
|
|
129
|
+
<button
|
|
130
|
+
type="button"
|
|
131
|
+
class="st-filterPill__remove"
|
|
132
|
+
aria-label={`Retirer le filtre ${field}`}
|
|
133
|
+
disabled={disabled || undefined}
|
|
134
|
+
onclick={handleRemove}
|
|
135
|
+
>
|
|
136
|
+
<X size={12} strokeWidth={2.5} aria-hidden="true" />
|
|
137
|
+
</button>
|
|
138
|
+
{/if}
|
|
139
|
+
</span>
|
|
140
|
+
|
|
141
|
+
<style>
|
|
142
|
+
/* Conteneur groupe — pas focusable, pas de cursor global */
|
|
143
|
+
.st-filterPill {
|
|
144
|
+
align-items: center;
|
|
145
|
+
border-radius: var(--st-radius-pill, 999px);
|
|
146
|
+
display: inline-flex;
|
|
147
|
+
font-size: 0.8125rem;
|
|
148
|
+
font-weight: 500;
|
|
149
|
+
gap: 0;
|
|
150
|
+
line-height: 1;
|
|
151
|
+
transition:
|
|
152
|
+
background-color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease),
|
|
153
|
+
color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease);
|
|
154
|
+
user-select: none;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* ---------- Tone : neutral (défaut) ---------- */
|
|
158
|
+
.st-filterPill--neutral {
|
|
159
|
+
background: var(--st-semantic-surface-subtle, #f8fafc);
|
|
160
|
+
color: var(--st-semantic-text-secondary, #475569);
|
|
161
|
+
border: 1px solid var(--st-semantic-border-interactive, #cbd5e1);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* ---------- Tone : success ---------- */
|
|
165
|
+
.st-filterPill--success {
|
|
166
|
+
background: color-mix(in srgb, var(--st-semantic-feedback-success, #16a34a) 12%, white);
|
|
167
|
+
color: color-mix(in oklch, var(--st-semantic-feedback-success, #16a34a) 78%, black);
|
|
168
|
+
border: 1px solid color-mix(in srgb, var(--st-semantic-feedback-success, #16a34a) 40%, white);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* ---------- Tone : warning ---------- */
|
|
172
|
+
.st-filterPill--warning {
|
|
173
|
+
background: color-mix(in srgb, var(--st-semantic-feedback-warning, #d97706) 12%, white);
|
|
174
|
+
color: color-mix(in oklch, var(--st-semantic-feedback-warning, #d97706) 78%, black);
|
|
175
|
+
border: 1px solid color-mix(in srgb, var(--st-semantic-feedback-warning, #d97706) 40%, white);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* ---------- Tone : error ---------- */
|
|
179
|
+
.st-filterPill--error {
|
|
180
|
+
background: color-mix(in srgb, var(--st-semantic-feedback-error, #dc2626) 12%, white);
|
|
181
|
+
color: color-mix(in oklch, var(--st-semantic-feedback-error, #dc2626) 78%, black);
|
|
182
|
+
border: 1px solid color-mix(in srgb, var(--st-semantic-feedback-error, #dc2626) 40%, white);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* ---------- Tone : info ---------- */
|
|
186
|
+
.st-filterPill--info {
|
|
187
|
+
background: color-mix(in srgb, var(--st-semantic-feedback-info, #2563eb) 12%, white);
|
|
188
|
+
color: color-mix(in oklch, var(--st-semantic-feedback-info, #2563eb) 78%, black);
|
|
189
|
+
border: 1px solid color-mix(in srgb, var(--st-semantic-feedback-info, #2563eb) 40%, white);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* ---------- État actif — Fix #3 (contraste) + Fix #4 (tone honoré) ----------
|
|
193
|
+
L'état actif renforce le tone courant avec un fond SOLIDE opaque (no transparent)
|
|
194
|
+
et un texte contrasté apparié. La spécificité (0,2,0) surclasse les règles tone
|
|
195
|
+
(0,1,0) — tone est toujours honoré, actif l'intensifie.
|
|
196
|
+
*/
|
|
197
|
+
.st-filterPill--neutral.st-filterPill--active {
|
|
198
|
+
background: var(
|
|
199
|
+
--st-component-filterPill-activeBackground,
|
|
200
|
+
color-mix(in oklch, var(--st-semantic-action-primary, #2563eb) 12%, white)
|
|
201
|
+
);
|
|
202
|
+
color: var(
|
|
203
|
+
--st-component-filterPill-activeText,
|
|
204
|
+
color-mix(in oklch, var(--st-semantic-action-primary, #2563eb) 78%, black)
|
|
205
|
+
);
|
|
206
|
+
border-color: color-mix(in oklch, var(--st-semantic-action-primary, #2563eb) 50%, white);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.st-filterPill--success.st-filterPill--active {
|
|
210
|
+
background: color-mix(in oklch, var(--st-semantic-feedback-success, #16a34a) 78%, black);
|
|
211
|
+
color: white;
|
|
212
|
+
border-color: color-mix(in oklch, var(--st-semantic-feedback-success, #16a34a) 78%, black);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.st-filterPill--warning.st-filterPill--active {
|
|
216
|
+
background: color-mix(in oklch, var(--st-semantic-feedback-warning, #d97706) 78%, black);
|
|
217
|
+
color: white;
|
|
218
|
+
border-color: color-mix(in oklch, var(--st-semantic-feedback-warning, #d97706) 78%, black);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.st-filterPill--error.st-filterPill--active {
|
|
222
|
+
background: color-mix(in oklch, var(--st-semantic-feedback-error, #dc2626) 78%, black);
|
|
223
|
+
color: white;
|
|
224
|
+
border-color: color-mix(in oklch, var(--st-semantic-feedback-error, #dc2626) 78%, black);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.st-filterPill--info.st-filterPill--active {
|
|
228
|
+
background: color-mix(in oklch, var(--st-semantic-feedback-info, #2563eb) 78%, black);
|
|
229
|
+
color: white;
|
|
230
|
+
border-color: color-mix(in oklch, var(--st-semantic-feedback-info, #2563eb) 78%, black);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* Fallback moteurs sans color-mix */
|
|
234
|
+
@supports not (color: color-mix(in oklch, red, blue)) {
|
|
235
|
+
.st-filterPill--neutral.st-filterPill--active {
|
|
236
|
+
background: var(
|
|
237
|
+
--st-component-filterPill-activeBackground,
|
|
238
|
+
var(--st-semantic-surface-subtle, #eef2ff)
|
|
239
|
+
);
|
|
240
|
+
color: var(
|
|
241
|
+
--st-component-filterPill-activeText,
|
|
242
|
+
var(--st-semantic-action-primary, #1d4ed8)
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
.st-filterPill--success.st-filterPill--active {
|
|
246
|
+
background: var(--st-semantic-feedback-success, #16a34a);
|
|
247
|
+
color: white;
|
|
248
|
+
}
|
|
249
|
+
.st-filterPill--warning.st-filterPill--active {
|
|
250
|
+
background: var(--st-semantic-feedback-warning, #d97706);
|
|
251
|
+
color: white;
|
|
252
|
+
}
|
|
253
|
+
.st-filterPill--error.st-filterPill--active {
|
|
254
|
+
background: var(--st-semantic-feedback-error, #dc2626);
|
|
255
|
+
color: white;
|
|
256
|
+
}
|
|
257
|
+
.st-filterPill--info.st-filterPill--active {
|
|
258
|
+
background: var(--st-semantic-feedback-info, #2563eb);
|
|
259
|
+
color: white;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.st-filterPill--disabled {
|
|
264
|
+
cursor: var(--st-cursor-disabled, not-allowed);
|
|
265
|
+
opacity: 0.55;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* Corps bouton / span statique */
|
|
269
|
+
.st-filterPill__body {
|
|
270
|
+
align-items: center;
|
|
271
|
+
background: transparent;
|
|
272
|
+
border: 0;
|
|
273
|
+
border-radius: var(--st-radius-pill, 999px) 0 0 var(--st-radius-pill, 999px);
|
|
274
|
+
color: inherit;
|
|
275
|
+
cursor: var(--st-cursor-interactive, pointer);
|
|
276
|
+
display: inline-flex;
|
|
277
|
+
font: inherit;
|
|
278
|
+
gap: var(--st-spacing-1, 0.25rem);
|
|
279
|
+
line-height: 1;
|
|
280
|
+
padding: 0.3125rem var(--st-spacing-1, 0.25rem) 0.3125rem var(--st-spacing-2, 0.5rem);
|
|
281
|
+
transition:
|
|
282
|
+
background-color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease),
|
|
283
|
+
color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Corps statique (sans onClick) : arrondi complet si pas de ✕ */
|
|
287
|
+
.st-filterPill__body--static {
|
|
288
|
+
cursor: default;
|
|
289
|
+
padding: 0.3125rem var(--st-spacing-2, 0.5rem);
|
|
290
|
+
border-radius: var(--st-radius-pill, 999px);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/* Quand le ✕ est présent, le statique garde arrondi à gauche seulement */
|
|
294
|
+
.st-filterPill:has(.st-filterPill__remove) .st-filterPill__body--static {
|
|
295
|
+
border-radius: var(--st-radius-pill, 999px) 0 0 var(--st-radius-pill, 999px);
|
|
296
|
+
padding-right: var(--st-spacing-1, 0.25rem);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.st-filterPill__body:not(:disabled):hover {
|
|
300
|
+
opacity: 0.88;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.st-filterPill__body:focus-visible {
|
|
304
|
+
outline: 2px solid var(--st-semantic-border-interactive, var(--st-semantic-action-primary, #2563eb));
|
|
305
|
+
outline-offset: 2px;
|
|
306
|
+
border-radius: var(--st-radius-pill, 999px);
|
|
307
|
+
z-index: 1;
|
|
308
|
+
position: relative;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.st-filterPill__body:disabled {
|
|
312
|
+
cursor: var(--st-cursor-disabled, not-allowed);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.st-filterPill__operator {
|
|
316
|
+
color: var(--st-semantic-text-muted, #64748b);
|
|
317
|
+
font-size: 0.75em;
|
|
318
|
+
font-style: italic;
|
|
319
|
+
margin-inline: 0.125rem;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.st-filterPill__value {
|
|
323
|
+
max-width: 12rem;
|
|
324
|
+
overflow: hidden;
|
|
325
|
+
text-overflow: ellipsis;
|
|
326
|
+
white-space: nowrap;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.st-filterPill__remove {
|
|
330
|
+
align-items: center;
|
|
331
|
+
background: transparent;
|
|
332
|
+
border: 0;
|
|
333
|
+
border-radius: 0 var(--st-radius-pill, 999px) var(--st-radius-pill, 999px) 0;
|
|
334
|
+
color: inherit;
|
|
335
|
+
cursor: pointer;
|
|
336
|
+
display: inline-flex;
|
|
337
|
+
font: inherit;
|
|
338
|
+
height: 100%;
|
|
339
|
+
justify-content: center;
|
|
340
|
+
line-height: 1;
|
|
341
|
+
padding: 0.3125rem var(--st-spacing-2, 0.5rem) 0.3125rem var(--st-spacing-1, 0.25rem);
|
|
342
|
+
transition: background-color var(--st-motion-fast, 120ms) var(--st-motion-easing, ease);
|
|
343
|
+
min-width: 1.75rem;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.st-filterPill__remove:hover:not(:disabled) {
|
|
347
|
+
background: color-mix(in srgb, currentColor 12%, transparent);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.st-filterPill__remove:focus-visible {
|
|
351
|
+
outline: 2px solid currentColor;
|
|
352
|
+
outline-offset: 1px;
|
|
353
|
+
border-radius: var(--st-radius-pill, 999px);
|
|
354
|
+
z-index: 1;
|
|
355
|
+
position: relative;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.st-filterPill__remove:disabled {
|
|
359
|
+
cursor: var(--st-cursor-disabled, not-allowed);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
@media (prefers-reduced-motion: reduce) {
|
|
363
|
+
.st-filterPill,
|
|
364
|
+
.st-filterPill__body,
|
|
365
|
+
.st-filterPill__remove {
|
|
366
|
+
transition: none;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type FilterPillTone = "neutral" | "success" | "warning" | "error" | "info";
|
|
2
|
+
export type FilterPillProps = {
|
|
3
|
+
/** Nom du champ/dimension affiché à gauche. */
|
|
4
|
+
field: string;
|
|
5
|
+
/** Résumé de la valeur sélectionnée, ex "France, Italie" ou "> 100". */
|
|
6
|
+
value: string;
|
|
7
|
+
/** Opérateur optionnel affiché entre field et value, ex "=", "in", "entre". */
|
|
8
|
+
operator?: string;
|
|
9
|
+
/** Pilule active (aria-pressed). Défaut true. */
|
|
10
|
+
active?: boolean;
|
|
11
|
+
/** Affiche le bouton ✕. Défaut true. */
|
|
12
|
+
removable?: boolean;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
tone?: FilterPillTone;
|
|
15
|
+
onClick?: () => void;
|
|
16
|
+
onRemove?: () => void;
|
|
17
|
+
class?: string;
|
|
18
|
+
};
|
|
19
|
+
declare const FilterPill: import("svelte").Component<FilterPillProps, {}, "">;
|
|
20
|
+
type FilterPill = ReturnType<typeof FilterPill>;
|
|
21
|
+
export default FilterPill;
|
|
22
|
+
//# sourceMappingURL=FilterPill.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterPill.svelte.d.ts","sourceRoot":"","sources":["../src/lib/FilterPill.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAElF,MAAM,MAAM,eAAe,GAAG;IAC5B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAgHJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|