@nuxt/ui 4.11.0 → 4.11.2
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 +3 -3
- package/dist/module.json +1 -1
- package/dist/module.mjs +2 -2
- package/dist/runtime/components/Accordion.d.vue.ts +1 -1
- package/dist/runtime/components/Accordion.vue.d.ts +1 -1
- package/dist/runtime/components/Breadcrumb.d.vue.ts +1 -1
- package/dist/runtime/components/Breadcrumb.vue.d.ts +1 -1
- package/dist/runtime/components/Carousel.d.vue.ts +7 -7
- package/dist/runtime/components/Carousel.vue.d.ts +7 -7
- package/dist/runtime/components/ChatMessages.d.vue.ts +2 -2
- package/dist/runtime/components/ChatMessages.vue.d.ts +2 -2
- package/dist/runtime/components/CheckboxGroup.d.vue.ts +1 -1
- package/dist/runtime/components/CheckboxGroup.vue.d.ts +1 -1
- package/dist/runtime/components/CommandPalette.d.vue.ts +1 -1
- package/dist/runtime/components/CommandPalette.vue.d.ts +1 -1
- package/dist/runtime/components/ContextMenu.d.vue.ts +1 -1
- package/dist/runtime/components/ContextMenu.vue.d.ts +1 -1
- package/dist/runtime/components/DashboardNavbar.vue +1 -1
- package/dist/runtime/components/DropdownMenu.d.vue.ts +1 -1
- package/dist/runtime/components/DropdownMenu.vue.d.ts +1 -1
- package/dist/runtime/components/FooterColumns.d.vue.ts +1 -1
- package/dist/runtime/components/FooterColumns.vue.d.ts +1 -1
- package/dist/runtime/components/Form.vue +2 -2
- package/dist/runtime/components/Input.vue +5 -5
- package/dist/runtime/components/InputDate.vue +12 -6
- package/dist/runtime/components/InputMenu.d.vue.ts +1 -1
- package/dist/runtime/components/InputMenu.vue +18 -7
- package/dist/runtime/components/InputMenu.vue.d.ts +1 -1
- package/dist/runtime/components/InputNumber.vue +8 -5
- package/dist/runtime/components/InputTime.vue +12 -6
- package/dist/runtime/components/Link.vue +61 -7
- package/dist/runtime/components/LinkBase.vue +3 -1
- package/dist/runtime/components/Listbox.d.vue.ts +1 -1
- package/dist/runtime/components/Listbox.vue.d.ts +1 -1
- package/dist/runtime/components/NavigationMenu.d.vue.ts +1 -1
- package/dist/runtime/components/NavigationMenu.vue +10 -10
- package/dist/runtime/components/NavigationMenu.vue.d.ts +1 -1
- package/dist/runtime/components/PageAnchors.d.vue.ts +1 -1
- package/dist/runtime/components/PageAnchors.vue.d.ts +1 -1
- package/dist/runtime/components/PageLinks.d.vue.ts +1 -1
- package/dist/runtime/components/PageLinks.vue.d.ts +1 -1
- package/dist/runtime/components/PinInput.d.vue.ts +3 -1
- package/dist/runtime/components/PinInput.vue +15 -7
- package/dist/runtime/components/PinInput.vue.d.ts +3 -1
- package/dist/runtime/components/ProgressGroup.d.vue.ts +1 -1
- package/dist/runtime/components/ProgressGroup.vue.d.ts +1 -1
- package/dist/runtime/components/RadioGroup.d.vue.ts +1 -1
- package/dist/runtime/components/RadioGroup.vue.d.ts +1 -1
- package/dist/runtime/components/Select.d.vue.ts +3 -1
- package/dist/runtime/components/Select.vue +2 -0
- package/dist/runtime/components/Select.vue.d.ts +3 -1
- package/dist/runtime/components/SelectMenu.d.vue.ts +4 -1
- package/dist/runtime/components/SelectMenu.vue +24 -4
- package/dist/runtime/components/SelectMenu.vue.d.ts +4 -1
- package/dist/runtime/components/Slider.vue +1 -1
- package/dist/runtime/components/Splitter.d.vue.ts +1 -1
- package/dist/runtime/components/Splitter.vue.d.ts +1 -1
- package/dist/runtime/components/Stepper.d.vue.ts +1 -1
- package/dist/runtime/components/Stepper.vue.d.ts +1 -1
- package/dist/runtime/components/Table.vue +29 -7
- package/dist/runtime/components/Tabs.d.vue.ts +1 -1
- package/dist/runtime/components/Tabs.vue.d.ts +1 -1
- package/dist/runtime/components/Textarea.vue +5 -5
- package/dist/runtime/components/Timeline.d.vue.ts +1 -1
- package/dist/runtime/components/Timeline.vue.d.ts +1 -1
- package/dist/runtime/components/Toaster.vue +1 -1
- package/dist/runtime/components/Tree.d.vue.ts +1 -1
- package/dist/runtime/components/Tree.vue +1 -1
- package/dist/runtime/components/Tree.vue.d.ts +1 -1
- package/dist/runtime/components/color-mode/ColorModeSelect.vue +1 -0
- package/dist/runtime/components/content/ContentNavigation.d.vue.ts +1 -1
- package/dist/runtime/components/content/ContentNavigation.vue.d.ts +1 -1
- package/dist/runtime/components/content/ContentSurround.d.vue.ts +1 -1
- package/dist/runtime/components/content/ContentSurround.vue.d.ts +1 -1
- package/dist/runtime/components/content/ContentToc.d.vue.ts +1 -1
- package/dist/runtime/components/content/ContentToc.vue.d.ts +1 -1
- package/dist/runtime/components/locale/LocaleSelect.vue +1 -0
- package/dist/runtime/components/prose/CodeTree.vue +31 -18
- package/dist/runtime/composables/useForwardProps.js +2 -2
- package/dist/runtime/composables/useResizable.js +1 -1
- package/dist/runtime/utils/form.d.ts +1 -1
- package/dist/runtime/utils/form.js +3 -1
- package/dist/runtime/utils/prefetch.d.ts +5 -0
- package/dist/runtime/utils/prefetch.js +45 -0
- package/dist/runtime/utils/search.js +8 -6
- package/dist/runtime/utils/virtualizer.d.ts +1 -1
- package/dist/runtime/utils/virtualizer.js +9 -11
- package/dist/runtime/vue/components/color-mode/ColorModeSelect.vue +1 -0
- package/dist/runtime/vue/overrides/inertia/LinkBase.vue +3 -1
- package/dist/shared/{ui.DNq7CNkE.mjs → ui.oNygBd3N.mjs} +40 -12
- package/dist/unplugin.d.mts +2 -1
- package/dist/unplugin.mjs +22 -10
- package/dist/vite.mjs +1 -1
- package/package.json +79 -83
- package/cli/commands/make/component.mjs +0 -86
- package/cli/commands/make/index.mjs +0 -14
- package/cli/commands/make/locale.mjs +0 -93
- package/cli/index.mjs +0 -15
- package/cli/package.json +0 -13
- package/cli/templates.mjs +0 -256
- package/cli/utils.mjs +0 -50
|
@@ -3,16 +3,17 @@ import theme from "#build/ui/link";
|
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
5
|
<script setup>
|
|
6
|
-
import { computed } from "vue";
|
|
6
|
+
import { computed, getCurrentInstance, mergeProps, onMounted, onBeforeUnmount } from "vue";
|
|
7
7
|
import { isEqual } from "ohash/utils";
|
|
8
8
|
import { useForwardProps, Slot } from "reka-ui";
|
|
9
9
|
import { defu } from "defu";
|
|
10
10
|
import { hasProtocol } from "ufo";
|
|
11
11
|
import { reactiveOmit } from "@vueuse/core";
|
|
12
|
-
import { useRoute, useAppConfig, useNuxtApp } from "#imports";
|
|
12
|
+
import { useRoute, useAppConfig, useNuxtApp, onNuxtReady } from "#imports";
|
|
13
13
|
import { mergeClasses } from "../utils";
|
|
14
14
|
import { tv } from "../utils/tv";
|
|
15
15
|
import { isPartiallyEqual } from "../utils/link";
|
|
16
|
+
import { requestIdleCallback, cancelIdleCallback, observeIntersection } from "../utils/prefetch";
|
|
16
17
|
import ULinkBase from "./LinkBase.vue";
|
|
17
18
|
defineOptions({ inheritAttrs: false });
|
|
18
19
|
const props = defineProps({
|
|
@@ -126,13 +127,63 @@ function isLinkActive({ route: linkRoute, isActive, isExactActive } = {}) {
|
|
|
126
127
|
}
|
|
127
128
|
return false;
|
|
128
129
|
}
|
|
129
|
-
function resolveLinkClass({ route: route2, isActive, isExactActive } = {}) {
|
|
130
|
+
function resolveLinkClass({ route: route2, isActive, isExactActive, prefetched } = {}) {
|
|
130
131
|
const active = isLinkActive({ route: route2, isActive, isExactActive });
|
|
132
|
+
const prefetchedClass = prefetched ? props.prefetchedClass : void 0;
|
|
131
133
|
if (props.raw) {
|
|
132
|
-
return [props.class, active ? props.activeClass : props.inactiveClass];
|
|
134
|
+
return [props.class, active ? props.activeClass : props.inactiveClass, prefetchedClass];
|
|
133
135
|
}
|
|
134
|
-
return ui.value({ class: props.class, active, disabled: props.disabled });
|
|
136
|
+
return ui.value({ class: prefetchedClass ? [props.class, prefetchedClass] : props.class, active, disabled: props.disabled });
|
|
135
137
|
}
|
|
138
|
+
const instance = getCurrentInstance();
|
|
139
|
+
let prefetchApi;
|
|
140
|
+
function onPrefetch() {
|
|
141
|
+
prefetchApi?.prefetch?.(nuxtApp);
|
|
142
|
+
}
|
|
143
|
+
function getPrefetchListeners({ prefetch, shouldPrefetch }, attrs) {
|
|
144
|
+
if (!prefetch || !shouldPrefetch) {
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
prefetchApi = { prefetch, shouldPrefetch };
|
|
148
|
+
if (!shouldPrefetch("interaction")) {
|
|
149
|
+
return void 0;
|
|
150
|
+
}
|
|
151
|
+
return mergeProps(
|
|
152
|
+
{ onPointerenter: attrs.onPointerenter, onFocus: attrs.onFocus },
|
|
153
|
+
{ onPointerenter: onPrefetch, onFocus: onPrefetch }
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
let idleId;
|
|
157
|
+
let unobserve = null;
|
|
158
|
+
let unmounted = false;
|
|
159
|
+
onMounted(() => {
|
|
160
|
+
if (!prefetchApi?.shouldPrefetch?.("visibility")) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const root = instance?.proxy?.$el;
|
|
164
|
+
const el = root instanceof Element ? root : root?.nextElementSibling;
|
|
165
|
+
if (!el) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
onNuxtReady(() => {
|
|
169
|
+
if (unmounted) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
idleId = requestIdleCallback(() => {
|
|
173
|
+
unobserve = observeIntersection(el, () => {
|
|
174
|
+
unobserve?.();
|
|
175
|
+
unobserve = null;
|
|
176
|
+
onPrefetch();
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
onBeforeUnmount(() => {
|
|
182
|
+
unmounted = true;
|
|
183
|
+
cancelIdleCallback(idleId);
|
|
184
|
+
unobserve?.();
|
|
185
|
+
unobserve = null;
|
|
186
|
+
});
|
|
136
187
|
</script>
|
|
137
188
|
|
|
138
189
|
<template>
|
|
@@ -142,6 +193,8 @@ function resolveLinkClass({ route: route2, isActive, isExactActive } = {}) {
|
|
|
142
193
|
v-bind="{
|
|
143
194
|
...$attrs,
|
|
144
195
|
...exact && isExactActive ? { 'aria-current': props.ariaCurrentValue } : {},
|
|
196
|
+
...rest.prefetched && prefetchedClass ? { class: prefetchedClass } : {},
|
|
197
|
+
...getPrefetchListeners(rest, $attrs),
|
|
145
198
|
as,
|
|
146
199
|
type,
|
|
147
200
|
disabled,
|
|
@@ -166,9 +219,10 @@ function resolveLinkClass({ route: route2, isActive, isExactActive } = {}) {
|
|
|
166
219
|
navigate,
|
|
167
220
|
rel,
|
|
168
221
|
target: rest.target,
|
|
169
|
-
isExternal: rest.isExternal
|
|
222
|
+
isExternal: rest.isExternal,
|
|
223
|
+
...getPrefetchListeners(rest, $attrs)
|
|
170
224
|
}"
|
|
171
|
-
:class="resolveLinkClass({ route: linkRoute, isActive, isExactActive })"
|
|
225
|
+
:class="resolveLinkClass({ route: linkRoute, isActive, isExactActive, prefetched: rest.prefetched })"
|
|
172
226
|
>
|
|
173
227
|
<slot :active="isLinkActive({ route: linkRoute, isActive, isExactActive })" />
|
|
174
228
|
</ULinkBase>
|
|
@@ -22,14 +22,16 @@ function onClickWrapper(e) {
|
|
|
22
22
|
e.preventDefault();
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
+
const results = [];
|
|
25
26
|
if (props.onClick) {
|
|
26
27
|
for (const onClick of Array.isArray(props.onClick) ? props.onClick : [props.onClick]) {
|
|
27
|
-
onClick(e);
|
|
28
|
+
results.push(onClick(e));
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
if (props.href && props.navigate && !props.isExternal) {
|
|
31
32
|
props.navigate(e);
|
|
32
33
|
}
|
|
34
|
+
return Promise.all(results);
|
|
33
35
|
}
|
|
34
36
|
</script>
|
|
35
37
|
|
|
@@ -27,7 +27,7 @@ export interface ListboxItem {
|
|
|
27
27
|
disabled?: boolean;
|
|
28
28
|
onSelect?: (e: Event) => void;
|
|
29
29
|
class?: any;
|
|
30
|
-
ui?: Pick<Listbox['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatar' | 'itemLeadingAvatarSize' | 'itemLeadingChip' | 'itemLeadingChipSize' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'
|
|
30
|
+
ui?: Partial<Pick<Listbox['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatar' | 'itemLeadingAvatarSize' | 'itemLeadingChip' | 'itemLeadingChipSize' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'>>;
|
|
31
31
|
[key: string]: any;
|
|
32
32
|
}
|
|
33
33
|
export interface ListboxProps<T extends ArrayOrNested<ListboxItem> = ArrayOrNested<ListboxItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false, Mod extends Omit<ModelModifiers, 'lazy'> = Omit<ModelModifiers, 'lazy'>> extends Pick<ListboxRootProps, 'by' | 'disabled' | 'highlightOnHover' | 'name' | 'orientation' | 'required' | 'selectionBehavior'> {
|
|
@@ -27,7 +27,7 @@ export interface ListboxItem {
|
|
|
27
27
|
disabled?: boolean;
|
|
28
28
|
onSelect?: (e: Event) => void;
|
|
29
29
|
class?: any;
|
|
30
|
-
ui?: Pick<Listbox['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatar' | 'itemLeadingAvatarSize' | 'itemLeadingChip' | 'itemLeadingChipSize' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'
|
|
30
|
+
ui?: Partial<Pick<Listbox['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatar' | 'itemLeadingAvatarSize' | 'itemLeadingChip' | 'itemLeadingChipSize' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'>>;
|
|
31
31
|
[key: string]: any;
|
|
32
32
|
}
|
|
33
33
|
export interface ListboxProps<T extends ArrayOrNested<ListboxItem> = ArrayOrNested<ListboxItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false, Mod extends Omit<ModelModifiers, 'lazy'> = Omit<ModelModifiers, 'lazy'>> extends Pick<ListboxRootProps, 'by' | 'disabled' | 'highlightOnHover' | 'name' | 'orientation' | 'required' | 'selectionBehavior'> {
|
|
@@ -67,7 +67,7 @@ export interface NavigationMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'cu
|
|
|
67
67
|
open?: boolean;
|
|
68
68
|
onSelect?: (e: Event) => void;
|
|
69
69
|
class?: any;
|
|
70
|
-
ui?: Pick<NavigationMenu['slots'], 'item' | 'linkLeadingAvatarSize' | 'linkLeadingAvatar' | 'linkLeadingIcon' | 'linkLeadingChipSize' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkTrailing' | 'linkTrailingBadgeSize' | 'linkTrailingBadge' | 'linkTrailingIcon' | 'label' | 'link' | 'content' | 'childList' | 'childLabel' | 'childItem' | 'childLink' | 'childLinkIcon' | 'childLinkWrapper' | 'childLinkLabel' | 'childLinkLabelExternalIcon' | 'childLinkDescription'
|
|
70
|
+
ui?: Partial<Pick<NavigationMenu['slots'], 'item' | 'linkLeadingAvatarSize' | 'linkLeadingAvatar' | 'linkLeadingIcon' | 'linkLeadingChipSize' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkTrailing' | 'linkTrailingBadgeSize' | 'linkTrailingBadge' | 'linkTrailingIcon' | 'label' | 'link' | 'content' | 'childList' | 'childLabel' | 'childItem' | 'childLink' | 'childLinkIcon' | 'childLinkWrapper' | 'childLinkLabel' | 'childLinkLabelExternalIcon' | 'childLinkDescription'>>;
|
|
71
71
|
[key: string]: any;
|
|
72
72
|
}
|
|
73
73
|
type SingleOrMultipleType = 'single' | 'multiple';
|
|
@@ -106,13 +106,13 @@ function getAccordionDefaultValue(list, level = 0, listIndex = 0) {
|
|
|
106
106
|
}, []);
|
|
107
107
|
return props.type === "single" ? indexes[0] : indexes;
|
|
108
108
|
}
|
|
109
|
-
function onLinkTrailingClick(e, item) {
|
|
109
|
+
function onLinkTrailingClick(e, item, trailingTrigger) {
|
|
110
110
|
if (!item.children?.length) {
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
if (props.orientation === "horizontal") {
|
|
114
114
|
e.preventDefault();
|
|
115
|
-
} else if (props.orientation === "vertical" && !props.collapsed) {
|
|
115
|
+
} else if (props.orientation === "vertical" && !props.collapsed && trailingTrigger) {
|
|
116
116
|
e.preventDefault();
|
|
117
117
|
e.stopPropagation();
|
|
118
118
|
}
|
|
@@ -120,7 +120,7 @@ function onLinkTrailingClick(e, item) {
|
|
|
120
120
|
</script>
|
|
121
121
|
|
|
122
122
|
<template>
|
|
123
|
-
<DefineLinkTemplate v-slot="{ item, active, index }">
|
|
123
|
+
<DefineLinkTemplate v-slot="{ item, active, index, trailingTrigger }">
|
|
124
124
|
<slot :name="item.slot || 'item'" :item="item" :index="index" :active="active" :ui="ui">
|
|
125
125
|
<slot :name="item.slot ? `${item.slot}-leading` : 'item-leading'" :item="item" :active="active" :index="index" :ui="ui">
|
|
126
126
|
<UAvatar v-if="item.avatar" :size="item.ui?.linkLeadingAvatarSize || props.ui?.linkLeadingAvatarSize || ui.linkLeadingAvatarSize()" v-bind="item.avatar" data-slot="linkLeadingAvatar" :class="ui.linkLeadingAvatar({ class: [props.ui?.linkLeadingAvatar, item.ui?.linkLeadingAvatar], active, disabled: !!item.disabled })" />
|
|
@@ -149,12 +149,12 @@ function onLinkTrailingClick(e, item) {
|
|
|
149
149
|
</span>
|
|
150
150
|
|
|
151
151
|
<component
|
|
152
|
-
:is="props.orientation === 'vertical' && item.children?.length && !props.collapsed ? AccordionTrigger : 'span'"
|
|
152
|
+
:is="props.orientation === 'vertical' && item.children?.length && !props.collapsed && trailingTrigger ? AccordionTrigger : 'span'"
|
|
153
153
|
v-if="item.badge || item.badge === 0 || props.orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content']) || props.orientation === 'vertical' && item.children?.length || item.trailingIcon || !!slots[item.slot ? `${item.slot}-trailing` : 'item-trailing']"
|
|
154
|
-
:as="props.orientation === 'vertical' && item.children?.length && !props.collapsed ? 'span' : void 0"
|
|
154
|
+
:as="props.orientation === 'vertical' && item.children?.length && !props.collapsed && trailingTrigger ? 'span' : void 0"
|
|
155
155
|
data-slot="linkTrailing"
|
|
156
156
|
:class="ui.linkTrailing({ class: [props.ui?.linkTrailing, item.ui?.linkTrailing] })"
|
|
157
|
-
@click="(e) => onLinkTrailingClick(e, item)"
|
|
157
|
+
@click="(e) => onLinkTrailingClick(e, item, trailingTrigger)"
|
|
158
158
|
>
|
|
159
159
|
<slot :name="item.slot ? `${item.slot}-trailing` : 'item-trailing'" :item="item" :active="active" :index="index" :ui="ui">
|
|
160
160
|
<UBadge
|
|
@@ -182,7 +182,7 @@ function onLinkTrailingClick(e, item) {
|
|
|
182
182
|
:value="getItemValue(item, index, level, listIndex)"
|
|
183
183
|
>
|
|
184
184
|
<div v-if="props.orientation === 'vertical' && item.type === 'label' && !props.collapsed" data-slot="label" :class="ui.label({ class: [props.ui?.label, item.ui?.label, item.class] })">
|
|
185
|
-
<ReuseLinkTemplate :item="item" :index="index" />
|
|
185
|
+
<ReuseLinkTemplate :item="item" :index="index" :trailing-trigger="true" />
|
|
186
186
|
</div>
|
|
187
187
|
<ULink v-else-if="item.type !== 'label'" v-slot="{ active, ...slotProps }" v-bind="props.orientation === 'vertical' && item.children?.length && !props.collapsed && item.type === 'trigger' ? {} : pickLinkProps(item)" custom>
|
|
188
188
|
<component
|
|
@@ -194,7 +194,7 @@ function onLinkTrailingClick(e, item) {
|
|
|
194
194
|
>
|
|
195
195
|
<UPopover v-if="props.orientation === 'vertical' && props.collapsed && item.children?.length && (!!props.popover || !!item.popover)" v-bind="{ ...popoverProps, ...typeof item.popover === 'boolean' ? {} : item.popover || {} }" :ui="{ content: ui.content({ class: [props.ui?.content, item.ui?.content] }) }">
|
|
196
196
|
<ULinkBase v-bind="slotProps" data-slot="link" :class="ui.link({ class: [props.ui?.link, item.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: level > 0 })">
|
|
197
|
-
<ReuseLinkTemplate :item="item" :active="active || item.active" :index="index" />
|
|
197
|
+
<ReuseLinkTemplate :item="item" :active="active || item.active" :index="index" :trailing-trigger="!!slotProps.href" />
|
|
198
198
|
</ULinkBase>
|
|
199
199
|
|
|
200
200
|
<template #content="{ close }">
|
|
@@ -231,11 +231,11 @@ function onLinkTrailingClick(e, item) {
|
|
|
231
231
|
</UPopover>
|
|
232
232
|
<UTooltip v-else-if="props.orientation === 'vertical' && props.collapsed && (!!props.tooltip || !!item.tooltip) || props.orientation === 'horizontal' && !!item.tooltip" :text="get(item, props.labelKey)" v-bind="{ ...tooltipProps, ...typeof item.tooltip === 'boolean' ? {} : item.tooltip || {} }">
|
|
233
233
|
<ULinkBase v-bind="slotProps" data-slot="link" :class="ui.link({ class: [props.ui?.link, item.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: level > 0 })">
|
|
234
|
-
<ReuseLinkTemplate :item="item" :active="active || item.active" :index="index" />
|
|
234
|
+
<ReuseLinkTemplate :item="item" :active="active || item.active" :index="index" :trailing-trigger="!!slotProps.href" />
|
|
235
235
|
</ULinkBase>
|
|
236
236
|
</UTooltip>
|
|
237
237
|
<ULinkBase v-else v-bind="slotProps" data-slot="link" :class="ui.link({ class: [props.ui?.link, item.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: props.orientation === 'horizontal' || level > 0 })">
|
|
238
|
-
<ReuseLinkTemplate :item="item" :active="active || item.active" :index="index" />
|
|
238
|
+
<ReuseLinkTemplate :item="item" :active="active || item.active" :index="index" :trailing-trigger="!!slotProps.href" />
|
|
239
239
|
</ULinkBase>
|
|
240
240
|
</component>
|
|
241
241
|
|
|
@@ -67,7 +67,7 @@ export interface NavigationMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'cu
|
|
|
67
67
|
open?: boolean;
|
|
68
68
|
onSelect?: (e: Event) => void;
|
|
69
69
|
class?: any;
|
|
70
|
-
ui?: Pick<NavigationMenu['slots'], 'item' | 'linkLeadingAvatarSize' | 'linkLeadingAvatar' | 'linkLeadingIcon' | 'linkLeadingChipSize' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkTrailing' | 'linkTrailingBadgeSize' | 'linkTrailingBadge' | 'linkTrailingIcon' | 'label' | 'link' | 'content' | 'childList' | 'childLabel' | 'childItem' | 'childLink' | 'childLinkIcon' | 'childLinkWrapper' | 'childLinkLabel' | 'childLinkLabelExternalIcon' | 'childLinkDescription'
|
|
70
|
+
ui?: Partial<Pick<NavigationMenu['slots'], 'item' | 'linkLeadingAvatarSize' | 'linkLeadingAvatar' | 'linkLeadingIcon' | 'linkLeadingChipSize' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkTrailing' | 'linkTrailingBadgeSize' | 'linkTrailingBadge' | 'linkTrailingIcon' | 'label' | 'link' | 'content' | 'childList' | 'childLabel' | 'childItem' | 'childLink' | 'childLinkIcon' | 'childLinkWrapper' | 'childLinkLabel' | 'childLinkLabelExternalIcon' | 'childLinkDescription'>>;
|
|
71
71
|
[key: string]: any;
|
|
72
72
|
}
|
|
73
73
|
type SingleOrMultipleType = 'single' | 'multiple';
|
|
@@ -12,7 +12,7 @@ export interface PageAnchor extends Omit<LinkProps, 'custom'> {
|
|
|
12
12
|
*/
|
|
13
13
|
icon?: IconProps['name'];
|
|
14
14
|
class?: any;
|
|
15
|
-
ui?: Pick<PageAnchors['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeading' | 'linkLeadingIcon'
|
|
15
|
+
ui?: Partial<Pick<PageAnchors['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeading' | 'linkLeadingIcon'>>;
|
|
16
16
|
}
|
|
17
17
|
export interface PageAnchorsProps<T extends PageAnchor = PageAnchor> {
|
|
18
18
|
/**
|
|
@@ -12,7 +12,7 @@ export interface PageAnchor extends Omit<LinkProps, 'custom'> {
|
|
|
12
12
|
*/
|
|
13
13
|
icon?: IconProps['name'];
|
|
14
14
|
class?: any;
|
|
15
|
-
ui?: Pick<PageAnchors['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeading' | 'linkLeadingIcon'
|
|
15
|
+
ui?: Partial<Pick<PageAnchors['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeading' | 'linkLeadingIcon'>>;
|
|
16
16
|
}
|
|
17
17
|
export interface PageAnchorsProps<T extends PageAnchor = PageAnchor> {
|
|
18
18
|
/**
|
|
@@ -12,7 +12,7 @@ export interface PageLink extends Omit<LinkProps, 'custom'> {
|
|
|
12
12
|
*/
|
|
13
13
|
icon?: IconProps['name'];
|
|
14
14
|
class?: any;
|
|
15
|
-
ui?: Pick<PageLinks['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeadingIcon'
|
|
15
|
+
ui?: Partial<Pick<PageLinks['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeadingIcon'>>;
|
|
16
16
|
}
|
|
17
17
|
export interface PageLinksProps<T extends PageLink = PageLink> {
|
|
18
18
|
/**
|
|
@@ -12,7 +12,7 @@ export interface PageLink extends Omit<LinkProps, 'custom'> {
|
|
|
12
12
|
*/
|
|
13
13
|
icon?: IconProps['name'];
|
|
14
14
|
class?: any;
|
|
15
|
-
ui?: Pick<PageLinks['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeadingIcon'
|
|
15
|
+
ui?: Partial<Pick<PageLinks['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeadingIcon'>>;
|
|
16
16
|
}
|
|
17
17
|
export interface PageLinksProps<T extends PageLink = PageLink> {
|
|
18
18
|
/**
|
|
@@ -46,6 +46,7 @@ export interface PinInputProps<T extends PinInputType = 'text'> extends Pick<Pin
|
|
|
46
46
|
export type PinInputEmits<T extends PinInputType = 'text'> = PinInputRootEmits<T> & {
|
|
47
47
|
change: [event: Event];
|
|
48
48
|
blur: [event: Event];
|
|
49
|
+
focus: [event: Event];
|
|
49
50
|
};
|
|
50
51
|
export interface PinInputSlots {
|
|
51
52
|
separator?(props: {
|
|
@@ -58,6 +59,7 @@ declare const __VLS_export: <T extends PinInputType>(__VLS_props: NonNullable<Aw
|
|
|
58
59
|
props: import("vue").PublicProps & __VLS_PrettifyLocal<PinInputProps<T> & {
|
|
59
60
|
onBlur?: ((event: Event) => any) | undefined;
|
|
60
61
|
onChange?: ((event: Event) => any) | undefined;
|
|
62
|
+
onFocus?: ((event: Event) => any) | undefined;
|
|
61
63
|
"onUpdate:modelValue"?: ((value: [T] extends ["number"] ? number[] : string[]) => any) | undefined;
|
|
62
64
|
onComplete?: ((value: [T] extends ["number"] ? number[] : string[]) => any) | undefined;
|
|
63
65
|
}> & (typeof globalThis extends {
|
|
@@ -68,7 +70,7 @@ declare const __VLS_export: <T extends PinInputType>(__VLS_props: NonNullable<Aw
|
|
|
68
70
|
}>) => void;
|
|
69
71
|
attrs: any;
|
|
70
72
|
slots: PinInputSlots;
|
|
71
|
-
emit: ((evt: "blur", event: Event) => void) & ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: [T] extends ["number"] ? number[] : string[]) => void) & ((evt: "complete", value: [T] extends ["number"] ? number[] : string[]) => void);
|
|
73
|
+
emit: ((evt: "blur", event: Event) => void) & ((evt: "change", event: Event) => void) & ((evt: "focus", event: Event) => void) & ((evt: "update:modelValue", value: [T] extends ["number"] ? number[] : string[]) => void) & ((evt: "complete", value: [T] extends ["number"] ? number[] : string[]) => void);
|
|
72
74
|
}>) => import("vue").VNode & {
|
|
73
75
|
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
74
76
|
};
|
|
@@ -36,7 +36,7 @@ const _props = defineProps({
|
|
|
36
36
|
required: { type: Boolean, required: false },
|
|
37
37
|
type: { type: null, required: false, default: "text" }
|
|
38
38
|
});
|
|
39
|
-
const emits = defineEmits(["update:modelValue", "complete", "change", "blur"]);
|
|
39
|
+
const emits = defineEmits(["update:modelValue", "complete", "change", "blur", "focus"]);
|
|
40
40
|
defineSlots();
|
|
41
41
|
const props = useComponentProps("pinInput", _props);
|
|
42
42
|
const appConfig = useAppConfig();
|
|
@@ -62,11 +62,19 @@ function onComplete(value) {
|
|
|
62
62
|
emits("change", event);
|
|
63
63
|
emitFormChange();
|
|
64
64
|
}
|
|
65
|
-
function
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
emitFormBlur();
|
|
65
|
+
function onFocusOut(event) {
|
|
66
|
+
if (event.relatedTarget && event.currentTarget.contains(event.relatedTarget)) {
|
|
67
|
+
return;
|
|
69
68
|
}
|
|
69
|
+
emits("blur", event);
|
|
70
|
+
emitFormBlur();
|
|
71
|
+
}
|
|
72
|
+
function onFocusIn(event) {
|
|
73
|
+
if (event.relatedTarget && event.currentTarget.contains(event.relatedTarget)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
emits("focus", event);
|
|
77
|
+
emitFormFocus();
|
|
70
78
|
}
|
|
71
79
|
function autoFocus() {
|
|
72
80
|
if (props.autofocus) {
|
|
@@ -111,6 +119,8 @@ defineExpose({
|
|
|
111
119
|
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
|
112
120
|
@update:model-value="emitFormInput()"
|
|
113
121
|
@complete="onComplete"
|
|
122
|
+
@focusout="onFocusOut"
|
|
123
|
+
@focusin="onFocusIn"
|
|
114
124
|
>
|
|
115
125
|
<template v-for="(ids, index) in looseToNumber(props.length)" :key="ids">
|
|
116
126
|
<PinInputInput
|
|
@@ -119,8 +129,6 @@ defineExpose({
|
|
|
119
129
|
data-slot="base"
|
|
120
130
|
:class="ui.base({ class: props.ui?.base })"
|
|
121
131
|
:disabled="disabled"
|
|
122
|
-
@blur="onBlur"
|
|
123
|
-
@focus="emitFormFocus"
|
|
124
132
|
/>
|
|
125
133
|
<span
|
|
126
134
|
v-if="shouldInsertSeparator(index)"
|
|
@@ -46,6 +46,7 @@ export interface PinInputProps<T extends PinInputType = 'text'> extends Pick<Pin
|
|
|
46
46
|
export type PinInputEmits<T extends PinInputType = 'text'> = PinInputRootEmits<T> & {
|
|
47
47
|
change: [event: Event];
|
|
48
48
|
blur: [event: Event];
|
|
49
|
+
focus: [event: Event];
|
|
49
50
|
};
|
|
50
51
|
export interface PinInputSlots {
|
|
51
52
|
separator?(props: {
|
|
@@ -58,6 +59,7 @@ declare const __VLS_export: <T extends PinInputType>(__VLS_props: NonNullable<Aw
|
|
|
58
59
|
props: import("vue").PublicProps & __VLS_PrettifyLocal<PinInputProps<T> & {
|
|
59
60
|
onBlur?: ((event: Event) => any) | undefined;
|
|
60
61
|
onChange?: ((event: Event) => any) | undefined;
|
|
62
|
+
onFocus?: ((event: Event) => any) | undefined;
|
|
61
63
|
"onUpdate:modelValue"?: ((value: [T] extends ["number"] ? number[] : string[]) => any) | undefined;
|
|
62
64
|
onComplete?: ((value: [T] extends ["number"] ? number[] : string[]) => any) | undefined;
|
|
63
65
|
}> & (typeof globalThis extends {
|
|
@@ -68,7 +70,7 @@ declare const __VLS_export: <T extends PinInputType>(__VLS_props: NonNullable<Aw
|
|
|
68
70
|
}>) => void;
|
|
69
71
|
attrs: any;
|
|
70
72
|
slots: PinInputSlots;
|
|
71
|
-
emit: ((evt: "blur", event: Event) => void) & ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: [T] extends ["number"] ? number[] : string[]) => void) & ((evt: "complete", value: [T] extends ["number"] ? number[] : string[]) => void);
|
|
73
|
+
emit: ((evt: "blur", event: Event) => void) & ((evt: "change", event: Event) => void) & ((evt: "focus", event: Event) => void) & ((evt: "update:modelValue", value: [T] extends ["number"] ? number[] : string[]) => void) & ((evt: "complete", value: [T] extends ["number"] ? number[] : string[]) => void);
|
|
72
74
|
}>) => import("vue").VNode & {
|
|
73
75
|
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
74
76
|
};
|
|
@@ -20,7 +20,7 @@ export interface ProgressGroupItem {
|
|
|
20
20
|
color?: ProgressGroup['variants']['color'] | (string & {});
|
|
21
21
|
slot?: string;
|
|
22
22
|
class?: any;
|
|
23
|
-
ui?: Pick<ProgressGroup['slots'], 'segment' | 'indicator' | 'item' | 'itemLeadingIcon' | 'itemLeadingDot' | 'itemLabel' | 'itemTrailing'
|
|
23
|
+
ui?: Partial<Pick<ProgressGroup['slots'], 'segment' | 'indicator' | 'item' | 'itemLeadingIcon' | 'itemLeadingDot' | 'itemLabel' | 'itemTrailing'>>;
|
|
24
24
|
[key: string]: any;
|
|
25
25
|
}
|
|
26
26
|
export interface ProgressGroupProps<T extends ProgressGroupItem = ProgressGroupItem> {
|
|
@@ -20,7 +20,7 @@ export interface ProgressGroupItem {
|
|
|
20
20
|
color?: ProgressGroup['variants']['color'] | (string & {});
|
|
21
21
|
slot?: string;
|
|
22
22
|
class?: any;
|
|
23
|
-
ui?: Pick<ProgressGroup['slots'], 'segment' | 'indicator' | 'item' | 'itemLeadingIcon' | 'itemLeadingDot' | 'itemLabel' | 'itemTrailing'
|
|
23
|
+
ui?: Partial<Pick<ProgressGroup['slots'], 'segment' | 'indicator' | 'item' | 'itemLeadingIcon' | 'itemLeadingDot' | 'itemLabel' | 'itemTrailing'>>;
|
|
24
24
|
[key: string]: any;
|
|
25
25
|
}
|
|
26
26
|
export interface ProgressGroupProps<T extends ProgressGroupItem = ProgressGroupItem> {
|
|
@@ -18,7 +18,7 @@ export type RadioGroupItem = RadioGroupValue | {
|
|
|
18
18
|
*/
|
|
19
19
|
icon?: IconProps['name'];
|
|
20
20
|
class?: any;
|
|
21
|
-
ui?: Pick<RadioGroup['slots'], 'item' | 'container' | 'base' | 'indicator' | 'wrapper' | 'label' | 'icon' | 'description'
|
|
21
|
+
ui?: Partial<Pick<RadioGroup['slots'], 'item' | 'container' | 'base' | 'indicator' | 'wrapper' | 'label' | 'icon' | 'description'>>;
|
|
22
22
|
[key: string]: any;
|
|
23
23
|
};
|
|
24
24
|
export interface RadioGroupProps<T extends RadioGroupItem[] = RadioGroupItem[], VK extends GetItemKeys<T> = 'value'> extends Pick<RadioGroupRootProps, 'disabled' | 'loop' | 'name' | 'required'> {
|
|
@@ -18,7 +18,7 @@ export type RadioGroupItem = RadioGroupValue | {
|
|
|
18
18
|
*/
|
|
19
19
|
icon?: IconProps['name'];
|
|
20
20
|
class?: any;
|
|
21
|
-
ui?: Pick<RadioGroup['slots'], 'item' | 'container' | 'base' | 'indicator' | 'wrapper' | 'label' | 'icon' | 'description'
|
|
21
|
+
ui?: Partial<Pick<RadioGroup['slots'], 'item' | 'container' | 'base' | 'indicator' | 'wrapper' | 'label' | 'icon' | 'description'>>;
|
|
22
22
|
[key: string]: any;
|
|
23
23
|
};
|
|
24
24
|
export interface RadioGroupProps<T extends RadioGroupItem[] = RadioGroupItem[], VK extends GetItemKeys<T> = 'value'> extends Pick<RadioGroupRootProps, 'disabled' | 'loop' | 'name' | 'required'> {
|
|
@@ -30,7 +30,7 @@ export type SelectItem = SelectValue | {
|
|
|
30
30
|
disabled?: boolean;
|
|
31
31
|
onSelect?: (e: Event) => void;
|
|
32
32
|
class?: any;
|
|
33
|
-
ui?: Pick<Select['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'
|
|
33
|
+
ui?: Partial<Pick<Select['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'>>;
|
|
34
34
|
[key: string]: any;
|
|
35
35
|
};
|
|
36
36
|
type ExcludeItem = {
|
|
@@ -105,6 +105,8 @@ export interface SelectProps<T extends ArrayOrNested<SelectItem> = ArrayOrNested
|
|
|
105
105
|
multiple?: M & boolean;
|
|
106
106
|
/** Highlight the ring color like a focus state. */
|
|
107
107
|
highlight?: boolean;
|
|
108
|
+
/** Keep the mobile text size on all breakpoints. */
|
|
109
|
+
fixed?: boolean;
|
|
108
110
|
autofocus?: boolean;
|
|
109
111
|
autofocusDelay?: number;
|
|
110
112
|
class?: any;
|
|
@@ -40,6 +40,7 @@ const _props = defineProps({
|
|
|
40
40
|
modelModifiers: { type: null, required: false },
|
|
41
41
|
multiple: { type: Boolean, required: false },
|
|
42
42
|
highlight: { type: Boolean, required: false },
|
|
43
|
+
fixed: { type: Boolean, required: false },
|
|
43
44
|
autofocus: { type: Boolean, required: false },
|
|
44
45
|
autofocusDelay: { type: Number, required: false, default: 0 },
|
|
45
46
|
class: { type: null, required: false },
|
|
@@ -90,6 +91,7 @@ const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.select || {} })({
|
|
|
90
91
|
size: size.value,
|
|
91
92
|
loading: props.loading,
|
|
92
93
|
highlight: highlight.value,
|
|
94
|
+
fixed: props.fixed,
|
|
93
95
|
leading: isLeading.value || !!props.avatar || !!slots.leading,
|
|
94
96
|
trailing: isTrailing.value || !!slots.trailing,
|
|
95
97
|
fieldGroup: orientation.value,
|
|
@@ -30,7 +30,7 @@ export type SelectItem = SelectValue | {
|
|
|
30
30
|
disabled?: boolean;
|
|
31
31
|
onSelect?: (e: Event) => void;
|
|
32
32
|
class?: any;
|
|
33
|
-
ui?: Pick<Select['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'
|
|
33
|
+
ui?: Partial<Pick<Select['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'>>;
|
|
34
34
|
[key: string]: any;
|
|
35
35
|
};
|
|
36
36
|
type ExcludeItem = {
|
|
@@ -105,6 +105,8 @@ export interface SelectProps<T extends ArrayOrNested<SelectItem> = ArrayOrNested
|
|
|
105
105
|
multiple?: M & boolean;
|
|
106
106
|
/** Highlight the ring color like a focus state. */
|
|
107
107
|
highlight?: boolean;
|
|
108
|
+
/** Keep the mobile text size on all breakpoints. */
|
|
109
|
+
fixed?: boolean;
|
|
108
110
|
autofocus?: boolean;
|
|
109
111
|
autofocusDelay?: number;
|
|
110
112
|
class?: any;
|
|
@@ -32,7 +32,7 @@ export type SelectMenuItem = SelectMenuValue | {
|
|
|
32
32
|
disabled?: boolean;
|
|
33
33
|
onSelect?: (e: Event) => void;
|
|
34
34
|
class?: any;
|
|
35
|
-
ui?: Pick<SelectMenu['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'
|
|
35
|
+
ui?: Partial<Pick<SelectMenu['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'>>;
|
|
36
36
|
[key: string]: any;
|
|
37
37
|
};
|
|
38
38
|
type ExcludeItem = {
|
|
@@ -47,6 +47,7 @@ export interface SelectMenuProps<T extends ArrayOrNested<SelectMenuItem> = Array
|
|
|
47
47
|
* Whether to display the search input or not.
|
|
48
48
|
* Can be an object to pass additional props to the input.
|
|
49
49
|
* `{ placeholder: 'Search...', variant: 'none' }`{lang="ts-type"}
|
|
50
|
+
* Set `autofocus: false` to prevent the search input from being focused when the menu opens (e.g. to avoid opening the virtual keyboard on touch devices).
|
|
50
51
|
* @defaultValue true
|
|
51
52
|
*/
|
|
52
53
|
searchInput?: boolean | Omit<InputProps, 'modelValue' | 'defaultValue'>;
|
|
@@ -145,6 +146,8 @@ export interface SelectMenuProps<T extends ArrayOrNested<SelectMenuItem> = Array
|
|
|
145
146
|
multiple?: M & boolean;
|
|
146
147
|
/** Highlight the ring color like a focus state. */
|
|
147
148
|
highlight?: boolean;
|
|
149
|
+
/** Keep the mobile text size on all breakpoints. */
|
|
150
|
+
fixed?: boolean;
|
|
148
151
|
/**
|
|
149
152
|
* Determines if custom user input that does not exist in options can be added.
|
|
150
153
|
* @defaultValue false
|
|
@@ -50,6 +50,7 @@ const _props = defineProps({
|
|
|
50
50
|
modelModifiers: { type: null, required: false },
|
|
51
51
|
multiple: { type: Boolean, required: false },
|
|
52
52
|
highlight: { type: Boolean, required: false },
|
|
53
|
+
fixed: { type: Boolean, required: false },
|
|
53
54
|
createItem: { type: [Boolean, String, Object], required: false },
|
|
54
55
|
filterFields: { type: Array, required: false },
|
|
55
56
|
ignoreFilter: { type: Boolean, required: false },
|
|
@@ -92,7 +93,7 @@ const virtualizerProps = toRef(() => {
|
|
|
92
93
|
estimateSize: getEstimateSize(filteredItems.value, size.value ?? "md", props.descriptionKey, !!slots["item-description"])
|
|
93
94
|
});
|
|
94
95
|
});
|
|
95
|
-
const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t("selectMenu.search"), variant: "none" }));
|
|
96
|
+
const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t("selectMenu.search"), variant: "none", fixed: props.fixed }));
|
|
96
97
|
const { emitFormBlur, emitFormFocus, emitFormInput, emitFormChange, size: formFieldSize, color: formFieldColor, id, name, highlight: formFieldHighlight, disabled: formFieldDisabled, ariaAttrs } = useFormField(_props);
|
|
97
98
|
const { orientation, size: fieldGroupSize } = useFieldGroup(_props);
|
|
98
99
|
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(computed(() => ({
|
|
@@ -127,6 +128,7 @@ const ui = computed(() => tv({ extend: theme, ...appConfig.ui?.selectMenu || {}
|
|
|
127
128
|
size: size.value,
|
|
128
129
|
loading: props.loading,
|
|
129
130
|
highlight: highlight.value,
|
|
131
|
+
fixed: props.fixed,
|
|
130
132
|
leading: isLeading.value || !!props.avatar || !!slots.leading,
|
|
131
133
|
trailing: isTrailing.value || !!slots.trailing,
|
|
132
134
|
fieldGroup: orientation.value,
|
|
@@ -235,6 +237,14 @@ function onUpdateOpen(value) {
|
|
|
235
237
|
clearTimeout(timeoutId);
|
|
236
238
|
}
|
|
237
239
|
}
|
|
240
|
+
function onTriggerKeydown(e) {
|
|
241
|
+
if (isOpen.value) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const trigger = e.currentTarget;
|
|
245
|
+
e.preventDefault();
|
|
246
|
+
trigger.click();
|
|
247
|
+
}
|
|
238
248
|
function onCreate(e) {
|
|
239
249
|
e.preventDefault();
|
|
240
250
|
e.stopPropagation();
|
|
@@ -260,8 +270,16 @@ function isModelValueEmpty(modelValue) {
|
|
|
260
270
|
return modelValue === void 0 || modelValue === null || modelValue === "";
|
|
261
271
|
}
|
|
262
272
|
function onClear() {
|
|
273
|
+
if (disabled.value) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
263
276
|
emits("clear");
|
|
264
277
|
}
|
|
278
|
+
function onMountAutoFocus(event) {
|
|
279
|
+
if (searchInputProps.value.autofocus === false) {
|
|
280
|
+
event.preventDefault();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
265
283
|
const viewportRef = useTemplateRef("viewportRef");
|
|
266
284
|
const comboboxRootRef = useTemplateRef("comboboxRootRef");
|
|
267
285
|
watch(() => props.items, async () => {
|
|
@@ -366,7 +384,9 @@ defineExpose({
|
|
|
366
384
|
data-slot="base"
|
|
367
385
|
:class="ui.base({ class: [props.ui?.base, props.class] })"
|
|
368
386
|
tabindex="0"
|
|
369
|
-
v-bind="{ ...$attrs, ...ariaAttrs }"
|
|
387
|
+
v-bind="{ 'aria-label': void 0, ...$attrs, ...ariaAttrs }"
|
|
388
|
+
@keydown.down="onTriggerKeydown"
|
|
389
|
+
@keydown.up="onTriggerKeydown"
|
|
370
390
|
>
|
|
371
391
|
<span v-if="isLeading || !!props.avatar || !!slots.leading" data-slot="leading" :class="ui.leading({ class: props.ui?.leading })">
|
|
372
392
|
<slot name="leading" :model-value="modelValue" :open="open" :ui="ui">
|
|
@@ -388,7 +408,7 @@ defineExpose({
|
|
|
388
408
|
|
|
389
409
|
<span v-if="isTrailing || !!slots.trailing || !!props.clear" data-slot="trailing" :class="ui.trailing({ class: props.ui?.trailing })">
|
|
390
410
|
<slot name="trailing" :model-value="modelValue" :open="open" :ui="ui">
|
|
391
|
-
<ComboboxCancel v-if="!!props.clear && !isModelValueEmpty(modelValue)" as-child>
|
|
411
|
+
<ComboboxCancel v-if="!!props.clear && !disabled && !isModelValueEmpty(modelValue)" as-child>
|
|
392
412
|
<UButton
|
|
393
413
|
as="span"
|
|
394
414
|
:icon="props.clearIcon || appConfig.ui.icons.close"
|
|
@@ -412,7 +432,7 @@ defineExpose({
|
|
|
412
432
|
<ComboboxPortal v-bind="portalProps">
|
|
413
433
|
<FieldGroupReset>
|
|
414
434
|
<ComboboxContent data-slot="content" :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
|
|
415
|
-
<FocusScope trapped data-slot="focusScope" :class="ui.focusScope({ class: props.ui?.focusScope })">
|
|
435
|
+
<FocusScope trapped data-slot="focusScope" :class="ui.focusScope({ class: props.ui?.focusScope })" @mount-auto-focus="onMountAutoFocus">
|
|
416
436
|
<slot name="content-top" />
|
|
417
437
|
|
|
418
438
|
<ComboboxInput v-if="!!props.searchInput" v-model="searchTerm" :display-value="() => searchTerm" as-child>
|
|
@@ -32,7 +32,7 @@ export type SelectMenuItem = SelectMenuValue | {
|
|
|
32
32
|
disabled?: boolean;
|
|
33
33
|
onSelect?: (e: Event) => void;
|
|
34
34
|
class?: any;
|
|
35
|
-
ui?: Pick<SelectMenu['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'
|
|
35
|
+
ui?: Partial<Pick<SelectMenu['slots'], 'label' | 'separator' | 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemWrapper' | 'itemLabel' | 'itemDescription' | 'itemTrailing' | 'itemTrailingIcon'>>;
|
|
36
36
|
[key: string]: any;
|
|
37
37
|
};
|
|
38
38
|
type ExcludeItem = {
|
|
@@ -47,6 +47,7 @@ export interface SelectMenuProps<T extends ArrayOrNested<SelectMenuItem> = Array
|
|
|
47
47
|
* Whether to display the search input or not.
|
|
48
48
|
* Can be an object to pass additional props to the input.
|
|
49
49
|
* `{ placeholder: 'Search...', variant: 'none' }`{lang="ts-type"}
|
|
50
|
+
* Set `autofocus: false` to prevent the search input from being focused when the menu opens (e.g. to avoid opening the virtual keyboard on touch devices).
|
|
50
51
|
* @defaultValue true
|
|
51
52
|
*/
|
|
52
53
|
searchInput?: boolean | Omit<InputProps, 'modelValue' | 'defaultValue'>;
|
|
@@ -145,6 +146,8 @@ export interface SelectMenuProps<T extends ArrayOrNested<SelectMenuItem> = Array
|
|
|
145
146
|
multiple?: M & boolean;
|
|
146
147
|
/** Highlight the ring color like a focus state. */
|
|
147
148
|
highlight?: boolean;
|
|
149
|
+
/** Keep the mobile text size on all breakpoints. */
|
|
150
|
+
fixed?: boolean;
|
|
148
151
|
/**
|
|
149
152
|
* Determines if custom user input that does not exist in options can be added.
|
|
150
153
|
* @defaultValue false
|