vueless 1.2.5-beta.1 → 1.2.5-beta.3

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/constants.d.ts CHANGED
@@ -10,7 +10,6 @@ export const ROUNDING: "rounding";
10
10
  export const DISABLED_OPACITY: "disabled-opacity";
11
11
  export const LETTER_SPACING: "letter-spacing";
12
12
  export const COLOR_MODE_KEY: "vl-color-mode";
13
- export const AUTO_MODE_KEY: "vl-auto-mode";
14
13
  export const DARK_MODE_CLASS: "vl-dark";
15
14
  export const LIGHT_MODE_CLASS: "vl-light";
16
15
  export const DEFAULT_PRIMARY_COLOR: "grayscale";
@@ -293,11 +292,9 @@ export namespace DEFAULT_SVGO_CONFIG {
293
292
  let plugins: {
294
293
  name: string;
295
294
  params: {
296
- overrides: {
297
- convertColors: {
298
- currentColor: boolean;
299
- };
300
- };
295
+ attributes: {
296
+ fill: string;
297
+ }[];
301
298
  };
302
299
  }[];
303
300
  }
package/constants.js CHANGED
@@ -20,7 +20,6 @@ export const LETTER_SPACING = "letter-spacing";
20
20
 
21
21
  /* Vueless color mode keys */
22
22
  export const COLOR_MODE_KEY = "vl-color-mode";
23
- export const AUTO_MODE_KEY = "vl-auto-mode";
24
23
  export const DARK_MODE_CLASS = "vl-dark";
25
24
  export const LIGHT_MODE_CLASS = "vl-light";
26
25
 
@@ -368,13 +367,9 @@ export const TAILWIND_MERGE_EXTENSION = {
368
367
  export const DEFAULT_SVGO_CONFIG = {
369
368
  plugins: [
370
369
  {
371
- name: "preset-default",
370
+ name: "addAttributesToSVGElement",
372
371
  params: {
373
- overrides: {
374
- convertColors: {
375
- currentColor: true,
376
- },
377
- },
372
+ attributes: [{ fill: "currentColor" }],
378
373
  },
379
374
  },
380
375
  ],
package/index.d.ts CHANGED
@@ -8,13 +8,10 @@ export {
8
8
  isCSR,
9
9
  setTitle,
10
10
  getRandomId,
11
- getCookie,
12
- setCookie,
13
- deleteCookie,
14
11
  createDebounce,
15
12
  hasSlotContent
16
13
  } from "./utils/helper";
17
- export { getStored, setTheme, cssVar } from "./utils/theme";
14
+ export { getStored, getTheme, setTheme, resetTheme, cssVar } from "./utils/theme";
18
15
  export { isMac, isPWA, isIOS, isAndroid, isMobileApp, isWindows } from "./utils/platform";
19
16
  export { cx, cva, compose, getDefaults, setVuelessConfig, setColor, vuelessConfig } from "./utils/ui";
20
17
  export { getArgTypes, getSlotNames, getSlotsFragment, getSource, getDocsDescription } from "./utils/storybook";
package/index.ts CHANGED
@@ -14,13 +14,10 @@ export {
14
14
  isCSR,
15
15
  setTitle,
16
16
  getRandomId,
17
- getCookie,
18
- setCookie,
19
- deleteCookie,
20
17
  createDebounce,
21
18
  hasSlotContent
22
19
  } from "./utils/helper";
23
- export { getStored, setTheme, cssVar } from "./utils/theme";
20
+ export { getStored, getTheme, setTheme, resetTheme, cssVar } from "./utils/theme";
24
21
  export { isMac, isPWA, isIOS, isAndroid, isMobileApp, isWindows } from "./utils/platform";
25
22
  export { cx, cva, compose, getDefaults, setVuelessConfig, setColor, vuelessConfig } from "./utils/ui";
26
23
  export { getArgTypes, getSlotNames, getSlotsFragment, getSource, getDocsDescription } from "./utils/storybook";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "1.2.5-beta.1",
3
+ "version": "1.2.5-beta.3",
4
4
  "description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
5
5
  "author": "Johnny Grid <hello@vueless.com> (https://vueless.com)",
6
6
  "homepage": "https://vueless.com",
@@ -56,7 +56,7 @@
56
56
  "@vue/eslint-config-typescript": "^14.6.0",
57
57
  "@vue/test-utils": "^2.4.6",
58
58
  "@vue/tsconfig": "^0.7.0",
59
- "@vueless/storybook": "^1.2.1",
59
+ "@vueless/storybook": "^1.2.2",
60
60
  "eslint": "^9.32.0",
61
61
  "eslint-plugin-storybook": "^9.0.18",
62
62
  "eslint-plugin-vue": "^10.3.0",
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed, provide, useTemplateRef, ref, watch } from "vue";
2
+ import { computed, provide, useTemplateRef, ref, watch, onMounted } from "vue";
3
3
 
4
4
  import useUI from "../composables/useUI";
5
5
  import { getDefaults } from "../utils/ui";
@@ -15,7 +15,7 @@ defineOptions({ inheritAttrs: false });
15
15
 
16
16
  const props = withDefaults(defineProps<Props>(), {
17
17
  ...getDefaults<Props, Config>(defaultConfig, COMPONENT_NAME),
18
- modelValue: undefined,
18
+ modelValue: () => [],
19
19
  options: () => [],
20
20
  });
21
21
 
@@ -42,6 +42,16 @@ const selectedItem = computed({
42
42
  },
43
43
  });
