vueless 0.0.602 → 0.0.604

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 (35) hide show
  1. package/composables/useUI.ts +57 -27
  2. package/directives/tooltip/vTooltip.ts +0 -1
  3. package/package.json +1 -1
  4. package/ui.container-modal-confirm/UModalConfirm.vue +3 -1
  5. package/ui.data-list/UDataList.vue +1 -1
  6. package/ui.data-table/UTable.vue +1 -1
  7. package/ui.data-table/config.ts +1 -9
  8. package/ui.data-table/storybook/stories.ts +4 -4
  9. package/ui.data-table/types.ts +1 -10
  10. package/ui.dropdown-list/UDropdownList.vue +2 -2
  11. package/ui.form-calendar/UCalendar.vue +1 -1
  12. package/ui.form-checkbox/UCheckbox.vue +1 -0
  13. package/ui.form-checkbox/config.ts +1 -1
  14. package/ui.form-date-picker/UDatePicker.vue +2 -2
  15. package/ui.form-date-picker-range/UDatePickerRange.vue +1 -1
  16. package/ui.form-date-picker-range/useLocale.ts +3 -1
  17. package/ui.form-input/UInput.vue +1 -0
  18. package/ui.form-input/config.ts +6 -3
  19. package/ui.form-input/storybook/stories.ts +1 -0
  20. package/ui.form-input-file/UInputFile.vue +2 -1
  21. package/ui.form-label/config.ts +4 -9
  22. package/ui.form-label/types.ts +5 -0
  23. package/ui.form-radio/URadio.vue +1 -0
  24. package/ui.form-radio/config.ts +1 -1
  25. package/ui.form-select/USelect.vue +4 -3
  26. package/ui.form-switch/USwitch.vue +2 -1
  27. package/ui.form-textarea/UTextarea.vue +1 -0
  28. package/ui.form-textarea/config.ts +5 -2
  29. package/ui.loader-progress/ULoaderProgress.vue +1 -1
  30. package/ui.loader-progress/types.ts +5 -0
  31. package/ui.text-money/config.ts +0 -1
  32. package/ui.text-notify/UNotify.vue +1 -1
  33. package/utils/node/loaderIcon.js +1 -1
  34. package/utils/ui.ts +4 -4
  35. package/web-types.json +20 -1
@@ -93,6 +93,8 @@ export default function useUI<T>(
93
93
  classes = cx([classes, attrs.class]);
94
94
  }
95
95
 
96
+ classes = classes.replaceAll(EXTENDS_PATTERN_REG_EXP, "");
97
+
96
98
  return color ? setColor(classes, color) : classes;
97
99
  });
98
100
  }
