@sveltia/ui 0.10.5 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 Kohei Yoshino.
3
+ Copyright (c) 2024 Kohei Yoshino.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -137,6 +137,7 @@
137
137
  on:mouseenter
138
138
  on:mouseleave
139
139
  on:click
140
+ on:dblclick
140
141
  on:dragover
141
142
  on:dragleave
142
143
  on:dragend
@@ -144,6 +145,8 @@
144
145
  on:keydown
145
146
  on:keyup
146
147
  on:keypress
148
+ on:focus
149
+ on:blur
147
150
  on:select={(/** @type {CustomEvent} */ event) => {
148
151
  dispatch('select', event.detail);
149
152
  }}
@@ -231,11 +234,11 @@ button:global(.primary) {
231
234
  font-weight: var(--sui-button-primary-font-weight, normal);
232
235
  }
233
236
  button:global(.primary):hover, button:global(.primary):focus-visible, button:global(.primary)[aria-expanded=true] {
234
- color: var(--sui-button-primary-foreground-color-focus);
237
+ color: var(--sui-button-primary-foreground-color-focus, var(--sui-button-primary-foreground-color, var(--sui-primary-accent-color-inverted)));
235
238
  background-color: var(--sui-button-primary-background-color-focus, var(--sui-primary-accent-color-light));
236
239
  }
237
240
  button:global(.primary):active {
238
- color: var(--sui-button-primary-foreground-color-active);
241
+ color: var(--sui-button-primary-foreground-color-active, var(--sui-button-primary-foreground-color, var(--sui-primary-accent-color-inverted)));
239
242
  background-color: var(--sui-button-primary-background-color-active, var(--sui-primary-accent-color-dark));
240
243
  }
