@sveltia/ui 0.13.2 → 0.15.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.
@@ -20,6 +20,10 @@
20
20
  * @type {boolean}
21
21
  */
22
22
  export let multiple = false;
23
+ /**
24
+ * Whether to select a row by clicking on it.
25
+ */
26
+ export let clickToSelect = true;
23
27
 
24
28
  /** @type {HTMLElement | undefined} */
25
29
  export let element = undefined;
@@ -33,7 +37,7 @@
33
37
  aria-multiselectable={multiple}
34
38
  {...$$restProps}
35
39
  bind:this={element}
36
- use:activateGroup
40
+ use:activateGroup={{ clickToSelect }}
37
41
  on:change={(/** @type {CustomEvent} */ event) => {
38
42
  dispatch('change', event.detail);
39
43
  }}
@@ -10,6 +10,7 @@ export default class Grid extends SvelteComponent<{
10
10
  [x: string]: any;
11
11
  class?: string | undefined;
12
12
  element?: HTMLElement | undefined;
13
+ clickToSelect?: boolean | undefined;
13
14
  multiple?: boolean | undefined;
14
15
  }, {
15
16
  change: CustomEvent<any>;
@@ -28,6 +29,7 @@ declare const __propDef: {
28
29
  [x: string]: any;
29
30
  class?: string | undefined;
30
31
  element?: HTMLElement | undefined;
32
+ clickToSelect?: boolean | undefined;
31
33
  multiple?: boolean | undefined;
32
34
  };
33
35
  events: {
@@ -44,9 +44,14 @@
44
44
  * @type {string}
45
45
  */
46
46
  export let searchValue = label;
47
+ /**
48
+ * Whether to wrap a long label.
49
+ * @type {boolean}
50
+ */
51
+ export let wrap = false;
47
52
  </script>
48
53
 
49
- <div role="none" class="sui option {className}" hidden={hidden || undefined}>
54
+ <div role="none" class="sui option {className}" class:wrap hidden={hidden || undefined}>
50
55
  <Button
51
56
  role="option"
52
57
  tabindex="-1"
@@ -103,9 +108,15 @@
103
108
  border-radius: var(--sui-option-border-radius);
104
109
  padding: var(--sui-option-padding);
105
110
  width: 100%;
106
- height: var(--sui-option-height);
111
+ height: auto;
112
+ min-height: var(--sui-option-height);
113
+ overflow: hidden;
114
+ text-overflow: ellipsis;
107
115
  white-space: nowrap;
108
116
  }
117
+ .option.wrap :global(button) {
118
+ white-space: normal;
119
+ }
109
120
  .option :global(.focused),
110
121
  .option :global(button:hover) {
111
122
  color: var(--sui-highlight-foreground-color);
@@ -15,6 +15,7 @@ export default class Option extends SvelteComponent<{
15
15
  hidden?: boolean | undefined;
16
16
  selected?: boolean | undefined;
17
17
  searchValue?: string | undefined;
18
+ wrap?: boolean | undefined;
18
19
  }, {
19
20
  click: MouseEvent;
20
21
  dblclick: MouseEvent;
@@ -53,6 +54,7 @@ declare const __propDef: {
53
54
  hidden?: boolean | undefined;
54
55
  selected?: boolean | undefined;
55
56
  searchValue?: string | undefined;
57
+ wrap?: boolean | undefined;
56
58
  };
57
59
  events: {
58
60
  click: MouseEvent;
@@ -87,7 +87,6 @@
87
87
  */
88
88
  const onChange = () => {
89
89
  const selected = popupComponent?.content?.querySelector(selectedSelector);
90
-
91
90
  const target = /** @type {HTMLButtonElement} */ (
92
91
  popupComponent?.content?.querySelector(`[role="option"][value="${value}"]`)
93
92
  );
@@ -87,7 +87,6 @@
87
87
 
88
88
  const fromIndex = positionList.findLastIndex((s) => s <= diff);
89
89
  const toIndex = positionList.findIndex((s) => diff <= s);
90
-
91
90
  const index =
92
91
  Math.abs(positionList[fromIndex] - diff) < Math.abs(positionList[toIndex] - diff)
93
92
  ? fromIndex
@@ -150,6 +150,7 @@ export const initEditor = () => {
150
150
  TOGGLE_LINK_COMMAND,
151
151
  (payload) => {
152
152
  toggleLink(typeof payload === 'string' ? payload : null);
153
+
153
154
  return true;
154
155
  },
155
156
  COMMAND_PRIORITY_NORMAL,
@@ -159,6 +160,7 @@ export const initEditor = () => {
159
160
  INSERT_UNORDERED_LIST_COMMAND,
160
161
  () => {
161
162
  insertList(editor, 'bullet');
163
+
162
164
  return true;
163
165
  },
164
166
  COMMAND_PRIORITY_NORMAL,
@@ -168,6 +170,7 @@ export const initEditor = () => {
168
170
  INSERT_ORDERED_LIST_COMMAND,
169
171
  () => {
170
172
  insertList(editor, 'number');
173
+
171
174
  return true;
172
175
  },
173
176
  COMMAND_PRIORITY_NORMAL,
@@ -74,17 +74,14 @@ export const availableButtons = {
74
74
  inline: false,
75
75
  },
76
76
  };
77
-
78
77
  /**
79
78
  * @type {TextEditorFormatType[]}
80
79
  */
81
80
  export const textFormatButtonTypes = ['bold', 'italic', 'code'];
82
-
83
81
  /**
84
82
  * @type {TextEditorInlineType[]}
85
83
  */
86
84
  export const inlineButtonTypes = [...textFormatButtonTypes, 'link'];
87
-
88
85
  /**
89
86
  * @type {TextEditorBlockType[]}
90
87
  */
@@ -4,7 +4,7 @@
4
4
  -->
5
5
  <script>
6
6
  import { generateElementId } from '@sveltia/utils/element';
7
- import { onMount, setContext } from 'svelte';
7
+ import { setContext } from 'svelte';
8
8
  import { _ } from 'svelte-i18n';
9
9
  import { writable } from 'svelte/store';
10
10
  import Alert from '../alert/alert.svelte';
@@ -70,26 +70,65 @@
70
70
  const editorId = writable(generateElementId('editor'));
71
71
  const useRichText = writable(modes[0] === 'rich-text');
72
72
  const hasConverterError = writable(false);
73
+ let inputValue = '';
73
74
  let showConverterError = false;
74
75
 
75
76
  /**
76
- * Convert the Markdown {@link value} to Lexical nodes. Disable the rich text mode and restore the
77
- * original value when there is an error while conversion.
77
+ * Convert the Markdown {@link inputValue} to Lexical nodes. Disable the rich text mode and
78
+ * restore the original value when there is an error while conversion.
78
79
  */
79
80
  const convertMarkdown = async () => {
80
- const originalValue = value;
81
+ const originalValue = inputValue;
81
82
 
82
83
  try {
83
84
  // We should avoid an empty editor; there should be at least one `<p>`, so give it an empty
84
85
  // string if the `value` is `undefined`
85
86
  // @see https://github.com/facebook/lexical/issues/2308
86
- await convertMarkdownToLexical($editor, value ?? '');
87
+ await convertMarkdownToLexical($editor, inputValue ?? '');
87
88
  } catch {
88
89
  $hasConverterError = true;
89
- value = originalValue;
90
+ inputValue = originalValue;
90
91
  }
91
92
  };
92
93
 
94
+ /**
95
+ * Update {@link inputValue} based on {@link value}.
96
+ */
97
+ const setInputValue = () => {
98
+ const newValue = value ?? '';
99
+
100
+ // Avoid a cycle dependency & infinite loop
101
+ if (inputValue !== newValue) {
102
+ inputValue = newValue;
103
+
104
+ if ($useRichText) {
105
+ convertMarkdown();
106
+ }
107
+ }
108
+ };
109
+
110
+ /**
111
+ * Update {@link value} based on {@link inputValue}.
112
+ */
113
+ const setCurrentValue = () => {
114
+ const newValue = inputValue;
115
+
116
+ // Avoid a cycle dependency & infinite loop
117
+ if (value !== newValue) {
118
+ value = newValue;
119
+ }
120
+ };
121
+
122
+ $: {
123
+ void value;
124
+ setInputValue();
125
+ }
126
+
127
+ $: {
128
+ void inputValue;
129
+ setCurrentValue();
130
+ }
131
+
93
132
  $: {
94
133
  if ($hasConverterError) {
95
134
  $useRichText = false;
@@ -111,18 +150,12 @@
111
150
  convertMarkdown,
112
151
  }),
113
152
  );
114
-
115
- onMount(() => {
116
- if ($useRichText) {
117
- convertMarkdown();
118
- }
119
- });
120
153
  </script>
121
154
 
122
155
  <div role="none" class="sui text-editor" hidden={hidden || undefined} {...$$restProps}>
123
156
  <EditorToolbar {disabled} {readonly} />
124
157
  <LexicalRoot
125
- bind:value
158
+ bind:value={inputValue}
126
159
  hidden={!$useRichText || hidden}
127
160
  {disabled}
128
161
  {readonly}
@@ -131,7 +164,7 @@
131
164
  />
132
165
  <TextArea
133
166
  autoResize={true}
134
- bind:value
167
+ bind:value={inputValue}
135
168
  {flex}
136
169
  hidden={$useRichText || hidden}
137
170
  {disabled}
@@ -121,6 +121,12 @@ textarea,
121
121
  font-family: var(--sui-textbox-font-family);
122
122
  font-size: var(--sui-textbox-font-size);
123
123
  line-height: var(--sui-textbox-multiline-line-height);
124
+ font-weight: var(--sui-textbox-font-weight, normal);
125
+ text-align: var(--sui-textbox-text-align, left);
126
+ text-indent: var(--sui-textbox-text-indent, 0);
127
+ text-transform: var(--sui-textbox-text-transform, none);
128
+ letter-spacing: var(--sui-textbox-letter-spacing, normal);
129
+ word-spacing: var(--sui-word-spacing-normal, normal);
124
130
  transition: all 200ms;
125
131
  }
126
132
  textarea.resizing,
@@ -166,6 +166,7 @@ input {
166
166
  text-indent: var(--sui-textbox-text-indent, 0);
167
167
  text-transform: var(--sui-textbox-text-transform, none);
168
168
  letter-spacing: var(--sui-textbox-letter-spacing, normal);
169
+ word-spacing: var(--sui-word-spacing-normal, normal);
169
170
  transition: all 200ms;
170
171
  }
171
172
  input:focus {
@@ -194,7 +194,7 @@
194
194
  --sui-control-background-color: hsl(var(--sui-background-color-4-hsl));
195
195
  --sui-control-font-family: var(--sui-font-family-default);
196
196
  --sui-control-font-size: var(--sui-font-size-default);
197
- --sui-control-line-height: var(--sui-line-height-default);
197
+ --sui-control-line-height: var(--sui-line-height-compact);
198
198
  --sui-button-small-border-radius: var(--sui-control-small-border-radius);
199
199
  --sui-button-small-padding: var(--sui-control-small-padding);
200
200
  --sui-button-small-height: var(--sui-control-small-height);
@@ -211,7 +211,8 @@
211
211
  --sui-checkbox-border-color: hsl(var(--sui-border-color-1-hsl));
212
212
  --sui-checkbox-background-color: var(--sui-control-background-color);
213
213
  --sui-option-border-radius: var(--sui-control-medium-border-radius);
214
- --sui-option-padding: var(--sui-control-medium-padding);
214
+ --sui-option-padding: calc((var(--sui-control-medium-height) / 6))
215
+ calc((var(--sui-control-medium-height) / 2));
215
216
  --sui-option-height: var(--sui-control-medium-height);
216
217
  --sui-listbox-border-radius: var(--sui-control-medium-border-radius);
217
218
  --sui-listbox-border-color: var(--sui-control-border-color);
@@ -137,7 +137,8 @@
137
137
  class:touch
138
138
  style:inset={$style.inset}
139
139
  style:z-index={$style.zIndex}
140
- style:min-width={$style.width}
140
+ style:width={$style.width}
141
+ style:min-width={$style.minWidth}
141
142
  style:max-height={$style.height}
142
143
  style:visibility={$style.inset ? undefined : 'hidden'}
143
144
  bind:this={content}
@@ -1 +1 @@
1
- export function activateGroup(parent: HTMLElement, _params?: object | undefined): import('svelte/action').ActionReturn;
1
+ export function activateGroup(parent: HTMLElement, params?: object | undefined): import('svelte/action').ActionReturn;
@@ -62,9 +62,11 @@ class Group {
62
62
  /**
63
63
  * Initialize a new `Group` instance.
64
64
  * @param {HTMLElement} parent - Parent element.
65
+ * @param {object} [options] - Options.
66
+ * @param {boolean} [options.clickToSelect] - Whether to select an item by clicking on it.
65
67
  * @todo Check for added elements probably with `MutationObserver`.
66
68
  */
67
- constructor(parent) {
69
+ constructor(parent, { clickToSelect = true } = {}) {
68
70
  parent.dispatchEvent(new CustomEvent('initializing'));
69
71
 
70
72
  this.parent = parent;
@@ -72,6 +74,7 @@ class Group {
72
74
  this.multi = this.parent.getAttribute('aria-multiselectable') === 'true';
73
75
  this.id = generateElementId(this.role);
74
76
  this.parentGroupSelector = `[role="group"], [role="${this.role}"]`;
77
+ this.clickToSelect = clickToSelect;
75
78
 
76
79
  const { orientation, childRoles, childSelectedAttr, focusChild, selectFirst } =
77
80
  config[this.role];
@@ -103,7 +106,6 @@ class Group {
103
106
  const isSelected = defaultSelected
104
107
  ? element === defaultSelected
105
108
  : this.selectFirst && index === 0;
106
-
107
109
  const controlTarget = /** @type {HTMLElement | null} */ (
108
110
  document.querySelector(`#${element.getAttribute('aria-controls')}`)
109
111
  );
@@ -219,7 +221,6 @@ class Group {
219
221
  const targetRole = newTarget.getAttribute('role');
220
222
  const targetParent = newTarget.closest(this.parentGroupSelector);
221
223
  const selectByClick = event.type === 'click';
222
-
223
224
  const selectByKeydown =
224
225
  event.type === 'keydown' && /** @type {KeyboardEvent} */ (event).key === ' ';
225
226
 
@@ -335,12 +336,11 @@ class Group {
335
336
  onClick(event) {
336
337
  // eslint-disable-next-line prefer-destructuring
337
338
  const target = /** @type {HTMLElement} */ (event.target);
338
-
339
339
  const newTarget = target.matches(this.selector)
340
340
  ? target
341
341
  : /** @type {HTMLElement | null} */ (target.closest(this.selector));
342
342
 
343
- if (!newTarget || event.button !== 0) {
343
+ if (!newTarget || event.button !== 0 || !this.clickToSelect) {
344
344
  return;
345
345
  }
346
346
 
@@ -362,7 +362,6 @@ class Group {
362
362
  // eslint-disable-next-line prefer-destructuring
363
363
  const target = /** @type {HTMLElement} */ (event.target);
364
364
  const { allMembers, activeMembers } = this;
365
-
366
365
  /** @type {HTMLElement | undefined} */
367
366
  const currentTarget = (() => {
368
367
  if (!this.focusChild) {
@@ -461,7 +460,6 @@ class Group {
461
460
  onUpdate({ searchTerms }) {
462
461
  const terms = searchTerms.trim().toLocaleLowerCase();
463
462
  const _terms = terms ? terms.split(/\s+/) : [];
464
-
465
463
  const matched = this.allMembers
466
464
  .map((member) => {
467
465
  const searchValue =
@@ -471,7 +469,6 @@ class Group {
471
469
  member.querySelector('.label')?.textContent ??
472
470
  member.textContent
473
471
  )?.toLocaleLowerCase() ?? '';
474
-
475
472
  const hidden = !_terms.every((term) => searchValue.includes(term));
476
473
 
477
474
  member.dispatchEvent(new CustomEvent('toggle', { detail: { hidden } }));
@@ -489,20 +486,20 @@ class Group {
489
486
  /**
490
487
  * Activate a new group.
491
488
  * @param {HTMLElement} parent - Parent element.
492
- * @param {object} [_params] - Action params.
489
+ * @param {object} [params] - Action params.
493
490
  * @returns {import('svelte/action').ActionReturn} Action.
494
491
  */
495
492
  // eslint-disable-next-line no-unused-vars
496
- export const activateGroup = (parent, _params) => {
497
- const group = new Group(parent);
493
+ export const activateGroup = (parent, params) => {
494
+ const group = new Group(parent, params);
498
495
 
499
496
  return {
500
497
  /**
501
498
  * Called whenever the params are updated.
502
- * @param {any} params - Updated params.
499
+ * @param {any} newParams - Updated params.
503
500
  */
504
- update(params) {
505
- group.onUpdate(params);
501
+ update(newParams) {
502
+ group.onUpdate(newParams);
506
503
  },
507
504
  };
508
505
  };
@@ -26,9 +26,8 @@ class Popup {
26
26
  return;
27
27
  }
28
28
 
29
- const { scrollHeight: contentHeight, scrollWidth: contentWidth } =
30
- /** @type {HTMLElement} */ (this.popupElement.querySelector('.content'));
31
-
29
+ const content = /** @type {HTMLElement} */ (this.popupElement.querySelector('.content'));
30
+ const { scrollHeight: contentHeight, scrollWidth: contentWidth } = content;
32
31
  const topMargin = intersectionRect.top - 8;
33
32
  const bottomMargin = rootBounds.height - intersectionRect.bottom - 8;
34
33
  let { position } = this;
@@ -59,31 +58,27 @@ class Popup {
59
58
  : position.endsWith('-top')
60
59
  ? `${Math.round(intersectionRect.top)}px`
61
60
  : 'auto';
62
-
63
61
  const right = position.startsWith('left-')
64
62
  ? `${Math.round(rootBounds.width - intersectionRect.left)}px`
65
63
  : position.endsWith('-right')
66
64
  ? `${Math.round(rootBounds.width - intersectionRect.right)}px`
67
65
  : 'auto';
68
-
69
66
  const bottom = position.startsWith('top-')
70
67
  ? `${Math.round(rootBounds.height - intersectionRect.top)}px`
71
68
  : position.endsWith('-bottom')
72
69
  ? `${Math.round(rootBounds.height - intersectionRect.bottom)}px`
73
70
  : 'auto';
74
-
75
71
  const left = position.startsWith('right-')
76
72
  ? `${Math.round(intersectionRect.right)}px`
77
73
  : position.endsWith('-left')
78
74
  ? `${Math.round(intersectionRect.left)}px`
79
75
  : 'auto';
80
-
81
76
  const anchorPopup = /** @type {HTMLElement} */ (this.anchorElement.closest('.popup'));
82
-
83
77
  const style = {
84
78
  inset: [top, right, bottom, left].join(' '),
85
79
  zIndex: anchorPopup ? Number(anchorPopup.style.zIndex) + 1 : 1000,
86
- width: `${Math.round(intersectionRect.width)}px`,
80
+ width: content.matches('.menu') ? 'auto' : `${Math.round(intersectionRect.width)}px`,
81
+ minWidth: `${Math.round(intersectionRect.width)}px`,
87
82
  height: height ? `${Math.round(height)}px` : 'auto',
88
83
  };
89
84
 
@@ -176,6 +171,11 @@ class Popup {
176
171
 
177
172
  this.anchorElement.setAttribute('aria-expanded', String(open));
178
173
  });
174
+
175
+ // Update the popup width when the base element is resized
176
+ new ResizeObserver(() => {
177
+ this.checkPosition();
178
+ }).observe(this.positionBaseElement);
179
179
  }
180
180
 
181
181
  /**
@@ -184,7 +184,7 @@
184
184
  --sui-control-background-color: hsl(var(--sui-background-color-4-hsl));
185
185
  --sui-control-font-family: var(--sui-font-family-default);
186
186
  --sui-control-font-size: var(--sui-font-size-default);
187
- --sui-control-line-height: var(--sui-line-height-default);
187
+ --sui-control-line-height: var(--sui-line-height-compact);
188
188
  // Button
189
189
  --sui-button-small-border-radius: var(--sui-control-small-border-radius);
190
190
  --sui-button-small-padding: var(--sui-control-small-padding);
@@ -204,7 +204,8 @@
204
204
  --sui-checkbox-background-color: var(--sui-control-background-color);
205
205
  // Option & menu item
206
206
  --sui-option-border-radius: var(--sui-control-medium-border-radius);
207
- --sui-option-padding: var(--sui-control-medium-padding);
207
+ --sui-option-padding: calc((var(--sui-control-medium-height) / 6))
208
+ calc((var(--sui-control-medium-height) / 2));
208
209
  --sui-option-height: var(--sui-control-medium-height);
209
210
  // Listbox
210
211
  --sui-listbox-border-radius: var(--sui-control-medium-border-radius);
@@ -44,7 +44,7 @@ type TextEditorState = {
44
44
  */
45
45
  enabledButtons: (TextEditorBlockType | TextEditorInlineType)[];
46
46
  /**
47
- * Function to trigger the Lexical converter.
47
+ * - Function to trigger the Lexical converter.
48
48
  */
49
49
  convertMarkdown: Function;
50
50
  };
@@ -41,5 +41,5 @@
41
41
  * error while converting Markdown to Lexical nodes.
42
42
  * @property {(TextEditorBlockType | TextEditorInlineType)[]} enabledButtons - Enabled buttons for
43
43
  * the editor.
44
- * @property {Function} convertMarkdown Function to trigger the Lexical converter.
44
+ * @property {Function} convertMarkdown - Function to trigger the Lexical converter.
45
45
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltia/ui",
3
- "version": "0.13.2",
3
+ "version": "0.15.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -23,47 +23,47 @@
23
23
  "test:unit": "vitest"
24
24
  },
25
25
  "dependencies": {
26
- "@lexical/code": "^0.14.5",
27
- "@lexical/history": "^0.14.5",
28
- "@lexical/link": "^0.14.5",
29
- "@lexical/list": "^0.14.5",
30
- "@lexical/markdown": "^0.14.5",
31
- "@lexical/rich-text": "^0.14.5",
32
- "@lexical/selection": "^0.14.5",
33
- "@lexical/table": "^0.14.5",
34
- "@lexical/utils": "^0.14.5",
35
- "@sveltia/utils": "^0.1.1",
36
- "lexical": "^0.14.5",
37
- "svelte": "^4.2.15"
26
+ "@lexical/code": "^0.15.0",
27
+ "@lexical/history": "^0.15.0",
28
+ "@lexical/link": "^0.15.0",
29
+ "@lexical/list": "^0.15.0",
30
+ "@lexical/markdown": "^0.15.0",
31
+ "@lexical/rich-text": "^0.15.0",
32
+ "@lexical/selection": "^0.15.0",
33
+ "@lexical/table": "^0.15.0",
34
+ "@lexical/utils": "^0.15.0",
35
+ "@sveltia/utils": "^0.2.0",
36
+ "lexical": "^0.15.0",
37
+ "svelte": "^4.2.16"
38
38
  },
39
39
  "devDependencies": {
40
- "@playwright/test": "^1.43.1",
40
+ "@playwright/test": "^1.44.0",
41
41
  "@sveltejs/adapter-auto": "^3.2.0",
42
42
  "@sveltejs/kit": "^2.5.7",
43
43
  "@sveltejs/package": "^2.3.1",
44
44
  "@sveltejs/vite-plugin-svelte": "^3.1.0",
45
- "cspell": "^8.7.0",
45
+ "cspell": "^8.8.1",
46
46
  "eslint": "^8.57.0",
47
47
  "eslint-config-airbnb-base": "^15.0.0",
48
48
  "eslint-config-prettier": "^9.1.0",
49
49
  "eslint-plugin-import": "^2.29.1",
50
- "eslint-plugin-jsdoc": "^48.2.3",
51
- "eslint-plugin-svelte": "^2.38.0",
50
+ "eslint-plugin-jsdoc": "^48.2.4",
51
+ "eslint-plugin-svelte": "^2.39.0",
52
52
  "npm-run-all": "^4.1.5",
53
53
  "postcss": "^8.4.38",
54
- "postcss-html": "^1.6.0",
54
+ "postcss-html": "^1.7.0",
55
55
  "prettier": "^3.2.5",
56
56
  "prettier-plugin-svelte": "^3.2.3",
57
- "sass": "^1.75.0",
58
- "stylelint": "^16.4.0",
57
+ "sass": "^1.77.1",
58
+ "stylelint": "^16.5.0",
59
59
  "stylelint-config-recommended-scss": "^14.0.0",
60
- "stylelint-scss": "^6.2.1",
61
- "svelte-check": "^3.7.0",
60
+ "stylelint-scss": "^6.3.0",
61
+ "svelte-check": "^3.7.1",
62
62
  "svelte-i18n": "^4.0.0",
63
63
  "svelte-preprocess": "^5.1.4",
64
64
  "tslib": "^2.6.2",
65
- "vite": "^5.2.10",
66
- "vitest": "^1.5.2"
65
+ "vite": "^5.2.11",
66
+ "vitest": "^1.6.0"
67
67
  },
68
68
  "exports": {
69
69
  "./package.json": "./package.json",