vueless 0.0.192 → 0.0.194

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.
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ref,
3
+ watch,
3
4
  watchEffect,
4
5
  getCurrentInstance,
5
6
  toValue,
@@ -69,7 +70,6 @@ export default function useUI(defaultConfig = {}, propsConfigGetter = null, topL
69
70
  });
70
71
 
71
72
  function getAttrs(configKey, options) {
72
- const cvaClasses = options?.classes || "";
73
73
  const nestedComponent = options?.isComponent || getNestedComponent(defaultConfig[configKey]); // TODO: Remove `options?.isComponent` when all `attrs.composable.js` will be migranted
74
74
 
75
75
  const attrs = useAttrs();
@@ -87,7 +87,9 @@ export default function useUI(defaultConfig = {}, propsConfigGetter = null, topL
87
87
  // Delete value key to prevent v-model overwrite
88
88
  delete commonAttrs.value;
89
89
 
90
- watchEffect(() => {
90
+ watch(config, updateVuelessAttrs, { immediate: true });
91
+
92
+ function updateVuelessAttrs() {
91
93
  const configKeyValue = config.value[configKey];
92
94
  const isObject = typeof configKeyValue === "object";
93
95
 
@@ -97,16 +99,15 @@ export default function useUI(defaultConfig = {}, propsConfigGetter = null, topL
97
99
  };
98
100
 
99
101
  const isTopLevelClassKey = configKey === (topLevelClassKey || firstClassKey);
100
-
101
102
  const attrClass = isTopLevelClassKey && !nestedComponent ? attrs.class : "";
102
- const configKeyClass = isObject ? configKeyValue.base : configKeyValue;
103
+ const classes = options?.classes ? toValue(options?.classes) : getBaseClasses(configKeyValue);
103
104
 
104
105
  vuelessAttrs.value = {
105
106
  ...commonAttrs,
106
- class: cx([configKeyClass, toValue(cvaClasses), attrClass]),
107
+ class: cx([classes, attrClass]),
107
108
  ...((isObject && configAttrs) || {}),
108
109
  };
109
- });
110
+ }
110
111
 
111
112
  return vuelessAttrs;
112
113
  }
@@ -261,6 +262,8 @@ function mergeConfigs({
261
262
  @returns {Object}
262
263
  */
263
264
  function stringToObject(value) {
265
+ if (value === undefined) value = "";
266
+
264
267
  return typeof value === "object" ? value : { base: value };
265
268
  }
266
269
 
@@ -359,13 +362,22 @@ function mergeClassesIntoConfig(config, topLevelClassKey, attrs) {
359
362
  return config;
360
363
  }
361
364
 
365
+ /**
366
+ Return base classes.
367
+ @param { String | Object } value
368
+ @returns { String }
369
+ */
370
+ function getBaseClasses(value) {
371
+ return typeof value === "object" ? value.base || "" : value || "";
372
+ }
373
+
362
374
  /**
363
375
  Check is config key contains component name and if contains return it.
364
376
  @param { String | Object } value
365
377
  @returns { String }
366
378
  */
367
379
  function getNestedComponent(value) {
368
- const classes = typeof value === "object" ? value.base || "" : value || "";
380
+ const classes = getBaseClasses(value);
369
381
  const match = classes.match(nestedComponentRegEx);
370
382
 
371
383
  return match ? match[1] : "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.192",
3
+ "version": "0.0.194",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless Component Framework.",
6
6
  "homepage": "https://vueless.com",
@@ -38,8 +38,8 @@
38
38
  "@vitejs/plugin-vue": "^5.0.5",
39
39
  "@vue/eslint-config-prettier": "^9.0.0",
40
40
  "@vueless/plugin-vite": "^0.0.34",
41
- "@vueless/storybook": "^0.0.32",
42
- "@vueless/web-types": "^0.0.12",
41
+ "@vueless/storybook": "^0.0.33",
42
+ "@vueless/web-types": "^0.0.13",
43
43
  "autoprefixer": "^10.4.19",
44
44
  "cssnano": "^6.1.2",
45
45
  "eslint": "^8.55.0",
@@ -18,10 +18,6 @@ export function getArgTypes(componentName) {
18
18
 
19
19
  const types = {};
20
20
 
21
- getSlotNames(componentName)?.forEach((slotName) => {
22
- types[slotName] = { control: "text" };
23
- });
24
-
25
21
  component.attributes?.forEach((attribute) => {
26
22
  const type = attribute.value.type;
27
23
 
@@ -84,16 +80,48 @@ export function getArgTypes(componentName) {
84
80
  }
85
81
  });
86
82
 
87
- if (import.meta.env.STORYBOOK_FULL) {
88
- component.events?.forEach((event) => {
83
+ component.slots?.forEach((slot) => {
84
+ const bindings = [];
85
+
86
+ slot.bindings?.forEach((binding) => {
87
+ const description = binding.description ? ` (${binding.description})` : "";
88
+
89
+ bindings.push(`${binding.name}: ${binding.type}${description}`);
90
+ });
91
+
92
+ types[`${slot.name}Slot`] = {
93
+ name: slot.name,
94
+ description: slot.description,
95
+ type: slot.bindings ? `{ ${bindings.join(", ")} }` : null,
96
+ control: "text",
97
+ table: { category: "slots" },
98
+ };
99
+ });
100
+
101
+ component.events?.forEach((event) => {
102
+ const properties = [];
103
+
104
+ event.properties?.forEach((property) => {
105
+ const description = property.description ? ` (${property.description})` : "";
106
+
107
+ properties.push(`${property.name}: ${property.type}${description}`);
108
+ });
109
+
110
+ types[event.name] = {
111
+ type: event.properties ? `{ ${properties.join(", ")} }` : null,
112
+ name: event.name,
113
+ description: event.description,
114
+ };
115
+
116
+ if (import.meta.env.STORYBOOK_FULL) {
89
117
  const eventName = "on" + event.name.charAt(0).toUpperCase() + event.name.slice(1);
90
118
 
91
119
  types[eventName] = {
92
120
  action: event.name,
93
121
  table: { category: "Storybook Events" },
94
122
  };
95
- });
96
- }
123
+ }
124
+ });
97
125
 
98
126
  return types;
99
127
  }
@@ -101,3 +129,9 @@ export function getArgTypes(componentName) {
101
129
  export function getSource(defaultCnfig) {
102
130
  return defaultCnfig.replace("export default /*tw*/ ", "").replace(";", "");
103
131
  }
132
+
133
+ export const allSlotsFragment = `
134
+ <template v-for="(slot, index) of slots" :key="index" v-slot:[slot]>
135
+ <template v-if="args[slot + 'Slot']">{{ args[slot + 'Slot'] }}</template>
136
+ </template>
137
+ `;
@@ -47,7 +47,7 @@ const props = defineProps({
47
47
  */
48
48
  modelValue: {
49
49
  type: [String, Number, Array],
50
- default: () => (!this.multiple ? "" : []),
50
+ default: "",
51
51
  },
52
52
 
53
53
  /**
@@ -146,9 +146,7 @@ function onClickSetValue() {
146
146
  selectedItem.value = props.value;
147
147
  }
148
148
 
149
- if (updateSelectedValue) {
150
- updateSelectedValue(props.value, !selectedItem.value);
151
- }
149
+ updateSelectedValue && updateSelectedValue(props.value, !selectedItem.value);
152
150
 
153
151
  emit("update:modelValue", props.value);
154
152
  }
@@ -46,7 +46,7 @@ function onClick() {
46
46
  // invokes click event on current item
47
47
  emit("click");
48
48
 
49
- if (hideDropdownOptions) hideDropdownOptions();
49
+ hideDropdownOptions && hideDropdownOptions();
50
50
  }
51
51
 
52
52
  const { wrapperAttrs } = useAttrs(props);
@@ -39,7 +39,7 @@
39
39
  </template>
40
40
 
41
41
  <script setup>
42
- import { inject, ref, onMounted, computed, watchEffect } from "vue";
42
+ import { inject, ref, onMounted, computed, watchEffect, toValue } from "vue";
43
43
  import { isEqual } from "lodash-es";
44
44
 
45
45
  import UIcon from "../ui.image-icon";
@@ -210,7 +210,7 @@ const iconSize = computed(() => {
210
210
  });
211
211
 
212
212
  const isBinary = computed(() => !Array.isArray(props.modelValue));
213
- const isCheckboxInGroup = computed(() => Boolean(getCheckboxGroupName()));
213
+ const isCheckboxInGroup = computed(() => Boolean(toValue(getCheckboxGroupName)));
214
214
 
215
215
  const isChecked = computed(() => {
216
216
  return isBinary.value && !isCheckboxInGroup.value
@@ -223,17 +223,15 @@ const checkboxValue = computed(() => {
223
223
  });
224
224
 
225
225
  const currentValue = computed(() => {
226
- return isCheckboxInGroup.value ? getCheckboxGroupCheckedItems() : props.modelValue;
226
+ return isCheckboxInGroup.value ? toValue(getCheckboxGroupCheckedItems) : props.modelValue;
227
227
  });
228
228
 
229
229
  onMounted(() => {
230
- checkboxName.value = isCheckboxInGroup.value ? getCheckboxGroupName() : props.name;
230
+ checkboxName.value = isCheckboxInGroup.value ? toValue(getCheckboxGroupName) : props.name;
231
231
  });
232
232
 
233
- watchEffect(
234
- () => (checkboxColor.value = getCheckboxGroupColor ? getCheckboxGroupColor() : props.color),
235
- );
236
- watchEffect(() => (checkboxSize.value = getCheckboxSize ? getCheckboxSize() : props.size));
233
+ watchEffect(() => (checkboxColor.value = toValue(getCheckboxGroupColor) || props.color));
234
+ watchEffect(() => (checkboxSize.value = toValue(getCheckboxSize) || props.size));
237
235
 
238
236
  function onChange() {
239
237
  let newModelValue;
@@ -1,35 +1,37 @@
1
+ import { computed } from "vue";
1
2
  import useUI from "../../composable.ui";
2
3
  import { cva } from "../../service.ui";
3
-
4
4
  import defaultConfig from "../configs/default.config";
5
- import { computed } from "vue";
6
5
 
7
6
  export function useAttrs(props) {
8
- const { config, getAttrs } = useUI(defaultConfig, () => props.config);
9
- const { counter } = config.value;
7
+ const { config, getAttrs, hasSlotContent, isSystemKey } = useUI(
8
+ defaultConfig,
9
+ () => props.config,
10
+ );
11
+ const attrs = {};
12
+
13
+ for (const key in defaultConfig) {
14
+ if (isSystemKey(key)) continue;
15
+
16
+ let classes = "";
17
+ let value = config.value[key];
10
18
 
11
- const cvaCounter = cva({
12
- base: counter.base,
13
- variants: counter.variants,
14
- compoundVariants: counter.compoundVariants,
15
- });
19
+ if (value.variants || value.compoundVariants) {
20
+ const getCVA = cva(value);
16
21
 
17
- const counterClasses = computed(() => cvaCounter({ size: props.size }));
22
+ classes = computed(() =>
23
+ getCVA({
24
+ ...props,
25
+ }),
26
+ );
27
+ }
18
28
 
19
- const counterAttrs = getAttrs("counter", { classes: counterClasses });
20
- const ratingAttrs = getAttrs("rating");
21
- const wrapperAttrs = getAttrs("wrapper");
22
- const iconAttrs = getAttrs("icon", { isComponent: true });
23
- const iconWrapperAttrs = getAttrs("iconWrapper");
24
- const labelAttrs = getAttrs("label", { isComponent: true });
29
+ attrs[`${key}Attrs`] = getAttrs(key, { classes });
30
+ }
25
31
 
26
32
  return {
33
+ ...attrs,
27
34
  config,
28
- counterAttrs,
29
- ratingAttrs,
30
- wrapperAttrs,
31
- iconAttrs,
32
- iconWrapperAttrs,
33
- labelAttrs,
35
+ hasSlotContent,
34
36
  };
35
37
  }
@@ -1,27 +1,42 @@
1
1
  export default /*tw*/ {
2
- rating: "flex flex-col",
3
- label: "",
4
- wrapper: "",
5
- iconWrapper: "leading-none flex",
6
- icon: "",
2
+ label: "{ULabel}",
3
+ wrapper: {
4
+ base: "flex items-center text-gray-500 !leading-none",
5
+ variants: {
6
+ size: {
7
+ sm: "gap-1.5",
8
+ md: "gap-2",
9
+ lg: "gap-2.5",
10
+ },
11
+ },
12
+ },
13
+ stars: "flex",
14
+ star: "{UIcon}",
7
15
  selectedIconName: "star-fill",
8
16
  unselectedIconName: "star",
9
17
  counter: {
10
- base: "leading-none",
11
18
  variants: {
12
19
  size: {
13
- sm: "text-2xs",
14
- md: "text-xs",
15
- lg: "text-sm",
20
+ sm: "text-base",
21
+ md: "text-xl",
22
+ lg: "text-2xl",
23
+ },
24
+ },
25
+ },
26
+ total: {
27
+ variants: {
28
+ size: {
29
+ sm: "text-sm",
30
+ md: "text-base",
31
+ lg: "text-xl",
16
32
  },
17
33
  },
18
34
  },
19
35
  defaultVariants: {
36
+ labelAlign: "top",
20
37
  size: "md",
21
- modelValue: 0,
22
- starsNumber: 5,
38
+ stars: 5,
39
+ counter: false,
23
40
  selectable: false,
24
- noCounter: false,
25
- labelAlign: "topInside",
26
41
  },
27
42
  };
@@ -1,4 +1,4 @@
1
- import { getArgTypes, getSlotNames } from "../service.storybook";
1
+ import { getArgTypes, getSlotNames, allSlotsFragment } from "../service.storybook";
2
2
 
3
3
  import UInputRating from "../ui.form-input-rating";
4
4
  import URow from "../ui.container-row";
@@ -11,8 +11,8 @@ export default {
11
11
  title: "Form Inputs & Controls / Input Rating",
12
12
  component: UInputRating,
13
13
  args: {
14
+ modelValue: 2,
14
15
  label: "Label",
15
- value: 2,
16
16
  },
17
17
  argTypes: {
18
18
  ...getArgTypes(UInputRating.name),
@@ -29,12 +29,9 @@ const DefaultTemplate = (args) => ({
29
29
  template: `
30
30
  <UInputRating
31
31
  v-bind="args"
32
- v-model="args.value"
32
+ v-model="args.modelValue"
33
33
  >
34
- <template v-for="(slot, index) of slots" :key="index" v-slot:[slot]>
35
- <template v-if="args[slot]">{{ args[slot] }}</template>
36
- </template>
37
-
34
+ ${allSlotsFragment}
38
35
  </UInputRating>
39
36
  `,
40
37
  });
@@ -47,7 +44,7 @@ const SlotTemplate = (args) => ({
47
44
  template: `
48
45
  <UInputRating
49
46
  v-bind="args"
50
- v-model="args.value"
47
+ v-model="args.modelValue"
51
48
  >
52
49
  ${args.slotTemplate}
53
50
  </UInputRating>
@@ -63,12 +60,13 @@ const SizesTemplate = (args, { argTypes } = {}) => ({
63
60
  };
64
61
  },
65
62
  template: `
66
- <URow>
63
+ <URow gap="2xl">
67
64
  <UInputRating
68
65
  v-for="(size, index) in sizes"
66
+ :key="index"
69
67
  v-bind="args"
68
+ v-model="args.modelValue"
70
69
  :size="size"
71
- :key="index"
72
70
  />
73
71
  </URow>
74
72
  `,
@@ -80,32 +78,39 @@ Default.args = {};
80
78
  export const sizes = SizesTemplate.bind({});
81
79
  sizes.args = {};
82
80
 
81
+ export const starAmount = DefaultTemplate.bind({});
82
+ starAmount.args = { value: 4, stars: 7 };
83
+
83
84
  export const selectable = DefaultTemplate.bind({});
84
85
  selectable.args = { selectable: true };
85
86
 
86
- export const starsNumber = DefaultTemplate.bind({});
87
- starsNumber.args = { value: 4, starsNumber: 7 };
87
+ export const description = DefaultTemplate.bind({});
88
+ description.args = { description: "Some description" };
88
89
 
89
90
  export const error = DefaultTemplate.bind({});
90
- error.args = { error: "some error" };
91
+ error.args = { error: "Some error" };
92
+
93
+ export const withCounter = DefaultTemplate.bind({});
94
+ withCounter.args = { counter: true };
91
95
 
92
- export const withoutCounter = DefaultTemplate.bind({});
93
- withoutCounter.args = { withCounter: false };
96
+ export const withTotal = DefaultTemplate.bind({});
97
+ withTotal.args = { total: 250 };
94
98
 
95
99
  export const slotCounter = SlotTemplate.bind({});
96
100
  slotCounter.args = {
97
101
  slotTemplate: `
98
- <template #counter>
99
- some counter
102
+ <template #counter="{counter}">
103
+ Rating: {{counter}}
100
104
  </template>
101
105
  `,
102
106
  };
103
107
 
104
- export const slotRight = SlotTemplate.bind({});
105
- slotRight.args = {
108
+ export const slotTotal = SlotTemplate.bind({});
109
+ slotTotal.args = {
110
+ total: 250,
106
111
  slotTemplate: `
107
- <template #right>
108
- 🤘🤘🤘
112
+ <template #total="{total}">
113
+ ({{total}}) reviews
109
114
  </template>
110
115
  `,
111
116
  };