vueless 0.0.191 → 0.0.193

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.191",
3
+ "version": "0.0.193",
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
+ `;
@@ -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
  };
@@ -1,43 +1,52 @@
1
1
  <template>
2
- <div :data-cy="dataCy" v-bind="ratingAttrs">
3
- <ULabel
4
- :label="label"
5
- :error="error"
6
- :size="size"
7
- :description="description"
8
- :align="labelAlign"
9
- v-bind="labelAttrs"
10
- >
11
- <div v-bind="wrapperAttrs">
12
- <div v-if="!noCounter" v-bind="counterAttrs">
13
- <!-- @slot Use it to add counter. -->
14
- <slot name="counter">
15
- {{ ratingCounter }}
16
- </slot>
17
- </div>
18
-
19
- <div v-bind="iconWrapperAttrs">
20
- <UIcon
21
- v-for="star in starsNumber"
22
- :key="star"
23
- internal
24
- color="yellow"
25
- :size="iconSize"
26
- :interactive="selectable"
27
- :data-cy="`${dataCy}-rating-star-${star}`"
28
- :name="star <= ratingCounter ? config.selectedIconName : config.unselectedIconName"
29
- v-bind="iconAttrs"
30
- @mouseover="onMouseHover(star)"
31
- @mouseleave="onMouseHover()"
32
- @click="onClickStar(star)"
33
- />
34
- </div>
35
-
36
- <!-- @slot Use it to add something right. -->
37
- <slot name="right" />
2
+ <ULabel
3
+ :label="label"
4
+ :error="error"
5
+ :size="size"
6
+ :align="labelAlign"
7
+ :description="description"
8
+ v-bind="labelAttrs"
9
+ :data-cy="dataCy"
10
+ >
11
+ <div v-bind="wrapperAttrs">
12
+ <div v-if="counter || hasSlotContent($slots['counter'])" v-bind="counterAttrs">
13
+ <!--
14
+ @slot Use it to customise counter.
15
+ @binding {number} counter
16
+ @binding {number} total
17
+ -->
18
+ <slot name="counter" :counter="counterValue" :total="total">
19
+ {{ counterValue }}
20
+ </slot>
38
21
  </div>
39
- </ULabel>
40
- </div>
22
+
23
+ <div v-bind="starsAttrs">
24
+ <UIcon
25
+ v-for="star in stars"
26
+ :key="star"
27
+ internal
28
+ color="yellow"
29
+ :size="iconSize"
30
+ :interactive="selectable"
31
+ :name="star <= counterValue ? config.selectedIconName : config.unselectedIconName"
32
+ v-bind="starAttrs"
33
+ :data-cy="`${dataCy}-rating-star-${star}`"
34
+ @click="onClickStar(star)"
35
+ @mouseleave="onMouseHover()"
36
+ @mouseover="onMouseHover(star)"
37
+ />
38
+ </div>
39
+
40
+ <div v-if="total || hasSlotContent($slots['total'])" v-bind="totalAttrs">
41
+ <!--
42
+ @slot Use it to customise total.
43
+ @binding {number} counter
44
+ @binding {number} total
45
+ -->
46
+ <slot name="total" :counter="counter" :total="total">({{ total }})</slot>
47
+ </div>
48
+ </div>
49
+ </ULabel>
41
50
  </template>
42
51
 
43
52
  <script setup>
@@ -56,31 +65,23 @@ defineOptions({ name: "UInputRating", inheritAttrs: false });
56
65
 
57
66
  const props = defineProps({
58
67
  /**
59
- * Set input rating label.
60
- */
61
- label: {
62
- type: String,
63
- default: "",
64
- },
65
-
66
- /**
67
- * Set input rating value.
68
+ * Rating value.
68
69
  */
69
70
  modelValue: {
70
71
  type: Number,
71
- default: UIService.get(defaultConfig, UInputRating).default.modelValue,
72
+ default: 0,
72
73
  },
73
74
 
74
75
  /**
75
- * Set the number of stars.
76
+ * Rating number of stars.
76
77
  */
77
- starsNumber: {
78
+ stars: {
78
79
  type: Number,
79
- default: UIService.get(defaultConfig, UInputRating).default.starsNumber,
80
+ default: UIService.get(defaultConfig, UInputRating).default.stars,
80
81
  },
81
82
 
82
83
  /**
83
- * Set component size.
84
+ * Rating size.
84
85
  * @values sm, md, lg
85
86
  */
86
87
  size: {
@@ -89,15 +90,15 @@ const props = defineProps({
89
90
  },
90
91
 
91
92
  /**
92
- * Make stars selectable.
93
+ * Rating label.
93
94
  */
94
- selectable: {
95
- type: Boolean,
96
- default: UIService.get(defaultConfig, UInputRating).default.selectable,
95
+ label: {
96
+ type: String,
97
+ default: "",
97
98
  },
98
99
 
99
100
  /**
100
- * Set label placement related from the default slot.
101
+ * Rating label placement.
101
102
  * @values top, topInside, topWithDesc, bottom, left, right
102
103
  */
103
104
  labelAlign: {
@@ -106,7 +107,7 @@ const props = defineProps({
106
107
  },
107
108
 
108
109
  /**
109
- * Set error message.
110
+ * Rating error message.
110
111
  */
111
112
  error: {
112
113
  type: String,
@@ -114,7 +115,7 @@ const props = defineProps({
114
115
  },
115
116
 
116
117
  /**
117
- * Set description text.
118
+ * Rating description.
118
119
  */
119
120
  description: {
120
121
  type: String,
@@ -122,15 +123,31 @@ const props = defineProps({
122
123
  },
123
124
 
124
125
  /**
125
- * Hide / show counter.
126
+ * Rating total.
127
+ */
128
+ total: {
129
+ type: Number,
130
+ default: 0,
131
+ },
132
+
133
+ /**
134
+ * Show rating counter.
126
135
  */
127
- noCounter: {
136
+ counter: {
128
137
  type: Boolean,
129
- default: UIService.get(defaultConfig, UInputRating).default.noCounter,
138
+ default: UIService.get(defaultConfig, UInputRating).default.counter,
130
139
  },
131
140
 
132
141
  /**
133
- * Sets component ui config object.
142
+ * Make rating selectable.
143
+ */
144
+ selectable: {
145
+ type: Boolean,
146
+ default: UIService.get(defaultConfig, UInputRating).default.selectable,
147
+ },
148
+
149
+ /**
150
+ * Component ui config object.
134
151
  */
135
152
  config: {
136
153
  type: Object,
@@ -138,7 +155,7 @@ const props = defineProps({
138
155
  },
139
156
 
140
157
  /**
141
- * Sets data-cy attribute for automated testing.
158
+ * Data-cy attribute for automated testing.
142
159
  */
143
160
  dataCy: {
144
161
  type: String,
@@ -146,12 +163,26 @@ const props = defineProps({
146
163
  },
147
164
  });
148
165
 
149
- const emit = defineEmits(["update:modelValue"]);
166
+ const emit = defineEmits([
167
+ /**
168
+ * Triggers when the rating is changes.
169
+ * @property {number} modelValue
170
+ */
171
+ "update:modelValue",
172
+ ]);
150
173
 
151
174
  const hovered = ref(null);
152
175
 
153
- const { config, counterAttrs, ratingAttrs, wrapperAttrs, iconAttrs, iconWrapperAttrs, labelAttrs } =
154
- useAttrs(props);
176
+ const {
177
+ config,
178
+ labelAttrs,
179
+ wrapperAttrs,
180
+ counterAttrs,
181
+ totalAttrs,
182
+ starsAttrs,
183
+ starAttrs,
184
+ hasSlotContent,
185
+ } = useAttrs(props);
155
186
 
156
187
  const iconSize = computed(() => {
157
188
  const sizes = {
@@ -163,7 +194,7 @@ const iconSize = computed(() => {
163
194
  return sizes[props.size];
164
195
  });
165
196
 
166
- const ratingCounter = computed(() => {
197
+ const counterValue = computed(() => {
167
198
  return hovered.value || props.modelValue;
168
199
  });
169
200
 
@@ -30,7 +30,7 @@
30
30
  </template>
31
31
 
32
32
  <script setup>
33
- import { computed, inject, onMounted, ref, watchEffect } from "vue";
33
+ import { computed, inject, onMounted, ref, watchEffect, toValue } from "vue";
34
34
 
35
35
  import ULabel from "../ui.form-label";
36
36
  import UIService, { getRandomId } from "../service.ui";
@@ -162,8 +162,8 @@ const emit = defineEmits(["update:modelValue"]);
162
162
 
163
163
  const localValue = ref("");
164
164
  const radioName = ref(null);
165
- const radioColor = ref(getRadioGroupColor ? getRadioGroupColor() : props.color);
166
- const radioSize = ref(getRadioGroupSize ? getRadioGroupSize() : props.size);
165
+ const radioColor = ref(toValue(getRadioGroupColor) || props.color);
166
+ const radioSize = ref(toValue(getRadioGroupSize) || props.size);
167
167
 
168
168
  const isChecked = computed(() => {
169
169
  const currentValue = props.modelValue ?? localValue.value;
@@ -182,14 +182,13 @@ const radioValue = computed(() => {
182
182
  });
183
183
 
184
184
  onMounted(() => {
185
- radioName.value = props.name || getRadioGroupName();
185
+ radioName.value = props.name || toValue(getRadioGroupName);
186
186
  });
187
187
 
188
- watchEffect(() => (radioColor.value = getRadioGroupColor ? getRadioGroupColor() : props.color));
189
- watchEffect(() => (radioSize.value = getRadioGroupSize ? getRadioGroupSize() : props.size));
188
+ watchEffect(() => (radioColor.value = toValue(getRadioGroupColor) || props.color));
189
+ watchEffect(() => (radioSize.value = toValue(getRadioGroupSize) || props.size));
190
190
  watchEffect(() => {
191
- localValue.value = getRadioGroupSelectedItem ? getRadioGroupSelectedItem() : null;
192
-
191
+ localValue.value = toValue(getRadioGroupSelectedItem) || null;
193
192
  emit("update:modelValue", props.value);
194
193
  });
195
194
 
@@ -47,5 +47,6 @@ export function useAttrs(props) {
47
47
  return {
48
48
  loaderAttrs,
49
49
  ellipseAttrs,
50
+ config,
50
51
  };
51
52
  }