@websline/system-components 1.0.10-beta → 1.0.12

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.
@@ -34,7 +34,7 @@
34
34
  <Comp
35
35
  aria-hidden={title ? undefined : "true"}
36
36
  aria-label={title || undefined}
37
- class={`cms-icon ${className}`}
37
+ class={`cms-icon${className ? ` ${className}` : ""}`}
38
38
  {color}
39
39
  height={wh}
40
40
  role={title ? "img" : undefined}
@@ -6,7 +6,7 @@ import { tv } from "tailwind-variants";
6
6
  const inputBaseVariant = tv({
7
7
  slots: {
8
8
  base: [
9
- "w-full rounded-lg bg-transparent px-4 body-small",
9
+ "w-full rounded-lg px-4 body-small",
10
10
  "text-neutral-900 placeholder-neutral-500 dark:text-neutral-200",
11
11
  "bg-white dark:bg-neutral-800",
12
12
  "outline-transparent transition-[border,color,outline] duration-300",
@@ -29,9 +29,9 @@ const inputBaseVariant = tv({
29
29
  error: false,
30
30
  class: {
31
31
  base: [
32
- "hover:ring-1 focus:ring-1",
33
- "hover:border-blue-500 hover:ring-blue-500 focus:border-blue-500 focus:ring-blue-500",
34
- "dark:hover:border-blue-400 dark:hover:ring-blue-400 dark:focus:border-blue-400 dark:focus:ring-blue-400",
32
+ "focus-within:ring-1 hover:ring-1",
33
+ "focus-within:border-blue-500 focus-within:ring-blue-500 hover:border-blue-500 hover:ring-blue-500",
34
+ "dark:focus-within:border-blue-400 dark:focus-within:ring-blue-400 dark:hover:border-blue-400 dark:hover:ring-blue-400",
35
35
  ],
36
36
  },
37
37
  },
@@ -30,7 +30,6 @@
30
30
  required = false,
31
31
  value = $bindable(),
32
32
  variant = "default",
33
-
34
33
  ...rest
35
34
  } = $props();
36
35
 
@@ -0,0 +1,111 @@
1
+ <script>
2
+ import { Icon } from "../../../index.js";
3
+ import { onDestroy, onMount } from "svelte";
4
+ import { tagSelectorVariants } from "./tagSelector.variants.js";
5
+
6
+ let {
7
+ filtered,
8
+ highlighted,
9
+ inputRef,
10
+ labelCreate,
11
+ localValues,
12
+ onCreateItem,
13
+ onSelectItem,
14
+ query,
15
+ showCreate,
16
+ value = [],
17
+ ...rest
18
+ } = $props();
19
+
20
+ let styles = $derived(tagSelectorVariants());
21
+
22
+ let dropdownPosition = $state("bottom");
23
+ let dropdownMaxHeight = $state(200);
24
+
25
+ const attachHighlightedItem = (item) => {
26
+ if (inputRef) {
27
+ // so the screen reader can read the highlighted option aloud
28
+ if (item.id) inputRef.setAttribute("aria-activedescendant", item.id);
29
+ else inputRef.removeAttribute("aria-activedescendant");
30
+ }
31
+
32
+ // maybe scroll item into view
33
+ if (item.offsetTop < item.offsetParent.scrollTop)
34
+ item.scrollIntoView({ block: "nearest" });
35
+ else if (
36
+ item.offsetTop + item.offsetHeight >
37
+ item.offsetParent.scrollTop + item.offsetParent.offsetHeight
38
+ )
39
+ item.scrollIntoView({ block: "nearest" });
40
+ };
41
+
42
+ const updateDropdownPosition = () => {
43
+ if (!inputRef) return;
44
+
45
+ const rect = inputRef.getBoundingClientRect();
46
+ const spaceBelow = window.innerHeight - rect.bottom;
47
+ const spaceAbove = rect.top;
48
+
49
+ dropdownPosition = spaceBelow > spaceAbove ? "bottom" : "top";
50
+
51
+ dropdownMaxHeight =
52
+ dropdownPosition === "bottom"
53
+ ? Math.min(300, spaceBelow - 24)
54
+ : Math.min(300, spaceAbove - 24);
55
+ };
56
+
57
+ const getOptionId = (itemId) =>
58
+ `${localValues?.id ?? "tagselector"}-option-${itemId}`;
59
+
60
+ onMount(() => updateDropdownPosition());
61
+ onDestroy(() => {
62
+ inputRef?.removeAttribute("aria-activedescendant");
63
+ });
64
+ </script>
65
+
66
+ <svelte:window onscroll={updateDropdownPosition} onresize={updateDropdownPosition} />
67
+
68
+ <div
69
+ class={styles.dropdown({ dropdownPosition })}
70
+ id={localValues.id}
71
+ role="listbox"
72
+ style={`max-height: ${dropdownMaxHeight}px`}
73
+ tabindex="-1"
74
+ {...rest}>
75
+ {#snippet option({ highlighted, id, label, selected, ...rest })}
76
+ <button
77
+ aria-selected={selected}
78
+ {@attach highlighted ? attachHighlightedItem : null}
79
+ class={styles.dropdownItem()}
80
+ data-highlighted={highlighted}
81
+ {id}
82
+ role="option"
83
+ tabindex="-1"
84
+ {...rest}>
85
+ {label}
86
+ {#if selected}
87
+ <Icon class={styles.dropdownCheckmark()} name="check" size={16} />
88
+ {/if}
89
+ </button>
90
+ {/snippet}
91
+
92
+ {#each filtered as item, i (item.id)}
93
+ {@render option({
94
+ highlighted: highlighted === i,
95
+ id: getOptionId(item.id),
96
+ label: item.label,
97
+ selected: value.includes(item.id),
98
+ onclick: () => onSelectItem(item.id),
99
+ })}
100
+ {/each}
101
+
102
+ {#if showCreate}
103
+ {@render option({
104
+ highlighted: highlighted === filtered.length,
105
+ id: getOptionId("create"),
106
+ label: `${labelCreate}: "${query}"`,
107
+ selected: false,
108
+ onclick: onCreateItem,
109
+ })}
110
+ {/if}
111
+ </div>
@@ -0,0 +1,29 @@
1
+ export default Dropdown;
2
+ type Dropdown = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Dropdown: import("svelte").Component<{
7
+ filtered: any;
8
+ highlighted: any;
9
+ inputRef: any;
10
+ labelCreate: any;
11
+ localValues: any;
12
+ onCreateItem: any;
13
+ onSelectItem: any;
14
+ query: any;
15
+ showCreate: any;
16
+ value?: any[];
17
+ } & Record<string, any>, {}, "">;
18
+ type $$ComponentProps = {
19
+ filtered: any;
20
+ highlighted: any;
21
+ inputRef: any;
22
+ labelCreate: any;
23
+ localValues: any;
24
+ onCreateItem: any;
25
+ onSelectItem: any;
26
+ query: any;
27
+ showCreate: any;
28
+ value?: any[];
29
+ } & Record<string, any>;
@@ -0,0 +1,241 @@
1
+ <script>
2
+ import { getContext } from "svelte";
3
+ import Dropdown from "./Dropdown.svelte";
4
+ import ValueList from "./ValueList.svelte";
5
+ import { tagSelectorVariants } from "./tagSelector.variants.js";
6
+
7
+ /**
8
+ * @typedef {Object} Props
9
+ * @property {boolean} [autofocus=false] Whether the input should be autofocused on mount
10
+ * @property {string} [class=""] Additional CSS classes to apply to the component
11
+ * @property {boolean} [disabled=false] Whether the component is disabled
12
+ * @property {string} [id=""] The ID of the input element
13
+ * @property {string} [labelCreate=""] The label for the create new tag option
14
+ * @property {string} [name] The name of the input, used for form submission
15
+ * @property {Array<{id: string | number, label: string}>} [options=[]] The available tag options
16
+ * @property {string} [placeholder=""] The placeholder text for the input
17
+ * @property {Array<string | number>} [value=[]] The currently selected tags, bound to the component
18
+ */
19
+
20
+ /** @type {Props} */
21
+ let {
22
+ autofocus = false,
23
+ class: className = "",
24
+ disabled = false,
25
+ id = "",
26
+ labelCreate = "",
27
+ name,
28
+ options = [],
29
+ placeholder = "",
30
+ value = $bindable([]),
31
+ ...rest
32
+ } = $props();
33
+
34
+ let store = getContext("form-field-store");
35
+
36
+ let localValues = $derived.by(() => {
37
+ if (store) {
38
+ return {
39
+ ...store(),
40
+ };
41
+ }
42
+
43
+ return {
44
+ disabled,
45
+ id,
46
+ };
47
+ });
48
+
49
+ let open = $state(false);
50
+ let query = $state("");
51
+ let highlighted = $state(-1);
52
+
53
+ let inputRef = $state();
54
+ let rootRef = $state();
55
+
56
+ let normalized = $derived(query.trim().toLowerCase());
57
+
58
+ let filtered = $derived(
59
+ options.filter((i) => i.label.toLowerCase().includes(normalized)),
60
+ );
61
+
62
+ let showCreate = $derived(
63
+ normalized.length > 0 &&
64
+ !filtered.some((i) => i.label.toLowerCase() === normalized),
65
+ );
66
+
67
+ $effect(() => {
68
+ if (autofocus && inputRef) inputRef.focus();
69
+ });
70
+
71
+ const openDropdown = () => {
72
+ open = true;
73
+ highlighted = -1;
74
+ };
75
+
76
+ const closeDropdown = () => {
77
+ open = false;
78
+ highlighted = -1;
79
+ };
80
+
81
+ const dispatchChange = () => {
82
+ rootRef.dispatchEvent(new CustomEvent("change", { detail: value }));
83
+ };
84
+
85
+ const dispatchCreate = (item) => {
86
+ rootRef.dispatchEvent(new CustomEvent("create", { detail: item }));
87
+ };
88
+
89
+ const refocusInput = () => {
90
+ query = "";
91
+ open = true;
92
+ requestAnimationFrame(() => inputRef?.focus());
93
+ };
94
+
95
+ const removeItem = (id) => {
96
+ value = value.filter((vId) => vId !== id);
97
+ dispatchChange();
98
+ };
99
+
100
+ const selectItem = (id) => {
101
+ if (value.includes(id)) {
102
+ removeItem(id);
103
+ } else {
104
+ value = [...value, id];
105
+ dispatchChange();
106
+ }
107
+
108
+ refocusInput();
109
+ };
110
+
111
+ const handleFocusOut = (e) => {
112
+ const next = e.relatedTarget;
113
+
114
+ if (next && rootRef.contains(next)) return;
115
+ if (document.activeElement === inputRef) return;
116
+
117
+ closeDropdown();
118
+ };
119
+
120
+ const createItem = () => {
121
+ const label = query.trim();
122
+ if (label === "") return; // also reset here?
123
+
124
+ const lower = label.toLowerCase();
125
+
126
+ const preset = options.find((i) => i.label.toLowerCase() === lower);
127
+
128
+ if (preset) {
129
+ const alreadySelected = value.includes(preset.id);
130
+
131
+ if (!alreadySelected) {
132
+ value = [...value, preset.id];
133
+ dispatchChange();
134
+ }
135
+
136
+ refocusInput();
137
+ return;
138
+ }
139
+
140
+ const selectedMatch = value.find(
141
+ (id) => typeof id === "string" && id.toLowerCase() === lower,
142
+ );
143
+
144
+ if (!selectedMatch) {
145
+ value = [...value, label];
146
+ dispatchChange();
147
+ dispatchCreate(label);
148
+ }
149
+
150
+ refocusInput();
151
+ };
152
+
153
+ const handleKey = (e) => {
154
+ if (!open) return;
155
+
156
+ const total = filtered.length + (showCreate ? 1 : 0);
157
+ const presetHighlighted = highlighted >= 0 && highlighted < filtered.length;
158
+
159
+ if (e.key === "ArrowDown") {
160
+ e.preventDefault();
161
+ highlighted = (highlighted + 1) % total;
162
+ return;
163
+ }
164
+
165
+ if (e.key === "ArrowUp") {
166
+ e.preventDefault();
167
+ highlighted = (highlighted - 1 + total) % total;
168
+ return;
169
+ }
170
+
171
+ if (e.key === "Escape") {
172
+ e.preventDefault();
173
+ if (normalized === "") open = false;
174
+ else refocusInput();
175
+ return;
176
+ }
177
+
178
+ if (e.key === "Enter" || (e.key === " " && presetHighlighted)) {
179
+ e.preventDefault();
180
+
181
+ if (presetHighlighted) {
182
+ selectItem(filtered[highlighted].id);
183
+ return;
184
+ }
185
+
186
+ if (showCreate && highlighted === filtered.length) {
187
+ createItem();
188
+ return;
189
+ }
190
+
191
+ if (normalized !== "") {
192
+ createItem();
193
+ return;
194
+ }
195
+ }
196
+ };
197
+
198
+ let styles = $derived(tagSelectorVariants({ disabled: localValues.disabled }));
199
+ </script>
200
+
201
+ <div
202
+ bind:this={rootRef}
203
+ aria-expanded={open}
204
+ class={styles.base({ class: className })}
205
+ onfocusout={handleFocusOut}
206
+ role="combobox"
207
+ {...open
208
+ ? {
209
+ "aria-controls": localValues.id,
210
+ "aria-haspopup": "listbox",
211
+ "aria-owns": localValues.id,
212
+ }
213
+ : {}}
214
+ {...rest}>
215
+ <input {name} readonly type="hidden" value={value.join(",")} />
216
+ <ValueList
217
+ bind:inputRef
218
+ {localValues}
219
+ onKeydown={handleKey}
220
+ onOpenDropdown={openDropdown}
221
+ onRemoveItem={removeItem}
222
+ {open}
223
+ {options}
224
+ {placeholder}
225
+ bind:query
226
+ {value} />
227
+
228
+ {#if open}
229
+ <Dropdown
230
+ {filtered}
231
+ {highlighted}
232
+ {inputRef}
233
+ {labelCreate}
234
+ {localValues}
235
+ onCreateItem={createItem}
236
+ onSelectItem={selectItem}
237
+ {query}
238
+ {showCreate}
239
+ {value} />
240
+ {/if}
241
+ </div>
@@ -0,0 +1,87 @@
1
+ export default TagSelector;
2
+ type TagSelector = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<Props>): void;
5
+ };
6
+ declare const TagSelector: import("svelte").Component<{
7
+ /**
8
+ * Whether the input should be autofocused on mount
9
+ */
10
+ autofocus?: boolean;
11
+ /**
12
+ * Additional CSS classes to apply to the component
13
+ */
14
+ class?: string;
15
+ /**
16
+ * Whether the component is disabled
17
+ */
18
+ disabled?: boolean;
19
+ /**
20
+ * The ID of the input element
21
+ */
22
+ id?: string;
23
+ /**
24
+ * The label for the create new tag option
25
+ */
26
+ labelCreate?: string;
27
+ /**
28
+ * The name of the input, used for form submission
29
+ */
30
+ name?: string;
31
+ /**
32
+ * The available tag options
33
+ */
34
+ options?: Array<{
35
+ id: string | number;
36
+ label: string;
37
+ }>;
38
+ /**
39
+ * The placeholder text for the input
40
+ */
41
+ placeholder?: string;
42
+ /**
43
+ * The currently selected tags, bound to the component
44
+ */
45
+ value?: Array<string | number>;
46
+ }, {}, "value">;
47
+ type Props = {
48
+ /**
49
+ * Whether the input should be autofocused on mount
50
+ */
51
+ autofocus?: boolean;
52
+ /**
53
+ * Additional CSS classes to apply to the component
54
+ */
55
+ class?: string;
56
+ /**
57
+ * Whether the component is disabled
58
+ */
59
+ disabled?: boolean;
60
+ /**
61
+ * The ID of the input element
62
+ */
63
+ id?: string;
64
+ /**
65
+ * The label for the create new tag option
66
+ */
67
+ labelCreate?: string;
68
+ /**
69
+ * The name of the input, used for form submission
70
+ */
71
+ name?: string;
72
+ /**
73
+ * The available tag options
74
+ */
75
+ options?: Array<{
76
+ id: string | number;
77
+ label: string;
78
+ }>;
79
+ /**
80
+ * The placeholder text for the input
81
+ */
82
+ placeholder?: string;
83
+ /**
84
+ * The currently selected tags, bound to the component
85
+ */
86
+ value?: Array<string | number>;
87
+ };
@@ -0,0 +1,52 @@
1
+ <script>
2
+ import { Chip } from "../../../index.js";
3
+ import { tagSelectorVariants } from "./tagSelector.variants.js";
4
+
5
+ let {
6
+ inputRef = $bindable(),
7
+ localValues,
8
+ onKeydown,
9
+ onOpenDropdown,
10
+ onRemoveItem,
11
+ open = false,
12
+ options = [],
13
+ placeholder,
14
+ query = $bindable(),
15
+ value = [],
16
+ } = $props();
17
+
18
+ let styles = $derived(tagSelectorVariants());
19
+ </script>
20
+
21
+ <div class={styles.valueList()}>
22
+ {#each value as s (s)}
23
+ {@const opt = options.find((i) => i.id === s)}
24
+ <Chip
25
+ class={styles.item()}
26
+ clickable
27
+ icon="closeSmall"
28
+ onclick={() => onRemoveItem(s)}>
29
+ {opt?.label ?? s}
30
+ </Chip>
31
+ {/each}
32
+
33
+ {#if !localValues.disabled}
34
+ <Chip class={styles.searchField()} icon="add" variant="outline">
35
+ <input
36
+ bind:this={inputRef}
37
+ bind:value={query}
38
+ autocomplete="off"
39
+ class={styles.searchInput()}
40
+ onfocus={onOpenDropdown}
41
+ oninput={onOpenDropdown}
42
+ onkeydown={onKeydown}
43
+ {...open
44
+ ? {
45
+ "aria-controls": localValues.id,
46
+ }
47
+ : {}}
48
+ {placeholder}
49
+ role="searchbox" />
50
+ </Chip>
51
+ {/if}
52
+ </div>
@@ -0,0 +1,29 @@
1
+ export default ValueList;
2
+ type ValueList = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const ValueList: import("svelte").Component<{
7
+ inputRef?: any;
8
+ localValues: any;
9
+ onKeydown: any;
10
+ onOpenDropdown: any;
11
+ onRemoveItem: any;
12
+ open?: boolean;
13
+ options?: any[];
14
+ placeholder: any;
15
+ query?: any;
16
+ value?: any[];
17
+ }, {}, "inputRef" | "query">;
18
+ type $$ComponentProps = {
19
+ inputRef?: any;
20
+ localValues: any;
21
+ onKeydown: any;
22
+ onOpenDropdown: any;
23
+ onRemoveItem: any;
24
+ open?: boolean;
25
+ options?: any[];
26
+ placeholder: any;
27
+ query?: any;
28
+ value?: any[];
29
+ };
@@ -0,0 +1,71 @@
1
+ export const tagSelectorVariants: import("tailwind-variants").TVReturnType<{
2
+ dropdownPosition: {
3
+ bottom: {
4
+ dropdown: string;
5
+ };
6
+ top: {
7
+ dropdown: string;
8
+ };
9
+ };
10
+ }, {
11
+ base: string;
12
+ valueList: string;
13
+ item: string;
14
+ searchField: string;
15
+ searchInput: string;
16
+ dropdown: string;
17
+ dropdownCheckmark: string;
18
+ dropdownItem: string[];
19
+ }, undefined, {
20
+ disabled: {
21
+ true: {
22
+ base: string;
23
+ };
24
+ };
25
+ error: {
26
+ true: {
27
+ base: string;
28
+ };
29
+ };
30
+ }, {
31
+ base: string[];
32
+ }, import("tailwind-variants").TVReturnType<{
33
+ disabled: {
34
+ true: {
35
+ base: string;
36
+ };
37
+ };
38
+ error: {
39
+ true: {
40
+ base: string;
41
+ };
42
+ };
43
+ }, {
44
+ base: string[];
45
+ }, undefined, {
46
+ disabled: {
47
+ true: {
48
+ base: string;
49
+ };
50
+ };
51
+ error: {
52
+ true: {
53
+ base: string;
54
+ };
55
+ };
56
+ }, {
57
+ base: string[];
58
+ }, import("tailwind-variants").TVReturnType<{
59
+ disabled: {
60
+ true: {
61
+ base: string;
62
+ };
63
+ };
64
+ error: {
65
+ true: {
66
+ base: string;
67
+ };
68
+ };
69
+ }, {
70
+ base: string[];
71
+ }, undefined, unknown, unknown, undefined>>>;
@@ -0,0 +1,36 @@
1
+ import { tv } from "tailwind-variants";
2
+ import { inputBaseVariant } from "../../atoms/input/input.variants.js";
3
+
4
+ const tagSelectorVariants = tv({
5
+ extend: inputBaseVariant,
6
+ slots: {
7
+ base: "relative min-h-10 p-1",
8
+ valueList: "flex flex-wrap gap-1",
9
+ item: "h-7.5",
10
+ searchField: "relative h-7.5 w-30",
11
+ searchInput:
12
+ "absolute inset-0 appearance-none border-0 bg-transparent pr-1 pl-8 ui-tag-badge placeholder-current focus:ring-0",
13
+ dropdown:
14
+ "absolute w-full max-w-100 overflow-y-auto bg-white p-1 pr-5 shadow-sm dark:border-neutral-700 dark:bg-neutral-800",
15
+ dropdownCheckmark: "ml-auto shrink-0",
16
+ dropdownItem: [
17
+ "flex w-full grow items-center gap-2 rounded-sm p-2 ui-select-label",
18
+ "bg-white dark:bg-neutral-800",
19
+ "bg-linear-to-r to-transparent",
20
+ "cursor-pointer text-neutral-900 hover:from-black/15 dark:text-neutral-200 dark:hover:from-white/15",
21
+ "data-[highlighted=true]:from-black/15 dark:data-[highlighted=true]:from-white/15",
22
+ ],
23
+ },
24
+ variants: {
25
+ dropdownPosition: {
26
+ bottom: {
27
+ dropdown: "top-full mt-1",
28
+ },
29
+ top: {
30
+ dropdown: "bottom-full mb-1",
31
+ },
32
+ },
33
+ },
34
+ });
35
+
36
+ export { tagSelectorVariants };
package/dist/index.d.ts CHANGED
@@ -25,6 +25,7 @@ export { default as FormLayout } from "./components/molecules/formLayout/FormLay
25
25
  export { default as Notification } from "./components/molecules/notification/Notification.svelte";
26
26
  export { default as RichTextEditor } from "./components/molecules/richTextEditor/RichTextEditor.svelte";
27
27
  export { default as SelectorCard } from "./components/molecules/selectorCard/SelectorCard.svelte";
28
+ export { default as TagSelector } from "./components/molecules/tagSelector/TagSelector.svelte";
28
29
  export { default as ToggleGroup } from "./components/molecules/toggleGroup/ToggleGroup.svelte";
29
30
  export { default as ToggleGroupItem } from "./components/molecules/toggleGroup/ToggleGroupItem.svelte";
30
31
  export * as Dialog from "./components/organisms/dialog/index.js";
package/dist/index.js CHANGED
@@ -35,6 +35,7 @@ export { default as FormLayout } from "./components/molecules/formLayout/FormLay
35
35
  export { default as Notification } from "./components/molecules/notification/Notification.svelte";
36
36
  export { default as RichTextEditor } from "./components/molecules/richTextEditor/RichTextEditor.svelte";
37
37
  export { default as SelectorCard } from "./components/molecules/selectorCard/SelectorCard.svelte";
38
+ export { default as TagSelector } from "./components/molecules/tagSelector/TagSelector.svelte";
38
39
  export { default as ToggleGroup } from "./components/molecules/toggleGroup/ToggleGroup.svelte";
39
40
  export { default as ToggleGroupItem } from "./components/molecules/toggleGroup/ToggleGroupItem.svelte";
40
41
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@websline/system-components",
3
- "version": "1.0.10-beta",
3
+ "version": "1.0.12",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -44,37 +44,37 @@
44
44
  },
45
45
  "devDependencies": {
46
46
  "@eslint/compat": "^2.0.0",
47
- "@eslint/js": "^9.39.1",
48
- "@storybook/addon-a11y": "^10.1.6",
49
- "@storybook/addon-docs": "^10.1.6",
47
+ "@eslint/js": "^9.39.2",
48
+ "@storybook/addon-a11y": "^10.1.10",
49
+ "@storybook/addon-docs": "^10.1.10",
50
50
  "@storybook/addon-svelte-csf": "^5.0.10",
51
- "@storybook/sveltekit": "^10.1.6",
51
+ "@storybook/sveltekit": "^10.1.10",
52
52
  "@sveltejs/adapter-auto": "^7.0.0",
53
53
  "@sveltejs/kit": "^2.49.2",
54
54
  "@sveltejs/package": "^2.5.7",
55
55
  "@sveltejs/vite-plugin-svelte": "^6.2.1",
56
- "@tailwindcss/forms": "^0.5.10",
56
+ "@tailwindcss/forms": "^0.5.11",
57
57
  "@tailwindcss/typography": "^0.5.19",
58
- "@tailwindcss/vite": "^4.1.17",
59
- "@types/node": "^24.10.2",
60
- "@vitest/browser": "^4.0.15",
61
- "eslint": "^9.39.1",
58
+ "@tailwindcss/vite": "^4.1.18",
59
+ "@types/node": "^25.0.3",
60
+ "@vitest/browser": "^4.0.16",
61
+ "eslint": "^9.39.2",
62
62
  "eslint-config-prettier": "^10.1.8",
63
- "eslint-plugin-storybook": "^10.1.6",
63
+ "eslint-plugin-storybook": "^10.1.10",
64
64
  "eslint-plugin-svelte": "^3.13.1",
65
65
  "globals": "^16.5.0",
66
66
  "playwright": "^1.57.0",
67
67
  "postcss-url": "^10.1.3",
68
68
  "prettier": "^3.7.4",
69
- "prettier-plugin-svelte": "^3.4.0",
69
+ "prettier-plugin-svelte": "^3.4.1",
70
70
  "prettier-plugin-tailwindcss": "^0.7.2",
71
71
  "publint": "^0.3.16",
72
- "storybook": "^10.1.6",
73
- "svelte": "^5.45.8",
74
- "tailwindcss": "^4.1.17",
72
+ "storybook": "^10.1.10",
73
+ "svelte": "^5.46.0",
74
+ "tailwindcss": "^4.1.18",
75
75
  "typescript": "^5.9.3",
76
- "vite": "^7.2.7",
77
- "vitest": "^4.0.15",
76
+ "vite": "^7.3.0",
77
+ "vitest": "^4.0.16",
78
78
  "vitest-browser-svelte": "^2.0.1"
79
79
  },
80
80
  "keywords": [