@sewadah/selaras 0.3.0 → 0.3.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 +4 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +21 -6
- package/dist/runtime/components/AlertDialog.d.vue.ts +5 -3
- package/dist/runtime/components/AlertDialog.vue +17 -9
- package/dist/runtime/components/AlertDialog.vue.d.ts +5 -3
- package/dist/runtime/components/App.vue +2 -0
- package/dist/runtime/components/Autocomplete.d.vue.ts +2 -2
- package/dist/runtime/components/Autocomplete.vue +4 -2
- package/dist/runtime/components/Autocomplete.vue.d.ts +2 -2
- package/dist/runtime/components/Button.d.vue.ts +7 -5
- package/dist/runtime/components/Button.vue +14 -3
- package/dist/runtime/components/Button.vue.d.ts +7 -5
- package/dist/runtime/components/Calendar.d.vue.ts +69 -0
- package/dist/runtime/components/Calendar.vue +163 -0
- package/dist/runtime/components/Calendar.vue.d.ts +69 -0
- package/dist/runtime/components/Callout.vue +12 -1
- package/dist/runtime/components/CodeGroup.vue +13 -3
- package/dist/runtime/components/CodeTree.d.vue.ts +2 -0
- package/dist/runtime/components/CodeTree.vue +52 -1
- package/dist/runtime/components/CodeTree.vue.d.ts +2 -0
- package/dist/runtime/components/ColorModeSwitch.d.vue.ts +18 -0
- package/dist/runtime/components/ColorModeSwitch.vue +59 -0
- package/dist/runtime/components/ColorModeSwitch.vue.d.ts +18 -0
- package/dist/runtime/components/ColorPicker.d.vue.ts +8 -0
- package/dist/runtime/components/ColorPicker.vue +66 -45
- package/dist/runtime/components/ColorPicker.vue.d.ts +8 -0
- package/dist/runtime/components/Column.js +1 -1
- package/dist/runtime/components/CommandPalette.d.vue.ts +3 -1
- package/dist/runtime/components/CommandPalette.vue +5 -0
- package/dist/runtime/components/CommandPalette.vue.d.ts +3 -1
- package/dist/runtime/components/ConfirmRenderer.d.vue.ts +3 -0
- package/dist/runtime/components/ConfirmRenderer.vue +39 -0
- package/dist/runtime/components/ConfirmRenderer.vue.d.ts +3 -0
- package/dist/runtime/components/ContentNavigation.d.vue.ts +8 -1
- package/dist/runtime/components/ContentNavigation.vue +9 -2
- package/dist/runtime/components/ContentNavigation.vue.d.ts +8 -1
- package/dist/runtime/components/ContextMenu.d.vue.ts +8 -1
- package/dist/runtime/components/ContextMenu.vue +20 -6
- package/dist/runtime/components/ContextMenu.vue.d.ts +8 -1
- package/dist/runtime/components/DatePicker.d.vue.ts +10 -3
- package/dist/runtime/components/DatePicker.vue +24 -16
- package/dist/runtime/components/DatePicker.vue.d.ts +10 -3
- package/dist/runtime/components/Drawer.vue +3 -2
- package/dist/runtime/components/Dropdown.d.vue.ts +33 -6
- package/dist/runtime/components/Dropdown.vue +146 -12
- package/dist/runtime/components/Dropdown.vue.d.ts +33 -6
- package/dist/runtime/components/FileTree.d.vue.ts +2 -0
- package/dist/runtime/components/FileTree.vue +8 -4
- package/dist/runtime/components/FileTree.vue.d.ts +2 -0
- package/dist/runtime/components/FormField.d.vue.ts +4 -0
- package/dist/runtime/components/FormField.vue +19 -4
- package/dist/runtime/components/FormField.vue.d.ts +4 -0
- package/dist/runtime/components/Input.vue +3 -2
- package/dist/runtime/components/Kbd.vue +12 -2
- package/dist/runtime/components/Modal.vue +3 -2
- package/dist/runtime/components/NavigationMenu.d.vue.ts +10 -10
- package/dist/runtime/components/NavigationMenu.vue +13 -9
- package/dist/runtime/components/NavigationMenu.vue.d.ts +10 -10
- package/dist/runtime/components/NavigationMenuAccordionItem.vue +5 -1
- package/dist/runtime/components/NavigationMenuFlyoutList.vue +7 -4
- package/dist/runtime/components/Popover.d.vue.ts +8 -2
- package/dist/runtime/components/Popover.vue +13 -6
- package/dist/runtime/components/Popover.vue.d.ts +8 -2
- package/dist/runtime/components/ProsePre.d.vue.ts +2 -0
- package/dist/runtime/components/ProsePre.vue +2 -1
- package/dist/runtime/components/ProsePre.vue.d.ts +2 -0
- package/dist/runtime/components/Select.d.vue.ts +8 -4
- package/dist/runtime/components/Select.vue +4 -2
- package/dist/runtime/components/Select.vue.d.ts +8 -4
- package/dist/runtime/components/Slideover.vue +3 -2
- package/dist/runtime/components/SplitterPanel.d.vue.ts +2 -2
- package/dist/runtime/components/SplitterPanel.vue.d.ts +2 -2
- package/dist/runtime/components/Table.vue +95 -26
- package/dist/runtime/components/Tabs.d.vue.ts +44 -4
- package/dist/runtime/components/Tabs.vue +171 -18
- package/dist/runtime/components/Tabs.vue.d.ts +44 -4
- package/dist/runtime/components/Textarea.vue +3 -2
- package/dist/runtime/components/Timeline.d.vue.ts +19 -0
- package/dist/runtime/components/Timeline.vue +99 -0
- package/dist/runtime/components/Timeline.vue.d.ts +19 -0
- package/dist/runtime/components/Toast.d.vue.ts +10 -1
- package/dist/runtime/components/Toast.vue +94 -8
- package/dist/runtime/components/Toast.vue.d.ts +10 -1
- package/dist/runtime/components/Tooltip.d.vue.ts +8 -2
- package/dist/runtime/components/Tooltip.vue +13 -6
- package/dist/runtime/components/Tooltip.vue.d.ts +8 -2
- package/dist/runtime/composables/use-confirm.d.ts +14 -0
- package/dist/runtime/composables/use-confirm.js +28 -0
- package/dist/runtime/composables/use-form-field.d.ts +1 -0
- package/dist/runtime/composables/use-table.d.ts +3 -0
- package/dist/runtime/composables/use-table.js +10 -4
- package/dist/runtime/composables/use-toast.js +5 -1
- package/dist/runtime/directives/hotkey.d.ts +13 -0
- package/dist/runtime/directives/hotkey.js +107 -0
- package/dist/runtime/directives/index.d.ts +2 -0
- package/dist/runtime/directives/index.js +2 -0
- package/dist/runtime/directives/mask.d.ts +30 -0
- package/dist/runtime/directives/mask.js +165 -0
- package/dist/runtime/internal/ComboboxSelectBase.d.vue.ts +41 -36
- package/dist/runtime/internal/ComboboxSelectBase.vue +119 -26
- package/dist/runtime/internal/ComboboxSelectBase.vue.d.ts +41 -36
- package/dist/runtime/internal/ComboboxSelectBody.d.vue.ts +23 -17
- package/dist/runtime/internal/ComboboxSelectBody.vue +50 -11
- package/dist/runtime/internal/ComboboxSelectBody.vue.d.ts +23 -17
- package/dist/runtime/internal/DatePickerCalendarBody.vue +1 -1
- package/dist/runtime/internal/DatePickerRangeCalendarBody.vue +1 -1
- package/dist/runtime/internal/ShortcutHint.d.vue.ts +6 -0
- package/dist/runtime/internal/ShortcutHint.vue +13 -0
- package/dist/runtime/internal/ShortcutHint.vue.d.ts +6 -0
- package/dist/runtime/internal/ToastItemRenderer.d.vue.ts +9 -1
- package/dist/runtime/internal/ToastItemRenderer.vue +55 -8
- package/dist/runtime/internal/ToastItemRenderer.vue.d.ts +9 -1
- package/dist/runtime/internal/combobox-select.d.ts +19 -18
- package/dist/runtime/internal/combobox-select.js +38 -15
- package/dist/runtime/internal/programmatic-services.d.ts +13 -0
- package/dist/runtime/internal/programmatic-services.js +9 -0
- package/dist/runtime/internal/toast-stack.d.ts +36 -0
- package/dist/runtime/internal/toast-stack.js +36 -0
- package/dist/runtime/structural.css +1 -1
- package/dist/runtime/table.d.ts +1 -1
- package/dist/runtime/theme/alert-dialog.js +1 -1
- package/dist/runtime/theme/badge.d.ts +9 -0
- package/dist/runtime/theme/badge.js +2 -1
- package/dist/runtime/theme/button.d.ts +18 -0
- package/dist/runtime/theme/button.js +4 -1
- package/dist/runtime/theme/calendar.d.ts +86 -0
- package/dist/runtime/theme/calendar.js +19 -0
- package/dist/runtime/theme/callout.d.ts +0 -12
- package/dist/runtime/theme/callout.js +8 -8
- package/dist/runtime/theme/code-tree.js +1 -1
- package/dist/runtime/theme/command-palette.js +1 -1
- package/dist/runtime/theme/content-navigation.d.ts +3 -0
- package/dist/runtime/theme/content-navigation.js +1 -0
- package/dist/runtime/theme/drawer.js +1 -1
- package/dist/runtime/theme/dropdown.d.ts +21 -0
- package/dist/runtime/theme/dropdown.js +15 -2
- package/dist/runtime/theme/file-tree.js +1 -1
- package/dist/runtime/theme/form-field.d.ts +18 -0
- package/dist/runtime/theme/form-field.js +6 -1
- package/dist/runtime/theme/modal.js +1 -1
- package/dist/runtime/theme/slideover.js +1 -1
- package/dist/runtime/theme/table.d.ts +27 -0
- package/dist/runtime/theme/table.js +11 -2
- package/dist/runtime/theme/tabs.d.ts +87 -3
- package/dist/runtime/theme/tabs.js +46 -22
- package/dist/runtime/theme/timeline.d.ts +251 -0
- package/dist/runtime/theme/timeline.js +84 -0
- package/dist/runtime/theme/toast.d.ts +92 -0
- package/dist/runtime/theme/toast.js +29 -7
- package/dist/runtime/theme-config.d.ts +13 -2
- package/dist/runtime/types/index.d.ts +10 -2
- package/dist/runtime/utils/arrow.d.ts +21 -0
- package/dist/runtime/utils/arrow.js +10 -0
- package/dist/runtime/utils/autocomplete-contracts.d.ts +4 -4
- package/dist/runtime/utils/file-icons.js +3 -0
- package/dist/runtime/utils/icons.d.ts +2 -0
- package/dist/runtime/utils/icons.js +2 -0
- package/dist/runtime/utils/messages.d.ts +7 -0
- package/dist/runtime/utils/messages.js +7 -0
- package/dist/runtime/utils/navigation-menu.d.ts +7 -0
- package/dist/runtime/utils/navigation-menu.js +3 -0
- package/dist/runtime/utils/overlay.d.ts +17 -0
- package/dist/runtime/utils/overlay.js +7 -0
- package/dist/runtime/utils/select-contracts.d.ts +25 -11
- package/dist/runtime/utils/table-columns.js +1 -1
- package/dist/runtime/utils/table-contracts.d.ts +9 -1
- package/dist/runtime/utils/timeline-contracts.d.ts +42 -0
- package/dist/runtime/utils/timeline-contracts.js +0 -0
- package/dist/runtime/utils/ui.d.ts +11 -0
- package/dist/runtime/utils/ui.js +54 -1
- package/package.json +6 -5
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { DropdownMenuArrow, DropdownMenuContent, DropdownMenuItem, DropdownMenuPortal, DropdownMenuRoot, DropdownMenuSeparator, DropdownMenuTrigger } from "reka-ui";
|
|
3
|
-
import { computed, getCurrentInstance, ref, watch } from "vue";
|
|
3
|
+
import { computed, getCurrentInstance, onMounted, ref, useId, watch, watchPostEffect } from "vue";
|
|
4
|
+
import { NuxtLink } from "#components";
|
|
5
|
+
import { useIsMobile } from "../composables/use-media-query";
|
|
6
|
+
import { useMessages } from "../composables/use-messages";
|
|
7
|
+
import { vHotkey } from "../directives/hotkey";
|
|
8
|
+
import ShortcutHint from "../internal/ShortcutHint.vue";
|
|
4
9
|
import { dropdownTheme } from "../theme/dropdown";
|
|
5
|
-
import {
|
|
10
|
+
import { arrowContentProps, arrowElementProps } from "../utils/arrow";
|
|
11
|
+
import { overlayPortalProps } from "../utils/overlay";
|
|
12
|
+
import { resolveSlot, useComponentTheme, useFallthroughProps, useThemeBindings } from "../utils/ui";
|
|
6
13
|
import Icon from "./Icon.vue";
|
|
14
|
+
import Modal from "./Modal.vue";
|
|
15
|
+
defineOptions({ inheritAttrs: false });
|
|
7
16
|
const props = defineProps({
|
|
8
17
|
items: { type: Array, required: true },
|
|
9
18
|
open: { type: Boolean, required: false, default: void 0 },
|
|
10
19
|
defaultOpen: { type: Boolean, required: false },
|
|
11
|
-
arrow: { type: Boolean, required: false, default: false },
|
|
20
|
+
arrow: { type: [Boolean, Object], required: false, default: false },
|
|
21
|
+
positioning: { type: Object, required: false },
|
|
22
|
+
portal: { type: [Boolean, String], required: false, skipCheck: true, default: void 0 },
|
|
23
|
+
adaptive: { type: Boolean, required: false },
|
|
12
24
|
ui: { type: Object, required: false }
|
|
13
25
|
});
|
|
14
26
|
const emit = defineEmits(["update:open"]);
|
|
@@ -25,42 +37,164 @@ function onUpdateOpen(value) {
|
|
|
25
37
|
}
|
|
26
38
|
const theme = useComponentTheme("dropdown", dropdownTheme);
|
|
27
39
|
const themeBindings = useThemeBindings();
|
|
40
|
+
const messages = useMessages();
|
|
41
|
+
const isMobile = useIsMobile();
|
|
42
|
+
const modalId = `selaras-dropdown-modal-${useId()}`;
|
|
43
|
+
const triggerElement = ref();
|
|
28
44
|
const ui = computed(() => theme.value());
|
|
29
|
-
const
|
|
30
|
-
const
|
|
45
|
+
const triggerProps = useFallthroughProps();
|
|
46
|
+
const contentProps = computed(() => ({ ...resolveSlot(ui.value.content, props.ui?.content), ...arrowContentProps(props.arrow), ...props.positioning }));
|
|
47
|
+
const portalProps = computed(() => overlayPortalProps(props.portal));
|
|
48
|
+
const arrowProps = computed(() => ({ ...resolveSlot(ui.value.arrow, props.ui?.arrow), ...arrowElementProps(props.arrow) }));
|
|
31
49
|
function itemPropsFor(item) {
|
|
32
50
|
return resolveSlot(theme.value({ destructive: item.destructive }).item, props.ui?.item);
|
|
33
51
|
}
|
|
52
|
+
function mobileItemPropsFor(item) {
|
|
53
|
+
return resolveSlot(theme.value({ destructive: item.destructive, mobile: true }).item, props.ui?.item);
|
|
54
|
+
}
|
|
55
|
+
const mobileListProps = computed(() => resolveSlot(ui.value.mobileList, props.ui?.mobileList));
|
|
56
|
+
const mobileGroupProps = computed(() => resolveSlot(ui.value.mobileGroup, props.ui?.mobileGroup));
|
|
34
57
|
function iconPropsFor(item) {
|
|
35
58
|
return resolveSlot(theme.value({ destructive: item.destructive }).icon, props.ui?.icon);
|
|
36
59
|
}
|
|
60
|
+
function hotkeyFor(item) {
|
|
61
|
+
return item.hotkey && item.shortcut && !item.disabled ? { keys: item.shortcut, when: () => internalOpen.value } : void 0;
|
|
62
|
+
}
|
|
37
63
|
const separatorProps = computed(() => resolveSlot(ui.value.separator, props.ui?.separator));
|
|
64
|
+
const mobilePresentation = ref(false);
|
|
65
|
+
const isOpen = computed(() => isControlled ? props.open ?? false : internalOpen.value);
|
|
66
|
+
watch(isOpen, (open) => {
|
|
67
|
+
if (open)
|
|
68
|
+
mobilePresentation.value = !!props.adaptive && isMobile.value;
|
|
69
|
+
});
|
|
70
|
+
onMounted(() => {
|
|
71
|
+
if (isOpen.value)
|
|
72
|
+
mobilePresentation.value = !!props.adaptive && isMobile.value;
|
|
73
|
+
});
|
|
74
|
+
function onUpdateMenuOpen(value) {
|
|
75
|
+
onUpdateOpen(value);
|
|
76
|
+
}
|
|
77
|
+
const desktopOpen = computed(() => isOpen.value && !mobilePresentation.value);
|
|
78
|
+
const mobileOpen = computed(() => isOpen.value && mobilePresentation.value);
|
|
79
|
+
const adaptiveUi = computed(() => ({
|
|
80
|
+
content: {
|
|
81
|
+
class: "rounded-[var(--selaras-resolved-radius-md)]",
|
|
82
|
+
id: modalId
|
|
83
|
+
}
|
|
84
|
+
}));
|
|
85
|
+
watchPostEffect(() => {
|
|
86
|
+
if (!props.adaptive)
|
|
87
|
+
return;
|
|
88
|
+
const element = triggerElement.value instanceof HTMLElement ? triggerElement.value : triggerElement.value?.$el;
|
|
89
|
+
if (!element)
|
|
90
|
+
return;
|
|
91
|
+
const dialog = isOpen.value ? mobilePresentation.value : isMobile.value;
|
|
92
|
+
element.setAttribute("aria-haspopup", dialog ? "dialog" : "menu");
|
|
93
|
+
element.setAttribute("aria-expanded", String(isOpen.value));
|
|
94
|
+
if (dialog && isOpen.value)
|
|
95
|
+
element.setAttribute("aria-controls", modalId);
|
|
96
|
+
else if (element.getAttribute("aria-controls") === modalId)
|
|
97
|
+
element.removeAttribute("aria-controls");
|
|
98
|
+
});
|
|
99
|
+
function selectMobileItem(item) {
|
|
100
|
+
item.onSelect?.();
|
|
101
|
+
onUpdateOpen(false);
|
|
102
|
+
}
|
|
103
|
+
function onModalAfterLeave() {
|
|
104
|
+
if (!isOpen.value)
|
|
105
|
+
mobilePresentation.value = false;
|
|
106
|
+
}
|
|
38
107
|
</script>
|
|
39
108
|
|
|
40
109
|
<template>
|
|
41
|
-
<DropdownMenuRoot :open="
|
|
42
|
-
<DropdownMenuTrigger as-child>
|
|
110
|
+
<DropdownMenuRoot :open="desktopOpen" @update:open="onUpdateMenuOpen">
|
|
111
|
+
<DropdownMenuTrigger ref="triggerElement" as-child v-bind="triggerProps">
|
|
43
112
|
<slot />
|
|
44
113
|
</DropdownMenuTrigger>
|
|
45
|
-
<DropdownMenuPortal>
|
|
114
|
+
<DropdownMenuPortal v-if="!mobilePresentation" v-bind="portalProps">
|
|
46
115
|
<DropdownMenuContent :side-offset="6" align="start" :data-selaras-theme="themeBindings['data-selaras-theme']" :data-selaras-mode="themeBindings['data-selaras-mode']" :style="themeBindings.style" v-bind="contentProps">
|
|
47
116
|
<template v-for="(group, groupIndex) in items" :key="groupIndex">
|
|
48
117
|
<DropdownMenuSeparator v-if="groupIndex > 0" v-bind="separatorProps" />
|
|
49
118
|
<DropdownMenuItem
|
|
50
119
|
v-for="(item, itemIndex) in group"
|
|
51
120
|
:key="itemIndex"
|
|
121
|
+
v-hotkey="hotkeyFor(item)"
|
|
52
122
|
:disabled="item.disabled"
|
|
123
|
+
:as-child="Boolean(item.to)"
|
|
53
124
|
v-bind="itemPropsFor(item)"
|
|
54
125
|
@select="item.onSelect?.()"
|
|
55
126
|
>
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
127
|
+
<NuxtLink v-if="item.to" :to="item.to" :target="item.target" :rel="item.rel">
|
|
128
|
+
<Icon v-if="item.icon" :name="item.icon" v-bind="iconPropsFor(item)" />
|
|
129
|
+
<slot name="item" :item="item">
|
|
130
|
+
{{ item.label }}
|
|
131
|
+
<ShortcutHint :shortcut="item.shortcut" />
|
|
132
|
+
</slot>
|
|
133
|
+
</NuxtLink>
|
|
134
|
+
<template v-else>
|
|
135
|
+
<Icon v-if="item.icon" :name="item.icon" v-bind="iconPropsFor(item)" />
|
|
136
|
+
<slot name="item" :item="item">
|
|
137
|
+
{{ item.label }}
|
|
138
|
+
<ShortcutHint :shortcut="item.shortcut" />
|
|
139
|
+
</slot>
|
|
140
|
+
</template>
|
|
60
141
|
</DropdownMenuItem>
|
|
61
142
|
</template>
|
|
62
143
|
<DropdownMenuArrow v-if="arrow" v-bind="arrowProps" />
|
|
63
144
|
</DropdownMenuContent>
|
|
64
145
|
</DropdownMenuPortal>
|
|
65
146
|
</DropdownMenuRoot>
|
|
147
|
+
|
|
148
|
+
<Modal
|
|
149
|
+
v-if="mobilePresentation"
|
|
150
|
+
:open="mobileOpen"
|
|
151
|
+
:title="messages.dropdownMenu"
|
|
152
|
+
:description="messages.dropdownMenuDescription"
|
|
153
|
+
:close="false"
|
|
154
|
+
:ui="adaptiveUi"
|
|
155
|
+
@update:open="onUpdateOpen"
|
|
156
|
+
@after-leave="onModalAfterLeave"
|
|
157
|
+
>
|
|
158
|
+
<template #content>
|
|
159
|
+
<div v-bind="mobileListProps">
|
|
160
|
+
<template v-for="(group, groupIndex) in items" :key="groupIndex">
|
|
161
|
+
<div v-if="groupIndex > 0" role="separator" v-bind="separatorProps" />
|
|
162
|
+
<div v-bind="mobileGroupProps">
|
|
163
|
+
<template v-for="(item, itemIndex) in group" :key="itemIndex">
|
|
164
|
+
<!-- A disabled link renders as the disabled button below, which is inert. -->
|
|
165
|
+
<NuxtLink
|
|
166
|
+
v-if="item.to && !item.disabled"
|
|
167
|
+
v-hotkey="hotkeyFor(item)"
|
|
168
|
+
:to="item.to"
|
|
169
|
+
:target="item.target"
|
|
170
|
+
:rel="item.rel"
|
|
171
|
+
v-bind="mobileItemPropsFor(item)"
|
|
172
|
+
@click="selectMobileItem(item)"
|
|
173
|
+
>
|
|
174
|
+
<Icon v-if="item.icon" :name="item.icon" v-bind="iconPropsFor(item)" />
|
|
175
|
+
<slot name="item" :item="item">
|
|
176
|
+
{{ item.label }}
|
|
177
|
+
<ShortcutHint :shortcut="item.shortcut" />
|
|
178
|
+
</slot>
|
|
179
|
+
</NuxtLink>
|
|
180
|
+
<button
|
|
181
|
+
v-else
|
|
182
|
+
v-hotkey="hotkeyFor(item)"
|
|
183
|
+
type="button"
|
|
184
|
+
:disabled="item.disabled"
|
|
185
|
+
v-bind="mobileItemPropsFor(item)"
|
|
186
|
+
@click="selectMobileItem(item)"
|
|
187
|
+
>
|
|
188
|
+
<Icon v-if="item.icon" :name="item.icon" v-bind="iconPropsFor(item)" />
|
|
189
|
+
<slot name="item" :item="item">
|
|
190
|
+
{{ item.label }}
|
|
191
|
+
<ShortcutHint :shortcut="item.shortcut" />
|
|
192
|
+
</slot>
|
|
193
|
+
</button>
|
|
194
|
+
</template>
|
|
195
|
+
</div>
|
|
196
|
+
</template>
|
|
197
|
+
</div>
|
|
198
|
+
</template>
|
|
199
|
+
</Modal>
|
|
66
200
|
</template>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { DropdownThemeSlots } from '../theme/dropdown.js';
|
|
2
|
+
import type { RoundedArrowConfig } from '../utils/arrow.js';
|
|
3
|
+
import type { OverlayPortal, OverlayPositioning } from '../utils/overlay.js';
|
|
2
4
|
import type { UiProp } from '../utils/ui.js';
|
|
3
5
|
export interface DropdownItem {
|
|
4
6
|
label: string;
|
|
@@ -7,28 +9,53 @@ export interface DropdownItem {
|
|
|
7
9
|
/** Styles this item for a delete/remove-style action (danger text, danger-tinted hover) - just this one flag rather than the full color palette, since a menu item realistically only ever needs this one special case. */
|
|
8
10
|
destructive?: boolean;
|
|
9
11
|
onSelect?: () => void;
|
|
10
|
-
/**
|
|
12
|
+
/** Displays a keyboard shortcut hint. */
|
|
11
13
|
shortcut?: string;
|
|
14
|
+
/** Bind `shortcut` while this menu is open; activation follows the normal menu item click path. */
|
|
15
|
+
hotkey?: boolean;
|
|
16
|
+
/** Nuxt route or URL to navigate to instead of rendering an action item. */
|
|
17
|
+
to?: string;
|
|
18
|
+
/** Link target, for example `_blank`. */
|
|
19
|
+
target?: string;
|
|
20
|
+
rel?: string;
|
|
12
21
|
}
|
|
13
22
|
export interface DropdownProps {
|
|
14
23
|
items: DropdownItem[][];
|
|
15
24
|
open?: boolean;
|
|
16
25
|
/** Initial visibility for an uncontrolled dropdown. Supplying `open` makes the parent authoritative. */
|
|
17
26
|
defaultOpen?: boolean;
|
|
18
|
-
/** Shows
|
|
19
|
-
arrow?: boolean;
|
|
27
|
+
/** Shows the pointer; an object configures its size, rounding, and edge clearance. */
|
|
28
|
+
arrow?: boolean | RoundedArrowConfig;
|
|
29
|
+
/** Anchored menu placement. */
|
|
30
|
+
positioning?: OverlayPositioning;
|
|
31
|
+
/** Teleport target, or `false` to render inline. Defaults to `body`. */
|
|
32
|
+
portal?: OverlayPortal;
|
|
33
|
+
/** Opens a dialog-style action list on mobile instead of the anchored menu. */
|
|
34
|
+
adaptive?: boolean;
|
|
20
35
|
ui?: UiProp<DropdownThemeSlots>;
|
|
21
36
|
}
|
|
22
37
|
export interface DropdownEmits {
|
|
23
38
|
'update:open': [value: boolean];
|
|
24
39
|
}
|
|
25
|
-
declare var
|
|
40
|
+
declare var __VLS_17: {}, __VLS_55: {
|
|
41
|
+
item: DropdownItem;
|
|
42
|
+
}, __VLS_67: {
|
|
43
|
+
item: DropdownItem;
|
|
44
|
+
}, __VLS_102: {
|
|
45
|
+
item: DropdownItem;
|
|
46
|
+
}, __VLS_114: {
|
|
26
47
|
item: DropdownItem;
|
|
27
48
|
};
|
|
28
49
|
type __VLS_Slots = {} & {
|
|
29
|
-
default?: (props: typeof
|
|
50
|
+
default?: (props: typeof __VLS_17) => any;
|
|
51
|
+
} & {
|
|
52
|
+
item?: (props: typeof __VLS_55) => any;
|
|
53
|
+
} & {
|
|
54
|
+
item?: (props: typeof __VLS_67) => any;
|
|
55
|
+
} & {
|
|
56
|
+
item?: (props: typeof __VLS_102) => any;
|
|
30
57
|
} & {
|
|
31
|
-
item?: (props: typeof
|
|
58
|
+
item?: (props: typeof __VLS_114) => any;
|
|
32
59
|
};
|
|
33
60
|
declare const __VLS_base: import("vue").DefineComponent<DropdownProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
34
61
|
"update:open": (value: boolean) => any;
|
|
@@ -6,6 +6,8 @@ export interface FileTreeNode {
|
|
|
6
6
|
/** A node with children renders as a directory, one without as a file - the same convention ContentNavigation's own tree uses. */
|
|
7
7
|
children?: FileTreeNode[];
|
|
8
8
|
icon?: string;
|
|
9
|
+
/** Optional language hint for resolving a file-type icon when the filename is not recognized. */
|
|
10
|
+
language?: string;
|
|
9
11
|
}
|
|
10
12
|
export interface FileTreeProps {
|
|
11
13
|
items: FileTreeNode[];
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, ref } from "vue";
|
|
2
|
+
import { computed, ref, toRaw } from "vue";
|
|
3
3
|
import { useIcons } from "../composables/use-icons";
|
|
4
4
|
import { fileTreeTheme } from "../theme/file-tree";
|
|
5
|
+
import { resolveFileIcon } from "../utils/file-icons";
|
|
5
6
|
import { resolveRegisteredColorRole } from "../utils/registered-colors";
|
|
6
7
|
import { resolveSlot, useComponentTheme, useRootProps } from "../utils/ui";
|
|
7
8
|
import Icon from "./Icon.vue";
|
|
@@ -31,11 +32,14 @@ function toggle(index) {
|
|
|
31
32
|
function selectFile(node) {
|
|
32
33
|
emit("update:selected", node);
|
|
33
34
|
}
|
|
35
|
+
function isSelected(node) {
|
|
36
|
+
return props.selected != null && toRaw(props.selected) === toRaw(node);
|
|
37
|
+
}
|
|
34
38
|
function iconFor(node, index) {
|
|
35
39
|
if (node.icon)
|
|
36
40
|
return node.icon;
|
|
37
41
|
if (!node.children)
|
|
38
|
-
return icons.value.file;
|
|
42
|
+
return resolveFileIcon(node.language, node.name) ?? icons.value.file;
|
|
39
43
|
return isExpanded(index) ? icons.value.folderOpen : icons.value.folder;
|
|
40
44
|
}
|
|
41
45
|
const theme = useComponentTheme("fileTree", fileTreeTheme);
|
|
@@ -46,14 +50,14 @@ const itemProps = computed(() => resolveSlot(ui.value.item, props.ui?.item));
|
|
|
46
50
|
const iconProps = computed(() => resolveSlot(ui.value.icon, props.ui?.icon));
|
|
47
51
|
const labelProps = computed(() => resolveSlot(ui.value.label, props.ui?.label));
|
|
48
52
|
function rowProps(node) {
|
|
49
|
-
return resolveSlot(theme.value({ isNested: props.isNested, selected:
|
|
53
|
+
return resolveSlot(theme.value({ isNested: props.isNested, selected: isSelected(node), color: effectiveColor.value }).row, props.ui?.row);
|
|
50
54
|
}
|
|
51
55
|
</script>
|
|
52
56
|
|
|
53
57
|
<template>
|
|
54
58
|
<ul :data-selaras-color="effectiveColor" v-bind="rootProps">
|
|
55
59
|
<li v-for="(node, index) in items" :key="node.name" v-bind="itemProps">
|
|
56
|
-
<button type="button" v-bind="rowProps(node)" @click="node.children ? toggle(index) : selectFile(node)">
|
|
60
|
+
<button type="button" :aria-current="isSelected(node) ? 'true' : void 0" v-bind="rowProps(node)" @click="node.children ? toggle(index) : selectFile(node)">
|
|
57
61
|
<Icon :name="iconFor(node, index)" v-bind="iconProps" />
|
|
58
62
|
<span v-bind="labelProps">{{ node.name }}</span>
|
|
59
63
|
</button>
|
|
@@ -6,6 +6,8 @@ export interface FileTreeNode {
|
|
|
6
6
|
/** A node with children renders as a directory, one without as a file - the same convention ContentNavigation's own tree uses. */
|
|
7
7
|
children?: FileTreeNode[];
|
|
8
8
|
icon?: string;
|
|
9
|
+
/** Optional language hint for resolving a file-type icon when the filename is not recognized. */
|
|
10
|
+
language?: string;
|
|
9
11
|
}
|
|
10
12
|
export interface FileTreeProps {
|
|
11
13
|
items: FileTreeNode[];
|
|
@@ -16,6 +16,10 @@ export interface FormFieldProps {
|
|
|
16
16
|
size?: FormFieldVariants['size'];
|
|
17
17
|
/** 'vertical' (default) stacks the label above the control; 'horizontal' places the label beside it, with the control filling the remaining row width. */
|
|
18
18
|
orientation?: FormFieldVariants['orientation'];
|
|
19
|
+
/** 'floating' overlays the label on an empty control and lifts it on focus, open, or once filled. */
|
|
20
|
+
labelMode?: FormFieldVariants['labelMode'];
|
|
21
|
+
/** Explicit filled state for a custom or third-party control. */
|
|
22
|
+
filled?: boolean;
|
|
19
23
|
ui?: UiProp<FormFieldThemeSlots>;
|
|
20
24
|
}
|
|
21
25
|
declare var __VLS_1: {}, __VLS_3: {
|
|
@@ -14,10 +14,13 @@ const props = defineProps({
|
|
|
14
14
|
required: { type: Boolean, required: false },
|
|
15
15
|
size: { type: null, required: false },
|
|
16
16
|
orientation: { type: null, required: false, default: "vertical" },
|
|
17
|
+
labelMode: { type: null, required: false, default: "static" },
|
|
18
|
+
filled: { type: Boolean, required: false },
|
|
17
19
|
ui: { type: Object, required: false }
|
|
18
20
|
});
|
|
19
21
|
const id = props.id ?? useId();
|
|
20
22
|
const invalid = computed(() => !!props.error);
|
|
23
|
+
const floatingLabel = computed(() => props.labelMode === "floating");
|
|
21
24
|
const errorMessage = computed(() => typeof props.error === "string" ? props.error : void 0);
|
|
22
25
|
const describedBy = computed(() => {
|
|
23
26
|
const ids = [
|
|
@@ -32,11 +35,16 @@ provideFormField({
|
|
|
32
35
|
labelId: props.label ? `${id}-label` : void 0,
|
|
33
36
|
name: props.name,
|
|
34
37
|
size: props.size,
|
|
38
|
+
floatingLabel,
|
|
35
39
|
invalid,
|
|
36
40
|
describedBy
|
|
37
41
|
});
|
|
38
42
|
const theme = useComponentTheme("formField", formFieldTheme);
|
|
39
|
-
const ui = computed(() => theme.value({
|
|
43
|
+
const ui = computed(() => theme.value({
|
|
44
|
+
size: props.size,
|
|
45
|
+
orientation: floatingLabel.value ? "vertical" : props.orientation,
|
|
46
|
+
labelMode: props.labelMode
|
|
47
|
+
}));
|
|
40
48
|
const rootProps = useRootProps(() => ui.value.root, () => props.ui?.root);
|
|
41
49
|
const bodyProps = computed(() => resolveSlot(ui.value.body, props.ui?.body));
|
|
42
50
|
const headerProps = computed(() => resolveSlot(ui.value.header, props.ui?.header));
|
|
@@ -49,10 +57,10 @@ const errorProps = computed(() => resolveSlot(ui.value.error, props.ui?.error));
|
|
|
49
57
|
</script>
|
|
50
58
|
|
|
51
59
|
<template>
|
|
52
|
-
<div v-bind="rootProps">
|
|
60
|
+
<div :data-selaras-label-mode="labelMode" :data-filled="filled || void 0" :data-invalid="invalid || void 0" v-bind="rootProps">
|
|
53
61
|
<div v-bind="bodyProps">
|
|
54
|
-
<div v-bind="headerProps">
|
|
55
|
-
<label v-if="label" :id="`${id}-label`" :for="id" v-bind="labelProps">
|
|
62
|
+
<div v-if="description || label && !floatingLabel" v-bind="headerProps">
|
|
63
|
+
<label v-if="label && !floatingLabel" :id="`${id}-label`" :for="id" v-bind="labelProps">
|
|
56
64
|
{{ label }}<span v-if="required" v-bind="requiredProps">*</span>
|
|
57
65
|
</label>
|
|
58
66
|
<p v-if="description" :id="`${id}-description`" v-bind="descriptionProps">
|
|
@@ -62,6 +70,9 @@ const errorProps = computed(() => resolveSlot(ui.value.error, props.ui?.error));
|
|
|
62
70
|
</p>
|
|
63
71
|
</div>
|
|
64
72
|
<div v-bind="containerProps">
|
|
73
|
+
<label v-if="label && floatingLabel" :id="`${id}-label`" :for="id" data-selaras-floating-label v-bind="labelProps">
|
|
74
|
+
{{ label }}<span v-if="required" v-bind="requiredProps">*</span>
|
|
75
|
+
</label>
|
|
65
76
|
<slot :id="id" :invalid="invalid" :described-by="describedBy" />
|
|
66
77
|
</div>
|
|
67
78
|
</div>
|
|
@@ -73,3 +84,7 @@ const errorProps = computed(() => resolveSlot(ui.value.error, props.ui?.error));
|
|
|
73
84
|
</p>
|
|
74
85
|
</div>
|
|
75
86
|
</template>
|
|
87
|
+
|
|
88
|
+
<style scoped>
|
|
89
|
+
[data-selaras-label-mode=floating] [data-selaras-floating-label]{background:var(--selaras-resolved-surface-default);color:var(--selaras-resolved-text-muted);inset-inline-start:.75rem;line-height:1.2;max-width:calc(100% - 1.5rem);overflow:hidden;padding-inline:.25rem;pointer-events:none;position:absolute;text-overflow:ellipsis;top:50%;transform:translateY(-50%);transition:top .15s ease,color .15s ease,font-size .15s ease;white-space:nowrap;z-index:11}[data-selaras-label-mode=floating]:has(textarea) [data-selaras-floating-label]{top:1.1rem}[data-selaras-label-mode=floating]:has(:deep([data-selaras-field-leading])) [data-selaras-floating-label]{inset-inline-start:2.25rem;max-width:calc(100% - 3rem)}[data-selaras-label-mode=floating]:is(:focus-within,[data-filled],:has([data-selaras-field-segmented],[data-selaras-field-filled],[data-selaras-field-active],[data-ui-group-item]:is(input,textarea):not(:-moz-placeholder))) [data-selaras-floating-label]{color:var(--selaras-resolved-text-default);font-size:.75rem;top:0}[data-selaras-label-mode=floating]:is(:focus-within,[data-filled],:has([data-selaras-field-segmented],[data-selaras-field-filled],[data-selaras-field-active],[data-ui-group-item]:is(input,textarea):not(:placeholder-shown))) [data-selaras-floating-label]{color:var(--selaras-resolved-text-default);font-size:.75rem;top:0}[data-selaras-label-mode=floating][data-invalid] [data-selaras-floating-label]{color:var(--selaras-resolved-color-danger-text)}[data-selaras-label-mode=floating] :deep(:is(input,textarea)::-moz-placeholder){color:transparent}[data-selaras-label-mode=floating] :deep(:is(input,textarea)::placeholder){color:transparent}[data-selaras-label-mode=floating] :deep(:is(input,textarea):focus::-moz-placeholder){color:var(--selaras-resolved-text-muted)}[data-selaras-label-mode=floating] :deep(:is(input,textarea):focus::placeholder){color:var(--selaras-resolved-text-muted)}[data-selaras-label-mode=floating]:not(:has([data-selaras-field-segmented])) :deep([data-placeholder]){visibility:hidden}[data-selaras-label-mode=floating]:focus-within :deep([data-placeholder]){visibility:visible}@media (prefers-reduced-motion:reduce){[data-selaras-label-mode=floating] [data-selaras-floating-label]{transition:none}}
|
|
90
|
+
</style>
|
|
@@ -16,6 +16,10 @@ export interface FormFieldProps {
|
|
|
16
16
|
size?: FormFieldVariants['size'];
|
|
17
17
|
/** 'vertical' (default) stacks the label above the control; 'horizontal' places the label beside it, with the control filling the remaining row width. */
|
|
18
18
|
orientation?: FormFieldVariants['orientation'];
|
|
19
|
+
/** 'floating' overlays the label on an empty control and lifts it on focus, open, or once filled. */
|
|
20
|
+
labelMode?: FormFieldVariants['labelMode'];
|
|
21
|
+
/** Explicit filled state for a custom or third-party control. */
|
|
22
|
+
filled?: boolean;
|
|
19
23
|
ui?: UiProp<FormFieldThemeSlots>;
|
|
20
24
|
}
|
|
21
25
|
declare var __VLS_1: {}, __VLS_3: {
|
|
@@ -27,6 +27,7 @@ const props = defineProps({
|
|
|
27
27
|
});
|
|
28
28
|
const emit = defineEmits(["update:modelValue"]);
|
|
29
29
|
const field = useFormField();
|
|
30
|
+
const effectivePlaceholder = computed(() => props.placeholder || (field?.floatingLabel.value ? " " : void 0));
|
|
30
31
|
const inputId = computed(() => props.id ?? field?.id);
|
|
31
32
|
const inputInvalid = computed(() => props.invalid || (field?.invalid.value ?? false));
|
|
32
33
|
const describedBy = computed(() => field?.describedBy.value);
|
|
@@ -57,7 +58,7 @@ const inputProps = computed(() => mergeProps(baseProps.value, nativeInputAttrs.v
|
|
|
57
58
|
</script>
|
|
58
59
|
|
|
59
60
|
<template>
|
|
60
|
-
<div :data-selaras-color="inputInvalid ? 'danger' : effectiveColor" v-bind="rootProps">
|
|
61
|
+
<div :data-selaras-color="inputInvalid ? 'danger' : effectiveColor" :data-selaras-field-leading="icon ? '' : void 0" v-bind="rootProps">
|
|
61
62
|
<Icon v-if="icon" :name="icon" v-bind="resolveSlot(ui.leadingIcon, props.ui?.leadingIcon)" />
|
|
62
63
|
<input
|
|
63
64
|
:id="inputId"
|
|
@@ -65,7 +66,7 @@ const inputProps = computed(() => mergeProps(baseProps.value, nativeInputAttrs.v
|
|
|
65
66
|
:value="modelValue"
|
|
66
67
|
:type="type"
|
|
67
68
|
:name="name ?? field?.name"
|
|
68
|
-
:placeholder="
|
|
69
|
+
:placeholder="effectivePlaceholder"
|
|
69
70
|
:disabled="disabled"
|
|
70
71
|
:aria-invalid="inputInvalid || void 0"
|
|
71
72
|
:aria-describedby="describedBy"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed } from "vue";
|
|
2
|
+
import { computed, onMounted, ref } from "vue";
|
|
3
3
|
import { kbdTheme } from "../theme/kbd";
|
|
4
4
|
import { useComponentTheme, useRootProps } from "../utils/ui";
|
|
5
5
|
defineOptions({ inheritAttrs: false });
|
|
@@ -8,6 +8,10 @@ const props = defineProps({
|
|
|
8
8
|
size: { type: null, required: false },
|
|
9
9
|
ui: { type: Object, required: false }
|
|
10
10
|
});
|
|
11
|
+
const isMacPlatform = ref(false);
|
|
12
|
+
onMounted(() => {
|
|
13
|
+
isMacPlatform.value = /mac|iphone|ipad|ipod/i.test(navigator.platform || "");
|
|
14
|
+
});
|
|
11
15
|
const KEY_SYMBOLS = {
|
|
12
16
|
meta: "\u2318",
|
|
13
17
|
command: "\u2318",
|
|
@@ -31,7 +35,13 @@ const KEY_SYMBOLS = {
|
|
|
31
35
|
right: "\u2192",
|
|
32
36
|
space: "Space"
|
|
33
37
|
};
|
|
34
|
-
const resolvedValue = computed(() =>
|
|
38
|
+
const resolvedValue = computed(() => {
|
|
39
|
+
if (!props.value)
|
|
40
|
+
return void 0;
|
|
41
|
+
if (props.value.toLowerCase() === "mod")
|
|
42
|
+
return isMacPlatform.value ? KEY_SYMBOLS.meta : KEY_SYMBOLS.ctrl;
|
|
43
|
+
return KEY_SYMBOLS[props.value.toLowerCase()] ?? props.value;
|
|
44
|
+
});
|
|
35
45
|
const theme = useComponentTheme("kbd", kbdTheme);
|
|
36
46
|
const ui = computed(() => theme.value({ size: props.size }));
|
|
37
47
|
const rootProps = useRootProps(() => ui.value.base, () => props.ui?.base);
|
|
@@ -4,9 +4,10 @@ import { computed, getCurrentInstance, ref, useSlots, watch, watchEffect } from
|
|
|
4
4
|
import { useIcons } from "../composables/use-icons";
|
|
5
5
|
import { useMessages } from "../composables/use-messages";
|
|
6
6
|
import { modalTheme } from "../theme/modal";
|
|
7
|
-
import { resolveSlot, useComponentTheme, useThemeBindings } from "../utils/ui";
|
|
7
|
+
import { resolveSlot, useComponentTheme, useRootProps, useThemeBindings } from "../utils/ui";
|
|
8
8
|
import Button from "./Button.vue";
|
|
9
9
|
import Icon from "./Icon.vue";
|
|
10
|
+
defineOptions({ inheritAttrs: false });
|
|
10
11
|
const props = defineProps({
|
|
11
12
|
open: { type: Boolean, required: false, default: void 0 },
|
|
12
13
|
defaultOpen: { type: Boolean, required: false },
|
|
@@ -84,8 +85,8 @@ const messages = useMessages();
|
|
|
84
85
|
const theme = useComponentTheme("modal", modalTheme);
|
|
85
86
|
const themeBindings = useThemeBindings();
|
|
86
87
|
const ui = computed(() => theme.value({ fullscreen: internalFullscreen.value, transition: props.transition }));
|
|
88
|
+
const contentProps = useRootProps(() => ui.value.content, () => props.ui?.content);
|
|
87
89
|
const overlayProps = computed(() => resolveSlot(ui.value.overlay, props.ui?.overlay));
|
|
88
|
-
const contentProps = computed(() => resolveSlot(ui.value.content, props.ui?.content));
|
|
89
90
|
const headerProps = computed(() => resolveSlot(ui.value.header, props.ui?.header));
|
|
90
91
|
const headerActionsProps = computed(() => resolveSlot(ui.value.headerActions, props.ui?.headerActions));
|
|
91
92
|
const titleProps = computed(() => resolveSlot(ui.value.title, props.ui?.title));
|
|
@@ -45,19 +45,19 @@ declare var __VLS_8: {}, __VLS_17: string, __VLS_18: {
|
|
|
45
45
|
}, __VLS_124: string, __VLS_125: {
|
|
46
46
|
item: NavigationMenuItem;
|
|
47
47
|
active: boolean;
|
|
48
|
-
},
|
|
48
|
+
}, __VLS_147: string, __VLS_148: {
|
|
49
49
|
item: NavigationMenuItem;
|
|
50
50
|
active: boolean;
|
|
51
|
-
},
|
|
51
|
+
}, __VLS_151: string, __VLS_152: {
|
|
52
52
|
item: NavigationMenuItem;
|
|
53
53
|
active: boolean;
|
|
54
|
-
},
|
|
54
|
+
}, __VLS_160: string, __VLS_161: {
|
|
55
55
|
item: NavigationMenuItem;
|
|
56
56
|
active: boolean;
|
|
57
|
-
},
|
|
57
|
+
}, __VLS_164: string, __VLS_165: {
|
|
58
58
|
item: NavigationMenuItem;
|
|
59
59
|
active: boolean;
|
|
60
|
-
},
|
|
60
|
+
}, __VLS_172: {};
|
|
61
61
|
type __VLS_Slots = {} & {
|
|
62
62
|
[K in NonNullable<typeof __VLS_17>]?: (props: typeof __VLS_18) => any;
|
|
63
63
|
} & {
|
|
@@ -83,17 +83,17 @@ type __VLS_Slots = {} & {
|
|
|
83
83
|
} & {
|
|
84
84
|
[K in NonNullable<typeof __VLS_124>]?: (props: typeof __VLS_125) => any;
|
|
85
85
|
} & {
|
|
86
|
-
[K in NonNullable<typeof
|
|
86
|
+
[K in NonNullable<typeof __VLS_147>]?: (props: typeof __VLS_148) => any;
|
|
87
87
|
} & {
|
|
88
|
-
[K in NonNullable<typeof
|
|
88
|
+
[K in NonNullable<typeof __VLS_151>]?: (props: typeof __VLS_152) => any;
|
|
89
89
|
} & {
|
|
90
|
-
[K in NonNullable<typeof
|
|
90
|
+
[K in NonNullable<typeof __VLS_160>]?: (props: typeof __VLS_161) => any;
|
|
91
91
|
} & {
|
|
92
|
-
[K in NonNullable<typeof
|
|
92
|
+
[K in NonNullable<typeof __VLS_164>]?: (props: typeof __VLS_165) => any;
|
|
93
93
|
} & {
|
|
94
94
|
'list-leading'?: (props: typeof __VLS_8) => any;
|
|
95
95
|
} & {
|
|
96
|
-
'list-trailing'?: (props: typeof
|
|
96
|
+
'list-trailing'?: (props: typeof __VLS_172) => any;
|
|
97
97
|
};
|
|
98
98
|
declare const __VLS_base: import("vue").DefineComponent<NavigationMenuProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NavigationMenuProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
99
99
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -12,8 +12,10 @@ import { computed, ref, useSlots } from "vue";
|
|
|
12
12
|
import { NuxtLink } from "#components";
|
|
13
13
|
import { useRoute } from "#imports";
|
|
14
14
|
import { useIcons } from "../composables/use-icons";
|
|
15
|
+
import { vHotkey } from "../directives/hotkey";
|
|
16
|
+
import ShortcutHint from "../internal/ShortcutHint.vue";
|
|
15
17
|
import { navigationMenuTheme } from "../theme/navigation-menu";
|
|
16
|
-
import { isNavigationMenuItemActive } from "../utils/navigation-menu";
|
|
18
|
+
import { isNavigationMenuItemActive, navigationMenuHotkey } from "../utils/navigation-menu";
|
|
17
19
|
import { resolveRegisteredColorRole } from "../utils/registered-colors";
|
|
18
20
|
import { resolveSlot, useComponentTheme } from "../utils/ui";
|
|
19
21
|
import Icon from "./Icon.vue";
|
|
@@ -120,10 +122,10 @@ function onSelect(item, event) {
|
|
|
120
122
|
<li v-for="child in item.children" :key="child.label" v-bind="resolveSlot(ui.childItem, props.ui?.childItem)">
|
|
121
123
|
<NavigationMenuLink as-child :active="isActive(child)">
|
|
122
124
|
<component
|
|
123
|
-
:is="child.to ? NuxtLink : 'button'"
|
|
124
|
-
:
|
|
125
|
-
|
|
126
|
-
:aria-disabled="child.to && child.disabled ? 'true' : void 0" @click="onSelect(child, $event)"
|
|
125
|
+
:is="child.to ? NuxtLink : 'button'" v-hotkey="navigationMenuHotkey(child)" :to="child.to"
|
|
126
|
+
:type="child.to ? void 0 : 'button'" :disabled="child.to ? void 0 : child.disabled"
|
|
127
|
+
v-bind="childLinkProps(child)" :target="child.target" :rel="child.rel"
|
|
128
|
+
:aria-label="child.ariaLabel" :aria-disabled="child.to && child.disabled ? 'true' : void 0" @click="onSelect(child, $event)"
|
|
127
129
|
>
|
|
128
130
|
<slot :name="slotName(child, '')" :item="child" :active="isActive(child)">
|
|
129
131
|
<slot :name="slotName(child, '-leading')" :item="child" :active="isActive(child)">
|
|
@@ -133,6 +135,7 @@ function onSelect(item, event) {
|
|
|
133
135
|
<span v-bind="resolveSlot(ui.childLinkLabel, props.ui?.childLinkLabel)">{{ child.label }}</span>
|
|
134
136
|
</slot>
|
|
135
137
|
<slot :name="slotName(child, '-trailing')" :item="child" :active="isActive(child)" />
|
|
138
|
+
<ShortcutHint :shortcut="child.shortcut" />
|
|
136
139
|
</slot>
|
|
137
140
|
</component>
|
|
138
141
|
</NavigationMenuLink>
|
|
@@ -143,10 +146,10 @@ function onSelect(item, event) {
|
|
|
143
146
|
</template>
|
|
144
147
|
<NavigationMenuLink v-else as-child :active="isActive(item)">
|
|
145
148
|
<component
|
|
146
|
-
:is="item.to ? NuxtLink : 'button'"
|
|
147
|
-
:
|
|
148
|
-
|
|
149
|
-
:aria-disabled="item.to && item.disabled ? 'true' : void 0" @click="onSelect(item, $event)"
|
|
149
|
+
:is="item.to ? NuxtLink : 'button'" v-hotkey="navigationMenuHotkey(item)" :to="item.to"
|
|
150
|
+
:type="item.to ? void 0 : 'button'" :disabled="item.to ? void 0 : item.disabled"
|
|
151
|
+
v-bind="linkProps(item)" :target="item.target" :rel="item.rel"
|
|
152
|
+
:aria-label="item.ariaLabel" :aria-disabled="item.to && item.disabled ? 'true' : void 0" @click="onSelect(item, $event)"
|
|
150
153
|
>
|
|
151
154
|
<slot :name="slotName(item, '')" :item="item" :active="isActive(item)">
|
|
152
155
|
<slot :name="slotName(item, '-leading')" :item="item" :active="isActive(item)">
|
|
@@ -157,6 +160,7 @@ function onSelect(item, event) {
|
|
|
157
160
|
<span v-bind="resolveSlot(ui.linkLabel, props.ui?.linkLabel)">{{ item.label }}</span>
|
|
158
161
|
</slot>
|
|
159
162
|
<slot :name="slotName(item, '-trailing')" :item="item" :active="isActive(item)" />
|
|
163
|
+
<ShortcutHint :shortcut="collapsed ? void 0 : item.shortcut" />
|
|
160
164
|
</slot>
|
|
161
165
|
</component>
|
|
162
166
|
</NavigationMenuLink>
|