vueless 0.0.710 → 0.0.712
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/constants.js +3 -1
- package/package.json +1 -1
- package/preset-tailwind.js +12 -5
- package/types.ts +14 -2
- package/ui.dropdown-list/storybook/docs.mdx +1 -1
- package/ui.form-input/config.ts +1 -1
- package/ui.form-input-file/config.ts +1 -1
- package/ui.form-select/USelect.vue +7 -0
- package/ui.form-select/config.ts +2 -4
- package/ui.form-select/storybook/docs.mdx +3 -0
- package/ui.form-select/storybook/stories.ts +255 -106
- package/ui.form-select/types.ts +1 -1
- package/ui.form-textarea/config.ts +1 -1
- package/utils/theme.ts +34 -4
package/constants.js
CHANGED
|
@@ -18,6 +18,8 @@ export const COLOR_MODE_KEY = "vl-color-mode";
|
|
|
18
18
|
export const DEFAULT_BRAND_COLOR = GRAYSCALE_COLOR;
|
|
19
19
|
export const DEFAULT_GRAY_COLOR = COOL_COLOR;
|
|
20
20
|
export const DEFAULT_RING = 2; /* pixels */
|
|
21
|
+
export const RING_DECREMENT = 1; /* pixels */
|
|
22
|
+
export const RING_INCREMENT = 1; /* pixels */
|
|
21
23
|
export const DEFAULT_RING_OFFSET_COLOR_LIGHT = "#ffffff"; // white
|
|
22
24
|
export const DEFAULT_RING_OFFSET_COLOR_DARK = "#111827"; // gray-900
|
|
23
25
|
export const DEFAULT_ROUNDING = 8; /* pixels */
|
|
@@ -171,7 +173,7 @@ export const TAILWIND_MERGE_EXTENSION = {
|
|
|
171
173
|
spacing: ["safe-top", "safe-bottom", "safe-left", "safe-right"],
|
|
172
174
|
},
|
|
173
175
|
classGroups: {
|
|
174
|
-
"ring-w": [{ ring: ["dynamic", "dynamic-
|
|
176
|
+
"ring-w": [{ ring: ["dynamic", "dynamic-sm", "dynamic-lg"] }],
|
|
175
177
|
"ring-offset-color": [{ "ring-offset": ["color-dynamic"] }],
|
|
176
178
|
"font-size": [{ text: ["2xs"] }],
|
|
177
179
|
rounded: [{ rounded: ["dynamic", "dynamic-sm", "dynamic-lg", "inherit"] }],
|
package/package.json
CHANGED
package/preset-tailwind.js
CHANGED
|
@@ -17,6 +17,10 @@ import {
|
|
|
17
17
|
DEFAULT_BRAND_COLOR,
|
|
18
18
|
DEFAULT_GRAY_COLOR,
|
|
19
19
|
GRAYSCALE_COLOR,
|
|
20
|
+
ROUNDING_DECREMENT,
|
|
21
|
+
ROUNDING_INCREMENT,
|
|
22
|
+
RING_INCREMENT,
|
|
23
|
+
RING_DECREMENT,
|
|
20
24
|
} from "./constants.js";
|
|
21
25
|
|
|
22
26
|
const globalSettings = process.env.VUELESS_GLOBAL_SETTINGS || {};
|
|
@@ -92,8 +96,9 @@ export const vuelessTailwindConfig = {
|
|
|
92
96
|
"dynamic-lg": "var(--vl-rounding-lg)",
|
|
93
97
|
},
|
|
94
98
|
ringWidth: {
|
|
99
|
+
"dynamic-sm": "var(--vl-ring-sm)",
|
|
95
100
|
dynamic: "var(--vl-ring)",
|
|
96
|
-
"dynamic-
|
|
101
|
+
"dynamic-lg": "var(--vl-ring-lg)",
|
|
97
102
|
},
|
|
98
103
|
ringOffsetColor: {
|
|
99
104
|
dynamic: twColorWithOpacity("--vl-ring-offset-color"),
|
|
@@ -101,15 +106,17 @@ export const vuelessTailwindConfig = {
|
|
|
101
106
|
},
|
|
102
107
|
configViewer: {
|
|
103
108
|
themeReplacements: {
|
|
104
|
-
/* eslint-disable prettier/prettier */
|
|
109
|
+
/* eslint-disable prettier/prettier, vue/max-len */
|
|
110
|
+
"var(--vl-ring-sm)": globalSettings.ringSm || Math.max(0, (globalSettings.ring || DEFAULT_RING) - RING_DECREMENT),
|
|
105
111
|
"var(--vl-ring)": globalSettings.ring || DEFAULT_RING,
|
|
112
|
+
"var(--vl-ring-lg)": globalSettings.ringLg || Math.max(0, (globalSettings.ring || DEFAULT_RING) + RING_INCREMENT),
|
|
106
113
|
"var(--vl-ring-offset-color)": globalSettings.ringOffsetColorLight || DEFAULT_RING_OFFSET_COLOR_LIGHT,
|
|
107
|
-
"var(--vl-rounding-sm)": globalSettings.roundingSm || (globalSettings.
|
|
114
|
+
"var(--vl-rounding-sm)": globalSettings.roundingSm || Math.max(0, (globalSettings.rounding || DEFAULT_ROUNDING) - ROUNDING_DECREMENT),
|
|
108
115
|
"var(--vl-rounding)": globalSettings.ring || DEFAULT_ROUNDING,
|
|
109
|
-
"var(--vl-rounding-lg)": globalSettings.roundingLg || (globalSettings.
|
|
116
|
+
"var(--vl-rounding-lg)": globalSettings.roundingLg || Math.max(0, (globalSettings.rounding || DEFAULT_ROUNDING) - ROUNDING_INCREMENT),
|
|
110
117
|
...getReplacementColors(GRAY_COLOR, globalSettings.gray || DEFAULT_GRAY_COLOR),
|
|
111
118
|
...getReplacementColors(BRAND_COLOR, globalSettings.brand || DEFAULT_BRAND_COLOR),
|
|
112
|
-
/* eslint-enable prettier/prettier */
|
|
119
|
+
/* eslint-enable prettier/prettier, vue/max-len */
|
|
113
120
|
},
|
|
114
121
|
},
|
|
115
122
|
},
|
package/types.ts
CHANGED
|
@@ -81,7 +81,7 @@ export interface ThemeConfig {
|
|
|
81
81
|
gray?: GrayColors;
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* Default components
|
|
84
|
+
* Default components small size rounding (border-radius).
|
|
85
85
|
*/
|
|
86
86
|
roundingSm?: number;
|
|
87
87
|
|
|
@@ -91,15 +91,25 @@ export interface ThemeConfig {
|
|
|
91
91
|
rounding?: number;
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Default components
|
|
94
|
+
* Default components large size rounding (border-radius).
|
|
95
95
|
*/
|
|
96
96
|
roundingLg?: number;
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Default components small size ring width.
|
|
100
|
+
*/
|
|
101
|
+
ringSm?: number;
|
|
102
|
+
|
|
98
103
|
/**
|
|
99
104
|
* Default components ring width.
|
|
100
105
|
*/
|
|
101
106
|
ring?: number;
|
|
102
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Default components large size ring width.
|
|
110
|
+
*/
|
|
111
|
+
ringLg?: number;
|
|
112
|
+
|
|
103
113
|
/**
|
|
104
114
|
* Default components ring color for light theme.
|
|
105
115
|
*/
|
|
@@ -339,7 +349,9 @@ export interface TailwindColorShades {
|
|
|
339
349
|
}
|
|
340
350
|
|
|
341
351
|
export interface VuelessCssVariables {
|
|
352
|
+
"--vl-ring-sm": string;
|
|
342
353
|
"--vl-ring": string;
|
|
354
|
+
"--vl-ring-lg": string;
|
|
343
355
|
"--vl-ring-offset-color": string;
|
|
344
356
|
"--vl-rounding-sm": string;
|
|
345
357
|
"--vl-rounding": string;
|
package/ui.form-input/config.ts
CHANGED
|
@@ -4,7 +4,7 @@ export default /*tw*/ {
|
|
|
4
4
|
base: `
|
|
5
5
|
border rounded-dynamic border-gray-300 relative flex w-full bg-white transition
|
|
6
6
|
hover:border-gray-400 hover:focus-within:border-brand-600 focus-within:border-brand-600
|
|
7
|
-
focus-within:ring-dynamic-
|
|
7
|
+
focus-within:ring-dynamic-sm focus-within:ring-brand-600
|
|
8
8
|
`,
|
|
9
9
|
variants: {
|
|
10
10
|
error: {
|
|
@@ -5,7 +5,7 @@ export default /*tw*/ {
|
|
|
5
5
|
p-3 size-auto w-full bg-white transition
|
|
6
6
|
rounded-dynamic border border-solid border-gray-300
|
|
7
7
|
hover:border-gray-400 hover:focus-within:border-brand-600 focus-within:border-brand-600
|
|
8
|
-
focus-within:ring-brand-600 focus-within:ring-dynamic-
|
|
8
|
+
focus-within:ring-brand-600 focus-within:ring-dynamic-sm
|
|
9
9
|
`,
|
|
10
10
|
variants: {
|
|
11
11
|
error: {
|
|
@@ -10,6 +10,7 @@ import useUI from "../composables/useUI.ts";
|
|
|
10
10
|
import { createDebounce, hasSlotContent } from "../utils/helper.ts";
|
|
11
11
|
import { getDefaults } from "../utils/ui.ts";
|
|
12
12
|
import { isMac } from "../utils/platform.ts";
|
|
13
|
+
import { useMutationObserver } from "../composables/useMutationObserver.ts";
|
|
13
14
|
|
|
14
15
|
import {
|
|
15
16
|
filterOptions,
|
|
@@ -334,6 +335,12 @@ function onMouseDownClear() {
|
|
|
334
335
|
emit("remove", props.options);
|
|
335
336
|
}
|
|
336
337
|
|
|
338
|
+
useMutationObserver(leftSlotWrapperRef, (mutations) => mutations.forEach(setLabelPosition), {
|
|
339
|
+
childList: true,
|
|
340
|
+
characterData: true,
|
|
341
|
+
subtree: true,
|
|
342
|
+
});
|
|
343
|
+
|
|
337
344
|
function setLabelPosition() {
|
|
338
345
|
if (props.labelAlign === "top" || (!hasSlotContent(slots["left"]) && !props.leftIcon)) {
|
|
339
346
|
return;
|
package/ui.form-select/config.ts
CHANGED
|
@@ -5,7 +5,7 @@ export default /*tw*/ {
|
|
|
5
5
|
flex flex-row-reverse justify-between w-full min-h-full box-border relative
|
|
6
6
|
rounded-dynamic border border-gray-300 bg-white
|
|
7
7
|
hover:border-gray-400 hover:transition hover:focus-within:border-brand-600
|
|
8
|
-
focus-within:ring-brand-600 focus-within:ring-dynamic-
|
|
8
|
+
focus-within:ring-brand-600 focus-within:ring-dynamic-sm
|
|
9
9
|
focus-within:border-brand-600 focus-within:outline-none
|
|
10
10
|
`,
|
|
11
11
|
variants: {
|
|
@@ -114,10 +114,8 @@ export default /*tw*/ {
|
|
|
114
114
|
selected: {
|
|
115
115
|
false: "w-full",
|
|
116
116
|
},
|
|
117
|
-
opened: {
|
|
118
|
-
true: "w-full",
|
|
119
|
-
},
|
|
120
117
|
},
|
|
118
|
+
compoundVariants: [{ opened: true, searchable: false, class: "w-0" }],
|
|
121
119
|
},
|
|
122
120
|
searchInput: {
|
|
123
121
|
base: `
|
|
@@ -12,5 +12,8 @@ import defaultConfig from "../config.ts?raw"
|
|
|
12
12
|
<Controls of={stories.Default} />
|
|
13
13
|
<Stories of={stories} />
|
|
14
14
|
|
|
15
|
+
## Option meta keys
|
|
16
|
+
Full list of keys you may/have to provide to component in an option object can be found here: [UDropdownList docs](https://ui.vueless.com/?path=/docs/2050--docs).
|
|
17
|
+
|
|
15
18
|
## Default config
|
|
16
19
|
<Source code={getSource(defaultConfig)} language="jsx" dark />
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ref, computed } from "vue";
|
|
1
2
|
import {
|
|
2
3
|
getArgTypes,
|
|
3
4
|
getSlotNames,
|
|
@@ -7,16 +8,18 @@ import {
|
|
|
7
8
|
|
|
8
9
|
import USelect from "../../ui.form-select/USelect.vue";
|
|
9
10
|
import URow from "../../ui.container-row/URow.vue";
|
|
11
|
+
import UCol from "../../ui.container-col/UCol.vue";
|
|
10
12
|
import UBadge from "../../ui.text-badge/UBadge.vue";
|
|
11
13
|
import UIcon from "../../ui.image-icon/UIcon.vue";
|
|
12
14
|
import ULink from "../../ui.button-link/ULink.vue";
|
|
15
|
+
import UAvatar from "../../ui.image-avatar/UAvatar.vue";
|
|
13
16
|
|
|
14
17
|
import type { Meta, StoryFn } from "@storybook/vue3";
|
|
15
18
|
import type { Props } from "../types.ts";
|
|
16
19
|
|
|
17
20
|
interface USelectArgs extends Props {
|
|
18
21
|
slotTemplate?: string;
|
|
19
|
-
enum: "size" | "openDirection";
|
|
22
|
+
enum: "size" | "openDirection" | "labelAlign";
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
interface SelectOption {
|
|
@@ -30,13 +33,14 @@ export default {
|
|
|
30
33
|
title: "Form Inputs & Controls / Select",
|
|
31
34
|
component: USelect,
|
|
32
35
|
args: {
|
|
33
|
-
label: "
|
|
36
|
+
label: "Choose a city",
|
|
34
37
|
modelValue: null,
|
|
35
38
|
options: [
|
|
36
|
-
{
|
|
37
|
-
{
|
|
38
|
-
{
|
|
39
|
-
{
|
|
39
|
+
{ label: "New York", id: "1" },
|
|
40
|
+
{ label: "Los Angeles", id: "2" },
|
|
41
|
+
{ label: "Chicago", id: "3" },
|
|
42
|
+
{ label: "Houston", id: "4" },
|
|
43
|
+
{ label: "San Francisco", id: "5" },
|
|
40
44
|
],
|
|
41
45
|
},
|
|
42
46
|
argTypes: {
|
|
@@ -46,49 +50,63 @@ export default {
|
|
|
46
50
|
docs: {
|
|
47
51
|
...getDocsDescription(USelect.__name),
|
|
48
52
|
story: {
|
|
49
|
-
height: "
|
|
53
|
+
height: "300px",
|
|
50
54
|
},
|
|
51
55
|
},
|
|
52
56
|
},
|
|
53
57
|
} as Meta;
|
|
54
58
|
|
|
55
59
|
const DefaultTemplate: StoryFn<USelectArgs> = (args: USelectArgs) => ({
|
|
56
|
-
components: { USelect, UIcon, UBadge, ULink },
|
|
60
|
+
components: { USelect, UIcon, UBadge, ULink, UAvatar },
|
|
57
61
|
setup() {
|
|
58
62
|
function getSelectedBadge(options: SelectOption[], currentValue: string | number) {
|
|
59
63
|
return options?.find((option) => option.id === currentValue);
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
const slots = getSlotNames(USelect.__name);
|
|
67
|
+
const errorMessage = computed(() => (!args.modelValue ? args.error : ""));
|
|
68
|
+
const showAlert = (message: string) => alert(message);
|
|
63
69
|
|
|
64
|
-
return { args, slots, getSelectedBadge };
|
|
70
|
+
return { args, slots, getSelectedBadge, errorMessage, showAlert };
|
|
65
71
|
},
|
|
66
72
|
template: `
|
|
67
|
-
<USelect
|
|
73
|
+
<USelect
|
|
74
|
+
v-bind="args"
|
|
75
|
+
v-model="args.modelValue"
|
|
76
|
+
:error="errorMessage"
|
|
77
|
+
class="max-w-96"
|
|
78
|
+
@add="showAlert('You triggered the add action!')"
|
|
79
|
+
>
|
|
68
80
|
${args.slotTemplate || getSlotsFragment("")}
|
|
69
81
|
</USelect>
|
|
70
82
|
`,
|
|
71
83
|
});
|
|
72
84
|
|
|
73
85
|
const EnumVariantTemplate: StoryFn<USelectArgs> = (args: USelectArgs, { argTypes }) => ({
|
|
74
|
-
components: { USelect,
|
|
86
|
+
components: { USelect, UCol },
|
|
75
87
|
setup() {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
88
|
+
let filteredOptions = argTypes?.[args.enum]?.options;
|
|
89
|
+
|
|
90
|
+
if (args.enum === "labelAlign") {
|
|
91
|
+
filteredOptions = argTypes?.[args.enum]?.options?.filter(
|
|
92
|
+
(item) => item !== "right" && item !== "topWithDesc",
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { args, filteredOptions };
|
|
80
97
|
},
|
|
81
98
|
template: `
|
|
82
|
-
<
|
|
99
|
+
<UCol>
|
|
83
100
|
<USelect
|
|
84
|
-
v-for="(option, index) in
|
|
101
|
+
v-for="(option, index) in filteredOptions"
|
|
85
102
|
:key="index"
|
|
86
103
|
v-bind="args"
|
|
87
104
|
v-model="args.modelValue"
|
|
88
105
|
:[args.enum]="option"
|
|
89
|
-
:
|
|
106
|
+
:description="option"
|
|
107
|
+
class="max-w-96"
|
|
90
108
|
/>
|
|
91
|
-
</
|
|
109
|
+
</UCol>
|
|
92
110
|
`,
|
|
93
111
|
});
|
|
94
112
|
|
|
@@ -118,6 +136,24 @@ const GroupValuesTemplate: StoryFn<USelectArgs> = (args: USelectArgs) => ({
|
|
|
118
136
|
export const Default = DefaultTemplate.bind({});
|
|
119
137
|
Default.args = {};
|
|
120
138
|
|
|
139
|
+
export const Placeholder = DefaultTemplate.bind({});
|
|
140
|
+
Placeholder.args = { placeholder: "Start typing to search for a city..." };
|
|
141
|
+
|
|
142
|
+
export const Description = DefaultTemplate.bind({});
|
|
143
|
+
Description.args = { description: "You can only select a city from the list." };
|
|
144
|
+
|
|
145
|
+
export const Error = DefaultTemplate.bind({});
|
|
146
|
+
Error.args = { error: "Please select a city from the list" };
|
|
147
|
+
|
|
148
|
+
export const Disabled = DefaultTemplate.bind({});
|
|
149
|
+
Disabled.args = { disabled: true };
|
|
150
|
+
|
|
151
|
+
export const LabelPlacement = EnumVariantTemplate.bind({});
|
|
152
|
+
LabelPlacement.args = { enum: "labelAlign" };
|
|
153
|
+
|
|
154
|
+
export const Sizes = EnumVariantTemplate.bind({});
|
|
155
|
+
Sizes.args = { enum: "size", multiple: true, modelValue: [] };
|
|
156
|
+
|
|
121
157
|
export const LargeItemList = DefaultTemplate.bind({});
|
|
122
158
|
LargeItemList.args = {
|
|
123
159
|
options: [...new Array(1000)].map((_, index) => {
|
|
@@ -128,6 +164,18 @@ LargeItemList.args = {
|
|
|
128
164
|
export const Multiple = DefaultTemplate.bind({});
|
|
129
165
|
Multiple.args = { multiple: true, modelValue: [] };
|
|
130
166
|
|
|
167
|
+
export const ClearableAndSearchable = DefaultTemplate.bind({});
|
|
168
|
+
ClearableAndSearchable.args = { clearable: false, searchable: false };
|
|
169
|
+
ClearableAndSearchable.parameters = {
|
|
170
|
+
docs: {
|
|
171
|
+
description: {
|
|
172
|
+
story:
|
|
173
|
+
// eslint-disable-next-line vue/max-len
|
|
174
|
+
"The `clearable` and `searchable` props control whether users can clear the selected value or search within the list. <br/> In this example, both are set to `false`, meaning the selection cannot be cleared, and searching is disabled.",
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
131
179
|
export const OpenDirection = EnumVariantTemplate.bind({});
|
|
132
180
|
OpenDirection.args = { enum: "openDirection" };
|
|
133
181
|
|
|
@@ -159,36 +207,181 @@ GroupValue.args = {
|
|
|
159
207
|
],
|
|
160
208
|
};
|
|
161
209
|
|
|
162
|
-
export const Disabled = DefaultTemplate.bind({});
|
|
163
|
-
Disabled.args = { disabled: true };
|
|
164
|
-
|
|
165
|
-
export const Error = DefaultTemplate.bind({});
|
|
166
|
-
Error.args = { error: "some error text" };
|
|
167
|
-
|
|
168
|
-
export const Placeholder = DefaultTemplate.bind({});
|
|
169
|
-
Placeholder.args = { placeholder: "some placeholder text" };
|
|
170
|
-
|
|
171
|
-
export const Description = DefaultTemplate.bind({});
|
|
172
|
-
Description.args = { description: "some description text" };
|
|
173
|
-
|
|
174
210
|
export const OptionsLimit2 = DefaultTemplate.bind({});
|
|
175
211
|
OptionsLimit2.args = { optionsLimit: 2 };
|
|
212
|
+
OptionsLimit2.parameters = {
|
|
213
|
+
docs: {
|
|
214
|
+
description: {
|
|
215
|
+
story: "`optionsLimit` prop controls the number of options displayed in the dropdown.",
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export const VisibleOptions = DefaultTemplate.bind({});
|
|
221
|
+
VisibleOptions.args = { visibleOptions: 3 };
|
|
222
|
+
VisibleOptions.parameters = {
|
|
223
|
+
docs: {
|
|
224
|
+
description: {
|
|
225
|
+
story: "`visibleOptions` prop controls the number of options you can see without a scroll.",
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
};
|
|
176
229
|
|
|
177
230
|
export const AddOption = DefaultTemplate.bind({});
|
|
178
231
|
AddOption.args = { addOption: true };
|
|
232
|
+
AddOption.parameters = {
|
|
233
|
+
docs: {
|
|
234
|
+
description: {
|
|
235
|
+
story:
|
|
236
|
+
// eslint-disable-next-line vue/max-len
|
|
237
|
+
"The `addOption` prop displays an 'Add option' button, while the `add` event allows handling custom functionality when the button is clicked.",
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
};
|
|
179
241
|
|
|
180
|
-
export const
|
|
181
|
-
|
|
242
|
+
export const OptionSettings = DefaultTemplate.bind({});
|
|
243
|
+
OptionSettings.args = {
|
|
182
244
|
options: [
|
|
183
|
-
{
|
|
184
|
-
{
|
|
185
|
-
{
|
|
186
|
-
|
|
245
|
+
{ label: "1. New York", id: "1" },
|
|
246
|
+
{ label: "2. Los Angeles", id: "2", isHidden: true },
|
|
247
|
+
{
|
|
248
|
+
label: "3. Chicago",
|
|
249
|
+
id: "3",
|
|
250
|
+
onClick: (option) =>
|
|
251
|
+
alert("onClick function for the third option: " + JSON.stringify(option)),
|
|
252
|
+
},
|
|
253
|
+
{ label: "4. Houston", id: "4" },
|
|
254
|
+
{ label: "5. San Francisco", id: "5" },
|
|
187
255
|
],
|
|
188
256
|
};
|
|
257
|
+
OptionSettings.parameters = {
|
|
258
|
+
docs: {
|
|
259
|
+
description: {
|
|
260
|
+
story:
|
|
261
|
+
// eslint-disable-next-line vue/max-len
|
|
262
|
+
"The second option of the array is hidden (`isHidden` object property is set to `true`). <br/> The third option has `onClick` event handler: <br/> `onClick: (option: Option) => alert('onClick function for option 3: ' + JSON.stringify(option))`",
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
};
|
|
189
266
|
|
|
190
|
-
export const
|
|
191
|
-
|
|
267
|
+
export const IconProps: StoryFn<USelectArgs> = (args) => ({
|
|
268
|
+
components: { USelect, URow },
|
|
269
|
+
setup() {
|
|
270
|
+
const levelOptions = [
|
|
271
|
+
{ label: "Awesome", id: "1" },
|
|
272
|
+
{ label: "Good", id: "2" },
|
|
273
|
+
{ label: "Could be better", id: "3" },
|
|
274
|
+
{ label: "Terrible", id: "4" },
|
|
275
|
+
];
|
|
276
|
+
|
|
277
|
+
const roleOptions = [
|
|
278
|
+
{ label: "Admin", id: "1" },
|
|
279
|
+
{ label: "CEO", id: "2" },
|
|
280
|
+
{ label: "Manager", id: "3" },
|
|
281
|
+
{ label: "Guest", id: "4" },
|
|
282
|
+
];
|
|
283
|
+
|
|
284
|
+
return { args, levelOptions, roleOptions };
|
|
285
|
+
},
|
|
286
|
+
template: `
|
|
287
|
+
<URow no-mobile>
|
|
288
|
+
<USelect
|
|
289
|
+
left-icon="feedback"
|
|
290
|
+
label="Choose the level of our services"
|
|
291
|
+
placeholder="Share your feedback with us"
|
|
292
|
+
:options="levelOptions"
|
|
293
|
+
/>
|
|
294
|
+
<USelect
|
|
295
|
+
right-icon="person"
|
|
296
|
+
label="Select your role"
|
|
297
|
+
placeholder="Choose a role from the list"
|
|
298
|
+
:options="roleOptions"
|
|
299
|
+
/>
|
|
300
|
+
</URow>
|
|
301
|
+
`,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
export const Slots: StoryFn<USelectArgs> = (args) => ({
|
|
305
|
+
components: { USelect, UCol, URow, ULink, UBadge, UAvatar },
|
|
306
|
+
setup() {
|
|
307
|
+
const clearModel = ref(null);
|
|
308
|
+
const clearMultipleModel = ref([]);
|
|
309
|
+
const beforeToggleModel = ref(null);
|
|
310
|
+
const afterToggleModel = ref(null);
|
|
311
|
+
const leftModel = ref(null);
|
|
312
|
+
const rightModel = ref(null);
|
|
313
|
+
|
|
314
|
+
return {
|
|
315
|
+
args,
|
|
316
|
+
clearModel,
|
|
317
|
+
clearMultipleModel,
|
|
318
|
+
beforeToggleModel,
|
|
319
|
+
afterToggleModel,
|
|
320
|
+
leftModel,
|
|
321
|
+
rightModel,
|
|
322
|
+
};
|
|
323
|
+
},
|
|
324
|
+
template: `
|
|
325
|
+
<UCol no-mobile>
|
|
326
|
+
<USelect v-bind="args" v-model="args.clearModel" label="Slot clear">
|
|
327
|
+
<template #clear>
|
|
328
|
+
<ULink label="Close" />
|
|
329
|
+
</template>
|
|
330
|
+
</USelect>
|
|
331
|
+
|
|
332
|
+
<USelect
|
|
333
|
+
v-bind="args"
|
|
334
|
+
v-model="args.clearMultipleModel"
|
|
335
|
+
multiple
|
|
336
|
+
label="Slot clear-multiple"
|
|
337
|
+
>
|
|
338
|
+
<template #clear-multiple>
|
|
339
|
+
<ULink label="Close" color="green" />
|
|
340
|
+
</template>
|
|
341
|
+
</USelect>
|
|
342
|
+
|
|
343
|
+
<URow no-mobile>
|
|
344
|
+
<USelect v-bind="args" v-model="args.beforeToggleModel" label="Slot before-toggle">
|
|
345
|
+
<template #before-toggle>
|
|
346
|
+
<UAvatar />
|
|
347
|
+
</template>
|
|
348
|
+
</USelect>
|
|
349
|
+
|
|
350
|
+
<USelect
|
|
351
|
+
v-bind="args"
|
|
352
|
+
v-model="args.afterToggleModel"
|
|
353
|
+
:config="{ afterToggle: 'pt-0 items-center' }"
|
|
354
|
+
label="Slot after-toggle"
|
|
355
|
+
>
|
|
356
|
+
<template #after-toggle>
|
|
357
|
+
<UAvatar />
|
|
358
|
+
</template>
|
|
359
|
+
</USelect>
|
|
360
|
+
</URow>
|
|
361
|
+
|
|
362
|
+
<URow no-mobile>
|
|
363
|
+
<USelect v-bind="args" v-model="args.leftModel" label="Slot left">
|
|
364
|
+
<template #left>
|
|
365
|
+
<UAvatar />
|
|
366
|
+
</template>
|
|
367
|
+
</USelect>
|
|
368
|
+
|
|
369
|
+
<USelect v-bind="args" v-model="args.rightModel" label="Slot right">
|
|
370
|
+
<template #right>
|
|
371
|
+
<UAvatar />
|
|
372
|
+
</template>
|
|
373
|
+
</USelect>
|
|
374
|
+
</URow>
|
|
375
|
+
</UCol>
|
|
376
|
+
`,
|
|
377
|
+
});
|
|
378
|
+
Slots.parameters = {
|
|
379
|
+
docs: {
|
|
380
|
+
story: {
|
|
381
|
+
height: "500px",
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
};
|
|
192
385
|
|
|
193
386
|
export const SlotToggle = DefaultTemplate.bind({});
|
|
194
387
|
SlotToggle.args = {
|
|
@@ -202,67 +395,29 @@ SlotToggle.args = {
|
|
|
202
395
|
`,
|
|
203
396
|
};
|
|
204
397
|
|
|
205
|
-
export const SlotClear = DefaultTemplate.bind({});
|
|
206
|
-
SlotClear.args = {
|
|
207
|
-
slotTemplate: `
|
|
208
|
-
<template #clear>
|
|
209
|
-
<ULink label="Close" />
|
|
210
|
-
</template>
|
|
211
|
-
`,
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
export const SlotClearMultiple = DefaultTemplate.bind({});
|
|
215
|
-
SlotClearMultiple.args = {
|
|
216
|
-
multiple: true,
|
|
217
|
-
modelValue: [],
|
|
218
|
-
slotTemplate: `
|
|
219
|
-
<template #clear-multiple>
|
|
220
|
-
<ULink label="Close" />
|
|
221
|
-
</template>
|
|
222
|
-
`,
|
|
223
|
-
};
|
|
224
|
-
|
|
225
398
|
export const SlotSelectedValueLabel = DefaultTemplate.bind({});
|
|
226
399
|
SlotSelectedValueLabel.args = {
|
|
227
400
|
slotTemplate: `
|
|
228
|
-
<template #selected-label>
|
|
229
|
-
|
|
401
|
+
<template #selected-label="{ selectedLabel }">
|
|
402
|
+
<UBadge :label="selectedLabel" color="green" />
|
|
230
403
|
</template>
|
|
231
404
|
`,
|
|
232
405
|
};
|
|
233
406
|
|
|
234
407
|
export const SlotSelectedValueLabelAfter = DefaultTemplate.bind({});
|
|
235
408
|
SlotSelectedValueLabelAfter.args = {
|
|
409
|
+
options: [
|
|
410
|
+
{ label: "Venice", id: "1", icon: "sailing", color: "green" },
|
|
411
|
+
{ label: "Paris", id: "2", icon: "flight", color: "orange" },
|
|
412
|
+
],
|
|
236
413
|
slotTemplate: `
|
|
237
|
-
<template #selected-label-after>
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
SlotOption.args = {
|
|
245
|
-
slotTemplate: `
|
|
246
|
-
<template #option>
|
|
247
|
-
🤘🤘🤘
|
|
248
|
-
</template>
|
|
249
|
-
`,
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
export const SlotAfterToggle = DefaultTemplate.bind({});
|
|
253
|
-
SlotAfterToggle.args = {
|
|
254
|
-
slotTemplate: `
|
|
255
|
-
<template #after-toggle>
|
|
256
|
-
🤘
|
|
257
|
-
</template>
|
|
258
|
-
`,
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
export const SlotBeforeToggle = DefaultTemplate.bind({});
|
|
262
|
-
SlotBeforeToggle.args = {
|
|
263
|
-
slotTemplate: `
|
|
264
|
-
<template #before-toggle>
|
|
265
|
-
🤘
|
|
414
|
+
<template #selected-label-after="{ option }">
|
|
415
|
+
<UIcon
|
|
416
|
+
:name="option.icon"
|
|
417
|
+
:color="option.color"
|
|
418
|
+
size="xs"
|
|
419
|
+
class="ml-1"
|
|
420
|
+
/>
|
|
266
421
|
</template>
|
|
267
422
|
`,
|
|
268
423
|
};
|
|
@@ -270,32 +425,26 @@ SlotBeforeToggle.args = {
|
|
|
270
425
|
export const SlotBeforeOption = DefaultTemplate.bind({});
|
|
271
426
|
SlotBeforeOption.args = {
|
|
272
427
|
slotTemplate: `
|
|
273
|
-
<template #before-option>
|
|
274
|
-
|
|
428
|
+
<template #before-option="{ option, index }">
|
|
429
|
+
<UBadge v-if="index === 3" label="Special offer!" color="blue" class="mr-1" />
|
|
275
430
|
</template>
|
|
276
431
|
`,
|
|
277
432
|
};
|
|
278
433
|
|
|
279
|
-
export const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
export const RightIcon = DefaultTemplate.bind({});
|
|
283
|
-
RightIcon.args = { rightIcon: "star" };
|
|
284
|
-
|
|
285
|
-
export const SlotLeft = DefaultTemplate.bind({});
|
|
286
|
-
SlotLeft.args = {
|
|
434
|
+
export const SlotOption = DefaultTemplate.bind({});
|
|
435
|
+
SlotOption.args = {
|
|
287
436
|
slotTemplate: `
|
|
288
|
-
<template #
|
|
289
|
-
|
|
437
|
+
<template #option="{ option, index }">
|
|
438
|
+
<UBadge v-if="index === 1" :label="option.label" />
|
|
290
439
|
</template>
|
|
291
440
|
`,
|
|
292
441
|
};
|
|
293
442
|
|
|
294
|
-
export const
|
|
295
|
-
|
|
443
|
+
export const SlotAfterOption = DefaultTemplate.bind({});
|
|
444
|
+
SlotAfterOption.args = {
|
|
296
445
|
slotTemplate: `
|
|
297
|
-
<template #
|
|
298
|
-
|
|
446
|
+
<template #after-option="{ option, index }">
|
|
447
|
+
<UBadge v-if="index === 2" label="Special offer!" color="blue" class="ml-1" />
|
|
299
448
|
</template>
|
|
300
449
|
`,
|
|
301
450
|
};
|
package/ui.form-select/types.ts
CHANGED
|
@@ -7,7 +7,7 @@ export default /*tw*/ {
|
|
|
7
7
|
base: `
|
|
8
8
|
flex bg-white transition w-full
|
|
9
9
|
rounded-dynamic border border-gray-300 hover:border-gray-400 hover:focus-within:border-brand-600
|
|
10
|
-
focus-within:border-brand-600 focus-within:ring-dynamic-
|
|
10
|
+
focus-within:border-brand-600 focus-within:ring-dynamic-sm
|
|
11
11
|
focus-within:ring-brand-600 focus-within:outline-none
|
|
12
12
|
`,
|
|
13
13
|
variants: {
|
package/utils/theme.ts
CHANGED
|
@@ -10,12 +10,14 @@ import {
|
|
|
10
10
|
DARK_MODE_SELECTOR,
|
|
11
11
|
GRAYSCALE_COLOR,
|
|
12
12
|
TAILWIND_COLORS,
|
|
13
|
-
DEFAULT_RING,
|
|
14
|
-
DEFAULT_ROUNDING,
|
|
15
13
|
DEFAULT_BRAND_COLOR,
|
|
16
14
|
DEFAULT_GRAY_COLOR,
|
|
15
|
+
DEFAULT_RING,
|
|
17
16
|
DEFAULT_RING_OFFSET_COLOR_LIGHT,
|
|
18
17
|
DEFAULT_RING_OFFSET_COLOR_DARK,
|
|
18
|
+
RING_DECREMENT,
|
|
19
|
+
RING_INCREMENT,
|
|
20
|
+
DEFAULT_ROUNDING,
|
|
19
21
|
ROUNDING_DECREMENT,
|
|
20
22
|
ROUNDING_INCREMENT,
|
|
21
23
|
} from "../constants.js";
|
|
@@ -40,7 +42,9 @@ declare interface RootCSSVariableOptions {
|
|
|
40
42
|
colors: Colors;
|
|
41
43
|
brand: string;
|
|
42
44
|
gray: string;
|
|
45
|
+
ringSm: number;
|
|
43
46
|
ring: number;
|
|
47
|
+
ringLg: number;
|
|
44
48
|
ringOffsetColorDark: string;
|
|
45
49
|
ringOffsetColorLight: string;
|
|
46
50
|
roundingSm: number;
|
|
@@ -155,7 +159,11 @@ export function setTheme(config: Config = {}) {
|
|
|
155
159
|
let gray: GrayColors =
|
|
156
160
|
config.gray ?? getSelectedGrayColor() ?? vuelessConfig.gray ?? DEFAULT_GRAY_COLOR;
|
|
157
161
|
|
|
158
|
-
const
|
|
162
|
+
const { ringSm, ring, ringLg } = getRings(
|
|
163
|
+
config.ringSm ?? vuelessConfig.ringSm,
|
|
164
|
+
config.ring ?? vuelessConfig.ring,
|
|
165
|
+
config.ringLg ?? vuelessConfig.ringLg,
|
|
166
|
+
);
|
|
159
167
|
|
|
160
168
|
const ringOffsetColorDark =
|
|
161
169
|
config.ringOffsetColorDark ??
|
|
@@ -198,7 +206,9 @@ export function setTheme(config: Config = {}) {
|
|
|
198
206
|
colors,
|
|
199
207
|
brand,
|
|
200
208
|
gray,
|
|
209
|
+
ringSm,
|
|
201
210
|
ring,
|
|
211
|
+
ringLg,
|
|
202
212
|
ringOffsetColorDark,
|
|
203
213
|
ringOffsetColorLight,
|
|
204
214
|
roundingSm,
|
|
@@ -207,6 +217,22 @@ export function setTheme(config: Config = {}) {
|
|
|
207
217
|
});
|
|
208
218
|
}
|
|
209
219
|
|
|
220
|
+
function getRings(sm?: number, md?: number, lg?: number) {
|
|
221
|
+
const ring = Math.max(0, md ?? DEFAULT_RING);
|
|
222
|
+
const ringSm = Math.max(0, ring - RING_DECREMENT);
|
|
223
|
+
let ringLg = Math.max(0, ring + RING_INCREMENT);
|
|
224
|
+
|
|
225
|
+
if (ring === 0) {
|
|
226
|
+
ringLg = 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
ring,
|
|
231
|
+
ringSm: sm === undefined ? ringSm : Math.max(0, sm),
|
|
232
|
+
ringLg: lg === undefined ? ringLg : Math.max(0, lg),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
210
236
|
function getRoundings(sm?: number, md?: number, lg?: number) {
|
|
211
237
|
const rounding = Math.max(0, md ?? DEFAULT_ROUNDING);
|
|
212
238
|
let roundingSm = Math.max(0, rounding - ROUNDING_DECREMENT);
|
|
@@ -240,7 +266,9 @@ function setRootCSSVariables(options: RootCSSVariableOptions) {
|
|
|
240
266
|
colors,
|
|
241
267
|
brand,
|
|
242
268
|
gray,
|
|
269
|
+
ringSm,
|
|
243
270
|
ring,
|
|
271
|
+
ringLg,
|
|
244
272
|
ringOffsetColorDark,
|
|
245
273
|
ringOffsetColorLight,
|
|
246
274
|
roundingSm,
|
|
@@ -257,7 +285,9 @@ function setRootCSSVariables(options: RootCSSVariableOptions) {
|
|
|
257
285
|
"--vl-rounding-sm": `${Number(roundingSm) / PX_IN_REM}rem`,
|
|
258
286
|
"--vl-rounding": `${Number(rounding) / PX_IN_REM}rem`,
|
|
259
287
|
"--vl-rounding-lg": `${Number(roundingLg) / PX_IN_REM}rem`,
|
|
260
|
-
"--vl-ring": `${
|
|
288
|
+
"--vl-ring-sm": `${ringSm}px`,
|
|
289
|
+
"--vl-ring": `${ring}px`,
|
|
290
|
+
"--vl-ring-lg": `${ringLg}px`,
|
|
261
291
|
"--vl-ring-offset-color": convertHexInRgb(defaultRingOffsetColor),
|
|
262
292
|
"--vl-color-gray-default": convertHexInRgb(colors[gray]?.[defaultBrandShade]),
|
|
263
293
|
"--vl-color-brand-default": convertHexInRgb(colors[brand]?.[defaultGrayShade]),
|