vueless 0.0.725 → 0.0.727
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 +1 -1
- package/ui.button-toggle/UToggle.vue +36 -54
- package/ui.button-toggle/config.ts +1 -20
- package/ui.button-toggle/storybook/stories.ts +5 -33
- package/ui.button-toggle/types.ts +0 -20
- package/ui.dropdown-badge/config.ts +2 -2
- package/ui.dropdown-button/config.ts +2 -2
- package/ui.dropdown-link/config.ts +2 -2
- package/ui.form-calendar/config.ts +2 -2
- package/ui.form-input/config.ts +2 -2
- package/ui.form-input-file/config.ts +1 -1
- package/ui.form-input-rating/UInputRating.vue +28 -48
- package/ui.form-input-rating/config.ts +0 -2
- package/ui.form-input-rating/storybook/stories.ts +3 -22
- package/ui.form-input-rating/types.ts +0 -20
- package/ui.form-select/config.ts +3 -3
- package/ui.form-textarea/config.ts +2 -2
- package/ui.loader-progress/ULoaderProgress.vue +46 -63
- package/ui.loader-progress/config.ts +1 -1
- package/ui.loader-progress/constants.ts +0 -1
- package/ui.loader-progress/storybook/docs.mdx +3 -15
- package/ui.loader-progress/storybook/stories.ts +1 -1
- package/ui.loader-progress/types.ts +1 -1
- package/ui.loader-progress/useLoaderProgress.ts +19 -30
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from "vue";
|
|
3
3
|
|
|
4
|
-
import ULabel from "../ui.form-label/ULabel.vue";
|
|
5
4
|
import UButton from "../ui.button/UButton.vue";
|
|
6
5
|
|
|
7
6
|
import useUI from "../composables/useUI.ts";
|
|
@@ -65,78 +64,61 @@ const mutatedProps = computed(() => ({
|
|
|
65
64
|
selected: isSelected,
|
|
66
65
|
}));
|
|
67
66
|
|
|
68
|
-
const {
|
|
69
|
-
|
|
67
|
+
const { optionsAttrs, toggleButtonInactiveAttrs, toggleButtonActiveAttrs } = useUI<Config>(
|
|
68
|
+
defaultConfig,
|
|
69
|
+
mutatedProps,
|
|
70
|
+
);
|
|
70
71
|
</script>
|
|
71
72
|
|
|
72
73
|
<template>
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
<div v-bind="optionsAttrs">
|
|
92
|
-
<UButton
|
|
93
|
-
v-for="(option, index) in options"
|
|
94
|
-
:key="option.value"
|
|
95
|
-
:label="option.label"
|
|
96
|
-
tabindex="0"
|
|
97
|
-
color="gray"
|
|
98
|
-
:size="size"
|
|
99
|
-
:round="round"
|
|
100
|
-
:block="block"
|
|
101
|
-
:square="square"
|
|
102
|
-
:disabled="disabled"
|
|
103
|
-
v-bind="isSelected(option) ? toggleButtonActiveAttrs : toggleButtonInactiveAttrs"
|
|
104
|
-
:data-test="`${dataTest}-option-${index}`"
|
|
105
|
-
@click="onClickOption(option)"
|
|
106
|
-
>
|
|
107
|
-
<template #left="{ iconName }">
|
|
108
|
-
<!--
|
|
74
|
+
<div v-bind="optionsAttrs">
|
|
75
|
+
<UButton
|
|
76
|
+
v-for="(option, index) in options"
|
|
77
|
+
:key="option.value"
|
|
78
|
+
:label="option.label"
|
|
79
|
+
tabindex="0"
|
|
80
|
+
color="gray"
|
|
81
|
+
:size="size"
|
|
82
|
+
:round="round"
|
|
83
|
+
:block="block"
|
|
84
|
+
:square="square"
|
|
85
|
+
:disabled="disabled"
|
|
86
|
+
v-bind="isSelected(option) ? toggleButtonActiveAttrs : toggleButtonInactiveAttrs"
|
|
87
|
+
:data-test="`${dataTest}-option-${index}`"
|
|
88
|
+
@click="onClickOption(option)"
|
|
89
|
+
>
|
|
90
|
+
<template #left="{ iconName }">
|
|
91
|
+
<!--
|
|
109
92
|
@slot Use it to add something before the label.
|
|
110
93
|
@binding {object} option
|
|
111
94
|
@binding {string} icon-name
|
|
112
95
|
@binding {number} index
|
|
113
96
|
-->
|
|
114
|
-
|
|
115
|
-
|
|
97
|
+
<slot name="left" :option="option" :icon-name="iconName" :index="index" />
|
|
98
|
+
</template>
|
|
116
99
|
|
|
117
|
-
|
|
118
|
-
|
|
100
|
+
<template #default="{ label, iconName }">
|
|
101
|
+
<!--
|
|
119
102
|
@slot Use it to add something instead of the toggle option label.
|
|
120
103
|
@binding {object} option
|
|
121
104
|
@binding {string} label
|
|
122
105
|
@binding {string} icon-name
|
|
123
106
|
@binding {number} index
|
|
124
107
|
-->
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
108
|
+
<slot name="option" :option="option" :label="label" :icon-name="iconName" :index="index">
|
|
109
|
+
{{ option.label }}
|
|
110
|
+
</slot>
|
|
111
|
+
</template>
|
|
129
112
|
|
|
130
|
-
|
|
131
|
-
|
|
113
|
+
<template #right="{ iconName }">
|
|
114
|
+
<!--
|
|
132
115
|
@slot Use it to add something after the label.
|
|
133
116
|
@binding {object} option
|
|
134
117
|
@binding {string} icon-name
|
|
135
118
|
@binding {number} index
|
|
136
119
|
-->
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
</ULabel>
|
|
120
|
+
<slot name="right" :option="option" :icon-name="iconName" :index="index" />
|
|
121
|
+
</template>
|
|
122
|
+
</UButton>
|
|
123
|
+
</div>
|
|
142
124
|
</template>
|
|
@@ -1,22 +1,4 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
|
-
toggleLabel: {
|
|
3
|
-
base: "{ULabel} flex-wrap",
|
|
4
|
-
variants: {
|
|
5
|
-
block: {
|
|
6
|
-
true: "w-full",
|
|
7
|
-
},
|
|
8
|
-
},
|
|
9
|
-
defaults: {
|
|
10
|
-
size: {
|
|
11
|
-
"2xs": "sm",
|
|
12
|
-
xs: "sm",
|
|
13
|
-
sm: "md",
|
|
14
|
-
md: "md",
|
|
15
|
-
lg: "lg",
|
|
16
|
-
xl: "lg",
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
2
|
options: {
|
|
21
3
|
base: "flex",
|
|
22
4
|
variants: {
|
|
@@ -33,7 +15,7 @@ export default /*tw*/ {
|
|
|
33
15
|
false: "flex-nowrap gap-1 p-1 w-fit border rounded-dynamic border-gray-300",
|
|
34
16
|
},
|
|
35
17
|
disabled: {
|
|
36
|
-
true: "pointer-events-none",
|
|
18
|
+
true: "pointer-events-none bg-gray-100",
|
|
37
19
|
},
|
|
38
20
|
block: {
|
|
39
21
|
true: "w-full flex-nowrap",
|
|
@@ -78,7 +60,6 @@ export default /*tw*/ {
|
|
|
78
60
|
},
|
|
79
61
|
},
|
|
80
62
|
defaults: {
|
|
81
|
-
labelAlign: "top",
|
|
82
63
|
size: "md",
|
|
83
64
|
split: false,
|
|
84
65
|
block: false,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref
|
|
1
|
+
import { ref } from "vue";
|
|
2
2
|
import {
|
|
3
3
|
getArgTypes,
|
|
4
4
|
getSlotNames,
|
|
@@ -24,7 +24,6 @@ export default {
|
|
|
24
24
|
title: "Buttons & Links / Toggle",
|
|
25
25
|
component: UToggle,
|
|
26
26
|
args: {
|
|
27
|
-
label: "Please choose a role",
|
|
28
27
|
modelValue: "11",
|
|
29
28
|
options: [
|
|
30
29
|
{ value: "11", label: "Admin" },
|
|
@@ -47,22 +46,11 @@ const DefaultTemplate: StoryFn<UToggleArgs> = (args: UToggleArgs) => ({
|
|
|
47
46
|
components: { UToggle, UIcon, UBadge },
|
|
48
47
|
setup() {
|
|
49
48
|
const slots = getSlotNames(UToggle.__name);
|
|
50
|
-
const errorMessage = computed(() => {
|
|
51
|
-
if (args.name === "error" && Array.isArray(args.modelValue)) {
|
|
52
|
-
return args.modelValue.length === 0 ? "Please select at least one option" : "";
|
|
53
|
-
}
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return { args, slots, errorMessage };
|
|
50
|
+
return { args, slots };
|
|
59
51
|
},
|
|
60
52
|
template: `
|
|
61
|
-
<UToggle
|
|
62
|
-
v-bind="args"
|
|
63
|
-
v-model="args.modelValue"
|
|
64
|
-
:error="errorMessage"
|
|
65
|
-
>
|
|
53
|
+
<UToggle v-bind="args" v-model="args.modelValue">
|
|
66
54
|
${args.slotTemplate || getSlotsFragment("")}
|
|
67
55
|
</UToggle>
|
|
68
56
|
`,
|
|
@@ -87,7 +75,6 @@ const EnumVariantTemplate: StoryFn<UToggleArgs> = (args: UToggleArgs, { argTypes
|
|
|
87
75
|
v-bind="args"
|
|
88
76
|
v-model="values[option]"
|
|
89
77
|
:[args.enum]="option"
|
|
90
|
-
:label="option"
|
|
91
78
|
:options="[
|
|
92
79
|
{ value: option + 1, label: option },
|
|
93
80
|
{ value: option + 2, label: option },
|
|
@@ -106,7 +93,6 @@ Default.args = {
|
|
|
106
93
|
export const Disabled = DefaultTemplate.bind({});
|
|
107
94
|
Disabled.args = {
|
|
108
95
|
name: "Disabled",
|
|
109
|
-
label: "You can disable the whole toggle or specific items",
|
|
110
96
|
options: [
|
|
111
97
|
{ value: "11", label: "Admin" },
|
|
112
98
|
{ value: "12", label: "Editor", disabled: true },
|
|
@@ -115,9 +101,6 @@ Disabled.args = {
|
|
|
115
101
|
],
|
|
116
102
|
};
|
|
117
103
|
|
|
118
|
-
export const Description = DefaultTemplate.bind({});
|
|
119
|
-
Description.args = { name: "Description", description: "You can also add description" };
|
|
120
|
-
|
|
121
104
|
export const Sizes = EnumVariantTemplate.bind({});
|
|
122
105
|
Sizes.args = { name: "sizeTemplate", enum: "size" };
|
|
123
106
|
|
|
@@ -126,15 +109,6 @@ Multiple.args = {
|
|
|
126
109
|
name: "multiple",
|
|
127
110
|
multiple: true,
|
|
128
111
|
modelValue: [],
|
|
129
|
-
label: "You can choose more than one option",
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
export const Error = DefaultTemplate.bind({});
|
|
133
|
-
Error.args = {
|
|
134
|
-
name: "error",
|
|
135
|
-
multiple: true,
|
|
136
|
-
modelValue: [],
|
|
137
|
-
label: "If no option is selected, error message is displayed",
|
|
138
112
|
};
|
|
139
113
|
|
|
140
114
|
export const Block = DefaultTemplate.bind({});
|
|
@@ -150,7 +124,6 @@ export const Square = DefaultTemplate.bind({});
|
|
|
150
124
|
Square.args = {
|
|
151
125
|
name: "square",
|
|
152
126
|
square: true,
|
|
153
|
-
label: "Square prop is useful when icons are present",
|
|
154
127
|
options: [
|
|
155
128
|
{ value: "11", label: "star" },
|
|
156
129
|
{ value: "12", label: "add" },
|
|
@@ -166,7 +139,6 @@ Square.args = {
|
|
|
166
139
|
export const DefaultSlot = DefaultTemplate.bind({});
|
|
167
140
|
DefaultSlot.args = {
|
|
168
141
|
name: "defaultSlot",
|
|
169
|
-
label: "Please select an operation to proceed",
|
|
170
142
|
options: [
|
|
171
143
|
{ value: "1", label: "Download", rightIcon: "download", color: "green" },
|
|
172
144
|
{ value: "2", label: "Edit", rightIcon: "edit_note", color: "orange" },
|
|
@@ -195,13 +167,13 @@ export const Slots: StoryFn<UToggleArgs> = (args) => ({
|
|
|
195
167
|
<URow no-mobile>
|
|
196
168
|
<UToggle v-bind="args" v-model="leftModel" name="leftSlot">
|
|
197
169
|
<template #left="{ index }">
|
|
198
|
-
<UIcon v-if="index === 0" name="settings" />
|
|
170
|
+
<UIcon size="sm" color="inherit" v-if="index === 0" name="settings" />
|
|
199
171
|
</template>
|
|
200
172
|
</UToggle>
|
|
201
173
|
|
|
202
174
|
<UToggle v-bind="args" v-model="rightModel" name="rightSlot">
|
|
203
175
|
<template #right="{ index }">
|
|
204
|
-
<UIcon v-if="index === 2" name="person" />
|
|
176
|
+
<UIcon size="sm" color="inherit" v-if="index === 2" name="person" />
|
|
205
177
|
</template>
|
|
206
178
|
</UToggle>
|
|
207
179
|
</URow>
|
|
@@ -30,26 +30,6 @@ export interface Props {
|
|
|
30
30
|
*/
|
|
31
31
|
size?: "2xs" | "xs" | "sm" | "md" | "lg" | "xl";
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
* Error message.
|
|
35
|
-
*/
|
|
36
|
-
error?: string;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Label placement.
|
|
40
|
-
*/
|
|
41
|
-
labelAlign?: "top" | "topWithDesc" | "left" | "right";
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Toggle label.
|
|
45
|
-
*/
|
|
46
|
-
label?: string;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Toggle description.
|
|
50
|
-
*/
|
|
51
|
-
description?: string;
|
|
52
|
-
|
|
53
33
|
/**
|
|
54
34
|
* Toggle name.
|
|
55
35
|
*/
|
|
@@ -14,12 +14,12 @@ export default /*tw*/ {
|
|
|
14
14
|
},
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
|
-
dateInRange: "bg-brand/
|
|
17
|
+
dateInRange: "bg-brand-600/10 !text-brand-900 hover:bg-brand/15 rounded-none",
|
|
18
18
|
edgeDateInRange: "",
|
|
19
19
|
firstDateInRange: "rounded-r-none",
|
|
20
20
|
lastDateInRange: "rounded-l-none",
|
|
21
21
|
anotherMonthDate: "text-gray-400",
|
|
22
|
-
activeDate: "bg-brand-
|
|
22
|
+
activeDate: "bg-brand-600/10",
|
|
23
23
|
selectedDate: "",
|
|
24
24
|
currentDate: "border-2 border-brand-600",
|
|
25
25
|
day: "{UButton} size-9 w-full",
|
package/ui.form-input/config.ts
CHANGED
|
@@ -29,8 +29,8 @@ export default /*tw*/ {
|
|
|
29
29
|
rightIcon: "{UIcon} {>inputIcon}",
|
|
30
30
|
passwordIcon: "{UIcon} {>inputIcon}",
|
|
31
31
|
passwordIconWrapper: "flex items-center justify-end whitespace-nowrap pr-2.5 gap-1 rounded-inherit rounded-l-none",
|
|
32
|
-
leftSlot: "pl-
|
|
33
|
-
rightSlot: "pr-
|
|
32
|
+
leftSlot: "pl-2.5 flex items-center",
|
|
33
|
+
rightSlot: "pr-2.5 flex items-center",
|
|
34
34
|
input: {
|
|
35
35
|
base: `
|
|
36
36
|
block w-full py-2 px-3 font-normal !leading-none text-gray-900 bg-transparent
|
|
@@ -25,7 +25,7 @@ export default /*tw*/ {
|
|
|
25
25
|
descriptionTop: "{UText} text-gray-700 mb-2",
|
|
26
26
|
descriptionBottom: "{UText} text-gray-700 mt-2",
|
|
27
27
|
content: {
|
|
28
|
-
base: "p-3 gap-3 flex justify-between items-start relative w-full rounded-dynamic bg-brand-
|
|
28
|
+
base: "p-3 gap-3 flex justify-between items-start relative w-full rounded-dynamic bg-brand-600/5",
|
|
29
29
|
variants: {
|
|
30
30
|
multiple: {
|
|
31
31
|
false: "items-center",
|
|
@@ -6,7 +6,6 @@ import { hasSlotContent } from "../utils/helper.ts";
|
|
|
6
6
|
import { getDefaults } from "../utils/ui.ts";
|
|
7
7
|
|
|
8
8
|
import UIcon from "../ui.image-icon/UIcon.vue";
|
|
9
|
-
import ULabel from "../ui.form-label/ULabel.vue";
|
|
10
9
|
|
|
11
10
|
import { COMPONENT_NAME } from "./constants.ts";
|
|
12
11
|
import defaultConfig from "./config.ts";
|
|
@@ -60,65 +59,46 @@ function onMouseHover(overStar: number | null = null) {
|
|
|
60
59
|
* Get element / nested component attributes for each config token ✨
|
|
61
60
|
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
|
|
62
61
|
*/
|
|
63
|
-
const { config,
|
|
62
|
+
const { config, containerAttrs, counterAttrs, totalAttrs, starsAttrs, starAttrs } =
|
|
64
63
|
useUI<Config>(defaultConfig);
|
|
65
64
|
</script>
|
|
66
65
|
|
|
67
66
|
<template>
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
:error="error"
|
|
71
|
-
:size="size"
|
|
72
|
-
:align="labelAlign"
|
|
73
|
-
:description="description"
|
|
74
|
-
:disabled="disabled"
|
|
75
|
-
v-bind="inputLabelAttrs"
|
|
76
|
-
:data-test="dataTest"
|
|
77
|
-
>
|
|
78
|
-
<template #label>
|
|
67
|
+
<div v-bind="containerAttrs">
|
|
68
|
+
<div v-if="counter || hasSlotContent($slots['counter'])" v-bind="counterAttrs">
|
|
79
69
|
<!--
|
|
80
|
-
@slot Use this to add custom content instead of the label.
|
|
81
|
-
@binding {string} label
|
|
82
|
-
-->
|
|
83
|
-
<slot name="label" :label="label" />
|
|
84
|
-
</template>
|
|
85
|
-
|
|
86
|
-
<div v-bind="containerAttrs">
|
|
87
|
-
<div v-if="counter || hasSlotContent($slots['counter'])" v-bind="counterAttrs">
|
|
88
|
-
<!--
|
|
89
70
|
@slot Use it to customise counter.
|
|
90
71
|
@binding {number} counter
|
|
91
72
|
@binding {number} total
|
|
92
73
|
-->
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
74
|
+
<slot name="counter" :counter="counterValue" :total="total">
|
|
75
|
+
{{ counterValue }}
|
|
76
|
+
</slot>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div v-bind="starsAttrs">
|
|
80
|
+
<UIcon
|
|
81
|
+
v-for="star in stars"
|
|
82
|
+
:key="star"
|
|
83
|
+
internal
|
|
84
|
+
:color="error ? 'red' : 'brand'"
|
|
85
|
+
:interactive="selectable"
|
|
86
|
+
:name="starIcon(star)"
|
|
87
|
+
v-bind="starAttrs"
|
|
88
|
+
:data-test="`${dataTest}-rating-star-${star}`"
|
|
89
|
+
@click="onClickStar(star)"
|
|
90
|
+
@mouseleave="onMouseHover()"
|
|
91
|
+
@mouseover="onMouseHover(star)"
|
|
92
|
+
/>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div v-if="total || hasSlotContent($slots['total'])" v-bind="totalAttrs">
|
|
96
|
+
<!--
|
|
116
97
|
@slot Use it to customise total.
|
|
117
98
|
@binding {number} counter
|
|
118
99
|
@binding {number} total
|
|
119
100
|
-->
|
|
120
|
-
|
|
121
|
-
</div>
|
|
101
|
+
<slot name="total" :counter="counter" :total="total">({{ total }})</slot>
|
|
122
102
|
</div>
|
|
123
|
-
</
|
|
103
|
+
</div>
|
|
124
104
|
</template>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
|
-
inputLabel: "{ULabel}",
|
|
3
2
|
container: {
|
|
4
3
|
base: "flex items-center text-gray-500 !leading-none",
|
|
5
4
|
variants: {
|
|
@@ -45,7 +44,6 @@ export default /*tw*/ {
|
|
|
45
44
|
},
|
|
46
45
|
},
|
|
47
46
|
defaults: {
|
|
48
|
-
labelAlign: "top",
|
|
49
47
|
size: "md",
|
|
50
48
|
stars: 5,
|
|
51
49
|
counter: false,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { computed } from "vue";
|
|
2
1
|
import {
|
|
3
2
|
getArgTypes,
|
|
4
3
|
getSlotNames,
|
|
@@ -15,7 +14,7 @@ import type { Props } from "../types.ts";
|
|
|
15
14
|
|
|
16
15
|
interface UInputRatingArgs extends Props {
|
|
17
16
|
slotTemplate?: string;
|
|
18
|
-
enum: "size"
|
|
17
|
+
enum: "size";
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
export default {
|
|
@@ -40,16 +39,11 @@ const DefaultTemplate: StoryFn<UInputRatingArgs> = (args: UInputRatingArgs) => (
|
|
|
40
39
|
components: { UInputRating, UBadge },
|
|
41
40
|
setup() {
|
|
42
41
|
const slots = getSlotNames(UInputRating.__name);
|
|
43
|
-
const errorMessage = computed(() => (!args.modelValue ? args.error : ""));
|
|
44
42
|
|
|
45
|
-
return { args, slots
|
|
43
|
+
return { args, slots };
|
|
46
44
|
},
|
|
47
45
|
template: `
|
|
48
|
-
<UInputRating
|
|
49
|
-
v-bind="args"
|
|
50
|
-
v-model="args.modelValue"
|
|
51
|
-
:error="errorMessage"
|
|
52
|
-
>
|
|
46
|
+
<UInputRating v-bind="args" v-model="args.modelValue">
|
|
53
47
|
${args.slotTemplate || getSlotsFragment("")}
|
|
54
48
|
</UInputRating>
|
|
55
49
|
`,
|
|
@@ -81,25 +75,12 @@ const EnumVariantTemplate: StoryFn<UInputRatingArgs> = (args: UInputRatingArgs,
|
|
|
81
75
|
export const Default = DefaultTemplate.bind({});
|
|
82
76
|
Default.args = {};
|
|
83
77
|
|
|
84
|
-
export const Description = DefaultTemplate.bind({});
|
|
85
|
-
Description.args = { description: "Your review helps us improve our services." };
|
|
86
|
-
|
|
87
|
-
export const Error = DefaultTemplate.bind({});
|
|
88
|
-
Error.args = {
|
|
89
|
-
selectable: true,
|
|
90
|
-
modelValue: 0,
|
|
91
|
-
error: "Please select a rating before submitting your review.",
|
|
92
|
-
};
|
|
93
|
-
|
|
94
78
|
export const Disabled = DefaultTemplate.bind({});
|
|
95
79
|
Disabled.args = { disabled: true };
|
|
96
80
|
|
|
97
81
|
export const Sizes = EnumVariantTemplate.bind({});
|
|
98
82
|
Sizes.args = { enum: "size" };
|
|
99
83
|
|
|
100
|
-
export const LabelPlacement = EnumVariantTemplate.bind({});
|
|
101
|
-
LabelPlacement.args = { enum: "labelAlign" };
|
|
102
|
-
|
|
103
84
|
export const StarAmount = DefaultTemplate.bind({});
|
|
104
85
|
StarAmount.args = { stars: 7 };
|
|
105
86
|
StarAmount.parameters = {
|
|
@@ -5,21 +5,11 @@ import type { ComponentConfig } from "../types.ts";
|
|
|
5
5
|
export type Config = typeof defaultConfig;
|
|
6
6
|
|
|
7
7
|
export interface Props {
|
|
8
|
-
/**
|
|
9
|
-
* Rating label.
|
|
10
|
-
*/
|
|
11
|
-
label?: string;
|
|
12
|
-
|
|
13
8
|
/**
|
|
14
9
|
* Rating value.
|
|
15
10
|
*/
|
|
16
11
|
modelValue: number;
|
|
17
12
|
|
|
18
|
-
/**
|
|
19
|
-
* Rating description.
|
|
20
|
-
*/
|
|
21
|
-
description?: string;
|
|
22
|
-
|
|
23
13
|
/**
|
|
24
14
|
* Rating number of stars.
|
|
25
15
|
*/
|
|
@@ -30,16 +20,6 @@ export interface Props {
|
|
|
30
20
|
*/
|
|
31
21
|
size?: "sm" | "md" | "lg";
|
|
32
22
|
|
|
33
|
-
/**
|
|
34
|
-
* Rating label placement.
|
|
35
|
-
*/
|
|
36
|
-
labelAlign?: "top" | "topWithDesc" | "left" | "right";
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Rating error message.
|
|
40
|
-
*/
|
|
41
|
-
error?: string;
|
|
42
|
-
|
|
43
23
|
/**
|
|
44
24
|
* Disable the input.
|
|
45
25
|
*/
|
package/ui.form-select/config.ts
CHANGED
|
@@ -81,10 +81,10 @@ export default /*tw*/ {
|
|
|
81
81
|
},
|
|
82
82
|
leftIcon: "{UIcon} {>selectIcon}",
|
|
83
83
|
rightIcon: "{UIcon} {>selectIcon}",
|
|
84
|
-
leftSlot: "{>toggle} pl-
|
|
85
|
-
rightSlot: "{>toggle} pr-
|
|
84
|
+
leftSlot: "{>toggle} pl-2.5",
|
|
85
|
+
rightSlot: "{>toggle} pr-2.5",
|
|
86
86
|
beforeToggle: "{>toggle} cursor-auto",
|
|
87
|
-
afterToggle: "{>toggle} mr-
|
|
87
|
+
afterToggle: "{>toggle} mr-2.5 items-start pt-3 cursor-auto",
|
|
88
88
|
toggle: {
|
|
89
89
|
base: "flex items-center",
|
|
90
90
|
compoundVariants: [
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
2
|
textareaLabel: "{ULabel}",
|
|
3
3
|
slot: "flex items-center justify-center whitespace-nowrap gap-1 rounded-dynamic",
|
|
4
|
-
leftSlot: "{>slot} pl-
|
|
5
|
-
rightSlot: "{>slot} pr-
|
|
4
|
+
leftSlot: "{>slot} pl-2.5 rounded-r-none",
|
|
5
|
+
rightSlot: "{>slot} pr-2.5 rounded-l-none",
|
|
6
6
|
wrapper: {
|
|
7
7
|
base: `
|
|
8
8
|
flex bg-white transition w-full
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed,
|
|
2
|
+
import { computed, watch, ref } from "vue";
|
|
3
3
|
|
|
4
4
|
import useUI from "../composables/useUI.ts";
|
|
5
5
|
import { getDefaults } from "../utils/ui.ts";
|
|
@@ -7,7 +7,7 @@ import { getDefaults } from "../utils/ui.ts";
|
|
|
7
7
|
import { clamp, queue, getRequestWithoutQuery } from "./utilLoaderProgress.ts";
|
|
8
8
|
import { useLoaderProgress } from "./useLoaderProgress.ts";
|
|
9
9
|
|
|
10
|
-
import { COMPONENT_NAME, MAXIMUM, SPEED
|
|
10
|
+
import { COMPONENT_NAME, MAXIMUM, SPEED } from "./constants.ts";
|
|
11
11
|
import defaultConfig from "./config.ts";
|
|
12
12
|
|
|
13
13
|
import type { Props, Config } from "./types.ts";
|
|
@@ -25,16 +25,9 @@ const progress = ref(0);
|
|
|
25
25
|
const opacity = ref(1);
|
|
26
26
|
const status = ref<number | null>(null);
|
|
27
27
|
|
|
28
|
-
const {
|
|
29
|
-
requestQueue,
|
|
30
|
-
removeRequestUrl,
|
|
31
|
-
isLoading,
|
|
32
|
-
loaderProgressOff,
|
|
33
|
-
loaderProgressOn,
|
|
34
|
-
addRequestUrl,
|
|
35
|
-
} = useLoaderProgress();
|
|
28
|
+
const { requestQueue } = useLoaderProgress();
|
|
36
29
|
|
|
37
|
-
const
|
|
30
|
+
const isLoading = computed(() => {
|
|
38
31
|
return typeof status.value === "number";
|
|
39
32
|
});
|
|
40
33
|
|
|
@@ -45,68 +38,37 @@ const barStyle = computed(() => {
|
|
|
45
38
|
};
|
|
46
39
|
});
|
|
47
40
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
: [getRequestWithoutQuery(props.resources)];
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const isPropsLoading = computed(
|
|
55
|
-
() => requestQueue.value.includes(INFINITY_LOADING) && props.loading,
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
watch(() => requestQueue.value.length, onChangeRequestsQueue);
|
|
59
|
-
|
|
60
|
-
onMounted(() => {
|
|
61
|
-
window.addEventListener("loaderProgressOn", setLoaderOnHandler as EventListener);
|
|
62
|
-
window.addEventListener("loaderProgressOff", setLoaderOffHandler as EventListener);
|
|
63
|
-
|
|
64
|
-
if (props.resources) {
|
|
65
|
-
onChangeRequestsQueue();
|
|
41
|
+
const resourceSubscriptions = computed(() => {
|
|
42
|
+
if (Array.isArray(props.resources)) {
|
|
43
|
+
return props.resources.map(getRequestWithoutQuery);
|
|
66
44
|
}
|
|
67
|
-
});
|
|
68
45
|
|
|
69
|
-
|
|
70
|
-
removeRequestUrl(resourceNamesArray.value);
|
|
46
|
+
return [getRequestWithoutQuery(props.resources)];
|
|
71
47
|
});
|
|
72
48
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
49
|
+
const isActiveRequests = computed(() => {
|
|
50
|
+
const isAnyRequestActive = props.resources === "any" && requestQueue.value.length;
|
|
51
|
+
const isSubscribedRequestsActive = resourceSubscriptions.value.some((resource) =>
|
|
52
|
+
requestQueue.value.includes(resource),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return isAnyRequestActive || isSubscribedRequestsActive;
|
|
76
56
|
});
|
|
77
57
|
|
|
58
|
+
watch(() => requestQueue, onChangeRequestsQueue, { immediate: true, deep: true });
|
|
59
|
+
|
|
78
60
|
watch(
|
|
79
61
|
() => props.loading,
|
|
80
|
-
() =>
|
|
81
|
-
if (props.loading) {
|
|
82
|
-
addRequestUrl(INFINITY_LOADING);
|
|
83
|
-
isLoading.value = true;
|
|
84
|
-
} else {
|
|
85
|
-
removeRequestUrl(INFINITY_LOADING);
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
{ immediate: true },
|
|
62
|
+
() => (props.loading ? start() : stop()),
|
|
89
63
|
);
|
|
90
64
|
|
|
91
|
-
function setLoaderOnHandler(event: CustomEvent<{ resource: string }>) {
|
|
92
|
-
loaderProgressOn(event.detail.resource);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function setLoaderOffHandler(event: CustomEvent<{ resource: string }>) {
|
|
96
|
-
loaderProgressOff(event.detail.resource);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
65
|
function onChangeRequestsQueue() {
|
|
100
|
-
|
|
101
|
-
isPropsLoading.value ||
|
|
102
|
-
resourceNamesArray.value.some((resource: string) => {
|
|
103
|
-
return requestQueue.value.includes(resource);
|
|
104
|
-
});
|
|
66
|
+
if (props.loading !== undefined) return;
|
|
105
67
|
|
|
106
|
-
if (isActiveRequests
|
|
68
|
+
if (isActiveRequests.value && !isLoading.value) {
|
|
107
69
|
start();
|
|
108
|
-
} else if (!isActiveRequests &&
|
|
109
|
-
|
|
70
|
+
} else if (!isActiveRequests.value && isLoading.value && show.value) {
|
|
71
|
+
stop();
|
|
110
72
|
}
|
|
111
73
|
}
|
|
112
74
|
|
|
@@ -125,8 +87,9 @@ function afterEnter() {
|
|
|
125
87
|
}
|
|
126
88
|
|
|
127
89
|
function work() {
|
|
90
|
+
// TODO: Use requestAnimationFrame for animations instead of setTimeout for better performance and smoothness.
|
|
128
91
|
setTimeout(() => {
|
|
129
|
-
if (!
|
|
92
|
+
if (!isLoading.value) {
|
|
130
93
|
return;
|
|
131
94
|
}
|
|
132
95
|
|
|
@@ -152,7 +115,7 @@ function start() {
|
|
|
152
115
|
function set(amount: number) {
|
|
153
116
|
let currentProgress;
|
|
154
117
|
|
|
155
|
-
if (
|
|
118
|
+
if (isLoading.value) {
|
|
156
119
|
currentProgress = amount < progress.value ? clamp(amount, 0, 100) : clamp(amount, 0.8, 100);
|
|
157
120
|
} else {
|
|
158
121
|
currentProgress = 0;
|
|
@@ -200,10 +163,30 @@ function increase(amount?: number) {
|
|
|
200
163
|
set(clamp(currentProgress + (amount || 0), 0, MAXIMUM));
|
|
201
164
|
}
|
|
202
165
|
|
|
203
|
-
function
|
|
166
|
+
function stop() {
|
|
204
167
|
set(100);
|
|
205
168
|
}
|
|
206
169
|
|
|
170
|
+
defineExpose({
|
|
171
|
+
/**
|
|
172
|
+
* Start loading animation.
|
|
173
|
+
* @property {Function}
|
|
174
|
+
*/
|
|
175
|
+
start,
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Stop loading animation.
|
|
179
|
+
* @property {Function}
|
|
180
|
+
*/
|
|
181
|
+
stop,
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Loading state.
|
|
185
|
+
* @property {Boolean}
|
|
186
|
+
*/
|
|
187
|
+
isLoading,
|
|
188
|
+
});
|
|
189
|
+
|
|
207
190
|
/**
|
|
208
191
|
* Get element / nested component attributes for each config token ✨
|
|
209
192
|
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
|
|
@@ -21,33 +21,21 @@ The loader uses queue of resources and will be shown until at least one item is
|
|
|
21
21
|
import { useLoaderProgress } from "vueless";
|
|
22
22
|
|
|
23
23
|
const {
|
|
24
|
-
isLoading,
|
|
25
24
|
loaderProgressOn,
|
|
26
25
|
loaderProgressOff,
|
|
27
26
|
requestQueue,
|
|
28
|
-
addRequestUrl
|
|
29
|
-
removeRequestUrl
|
|
30
27
|
} = useLoaderProgress();
|
|
31
28
|
|
|
32
|
-
// get loader state
|
|
33
|
-
console.log(isLoading.value);
|
|
34
|
-
|
|
35
29
|
// show loader (add resource into queue)
|
|
36
30
|
loaderProgressOn("/transactions");
|
|
31
|
+
loaderProgressOff(["/transactions", "/products"]);
|
|
37
32
|
|
|
38
33
|
// hide loader (remove resource from queue)
|
|
39
34
|
loaderProgressOff("/transactions");
|
|
35
|
+
loaderProgressOff(["/transactions", "/products"]);
|
|
40
36
|
|
|
41
|
-
// get current resource
|
|
37
|
+
// get current global resource queue
|
|
42
38
|
console.log(requestQueue.value);
|
|
43
|
-
|
|
44
|
-
// add resource into loader queue
|
|
45
|
-
addRequestUrl("/transactions");
|
|
46
|
-
addRequestUrl(["/transactions", "/products"]);
|
|
47
|
-
|
|
48
|
-
// remove resource from loader queue
|
|
49
|
-
removeRequestUrl("/transactions");
|
|
50
|
-
removeRequestUrl(["/transactions", "/products"]);
|
|
51
39
|
`} language="jsx" dark />
|
|
52
40
|
|
|
53
41
|
## Using loader outside Vue components
|
|
@@ -97,7 +97,7 @@ const EnumVariantTemplate: StoryFn<ULoaderProgressArgs> = (
|
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
export const Default = DefaultTemplate.bind({});
|
|
100
|
-
Default.args = {
|
|
100
|
+
Default.args = {};
|
|
101
101
|
|
|
102
102
|
export const Color = EnumVariantTemplate.bind({});
|
|
103
103
|
Color.args = { enum: "color" };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { inject, readonly, ref } from "vue";
|
|
1
|
+
import { inject, onBeforeUnmount, readonly, ref } from "vue";
|
|
2
2
|
|
|
3
3
|
import type { Ref } from "vue";
|
|
4
4
|
|
|
@@ -7,38 +7,14 @@ import { getRequestWithoutQuery } from "./utilLoaderProgress.ts";
|
|
|
7
7
|
export const LoaderProgressSymbol = Symbol.for("vueless:loader-progress");
|
|
8
8
|
|
|
9
9
|
type LoaderProgress = {
|
|
10
|
-
isLoading: Ref<boolean>;
|
|
11
10
|
requestQueue: Readonly<Ref<readonly string[]>>;
|
|
12
11
|
loaderProgressOn: (url: string | string[]) => void;
|
|
13
12
|
loaderProgressOff: (url: string | string[]) => void;
|
|
14
|
-
addRequestUrl: (url: string | string[]) => void;
|
|
15
|
-
removeRequestUrl: (url: string | string[]) => void;
|
|
16
13
|
};
|
|
17
14
|
|
|
18
|
-
const isLoading = ref(false);
|
|
19
15
|
const requestQueue = ref<string[]>([]);
|
|
20
|
-
const requestTimeout = ref<number | undefined>(undefined);
|
|
21
16
|
|
|
22
17
|
function loaderProgressOn(url: string | string[]): void {
|
|
23
|
-
addRequestUrl(url);
|
|
24
|
-
isLoading.value = true;
|
|
25
|
-
|
|
26
|
-
if (requestTimeout.value !== undefined) {
|
|
27
|
-
clearTimeout(requestTimeout.value);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function loaderProgressOff(url: string | string[]): void {
|
|
32
|
-
removeRequestUrl(url);
|
|
33
|
-
|
|
34
|
-
requestTimeout.value = window.setTimeout(() => {
|
|
35
|
-
if (!requestQueue.value.length) {
|
|
36
|
-
isLoading.value = false;
|
|
37
|
-
}
|
|
38
|
-
}, 50);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function addRequestUrl(url: string | string[]): void {
|
|
42
18
|
if (Array.isArray(url)) {
|
|
43
19
|
requestQueue.value.push(...url.map(getRequestWithoutQuery));
|
|
44
20
|
} else {
|
|
@@ -46,28 +22,41 @@ function addRequestUrl(url: string | string[]): void {
|
|
|
46
22
|
}
|
|
47
23
|
}
|
|
48
24
|
|
|
49
|
-
function
|
|
25
|
+
function loaderProgressOff(url: string | string[]): void {
|
|
50
26
|
if (Array.isArray(url)) {
|
|
51
|
-
url.map(getRequestWithoutQuery).forEach(
|
|
27
|
+
url.map(getRequestWithoutQuery).forEach(loaderProgressOff);
|
|
52
28
|
} else {
|
|
53
29
|
requestQueue.value = requestQueue.value.filter((item) => item !== getRequestWithoutQuery(url));
|
|
54
30
|
}
|
|
55
31
|
}
|
|
56
32
|
|
|
33
|
+
function setLoaderOnHandler(event: CustomEvent<{ resource: string }>) {
|
|
34
|
+
loaderProgressOn(event.detail.resource);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function setLoaderOffHandler(event: CustomEvent<{ resource: string }>) {
|
|
38
|
+
loaderProgressOff(event.detail.resource);
|
|
39
|
+
}
|
|
40
|
+
|
|
57
41
|
export function createLoaderProgress(): LoaderProgress {
|
|
58
42
|
return {
|
|
59
|
-
isLoading,
|
|
60
43
|
requestQueue: readonly(requestQueue),
|
|
61
44
|
loaderProgressOn,
|
|
62
45
|
loaderProgressOff,
|
|
63
|
-
addRequestUrl,
|
|
64
|
-
removeRequestUrl,
|
|
65
46
|
};
|
|
66
47
|
}
|
|
67
48
|
|
|
68
49
|
export function useLoaderProgress(): LoaderProgress {
|
|
69
50
|
const loaderProgress = inject<LoaderProgress>(LoaderProgressSymbol);
|
|
70
51
|
|
|
52
|
+
window.addEventListener("loaderProgressOn", setLoaderOnHandler as EventListener);
|
|
53
|
+
window.addEventListener("loaderProgressOff", setLoaderOffHandler as EventListener);
|
|
54
|
+
|
|
55
|
+
onBeforeUnmount(() => {
|
|
56
|
+
window.removeEventListener("loaderProgressOn", setLoaderOnHandler as EventListener);
|
|
57
|
+
window.removeEventListener("loaderProgressOff", setLoaderOffHandler as EventListener);
|
|
58
|
+
});
|
|
59
|
+
|
|
71
60
|
if (!loaderProgress) {
|
|
72
61
|
throw new Error(
|
|
73
62
|
"LoaderProgress not provided. Ensure you are using `provide` with `LoaderProgressSymbol`.",
|