@sentropic/design-system-svelte 0.6.0 → 0.8.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 (96) hide show
  1. package/dist/Accordion.svelte +11 -3
  2. package/dist/Accordion.svelte.d.ts.map +1 -1
  3. package/dist/Alert.svelte +1 -1
  4. package/dist/AreaChart.svelte +414 -0
  5. package/dist/AreaChart.svelte.d.ts +18 -0
  6. package/dist/AreaChart.svelte.d.ts.map +1 -0
  7. package/dist/AspectRatio.svelte +44 -0
  8. package/dist/AspectRatio.svelte.d.ts +11 -0
  9. package/dist/AspectRatio.svelte.d.ts.map +1 -0
  10. package/dist/BarChart.svelte +383 -0
  11. package/dist/BarChart.svelte.d.ts +18 -0
  12. package/dist/BarChart.svelte.d.ts.map +1 -0
  13. package/dist/ChatComposer.svelte +238 -0
  14. package/dist/ChatComposer.svelte.d.ts +57 -0
  15. package/dist/ChatComposer.svelte.d.ts.map +1 -0
  16. package/dist/ChatMessage.svelte +271 -0
  17. package/dist/ChatMessage.svelte.d.ts +19 -0
  18. package/dist/ChatMessage.svelte.d.ts.map +1 -0
  19. package/dist/ChatThread.svelte +120 -0
  20. package/dist/ChatThread.svelte.d.ts +13 -0
  21. package/dist/ChatThread.svelte.d.ts.map +1 -0
  22. package/dist/CodeSnippet.svelte +91 -0
  23. package/dist/CodeSnippet.svelte.d.ts +13 -0
  24. package/dist/CodeSnippet.svelte.d.ts.map +1 -0
  25. package/dist/Combobox.svelte +16 -2
  26. package/dist/Combobox.svelte.d.ts.map +1 -1
  27. package/dist/CopyButton.svelte +3 -7
  28. package/dist/CopyButton.svelte.d.ts.map +1 -1
  29. package/dist/Drawer.svelte +23 -3
  30. package/dist/Drawer.svelte.d.ts +1 -1
  31. package/dist/Drawer.svelte.d.ts.map +1 -1
  32. package/dist/Dropdown.svelte +38 -2
  33. package/dist/Dropdown.svelte.d.ts.map +1 -1
  34. package/dist/FileUploader.svelte +119 -4
  35. package/dist/FileUploader.svelte.d.ts +1 -0
  36. package/dist/FileUploader.svelte.d.ts.map +1 -1
  37. package/dist/IconButton.svelte +103 -0
  38. package/dist/IconButton.svelte.d.ts +15 -0
  39. package/dist/IconButton.svelte.d.ts.map +1 -0
  40. package/dist/InlineLoading.svelte +22 -14
  41. package/dist/InlineLoading.svelte.d.ts.map +1 -1
  42. package/dist/LineChart.svelte +397 -0
  43. package/dist/LineChart.svelte.d.ts +19 -0
  44. package/dist/LineChart.svelte.d.ts.map +1 -0
  45. package/dist/Menu.svelte +164 -24
  46. package/dist/Menu.svelte.d.ts +26 -4
  47. package/dist/Menu.svelte.d.ts.map +1 -1
  48. package/dist/MenuPopover.svelte +180 -0
  49. package/dist/MenuPopover.svelte.d.ts +17 -0
  50. package/dist/MenuPopover.svelte.d.ts.map +1 -0
  51. package/dist/MenuTriggerButton.svelte +50 -0
  52. package/dist/MenuTriggerButton.svelte.d.ts +16 -0
  53. package/dist/MenuTriggerButton.svelte.d.ts.map +1 -0
  54. package/dist/MessageActions.svelte +89 -0
  55. package/dist/MessageActions.svelte.d.ts +22 -0
  56. package/dist/MessageActions.svelte.d.ts.map +1 -0
  57. package/dist/MessageStatusBadge.svelte +52 -0
  58. package/dist/MessageStatusBadge.svelte.d.ts +12 -0
  59. package/dist/MessageStatusBadge.svelte.d.ts.map +1 -0
  60. package/dist/Modal.svelte +83 -3
  61. package/dist/Modal.svelte.d.ts.map +1 -1
  62. package/dist/MultiSelect.svelte +17 -3
  63. package/dist/MultiSelect.svelte.d.ts.map +1 -1
  64. package/dist/OverflowMenu.svelte +111 -24
  65. package/dist/OverflowMenu.svelte.d.ts +21 -2
  66. package/dist/OverflowMenu.svelte.d.ts.map +1 -1
  67. package/dist/PaginationNav.svelte +6 -21
  68. package/dist/PaginationNav.svelte.d.ts.map +1 -1
  69. package/dist/PasswordInput.svelte +3 -9
  70. package/dist/PasswordInput.svelte.d.ts.map +1 -1
  71. package/dist/ProgressIndicator.svelte +3 -19
  72. package/dist/ProgressIndicator.svelte.d.ts.map +1 -1
  73. package/dist/Search.svelte +3 -6
  74. package/dist/Search.svelte.d.ts.map +1 -1
  75. package/dist/Sparkline.svelte +123 -0
  76. package/dist/Sparkline.svelte.d.ts +15 -0
  77. package/dist/Sparkline.svelte.d.ts.map +1 -0
  78. package/dist/StreamingMessage.svelte +292 -0
  79. package/dist/StreamingMessage.svelte.d.ts +51 -0
  80. package/dist/StreamingMessage.svelte.d.ts.map +1 -0
  81. package/dist/StructuredList.svelte +86 -0
  82. package/dist/StructuredList.svelte.d.ts +15 -0
  83. package/dist/StructuredList.svelte.d.ts.map +1 -0
  84. package/dist/Tag.svelte +2 -1
  85. package/dist/Tag.svelte.d.ts.map +1 -1
  86. package/dist/TileGroup.svelte +179 -0
  87. package/dist/TileGroup.svelte.d.ts +21 -0
  88. package/dist/TileGroup.svelte.d.ts.map +1 -0
  89. package/dist/Toast.svelte +2 -2
  90. package/dist/UnorderedList.svelte +108 -0
  91. package/dist/UnorderedList.svelte.d.ts +16 -0
  92. package/dist/UnorderedList.svelte.d.ts.map +1 -0
  93. package/dist/index.d.ts +23 -0
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +16 -0
  96. package/package.json +3 -2
