@r2digisolutions/components 0.5.0 → 0.6.1

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 (36) hide show
  1. package/dist/components/atoms/Button/Button.stories.d.ts +6 -0
  2. package/dist/components/atoms/Button/Button.stories.js +7 -0
  3. package/dist/components/atoms/Button/Button.svelte +15 -17
  4. package/dist/components/atoms/Button/Button.svelte.d.ts +1 -0
  5. package/dist/components/atoms/Button/ButtonStory.svelte +2 -0
  6. package/dist/components/atoms/Button/ButtonStory.svelte.d.ts +1 -0
  7. package/dist/components/molecules/Combobox/Combobox.stories.d.ts +6 -0
  8. package/dist/components/molecules/Combobox/Combobox.stories.js +5 -2
  9. package/dist/components/molecules/Combobox/Combobox.svelte +155 -64
  10. package/dist/components/molecules/Combobox/Combobox.svelte.d.ts +15 -0
  11. package/dist/components/molecules/Combobox/ComboboxStory.svelte +25 -12
  12. package/dist/components/molecules/Combobox/ComboboxStory.svelte.d.ts +1 -0
  13. package/dist/components/molecules/Combobox/combobox-context.d.ts +12 -0
  14. package/dist/components/molecules/Combobox/combobox-context.js +10 -0
  15. package/dist/components/molecules/ComboboxItem/ComboboxItem.stories.d.ts +9 -0
  16. package/dist/components/molecules/ComboboxItem/ComboboxItem.stories.js +8 -0
  17. package/dist/components/molecules/ComboboxItem/ComboboxItem.svelte +121 -0
  18. package/dist/components/molecules/ComboboxItem/ComboboxItem.svelte.d.ts +33 -0
  19. package/dist/components/molecules/ComboboxItem/ComboboxItemStory.svelte +54 -0
  20. package/dist/components/molecules/ComboboxItem/ComboboxItemStory.svelte.d.ts +3 -0
  21. package/dist/components/molecules/Form/Form.svelte +36 -10
  22. package/dist/components/molecules/FormField/FormField.svelte +56 -19
  23. package/dist/components/molecules/FormField/FormField.svelte.d.ts +21 -6
  24. package/dist/components/molecules/FormPasswordInput/FormPasswordInput.svelte +38 -9
  25. package/dist/components/molecules/FormPasswordInput/FormPasswordInput.svelte.d.ts +8 -1
  26. package/dist/components/organisms/BlogEditor/BlogEditorStory.svelte +1 -1
  27. package/dist/components/organisms/FileUploader/FileUploader.svelte +7 -3
  28. package/dist/components/organisms/InvoicePage/InvoicePage.svelte +1 -1
  29. package/dist/components/organisms/ProfileHeaderUploader/ProfileHeaderUploader.svelte +30 -10
  30. package/dist/components/organisms/ProfileHeaderUploader/ProfileHeaderUploader.svelte.d.ts +4 -0
  31. package/dist/index.d.ts +6 -3
  32. package/dist/index.js +3 -1
  33. package/dist/styles.css +6 -0
  34. package/dist/utils/formContext.d.ts +58 -0
  35. package/dist/utils/formContext.js +79 -1
  36. package/package.json +16 -16
@@ -17,6 +17,10 @@
17
17
  label?: string;
18
18
  coverHelperText?: string;
19
19
  avatarHelperText?: string;
20
+ /** Existing remote cover URL (shown when no local File is selected). */
21
+ coverSrc?: string;
22
+ /** Existing remote avatar URL (shown when no local File is selected). */
23
+ avatarSrc?: string;
20
24
  accept?: string;
21
25
  maxCoverMb?: number;
22
26
  maxAvatarMb?: number;
@@ -30,6 +34,8 @@
30
34
  label = 'Profile media',
31
35
  coverHelperText = 'Cover · PNG or JPG · max 10MB',
32
36
  avatarHelperText = 'Avatar · square image recommended',
