vueless 1.3.7-beta.1 → 1.3.7-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components.d.ts +1 -0
- package/components.ts +1 -0
- package/constants.d.ts +2 -0
- package/constants.js +2 -0
- package/package.json +2 -2
- package/ui.container-col/UCol.vue +0 -1
- package/ui.container-collapsible/UCollapsible.vue +190 -0
- package/ui.container-collapsible/config.ts +45 -0
- package/ui.container-collapsible/constants.ts +1 -0
- package/ui.container-collapsible/storybook/docs.mdx +17 -0
- package/ui.container-collapsible/storybook/stories.ts +261 -0
- package/ui.container-collapsible/tests/UCollapsible.test.ts +571 -0
- package/ui.container-collapsible/types.ts +57 -0
- package/ui.dropdown/UDropdown.vue +324 -0
- package/ui.dropdown/config.ts +27 -0
- package/ui.dropdown/constants.ts +1 -0
- package/ui.dropdown/storybook/docs.mdx +17 -0
- package/ui.dropdown/storybook/stories.ts +286 -0
- package/ui.dropdown/tests/UDropdown.test.ts +631 -0
- package/ui.dropdown/types.ts +127 -0
- package/ui.dropdown-badge/UDropdownBadge.vue +119 -227
- package/ui.dropdown-badge/config.ts +18 -15
- package/ui.dropdown-badge/tests/UDropdownBadge.test.ts +201 -67
- package/ui.dropdown-button/UDropdownButton.vue +121 -226
- package/ui.dropdown-button/config.ts +32 -28
- package/ui.dropdown-button/tests/UDropdownButton.test.ts +189 -73
- package/ui.dropdown-link/UDropdownLink.vue +123 -233
- package/ui.dropdown-link/config.ts +15 -18
- package/ui.dropdown-link/tests/UDropdownLink.test.ts +190 -71
- package/ui.form-listbox/UListbox.vue +2 -3
- package/ui.form-listbox/config.ts +2 -2
- package/ui.form-select/config.ts +1 -1
- package/utils/node/helper.js +6 -5
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import { isEqual } from "lodash-es";
|
|
2
|
+
import { computed, useTemplateRef } from "vue";
|
|
4
3
|
|
|
5
4
|
import { useUI } from "../composables/useUI";
|
|
6
5
|
import { getDefaults } from "../utils/ui";
|
|
7
6
|
|
|
8
7
|
import UIcon from "../ui.image-icon/UIcon.vue";
|
|
9
8
|
import UButton from "../ui.button/UButton.vue";
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
import vClickOutside from "../v.click-outside/vClickOutside";
|
|
9
|
+
import UDropdown from "../ui.dropdown/UDropdown.vue";
|
|
13
10
|
|
|
14
11
|
import defaultConfig from "./config";
|
|
15
12
|
import { COMPONENT_NAME } from "./constants";
|
|
16
13
|
|
|
17
14
|
import type { Props, Config } from "./types";
|
|
18
|
-
import type { Option, SelectedValue } from "../ui.form-listbox/types";
|
|
19
15
|
|
|
20
16
|
defineOptions({ inheritAttrs: false });
|
|
21
17
|
|
|
@@ -63,66 +59,9 @@ const emit = defineEmits([
|
|
|
63
59
|
"update:search",
|
|
64
60
|
]);
|
|
65
61
|
|
|
66
|
-
type
|
|
67
|
-
|
|
68
|
-
const isShownOptions = ref(false);
|
|
69
|
-
const isClickingOption = ref(false);
|
|
70
|
-
const listboxRef = useTemplateRef<UListboxRef>("dropdown-list");
|
|
71
|
-
const wrapperRef = useTemplateRef<HTMLDivElement>("wrapper");
|
|
72
|
-
|
|
73
|
-
const elementId = props.id || useId();
|
|
74
|
-
|
|
75
|
-
const dropdownValue = computed({
|
|
76
|
-
get: () => {
|
|
77
|
-
if (props.multiple && !Array.isArray(props.modelValue)) {
|
|
78
|
-
return props.modelValue ? [props.modelValue] : [];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return props.modelValue;
|
|
82
|
-
},
|
|
83
|
-
set: (value) => emit("update:modelValue", value),
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const dropdownSearch = computed({
|
|
87
|
-
get: () => props.search ?? "",
|
|
88
|
-
set: (value: string) => emit("update:search", value),
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
const selectedOptions = computed(() => {
|
|
92
|
-
if (props.multiple) {
|
|
93
|
-
return props.options.filter((option) => {
|
|
94
|
-
return (
|
|
95
|
-
option[props.valueKey] &&
|
|
96
|
-
(dropdownValue.value as SelectedValue[]).find((selected) =>
|
|
97
|
-
isEqual(selected, option[props.valueKey]),
|
|
98
|
-
)
|
|
99
|
-
);
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return [
|
|
104
|
-
props.options.find(
|
|
105
|
-
(option) => option[props.valueKey] && isEqual(option[props.valueKey], dropdownValue.value),
|
|
106
|
-
),
|
|
107
|
-
].filter((option) => !!option);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
const buttonLabel = computed(() => {
|
|
111
|
-
if (!props.labelDisplayCount || !selectedOptions.value.length) {
|
|
112
|
-
return props.label;
|
|
113
|
-
}
|
|
62
|
+
type UDropdownRef = InstanceType<typeof UDropdown>;
|
|
114
63
|
|
|
115
|
-
|
|
116
|
-
.slice(0, props.labelDisplayCount)
|
|
117
|
-
.map((option) => option[props.labelKey]);
|
|
118
|
-
const restLabelCount = selectedOptions.value.length - props.labelDisplayCount;
|
|
119
|
-
|
|
120
|
-
if (restLabelCount > 0) {
|
|
121
|
-
selectedLabels.push(`+${restLabelCount}`);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return selectedLabels.join(", ");
|
|
125
|
-
});
|
|
64
|
+
const dropdownRef = useTemplateRef<UDropdownRef>("dropdown");
|
|
126
65
|
|
|
127
66
|
const toggleIconName = computed(() => {
|
|
128
67
|
if (typeof props.toggleIcon === "string") {
|
|
@@ -132,55 +71,8 @@ const toggleIconName = computed(() => {
|
|
|
132
71
|
return props.toggleIcon ? config.value.defaults.toggleIcon : "";
|
|
133
72
|
});
|
|
134
73
|
|
|
135
|
-
function
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function getFullOptionLabels(value: Option | Option[]) {
|
|
140
|
-
const labelKey = props.labelKey;
|
|
141
|
-
|
|
142
|
-
if (Array.isArray(value)) {
|
|
143
|
-
return value.map((item) => item[labelKey]).join(", ");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return "";
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function onClickOption(option: Option) {
|
|
150
|
-
isClickingOption.value = true;
|
|
151
|
-
|
|
152
|
-
emit("clickOption", option);
|
|
153
|
-
|
|
154
|
-
if (!props.multiple && props.closeOnSelect) hideOptions();
|
|
155
|
-
|
|
156
|
-
nextTick(() => {
|
|
157
|
-
setTimeout(() => {
|
|
158
|
-
isClickingOption.value = false;
|
|
159
|
-
}, 10);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function handleClickOutside() {
|
|
164
|
-
if (isClickingOption.value) return;
|
|
165
|
-
|
|
166
|
-
hideOptions();
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function onClickButton() {
|
|
170
|
-
isShownOptions.value = !isShownOptions.value;
|
|
171
|
-
|
|
172
|
-
if (isShownOptions.value) {
|
|
173
|
-
nextTick(() => listboxRef.value?.wrapperRef?.focus());
|
|
174
|
-
|
|
175
|
-
emit("open");
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function hideOptions() {
|
|
180
|
-
isShownOptions.value = false;
|
|
181
|
-
dropdownSearch.value = "";
|
|
182
|
-
|
|
183
|
-
emit("close");
|
|
74
|
+
function hide() {
|
|
75
|
+
dropdownRef.value?.hide();
|
|
184
76
|
}
|
|
185
77
|
|
|
186
78
|
defineExpose({
|
|
@@ -188,136 +80,139 @@ defineExpose({
|
|
|
188
80
|
* A reference to the component's wrapper element for direct DOM manipulation.
|
|
189
81
|
* @property {HTMLDivElement}
|
|
190
82
|
*/
|
|
191
|
-
wrapperRef,
|
|
83
|
+
wrapperRef: computed(() => dropdownRef.value?.wrapperRef),
|
|
192
84
|
|
|
193
85
|
/**
|
|
194
|
-
* Hides the dropdown
|
|
86
|
+
* Hides the dropdown.
|
|
195
87
|
* @property {function}
|
|
196
88
|
*/
|
|
197
|
-
|
|
89
|
+
hide,
|
|
198
90
|
});
|
|
199
91
|
|
|
200
|
-
|
|
201
|
-
* Get element / nested component attributes for each config token ✨
|
|
92
|
+
/*
|
|
93
|
+
* Vueless: Get element / nested component attributes for each config token ✨
|
|
202
94
|
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
|
|
203
95
|
*/
|
|
204
96
|
const mutatedProps = computed(() => ({
|
|
205
97
|
/* component state, not a props */
|
|
206
|
-
opened:
|
|
98
|
+
opened: dropdownRef.value?.isOpened ?? false,
|
|
207
99
|
}));
|
|
208
100
|
|
|
209
|
-
const { getDataTest, config,
|
|
210
|
-
useUI<Config>(defaultConfig, mutatedProps, "
|
|
101
|
+
const { getDataTest, config, toggleButtonAttrs, dropdownButtonAttrs, toggleIconAttrs } =
|
|
102
|
+
useUI<Config>(defaultConfig, mutatedProps, "toggleButton");
|
|
211
103
|
</script>
|
|
212
104
|
|
|
213
105
|
<template>
|
|
214
|
-
<
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
:
|
|
106
|
+
<UDropdown
|
|
107
|
+
:id="id"
|
|
108
|
+
ref="dropdown"
|
|
109
|
+
:model-value="modelValue"
|
|
110
|
+
:label="label"
|
|
111
|
+
:label-display-count="labelDisplayCount"
|
|
112
|
+
:search="search"
|
|
113
|
+
:y-position="yPosition"
|
|
114
|
+
:x-position="xPosition"
|
|
115
|
+
:disabled="disabled"
|
|
116
|
+
:options="options"
|
|
117
|
+
:options-limit="optionsLimit"
|
|
118
|
+
:visible-options="visibleOptions"
|
|
119
|
+
:label-key="labelKey"
|
|
120
|
+
:value-key="valueKey"
|
|
121
|
+
:group-label-key="groupLabelKey"
|
|
122
|
+
:group-value-key="groupValueKey"
|
|
123
|
+
:searchable="searchable"
|
|
124
|
+
:multiple="multiple"
|
|
125
|
+
:color="color"
|
|
126
|
+
:close-on-select="closeOnSelect"
|
|
127
|
+
v-bind="dropdownButtonAttrs"
|
|
128
|
+
:data-test="dataTest"
|
|
129
|
+
@click-option="(option) => emit('clickOption', option)"
|
|
130
|
+
@update:model-value="(value) => emit('update:modelValue', value)"
|
|
131
|
+
@update:search="(value) => emit('update:search', value)"
|
|
132
|
+
@search-change="(query) => emit('searchChange', query)"
|
|
133
|
+
@open="emit('open')"
|
|
134
|
+
@close="emit('close')"
|
|
219
135
|
>
|
|
220
|
-
<
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
-->
|
|
240
|
-
<slot name="left" :opened="isShownOptions" />
|
|
241
|
-
</template>
|
|
242
|
-
|
|
243
|
-
<template #default>
|
|
244
|
-
<!--
|
|
245
|
-
@slot Use it to add something instead of the default label.
|
|
246
|
-
@binding {string} label
|
|
247
|
-
@binding {boolean} opened
|
|
248
|
-
-->
|
|
249
|
-
<slot :label="buttonLabel" :opened="isShownOptions" />
|
|
250
|
-
</template>
|
|
251
|
-
|
|
252
|
-
<template #right>
|
|
253
|
-
<!--
|
|
254
|
-
@slot Use it to add something instead of the toggle icon.
|
|
255
|
-
@binding {boolean} opened
|
|
256
|
-
-->
|
|
257
|
-
<slot name="toggle" :opened="isShownOptions">
|
|
258
|
-
<UIcon
|
|
259
|
-
v-if="toggleIconName"
|
|
260
|
-
color="inherit"
|
|
261
|
-
:name="toggleIconName"
|
|
262
|
-
v-bind="toggleIconAttrs"
|
|
263
|
-
:data-test="getDataTest('dropdown')"
|
|
264
|
-
/>
|
|
265
|
-
</slot>
|
|
266
|
-
</template>
|
|
267
|
-
</UButton>
|
|
268
|
-
|
|
269
|
-
<UListbox
|
|
270
|
-
v-if="isShownOptions"
|
|
271
|
-
ref="dropdown-list"
|
|
272
|
-
v-model="dropdownValue"
|
|
273
|
-
v-model:search="dropdownSearch"
|
|
274
|
-
:searchable="searchable"
|
|
275
|
-
:multiple="multiple"
|
|
276
|
-
:color="color"
|
|
277
|
-
:options="options"
|
|
278
|
-
:options-limit="optionsLimit"
|
|
279
|
-
:visible-options="visibleOptions"
|
|
280
|
-
:label-key="labelKey"
|
|
281
|
-
:value-key="valueKey"
|
|
282
|
-
:group-label-key="groupLabelKey"
|
|
283
|
-
:group-value-key="groupValueKey"
|
|
284
|
-
v-bind="listboxAttrs"
|
|
285
|
-
:data-test="getDataTest('list')"
|
|
286
|
-
@click-option="onClickOption"
|
|
287
|
-
@search-change="onSearchChange"
|
|
288
|
-
@update:search="(value) => emit('update:search', value)"
|
|
289
|
-
>
|
|
290
|
-
<template #before-option="{ option, index }">
|
|
291
|
-
<!--
|
|
292
|
-
@slot Use it to add something before option.
|
|
293
|
-
@binding {object} option
|
|
294
|
-
@binding {number} index
|
|
136
|
+
<template #default="{ opened, displayLabel, fullLabel }">
|
|
137
|
+
<UButton
|
|
138
|
+
:label="displayLabel"
|
|
139
|
+
:size="size"
|
|
140
|
+
:color="color"
|
|
141
|
+
:block="block"
|
|
142
|
+
:round="round"
|
|
143
|
+
:square="square"
|
|
144
|
+
:variant="variant"
|
|
145
|
+
:disabled="disabled"
|
|
146
|
+
:title="fullLabel"
|
|
147
|
+
v-bind="toggleButtonAttrs"
|
|
148
|
+
tabindex="-1"
|
|
149
|
+
:data-test="getDataTest()"
|
|
150
|
+
>
|
|
151
|
+
<template #left>
|
|
152
|
+
<!--
|
|
153
|
+
@slot Use it to add something before the label.
|
|
154
|
+
@binding {boolean} opened
|
|
295
155
|
-->
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
@slot Use it to
|
|
302
|
-
@binding {
|
|
303
|
-
@binding {
|
|
156
|
+
<slot name="left" :opened="opened" />
|
|
157
|
+
</template>
|
|
158
|
+
|
|
159
|
+
<template #default>
|
|
160
|
+
<!--
|
|
161
|
+
@slot Use it to add something instead of the default label.
|
|
162
|
+
@binding {string} label
|
|
163
|
+
@binding {boolean} opened
|
|
304
164
|
-->
|
|
305
|
-
|
|
306
|
-
|
|
165
|
+
<slot :label="displayLabel" :opened="opened" />
|
|
166
|
+
</template>
|
|
307
167
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
@slot Use it to add something
|
|
311
|
-
@binding {
|
|
312
|
-
@binding {number} index
|
|
168
|
+
<template #right>
|
|
169
|
+
<!--
|
|
170
|
+
@slot Use it to add something instead of the toggle icon.
|
|
171
|
+
@binding {boolean} opened
|
|
313
172
|
-->
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
173
|
+
<slot name="toggle" :opened="opened">
|
|
174
|
+
<UIcon
|
|
175
|
+
v-if="toggleIconName"
|
|
176
|
+
color="inherit"
|
|
177
|
+
:name="toggleIconName"
|
|
178
|
+
v-bind="toggleIconAttrs"
|
|
179
|
+
:data-test="getDataTest('dropdown')"
|
|
180
|
+
/>
|
|
181
|
+
</slot>
|
|
182
|
+
</template>
|
|
183
|
+
</UButton>
|
|
184
|
+
</template>
|
|
185
|
+
|
|
186
|
+
<template #before-option="{ option, index }">
|
|
187
|
+
<!--
|
|
188
|
+
@slot Use it to add something before option.
|
|
189
|
+
@binding {object} option
|
|
190
|
+
@binding {number} index
|
|
191
|
+
-->
|
|
192
|
+
<slot name="before-option" :option="option" :index="index" />
|
|
193
|
+
</template>
|
|
194
|
+
|
|
195
|
+
<template #option="{ option, index }">
|
|
196
|
+
<!--
|
|
197
|
+
@slot Use it to customize the option.
|
|
198
|
+
@binding {object} option
|
|
199
|
+
@binding {number} index
|
|
200
|
+
-->
|
|
201
|
+
<slot name="option" :option="option" :index="index" />
|
|
202
|
+
</template>
|
|
203
|
+
|
|
204
|
+
<template #after-option="{ option, index }">
|
|
205
|
+
<!--
|
|
206
|
+
@slot Use it to add something after option.
|
|
207
|
+
@binding {object} option
|
|
208
|
+
@binding {number} index
|
|
209
|
+
-->
|
|
210
|
+
<slot name="after-option" :option="option" :index="index" />
|
|
211
|
+
</template>
|
|
212
|
+
|
|
213
|
+
<template #empty>
|
|
214
|
+
<!-- @slot Use it to add something instead of empty state. -->
|
|
215
|
+
<slot name="empty" />
|
|
216
|
+
</template>
|
|
217
|
+
</UDropdown>
|
|
323
218
|
</template>
|
|
@@ -1,49 +1,53 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
|
-
|
|
3
|
-
base: "
|
|
2
|
+
dropdownButton: {
|
|
3
|
+
base: "{UDropdown}",
|
|
4
4
|
variants: {
|
|
5
5
|
block: {
|
|
6
|
-
true: "w-full",
|
|
6
|
+
true: "!block w-full",
|
|
7
7
|
},
|
|
8
8
|
},
|
|
9
|
-
},
|
|
10
|
-
dropdownButton: "{UButton} justify-between",
|
|
11
|
-
toggleIcon: {
|
|
12
|
-
base: "{UIcon} transition duration-300 -mr-1",
|
|
13
9
|
defaults: {
|
|
14
10
|
size: {
|
|
15
|
-
"2xs": "
|
|
16
|
-
xs: "
|
|
17
|
-
sm: "
|
|
18
|
-
md: "
|
|
19
|
-
lg: "
|
|
20
|
-
xl: "
|
|
11
|
+
"2xs": "sm",
|
|
12
|
+
xs: "sm",
|
|
13
|
+
sm: "md",
|
|
14
|
+
md: "md",
|
|
15
|
+
lg: "lg",
|
|
16
|
+
xl: "lg",
|
|
21
17
|
},
|
|
22
18
|
},
|
|
23
|
-
compoundVariants: [{ opened: true, class: "rotate-180" }],
|
|
24
19
|
},
|
|
25
|
-
|
|
26
|
-
base: "{
|
|
20
|
+
toggleButton: {
|
|
21
|
+
base: "{UButton} justify-between",
|
|
27
22
|
variants: {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
bottom: "top-full mt-1.5",
|
|
23
|
+
block: {
|
|
24
|
+
true: "w-full",
|
|
31
25
|
},
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
toggleIcon: {
|
|
29
|
+
base: "{UIcon} transition duration-300",
|
|
30
|
+
variants: {
|
|
31
|
+
size: {
|
|
32
|
+
"2xs": "-ml-0.5 -mr-1",
|
|
33
|
+
xs: "-ml-1 -mr-1",
|
|
34
|
+
sm: "-ml-1 -mr-1.5",
|
|
35
|
+
md: "-ml-1 -mr-2",
|
|
36
|
+
lg: "-ml-1.5 -mr-2.5",
|
|
37
|
+
xl: "-ml-1.5 -mr-2.5",
|
|
35
38
|
},
|
|
36
39
|
},
|
|
37
40
|
defaults: {
|
|
38
41
|
size: {
|
|
39
|
-
"2xs": "
|
|
40
|
-
xs: "
|
|
41
|
-
sm: "
|
|
42
|
-
md: "
|
|
43
|
-
lg: "
|
|
44
|
-
xl: "
|
|
42
|
+
"2xs": "2xs",
|
|
43
|
+
xs: "xs",
|
|
44
|
+
sm: "sm",
|
|
45
|
+
md: "sm",
|
|
46
|
+
lg: "md",
|
|
47
|
+
xl: "md",
|
|
45
48
|
},
|
|
46
49
|
},
|
|
50
|
+
compoundVariants: [{ opened: true, class: "rotate-180" }],
|
|
47
51
|
},
|
|
48
52
|
defaults: {
|
|
49
53
|
color: "primary",
|