@@ -0,0 +1,180 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ type MenuPopoverProps = Omit<HTMLAttributes<HTMLDivElement>, "class"> & {
6
+ open?: boolean;
7
+ trigger: HTMLElement | null;
8
+ placement?: "bottom-start" | "bottom-end" | "top-start" | "top-end";
9
+ align?: "start" | "end" | "center";
10
+ label: string;
11
+ class?: string;
12
+ closeOnOutside?: boolean;
13
+ closeOnEscape?: boolean;
14
+ children?: Snippet;
15
+ };
16
+
17
+ let {
18
+ open = $bindable(false),
19
+ trigger,
20
+ placement = "bottom-start",
21
+ align,
22
+ label,
23
+ class: className,
24
+ closeOnOutside = true,
25
+ closeOnEscape = true,
26
+ children,
27
+ ...rest
28
+ }: MenuPopoverProps = $props();
29
+
30
+ let panel: HTMLDivElement | undefined = $state();
31
+ let top = $state(0);
32
+ let left = $state(0);
33
+ let alignmentRight = $state(false);
34
+ let alignmentCenter = $state(false);
35
+
36
+ const GAP = 4;
37
+
38
+ function computePosition() {
39
+ if (!trigger) return;
40
+ const rect = trigger.getBoundingClientRect();
41
+ const verticalUp = placement === "top-start" || placement === "top-end";
42
+ const horizontalEnd = placement === "bottom-end" || placement === "top-end";
43
+
44
+ // Resolve secondary alignment override (align prop overrides the placement's horizontal cue).
45
+ const resolvedAlign: "start" | "end" | "center" = align
46
+ ?? (horizontalEnd ? "end" : "start");
47
+
48
+ alignmentRight = resolvedAlign === "end";
49
+ alignmentCenter = resolvedAlign === "center";
50
+
51
+ if (verticalUp) {
52
+ // We don't know the panel height yet on first frame; position the panel's
53
+ // bottom edge above the trigger using transform.
54
+ top = rect.top + window.scrollY - GAP;
55
+ } else {
56
+ top = rect.bottom + window.scrollY + GAP;
57
+ }
58
+
59
+ if (resolvedAlign === "end") {
60
+ left = rect.right + window.scrollX;
61
+ } else if (resolvedAlign === "center") {
62
+ left = rect.left + window.scrollX + rect.width / 2;
63
+ } else {
64
+ left = rect.left + window.scrollX;
65
+ }
66
+ }
67
+
68
+ $effect(() => {
69
+ if (!open) return;
70
+ computePosition();
71
+ const onScroll = () => computePosition();
72
+ const onResize = () => computePosition();
73
+ window.addEventListener("scroll", onScroll, true);
74
+ window.addEventListener("resize", onResize);
75
+ return () => {
76
+ window.removeEventListener("scroll", onScroll, true);
77
+ window.removeEventListener("resize", onResize);
78
+ };
79
+ });
80
+
81
+ function isWithin(event: Event, node: HTMLElement | null | undefined): boolean {
82
+ if (!node) return false;
83
+ const path = typeof (event as Event & { composedPath?: () => EventTarget[] }).composedPath === "function"
84
+ ? (event as Event & { composedPath: () => EventTarget[] }).composedPath()
85
+ : [];
86
+ if (path.includes(node)) return true;
87
+ const target = event.target as Node | null;
88
+ return Boolean(target && node.contains(target));
89
+ }
90
+
91
+ function onWindowPointerDown(event: PointerEvent) {
92
+ if (!open || !closeOnOutside) return;
93
+ if (isWithin(event, panel)) return;
94
+ if (isWithin(event, trigger)) return;
95
+ open = false;
96
+ }
97
+
98
+ function onWindowKeyDown(event: KeyboardEvent) {
99
+ if (!open || !closeOnEscape) return;
100
+ if (event.key === "Escape") {
101
+ event.preventDefault();
102
+ open = false;
103
+ }
104
+ }
105
+
106
+ const classes = () =>
107
+ [
108
+ "st-menuPopover",
109
+ `st-menuPopover--${placement}`,
110
+ alignmentRight ? "st-menuPopover--alignEnd" : null,
111
+ alignmentCenter ? "st-menuPopover--alignCenter" : null,
112
+ className
113
+ ]
114
+ .filter(Boolean)
115
+ .join(" ");
116
+ </script>
117
+
118
+ <svelte:window onpointerdown={onWindowPointerDown} onkeydown={onWindowKeyDown} />
119
+
120
+ {#if open}
121
+ <div
122
+ {...rest}
123
+ bind:this={panel}
124
+ class={classes()}
125
+ role="dialog"
126
+ aria-label={label}
127
+ style={`top: ${top}px; left: ${left}px;`}
128
+ >
129
+ {@render children?.()}
130
+ </div>
131
+ {/if}
132
+
133
+ <style>
134
+ .st-menuPopover {
135
+ background: var(--st-component-menu-background, var(--st-semantic-surface-raised, #ffffff));
136
+ border: 1px solid var(--st-component-menu-border, var(--st-semantic-border-subtle));
137
+ border-radius: var(--st-component-menu-radius, 0.375rem);
138
+ box-shadow: var(--st-component-menu-shadow, 0 8px 24px rgb(15 23 42 / 0.14));
139
+ color: var(--st-component-menu-text, var(--st-semantic-text-primary));
140
+ min-width: var(--st-component-menu-minWidth, 12rem);
141
+ max-width: var(--st-component-menu-maxWidth, 18rem);
142
+ max-height: calc(100vh - 2rem);
143
+ overflow: auto;
144
+ padding: 0;
145
+ position: absolute;
146
+ z-index: var(--st-component-popover-zIndex, 80);
147
+ }
148
+
149
+ /* Default origin: left edge aligned to trigger left. */
150
+ .st-menuPopover--alignEnd {
151
+ /* Move the panel left by 100% of its width so its right edge aligns to `left`. */
152
+ transform: translateX(-100%);
153
+ }
154
+
155
+ .st-menuPopover--alignCenter {
156
+ transform: translateX(-50%);
157
+ }
158
+
159
+ /* For top placements, the `top` value is the trigger's top edge; shift the
160
+ panel up by 100% of its height so its bottom edge sits above the trigger. */
161
+ .st-menuPopover--top-start {
162
+ transform: translateY(-100%);
163
+ }
164
+
165
+ .st-menuPopover--top-end {
166
+ transform: translate(-100%, -100%);
167
+ }
168
+
169
+ .st-menuPopover--top-start.st-menuPopover--alignEnd {
170
+ transform: translate(-100%, -100%);
171
+ }
172
+
173
+ .st-menuPopover--top-start.st-menuPopover--alignCenter {
174
+ transform: translate(-50%, -100%);
175
+ }
176
+
177
+ .st-menuPopover--top-end.st-menuPopover--alignCenter {
178
+ transform: translate(-50%, -100%);
179
+ }
180
+ </style>
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ type MenuPopoverProps = Omit<HTMLAttributes<HTMLDivElement>, "class"> & {
4
+ open?: boolean;
5
+ trigger: HTMLElement | null;
6
+ placement?: "bottom-start" | "bottom-end" | "top-start" | "top-end";
7
+ align?: "start" | "end" | "center";
8
+ label: string;
9
+ class?: string;
10
+ closeOnOutside?: boolean;
11
+ closeOnEscape?: boolean;
12
+ children?: Snippet;
13
+ };
14
+ declare const MenuPopover: import("svelte").Component<MenuPopoverProps, {}, "open">;
15
+ type MenuPopover = ReturnType<typeof MenuPopover>;
16
+ export default MenuPopover;
17
+ //# sourceMappingURL=MenuPopover.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MenuPopover.svelte.d.ts","sourceRoot":"","sources":["../src/lib/MenuPopover.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,GAAG;IACtE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;IACpE,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAuHJ,QAAA,MAAM,WAAW,0DAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,50 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLButtonAttributes } from "svelte/elements";
4
+ import { ChevronDownCircle } from "@lucide/svelte";
5
+ import IconButton from "./IconButton.svelte";
6
+
7
+ type MenuTriggerButtonProps = Omit<
8
+ HTMLButtonAttributes,
9
+ "class" | "type" | "aria-label" | "aria-haspopup" | "aria-expanded" | "aria-controls"
10
+ > & {
11
+ "aria-label": string;
12
+ "aria-controls"?: string;
13
+ expanded?: boolean;
14
+ size?: "sm" | "md" | "lg";
15
+ variant?: "ghost" | "secondary";
16
+ disabled?: boolean;
17
+ class?: string;
18
+ children?: Snippet;
19
+ };
20
+
21
+ let {
22
+ "aria-label": ariaLabel,
23
+ "aria-controls": ariaControls,
24
+ expanded = false,
25
+ size = "md",
26
+ variant = "ghost",
27
+ disabled = false,
28
+ class: className,
29
+ children,
30
+ ...rest
31
+ }: MenuTriggerButtonProps = $props();
32
+ </script>
33
+
34
+ <IconButton
35
+ {...rest}
36
+ aria-label={ariaLabel}
37
+ aria-haspopup="menu"
38
+ aria-expanded={expanded}
39
+ aria-controls={ariaControls}
40
+ {size}
41
+ {variant}
42
+ {disabled}
43
+ class={className}
44
+ >
45
+ {#if children}
46
+ {@render children()}
47
+ {:else}
48
+ <ChevronDownCircle size={18} strokeWidth={2} aria-hidden="true" />
49
+ {/if}
50
+ </IconButton>
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLButtonAttributes } from "svelte/elements";
3
+ type MenuTriggerButtonProps = Omit<HTMLButtonAttributes, "class" | "type" | "aria-label" | "aria-haspopup" | "aria-expanded" | "aria-controls"> & {
4
+ "aria-label": string;
5
+ "aria-controls"?: string;
6
+ expanded?: boolean;
7
+ size?: "sm" | "md" | "lg";
8
+ variant?: "ghost" | "secondary";
9
+ disabled?: boolean;
10
+ class?: string;
11
+ children?: Snippet;
12
+ };
13
+ declare const MenuTriggerButton: import("svelte").Component<MenuTriggerButtonProps, {}, "">;
14
+ type MenuTriggerButton = ReturnType<typeof MenuTriggerButton>;
15
+ export default MenuTriggerButton;
16
+ //# sourceMappingURL=MenuTriggerButton.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MenuTriggerButton.svelte.d.ts","sourceRoot":"","sources":["../src/lib/MenuTriggerButton.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAK1D,KAAK,sBAAsB,GAAG,IAAI,CAChC,oBAAoB,EACpB,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,eAAe,GAAG,eAAe,GAAG,eAAe,CACtF,GAAG;IACF,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA+BJ,QAAA,MAAM,iBAAiB,4DAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,89 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import IconButton from "./IconButton.svelte";
4
+ import type { HTMLAttributes } from "svelte/elements";
5
+
6
+ export type MessageActionVariant = "default" | "danger";
7
+
8
+ export type MessageAction = {
9
+ id: string;
10
+ label: string;
11
+ icon: Snippet;
12
+ onClick?: () => void;
13
+ disabled?: boolean;
14
+ variant?: MessageActionVariant;
15
+ };
16
+
17
+ type MessageActionsVisibility = "always" | "hover";
18
+
19
+ type MessageActionsProps = Omit<HTMLAttributes<HTMLElement>, "children" | "class"> & {
20
+ actions: MessageAction[];
21
+ visibility?: MessageActionsVisibility;
22
+ overflow?: Snippet;
23
+ class?: string;
24
+ };
25
+
26
+ let {
27
+ actions = [],
28
+ visibility = "hover",
29
+ overflow,
30
+ class: className,
31
+ ...rest
32
+ }: MessageActionsProps = $props();
33
+
34
+ const classes = () =>
35
+ ["st-messageActions", visibility === "hover" && "st-messageActions--hoverOnly", className]
36
+ .filter(Boolean)
37
+ .join(" ");
38
+ </script>
39
+
40
+ <div class={classes()} {...rest} role="group" aria-label="Actions du message">
41
+ {#if actions.length > 0}
42
+ {#each actions as action (action.id)}
43
+ <IconButton
44
+ size="sm"
45
+ variant={action.variant === "danger" ? "danger" : "ghost"}
46
+ aria-label={action.label}
47
+ disabled={action.disabled}
48
+ onclick={action.onClick}
49
+ >
50
+ {@render action.icon()}
51
+ </IconButton>
52
+ {/each}
53
+ {/if}
54
+ {#if overflow}
55
+ <div class="st-messageActions__overflow">{@render overflow()}</div>
56
+ {/if}
57
+ </div>
58
+
59
+ <style>
60
+ .st-messageActions {
61
+ align-items: center;
62
+ display: inline-flex;
63
+ gap: 0.25rem;
64
+ }
65
+
66
+ .st-messageActions--hoverOnly {
67
+ opacity: 0;
68
+ pointer-events: none;
69
+ transition:
70
+ opacity var(--st-motion-fast, 120ms) var(--st-motion-easing, ease);
71
+ }
72
+
73
+ .st-messageActions--hoverOnly:focus-within,
74
+ .st-messageActions--hoverOnly:hover {
75
+ opacity: 1;
76
+ pointer-events: auto;
77
+ }
78
+
79
+ @media (prefers-reduced-motion: reduce) {
80
+ .st-messageActions--hoverOnly {
81
+ transition: none;
82
+ }
83
+ }
84
+
85
+ .st-messageActions__overflow {
86
+ align-items: center;
87
+ display: inline-flex;
88
+ }
89
+ </style>
@@ -0,0 +1,22 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ export type MessageActionVariant = "default" | "danger";
4
+ export type MessageAction = {
5
+ id: string;
6
+ label: string;
7
+ icon: Snippet;
8
+ onClick?: () => void;
9
+ disabled?: boolean;
10
+ variant?: MessageActionVariant;
11
+ };
12
+ type MessageActionsVisibility = "always" | "hover";
13
+ type MessageActionsProps = Omit<HTMLAttributes<HTMLElement>, "children" | "class"> & {
14
+ actions: MessageAction[];
15
+ visibility?: MessageActionsVisibility;
16
+ overflow?: Snippet;
17
+ class?: string;
18
+ };
19
+ declare const MessageActions: import("svelte").Component<MessageActionsProps, {}, "">;
20
+ type MessageActions = ReturnType<typeof MessageActions>;
21
+ export default MessageActions;
22
+ //# sourceMappingURL=MessageActions.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageActions.svelte.d.ts","sourceRoot":"","sources":["../src/lib/MessageActions.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAExD,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC,CAAC;AAEF,KAAK,wBAAwB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEnD,KAAK,mBAAmB,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,GAAG;IACnF,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAyCJ,QAAA,MAAM,cAAc,yDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -0,0 +1,52 @@
1
+ <script lang="ts">
2
+ import Tag from "./Tag.svelte";
3
+ import type { ChatMessageStatus } from "./ChatMessage.svelte";
4
+ import type { HTMLAttributes } from "svelte/elements";
5
+
6
+ type StatusTone = "neutral" | "success" | "warning" | "error" | "info";
7
+
8
+ type MessageStatusBadgeProps = Omit<HTMLAttributes<HTMLSpanElement>, "children"> & {
9
+ status: ChatMessageStatus;
10
+ tone?: StatusTone;
11
+ class?: string;
12
+ };
13
+
14
+ let { status, tone, class: className, ...rest }: MessageStatusBadgeProps = $props();
15
+
16
+ const mappedTone = () => {
17
+ if (tone) return tone;
18
+ if (status === "processing") return "info";
19
+ if (status === "failed") return "error";
20
+ if (status === "completed") return "success";
21
+ return "warning";
22
+ };
23
+
24
+ const label = () => {
25
+ if (status === "pending") return "En attente";
26
+ if (status === "processing") return "En cours";
27
+ if (status === "completed") return "Terminé";
28
+ return "Échec";
29
+ };
30
+
31
+ const classes = () => ["st-messageStatusBadge", className].filter(Boolean).join(" ");
32
+ </script>
33
+
34
+ <Tag tone={mappedTone()} size="sm" class={classes()} {...rest} aria-label={`Statut: ${label()}`}>
35
+ <span class="st-messageStatusBadge__dot" aria-hidden="true"></span>
36
+ {label()}
37
+ </Tag>
38
+
39
+ <style>
40
+ .st-messageStatusBadge {
41
+ align-items: center;
42
+ text-transform: none;
43
+ }
44
+
45
+ .st-messageStatusBadge__dot {
46
+ background: currentColor;
47
+ border-radius: 999px;
48
+ display: inline-block;
49
+ height: 0.38rem;
50
+ width: 0.38rem;
51
+ }
52
+ </style>
@@ -0,0 +1,12 @@
1
+ import type { ChatMessageStatus } from "./ChatMessage.svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ type StatusTone = "neutral" | "success" | "warning" | "error" | "info";
4
+ type MessageStatusBadgeProps = Omit<HTMLAttributes<HTMLSpanElement>, "children"> & {
5
+ status: ChatMessageStatus;
6
+ tone?: StatusTone;
7
+ class?: string;
8
+ };
9
+ declare const MessageStatusBadge: import("svelte").Component<MessageStatusBadgeProps, {}, "">;
10
+ type MessageStatusBadge = ReturnType<typeof MessageStatusBadge>;
11
+ export default MessageStatusBadge;
12
+ //# sourceMappingURL=MessageStatusBadge.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageStatusBadge.svelte.d.ts","sourceRoot":"","sources":["../src/lib/MessageStatusBadge.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAEvE,KAAK,uBAAuB,GAAG,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,EAAE,UAAU,CAAC,GAAG;IACjF,MAAM,EAAE,iBAAiB,CAAC;IAC1B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAqCJ,QAAA,MAAM,kBAAkB,6DAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
package/dist/Modal.svelte CHANGED
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import { X } from "@lucide/svelte";
3
+ import { tick } from "svelte";
2
4
  import type { Snippet } from "svelte";
3
5
  import type { HTMLAttributes } from "svelte/elements";
4
6
 
@@ -25,19 +27,97 @@
25
27
  ...rest
26
28
  }: ModalProps = $props();
27
29
 
30
+ let dialog: HTMLElement | undefined = $state();
31
+ let closeButton: HTMLButtonElement | undefined = $state();
32
+ let previousFocus: HTMLElement | null = null;
28
33
  const classes = () => ["st-modal", className].filter(Boolean).join(" ");
34
+
35
+ const focusableSelector = [
36
+ "a[href]",
37
+ "button:not([disabled])",
38
+ "input:not([disabled])",
39
+ "select:not([disabled])",
40
+ "textarea:not([disabled])",
41
+ "[tabindex]:not([tabindex='-1'])"
42
+ ].join(",");
43
+
44
+ $effect(() => {
45
+ if (!open) return;
46
+ previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
47
+ tick().then(() => closeButton?.focus());
48
+ });
49
+
50
+ function requestClose() {
51
+ onclose?.();
52
+ tick().then(() => previousFocus?.focus());
53
+ }
54
+
55
+ function trapFocus(event: KeyboardEvent) {
56
+ if (!dialog || event.key !== "Tab") return;
57
+ const focusable = Array.from(dialog.querySelectorAll<HTMLElement>(focusableSelector));
58
+
59
+ if (focusable.length === 0) {
60
+ event.preventDefault();
61
+ dialog.focus();
62
+ return;
63
+ }
64
+
65
+ const first = focusable[0];
66
+ const last = focusable.at(-1);
67
+ const active = document.activeElement;
68
+
69
+ if (!dialog.contains(active)) {
70
+ event.preventDefault();
71
+ first.focus();
72
+ return;
73
+ }
74
+
75
+ if (event.shiftKey && active === first) {
76
+ event.preventDefault();
77
+ last?.focus();
78
+ } else if (!event.shiftKey && active === last) {
79
+ event.preventDefault();
80
+ first.focus();
81
+ }
82
+ }
83
+
84
+ function onWindowKeydown(event: KeyboardEvent) {
85
+ if (!open) return;
86
+ if (event.key === "Escape") {
87
+ event.preventDefault();
88
+ requestClose();
89
+ return;
90
+ }
91
+ trapFocus(event);
92
+ }
29
93
  </script>
30
94
 
95
+ <svelte:window onkeydown={onWindowKeydown} />
96
+
31
97
  {#if open}
32
98
  <div class="st-modal__backdrop">
33
- <section {...rest} class={classes()} role="dialog" aria-modal="true" aria-label={title}>
99
+ <section
100
+ {...rest}
101
+ bind:this={dialog}
102
+ class={classes()}
103
+ role="dialog"
104
+ aria-modal="true"
105
+ aria-label={title}
106
+ tabindex="-1"
107
+ >
34
108
  <header class="st-modal__header">
35
109
  <div>
36
110
  <h2 class="st-modal__title">{title}</h2>
37
111
  {#if description}<p class="st-modal__description">{description}</p>{/if}
38
112
  </div>
39
- <button class="st-modal__close" type="button" aria-label={closeLabel} onclick={onclose}>
40
- <span aria-hidden="true">x</span>
113
+ <button
114
+ bind:this={closeButton}
115
+ class="st-modal__close"
116
+ type="button"
117
+ aria-label={closeLabel}
118
+ onclick={requestClose}
119
+ >
120
+ <X size={18} strokeWidth={2.25} aria-hidden="true" />
41
121
  </button>
42
122
  </header>
43
123
  <div class="st-modal__body">
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Modal.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,GAAG;IAC7D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAiDJ,QAAA,MAAM,KAAK,gDAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Modal.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,GAAG;IAC7D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAmHJ,QAAA,MAAM,KAAK,gDAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -7,6 +7,7 @@
7
7
  </script>
8
8
 
9
9
  <script lang="ts">
10
+ import { ChevronDown, X } from "@lucide/svelte";
10
11
  import type { HTMLAttributes } from "svelte/elements";
11
12
 
12
13
  type MultiSelectProps = Omit<HTMLAttributes<HTMLDivElement>, "class" | "onchange"> & {
@@ -115,7 +116,7 @@
115
116
  {disabled}
116
117
  onclick={() => removeOption(option.value)}
117
118
  >
118
- <span aria-hidden="true">×</span>
119
+ <X size={14} strokeWidth={2.25} aria-hidden="true" />
119
120
  </button>
120
121
  </span>
121
122
  {/each}
@@ -135,7 +136,13 @@
135
136
  {:else}
136
137
  <span class="st-multiSelect__count">{selectedOptions.length} selected</span>
137
138
  {/if}
138
- <span class="st-multiSelect__caret" aria-hidden="true">▾</span>
139
+ <span class="st-multiSelect__caret" aria-hidden="true">
140
+ <ChevronDown
141
+ class={`st-multiSelect__caretIcon ${expanded ? "st-multiSelect__caretIcon--open" : ""}`}
142
+ size={18}
143
+ strokeWidth={2.25}
144
+ />
145
+ </span>
139
146
  <span class="st-visually-hidden">{toggleLabel}</span>
140
147
  </button>
141
148
  </span>
@@ -342,11 +349,18 @@
342
349
  color: var(--st-semantic-text-secondary);
343
350
  display: inline-flex;
344
351
  flex: 0 0 auto;
345
- font-size: 0.875rem;
346
352
  margin-inline-start: auto;
347
353
  padding-inline-start: 0.25rem;
348
354
  }
349
355
 
356
+ .st-multiSelect__caretIcon {
357
+ transition: transform var(--st-motion-fast, 120ms) var(--st-motion-easing, ease);
358
+ }
359
+
360
+ .st-multiSelect__caretIcon--open {
361
+ transform: rotate(180deg);
362
+ }
363
+
350
364
  .st-multiSelect__panel {
351
365
  background: var(--st-component-dropdown-background, var(--st-semantic-surface-default));
352
366
  border: 1px solid var(--st-component-dropdown-border, var(--st-semantic-border-subtle));
@@ -1 +1 @@
1
- {"version":3,"file":"MultiSelect.svelte.d.ts","sourceRoot":"","sources":["../src/lib/MultiSelect.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACzC,CAAC;AAkIJ,QAAA,MAAM,WAAW,8DAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"MultiSelect.svelte.d.ts","sourceRoot":"","sources":["../src/lib/MultiSelect.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACzC,CAAC;AAqIJ,QAAA,MAAM,WAAW,8DAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}