37
+ coverSrc = '',
38
+ avatarSrc = '',
33
39
  accept = 'image/*',
34
40
  maxCoverMb = 10,
35
41
  maxAvatarMb = 5,
@@ -52,6 +58,12 @@
52
58
  const coverInputId = $derived(`${id}-cover`);
53
59
  const avatarInputId = $derived(`${id}-avatar`);
54
60
 
61
+ const coverDisplayUrl = $derived(cover?.previewUrl || coverSrc || '');
62
+ const avatarDisplayUrl = $derived(avatar?.previewUrl || avatarSrc || '');
63
+ const hasCoverMedia = $derived(Boolean(coverDisplayUrl));
64
+ const hasAvatarMedia = $derived(Boolean(avatarDisplayUrl));
65
+ const hasLocalMedia = $derived(Boolean(cover || avatar));
66
+
55
67
  function revoke(media: ProfileMedia | null) {
56
68
  if (media?.previewUrl) URL.revokeObjectURL(media.previewUrl);
57
69
  }
@@ -171,7 +183,7 @@
171
183
  />
172
184
 
173
185
  <div
174
- class="relative overflow-hidden rounded-xl border border-border bg-surface-elevated shadow-sm"
186
+ class="relative rounded-xl border border-border bg-surface-elevated shadow-sm"
175
187
  aria-labelledby={label ? labelId : undefined}
