v-uixy 1.7.2 → 1.8.0
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/templates/components/Checkbox/Checkbox.styles.ts +1 -1
- package/templates/components/DatePicker/DatePicker.component.vue +6 -3
- package/templates/components/DatePicker/DatePicker.styles.ts +30 -11
- package/templates/components/DatePicker/DatePicker.types.ts +2 -0
- package/templates/components/DateRangePicker/DateRangePicker.component.vue +6 -3
- package/templates/components/DateRangePicker/DateRangePicker.types.ts +2 -0
- package/templates/components/Input/Input.component.vue +4 -1
- package/templates/components/Input/Input.styles.ts +24 -2
- package/templates/components/Input/Input.types.ts +2 -0
- package/templates/components/Select/Select.component.vue +57 -8
- package/templates/components/Select/Select.styles.ts +56 -3
- package/templates/components/Select/Select.types.ts +3 -0
- package/templates/components/Select/SelectTreeItem.vue +4 -0
- package/templates/components/Textarea/Textarea.component.vue +3 -1
- package/templates/components/Textarea/Textarea.styles.ts +6 -1
- package/templates/components/Textarea/Textarea.types.ts +3 -0
- package/templates/types/field.ts +1 -0
package/package.json
CHANGED
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
role="button"
|
|
10
10
|
:tabindex="props.disabled ? -1 : 0"
|
|
11
11
|
:aria-expanded="active"
|
|
12
|
-
:class="triggerStyles({ status, open: active })"
|
|
12
|
+
:class="triggerStyles({ status, open: active, size })"
|
|
13
13
|
@click="onTriggerClick"
|
|
14
14
|
@keydown.enter.prevent="onTriggerClick"
|
|
15
15
|
@keydown.space.prevent="onTriggerClick"
|
|
16
16
|
>
|
|
17
17
|
<uixy-icon
|
|
18
18
|
:name="props.icon ?? 'calendar'"
|
|
19
|
-
:class="triggerIconStyles({ disabled: props.disabled })"
|
|
19
|
+
:class="triggerIconStyles({ disabled: props.disabled, size })"
|
|
20
20
|
/>
|
|
21
21
|
<span
|
|
22
22
|
:class="
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<uixy-icon
|
|
29
29
|
v-if="model && !props.disabled"
|
|
30
30
|
name="close"
|
|
31
|
-
class="
|
|
31
|
+
:class="closeIconStyles({ size })"
|
|
32
32
|
@click.stop="clear"
|
|
33
33
|
/>
|
|
34
34
|
</div>
|
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
triggerStyles,
|
|
123
123
|
triggerValueStyles,
|
|
124
124
|
triggerIconStyles,
|
|
125
|
+
closeIconStyles,
|
|
125
126
|
labelStyles,
|
|
126
127
|
helperStyles,
|
|
127
128
|
panelStyles,
|
|
@@ -156,6 +157,8 @@
|
|
|
156
157
|
return props.status ?? "default";
|
|
157
158
|
});
|
|
158
159
|
|
|
160
|
+
const size = computed(() => props.size ?? "md");
|
|
161
|
+
|
|
159
162
|
const helperText = computed(() => {
|
|
160
163
|
if (status.value === "error") return props.errorText ?? "";
|
|
161
164
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import styles from "~/utils/styles";
|
|
2
2
|
|
|
3
3
|
export const triggerStyles = styles(
|
|
4
|
-
"relative flex w-full items-center gap-2 cursor-pointer transition-colors ease-in-out duration-150 border border-gray-300 dark:border-gray-900 rounded-1
|
|
4
|
+
"relative flex w-full items-center gap-2 cursor-pointer transition-colors ease-in-out duration-150 border border-gray-300 dark:border-gray-900 rounded-1 outline-offset-1 outline-gray-300 dark:outline-gray-800 select-none",
|
|
5
5
|
{
|
|
6
6
|
status: {
|
|
7
7
|
default:
|
|
@@ -15,7 +15,12 @@ export const triggerStyles = styles(
|
|
|
15
15
|
true: "border-gray-500 dark:border-gray-600",
|
|
16
16
|
false: "",
|
|
17
17
|
},
|
|
18
|
-
|
|
18
|
+
size: {
|
|
19
|
+
sm: "pl-2.5 pr-2.5 py-1.5 text-xs min-h-[32px]",
|
|
20
|
+
md: "pl-3 pr-3 py-2 text-sm min-h-[38px]",
|
|
21
|
+
xl: "pl-3.5 pr-3.5 py-2.5 text-base min-h-[42px]",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
19
24
|
);
|
|
20
25
|
|
|
21
26
|
export const triggerValueStyles = styles("flex-1 truncate text-left", {
|
|
@@ -30,13 +35,29 @@ export const triggerValueStyles = styles("flex-1 truncate text-left", {
|
|
|
30
35
|
});
|
|
31
36
|
|
|
32
37
|
export const triggerIconStyles = styles(
|
|
33
|
-
"
|
|
38
|
+
"shrink-0 text-gray-400 dark:text-gray-600",
|
|
34
39
|
{
|
|
35
40
|
disabled: {
|
|
36
41
|
true: "dark:text-gray-700",
|
|
37
42
|
false: "",
|
|
38
43
|
},
|
|
39
|
-
|
|
44
|
+
size: {
|
|
45
|
+
sm: "h-3.5 w-3.5",
|
|
46
|
+
md: "h-4 w-4",
|
|
47
|
+
xl: "h-5 w-5",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
export const closeIconStyles = styles(
|
|
53
|
+
"shrink-0 cursor-pointer text-gray-400 hover:text-black dark:text-gray-600 dark:hover:text-white",
|
|
54
|
+
{
|
|
55
|
+
size: {
|
|
56
|
+
sm: "h-3.5 w-3.5",
|
|
57
|
+
md: "h-4 w-4",
|
|
58
|
+
xl: "h-5 w-5",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
40
61
|
);
|
|
41
62
|
|
|
42
63
|
export const labelStyles = styles(
|
|
@@ -47,7 +68,7 @@ export const labelStyles = styles(
|
|
|
47
68
|
error: "text-error-600",
|
|
48
69
|
disabled: "text-gray-500 dark:text-gray-700",
|
|
49
70
|
},
|
|
50
|
-
}
|
|
71
|
+
},
|
|
51
72
|
);
|
|
52
73
|
|
|
53
74
|
export const helperStyles = styles(
|
|
@@ -58,17 +79,15 @@ export const helperStyles = styles(
|
|
|
58
79
|
error: "text-error-600",
|
|
59
80
|
disabled: "text-gray-400 dark:text-gray-800",
|
|
60
81
|
},
|
|
61
|
-
}
|
|
82
|
+
},
|
|
62
83
|
);
|
|
63
84
|
|
|
64
85
|
export const panelStyles = styles(
|
|
65
|
-
"flex flex-col gap-3 rounded-2 border border-gray-300 bg-gray-100 p-3 shadow-lg dark:border-gray-900 dark:bg-black"
|
|
86
|
+
"flex flex-col gap-3 rounded-2 border border-gray-300 bg-gray-100 p-3 shadow-lg dark:border-gray-900 dark:bg-black",
|
|
66
87
|
);
|
|
67
88
|
|
|
68
89
|
export const sectionLabelStyles = styles(
|
|
69
|
-
"text-xs font-500 text-gray-500 dark:text-gray-600"
|
|
90
|
+
"text-xs font-500 text-gray-500 dark:text-gray-600",
|
|
70
91
|
);
|
|
71
92
|
|
|
72
|
-
export const footerStyles = styles(
|
|
73
|
-
"flex items-center justify-between gap-2"
|
|
74
|
-
);
|
|
93
|
+
export const footerStyles = styles("flex items-center justify-between gap-2");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IconName } from "~/types/icons";
|
|
2
|
+
import type { UixyFieldSize } from "~/types/field";
|
|
2
3
|
|
|
3
4
|
export interface UixyDatePickerProps {
|
|
4
5
|
placeholder?: string;
|
|
@@ -14,4 +15,5 @@ export interface UixyDatePickerProps {
|
|
|
14
15
|
isDateDisabled?: (date: Date) => boolean;
|
|
15
16
|
direction?: "top" | "bottom";
|
|
16
17
|
closeOnSelect?: boolean;
|
|
18
|
+
size?: UixyFieldSize;
|
|
17
19
|
}
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
role="button"
|
|
10
10
|
:tabindex="props.disabled ? -1 : 0"
|
|
11
11
|
:aria-expanded="active"
|
|
12
|
-
:class="triggerStyles({ status, open: active })"
|
|
12
|
+
:class="triggerStyles({ status, open: active, size })"
|
|
13
13
|
@click="onTriggerClick"
|
|
14
14
|
@keydown.enter.prevent="onTriggerClick"
|
|
15
15
|
@keydown.space.prevent="onTriggerClick"
|
|
16
16
|
>
|
|
17
17
|
<uixy-icon
|
|
18
18
|
:name="props.icon ?? 'calendar'"
|
|
19
|
-
:class="triggerIconStyles({ disabled: props.disabled })"
|
|
19
|
+
:class="triggerIconStyles({ disabled: props.disabled, size })"
|
|
20
20
|
/>
|
|
21
21
|
<span
|
|
22
22
|
:class="
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<uixy-icon
|
|
32
32
|
v-if="hasValue && !props.disabled"
|
|
33
33
|
name="close"
|
|
34
|
-
class="
|
|
34
|
+
:class="closeIconStyles({ size })"
|
|
35
35
|
@click.stop="clear"
|
|
36
36
|
/>
|
|
37
37
|
</div>
|
|
@@ -145,6 +145,7 @@
|
|
|
145
145
|
triggerStyles,
|
|
146
146
|
triggerValueStyles,
|
|
147
147
|
triggerIconStyles,
|
|
148
|
+
closeIconStyles,
|
|
148
149
|
labelStyles,
|
|
149
150
|
helperStyles,
|
|
150
151
|
panelStyles,
|
|
@@ -187,6 +188,8 @@
|
|
|
187
188
|
return props.status ?? "default";
|
|
188
189
|
});
|
|
189
190
|
|
|
191
|
+
const size = computed(() => props.size ?? "md");
|
|
192
|
+
|
|
190
193
|
const helperText = computed(() => {
|
|
191
194
|
if (status.value === "error") return props.errorText ?? "";
|
|
192
195
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IconName } from "~/types/icons";
|
|
2
|
+
import type { UixyFieldSize } from "~/types/field";
|
|
2
3
|
|
|
3
4
|
export interface UixyDateRange {
|
|
4
5
|
start: Date | null;
|
|
@@ -19,4 +20,5 @@ export interface UixyDateRangePickerProps {
|
|
|
19
20
|
isDateDisabled?: (date: Date) => boolean;
|
|
20
21
|
direction?: "top" | "bottom";
|
|
21
22
|
closeOnSelect?: boolean;
|
|
23
|
+
size?: UixyFieldSize;
|
|
22
24
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
:id
|
|
9
9
|
:disabled="props.disabled"
|
|
10
10
|
:placeholder="props.placeholder"
|
|
11
|
-
:class="inputStyles({ status, icon }, $attrs.class as string)"
|
|
11
|
+
:class="inputStyles({ status, icon, size }, $attrs.class as string)"
|
|
12
12
|
v-bind="filteredAttrs"
|
|
13
13
|
/>
|
|
14
14
|
<uixy-icon
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
iconStyles({
|
|
20
20
|
status,
|
|
21
21
|
icon,
|
|
22
|
+
size,
|
|
22
23
|
targetable: !!hasIconClickEmit,
|
|
23
24
|
})
|
|
24
25
|
"
|
|
@@ -94,6 +95,8 @@
|
|
|
94
95
|
props.disabled ? "disabled" : (props.status ?? "default"),
|
|
95
96
|
);
|
|
96
97
|
|
|
98
|
+
const size = computed(() => props.size ?? "md");
|
|
99
|
+
|
|
97
100
|
const text = computed(
|
|
98
101
|
() =>
|
|
99
102
|
({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import styles from "~/utils/styles";
|
|
2
2
|
|
|
3
3
|
export const inputStyles = styles(
|
|
4
|
-
"peer transition-colors ease-in-out duration-150 border border-gray-300 dark:border-gray-900 rounded-1
|
|
4
|
+
"peer transition-colors ease-in-out duration-150 border border-gray-300 dark:border-gray-900 rounded-1 placeholder:text-gray-500 dark:placeholder:text-gray-700 dark:outline-gray-800 outline-offset-1 outline-gray-300",
|
|
5
5
|
{
|
|
6
6
|
status: {
|
|
7
7
|
default:
|
|
@@ -12,16 +12,27 @@ export const inputStyles = styles(
|
|
|
12
12
|
valid:
|
|
13
13
|
"bg-white dark:bg-gray-1000 focus-visible:border-gray-500 dark:focus-visible:border-gray-600",
|
|
14
14
|
},
|
|
15
|
+
size: {
|
|
16
|
+
sm: "px-2.5 py-1.5 text-xs",
|
|
17
|
+
md: "px-3 py-2 text-sm",
|
|
18
|
+
xl: "px-3.5 py-2.5 text-base",
|
|
19
|
+
},
|
|
15
20
|
icon: {
|
|
16
21
|
left: "pl-8",
|
|
17
22
|
right: "pr-8",
|
|
18
23
|
none: "",
|
|
19
24
|
},
|
|
20
25
|
},
|
|
26
|
+
{
|
|
27
|
+
"size.sm+icon.left": "pl-7",
|
|
28
|
+
"size.sm+icon.right": "pr-7",
|
|
29
|
+
"size.xl+icon.left": "pl-9",
|
|
30
|
+
"size.xl+icon.right": "pr-9",
|
|
31
|
+
},
|
|
21
32
|
);
|
|
22
33
|
|
|
23
34
|
export const iconStyles = styles(
|
|
24
|
-
"select-none pointer-events-none
|
|
35
|
+
"select-none pointer-events-none absolute transition-colors duration-150 ease-in-out",
|
|
25
36
|
{
|
|
26
37
|
status: {
|
|
27
38
|
default:
|
|
@@ -32,6 +43,11 @@ export const iconStyles = styles(
|
|
|
32
43
|
valid:
|
|
33
44
|
"text-gray-400 peer-focus:text-black hover:text-black dark:text-gray-700 dark:peer-focus:text-gray-500 dark:hover:text-gray-500",
|
|
34
45
|
},
|
|
46
|
+
size: {
|
|
47
|
+
sm: "h-4 w-4 bottom-1.5",
|
|
48
|
+
md: "h-5 w-5 bottom-2",
|
|
49
|
+
xl: "h-5 w-5 bottom-2.5",
|
|
50
|
+
},
|
|
35
51
|
icon: {
|
|
36
52
|
left: "left-2",
|
|
37
53
|
right: "right-2",
|
|
@@ -42,6 +58,12 @@ export const iconStyles = styles(
|
|
|
42
58
|
false: "",
|
|
43
59
|
},
|
|
44
60
|
},
|
|
61
|
+
{
|
|
62
|
+
"size.sm+icon.left": "left-1.5",
|
|
63
|
+
"size.sm+icon.right": "right-1.5",
|
|
64
|
+
"size.xl+icon.left": "left-2.5",
|
|
65
|
+
"size.xl+icon.right": "right-2.5",
|
|
66
|
+
},
|
|
45
67
|
);
|
|
46
68
|
|
|
47
69
|
export const labelStyles = styles(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IconName } from "~/types/icons";
|
|
2
|
+
import type { UixyFieldSize } from "~/types/field";
|
|
2
3
|
|
|
3
4
|
export interface UixyInputProps {
|
|
4
5
|
status?: "valid" | "error" | "default";
|
|
@@ -11,6 +12,7 @@ export interface UixyInputProps {
|
|
|
11
12
|
helperText?: string;
|
|
12
13
|
errorText?: string;
|
|
13
14
|
autoFocus?: boolean;
|
|
15
|
+
size?: UixyFieldSize;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export interface UixyInputEmits {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="flex flex-col gap-1">
|
|
3
3
|
<div class="relative flex flex-col-reverse gap-1" ref="refOptions">
|
|
4
4
|
<div
|
|
5
|
-
:class="selectStyles({ status }, $attrs.class as string)"
|
|
5
|
+
:class="selectStyles({ status, size }, $attrs.class as string)"
|
|
6
6
|
:tabIndex="props.disabled ? -1 : 0"
|
|
7
7
|
:auto-focus="props.autoFocus"
|
|
8
8
|
ref="refTrigger"
|
|
@@ -37,17 +37,17 @@
|
|
|
37
37
|
<uixy-icon
|
|
38
38
|
v-if="props.deselectable && !props.multiple && model"
|
|
39
39
|
name="close"
|
|
40
|
-
class="
|
|
40
|
+
:class="deselectIconStyles({ size })"
|
|
41
41
|
@click.stop="handleDeselect"
|
|
42
42
|
/>
|
|
43
|
-
<uixy-icon name="chevron-down" :class="iconStyles({ open })" />
|
|
43
|
+
<uixy-icon name="chevron-down" :class="iconStyles({ open, size })" />
|
|
44
44
|
</div>
|
|
45
45
|
|
|
46
46
|
<teleport to="body">
|
|
47
47
|
<animate-presence>
|
|
48
48
|
<motion.div
|
|
49
49
|
v-if="open && !props.disabled"
|
|
50
|
-
class="
|
|
50
|
+
:class="dropdownPanelStyles({ size })"
|
|
51
51
|
:style="dropdownStyles"
|
|
52
52
|
:initial="{ opacity: 0, y: -4, scale: 0.98 }"
|
|
53
53
|
:animate="{ opacity: 1, y: 0, scale: 1 }"
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
icon="search"
|
|
64
64
|
iconPositon="right"
|
|
65
65
|
placeholder="Search..."
|
|
66
|
+
:size="size"
|
|
66
67
|
/>
|
|
67
68
|
</div>
|
|
68
69
|
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
:multiple="props.multiple"
|
|
82
83
|
:search-term="search"
|
|
83
84
|
:original-options="props.options"
|
|
85
|
+
:size="size"
|
|
84
86
|
@toggle-expand="toggleExpand"
|
|
85
87
|
@select="handleClick"
|
|
86
88
|
/>
|
|
@@ -88,7 +90,12 @@
|
|
|
88
90
|
|
|
89
91
|
<li
|
|
90
92
|
v-if="filteredOptions.length === 0"
|
|
91
|
-
class="
|
|
93
|
+
:class="
|
|
94
|
+
listItemPaddingStyles(
|
|
95
|
+
{ size },
|
|
96
|
+
'text-center dark:text-gray-600',
|
|
97
|
+
)
|
|
98
|
+
"
|
|
92
99
|
>
|
|
93
100
|
No results found
|
|
94
101
|
</li>
|
|
@@ -103,6 +110,7 @@
|
|
|
103
110
|
itemStyles({
|
|
104
111
|
selected: isSelected(option),
|
|
105
112
|
disabled: !!option.disabled,
|
|
113
|
+
size,
|
|
106
114
|
})
|
|
107
115
|
"
|
|
108
116
|
@keydown="handleKeydownOption($event, option)"
|
|
@@ -112,13 +120,18 @@
|
|
|
112
120
|
<uixy-icon
|
|
113
121
|
v-if="isSelected(option)"
|
|
114
122
|
name="check"
|
|
115
|
-
class="
|
|
123
|
+
:class="checkIconStyles({ size })"
|
|
116
124
|
/>
|
|
117
125
|
</li>
|
|
118
126
|
|
|
119
127
|
<li
|
|
120
128
|
v-if="customAddVisible"
|
|
121
|
-
class="
|
|
129
|
+
:class="
|
|
130
|
+
listItemPaddingStyles(
|
|
131
|
+
{ size },
|
|
132
|
+
'relative rounded-1 cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-900 text-gray-500 dark:text-gray-600',
|
|
133
|
+
)
|
|
134
|
+
"
|
|
122
135
|
@click="handleCustomAdd"
|
|
123
136
|
>
|
|
124
137
|
Add: "{{ search }}"
|
|
@@ -126,7 +139,12 @@
|
|
|
126
139
|
|
|
127
140
|
<li
|
|
128
141
|
v-if="filteredOptions.length === 0 && !customAddVisible"
|
|
129
|
-
class="
|
|
142
|
+
:class="
|
|
143
|
+
listItemPaddingStyles(
|
|
144
|
+
{ size },
|
|
145
|
+
'text-center dark:text-gray-600',
|
|
146
|
+
)
|
|
147
|
+
"
|
|
130
148
|
>
|
|
131
149
|
No results found
|
|
132
150
|
</li>
|
|
@@ -174,6 +192,10 @@
|
|
|
174
192
|
itemStyles,
|
|
175
193
|
helperStyles,
|
|
176
194
|
badgesWrapperStyles,
|
|
195
|
+
deselectIconStyles,
|
|
196
|
+
dropdownPanelStyles,
|
|
197
|
+
listItemPaddingStyles,
|
|
198
|
+
checkIconStyles,
|
|
177
199
|
} from "./Select.styles";
|
|
178
200
|
import type { UixySelectEmits, UixySelectProps } from "./Select.types";
|
|
179
201
|
import { UixyBadge } from "../Badge";
|
|
@@ -232,9 +254,13 @@
|
|
|
232
254
|
handleCustomAdd,
|
|
233
255
|
} = useSelect<T>(props, model as Ref<T>, emits, refDropdownEl);
|
|
234
256
|
|
|
257
|
+
let positionRequestId = 0;
|
|
258
|
+
|
|
235
259
|
const updateDropdownPosition = async () => {
|
|
236
260
|
if (!open.value || props.disabled) return;
|
|
237
261
|
|
|
262
|
+
const requestId = ++positionRequestId;
|
|
263
|
+
|
|
238
264
|
await nextTick();
|
|
239
265
|
await new Promise<void>((r) => requestAnimationFrame(() => r()));
|
|
240
266
|
|
|
@@ -274,6 +300,8 @@
|
|
|
274
300
|
const maxLeft = scrollX + window.innerWidth - width - pad;
|
|
275
301
|
left = Math.min(Math.max(minLeft, left), Math.max(minLeft, maxLeft));
|
|
276
302
|
|
|
303
|
+
if (requestId !== positionRequestId) return;
|
|
304
|
+
|
|
277
305
|
dropdownStyles.value = {
|
|
278
306
|
position: "absolute",
|
|
279
307
|
top: `${Math.round(top)}px`,
|
|
@@ -290,6 +318,13 @@
|
|
|
290
318
|
void updateDropdownPosition();
|
|
291
319
|
};
|
|
292
320
|
|
|
321
|
+
const dropdownResizeObserver =
|
|
322
|
+
typeof ResizeObserver !== "undefined"
|
|
323
|
+
? new ResizeObserver(() => {
|
|
324
|
+
void updateDropdownPosition();
|
|
325
|
+
})
|
|
326
|
+
: null;
|
|
327
|
+
|
|
293
328
|
watch(
|
|
294
329
|
() => open.value,
|
|
295
330
|
(isOpen) => {
|
|
@@ -308,13 +343,25 @@
|
|
|
308
343
|
window.addEventListener("scroll", onAnyScroll, true);
|
|
309
344
|
}
|
|
310
345
|
|
|
346
|
+
if (dropdownResizeObserver) {
|
|
347
|
+
nextTick(() => {
|
|
348
|
+
if (refDropdownEl.value)
|
|
349
|
+
dropdownResizeObserver.observe(refDropdownEl.value);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
311
353
|
onWatcherCleanup(() => {
|
|
312
354
|
window.removeEventListener("resize", onResize);
|
|
313
355
|
window.removeEventListener("scroll", onAnyScroll, true);
|
|
356
|
+
dropdownResizeObserver?.disconnect();
|
|
314
357
|
});
|
|
315
358
|
},
|
|
316
359
|
);
|
|
317
360
|
|
|
361
|
+
onUnmounted(() => {
|
|
362
|
+
dropdownResizeObserver?.disconnect();
|
|
363
|
+
});
|
|
364
|
+
|
|
318
365
|
onMounted(() => {
|
|
319
366
|
if (props.autoOpen && !props.disabled) {
|
|
320
367
|
const delayMs = (props.delay ?? 0) * 1000;
|
|
@@ -352,6 +399,8 @@
|
|
|
352
399
|
props.disabled ? "disabled" : (props.status ?? "default"),
|
|
353
400
|
);
|
|
354
401
|
|
|
402
|
+
const size = computed(() => props.size ?? "md");
|
|
403
|
+
|
|
355
404
|
const text = computed(
|
|
356
405
|
() =>
|
|
357
406
|
({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import styles from "~/utils/styles";
|
|
2
2
|
|
|
3
3
|
export const selectStyles = styles(
|
|
4
|
-
"relative select-none peer transition-colors ease-in-out duration-150 border border-gray-300 dark:border-gray-900 rounded-1
|
|
4
|
+
"relative select-none peer transition-colors ease-in-out duration-150 border border-gray-300 dark:border-gray-900 rounded-1 placeholder:text-gray-500 dark:placeholder:text-gray-700 dark:outline-gray-800 outline-offset-1 outline-gray-300",
|
|
5
5
|
{
|
|
6
6
|
status: {
|
|
7
7
|
default:
|
|
@@ -13,16 +13,37 @@ export const selectStyles = styles(
|
|
|
13
13
|
valid:
|
|
14
14
|
"bg-white dark:bg-gray-1000 focus-visible:border-gray-500 dark:focus-visible:border-gray-600 cursor-pointer",
|
|
15
15
|
},
|
|
16
|
+
size: {
|
|
17
|
+
sm: "pl-2.5 pr-5 py-1.5 text-xs min-h-[32px]",
|
|
18
|
+
md: "pl-3 pr-6 py-2 text-sm min-h-[38px]",
|
|
19
|
+
xl: "pl-3.5 pr-7 py-2.5 text-base min-h-[42px]",
|
|
20
|
+
},
|
|
16
21
|
},
|
|
17
22
|
);
|
|
18
23
|
|
|
19
24
|
export const iconStyles = styles(
|
|
20
|
-
"pointer-events-none absolute
|
|
25
|
+
"pointer-events-none absolute top-1/2 -translate-y-1/2 select-none transition-transform duration-200 ease-in-out",
|
|
21
26
|
{
|
|
22
27
|
open: {
|
|
23
28
|
true: "rotate-180",
|
|
24
29
|
false: "",
|
|
25
30
|
},
|
|
31
|
+
size: {
|
|
32
|
+
sm: "h-3.5 w-3.5 right-1.5",
|
|
33
|
+
md: "h-4 w-4 right-2",
|
|
34
|
+
xl: "h-4 w-4 right-2.5",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export const deselectIconStyles = styles(
|
|
40
|
+
"absolute top-1/2 -translate-y-1/2 cursor-pointer z-10 text-gray-500 dark:text-gray-600 hover:text-black dark:hover:text-gray-400",
|
|
41
|
+
{
|
|
42
|
+
size: {
|
|
43
|
+
sm: "h-3.5 w-3.5 right-6",
|
|
44
|
+
md: "h-4 w-4 right-7",
|
|
45
|
+
xl: "h-4 w-4 right-8",
|
|
46
|
+
},
|
|
26
47
|
},
|
|
27
48
|
);
|
|
28
49
|
|
|
@@ -40,7 +61,7 @@ export const labelStyles = styles(
|
|
|
40
61
|
);
|
|
41
62
|
|
|
42
63
|
export const itemStyles = styles(
|
|
43
|
-
"relative
|
|
64
|
+
"relative rounded-1 cursor-pointer focus-visible:bg-gray-200 focus-visible:border-gray-100 hover:bg-gray-200 dark:focus-visible:bg-gray-900 dark:hover:bg-gray-900 dark:focus-visible:border-gray-600",
|
|
44
65
|
{
|
|
45
66
|
selected: {
|
|
46
67
|
true: "bg-gray-200 dark:bg-gray-900",
|
|
@@ -50,9 +71,41 @@ export const itemStyles = styles(
|
|
|
50
71
|
true: "pointer-events-none text-gray-500 dark:text-gray-700",
|
|
51
72
|
false: "",
|
|
52
73
|
},
|
|
74
|
+
size: {
|
|
75
|
+
sm: "py-1.5 px-2.5",
|
|
76
|
+
md: "py-2 px-3",
|
|
77
|
+
xl: "py-2.5 px-3.5",
|
|
78
|
+
},
|
|
53
79
|
},
|
|
54
80
|
);
|
|
55
81
|
|
|
82
|
+
export const listItemPaddingStyles = styles("", {
|
|
83
|
+
size: {
|
|
84
|
+
sm: "py-1.5 px-2.5",
|
|
85
|
+
md: "py-2 px-3",
|
|
86
|
+
xl: "py-2.5 px-3.5",
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export const dropdownPanelStyles = styles(
|
|
91
|
+
"scrollbar z-50 max-h-60 overflow-y-auto rounded-1 border border-gray-300 bg-white p-1 shadow-sm dark:border-gray-900 dark:bg-gray-1000",
|
|
92
|
+
{
|
|
93
|
+
size: {
|
|
94
|
+
sm: "text-xs",
|
|
95
|
+
md: "text-sm",
|
|
96
|
+
xl: "text-base",
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
export const checkIconStyles = styles("absolute", {
|
|
102
|
+
size: {
|
|
103
|
+
sm: "size-3.5 top-1.5 right-1.5",
|
|
104
|
+
md: "size-4 top-2 right-2",
|
|
105
|
+
xl: "size-5 top-2.5 right-2.5",
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
56
109
|
export const helperStyles = styles(
|
|
57
110
|
"transition-colors ease-in-out duration-150 text-xs",
|
|
58
111
|
{
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { UixyFieldSize } from "~/types/field";
|
|
2
|
+
|
|
1
3
|
export interface UixySelectOptionType {
|
|
2
4
|
label: string;
|
|
3
5
|
value?: string;
|
|
@@ -38,4 +40,5 @@ export type UixySelectProps = {
|
|
|
38
40
|
allowCustom?: boolean;
|
|
39
41
|
clearSearchOnSelect?: boolean;
|
|
40
42
|
followOnScroll?: boolean;
|
|
43
|
+
size?: UixyFieldSize;
|
|
41
44
|
} & (UixyMultipleSelectProps | UixySingleSelectProps);
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
itemStyles({
|
|
7
7
|
selected: isSelected(option),
|
|
8
8
|
disabled: !!option.disabled,
|
|
9
|
+
size: props.size ?? 'md',
|
|
9
10
|
})
|
|
10
11
|
"
|
|
11
12
|
:style="{
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
:multiple="multiple"
|
|
70
71
|
:search-term="searchTerm"
|
|
71
72
|
:original-options="originalOptions"
|
|
73
|
+
:size="size"
|
|
72
74
|
@toggle-expand="$emit('toggle-expand', $event)"
|
|
73
75
|
@select="$emit('select', $event)"
|
|
74
76
|
/>
|
|
@@ -81,6 +83,7 @@
|
|
|
81
83
|
import { motion, AnimatePresence } from "motion-v";
|
|
82
84
|
import { itemStyles } from "./Select.styles";
|
|
83
85
|
import type { UixySelectOptionType } from "./Select.types";
|
|
86
|
+
import type { UixyFieldSize } from "~/types/field";
|
|
84
87
|
import { UixyIcon } from "../Icon";
|
|
85
88
|
|
|
86
89
|
const props = defineProps<{
|
|
@@ -93,6 +96,7 @@
|
|
|
93
96
|
multiple?: boolean;
|
|
94
97
|
searchTerm?: string;
|
|
95
98
|
originalOptions?: UixySelectOptionType[];
|
|
99
|
+
size?: UixyFieldSize;
|
|
96
100
|
}>();
|
|
97
101
|
|
|
98
102
|
const emit = defineEmits<{
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
:max-length="props.maxLength"
|
|
12
12
|
:class="
|
|
13
13
|
textareaStyles(
|
|
14
|
-
{ status, noResize: !!props.noResize },
|
|
14
|
+
{ status, noResize: !!props.noResize, size },
|
|
15
15
|
$attrs.class as string,
|
|
16
16
|
)
|
|
17
17
|
"
|
|
@@ -74,6 +74,8 @@
|
|
|
74
74
|
props.disabled ? "disabled" : (props.status ?? "default"),
|
|
75
75
|
);
|
|
76
76
|
|
|
77
|
+
const size = computed(() => props.size ?? "md");
|
|
78
|
+
|
|
77
79
|
const text = computed(
|
|
78
80
|
() =>
|
|
79
81
|
({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import styles from "~/utils/styles";
|
|
2
2
|
|
|
3
3
|
export const textareaStyles = styles(
|
|
4
|
-
"peer transition-colors ease-in-out duration-150 border border-gray-300 dark:border-gray-900 rounded-1
|
|
4
|
+
"peer transition-colors ease-in-out duration-150 border border-gray-300 dark:border-gray-900 rounded-1 placeholder:text-gray-500 dark:placeholder:text-gray-700 dark:outline-gray-800 outline-offset-1 outline-gray-300 scrollbar",
|
|
5
5
|
{
|
|
6
6
|
status: {
|
|
7
7
|
default:
|
|
@@ -13,6 +13,11 @@ export const textareaStyles = styles(
|
|
|
13
13
|
valid:
|
|
14
14
|
"bg-white dark:bg-gray-1000 focus-visible:border-gray-500 dark:focus-visible:border-gray-600",
|
|
15
15
|
},
|
|
16
|
+
size: {
|
|
17
|
+
sm: "px-2.5 py-1.5 text-xs",
|
|
18
|
+
md: "px-3 py-2 text-sm",
|
|
19
|
+
xl: "px-3.5 py-2.5 text-base",
|
|
20
|
+
},
|
|
16
21
|
noResize: {
|
|
17
22
|
true: "resize-none",
|
|
18
23
|
false: "",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { UixyFieldSize } from "~/types/field";
|
|
2
|
+
|
|
1
3
|
export interface UixyTextareaProps {
|
|
2
4
|
status?: "valid" | "error" | "default";
|
|
3
5
|
label?: string;
|
|
@@ -10,4 +12,5 @@ export interface UixyTextareaProps {
|
|
|
10
12
|
noResize?: boolean;
|
|
11
13
|
rows?: number;
|
|
12
14
|
maxLength?: number;
|
|
15
|
+
size?: UixyFieldSize;
|
|
13
16
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type UixyFieldSize = "sm" | "md" | "xl";
|