44
44
 
45
+ onMounted(() => {
46
+ const initiallyOpened = props.options
47
+ .filter((option) => option.opened)
48
+ .map((option) => option.value);
49
+
50
+ if (initiallyOpened.length > 0) {
51
+ selectedItem.value = props.multiple ? initiallyOpened : initiallyOpened[0];
52
+ }
53
+ });
54
+
45
55
  provide<SetAccordionSelectedItem>("setAccordionSelectedItem", (value, opened) => {
46
56
  if (props.multiple) {
47
57
  let current: string[] = [];
@@ -101,7 +111,6 @@ const { getDataTest, accordionItemAttrs, accordionAttrs } = useUI<Config>(defaul
101
111
  :key="index"
102
112
  :model-value="selectedItem"
103
113
  :value="option.value"
104
- :opened="option.opened"
105
114
  :title="option.title"
106
115
  :description="option.description"
107
116
  :size="size"
@@ -28,7 +28,7 @@ export default {
28
28
  title: "Containers / Accordion",
29
29
  component: UAccordion,
30
30
  args: {
31
- modelValue: "2",
31
+ modelValue: null,
32
32
  options: [
33
33
  {
34
34
  value: "1",
@@ -40,6 +40,7 @@ export default {
40
40
  },
41
41
  {
42
42
  value: "2",
43
+ opened: true,
43
44
  title: "Pioneering Cutting-Edge Solutions",
44
45
  description:
45
46
  trimText(`Our team stays ahead of the curve, integrating the latest technologies
@@ -1,3 +1,4 @@
1
+ import { ref } from "vue";
1
2
  import { mount } from "@vue/test-utils";
2
3
  import { describe, it, expect } from "vitest";
3
4
 
@@ -57,8 +58,17 @@ describe("UAccordion", () => {
57
58
  // Events
58
59
  describe("Events", () => {
59
60
  it("emits update:modelValue when an item is toggled (single)", async () => {
61
+ const modelValue = ref<string | null>(null);
62
+
60
63
  const component = mount(UAccordion, {
61
- props: { options },
64
+ props: {
65
+ options,
66
+ modelValue: modelValue.value,
67
+ "onUpdate:modelValue": (value: string | null) => {
68
+ modelValue.value = value;
69
+ component.setProps({ modelValue: value });
70
+ },
71
+ },
62
72
  });
63
73
 
64
74
  const firstItem = component.findAllComponents(UAccordionItem)[0];
@@ -77,8 +87,18 @@ describe("UAccordion", () => {
77
87
  });
78
88
 
79
89
  it("emits update:modelValue with arrays when multiple=true", async () => {
90
+ const modelValue = ref<string[]>([]);
91
+
80
92
  const component = mount(UAccordion, {
81
- props: { options, multiple: true },
93
+ props: {
94
+ options,
95
+ multiple: true,
96
+ modelValue: modelValue.value,
97
+ "onUpdate:modelValue": (value: string[]) => {
98
+ modelValue.value = value;
99
+ component.setProps({ modelValue: value });
100
+ },
101
+ },
82
102
  });
83
103
 
84
104
  const [firstItem, secondItem] = component.findAllComponents(UAccordionItem);
@@ -54,7 +54,7 @@ watchEffect(() => (accordionDisabled.value = toValue(getAccordionDisabled) || pr
54
54
  const slots = useSlots();
55
55
  const elementId = props.id || useId();
56
56
 
57
- const internalOpened = ref(false);
57
+ const internalOpened = ref(props.opened || false);
58
58
 
59
59
  const isOpened = computed(() => {
60
60
  const selectedItem = toValue(getAccordionSelectedItem);
@@ -67,7 +67,7 @@ const isOpened = computed(() => {
67
67
  return isEqual(selectedItem, props.value);
68
68
  }
69
69
 
70
- return props.opened || internalOpened.value;
70
+ return internalOpened.value;
71
71
  });
72
72
 
73
73
  const toggleIconName = computed(() => {
@@ -27,6 +27,7 @@ export default {
27
27
  title: "Containers / Accordion Item",
28
28
  component: UAccordionItem,
29
29
  args: {
30
+ opened: true,
30
31
  title: "Committed to Quality and Performance",
31
32
  description: trimText(
32
33
  `We take pride in delivering high-quality solutions tailored to your needs.
@@ -1,6 +1,6 @@
1
1
  export default /*tw*/ {
2
2
  icon: {
3
- base: "text-{color} fill-current shrink-0 grow-0 focus:outline-0",
3
+ base: "text-{color} shrink-0 grow-0 focus:outline-0",
4
4
  variants: {
5
5
  variant: {
6
6
  light: "brightness-125",
@@ -2,13 +2,15 @@ import fs from "node:fs";
2
2
  import { compileTemplate } from "vue/compiler-sfc";
3
3
  import { optimize as optimizeSvg } from "svgo";
4
4
 
5
+ import { getVuelessConfig } from "./vuelessConfig.js";
5
6
  import { DEFAULT_SVGO_CONFIG } from "../../constants.js";
6
7
 
7
8
  export async function loadSvg(id, options) {
8
- const {
9
+ let {
10
+ basePath = "",
9
11
  defaultImport = "url",
12
+ svgoConfig = {},
10
13
  svgo = true,
11
- svgoConfig = DEFAULT_SVGO_CONFIG,
12
14
  debug = false,
13
15
  } = options;
14
16
  const svgRegex = /\.svg(\?(raw|url|component|skipsvgo))?$/;
@@ -45,7 +47,11 @@ export async function loadSvg(id, options) {
45
47
  }
46
48
 
47
49
  if (svgo !== false && query !== "skipsvgo") {
50
+ const vuelessConfig = getVuelessConfig(basePath);
51
+ const isLucideLibrary = vuelessConfig.components?.UIcon?.defaults?.library === "lucide-static";
52
+
48
53
  svg = optimizeSvg(svg, {
54
+ ...(isLucideLibrary ? {} : DEFAULT_SVGO_CONFIG),
49
55
  ...svgoConfig,
50
56
  svgPath,
51
57
  }).data;
package/utils/theme.ts CHANGED
@@ -1,12 +1,11 @@
1
1
  import { cloneDeep, merge } from "lodash-es";
2
2
 
3
3
  import { vuelessConfig } from "./ui";
4
- import { isCSR, setCookie } from "./helper";
4
+ import { isCSR, isSSR, setCookie, deleteCookie } from "./helper";
5
5
 
6
6
  import {
7
7
  PX_IN_REM,
8
8
  COLOR_MODE_KEY,
9
- AUTO_MODE_KEY,
10
9
  LIGHT_MODE_CLASS,
11
10
  DARK_MODE_CLASS,
12
11
  GRAYSCALE_COLOR,
@@ -78,15 +77,11 @@ function toggleColorModeClass() {
78
77
  /**
79
78
  * Sets color mode.
80
79
  * @param {string} mode (dark | light | auto)
81
- * @param {boolean} isCachedAutoMode
82
80
  * @return {string} current color mode
83
81
  */
84
- function setColorMode(mode: `${ColorMode}`, isCachedAutoMode?: boolean): string {
82
+ function setColorMode(mode: `${ColorMode}`): string {
85
83
  const colorMode = mode || getStored(COLOR_MODE_KEY) || vuelessConfig.colorMode || ColorMode.Light;
86
84
 
87
- // TODO: This always true `!!Number(getStored(AUTO_MODE_KEY))` > `!!Number(undefined) = true`
88
- isCachedAutoMode = isCachedAutoMode ?? !!Number(getStored(AUTO_MODE_KEY));
89
-
90
85
  const isAutoMode = colorMode === ColorMode.Auto;
91
86
  const isSystemDarkMode = isAutoMode && prefersColorSchemeDark && prefersColorSchemeDark?.matches;
92
87
  const isDarkMode = colorMode === ColorMode.Dark || isSystemDarkMode;
@@ -97,7 +92,7 @@ function setColorMode(mode: `${ColorMode}`, isCachedAutoMode?: boolean): string
97
92
  }
98
93
 
99
94
  /* Adding system color mode change event listener. */
100
- if ((isAutoMode || isCachedAutoMode) && prefersColorSchemeDark) {
95
+ if (isAutoMode && prefersColorSchemeDark) {
101
96
  prefersColorSchemeDark.addEventListener("change", toggleColorModeClass);
102
97
  }
103
98
 
@@ -117,10 +112,7 @@ function setColorMode(mode: `${ColorMode}`, isCachedAutoMode?: boolean): string
117
112
 
118
113
  if (mode) {
119
114
  setCookie(COLOR_MODE_KEY, currentColorMode);
120
- setCookie(AUTO_MODE_KEY, String(Number(isAutoMode || isCachedAutoMode)));
121
-
122
115
  localStorage.setItem(COLOR_MODE_KEY, currentColorMode);
123
- localStorage.setItem(AUTO_MODE_KEY, String(Number(isAutoMode || isCachedAutoMode)));
124
116
  }
125
117
 
126
118
  return currentColorMode;
@@ -139,7 +131,73 @@ export function cssVar(name: string) {
139
131
  * @return string | undefined
140
132
  */
141
133
  export function getStored(key: string) {
142
- return isCSR ? localStorage.getItem(key) : undefined;
134
+ if (isSSR) return;
135
+
136
+ return localStorage.getItem(key) ?? undefined;
137
+ }
138
+
139
+ /**
140
+ * Resets all theme data by clearing cookies and localStorage.
141
+ * This removes all stored theme preferences including color mode, colors, text sizes,
142
+ * outline sizes, rounding values, letter spacing, and disabled opacity.
143
+ */
144
+ export function resetTheme() {
145
+ if (!isCSR) return;
146
+
147
+ const themeKeys = [
148
+ COLOR_MODE_KEY,
149
+ `vl-${PRIMARY_COLOR}`,
150
+ `vl-${NEUTRAL_COLOR}`,
151
+ `vl-${TEXT}-xs`,
152
+ `vl-${TEXT}-sm`,
153
+ `vl-${TEXT}-md`,
154
+ `vl-${TEXT}-lg`,
155
+ `vl-${OUTLINE}-sm`,
156
+ `vl-${OUTLINE}-md`,
157
+ `vl-${OUTLINE}-lg`,
158
+ `vl-${ROUNDING}-sm`,
159
+ `vl-${ROUNDING}-md`,
160
+ `vl-${ROUNDING}-lg`,
161
+ `vl-${LETTER_SPACING}`,
162
+ `vl-${DISABLED_OPACITY}`,
163
+ ];
164
+
165
+ themeKeys.forEach((key) => {
166
+ localStorage.removeItem(key);
167
+ deleteCookie(key);
168
+ });
169
+ }
170
+
171
+ /**
172
+ * Retrieves the current theme configuration.
173
+ * @return ThemeConfig - current theme configuration
174
+ */
175
+ export function getTheme(): ThemeConfig {
176
+ const colorMode = getStored(COLOR_MODE_KEY) || vuelessConfig.colorMode || ColorMode.Light;
177
+ const primary = getPrimaryColor();
178
+ const neutral = getNeutralColor();
179
+
180
+ const text = getText();
181
+ const outline = getOutlines();
182
+ const rounding = getRoundings();
183
+ const letterSpacing = getLetterSpacing();
184
+ const disabledOpacity = getDisabledOpacity();
185
+
186
+ const lightTheme = merge({}, DEFAULT_LIGHT_THEME, vuelessConfig.lightTheme);
187
+ const darkTheme = merge({}, DEFAULT_DARK_THEME, vuelessConfig.darkTheme);
188
+
189
+ return {
190
+ colorMode: colorMode as `${ColorMode}`,
191
+ primary,
192
+ neutral,
193
+ text,
194
+ outline,
195
+ rounding,
196
+ letterSpacing,
197
+ disabledOpacity,
198
+ lightTheme,
199
+ darkTheme,
200
+ };
143
201
  }
144
202
 
145
203
  /**
@@ -147,8 +205,8 @@ export function getStored(key: string) {
147
205
  * Changes and reset Vueless CSS variables.
148
206
  * @return string - CSS variables
149
207
  */
150
- export function setTheme(config: ThemeConfig = {}, isCachedAutoMode?: boolean) {
151
- if (isCSR) setColorMode(config.colorMode as ColorMode, isCachedAutoMode);
208
+ export function setTheme(config: ThemeConfig = {}) {
209
+ if (isCSR) setColorMode(config.colorMode as ColorMode);
152
210
 
153
211
  const text = getText(config.text);
154
212
  const outline = getOutlines(config.outline);
@@ -306,6 +364,12 @@ function getText(text?: ThemeConfig["text"]) {
306
364
 
307
365
  const runtimeText = primitiveToObject(text) as ThemeConfigText;
308
366
  const globalText = primitiveToObject(vuelessConfig.text) as ThemeConfigText;
367
+ const storedText = {
368
+ xs: getStored(storageKey.xs),
369
+ sm: getStored(storageKey.sm),
370
+ md: getStored(storageKey.md),
371
+ lg: getStored(storageKey.lg),
372
+ };
309
373
 
310
374
  const textMd = Math.max(0, Number(runtimeText.md ?? globalText.md ?? DEFAULT_TEXT));
311
375
  const textXs = Math.max(0, textMd - TEXT_DECREMENT * 2);
@@ -319,20 +383,22 @@ function getText(text?: ThemeConfig["text"]) {
319
383
  lg: Math.max(0, Number(runtimeText.lg ?? getStored(storageKey.lg) ?? globalText.lg ?? 0)),
320
384
  };
321
385
 
386
+ /* eslint-disable prettier/prettier,vue/max-len */
322
387
  const mergedText = {
323
- xs: runtimeText.xs === undefined && globalText.xs === undefined ? textXs : definedText.xs,
324
- sm: runtimeText.sm === undefined && globalText.sm === undefined ? textSm : definedText.sm,
325
- md: runtimeText.md === undefined && globalText.md === undefined ? textMd : definedText.md,
326
- lg: runtimeText.lg === undefined && globalText.lg === undefined ? textLg : definedText.lg,
388
+ xs: runtimeText.xs === undefined && globalText.xs === undefined && (storedText.xs === undefined || typeof text === "number") ? textXs : definedText.xs,
389
+ sm: runtimeText.sm === undefined && globalText.sm === undefined && (storedText.sm === undefined || typeof text === "number") ? textSm : definedText.sm,
390
+ md: runtimeText.md === undefined && globalText.md === undefined && storedText.md === undefined ? textMd : definedText.md,
391
+ lg: runtimeText.lg === undefined && globalText.lg === undefined && (storedText.lg === undefined || typeof text === "number") ? textLg : definedText.lg,
327
392
  };
393
+ /* eslint-enable prettier/prettier,vue/max-len */
328
394
 
329
- if (isCSR && text) {
330
- setCookie(storageKey.sm, String(mergedText.xs));
395
+ if (isCSR && text !== undefined) {
396
+ setCookie(storageKey.xs, String(mergedText.xs));
331
397
  setCookie(storageKey.sm, String(mergedText.sm));
332
398
  setCookie(storageKey.md, String(mergedText.md));
333
399
  setCookie(storageKey.lg, String(mergedText.lg));
334
400
 
335
- localStorage.setItem(storageKey.sm, String(mergedText.xs));
401
+ localStorage.setItem(storageKey.xs, String(mergedText.xs));
336
402
  localStorage.setItem(storageKey.sm, String(mergedText.sm));
337
403
  localStorage.setItem(storageKey.md, String(mergedText.md));
338
404
  localStorage.setItem(storageKey.lg, String(mergedText.lg));
@@ -354,6 +420,11 @@ function getOutlines(outline?: ThemeConfig["outline"]) {
354
420
 
355
421
  const runtimeOutline = primitiveToObject(outline) as ThemeConfigOutline;
356
422
  const globalOutline = primitiveToObject(vuelessConfig.outline) as ThemeConfigOutline;
423
+ const storedOutline = {
424
+ sm: getStored(storageKey.sm),
425
+ md: getStored(storageKey.md),
426
+ lg: getStored(storageKey.lg),
427
+ };
357
428
 
358
429
  const outlineMd = Math.max(0, Number(runtimeOutline.md ?? globalOutline.md ?? DEFAULT_OUTLINE));
359
430
  const outlineSm = Math.max(0, outlineMd - OUTLINE_DECREMENT);
@@ -369,15 +440,15 @@ function getOutlines(outline?: ThemeConfig["outline"]) {
369
440
  lg: Math.max(0, Number(runtimeOutline.lg ?? getStored(storageKey.lg) ?? globalOutline.lg ?? 0)),
370
441
  };
371
442
 
372
- /* eslint-disable prettier/prettier */
443
+ /* eslint-disable prettier/prettier,vue/max-len */
373
444
  const mergedOutline = {
374
- sm: runtimeOutline.sm === undefined && globalOutline.sm === undefined ? outlineSm : definedOutline.sm,
375
- md: runtimeOutline.md === undefined && globalOutline.md === undefined ? outlineMd : definedOutline.md,
376
- lg: runtimeOutline.lg === undefined && globalOutline.lg === undefined ? outlineLg : definedOutline.lg,
445
+ sm: runtimeOutline.sm === undefined && globalOutline.sm === undefined && (storedOutline.sm === undefined || typeof outline === "number") ? outlineSm : definedOutline.sm,
446
+ md: runtimeOutline.md === undefined && globalOutline.md === undefined && storedOutline.md === undefined ? outlineMd : definedOutline.md,
447
+ lg: runtimeOutline.lg === undefined && globalOutline.lg === undefined && (storedOutline.lg === undefined || typeof outline === "number") ? outlineLg : definedOutline.lg,
377
448
  };
378
- /* eslint-enable prettier/prettier */
449
+ /* eslint-enable prettier/prettier,vue/max-len */
379
450
 
380
- if (isCSR && outline) {
451
+ if (isCSR && outline !== undefined) {
381
452
  setCookie(storageKey.sm, String(mergedOutline.sm));
382
453
  setCookie(storageKey.md, String(mergedOutline.md));
383
454
  setCookie(storageKey.lg, String(mergedOutline.lg));
@@ -403,6 +474,11 @@ function getRoundings(rounding?: ThemeConfig["rounding"]) {
403
474
 
404
475
  const runtimeRounding = primitiveToObject(rounding) as ThemeConfigRounding;
405
476
  const globalRounding = primitiveToObject(vuelessConfig.rounding) as ThemeConfigRounding;
477
+ const storedRounding = {
478
+ sm: getStored(storageKey.sm),
479
+ md: getStored(storageKey.md),
480
+ lg: getStored(storageKey.lg),
481
+ };
406
482
 
407
483
  // eslint-disable-next-line prettier/prettier
408
484
  const roundingMd = Math.max(0, Number(runtimeRounding.md ?? globalRounding.md ?? DEFAULT_ROUNDING));
@@ -421,7 +497,7 @@ function getRoundings(rounding?: ThemeConfig["rounding"]) {
421
497
  roundingLg = ROUNDING_INCREMENT - ROUNDING_DECREMENT;
422
498
  }
423
499
 
424
- /* eslint-disable prettier/prettier */
500
+ /* eslint-disable prettier/prettier,vue/max-len */
425
501
  const definedRounding = {
426
502
  sm: Math.max(0, Number(runtimeRounding.sm ?? getStored(storageKey.sm) ?? globalRounding.sm ?? 0)),
427
503
  md: Math.max(0, Number(runtimeRounding.md ?? getStored(storageKey.md) ?? globalRounding.md ?? 0)),
@@ -429,13 +505,13 @@ function getRoundings(rounding?: ThemeConfig["rounding"]) {
429
505
  };
430
506
 
431
507
  const mergedRounding = {
432
- sm: runtimeRounding.sm === undefined && globalRounding.sm === undefined ? roundingSm : definedRounding.sm,
433
- md: runtimeRounding.md === undefined && globalRounding.md === undefined ? roundingMd : definedRounding.md,
434
- lg: runtimeRounding.lg === undefined && globalRounding.lg === undefined ? roundingLg : definedRounding.lg,
508
+ sm: runtimeRounding.sm === undefined && globalRounding.sm === undefined && (storedRounding.sm === undefined || typeof rounding === "number") ? roundingSm : definedRounding.sm,
509
+ md: runtimeRounding.md === undefined && globalRounding.md === undefined && storedRounding.md === undefined ? roundingMd : definedRounding.md,
510
+ lg: runtimeRounding.lg === undefined && globalRounding.lg === undefined && (storedRounding.lg === undefined || typeof rounding === "number") ? roundingLg : definedRounding.lg,
435
511
  };
436
- /* eslint-enable prettier/prettier */
512
+ /* eslint-enable prettier/prettier,vue/max-len */
437
513
 
438
- if (isCSR && rounding) {
514
+ if (isCSR && rounding !== undefined) {
439
515
  setCookie(storageKey.sm, String(mergedRounding.sm));
440
516
  setCookie(storageKey.md, String(mergedRounding.md));
441
517
  setCookie(storageKey.lg, String(mergedRounding.lg));
@@ -456,9 +532,9 @@ function getLetterSpacing(letterSpacing?: ThemeConfig["letterSpacing"]) {
456
532
  const storageKey = `vl-${LETTER_SPACING}`;
457
533
 
458
534
  const spacing = letterSpacing ?? getStored(storageKey) ?? vuelessConfig.letterSpacing;
459
- const mergedSpacing = Number(spacing ?? DEFAULT_LETTER_SPACING);
535
+ const mergedSpacing = Math.max(0, Number(spacing ?? DEFAULT_LETTER_SPACING));
460
536
 
461
- if (isCSR && letterSpacing) {
537
+ if (isCSR && letterSpacing !== undefined) {
462
538
  setCookie(storageKey, String(mergedSpacing));
463
539
  localStorage.setItem(storageKey, String(mergedSpacing));
464
540
  }
@@ -476,7 +552,7 @@ function getDisabledOpacity(disabledOpacity?: ThemeConfig["disabledOpacity"]) {
476
552
  const opacity = disabledOpacity ?? getStored(storageKey) ?? vuelessConfig.disabledOpacity;
477
553
  const mergedOpacity = Math.max(0, Number(opacity ?? DEFAULT_DISABLED_OPACITY));
478
554
 
479
- if (isCSR && disabledOpacity) {
555
+ if (isCSR && disabledOpacity !== undefined) {
480
556
  setCookie(storageKey, String(mergedOpacity));
481
557
  localStorage.setItem(storageKey, String(mergedOpacity));
482
558
  }