176
188
  aria-describedby={[coverHelperText || avatarHelperText ? helperId : '', errorMessage ? errorId : '']
177
189
  .filter(Boolean)
@@ -182,7 +194,11 @@
182
194
  <div
183
195
  role="button"
184
196
  tabindex={disabled ? -1 : 0}
185
- aria-label={cover ? `Change cover photo, ${cover.name}` : 'Upload cover photo'}
197
+ aria-label={hasCoverMedia
198
+ ? cover
199
+ ? `Change cover photo, ${cover.name}`
200
+ : 'Change cover photo'
201
+ : 'Upload cover photo'}
186
202
  aria-disabled={disabled || undefined}
187
203
  ondragenter={(e) => {
188
204
  e.preventDefault();
@@ -200,14 +216,14 @@
200
216
  }}
201
217
  onclick={() => !disabled && coverInput?.click()}
202
218
  class={[
203
- 'group relative aspect-3/1 min-h-36 w-full overflow-hidden outline-none transition-colors',
219
+ 'group relative aspect-3/1 min-h-36 w-full overflow-hidden rounded-t-xl outline-none transition-colors',
204
220
  'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-500/40',
205
221
  coverDragging ? 'bg-brand-500/10' : 'bg-surface-overlay',
206
222
  disabled ? 'cursor-not-allowed opacity-60' : 'cursor-pointer'
207
223
  ]}
208
224
  >
209
- {#if cover}
210
- <img src={cover.previewUrl} alt="" class="h-full w-full object-cover" />
225
+ {#if hasCoverMedia}
226
+ <img src={coverDisplayUrl} alt="" class="h-full w-full object-cover" />
211
227
  {#if !disabled}
212
228
  <div
213
229
  class="absolute inset-0 flex items-start justify-end bg-linear-to-b from-black/35 via-transparent to-transparent p-3 opacity-0 transition-opacity group-hover:opacity-100 group-focus-visible:opacity-100"
@@ -267,7 +283,11 @@
267
283
  <div
268
284
  role="button"
269
285
  tabindex={disabled ? -1 : 0}
270
- aria-label={avatar ? `Change profile photo, ${avatar.name}` : 'Upload profile photo'}
286
+ aria-label={hasAvatarMedia
287
+ ? avatar
288
+ ? `Change profile photo, ${avatar.name}`
289
+ : 'Change profile photo'
290
+ : 'Upload profile photo'}
271
291
  aria-disabled={disabled || undefined}
272
292
  ondragenter={(e) => {
273
293
  e.preventDefault();
@@ -298,14 +318,14 @@
298
318
  if (!disabled) avatarInput?.click();
299
319
  }}
300
320
  class={[
301
- 'group relative h-20 w-20 shrink-0 overflow-hidden rounded-full border-4 border-surface-elevated bg-surface-overlay shadow-md outline-none transition sm:h-24 sm:w-24',
321
+ 'group relative z-10 h-20 w-20 shrink-0 overflow-hidden rounded-full border-4 border-surface-elevated bg-surface-overlay shadow-md outline-none transition sm:h-24 sm:w-24',
302
322
  'focus-visible:ring-2 focus-visible:ring-brand-500/40 focus-visible:ring-offset-2 focus-visible:ring-offset-surface-elevated',
303
323
  avatarDragging ? 'ring-2 ring-brand-500' : '',
304
324
  disabled ? 'cursor-not-allowed opacity-60' : 'cursor-pointer'
305
325
  ]}
306
326
  >
307
- {#if avatar}
308
- <img src={avatar.previewUrl} alt="" class="h-full w-full object-cover" />
327
+ {#if hasAvatarMedia}
328
+ <img src={avatarDisplayUrl} alt="" class="h-full w-full object-cover" />
309
329
  {#if !disabled}
310
330
  <div
311
331
  class="absolute inset-0 flex items-center justify-center bg-black/45 opacity-0 transition-opacity group-hover:opacity-100 group-focus-visible:opacity-100"
@@ -339,7 +359,7 @@
339
359
  </div>
340
360
 
341
361
  <div class="min-w-0 flex-1 pb-1">
342
- {#if avatar || cover}
362
+ {#if hasLocalMedia}
343
363
  <div class="flex flex-wrap items-center gap-2">
344
364
  {#if cover && !disabled}
345
365
  <button
@@ -7,6 +7,10 @@ interface ProfileHeaderUploaderProps {
7
7
  label?: string;
8
8
  coverHelperText?: string;
9
9
  avatarHelperText?: string;
10
+ /** Existing remote cover URL (shown when no local File is selected). */
11
+ coverSrc?: string;
12
+ /** Existing remote avatar URL (shown when no local File is selected). */
13
+ avatarSrc?: string;
10
14
  accept?: string;
11
15
  maxCoverMb?: number;
12
16
  maxAvatarMb?: number;
package/dist/index.d.ts CHANGED
@@ -210,7 +210,10 @@ export type { TimeFormat } from './components/molecules/TimePicker/TimePicker.sv
210
210
  export { default as DateTimePicker } from './components/molecules/DateTimePicker/DateTimePicker.svelte';
211
211
  export { default as DateRangePicker } from './components/molecules/DateRangePicker/DateRangePicker.svelte';
212
212
  export { default as Combobox } from './components/molecules/Combobox/Combobox.svelte';
213
- export type { ComboboxOption } from './components/molecules/Combobox/Combobox.svelte';
213
+ export type { ComboboxOption, ComboboxItemState } from './components/molecules/Combobox/Combobox.svelte';
214
+ export { default as ComboboxItem } from './components/molecules/ComboboxItem/ComboboxItem.svelte';
215
+ export { COMBOBOX_CONTEXT, COMBOBOX_CREATE_KEY, getComboboxContext, setComboboxContext } from './components/molecules/Combobox/combobox-context.js';
216
+ export type { ComboboxContext } from './components/molecules/Combobox/combobox-context.js';
214
217
  export { default as MultiSelect } from './components/molecules/MultiSelect/MultiSelect.svelte';
215
218
  export type { MultiSelectOption } from './components/molecules/MultiSelect/MultiSelect.svelte';
216
219
  export { default as ConfirmDialog } from './components/molecules/ConfirmDialog/ConfirmDialog.svelte';
@@ -306,8 +309,8 @@ export type { FilterChip } from './components/molecules/FilterBar/FilterBar.svel
306
309
  export { default as SortableList } from './components/molecules/SortableList/SortableList.svelte';
307
310
  export type { SortableItem } from './components/molecules/SortableList/SortableList.svelte';
308
311
  export { default as Form } from './components/molecules/Form/Form.svelte';
309
- export { getFormContext, FORM_CONTEXT_KEY, remoteIssuesToErrors, isRemoteForm, fieldPath, resolveFormFieldState, applyFormDataSync, sameStringArray } from './utils/formContext.js';
310
- export type { FormErrors, FormContext, FormDataValues, FormFieldStatus, FormRemote,
312
+ export { getFormContext, FORM_CONTEXT_KEY, remoteIssuesToErrors, isRemoteForm, fieldPath, resolveFormFieldState, resolveRemoteInputProps, parseRemoteFieldName, remoteAsProps, getRemoteFormId, applyFormDataSync, sameStringArray } from './utils/formContext.js';
313
+ export type { FormErrors, FormContext, FormDataValues, FormFieldStatus, FormRemote, ResolvedRemoteInputProps, ParsedRemoteFieldName,
311
314
  /** @deprecated Use `FormRemote` */
312
315
  RemoteFormSpread, RemoteForm, RemoteFormInput, RemoteFormIssue } from './utils/formContext.js';
313
316
  export { validateForm, isFormDirty, firstFormError } from './utils/formValidate.js';
package/dist/index.js CHANGED
@@ -166,6 +166,8 @@ export { default as TimePicker } from './components/molecules/TimePicker/TimePic
166
166
  export { default as DateTimePicker } from './components/molecules/DateTimePicker/DateTimePicker.svelte';
167
167
  export { default as DateRangePicker } from './components/molecules/DateRangePicker/DateRangePicker.svelte';
168
168
  export { default as Combobox } from './components/molecules/Combobox/Combobox.svelte';
169
+ export { default as ComboboxItem } from './components/molecules/ComboboxItem/ComboboxItem.svelte';
170
+ export { COMBOBOX_CONTEXT, COMBOBOX_CREATE_KEY, getComboboxContext, setComboboxContext } from './components/molecules/Combobox/combobox-context.js';
169
171
  export { default as MultiSelect } from './components/molecules/MultiSelect/MultiSelect.svelte';
170
172
  export { default as ConfirmDialog } from './components/molecules/ConfirmDialog/ConfirmDialog.svelte';
171
173
  export { default as ContextMenu } from './components/molecules/ContextMenu/ContextMenu.svelte';
@@ -233,7 +235,7 @@ export { default as TableOfContents } from './components/molecules/TableOfConten
233
235
  export { default as FilterBar } from './components/molecules/FilterBar/FilterBar.svelte';
234
236
  export { default as SortableList } from './components/molecules/SortableList/SortableList.svelte';
235
237
  export { default as Form } from './components/molecules/Form/Form.svelte';
236
- export { getFormContext, FORM_CONTEXT_KEY, remoteIssuesToErrors, isRemoteForm, fieldPath, resolveFormFieldState, applyFormDataSync, sameStringArray } from './utils/formContext.js';
238
+ export { getFormContext, FORM_CONTEXT_KEY, remoteIssuesToErrors, isRemoteForm, fieldPath, resolveFormFieldState, resolveRemoteInputProps, parseRemoteFieldName, remoteAsProps, getRemoteFormId, applyFormDataSync, sameStringArray } from './utils/formContext.js';
237
239
  export { validateForm, isFormDirty, firstFormError } from './utils/formValidate.js';
238
240
  export { UI_DICTIONARIES, resolveLocaleTag, getDictionary, formatMessage } from './utils/i18n.js';
239
241
  export { i18n } from './utils/i18n.svelte.js';
package/dist/styles.css CHANGED
@@ -234,4 +234,10 @@
234
234
  .text-primary { color: var(--text-primary); }
235
235
  .text-secondary { color: var(--text-secondary); }
236
236
  .text-muted { color: var(--text-muted); }
237
+
238
+ /* SVG chart labels — Tailwind fill-* needs these (text-* alone does not paint <text>) */
239
+ .fill-primary { fill: var(--text-primary); }
240
+ .fill-secondary { fill: var(--text-secondary); }
241
+ .fill-muted { fill: var(--text-muted); }
242
+ .stroke-border { stroke: var(--border); }
237
243
  }
@@ -30,6 +30,13 @@ export interface FormContext<TData extends FormDataValues = FormDataValues, TRes
30
30
  disabled: boolean;
31
31
  /** Last result from a remote form / submit handler, if any */
32
32
  result: TResult | undefined;
33
+ /**
34
+ * Full Kit `RemoteForm` when `<Form remote={...}>` received one
35
+ * (not an `.enhance(...)` return). Used by fields to call `.as()`.
36
+ */
37
+ remote: RemoteForm<any, any> | null;
38
+ /** Stable Kit form id (`1p9kxmo/login_user`) for encoding input names */
39
+ remoteFormId: string | null;
33
40
  setError: (name: string, message: string) => void;
34
41
  clearError: (name: string) => void;
35
42
  clearErrors: () => void;
@@ -37,6 +44,57 @@ export interface FormContext<TData extends FormDataValues = FormDataValues, TRes
37
44
  getError: (name: string) => string | undefined;
38
45
  getData: <K extends keyof TData & string>(name: K) => TData[K] | undefined;
39
46
  }
47
+ /**
48
+ * Props safe to spread onto library `<Input>` / `<PasswordInput>` for Kit remote forms.
49
+ * Omits Kit `value` getters/setters so they do not fight `bind:value`.
50
+ */
51
+ export type ResolvedRemoteInputProps = {
52
+ name?: string;
53
+ };
54
+ /**
55
+ * Extract Kit remote form id from `remote.action` (`?/remote=<id>`).
56
+ * Pass `untrack(() => remote.action)` from callers inside effects/derived.
57
+ */
58
+ export declare function getRemoteFormId(action: string | undefined | null): string | null;
59
+ /**
60
+ * Resolve HTML input props for a field inside a Kit remote form.
61
+ * Prefer a precomputed `formId` string so fields never touch Kit proxies.
62
+ */
63
+ export declare function resolveRemoteInputProps(formId: string | null | undefined, logicalName: string | undefined, type?: string): ResolvedRemoteInputProps;
64
+ export type ParsedRemoteFieldName = {
65
+ /** Field path for errors / `form.data` (`email`, `items[0].name`) */
66
+ logicalName: string | undefined;
67
+ /** Exact HTML `name` to put on the input (Kit-encoded or plain) */
68
+ htmlName: string | undefined;
69
+ /** True when `name` already includes `/formId` (from Kit `.as()`) */
70
+ isEncoded: boolean;
71
+ };
72
+ /**
73
+ * Split a Kit-encoded HTML `name` (`email/1p9kxmo/login_user`, `n:age/...`)
74
+ * into logical + html parts. Plain names pass through unchanged.
75
+ *
76
+ * When `formId` is known, uses Kit’s suffix rule (`/${formId}`).
77
+ * Otherwise treats the first `/` after an optional `n:`/`b:` prefix as the form-id boundary
78
+ * (logical paths use `.` / `[n]`, never `/`).
79
+ */
80
+ export declare function parseRemoteFieldName(name: string | undefined, formId?: string | null): ParsedRemoteFieldName;
81
+ /**
82
+ * Safe props to spread onto `FormField` / `FormPasswordInput` from Kit `.as(...)`.
83
+ * Keeps `name` (+ `type`) and drops Kit `value` / `defaultValue` accessors that
84
+ * fight library `$bindable` and can cause `effect_update_depth_exceeded`.
85
+ *
86
+ * @example
87
+ * ```svelte
88
+ * <FormField {...remoteAsProps(login_user.fields.email.as('email'))} label="Email" />
89
+ * ```
90
+ */
91
+ export declare function remoteAsProps(asProps: {
92
+ name: string;
93
+ type?: string;
94
+ }): {
95
+ name: string;
96
+ type?: string;
97
+ };
40
98
  /**
41
99
  * Access the nearest `<Form>` context from a child component.
42
100
  * Returns `null` when used outside a Form.
@@ -7,6 +7,83 @@ export const FORM_CONTEXT_KEY = 'r2-form';
7
7
  export function fieldPath(...segments) {
8
8
  return segments.map(String).filter((s) => s.length > 0).join('.');
9
9
  }
10
+ /**
11
+ * Extract Kit remote form id from `remote.action` (`?/remote=<id>`).
12
+ * Pass `untrack(() => remote.action)` from callers inside effects/derived.
13
+ */
14
+ export function getRemoteFormId(action) {
15
+ if (!action)
16
+ return null;
17
+ const match = action.match(/\/remote=([^&]+)/);
18
+ return match ? decodeURIComponent(match[1]) : null;
19
+ }
20
+ /**
21
+ * Resolve HTML input props for a field inside a Kit remote form.
22
+ * Prefer a precomputed `formId` string so fields never touch Kit proxies.
23
+ */
24
+ export function resolveRemoteInputProps(formId, logicalName, type = 'text') {
25
+ if (!logicalName)
26
+ return {};
27
+ if (!formId)
28
+ return { name: logicalName };
29
+ let prefix = '';
30
+ if (type === 'number' || type === 'range')
31
+ prefix = 'n:';
32
+ else if (type === 'checkbox' || type === 'boolean')
33
+ prefix = 'b:';
34
+ return { name: `${prefix}${logicalName}/${formId}` };
35
+ }
36
+ /**
37
+ * Split a Kit-encoded HTML `name` (`email/1p9kxmo/login_user`, `n:age/...`)
38
+ * into logical + html parts. Plain names pass through unchanged.
39
+ *
40
+ * When `formId` is known, uses Kit’s suffix rule (`/${formId}`).
41
+ * Otherwise treats the first `/` after an optional `n:`/`b:` prefix as the form-id boundary
42
+ * (logical paths use `.` / `[n]`, never `/`).
43
+ */
44
+ export function parseRemoteFieldName(name, formId) {
45
+ if (!name) {
46
+ return { logicalName: undefined, htmlName: undefined, isEncoded: false };
47
+ }
48
+ const htmlName = name;
49
+ if (formId && name.endsWith(`/${formId}`)) {
50
+ let logical = name.slice(0, -(formId.length + 1));
51
+ if (logical.startsWith('n:') || logical.startsWith('b:'))
52
+ logical = logical.slice(2);
53
+ if (logical.endsWith('[]'))
54
+ logical = logical.slice(0, -2);
55
+ return { logicalName: logical, htmlName, isEncoded: true };
56
+ }
57
+ // Heuristic without formId: Kit-encoded names contain `/`
58
+ if (name.includes('/')) {
59
+ let rest = name;
60
+ if (rest.startsWith('n:') || rest.startsWith('b:'))
61
+ rest = rest.slice(2);
62
+ const slash = rest.indexOf('/');
63
+ if (slash !== -1) {
64
+ let logical = rest.slice(0, slash);
65
+ if (logical.endsWith('[]'))
66
+ logical = logical.slice(0, -2);
67
+ return { logicalName: logical, htmlName, isEncoded: true };
68
+ }
69
+ }
70
+ return { logicalName: name, htmlName: name, isEncoded: false };
71
+ }
72
+ /**
73
+ * Safe props to spread onto `FormField` / `FormPasswordInput` from Kit `.as(...)`.
74
+ * Keeps `name` (+ `type`) and drops Kit `value` / `defaultValue` accessors that
75
+ * fight library `$bindable` and can cause `effect_update_depth_exceeded`.
76
+ *
77
+ * @example
78
+ * ```svelte
79
+ * <FormField {...remoteAsProps(login_user.fields.email.as('email'))} label="Email" />
80
+ * ```
81
+ */
82
+ export function remoteAsProps(asProps) {
83
+ return asProps.type != null
84
+ ? { name: asProps.name, type: asProps.type }
85
+ : { name: asProps.name };
86
+ }
10
87
  /**
11
88
  * Access the nearest `<Form>` context from a child component.
12
89
  * Returns `null` when used outside a Form.
@@ -42,7 +119,8 @@ export function remoteIssuesToErrors(issues) {
42
119
  }
43
120
  /** True when the spread value is a full `RemoteForm` (has `fields` / `pending`). */
44
121
  export function isRemoteForm(remote) {
45
- return !!remote && 'fields' in remote && typeof remote.fields === 'object';
122
+ // Avoid reading `.fields` (client getter allocates a proxy and can loop in `$derived`).
123
+ return !!remote && 'fields' in remote;
46
124
  }
47
125
  /**
48
126
  * Shared resolution for form-aware controls (error / status / disabled).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@r2digisolutions/components",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "private": false,
5
5
  "description": "R2DigiSolutions Svelte 5 component library — Atomic Design, Tailwind 4, Light/Dark mode",
6
6
  "license": "MIT",
@@ -66,37 +66,37 @@
66
66
  },
67
67
  "devDependencies": {
68
68
  "@eslint/js": "^10.0.1",
69
- "@lucide/svelte": "^1.26.0",
70
- "@playwright/test": "^1.61.1",
71
- "@storybook/addon-a11y": "^8.6.18",
69
+ "@lucide/svelte": "^1.27.0",
70
+ "@playwright/test": "^1.62.0",
71
+ "@storybook/addon-a11y": "^10.5.5",
72
72
  "@storybook/addon-essentials": "^8.6.18",
73
73
  "@storybook/addon-svelte-csf": "^5.1.2",
74
- "@storybook/addon-themes": "^8.6.18",
75
- "@storybook/svelte": "^8.6.18",
76
- "@storybook/sveltekit": "^8.6.18",
74
+ "@storybook/addon-themes": "^10.5.5",
75
+ "@storybook/svelte": "^10.5.5",
76
+ "@storybook/sveltekit": "^10.5.5",
77
77
  "@sveltejs/adapter-static": "next",
78
78
  "@sveltejs/kit": "next",
79
79
  "@sveltejs/package": "^2.5.8",
80
80
  "@sveltejs/vite-plugin-svelte": "^7.2.0",
81
81
  "@tailwindcss/vite": "^4.3.3",
82
- "@types/node": "^24.13.3",
82
+ "@types/node": "^26.1.2",
83
83
  "@vitest/browser-playwright": "^4.1.10",
84
- "bumpp": "^10.4.1",
85
- "eslint": "^10.7.0",
84
+ "bumpp": "^12.1.1",
85
+ "eslint": "^10.8.0",
86
86
  "eslint-config-prettier": "^10.1.8",
87
87
  "eslint-plugin-svelte": "^3.22.0",
88
- "globals": "^17.7.0",
88
+ "globals": "^17.8.0",
89
89
  "mdsvex": "^0.12.8",
90
- "playwright": "^1.61.1",
90
+ "playwright": "^1.62.0",
91
91
  "prettier": "^3.9.6",
92
92
  "prettier-plugin-svelte": "^4.1.1",
93
93
  "prettier-plugin-tailwindcss": "^0.8.1",
94
94
  "publint": "^0.3.22",
95
- "storybook": "^8.6.18",
96
- "svelte": "^5.56.7",
97
- "svelte-check": "^4.7.3",
95
+ "storybook": "^10.5.5",
96
+ "svelte": "^5.56.8",
97
+ "svelte-check": "^4.7.4",
98
98
  "tailwindcss": "^4.3.3",
99
- "typescript": "^6.0.3",
99
+ "typescript": "6.0.3",
100
100
  "typescript-eslint": "^8.65.0",
101
101
  "vite": "^8.1.5",
102
102
  "vitest": "^4.1.10",