241
244
  button:global(.secondary) {
@@ -247,11 +250,11 @@ button:global(.secondary) {
247
250
  font-weight: var(--sui-button-secondary-font-weight, normal);
248
251
  }
249
252
  button:global(.secondary):hover, button:global(.secondary):focus-visible, button:global(.secondary)[aria-expanded=true] {
250
- color: var(--sui-button-secondary-foreground-color-focus);
253
+ color: var(--sui-button-secondary-foreground-color-focus, var(--sui-button-secondary-foreground-color, var(--sui-primary-accent-color-text)));
251
254
  background-color: var(--sui-button-secondary-background-color-focus, var(--sui-hover-background-color));
252
255
  }
253
256
  button:global(.secondary):active {
254
- color: var(--sui-button-secondary-foreground-color-active);
257
+ color: var(--sui-button-secondary-foreground-color-active, var(--sui-button-secondary-foreground-color, var(--sui-primary-accent-color-text)));
255
258
  background-color: var(--sui-button-secondary-background-color-active, var(--sui-active-background-color));
256
259
  }
257
260
  button:global(.secondary)[aria-pressed=true] {
@@ -267,11 +270,11 @@ button:global(.tertiary) {
267
270
  font-weight: var(--sui-button-tertiary-font-weight, normal);
268
271
  }
269
272
  button:global(.tertiary):hover, button:global(.tertiary):focus-visible, button:global(.tertiary)[aria-expanded=true] {
270
- color: var(--sui-button-tertiary-foreground-color-focus);
273
+ color: var(--sui-button-tertiary-foreground-color-focus, var(--sui-button-tertiary-foreground-color, var(--sui-highlight-foreground-color)));
271
274
  background-color: var(--sui-button-tertiary-background-color-focus, var(--sui-hover-background-color));
272
275
  }
273
276
  button:global(.tertiary):active {
274
- color: var(--sui-button-tertiary-foreground-color-active);
277
+ color: var(--sui-button-tertiary-foreground-color-active, var(--sui-button-tertiary-foreground-color, var(--sui-highlight-foreground-color)));
275
278
  background-color: var(--sui-button-tertiary-background-color-active, var(--sui-active-background-color));
276
279
  }
277
280
  button:global(.tertiary)[aria-pressed=true] {
@@ -31,6 +31,7 @@ export default class Button extends SvelteComponent<{
31
31
  mouseenter: MouseEvent;
32
32
  mouseleave: MouseEvent;
33
33
  click: MouseEvent;
34
+ dblclick: MouseEvent;
34
35
  dragover: DragEvent;
35
36
  dragleave: DragEvent;
36
37
  dragend: DragEvent;
@@ -38,6 +39,8 @@ export default class Button extends SvelteComponent<{
38
39
  keydown: KeyboardEvent;
39
40
  keyup: KeyboardEvent;
40
41
  keypress: KeyboardEvent;
42
+ focus: FocusEvent;
43
+ blur: FocusEvent;
41
44
  select: CustomEvent<any>;
42
45
  change: CustomEvent<any>;
43
46
  } & {
@@ -137,6 +140,7 @@ declare const __propDef: {
137
140
  mouseenter: MouseEvent;
138
141
  mouseleave: MouseEvent;
139
142
  click: MouseEvent;
143
+ dblclick: MouseEvent;
140
144
  dragover: DragEvent;
141
145
  dragleave: DragEvent;
142
146
  dragend: DragEvent;
@@ -144,6 +148,8 @@ declare const __propDef: {
144
148
  keydown: KeyboardEvent;
145
149
  keyup: KeyboardEvent;
146
150
  keypress: KeyboardEvent;
151
+ focus: FocusEvent;
152
+ blur: FocusEvent;
147
153
  select: CustomEvent<any>;
148
154
  change: CustomEvent<any>;
149
155
  } & {
@@ -69,6 +69,7 @@
69
69
  aria-checked={selected}
70
70
  {...$$restProps}
71
71
  on:click
72
+ on:dblclick
72
73
  on:select
73
74
  on:change
74
75
  on:change={(event) => {
@@ -19,6 +19,7 @@ export default class SelectButton extends SvelteComponent<{
19
19
  selected?: boolean | undefined;
20
20
  }, {
21
21
  click: MouseEvent;
22
+ dblclick: MouseEvent;
22
23
  select: CustomEvent<any>;
23
24
  change: CustomEvent<any>;
24
25
  } & {
@@ -52,6 +53,7 @@ declare const __propDef: {
52
53
  };
53
54
  events: {
54
55
  click: MouseEvent;
56
+ dblclick: MouseEvent;
55
57
  select: CustomEvent<any>;
56
58
  change: CustomEvent<any>;
57
59
  } & {
@@ -29,6 +29,9 @@
29
29
  aria-selected={selected}
30
30
  {...$$restProps}
31
31
  on:click
32
+ on:dblclick
33
+ on:focus
34
+ on:blur
32
35
  on:select={(/** @type {any} */ event) => {
33
36
  dispatch('select', /** @type {CustomEvent} */ (event).detail);
34
37
  }}
@@ -12,6 +12,9 @@ export default class GridRow extends SvelteComponent<{
12
12
  selected?: boolean | undefined;
13
13
  }, {
14
14
  click: MouseEvent;
15
+ dblclick: MouseEvent;
16
+ focus: FocusEvent;
17
+ blur: FocusEvent;
15
18
  select: CustomEvent<any>;
16
19
  change: CustomEvent<any>;
17
20
  } & {
@@ -32,6 +35,9 @@ declare const __propDef: {
32
35
  };
33
36
  events: {
34
37
  click: MouseEvent;
38
+ dblclick: MouseEvent;
39
+ focus: FocusEvent;
40
+ blur: FocusEvent;
35
41
  select: CustomEvent<any>;
36
42
  change: CustomEvent<any>;
37
43
  } & {
@@ -53,6 +53,9 @@
53
53
  data-type={typeof value}
54
54
  {...$$restProps}
55
55
  on:click
56
+ on:dblclick
57
+ on:focus
58
+ on:blur
56
59
  on:dragover
57
60
  on:dragleave
58
61
  on:dragend
@@ -16,6 +16,9 @@ export default class Option extends SvelteComponent<{
16
16
  selected?: boolean | undefined;
17
17
  }, {
18
18
  click: MouseEvent;
19
+ dblclick: MouseEvent;
20
+ focus: FocusEvent;
21
+ blur: FocusEvent;
19
22
  dragover: DragEvent;
20
23
  dragleave: DragEvent;
21
24
  dragend: DragEvent;
@@ -51,6 +54,9 @@ declare const __propDef: {
51
54
  };
52
55
  events: {
53
56
  click: MouseEvent;
57
+ dblclick: MouseEvent;
58
+ focus: FocusEvent;
59
+ blur: FocusEvent;
54
60
  dragover: DragEvent;
55
61
  dragleave: DragEvent;
56
62
  dragend: DragEvent;
@@ -72,6 +72,8 @@
72
72
  $isPopupOpen = false;
73
73
  }
74
74
  }}
75
+ on:focus
76
+ on:blur
75
77
  on:select
76
78
  on:change
77
79
  >
@@ -16,6 +16,8 @@ export default class MenuItem extends SvelteComponent<{
16
16
  iconLabel?: string | undefined;
17
17
  }, {
18
18
  click: MouseEvent;
19
+ focus: FocusEvent;
20
+ blur: FocusEvent;
19
21
  select: CustomEvent<any>;
20
22
  change: CustomEvent<any>;
21
23
  } & {
@@ -49,6 +51,8 @@ declare const __propDef: {
49
51
  };
50
52
  events: {
51
53
  click: MouseEvent;
54
+ focus: FocusEvent;
55
+ blur: FocusEvent;
52
56
  select: CustomEvent<any>;
53
57
  change: CustomEvent<any>;
54
58
  } & {
@@ -81,6 +81,8 @@
81
81
  event.preventDefault();
82
82
  checked = true;
83
83
  }}
84
+ on:focus
85
+ on:blur
84
86
  on:select
85
87
  on:change
86
88
  />
@@ -17,6 +17,8 @@ export default class Radio extends SvelteComponent<{
17
17
  value?: string | undefined;
18
18
  hidden?: boolean | undefined;
19
19
  }, {
20
+ focus: FocusEvent;
21
+ blur: FocusEvent;
20
22
  select: CustomEvent<any>;
21
23
  change: CustomEvent<any>;
22
24
  } & {
@@ -41,6 +43,8 @@ declare const __propDef: {
41
43
  hidden?: boolean | undefined;
42
44
  };
43
45
  events: {
46
+ focus: FocusEvent;
47
+ blur: FocusEvent;
44
48
  select: CustomEvent<any>;
45
49
  change: CustomEvent<any>;
46
50
  } & {
@@ -64,6 +64,7 @@
64
64
 
65
65
  const dispatch = createEventDispatcher();
66
66
  const id = getRandomId('combobox');
67
+ const selectedSelector = '[role="option"][aria-selected="true"]';
67
68
  /** @type {HTMLElement} */
68
69
  let comboboxElement;
69
70
  /** @type {TextInput | undefined} */
@@ -75,22 +76,40 @@
75
76
  let label = '';
76
77
 
77
78
  /**
78
- * Update the `value` and `label` whenever an option is selected.
79
+ * Update the {@link label} and selected option when the {@link value} is changed.
80
+ */
81
+ const onChange = () => {
82
+ const selected = popupComponent?.content?.querySelector(selectedSelector);
83
+
84
+ const target = /** @type {HTMLButtonElement} */ (
85
+ popupComponent?.content?.querySelector(`[role="option"][value="${value}"]`)
86
+ );
87
+
88
+ if (target) {
89
+ label = target.querySelector('.label')?.textContent || target.textContent || target.value;
90
+
91
+ if (selected !== target) {
92
+ selected?.setAttribute('aria-selected', 'false');
93
+ target.setAttribute('aria-selected', 'true');
94
+ }
95
+ }
96
+ };
97
+
98
+ /**
99
+ * Update the {@link value} whenever an option is selected.
79
100
  * @param {HTMLButtonElement} target - Selected option.
80
101
  */
81
102
  const onSelect = (target) => {
82
103
  // @todo support more types
83
104
  value = target.dataset.type === 'number' ? Number(target.value) : target.value;
84
- label = target.querySelector('.label')?.textContent || target.value;
105
+ onChange();
85
106
  dispatch('change', { target: inputComponent?.element, value });
86
107
  };
87
108
 
88
109
  $: {
89
110
  if (popupComponent?.content) {
90
111
  window.requestAnimationFrame(() => {
91
- const selected = popupComponent?.content?.querySelector(
92
- '[role="option"][aria-selected="true"]',
93
- );
112
+ const selected = popupComponent?.content?.querySelector(selectedSelector);
94
113
 
95
114
  if (selected) {
96
115
  onSelect(/** @type {HTMLButtonElement} */ (selected));
@@ -98,9 +117,20 @@
98
117
  });
99
118
  }
100
119
  }
120
+
121
+ $: {
122
+ void value;
123
+ onChange();
124
+ }
101
125
  </script>
102
126
 
103
- <div role="none" class="sui combobox {className}" hidden={hidden || undefined} {...$$restProps}>
127
+ <div
128
+ role="none"
129
+ class="sui combobox {className}"
130
+ class:editable
131
+ hidden={hidden || undefined}
132
+ {...$$restProps}
133
+ >
104
134
  {#if !editable}
105
135
  <div
106
136
  role="combobox"
@@ -206,7 +236,7 @@
206
236
  border-top-left-radius: 0;
207
237
  border-bottom-left-radius: 0;
208
238
  }
209
- .combobox.readonly > :global(button) {
239
+ .combobox:not(.editable) > :global(button) {
210
240
  background-color: transparent !important;
211
241
  }
212
242
  .combobox > :global(button[tabindex="-1"]) {
@@ -37,6 +37,8 @@
37
37
  {disabled}
38
38
  aria-selected={selected}
39
39
  {...$$restProps}
40
+ on:focus
41
+ on:blur
40
42
  on:select
41
43
  on:change
42
44
  >
@@ -13,6 +13,8 @@ export default class Tab extends SvelteComponent<{
13
13
  hidden?: boolean | undefined;
14
14
  selected?: boolean | undefined;
15
15
  }, {
16
+ focus: FocusEvent;
17
+ blur: FocusEvent;
16
18
  select: CustomEvent<any>;
17
19
  change: CustomEvent<any>;
18
20
  } & {
@@ -40,6 +42,8 @@ declare const __propDef: {
40
42
  selected?: boolean | undefined;
41
43
  };
42
44
  events: {
45
+ focus: FocusEvent;
46
+ blur: FocusEvent;
43
47
  select: CustomEvent<any>;
44
48
  change: CustomEvent<any>;
45
49
  } & {
@@ -163,7 +163,7 @@
163
163
  height: var(--sui-button-medium-height);
164
164
  }
165
165
  .search-bar :global(.label) {
166
- inset: 0 36px;
166
+ --sui-textbox-padding: 0 36px;
167
167
  }
168
168
  .search-bar :global(.text-input) {
169
169
  flex: auto;
@@ -78,13 +78,21 @@
78
78
  background-color: var(--sui-selected-background-color);
79
79
  }
80
80
  [role=toolbar] :global(h2) {
81
+ flex: auto;
81
82
  display: flex;
82
83
  align-items: center;
83
84
  gap: 8px;
84
85
  margin: 0;
85
86
  padding: 0 8px;
87
+ min-width: 0;
86
88
  font-size: var(--sui-font-size-large);
87
89
  }
90
+ [role=toolbar] :global(h2) :global(strong) {
91
+ display: block;
92
+ overflow: hidden;
93
+ text-overflow: ellipsis;
94
+ white-space: nowrap;
95
+ }
88
96
  [role=toolbar] :global(h2) :global(span) {
89
97
  font-size: var(--sui-font-size-small);
90
98
  font-weight: normal;
@@ -112,7 +112,7 @@
112
112
  var(--sui-success-color-hue) var(--sui-alert-foreground-color-saturation)
113
113
  var(--sui-alert-foreground-color-lightness)
114
114
  );
115
- --sui-hover-background-color: hsl(var(--sui-background-color-5-hsl) / 50%);
115
+ --sui-hover-background-color: hsl(var(--sui-background-color-5-hsl) / 35%);
116
116
  --sui-selected-background-color: hsl(var(--sui-background-color-5-hsl) / 75%);
117
117
  --sui-active-background-color: hsl(var(--sui-background-color-5-hsl) / 100%);
118
118
  --sui-content-background-color: hsl(var(--sui-background-color-1-hsl));
@@ -171,7 +171,7 @@
171
171
  --sui-font-weight-normal: 300;
172
172
  --sui-font-weight-bold: 600;
173
173
  --sui-font-family-monospace: "Noto Sans Mono", monospace;
174
- --sui-font-size-monospace: 13px;
174
+ --sui-font-size-monospace: 12.5px;
175
175
  --sui-line-height-default: 1.25;
176
176
  --sui-line-height-compact: 1.5;
177
177
  --sui-line-height-comfortable: 1.75;
@@ -424,6 +424,10 @@
424
424
  }
425
425
  }
426
426
 
427
+ :global(::selection) {
428
+ background-color: var(--sui-primary-accent-color-translucent);
429
+ }
430
+
427
431
  :global(*) {
428
432
  -webkit-tap-highlight-color: transparent;
429
433
  }
@@ -465,6 +469,7 @@
465
469
  :global(code),
466
470
  :global(pre) {
467
471
  font-family: var(--sui-font-family-monospace);
472
+ font-size: var(--sui-font-size-monospace);
468
473
  }
469
474
 
470
475
  :global(pre) {
@@ -61,7 +61,6 @@ class Group {
61
61
 
62
62
  this.parent = parent;
63
63
  this.role = /** @type {string} */ (parent.getAttribute('role'));
64
- this.grid = this.role === 'listbox' && parent.matches('.grid');
65
64
  this.multi = this.parent.getAttribute('aria-multiselectable') === 'true';
66
65
  this.id = getRandomId(this.role);
67
66
  this.parentGroupSelector = `[role="group"], [role="${this.role}"]`;
@@ -112,9 +111,7 @@ class Group {
112
111
  });
113
112
 
114
113
  parent.addEventListener('click', (event) => {
115
- if (/** @type {HTMLElement} */ (event.target).matches(this.selector)) {
116
- this.onClick(event);
117
- }
114
+ this.onClick(event);
118
115
  });
119
116
 
120
117
  parent.addEventListener('keydown', (event) => {
@@ -176,6 +173,14 @@ class Group {
176
173
  return this.parent.matches('[aria-readonly="true"]');
177
174
  }
178
175
 
176
+ /**
177
+ * Whether the widget is displayed in grid mode.
178
+ * @type {boolean}
179
+ */
180
+ get grid() {
181
+ return this.role === 'grid' || (this.role === 'listbox' && this.parent.matches('.grid'));
182
+ }
183
+
179
184
  /**
180
185
  * Select (and move focus to) the given target.
181
186
  * @param {(MouseEvent | KeyboardEvent)} event - Triggered event.
@@ -241,13 +246,21 @@ class Group {
241
246
  }
242
247
 
243
248
  if (this.focusChild) {
244
- element.tabIndex = isTarget ? 0 : -1;
249
+ // Wait a bit before the element is rerendered
250
+ window.requestAnimationFrame(() => {
251
+ element.tabIndex = isTarget ? 0 : -1;
245
252
 
246
- if (isTarget) {
247
- element.focus();
248
- }
253
+ if (isTarget) {
254
+ element.focus();
255
+ element.dispatchEvent(new CustomEvent('focus'));
256
+ }
257
+ });
249
258
  } else {
250
259
  element.classList.toggle('focused', isTarget);
260
+
261
+ if (isTarget) {
262
+ element.dispatchEvent(new CustomEvent('focus'));
263
+ }
251
264
  }
252
265
 
253
266
  if (controlTarget) {
@@ -299,7 +312,10 @@ class Group {
299
312
  onClick(event) {
300
313
  // eslint-disable-next-line prefer-destructuring
301
314
  const target = /** @type {HTMLElement} */ (event.target);
302
- const newTarget = target.matches(this.selector) ? target : undefined;
315
+
316
+ const newTarget = target.matches(this.selector)
317
+ ? target
318
+ : /** @type {HTMLElement | null} */ (target.closest(this.selector));
303
319
 
304
320
  if (!newTarget || event.button !== 0) {
305
321
  return;
@@ -35,6 +35,10 @@
35
35
  }
36
36
  }
37
37
 
38
+ ::selection {
39
+ background-color: var(--sui-primary-accent-color-translucent);
40
+ }
41
+
38
42
  * {
39
43
  -webkit-tap-highlight-color: transparent;
40
44
  }
@@ -76,6 +80,7 @@ li {
76
80
  code,
77
81
  pre {
78
82
  font-family: var(--sui-font-family-monospace);
83
+ font-size: var(--sui-font-size-monospace);
79
84
  }
80
85
 
81
86
  pre {
@@ -97,7 +97,7 @@
97
97
  var(--sui-alert-foreground-color-lightness)
98
98
  );
99
99
  // Background
100
- --sui-hover-background-color: hsl(var(--sui-background-color-5-hsl) / 50%);
100
+ --sui-hover-background-color: hsl(var(--sui-background-color-5-hsl) / 35%);
101
101
  --sui-selected-background-color: hsl(var(--sui-background-color-5-hsl) / 75%);
102
102
  --sui-active-background-color: hsl(var(--sui-background-color-5-hsl) / 100%);
103
103
  --sui-content-background-color: hsl(var(--sui-background-color-1-hsl));
@@ -160,7 +160,7 @@
160
160
  --sui-font-weight-normal: 300;
161
161
  --sui-font-weight-bold: 600;
162
162
  --sui-font-family-monospace: "Noto Sans Mono", monospace;
163
- --sui-font-size-monospace: 13px;
163
+ --sui-font-size-monospace: 12.5px;
164
164
  --sui-line-height-default: 1.25;
165
165
  --sui-line-height-compact: 1.5;
166
166
  --sui-line-height-comfortable: 1.75;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltia/ui",
3
- "version": "0.10.5",
3
+ "version": "0.10.7",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -23,36 +23,36 @@
23
23
  "test:unit": "vitest"
24
24
  },
25
25
  "dependencies": {
26
- "svelte": "^4.2.9"
26
+ "svelte": "^4.2.12"
27
27
  },
28
28
  "devDependencies": {
29
- "@playwright/test": "^1.41.1",
29
+ "@playwright/test": "^1.42.1",
30
30
  "@sveltejs/adapter-auto": "^3.1.1",
31
- "@sveltejs/kit": "^2.4.1",
32
- "@sveltejs/package": "^2.2.6",
33
- "@sveltejs/vite-plugin-svelte": "^3.0.1",
34
- "cspell": "^8.3.2",
35
- "eslint": "^8.56.0",
31
+ "@sveltejs/kit": "^2.5.4",
32
+ "@sveltejs/package": "^2.3.0",
33
+ "@sveltejs/vite-plugin-svelte": "^3.0.2",
34
+ "cspell": "^8.6.0",
35
+ "eslint": "^8.57.0",
36
36
  "eslint-config-airbnb-base": "^15.0.0",
37
37
  "eslint-config-prettier": "^9.1.0",
38
38
  "eslint-plugin-import": "^2.29.1",
39
- "eslint-plugin-jsdoc": "^48.0.2",
39
+ "eslint-plugin-jsdoc": "^48.2.1",
40
40
  "eslint-plugin-svelte": "^2.35.1",
41
41
  "npm-run-all": "^4.1.5",
42
- "postcss": "^8.4.33",
42
+ "postcss": "^8.4.35",
43
43
  "postcss-html": "^1.6.0",
44
- "prettier": "^3.2.4",
45
- "prettier-plugin-svelte": "^3.1.2",
46
- "sass": "^1.70.0",
47
- "stylelint": "^16.2.0",
44
+ "prettier": "^3.2.5",
45
+ "prettier-plugin-svelte": "^3.2.2",
46
+ "sass": "^1.72.0",
47
+ "stylelint": "^16.2.1",
48
48
  "stylelint-config-recommended-scss": "^14.0.0",
49
- "stylelint-scss": "^6.0.0",
50
- "svelte-check": "^3.6.3",
49
+ "stylelint-scss": "^6.2.1",
50
+ "svelte-check": "^3.6.7",
51
51
  "svelte-i18n": "^4.0.0",
52
52
  "svelte-preprocess": "^5.1.3",
53
53
  "tslib": "^2.6.2",
54
- "vite": "^5.0.12",
55
- "vitest": "^1.2.1"
54
+ "vite": "^5.1.6",
55
+ "vitest": "^1.4.0"
56
56
  },
57
57
  "exports": {
58
58
  "./package.json": "./package.json",