@@ -118,12 +120,12 @@ export default function useUI<T>(
118
120
  * Get an element attributes for a given key.
119
121
  */
120
122
  function getAttrs(configKey: string, classes: ComputedRef<string>) {
121
- const nestedComponent = getNestedComponent(config.value[configKey] || "");
123
+ const vuelessAttrs = ref({});
122
124
 
123
125
  const attrs = useAttrs() as KeyAttrs;
124
126
  const isDev = isCSR && import.meta.env?.DEV;
125
- const vuelessAttrs = ref({});
126
127
  const isTopLevelKey = (topLevelClassKey || firstClassKey) === configKey;
128
+ const nestedComponent = getNestedComponent(config.value[configKey] || "");
127
129
 
128
130
  const commonAttrs: KeyAttrs = {
129
131
  ...(isTopLevelKey ? attrs : {}),
@@ -139,32 +141,25 @@ export default function useUI<T>(
139
141
 
140
142
  watch(config, updateVuelessAttrs, { immediate: true });
141
143
  watch(props, updateVuelessAttrs);
144
+ watch(classes, updateVuelessAttrs);
142
145
 
143
- if (classes?.value) {
144
- watch(classes, updateVuelessAttrs);
145
- }
146
-
146
+ /**
147
+ * Updating Vueless attributes.
148
+ */
147
149
  function updateVuelessAttrs() {
148
150
  let configAttr: NestedComponent = {};
149
- let extendsConfigAttr: NestedComponent = {};
150
- let extendsClasses: string[] = [];
151
-
152
- const baseClasses = getBaseClasses(config.value[configKey]);
153
- const extendsKeys = getExtendsKeys(baseClasses);
154
151
 
155
152
  if (typeof config.value[configKey] === "object") {
156
153
  configAttr = config.value[configKey] as NestedComponent;
157
154
  }
158
155
 
159
- if (extendsKeys.length) {
160
- extendsClasses = extendsKeys.map((key) => toValue(getClasses(key, mutatedProps)));
161
- extendsConfigAttr = getExtendsConfig(extendsKeys);
162
- }
156
+ const extendsClasses = getExtendsClasses(configKey);
157
+ const extendsConfigAttr = getExtendsConfigAttr(configKey);
163
158
 
164
159
  vuelessAttrs.value = {
165
160
  ...commonAttrs,
166
- class: cx([...extendsClasses, toValue(classes).replaceAll(EXTENDS_PATTERN_REG_EXP, "")]),
167
- config: merge(configAttr, extendsConfigAttr),
161
+ class: cx([...extendsClasses, toValue(classes)]),
162
+ config: merge({}, configAttr, extendsConfigAttr),
168
163
  ...getDefaults({
169
164
  ...(configAttr.defaults || {}),
170
165
  ...(extendsConfigAttr.defaults || {}),
@@ -172,21 +167,51 @@ export default function useUI<T>(
172
167
  };
173
168
  }
174
169
 
170
+ /**
171
+ * Recursively get extends classes.
172
+ */
173
+ function getExtendsClasses(configKey: string) {
174
+ let extendsClasses: string[] = [];
175
+
176
+ const extendsKeys = getExtendsKeys(config.value[configKey]);
177
+
178
+ if (extendsKeys.length) {
179
+ extendsKeys.forEach((key) => {
180
+ extendsClasses = [
181
+ ...extendsClasses,
182
+ ...getExtendsClasses(key),
183
+ toValue(getClasses(key, mutatedProps)),
184
+ ];
185
+ });
186
+ }
187
+
188
+ return extendsClasses;
189
+ }
190
+
175
191
  /**
176
192
  * Merge extends nested component configs.
177
193
  * TODO: Add ability to merge multiple keys in one (now works for merging only 1 first key).
178
194
  */
179
- function getExtendsConfig(extendsKeys: string[]) {
180
- const [firstKey] = extendsKeys;
181
-
182
- return getMergedConfig({
183
- defaultConfig: config.value[firstKey],
184
- globalConfig: globalConfig[firstKey],
185
- propsConfig: propsConfig[firstKey],
186
- }) as NestedComponent;
195
+ function getExtendsConfigAttr(configKey: string) {
196
+ let extendsConfigAttr: NestedComponent = {};
197
+
198
+ const extendsKeys = getExtendsKeys(config.value[configKey]);
199
+
200
+ if (extendsKeys.length) {
201
+ const [firstKey] = extendsKeys;
202
+
203
+ extendsConfigAttr = getMergedConfig({
204
+ defaultConfig: config.value[firstKey],
205
+ globalConfig: globalConfig[firstKey],
206
+ propsConfig: propsConfig[firstKey],
207
+ }) as NestedComponent;
208
+ }
209
+
210
+ return extendsConfigAttr;
187
211
  }
188
212
 
189
213
  /**
214
+ * Get component prop default value.
190
215
  * Conditionally set props default value for nested components based on parent component prop value.
191
216
  * For example, set icon size for the nested component based on the size of the parent component.
192
217
  * Use an object where key = parent component prop value, value = nested component prop value.
@@ -221,7 +246,8 @@ function getBaseClasses(value: string | CVA | undefined) {
221
246
  * Retrieves extends keys from patterns:
222
247
  * Example: `{>someKey} {>someOtherKey}` >>> `["someKey", "someOtherKey"]`.
223
248
  */
224
- function getExtendsKeys(values: string = ""): string[] {
249
+ function getExtendsKeys(configItemValue?: CVA | string): string[] {
250
+ const values = getBaseClasses(configItemValue);
225
251
  const matches = values.match(EXTENDS_PATTERN_REG_EXP);
226
252
 
227
253
  return matches ? matches?.map((pattern) => pattern.slice(2, -1)) : [];
@@ -249,7 +275,11 @@ function isSystemKey(key: string): boolean {
249
275
  /**
250
276
  * Check is config contains default CVA keys.
251
277
  */
252
- function isCVA(config: UnknownObject): boolean {
278
+ function isCVA(config?: UnknownObject | string): boolean {
279
+ if (typeof config !== "object") {
280
+ return false;
281
+ }
282
+
253
283
  return Object.values(CVA_CONFIG_KEY).some((value) =>
254
284
  Object.keys(config).some((key) => key === value),
255
285
  );
@@ -24,7 +24,6 @@ if (isCSR) {
24
24
  animation: "shift-away",
25
25
  };
26
26
 
27
- settings = merge(defaultSettings, {});
28
27
  settings = merge(defaultSettings, vuelessConfig.directive?.tooltip || {}) as DefaultProps;
29
28
  tippy.setDefaultProps(settings);
30
29
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.602",
3
+ "version": "0.0.604",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
6
6
  "keywords": [
@@ -49,7 +49,9 @@ const isShownModal = computed({
49
49
  });
50
50
 
51
51
  const i18nGlobal = tm(UModalConfirm);
52
- const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props?.config?.i18n));
52
+ const currentLocale = computed(() =>
53
+ merge({}, defaultConfig.i18n, i18nGlobal, props?.config?.i18n),
54
+ );
53
55
 
54
56
  function closeModal() {
55
57
  isShownModal.value = false;
@@ -48,7 +48,7 @@ const emit = defineEmits([
48
48
  const { tm } = useLocale();
49
49
 
50
50
  const i18nGlobal = tm(UDataListName);
51
- const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
51
+ const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
52
52
 
53
53
  const iconSize = computed(() => {
54
54
  const sizes = {
@@ -96,7 +96,7 @@ const stickyActionHeaderRowRef = useTemplateRef<HTMLDivElement>("sticky-action-h
96
96
  const actionHeaderRowRef = useTemplateRef<HTMLDivElement>("action-header-row");
97
97
 
98
98
  const i18nGlobal = tm(UTable);
99
- const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
99
+ const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
100
100
 
101
101
  const sortedRows: ComputedRef<Row[]> = computed(() => {
102
102
  const headerKeys = props.columns.map((column) =>
@@ -40,14 +40,7 @@ export default /*tw*/ {
40
40
  },
41
41
  headerCellCheckbox: "{>headerCellBase} w-10 pr-2",
42
42
  headerCheckbox: "{UCheckbox}",
43
- headerCounter: {
44
- base: "{>headerCounterBase} absolute top-4 mt-px left-11 ml-px",
45
- variants: {
46
- compact: {
47
- true: "top-3",
48
- },
49
- },
50
- },
43
+ headerCounter: "{>stickyHeaderCounter} mt-px ml-px",
51
44
  headerLoader: "{ULoaderProgress} absolute !top-auto",
52
45
  body: "group/body divide-none",
53
46
  bodyRow: "hover:bg-gray-50",
@@ -108,7 +101,6 @@ export default /*tw*/ {
108
101
  },
109
102
  defaults: {
110
103
  emptyCellLabel: "—",
111
- nesting: false,
112
104
  compact: false,
113
105
  selectable: false,
114
106
  dateDivider: false,
@@ -39,12 +39,12 @@ export default {
39
39
  argTypes: {
40
40
  ...getArgTypes(UTable.__name),
41
41
  row: {
42
- description:
43
- "The row of the table. It's not a prop (it created for ease of work with storybook).",
42
+ table: {
43
+ disable: true,
44
+ },
44
45
  },
45
46
  numberOfRows: {
46
- description:
47
- "The number of table rows. It's not a prop (it created for ease of work with storybook).",
47
+ description: "The number of table rows (not a component prop).",
48
48
  },
49
49
  },
50
50
  args: {
@@ -5,16 +5,7 @@ import type { ComponentConfig, UnknownObject } from "../types.ts";
5
5
 
6
6
  export type Config = typeof defaultConfig;
7
7
 
8
- type RowKeys =
9
- | number
10
- | string
11
- | boolean
12
- | undefined
13
- | Date
14
- | Row
15
- | Row[]
16
- | string
17
- | ((row: Row) => string);
8
+ type RowKeys = number | string | boolean | undefined | Date | Row | Row[] | ((row: Row) => string);
18
9
 
19
10
  export interface CellObject {
20
11
  contentClasses?: string | ((value: unknown | string, row: Row) => string);
@@ -54,7 +54,7 @@ const elementId = props.id || useId();
54
54
  const { tm } = useLocale();
55
55
 
56
56
  const i18nGlobal = tm(UDropdownList);
57
- const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
57
+ const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
58
58
 
59
59
  const addOptionKeyCombination = computed(() => {
60
60
  return isMac ? "(⌘ + Enter)" : "(Ctrl + Enter)";
@@ -151,7 +151,7 @@ function optionHighlight(index: number, option: Option) {
151
151
  return classes;
152
152
  }
153
153
 
154
- function addPointerElement(keyCode: string) {
154
+ function addPointerElement(keyCode?: string) {
155
155
  if (props.options.length > 0) {
156
156
  select(props.options[pointer.value], keyCode);
157
157
  onClickOption(props.options[pointer.value]);
@@ -129,7 +129,7 @@ const isCurrentView = computed(() => ({
129
129
  const i18nGlobal = tm<DefaultLocale>(UCalendar);
130
130
 
131
131
  const currentLocale: ComputedRef<Locale> = computed(() =>
132
- merge(defaultConfig.i18n, i18nGlobal, props.config?.i18n),
132
+ merge({}, defaultConfig.i18n, i18nGlobal, props.config?.i18n),
133
133
  );
134
134
 
135
135
  const locale = computed(() => {
@@ -142,6 +142,7 @@ const { config, checkboxAttrs, iconWrapperAttrs, checkboxLabelAttrs, checkedIcon
142
142
  :align="labelAlign"
143
143
  :disabled="disabled"
144
144
  :description="description"
145
+ interactive
145
146
  v-bind="checkboxLabelAttrs"
146
147
  :data-test="`${dataTest}-label`"
147
148
  >
@@ -5,7 +5,7 @@ export default /*tw*/ {
5
5
  border rounded bg-white cursor-pointer transition checked:text-{color}-600
6
6
  border-gray-300 hover:border-gray-400 focus:border-{color}-500 active:border-{color}-800
7
7
  focus:ring-{color}-700/15 focus:ring-dynamic focus:ring-offset-dynamic
8
- disabled:border-gray-300 disabled:bg-gray-100
8
+ disabled:border-gray-300 disabled:bg-gray-100 disabled:cursor-not-allowed
9
9
  `,
10
10
  variants: {
11
11
  size: {
@@ -82,7 +82,7 @@ const localValue = computed({
82
82
  });
83
83
 
84
84
  const currentLocale: ComputedRef<Locale> = computed(() =>
85
- merge(defaultConfig.i18n, i18nGlobal, props.config.i18n),
85
+ merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n),
86
86
  );
87
87
 
88
88
  const clickOutsideOptions = computed(() => ({ ignore: [datepickerInputRef.value?.inputRef] }));
@@ -268,7 +268,7 @@ watchEffect(() => {
268
268
  const calendarConfig = datepickerCalendarAttrs.value.config as unknown as UCalendarConfig;
269
269
 
270
270
  if (!calendarConfig?.i18n || props.config?.i18n) {
271
- calendarConfig.i18n = merge(calendarConfig.i18n, config.value.i18n);
271
+ calendarConfig.i18n = merge({}, calendarConfig.i18n, config.value.i18n);
272
272
  }
273
273
  });
274
274
  </script>
@@ -573,7 +573,7 @@ watchEffect(() => {
573
573
  const calendarConfig = datepickerCalendarAttrs.value.config as unknown as UCalendarConfig;
574
574
 
575
575
  if (!calendarConfig.i18n || props.config?.i18n) {
576
- calendarConfig.i18n = merge(calendarConfig.i18n, config.value.i18n);
576
+ calendarConfig.i18n = merge({}, calendarConfig.i18n, config.value.i18n);
577
577
  }
578
578
  });
579
579
  </script>
@@ -15,7 +15,9 @@ export function useLocale(props: UDatePickerRangeProps<unknown>) {
15
15
 
16
16
  const i18nGlobal = tm<Locale>(UDatePickerRange);
17
17
 
18
- const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config?.i18n));
18
+ const currentLocale = computed(() =>
19
+ merge({}, defaultConfig.i18n, i18nGlobal, props.config?.i18n),
20
+ );
19
21
 
20
22
  const locale = computed(() => {
21
23
  const { months, weekdays } = currentLocale.value;
@@ -273,6 +273,7 @@ const {
273
273
  :size="size"
274
274
  :align="labelAlign"
275
275
  centred
276
+ interactive
276
277
  v-bind="inputLabelAttrs"
277
278
  >
278
279
  <label :for="elementId" v-bind="wrapperAttrs">
@@ -15,7 +15,10 @@ export default /*tw*/ {
15
15
  `,
16
16
  },
17
17
  disabled: {
18
- true: "focus-within:ring-0 focus-within:ring-offset-0 pointer-events-none",
18
+ true: `
19
+ focus-within:ring-0 focus-within:ring-offset-0 bg-gray-100
20
+ hover:border-gray-300 focus-within:border-gray-300 hover:focus-within:border-gray-300
21
+ `,
19
22
  },
20
23
  },
21
24
  },
@@ -26,10 +29,10 @@ export default /*tw*/ {
26
29
  passwordIcon: "{UIcon}",
27
30
  input: {
28
31
  base: `
29
- block w-full py-2 px-3 font-normal !leading-none text-gray-900 bg-white
32
+ block w-full py-2 px-3 font-normal !leading-none text-gray-900 bg-transparent
30
33
  border-none rounded-dynamic transition focus:ring-0
31
34
  placeholder:font-normal placeholder-gray-400
32
- disabled:text-gray-700 disabled:bg-gray-100
35
+ disabled:text-gray-700 disabled:cursor-not-allowed
33
36
  `,
34
37
  variants: {
35
38
  size: {
@@ -127,6 +127,7 @@ RightIconSlot.args = {
127
127
  slotTemplate: `
128
128
  <template #right-icon>
129
129
  <UIcon
130
+ interactive
130
131
  name="star"
131
132
  color="green"
132
133
  />
@@ -50,7 +50,7 @@ const fileInputRef = ref<HTMLInputElement | null>(null);
50
50
  const elementId = props.id || useId();
51
51
 
52
52
  const i18nGlobal = tm(UInputFile);
53
- const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
53
+ const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
54
54
 
55
55
  const currentFiles = computed<File | File[] | null>({
56
56
  get: () => props.modelValue,
@@ -281,6 +281,7 @@ const {
281
281
  :align="labelAlign"
282
282
  :disabled="disabled"
283
283
  :description="description"
284
+ interactive
284
285
  v-bind="inputLabelAttrs"
285
286
  >
286
287
  <div ref="dropZoneRef" :ondrop="onDrop" v-bind="dropzoneAttrs">
@@ -24,14 +24,7 @@ export default /*tw*/ {
24
24
  { align: "right", centred: true, class: "items-center justify-start w-auto" },
25
25
  ],
26
26
  },
27
- content: {
28
- base: "flex",
29
- variants: {
30
- disabled: {
31
- true: "pointer-events-none",
32
- },
33
- },
34
- },
27
+ content: "flex",
35
28
  label: {
36
29
  base: "text-gray-900 z-10 block !leading-none w-max",
37
30
  variants: {
@@ -51,10 +44,11 @@ export default /*tw*/ {
51
44
  true: "text-red-500",
52
45
  },
53
46
  disabled: {
54
- true: "text-gray-500 pointer-events-none",
47
+ true: "text-gray-500 cursor-not-allowed",
55
48
  },
56
49
  },
57
50
  compoundVariants: [
51
+ { interactive: true, disabled: false, class: "hover:cursor-pointer" },
58
52
  { align: "topInside", size: "sm", class: "top-2 text-2xs" },
59
53
  { align: "topInside", size: "md", class: "top-2.5 text-xs" },
60
54
  { align: "topInside", size: "lg", class: "top-2.5 text-sm" },
@@ -101,5 +95,6 @@ export default /*tw*/ {
101
95
  size: "md",
102
96
  centred: false,
103
97
  disabled: false,
98
+ interactive: false,
104
99
  },
105
100
  };
@@ -25,6 +25,11 @@ export interface Props {
25
25
  */
26
26
  error?: string;
27
27
 
28
+ /**
29
+ * Make the label interactive (cursor pointer on hover).
30
+ */
31
+ interactive?: boolean;
32
+
28
33
  /**
29
34
  * Label align.
30
35
  */
@@ -103,6 +103,7 @@ const { radioAttrs, radioLabelAttrs } = useUI<Config>(defaultConfig, mutatedProp
103
103
  :align="labelAlign"
104
104
  :disabled="disabled"
105
105
  :description="description"
106
+ interactive
106
107
  v-bind="radioLabelAttrs"
107
108
  :data-test="`${dataTest}-label`"
108
109
  >
@@ -6,7 +6,7 @@ export default /*tw*/ {
6
6
  border-gray-300 hover:border-gray-400 focus:border-{color}-500 active:border-{color}-800
7
7
  focus:ring-{color}-700/15 focus:ring-dynamic focus:ring-offset-dynamic
8
8
  disabled:border-gray-300 disabled:text-gray-100
9
- checked:disabled:border-gray-400 checked:disabled:text-gray-400
9
+ checked:disabled:border-gray-400 checked:disabled:text-gray-400 disabled:cursor-not-allowed
10
10
  `,
11
11
  variants: {
12
12
  size: {
@@ -97,7 +97,7 @@ const innerWrapperRef = ref<HTMLDivElement | null>(null);
97
97
  const elementId = props.id || useId();
98
98
 
99
99
  const i18nGlobal = tm(USelect);
100
- const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
100
+ const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
101
101
 
102
102
  const isTop = computed(() => {
103
103
  if (props.openDirection === DIRECTION.top) return true;
@@ -465,6 +465,7 @@ const {
465
465
  :align="labelAlign"
466
466
  :disabled="disabled"
467
467
  centred
468
+ interactive
468
469
  v-bind="selectLabelAttrs"
469
470
  :data-test="dataTest"
470
471
  :tabindex="-1"
@@ -479,7 +480,7 @@ const {
479
480
  @blur="deactivate"
480
481
  @keydown.self.down.prevent="dropdownListRef?.pointerForward"
481
482
  @keydown.self.up.prevent="dropdownListRef?.pointerBackward"
482
- @keydown.enter.tab.stop.self="dropdownListRef?.addPointerElement"
483
+ @keydown.enter.tab.stop.self="dropdownListRef?.addPointerElement()"
483
484
  @keyup.esc="deactivate"
484
485
  >
485
486
  <!-- @slot Use it to add something right. -->
@@ -677,7 +678,7 @@ const {
677
678
  @keyup.esc="deactivate"
678
679
  @keydown.down.prevent="dropdownListRef?.pointerForward"
679
680
  @keydown.up.prevent="dropdownListRef?.pointerBackward"
680
- @keydown.enter.prevent.stop.self="dropdownListRef?.addPointerElement"
681
+ @keydown.enter.prevent.stop.self="dropdownListRef?.addPointerElement()"
681
682
  />
682
683
  </div>
683
684
 
@@ -33,7 +33,7 @@ const emit = defineEmits([
33
33
  const { tm } = useLocale();
34
34
 
35
35
  const i18nGlobal = tm(USwitch);
36
- const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config?.i18n));
36
+ const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config?.i18n));
37
37
 
38
38
  const checkedValue = computed({
39
39
  get: () => props.modelValue,
@@ -105,6 +105,7 @@ const {
105
105
  :description="description"
106
106
  :align="labelAlign"
107
107
  :disabled="disabled"
108
+ interactive
108
109
  v-bind="switchLabelAttrs"
109
110
  :data-test="dataTest"
110
111
  @click="onClickToggle"
@@ -200,6 +200,7 @@ const { textareaAttrs, textareaLabelAttrs, textareaWrapperAttrs, leftSlotAttrs,
200
200
  :size="size"
201
201
  :disabled="disabled"
202
202
  :align="labelAlign"
203
+ interactive
203
204
  v-bind="textareaLabelAttrs"
204
205
  :data-test="dataTest"
205
206
  >
@@ -18,7 +18,10 @@ export default /*tw*/ {
18
18
  `,
19
19
  },
20
20
  disabled: {
21
- true: "focus-within:ring-0 focus-within:ring-offset-0 bg-gray-100 pointer-events-none",
21
+ true: `
22
+ focus-within:ring-0 focus-within:ring-offset-0 bg-gray-100
23
+ hover:border-gray-300 focus-within:border-gray-300 hover:focus-within:border-gray-300
24
+ `,
22
25
  },
23
26
  },
24
27
  compoundVariants: [
@@ -31,7 +34,7 @@ export default /*tw*/ {
31
34
  base: `
32
35
  p-0 block w-full bg-transparent border-none !leading-none font-normal text-gray-900
33
36
  placeholder:text-gray-400 placeholder:font-normal placeholder:leading-none
34
- focus:border-none focus:outline-none focus:ring-0
37
+ focus:border-none focus:outline-none focus:ring-0 disabled:cursor-not-allowed
35
38
  `,
36
39
  variants: {
37
40
  size: {
@@ -213,6 +213,6 @@ const { stripeAttrs } = useUI<Config>(defaultConfig);
213
213
 
214
214
  <template>
215
215
  <Transition :css="false" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
216
- <div v-if="show" v-bind="stripeAttrs" :style="barStyle" />
216
+ <div v-if="show" v-bind="stripeAttrs" :data-test="dataTest" :style="barStyle" />
217
217
  </Transition>
218
218
  </template>
@@ -49,4 +49,9 @@ export interface Props {
49
49
  * Component config object.
50
50
  */
51
51
  config?: ComponentConfig<Config>;
52
+
53
+ /**
54
+ * Data-test attribute for automated testing.
55
+ */
56
+ dataTest?: string;
52
57
  }
@@ -59,7 +59,6 @@ export default /*tw*/ {
59
59
  decimalSeparator: ",",
60
60
  thousandsSeparator: " ",
61
61
  planned: false,
62
- integer: false,
63
62
  symbolDivided: true,
64
63
  },
65
64
  };
@@ -27,7 +27,7 @@ const notifyPositionStyles = ref({});
27
27
  const notificationsWrapperRef = ref<NotificationsWrapperRef | null>(null);
28
28
 
29
29
  const i18nGlobal = tm(UNotify);
30
- const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
30
+ const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
31
31
 
32
32
  onMounted(() => {
33
33
  window.addEventListener("resize", setPosition, { passive: true });
@@ -311,5 +311,5 @@ async function getDefaults() {
311
311
  const defaultConfigPath = path.join(cwd, defaultIconsDir, COMPONENTS[U_ICON], "config.ts");
312
312
  const uIconDefaultConfig = await getComponentDefaultConfig(U_ICON, defaultConfigPath);
313
313
 
314
- return merge(uIconDefaultConfig?.defaults, vuelessConfig?.component?.[U_ICON]?.defaults);
314
+ return merge({}, uIconDefaultConfig?.defaults, vuelessConfig?.component?.[U_ICON]?.defaults);
315
315
  }
package/utils/ui.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { merge } from "lodash-es";
2
2
  import { defineConfig } from "cva";
3
3
  import { extendTailwindMerge } from "tailwind-merge";
4
- import { cloneDeep, isCSR, isSSR } from "./helper.ts";
4
+ import { isCSR, isSSR } from "./helper.ts";
5
5
  import { createGetMergedConfig } from "./node/mergeConfigs.js";
6
6
  import { UIcon } from "../ui.image-icon/constants.ts";
7
7
  import {
@@ -99,10 +99,10 @@ export const cva = ({ base = "", variants = {}, compoundVariants = [], defaultVa
99
99
  * Return default values for component props, icons, etc..
100
100
  */
101
101
  export function getDefaults<Props, Config>(defaultConfig: Config, name: ComponentNames) {
102
- const componentDefaults = cloneDeep((defaultConfig as UnknownObject).defaults) || {};
103
- const globalDefaults = cloneDeep(vuelessConfig.component?.[name]?.defaults) || {};
102
+ const componentDefaults = (defaultConfig as UnknownObject).defaults || {};
103
+ const globalDefaults = vuelessConfig.component?.[name]?.defaults || {};
104
104
 
105
- const defaults = merge(componentDefaults, globalDefaults) as Props & Defaults;
105
+ const defaults = merge({}, componentDefaults, globalDefaults) as Props & Defaults;
106
106
 
107
107
  if (defaults.color) {
108
108
  defaults.color = getColor(defaults.color as BrandColors);
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "framework": "vue",
3
3
  "name": "vueless",
4
- "version": "0.0.602",
4
+ "version": "0.0.604",
5
5
  "contributions": {
6
6
  "html": {
7
7
  "description-markup": "markdown",
@@ -7178,6 +7178,16 @@
7178
7178
  "type": "string"
7179
7179
  }
7180
7180
  },
7181
+ {
7182
+ "name": "interactive",
7183
+ "required": false,
7184
+ "description": "Make the label interactive (cursor pointer on hover).",
7185
+ "value": {
7186
+ "kind": "expression",
7187
+ "type": "boolean"
7188
+ },
7189
+ "default": "false"
7190
+ },
7181
7191
  {
7182
7192
  "name": "align",
7183
7193
  "required": false,
@@ -7848,6 +7858,15 @@
7848
7858
  "kind": "expression",
7849
7859
  "type": "ComponentConfig"
7850
7860
  }
7861
+ },
7862
+ {
7863
+ "name": "dataTest",
7864
+ "required": false,
7865
+ "description": "Data-test attribute for automated testing.",
7866
+ "value": {
7867
+ "kind": "expression",
7868
+ "type": "string"
7869
+ }
7851
7870
  }
7852
7871
  ],
7853
7872
  "source": {