@sewadah/selaras 0.8.0 → 0.9.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/README.md +1 -1
- package/dist/agent/catalog.json +1 -1
- package/dist/module.json +1 -1
- package/dist/runtime/components/Autocomplete.vue +6 -0
- package/dist/runtime/components/Input.d.vue.ts +7 -4
- package/dist/runtime/components/Input.vue +22 -5
- package/dist/runtime/components/Input.vue.d.ts +7 -4
- package/dist/runtime/components/Select.vue +6 -0
- package/dist/runtime/components/Textarea.d.vue.ts +7 -4
- package/dist/runtime/components/Textarea.vue +24 -7
- package/dist/runtime/components/Textarea.vue.d.ts +7 -4
- package/dist/runtime/internal/ComboboxSelectBase.d.vue.ts +7 -63
- package/dist/runtime/internal/ComboboxSelectBase.vue +18 -5
- package/dist/runtime/internal/ComboboxSelectBase.vue.d.ts +7 -63
- package/dist/runtime/theme/input.d.ts +6 -0
- package/dist/runtime/theme/input.js +2 -0
- package/dist/runtime/theme/select.d.ts +6 -0
- package/dist/runtime/theme/select.js +2 -0
- package/dist/runtime/theme/textarea.d.ts +6 -0
- package/dist/runtime/theme/textarea.js +2 -0
- package/dist/runtime/types/index.d.ts +1 -0
- package/dist/runtime/utils/field-adornments.d.ts +14 -0
- package/dist/runtime/utils/field-adornments.js +36 -0
- package/dist/runtime/utils/select-contracts.d.ts +3 -0
- package/package.json +5 -4
- package/skills/selaras/SKILL.md +7 -7
package/dist/module.json
CHANGED
|
@@ -69,6 +69,12 @@ const unscopedSlots = ["header", "footer", "empty", "empty-filter", "clear-icon"
|
|
|
69
69
|
@update:model-value="updateValue"
|
|
70
70
|
@update:search-term="emit('update:searchTerm', $event)"
|
|
71
71
|
>
|
|
72
|
+
<template v-if="slots.leading" #leading="scope">
|
|
73
|
+
<slot name="leading" v-bind="scope" />
|
|
74
|
+
</template>
|
|
75
|
+
<template v-if="slots.trailing" #trailing="scope">
|
|
76
|
+
<slot name="trailing" v-bind="scope" />
|
|
77
|
+
</template>
|
|
72
78
|
<template v-if="slots.item" #item="{ item }">
|
|
73
79
|
<slot name="item" :item="itemData(item)" />
|
|
74
80
|
</template>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
2
|
import type { InputThemeSlots } from '../theme/input.js';
|
|
3
3
|
import type { ColorRole } from '../utils/color-registry.js';
|
|
4
|
+
import type { FieldAdornmentSlotProps } from '../utils/field-adornments.js';
|
|
4
5
|
import type { UiProp } from '../utils/ui.js';
|
|
5
6
|
import { inputTheme } from '../theme/input.js';
|
|
6
7
|
type InputVariants = VariantProps<typeof inputTheme>;
|
|
8
|
+
type __VLS_Slots = InputSlots;
|
|
7
9
|
export interface InputProps {
|
|
8
10
|
id?: string;
|
|
9
11
|
name?: string;
|
|
@@ -23,10 +25,11 @@ export interface InputProps {
|
|
|
23
25
|
export interface InputEmits {
|
|
24
26
|
'update:modelValue': [value: string];
|
|
25
27
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'
|
|
29
|
-
|
|
28
|
+
export interface InputSlots {
|
|
29
|
+
'leading'?: (props: FieldAdornmentSlotProps) => any;
|
|
30
|
+
'trailing'?: (props: FieldAdornmentSlotProps) => any;
|
|
31
|
+
'clear-icon'?: () => any;
|
|
32
|
+
}
|
|
30
33
|
declare const __VLS_base: import("vue").DefineComponent<InputProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
31
34
|
"update:modelValue": (value: string) => any;
|
|
32
35
|
}, string, import("vue").PublicProps, Readonly<InputProps> & Readonly<{
|
|
@@ -4,6 +4,7 @@ import { useFormField } from "../composables/use-form-field";
|
|
|
4
4
|
import { useIcons } from "../composables/use-icons";
|
|
5
5
|
import { useMessages } from "../composables/use-messages";
|
|
6
6
|
import { inputTheme } from "../theme/input";
|
|
7
|
+
import { useFieldAdornments } from "../utils/field-adornments";
|
|
7
8
|
import { isNativeInputA11yAttr, isNativeInputAttr } from "../utils/native-input";
|
|
8
9
|
import { resolveRegisteredColorRole } from "../utils/registered-colors";
|
|
9
10
|
import { resolveSlot, useComponentTheme, useFallthroughAttrs, useRootProps, useThemeProps } from "../utils/ui";
|
|
@@ -26,6 +27,8 @@ const props = defineProps({
|
|
|
26
27
|
ui: { type: Object, required: false }
|
|
27
28
|
});
|
|
28
29
|
const emit = defineEmits(["update:modelValue"]);
|
|
30
|
+
const slots = defineSlots();
|
|
31
|
+
const { leading, trailing, padding, clearOffset } = useFieldAdornments();
|
|
29
32
|
const field = useFormField();
|
|
30
33
|
const effectivePlaceholder = computed(() => props.placeholder || (field?.floatingLabel.value ? " " : void 0));
|
|
31
34
|
const inputId = computed(() => props.id ?? field?.id);
|
|
@@ -39,6 +42,8 @@ function clear() {
|
|
|
39
42
|
const themeProps = useThemeProps("input");
|
|
40
43
|
const effectiveSize = computed(() => props.size ?? field?.size ?? themeProps.value.size ?? "md");
|
|
41
44
|
const clearSize = computed(() => ({ sm: "sm", md: "sm", lg: "md" })[effectiveSize.value]);
|
|
45
|
+
const adornmentScope = computed(() => ({ disabled: !!props.disabled, size: effectiveSize.value, buttonSize: clearSize.value }));
|
|
46
|
+
const clearWidth = computed(() => ({ sm: "1.75rem", md: "2.25rem", lg: "2.5rem" })[effectiveSize.value]);
|
|
42
47
|
const icons = useIcons();
|
|
43
48
|
const messages = useMessages();
|
|
44
49
|
const theme = useComponentTheme("input", inputTheme);
|
|
@@ -55,11 +60,20 @@ const rootProps = useRootProps(() => ui.value.root, () => props.ui?.root, { excl
|
|
|
55
60
|
const nativeInputAttrs = useFallthroughAttrs(isInputAttr);
|
|
56
61
|
const baseProps = computed(() => resolveSlot(ui.value.base, props.ui?.base));
|
|
57
62
|
const inputProps = computed(() => mergeProps(baseProps.value, nativeInputAttrs.value));
|
|
63
|
+
function adornedInputProps() {
|
|
64
|
+
return mergeProps({ style: padding(!!slots.leading, !!slots.trailing, showClear.value ? clearWidth.value : "0rem") }, inputProps.value);
|
|
65
|
+
}
|
|
66
|
+
function clearProps() {
|
|
67
|
+
return mergeProps({ style: slots.trailing ? clearOffset() : void 0 }, resolveSlot(ui.value.clear, props.ui?.clear));
|
|
68
|
+
}
|
|
58
69
|
</script>
|
|
59
70
|
|
|
60
71
|
<template>
|
|
61
|
-
<div :data-selaras-color="inputInvalid ? 'danger' : effectiveColor" :data-selaras-field-leading="icon ? '' : void 0" v-bind="rootProps">
|
|
62
|
-
<
|
|
72
|
+
<div :data-selaras-color="inputInvalid ? 'danger' : effectiveColor" :data-selaras-field-leading="icon || slots.leading ? '' : void 0" v-bind="rootProps">
|
|
73
|
+
<fieldset v-if="slots.leading" ref="leading" :disabled="disabled" :inert="disabled || void 0" v-bind="resolveSlot(ui.leading, props.ui?.leading)">
|
|
74
|
+
<slot name="leading" v-bind="adornmentScope" />
|
|
75
|
+
</fieldset>
|
|
76
|
+
<Icon v-else-if="icon" :name="icon" v-bind="resolveSlot(ui.leadingIcon, props.ui?.leadingIcon)" />
|
|
63
77
|
<input
|
|
64
78
|
:id="inputId"
|
|
65
79
|
data-ui-group-item
|
|
@@ -70,7 +84,7 @@ const inputProps = computed(() => mergeProps(baseProps.value, nativeInputAttrs.v
|
|
|
70
84
|
:disabled="disabled"
|
|
71
85
|
:aria-invalid="inputInvalid || void 0"
|
|
72
86
|
:aria-describedby="describedBy"
|
|
73
|
-
v-bind="
|
|
87
|
+
v-bind="adornedInputProps()"
|
|
74
88
|
@input="$emit('update:modelValue', $event.target.value)"
|
|
75
89
|
>
|
|
76
90
|
<Button
|
|
@@ -79,7 +93,7 @@ const inputProps = computed(() => mergeProps(baseProps.value, nativeInputAttrs.v
|
|
|
79
93
|
variant="text"
|
|
80
94
|
color="neutral"
|
|
81
95
|
:aria-label="messages.clear"
|
|
82
|
-
v-bind="
|
|
96
|
+
v-bind="clearProps()"
|
|
83
97
|
@click="clear"
|
|
84
98
|
>
|
|
85
99
|
<template #icon="{ class: iconClass }">
|
|
@@ -88,6 +102,9 @@ const inputProps = computed(() => mergeProps(baseProps.value, nativeInputAttrs.v
|
|
|
88
102
|
</slot>
|
|
89
103
|
</template>
|
|
90
104
|
</Button>
|
|
91
|
-
<Icon v-else-if="trailingIcon" :name="trailingIcon" v-bind="resolveSlot(ui.trailingIcon, props.ui?.trailingIcon)" />
|
|
105
|
+
<Icon v-else-if="trailingIcon && !slots.trailing" :name="trailingIcon" v-bind="resolveSlot(ui.trailingIcon, props.ui?.trailingIcon)" />
|
|
106
|
+
<fieldset v-if="slots.trailing" ref="trailing" :disabled="disabled" :inert="disabled || void 0" v-bind="resolveSlot(ui.trailing, props.ui?.trailing)">
|
|
107
|
+
<slot name="trailing" v-bind="adornmentScope" />
|
|
108
|
+
</fieldset>
|
|
92
109
|
</div>
|
|
93
110
|
</template>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
2
|
import type { InputThemeSlots } from '../theme/input.js';
|
|
3
3
|
import type { ColorRole } from '../utils/color-registry.js';
|
|
4
|
+
import type { FieldAdornmentSlotProps } from '../utils/field-adornments.js';
|
|
4
5
|
import type { UiProp } from '../utils/ui.js';
|
|
5
6
|
import { inputTheme } from '../theme/input.js';
|
|
6
7
|
type InputVariants = VariantProps<typeof inputTheme>;
|
|
8
|
+
type __VLS_Slots = InputSlots;
|
|
7
9
|
export interface InputProps {
|
|
8
10
|
id?: string;
|
|
9
11
|
name?: string;
|
|
@@ -23,10 +25,11 @@ export interface InputProps {
|
|
|
23
25
|
export interface InputEmits {
|
|
24
26
|
'update:modelValue': [value: string];
|
|
25
27
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'
|
|
29
|
-
|
|
28
|
+
export interface InputSlots {
|
|
29
|
+
'leading'?: (props: FieldAdornmentSlotProps) => any;
|
|
30
|
+
'trailing'?: (props: FieldAdornmentSlotProps) => any;
|
|
31
|
+
'clear-icon'?: () => any;
|
|
32
|
+
}
|
|
30
33
|
declare const __VLS_base: import("vue").DefineComponent<InputProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
31
34
|
"update:modelValue": (value: string) => any;
|
|
32
35
|
}, string, import("vue").PublicProps, Readonly<InputProps> & Readonly<{
|
|
@@ -75,6 +75,12 @@ const unscopedSlots = ["header", "footer", "empty", "empty-filter", "filter-icon
|
|
|
75
75
|
@update:model-value="updateValue"
|
|
76
76
|
@update:search-term="emit('update:searchTerm', $event)"
|
|
77
77
|
>
|
|
78
|
+
<template v-if="slots.leading" #leading="scope">
|
|
79
|
+
<slot name="leading" v-bind="scope" />
|
|
80
|
+
</template>
|
|
81
|
+
<template v-if="slots.trailing" #trailing="scope">
|
|
82
|
+
<slot name="trailing" v-bind="scope" />
|
|
83
|
+
</template>
|
|
78
84
|
<template v-if="slots.item" #item="{ item }">
|
|
79
85
|
<slot name="item" :item="itemData(item)" />
|
|
80
86
|
</template>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
2
|
import type { TextareaThemeSlots } from '../theme/textarea.js';
|
|
3
3
|
import type { ColorRole } from '../utils/color-registry.js';
|
|
4
|
+
import type { FieldAdornmentSlotProps } from '../utils/field-adornments.js';
|
|
4
5
|
import type { UiProp } from '../utils/ui.js';
|
|
5
6
|
import { textareaTheme } from '../theme/textarea.js';
|
|
6
7
|
type TextareaVariants = VariantProps<typeof textareaTheme>;
|
|
8
|
+
type __VLS_Slots = TextareaSlots;
|
|
7
9
|
export interface TextareaProps {
|
|
8
10
|
id?: string;
|
|
9
11
|
name?: string;
|
|
@@ -27,10 +29,11 @@ export interface TextareaProps {
|
|
|
27
29
|
export interface TextareaEmits {
|
|
28
30
|
'update:modelValue': [value: string];
|
|
29
31
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
'
|
|
33
|
-
|
|
32
|
+
export interface TextareaSlots {
|
|
33
|
+
'leading'?: (props: FieldAdornmentSlotProps) => any;
|
|
34
|
+
'trailing'?: (props: FieldAdornmentSlotProps) => any;
|
|
35
|
+
'clear-icon'?: () => any;
|
|
36
|
+
}
|
|
34
37
|
declare const __VLS_base: import("vue").DefineComponent<TextareaProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
35
38
|
"update:modelValue": (value: string) => any;
|
|
36
39
|
}, string, import("vue").PublicProps, Readonly<TextareaProps> & Readonly<{
|
|
@@ -4,6 +4,7 @@ import { useFormField } from "../composables/use-form-field";
|
|
|
4
4
|
import { useIcons } from "../composables/use-icons";
|
|
5
5
|
import { useMessages } from "../composables/use-messages";
|
|
6
6
|
import { textareaTheme } from "../theme/textarea";
|
|
7
|
+
import { useFieldAdornments } from "../utils/field-adornments";
|
|
7
8
|
import { isNativeInputA11yAttr, isNativeInputAttr } from "../utils/native-input";
|
|
8
9
|
import { resolveRegisteredColorRole } from "../utils/registered-colors";
|
|
9
10
|
import { resolveSlot, useComponentTheme, useFallthroughAttrs, useRootProps } from "../utils/ui";
|
|
@@ -28,6 +29,8 @@ const props = defineProps({
|
|
|
28
29
|
ui: { type: Object, required: false }
|
|
29
30
|
});
|
|
30
31
|
const emit = defineEmits(["update:modelValue"]);
|
|
32
|
+
const slots = defineSlots();
|
|
33
|
+
const { leading, trailing, padding, clearOffset } = useFieldAdornments();
|
|
31
34
|
const field = useFormField();
|
|
32
35
|
const effectivePlaceholder = computed(() => props.placeholder || (field?.floatingLabel.value ? " " : void 0));
|
|
33
36
|
const textareaId = computed(() => props.id ?? field?.id);
|
|
@@ -40,6 +43,8 @@ function clear() {
|
|
|
40
43
|
}
|
|
41
44
|
const effectiveSize = computed(() => props.size ?? field?.size ?? "md");
|
|
42
45
|
const clearSize = computed(() => ({ sm: "sm", md: "sm", lg: "md" })[effectiveSize.value]);
|
|
46
|
+
const adornmentScope = computed(() => ({ disabled: !!props.disabled, size: effectiveSize.value, buttonSize: clearSize.value }));
|
|
47
|
+
const clearWidth = computed(() => ({ sm: "1.75rem", md: "2.25rem", lg: "2.5rem" })[effectiveSize.value]);
|
|
43
48
|
const icons = useIcons();
|
|
44
49
|
const messages = useMessages();
|
|
45
50
|
const theme = useComponentTheme("textarea", textareaTheme);
|
|
@@ -66,8 +71,8 @@ async function resize() {
|
|
|
66
71
|
if (props.maxrows) {
|
|
67
72
|
const cs = getComputedStyle(el);
|
|
68
73
|
const lineHeight = Number.parseFloat(cs.lineHeight);
|
|
69
|
-
const
|
|
70
|
-
const maxHeight = lineHeight * props.maxrows +
|
|
74
|
+
const padding2 = Number.parseFloat(cs.paddingTop) + Number.parseFloat(cs.paddingBottom);
|
|
75
|
+
const maxHeight = lineHeight * props.maxrows + padding2;
|
|
71
76
|
el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;
|
|
72
77
|
el.style.overflowY = el.scrollHeight > maxHeight ? "auto" : "hidden";
|
|
73
78
|
return;
|
|
@@ -76,11 +81,20 @@ async function resize() {
|
|
|
76
81
|
}
|
|
77
82
|
onMounted(resize);
|
|
78
83
|
watch(() => props.modelValue, resize);
|
|
84
|
+
function adornedInputProps() {
|
|
85
|
+
return mergeProps({ style: padding(!!slots.leading, !!slots.trailing, showClear.value ? clearWidth.value : "0rem") }, baseProps.value);
|
|
86
|
+
}
|
|
87
|
+
function clearProps() {
|
|
88
|
+
return mergeProps({ style: slots.trailing ? clearOffset() : void 0 }, resolveSlot(ui.value.clear, props.ui?.clear));
|
|
89
|
+
}
|
|
79
90
|
</script>
|
|
80
91
|
|
|
81
92
|
<template>
|
|
82
|
-
<div :data-selaras-color="textareaInvalid ? 'danger' : effectiveColor" :data-selaras-field-leading="icon ? '' : void 0" v-bind="rootProps">
|
|
83
|
-
<
|
|
93
|
+
<div :data-selaras-color="textareaInvalid ? 'danger' : effectiveColor" :data-selaras-field-leading="icon || slots.leading ? '' : void 0" v-bind="rootProps">
|
|
94
|
+
<fieldset v-if="slots.leading" ref="leading" :disabled="disabled" :inert="disabled || void 0" v-bind="resolveSlot(ui.leading, props.ui?.leading)">
|
|
95
|
+
<slot name="leading" v-bind="adornmentScope" />
|
|
96
|
+
</fieldset>
|
|
97
|
+
<Icon v-else-if="icon" :name="icon" v-bind="resolveSlot(ui.leadingIcon, props.ui?.leadingIcon)" />
|
|
84
98
|
<textarea
|
|
85
99
|
:id="textareaId"
|
|
86
100
|
ref="textareaRef"
|
|
@@ -92,7 +106,7 @@ watch(() => props.modelValue, resize);
|
|
|
92
106
|
:disabled="disabled"
|
|
93
107
|
:aria-invalid="textareaInvalid || void 0"
|
|
94
108
|
:aria-describedby="describedBy"
|
|
95
|
-
v-bind="
|
|
109
|
+
v-bind="adornedInputProps()"
|
|
96
110
|
@input="$emit('update:modelValue', $event.target.value);
|
|
97
111
|
resize()"
|
|
98
112
|
/>
|
|
@@ -102,7 +116,7 @@ watch(() => props.modelValue, resize);
|
|
|
102
116
|
variant="text"
|
|
103
117
|
color="neutral"
|
|
104
118
|
:aria-label="messages.clear"
|
|
105
|
-
v-bind="
|
|
119
|
+
v-bind="clearProps()"
|
|
106
120
|
@click="clear"
|
|
107
121
|
>
|
|
108
122
|
<template #icon="{ class: iconClass }">
|
|
@@ -111,6 +125,9 @@ watch(() => props.modelValue, resize);
|
|
|
111
125
|
</slot>
|
|
112
126
|
</template>
|
|
113
127
|
</Button>
|
|
114
|
-
<Icon v-else-if="trailingIcon" :name="trailingIcon" v-bind="resolveSlot(ui.trailingIcon, props.ui?.trailingIcon)" />
|
|
128
|
+
<Icon v-else-if="trailingIcon && !slots.trailing" :name="trailingIcon" v-bind="resolveSlot(ui.trailingIcon, props.ui?.trailingIcon)" />
|
|
129
|
+
<fieldset v-if="slots.trailing" ref="trailing" :disabled="disabled" :inert="disabled || void 0" v-bind="resolveSlot(ui.trailing, props.ui?.trailing)">
|
|
130
|
+
<slot name="trailing" v-bind="adornmentScope" />
|
|
131
|
+
</fieldset>
|
|
115
132
|
</div>
|
|
116
133
|
</template>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
2
|
import type { TextareaThemeSlots } from '../theme/textarea.js';
|
|
3
3
|
import type { ColorRole } from '../utils/color-registry.js';
|
|
4
|
+
import type { FieldAdornmentSlotProps } from '../utils/field-adornments.js';
|
|
4
5
|
import type { UiProp } from '../utils/ui.js';
|
|
5
6
|
import { textareaTheme } from '../theme/textarea.js';
|
|
6
7
|
type TextareaVariants = VariantProps<typeof textareaTheme>;
|
|
8
|
+
type __VLS_Slots = TextareaSlots;
|
|
7
9
|
export interface TextareaProps {
|
|
8
10
|
id?: string;
|
|
9
11
|
name?: string;
|
|
@@ -27,10 +29,11 @@ export interface TextareaProps {
|
|
|
27
29
|
export interface TextareaEmits {
|
|
28
30
|
'update:modelValue': [value: string];
|
|
29
31
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
'
|
|
33
|
-
|
|
32
|
+
export interface TextareaSlots {
|
|
33
|
+
'leading'?: (props: FieldAdornmentSlotProps) => any;
|
|
34
|
+
'trailing'?: (props: FieldAdornmentSlotProps) => any;
|
|
35
|
+
'clear-icon'?: () => any;
|
|
36
|
+
}
|
|
34
37
|
declare const __VLS_base: import("vue").DefineComponent<TextareaProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
35
38
|
"update:modelValue": (value: string) => any;
|
|
36
39
|
}, string, import("vue").PublicProps, Readonly<TextareaProps> & Readonly<{
|
|
@@ -2,12 +2,18 @@ import type { VariantProps } from 'tailwind-variants';
|
|
|
2
2
|
import type { SelectThemeSlots } from '../theme/select.js';
|
|
3
3
|
import type { RoundedArrowConfig } from '../utils/arrow.js';
|
|
4
4
|
import type { ColorRole } from '../utils/color-registry.js';
|
|
5
|
+
import type { FieldAdornmentSlotProps } from '../utils/field-adornments.js';
|
|
5
6
|
import type { OverlayPortal, OverlayPositioning } from '../utils/overlay.js';
|
|
6
7
|
import type { SelectModelValue } from '../utils/select-contracts.js';
|
|
7
8
|
import type { UiProp } from '../utils/ui.js';
|
|
8
|
-
import type { SelectItems
|
|
9
|
+
import type { SelectItems } from './combobox-select.js';
|
|
9
10
|
import { selectTheme } from '../theme/select.js';
|
|
10
11
|
type SelectVariants = VariantProps<typeof selectTheme>;
|
|
12
|
+
type __VLS_Slots = {
|
|
13
|
+
leading?: (props: FieldAdornmentSlotProps) => any;
|
|
14
|
+
trailing?: (props: FieldAdornmentSlotProps) => any;
|
|
15
|
+
[name: string]: ((props: any) => any) | undefined;
|
|
16
|
+
};
|
|
11
17
|
export interface ComboboxSelectBaseProps {
|
|
12
18
|
id?: string;
|
|
13
19
|
name?: string;
|
|
@@ -58,68 +64,6 @@ export interface ComboboxSelectBaseEmits {
|
|
|
58
64
|
'update:modelValue': [value: SelectModelValue | SelectModelValue[] | undefined];
|
|
59
65
|
'update:searchTerm': [value: string];
|
|
60
66
|
}
|
|
61
|
-
declare var __VLS_43: {
|
|
62
|
-
item: SelectModelValue | SelectOption<SelectModelValue>;
|
|
63
|
-
}, __VLS_98: {}, __VLS_105: {}, __VLS_120: {}, __VLS_136: {}, __VLS_143: {}, __VLS_150: {}, __VLS_174: {
|
|
64
|
-
item: SelectModelValue | SelectOption<SelectModelValue>;
|
|
65
|
-
}, __VLS_194: {
|
|
66
|
-
selected: import("./combobox-select.js").ResolvedOption | undefined;
|
|
67
|
-
}, __VLS_205: {}, __VLS_212: {}, __VLS_219: {}, __VLS_249: {}, __VLS_252: {}, __VLS_255: {}, __VLS_258: {}, __VLS_261: {
|
|
68
|
-
item: SelectModelValue | SelectOption<SelectModelValue>;
|
|
69
|
-
}, __VLS_264: {
|
|
70
|
-
group: import("./combobox-select.js").SelectOptionGroup<SelectModelValue>;
|
|
71
|
-
}, __VLS_267: {}, __VLS_305: string, __VLS_306: {}, __VLS_309: {}, __VLS_319: {
|
|
72
|
-
item: SelectModelValue | SelectOption<SelectModelValue>;
|
|
73
|
-
}, __VLS_322: {
|
|
74
|
-
group: import("./combobox-select.js").SelectOptionGroup<SelectModelValue>;
|
|
75
|
-
};
|
|
76
|
-
type __VLS_Slots = {} & {
|
|
77
|
-
[K in NonNullable<typeof __VLS_305>]?: (props: typeof __VLS_306) => any;
|
|
78
|
-
} & {
|
|
79
|
-
item?: (props: typeof __VLS_43) => any;
|
|
80
|
-
} & {
|
|
81
|
-
'clear-icon'?: (props: typeof __VLS_98) => any;
|
|
82
|
-
} & {
|
|
83
|
-
'loading-icon'?: (props: typeof __VLS_105) => any;
|
|
84
|
-
} & {
|
|
85
|
-
'dropdown-icon'?: (props: typeof __VLS_120) => any;
|
|
86
|
-
} & {
|
|
87
|
-
'clear-icon'?: (props: typeof __VLS_136) => any;
|
|
88
|
-
} & {
|
|
89
|
-
'loading-icon'?: (props: typeof __VLS_143) => any;
|
|
90
|
-
} & {
|
|
91
|
-
'dropdown-icon'?: (props: typeof __VLS_150) => any;
|
|
92
|
-
} & {
|
|
93
|
-
item?: (props: typeof __VLS_174) => any;
|
|
94
|
-
} & {
|
|
95
|
-
value?: (props: typeof __VLS_194) => any;
|
|
96
|
-
} & {
|
|
97
|
-
'clear-icon'?: (props: typeof __VLS_205) => any;
|
|
98
|
-
} & {
|
|
99
|
-
'loading-icon'?: (props: typeof __VLS_212) => any;
|
|
100
|
-
} & {
|
|
101
|
-
'dropdown-icon'?: (props: typeof __VLS_219) => any;
|
|
102
|
-
} & {
|
|
103
|
-
header?: (props: typeof __VLS_249) => any;
|
|
104
|
-
} & {
|
|
105
|
-
'filter-icon'?: (props: typeof __VLS_252) => any;
|
|
106
|
-
} & {
|
|
107
|
-
empty?: (props: typeof __VLS_255) => any;
|
|
108
|
-
} & {
|
|
109
|
-
'empty-filter'?: (props: typeof __VLS_258) => any;
|
|
110
|
-
} & {
|
|
111
|
-
item?: (props: typeof __VLS_261) => any;
|
|
112
|
-
} & {
|
|
113
|
-
group?: (props: typeof __VLS_264) => any;
|
|
114
|
-
} & {
|
|
115
|
-
footer?: (props: typeof __VLS_267) => any;
|
|
116
|
-
} & {
|
|
117
|
-
header?: (props: typeof __VLS_309) => any;
|
|
118
|
-
} & {
|
|
119
|
-
item?: (props: typeof __VLS_319) => any;
|
|
120
|
-
} & {
|
|
121
|
-
group?: (props: typeof __VLS_322) => any;
|
|
122
|
-
};
|
|
123
67
|
declare const __VLS_base: import("vue").DefineComponent<ComboboxSelectBaseProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
124
68
|
"update:modelValue": (value: SelectModelValue | SelectModelValue[] | undefined) => any;
|
|
125
69
|
"update:open": (value: boolean) => any;
|
|
@@ -28,10 +28,11 @@ import { useIsMobile } from "../composables/use-media-query";
|
|
|
28
28
|
import { useMessages } from "../composables/use-messages";
|
|
29
29
|
import { selectTheme } from "../theme/select";
|
|
30
30
|
import { arrowContentProps, arrowElementProps } from "../utils/arrow";
|
|
31
|
+
import { useFieldAdornments } from "../utils/field-adornments";
|
|
31
32
|
import { isNativeInputA11yAttr, isNativeInputAttr, isNativeInputEvent } from "../utils/native-input";
|
|
32
33
|
import { overlayPortalProps } from "../utils/overlay";
|
|
33
34
|
import { resolveRegisteredColorRole } from "../utils/registered-colors";
|
|
34
|
-
import { resolveSlot, useComponentTheme, useFallthroughAttrs, useRootProps, useThemeBindings } from "../utils/ui";
|
|
35
|
+
import { applyClassPrefix, resolveSlot, useComponentTheme, useFallthroughAttrs, useRootProps, useThemeBindings } from "../utils/ui";
|
|
35
36
|
import { useComboboxSelect } from "./combobox-select";
|
|
36
37
|
import ComboboxSelectBody from "./ComboboxSelectBody.vue";
|
|
37
38
|
defineOptions({ inheritAttrs: false });
|
|
@@ -72,6 +73,8 @@ const props = defineProps({
|
|
|
72
73
|
ui: { type: Object, required: false }
|
|
73
74
|
});
|
|
74
75
|
const emit = defineEmits(["update:open", "update:modelValue", "update:searchTerm"]);
|
|
76
|
+
const slots = defineSlots();
|
|
77
|
+
const { leading, trailing, padding } = useFieldAdornments();
|
|
75
78
|
const instance = getCurrentInstance();
|
|
76
79
|
const initialValue = Array.isArray(props.defaultValue) ? [...props.defaultValue] : props.defaultValue;
|
|
77
80
|
const isControlled = () => Object.hasOwn(instance.vnode.props ?? {}, "modelValue") || Object.hasOwn(instance.vnode.props ?? {}, "model-value");
|
|
@@ -413,6 +416,7 @@ const searchDescribedBy = computed(() => [
|
|
|
413
416
|
].filter(Boolean).join(" ") || void 0);
|
|
414
417
|
const effectiveSize = computed(() => props.size ?? field?.size ?? "md");
|
|
415
418
|
const clearSize = computed(() => ({ sm: "sm", md: "sm", lg: "md" })[effectiveSize.value]);
|
|
419
|
+
const adornmentScope = computed(() => ({ disabled: !!props.disabled, size: effectiveSize.value, buttonSize: clearSize.value }));
|
|
416
420
|
const icons = useIcons();
|
|
417
421
|
const messages = useMessages();
|
|
418
422
|
const theme = useComponentTheme("select", selectTheme);
|
|
@@ -427,6 +431,9 @@ const triggerProps = computed(() => mergeProps(
|
|
|
427
431
|
resolveSlot(ui.value.trigger, props.ui?.trigger),
|
|
428
432
|
!props.creatable ? nativeTriggerAttrs.value : {}
|
|
429
433
|
));
|
|
434
|
+
function adornedTriggerProps() {
|
|
435
|
+
return mergeProps({ style: padding(!!slots.leading, !!slots.trailing) }, triggerProps.value);
|
|
436
|
+
}
|
|
430
437
|
const valueProps = computed(() => resolveSlot(ui.value.value, props.ui?.value));
|
|
431
438
|
const commaValueProps = computed(() => {
|
|
432
439
|
const override = props.ui?.value;
|
|
@@ -596,7 +603,10 @@ const bodyProps = computed(() => ({
|
|
|
596
603
|
@update:open="updateOpen($event)"
|
|
597
604
|
@update:model-value="(value2) => onComboboxValueUpdate(value2)"
|
|
598
605
|
>
|
|
599
|
-
<ComboboxAnchor>
|
|
606
|
+
<ComboboxAnchor :class="applyClassPrefix('relative')">
|
|
607
|
+
<fieldset v-if="slots.leading" ref="leading" :disabled="disabled" :inert="disabled || void 0" v-bind="resolveSlot(ui.leading, props.ui?.leading)">
|
|
608
|
+
<slot name="leading" v-bind="adornmentScope" />
|
|
609
|
+
</fieldset>
|
|
600
610
|
<!--
|
|
601
611
|
Select (creatable=false): a button trigger, opened by clicking anywhere
|
|
602
612
|
on it - the search input (if any) lives inside the popover instead.
|
|
@@ -608,7 +618,7 @@ const bodyProps = computed(() => ({
|
|
|
608
618
|
data-ui-group-item
|
|
609
619
|
:data-selaras-field-filled="selectedValues.length ? '' : void 0"
|
|
610
620
|
:data-selaras-field-active="open ? '' : void 0"
|
|
611
|
-
v-bind="
|
|
621
|
+
v-bind="adornedTriggerProps()"
|
|
612
622
|
@keydown.capture="onSearchKeydown"
|
|
613
623
|
>
|
|
614
624
|
<!--
|
|
@@ -745,7 +755,7 @@ const bodyProps = computed(() => ({
|
|
|
745
755
|
data-ui-group-item
|
|
746
756
|
:data-selaras-field-filled="selectedValues.length ? '' : void 0"
|
|
747
757
|
:data-selaras-field-active="open ? '' : void 0"
|
|
748
|
-
v-bind="
|
|
758
|
+
v-bind="adornedTriggerProps()"
|
|
749
759
|
@click="openMobileAutocomplete()"
|
|
750
760
|
>
|
|
751
761
|
<span v-if="multiple && selectedOptions.length" v-bind="commaValueProps">{{ commaText }}</span>
|
|
@@ -794,7 +804,7 @@ const bodyProps = computed(() => ({
|
|
|
794
804
|
:aria-invalid="selectInvalid || void 0"
|
|
795
805
|
:aria-describedby="describedBy"
|
|
796
806
|
:aria-busy="loading || void 0"
|
|
797
|
-
v-bind="mergeProps(
|
|
807
|
+
v-bind="mergeProps(adornedTriggerProps(), modalTriggerAttrs)"
|
|
798
808
|
tabindex="0"
|
|
799
809
|
@keydown="onTriggerKeydown"
|
|
800
810
|
@blur="selectedChipValue = void 0"
|
|
@@ -894,6 +904,9 @@ const bodyProps = computed(() => ({
|
|
|
894
904
|
</template>
|
|
895
905
|
<span v-if="loading" class="sr-only">{{ messages.loading }}</span>
|
|
896
906
|
</ComboboxTrigger>
|
|
907
|
+
<fieldset v-if="slots.trailing" ref="trailing" :disabled="disabled" :inert="disabled || void 0" v-bind="resolveSlot(ui.trailing, props.ui?.trailing)">
|
|
908
|
+
<slot name="trailing" v-bind="adornmentScope" />
|
|
909
|
+
</fieldset>
|
|
897
910
|
</ComboboxAnchor>
|
|
898
911
|
|
|
899
912
|
<ComboboxPortal v-if="!showMobileModal" v-bind="portalProps">
|
|
@@ -2,12 +2,18 @@ import type { VariantProps } from 'tailwind-variants';
|
|
|
2
2
|
import type { SelectThemeSlots } from '../theme/select.js';
|
|
3
3
|
import type { RoundedArrowConfig } from '../utils/arrow.js';
|
|
4
4
|
import type { ColorRole } from '../utils/color-registry.js';
|
|
5
|
+
import type { FieldAdornmentSlotProps } from '../utils/field-adornments.js';
|
|
5
6
|
import type { OverlayPortal, OverlayPositioning } from '../utils/overlay.js';
|
|
6
7
|
import type { SelectModelValue } from '../utils/select-contracts.js';
|
|
7
8
|
import type { UiProp } from '../utils/ui.js';
|
|
8
|
-
import type { SelectItems
|
|
9
|
+
import type { SelectItems } from './combobox-select.js';
|
|
9
10
|
import { selectTheme } from '../theme/select.js';
|
|
10
11
|
type SelectVariants = VariantProps<typeof selectTheme>;
|
|
12
|
+
type __VLS_Slots = {
|
|
13
|
+
leading?: (props: FieldAdornmentSlotProps) => any;
|
|
14
|
+
trailing?: (props: FieldAdornmentSlotProps) => any;
|
|
15
|
+
[name: string]: ((props: any) => any) | undefined;
|
|
16
|
+
};
|
|
11
17
|
export interface ComboboxSelectBaseProps {
|
|
12
18
|
id?: string;
|
|
13
19
|
name?: string;
|
|
@@ -58,68 +64,6 @@ export interface ComboboxSelectBaseEmits {
|
|
|
58
64
|
'update:modelValue': [value: SelectModelValue | SelectModelValue[] | undefined];
|
|
59
65
|
'update:searchTerm': [value: string];
|
|
60
66
|
}
|
|
61
|
-
declare var __VLS_43: {
|
|
62
|
-
item: SelectModelValue | SelectOption<SelectModelValue>;
|
|
63
|
-
}, __VLS_98: {}, __VLS_105: {}, __VLS_120: {}, __VLS_136: {}, __VLS_143: {}, __VLS_150: {}, __VLS_174: {
|
|
64
|
-
item: SelectModelValue | SelectOption<SelectModelValue>;
|
|
65
|
-
}, __VLS_194: {
|
|
66
|
-
selected: import("./combobox-select.js").ResolvedOption | undefined;
|
|
67
|
-
}, __VLS_205: {}, __VLS_212: {}, __VLS_219: {}, __VLS_249: {}, __VLS_252: {}, __VLS_255: {}, __VLS_258: {}, __VLS_261: {
|
|
68
|
-
item: SelectModelValue | SelectOption<SelectModelValue>;
|
|
69
|
-
}, __VLS_264: {
|
|
70
|
-
group: import("./combobox-select.js").SelectOptionGroup<SelectModelValue>;
|
|
71
|
-
}, __VLS_267: {}, __VLS_305: string, __VLS_306: {}, __VLS_309: {}, __VLS_319: {
|
|
72
|
-
item: SelectModelValue | SelectOption<SelectModelValue>;
|
|
73
|
-
}, __VLS_322: {
|
|
74
|
-
group: import("./combobox-select.js").SelectOptionGroup<SelectModelValue>;
|
|
75
|
-
};
|
|
76
|
-
type __VLS_Slots = {} & {
|
|
77
|
-
[K in NonNullable<typeof __VLS_305>]?: (props: typeof __VLS_306) => any;
|
|
78
|
-
} & {
|
|
79
|
-
item?: (props: typeof __VLS_43) => any;
|
|
80
|
-
} & {
|
|
81
|
-
'clear-icon'?: (props: typeof __VLS_98) => any;
|
|
82
|
-
} & {
|
|
83
|
-
'loading-icon'?: (props: typeof __VLS_105) => any;
|
|
84
|
-
} & {
|
|
85
|
-
'dropdown-icon'?: (props: typeof __VLS_120) => any;
|
|
86
|
-
} & {
|
|
87
|
-
'clear-icon'?: (props: typeof __VLS_136) => any;
|
|
88
|
-
} & {
|
|
89
|
-
'loading-icon'?: (props: typeof __VLS_143) => any;
|
|
90
|
-
} & {
|
|
91
|
-
'dropdown-icon'?: (props: typeof __VLS_150) => any;
|
|
92
|
-
} & {
|
|
93
|
-
item?: (props: typeof __VLS_174) => any;
|
|
94
|
-
} & {
|
|
95
|
-
value?: (props: typeof __VLS_194) => any;
|
|
96
|
-
} & {
|
|
97
|
-
'clear-icon'?: (props: typeof __VLS_205) => any;
|
|
98
|
-
} & {
|
|
99
|
-
'loading-icon'?: (props: typeof __VLS_212) => any;
|
|
100
|
-
} & {
|
|
101
|
-
'dropdown-icon'?: (props: typeof __VLS_219) => any;
|
|
102
|
-
} & {
|
|
103
|
-
header?: (props: typeof __VLS_249) => any;
|
|
104
|
-
} & {
|
|
105
|
-
'filter-icon'?: (props: typeof __VLS_252) => any;
|
|
106
|
-
} & {
|
|
107
|
-
empty?: (props: typeof __VLS_255) => any;
|
|
108
|
-
} & {
|
|
109
|
-
'empty-filter'?: (props: typeof __VLS_258) => any;
|
|
110
|
-
} & {
|
|
111
|
-
item?: (props: typeof __VLS_261) => any;
|
|
112
|
-
} & {
|
|
113
|
-
group?: (props: typeof __VLS_264) => any;
|
|
114
|
-
} & {
|
|
115
|
-
footer?: (props: typeof __VLS_267) => any;
|
|
116
|
-
} & {
|
|
117
|
-
header?: (props: typeof __VLS_309) => any;
|
|
118
|
-
} & {
|
|
119
|
-
item?: (props: typeof __VLS_319) => any;
|
|
120
|
-
} & {
|
|
121
|
-
group?: (props: typeof __VLS_322) => any;
|
|
122
|
-
};
|
|
123
67
|
declare const __VLS_base: import("vue").DefineComponent<ComboboxSelectBaseProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
124
68
|
"update:modelValue": (value: SelectModelValue | SelectModelValue[] | undefined) => any;
|
|
125
69
|
"update:open": (value: boolean) => any;
|
|
@@ -42,6 +42,8 @@ export declare const inputTheme: import("tailwind-variants").TVReturnType<{
|
|
|
42
42
|
}, {
|
|
43
43
|
root: string;
|
|
44
44
|
base: string;
|
|
45
|
+
leading: string;
|
|
46
|
+
trailing: string;
|
|
45
47
|
leadingIcon: string;
|
|
46
48
|
trailingIcon: string;
|
|
47
49
|
clear: string;
|
|
@@ -89,6 +91,8 @@ export declare const inputTheme: import("tailwind-variants").TVReturnType<{
|
|
|
89
91
|
}, {
|
|
90
92
|
root: string;
|
|
91
93
|
base: string;
|
|
94
|
+
leading: string;
|
|
95
|
+
trailing: string;
|
|
92
96
|
leadingIcon: string;
|
|
93
97
|
trailingIcon: string;
|
|
94
98
|
clear: string;
|
|
@@ -136,6 +140,8 @@ export declare const inputTheme: import("tailwind-variants").TVReturnType<{
|
|
|
136
140
|
}, {
|
|
137
141
|
root: string;
|
|
138
142
|
base: string;
|
|
143
|
+
leading: string;
|
|
144
|
+
trailing: string;
|
|
139
145
|
leadingIcon: string;
|
|
140
146
|
trailingIcon: string;
|
|
141
147
|
clear: string;
|
|
@@ -10,6 +10,8 @@ export const inputTheme = tv({
|
|
|
10
10
|
// hardcoded here - hover's own color stays neutral regardless of
|
|
11
11
|
// `color`, matching every other component's own hover state.
|
|
12
12
|
base: "w-full rounded-[var(--selaras-resolved-radius-md)] bg-[var(--selaras-resolved-surface-default)] text-[var(--selaras-resolved-text-default)] ring-1 ring-inset ring-[var(--selaras-resolved-border-default)] placeholder:text-[var(--selaras-resolved-text-muted)] outline-none transition-[color,background-color,box-shadow] not-focus:hover:ring-[var(--selaras-resolved-border-hover)] hover:bg-[var(--selaras-resolved-surface-elevated)] focus:ring-2 focus:ring-[var(--_selaras-color-focus)] disabled:opacity-50 disabled:pointer-events-none",
|
|
13
|
+
leading: "absolute top-1/2 -translate-y-1/2 start-0 m-0 flex min-w-0 items-center gap-1 border-0 p-0 ps-2.5 text-sm text-[var(--selaras-resolved-text-muted)] disabled:opacity-50",
|
|
14
|
+
trailing: "absolute top-1/2 -translate-y-1/2 end-0 m-0 flex min-w-0 items-center gap-1 border-0 p-0 pe-1 text-sm text-[var(--selaras-resolved-text-muted)] disabled:opacity-50",
|
|
13
15
|
leadingIcon: "absolute start-2.5 shrink-0 text-[var(--selaras-resolved-text-muted)]",
|
|
14
16
|
trailingIcon: "absolute end-2.5 shrink-0 text-[var(--selaras-resolved-text-muted)]",
|
|
15
17
|
// A separate slot from trailingIcon (not reused) - that one is a
|
|
@@ -29,6 +29,8 @@ export declare const selectTheme: import("tailwind-variants").TVReturnType<{
|
|
|
29
29
|
}, {
|
|
30
30
|
root: string;
|
|
31
31
|
trigger: string;
|
|
32
|
+
leading: string;
|
|
33
|
+
trailing: string;
|
|
32
34
|
value: string;
|
|
33
35
|
chipOverflow: string;
|
|
34
36
|
icon: string;
|
|
@@ -76,6 +78,8 @@ export declare const selectTheme: import("tailwind-variants").TVReturnType<{
|
|
|
76
78
|
}, {
|
|
77
79
|
root: string;
|
|
78
80
|
trigger: string;
|
|
81
|
+
leading: string;
|
|
82
|
+
trailing: string;
|
|
79
83
|
value: string;
|
|
80
84
|
chipOverflow: string;
|
|
81
85
|
icon: string;
|
|
@@ -123,6 +127,8 @@ export declare const selectTheme: import("tailwind-variants").TVReturnType<{
|
|
|
123
127
|
}, {
|
|
124
128
|
root: string;
|
|
125
129
|
trigger: string;
|
|
130
|
+
leading: string;
|
|
131
|
+
trailing: string;
|
|
126
132
|
value: string;
|
|
127
133
|
chipOverflow: string;
|
|
128
134
|
icon: string;
|