routie dev init since i didn't adhere to any proper guidance up until now

This commit is contained in:
2026-04-29 22:27:29 -06:00
commit e1dabb71e2
15301 changed files with 3562618 additions and 0 deletions
@@ -0,0 +1,34 @@
@layer vuetify-components {
.v-command-palette > .v-overlay__content > .v-sheet {
display: flex;
flex: 1 1 100%;
flex-direction: column;
}
.v-command-palette--density-default .v-command-palette__input-container {
padding-block: 8px;
padding-inline: 16px;
}
.v-command-palette--density-comfortable .v-command-palette__input-container {
padding-block: 4px;
padding-inline: 12px;
}
.v-command-palette--density-compact .v-command-palette__input-container {
padding-block: 0px;
padding-inline: 8px;
}
.v-command-palette__content {
overflow-y: auto;
}
.v-command-palette__no-data {
opacity: 0.6;
padding: 16px;
text-align: center;
}
.v-command-palette__list .v-list-subheader {
opacity: 0.7;
user-select: none;
}
.v-command-palette__list .v-divider {
margin-block: 4px;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,313 @@
import { createVNode as _createVNode, createElementVNode as _createElementVNode, mergeProps as _mergeProps, normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle } from "vue";
// Styles
import "./VCommandPalette.css";
// Components
import { VCommandPaletteSymbol } from "./shared.js";
import { VCommandPaletteItem } from "./VCommandPaletteItem.js";
import { VDialog } from "../../components/VDialog/index.js";
import { makeVDialogProps } from "../../components/VDialog/VDialog.js";
import { VList } from "../../components/VList/index.js";
import { VSheet } from "../../components/VSheet/index.js";
import { VTextField } from "../../components/VTextField/index.js"; // Composables
import { useCommandPaletteNavigation } from "./composables/useCommandPaletteNavigation.js";
import { makeDensityProps } from "../../composables/density.js";
import { makeFilterProps, useFilter } from "../../composables/filter.js";
import { useHotkey } from "../../composables/hotkey/index.js";
import { useLocale } from "../../composables/locale.js";
import { useProxiedModel } from "../../composables/proxiedModel.js"; // Utilities
import { computed, nextTick, onUnmounted, provide, ref, shallowRef, toRef, watch, watchEffect } from 'vue';
import { isActionItem } from "./types.js";
import { genericComponent, omit, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVCommandPaletteProps = propsFactory({
modelValue: Boolean,
search: String,
items: {
type: Array,
default: () => []
},
placeholder: {
type: String,
default: '$vuetify.command.search'
},
inputIcon: {
type: String,
default: '$search'
},
hotkey: String,
closeOnSelect: {
type: Boolean,
default: true
},
noDataText: {
type: String,
default: '$vuetify.noDataText'
},
listProps: Object,
...makeFilterProps({
filterKeys: ['title', 'subtitle']
}),
...makeDensityProps(),
...omit(makeVDialogProps({
maxWidth: 500
}), ['modelValue'])
}, 'VCommandPalette');
export const VCommandPalette = genericComponent()({
name: 'VCommandPalette',
props: makeVCommandPaletteProps(),
emits: {
'update:modelValue': value => true,
'update:search': value => true,
'click:item': (item, event) => true,
'before-select': payload => true
},
setup(props, {
emit,
slots
}) {
const {
t
} = useLocale();
const isOpen = useProxiedModel(props, 'modelValue');
const searchQuery = useProxiedModel(props, 'search');
const searchInputRef = ref();
const dialogRef = ref();
const previouslyFocusedElement = shallowRef(null);
const internalItems = computed(() => props.items.map((item, index) => ({
value: index,
type: item.type,
raw: item,
...('title' in item && {
title: item.title
}),
...('subtitle' in item && {
subtitle: item.subtitle
})
})));
const {
filteredItems: filterResult
} = useFilter(props, internalItems, searchQuery);
const filteredItems = computed(() => filterResult.value.map(item => item.raw));
const itemsForList = computed(() => {
return filteredItems.value.map((item, idx) => ({
...item,
value: idx
}));
});
function executeItem(item, event) {
if ('onClick' in item && item.onClick) {
item.onClick(event, item.value);
}
emit('click:item', item, event);
if (!isActionItem(item) || !props.closeOnSelect) return;
let shouldClose = true;
emit('before-select', {
item,
event,
preventDefault: () => {
shouldClose = false;
}
});
if (shouldClose) {
isOpen.value = false;
}
}
const navigation = useCommandPaletteNavigation({
filteredItems,
onItemClick: (item, event) => {
executeItem(item, event);
}
});
provide(VCommandPaletteSymbol, {
items: computed(() => props.items),
filteredItems,
selectedIndex: navigation.selectedIndex,
search: searchQuery,
setSelectedIndex: navigation.setSelectedIndex
});
// Register main hotkey with cleanup - using toRef for reactivity
const hotkeyUnsubscribe = useHotkey(toRef(props, 'hotkey'), () => {
isOpen.value = !isOpen.value;
});
watchEffect(onCleanup => {
if (!isOpen.value) {
return;
}
const hotkeyUnsubscribes = [];
function registerItemHotkeys(items) {
items.forEach(item => {
if (isActionItem(item) && item.hotkey) {
const unsubscribe = useHotkey(item.hotkey, event => {
event.preventDefault();
executeItem(item, event);
}, {
inputs: true
});
hotkeyUnsubscribes.push(unsubscribe);
}
});
}
registerItemHotkeys(props.items);
onCleanup(() => {
hotkeyUnsubscribes.forEach(unsubscribe => unsubscribe?.());
});
});
function findNextSelectableIndex(startIndex, direction) {
const items = filteredItems.value;
if (items.length === 0) return -1;
let index = startIndex;
const maxIterations = items.length;
for (let i = 0; i < maxIterations; i++) {
index += direction;
if (index >= items.length) index = 0;
if (index < 0) index = items.length - 1;
if (isActionItem(items[index])) {
return index;
}
}
return -1;
}
function handleSearchKeydown(e) {
switch (e.key) {
case 'ArrowDown':
{
e.preventDefault();
const nextIndex = findNextSelectableIndex(navigation.selectedIndex.value, 1);
if (nextIndex !== -1) {
navigation.setSelectedIndex(nextIndex);
}
break;
}
case 'ArrowUp':
{
e.preventDefault();
const prevIndex = findNextSelectableIndex(navigation.selectedIndex.value, -1);
if (prevIndex !== -1) {
navigation.setSelectedIndex(prevIndex);
}
break;
}
case 'Enter':
e.preventDefault();
navigation.executeSelected(e);
break;
case 'Escape':
e.preventDefault();
isOpen.value = false;
break;
}
}
watch(isOpen, (newValue, oldValue) => {
if (newValue && !oldValue) {
previouslyFocusedElement.value = document.activeElement;
searchQuery.value = '';
navigation.reset();
// Use requestAnimationFrame to ensure DOM is fully rendered
nextTick(() => {
requestAnimationFrame(() => {
if (searchInputRef.value && typeof searchInputRef.value.focus === 'function') {
searchInputRef.value.focus();
}
});
});
} else if (!newValue && oldValue) {
nextTick(() => {
previouslyFocusedElement.value?.focus({
preventScroll: true
});
previouslyFocusedElement.value = null;
});
}
}, {
immediate: true
});
onUnmounted(() => {
hotkeyUnsubscribe();
previouslyFocusedElement.value = null;
});
useRender(() => {
const dialogProps = VDialog.filterProps(omit(props, ['modelValue', 'class', 'style']));
return _createVNode(VDialog, _mergeProps({
"ref": dialogRef,
"class": "v-command-palette",
"modelValue": isOpen.value,
"onUpdate:modelValue": $event => isOpen.value = $event,
"scrollable": true
}, dialogProps), {
activator: slots.activator,
default: () => _createVNode(VSheet, {
"class": _normalizeClass(props.class),
"style": _normalizeStyle(props.style)
}, {
default: () => [slots.prepend?.(), _createElementVNode("div", {
"class": "v-command-palette__input-container"
}, [slots.input?.() ?? _createVNode(VTextField, {
"ref": searchInputRef,
"modelValue": searchQuery.value,
"onUpdate:modelValue": $event => searchQuery.value = $event,
"density": props.density,
"placeholder": t(props.placeholder),
"prependInnerIcon": props.inputIcon,
"autocomplete": "off",
"autofocus": true,
"singleLine": true,
"hideDetails": true,
"variant": "solo",
"flat": true,
"bgColor": "transparent",
"onKeydown": handleSearchKeydown
}, {
'append-inner': slots['input.append-inner']
})]), _createElementVNode("div", {
"class": "v-command-palette__content"
}, [filteredItems.value.length > 0 ? _createVNode(VList, _mergeProps({
"key": "list",
"class": "v-command-palette__list",
"density": props.density,
"items": itemsForList.value,
"itemType": "type",
"itemProps": true,
"activatable": true
}, props.listProps, {
"navigationStrategy": "track",
"navigationIndex": navigation.selectedIndex.value,
"onUpdate:navigationIndex": navigation.setSelectedIndex
}), {
prepend: slots['list.prepend'],
subheader: slots['list.subheader'],
item: ({
props: itemProps
}) => slots.item?.({
item: itemProps,
index: itemProps.index
}) ?? _createVNode(VCommandPaletteItem, {
"key": `item-${itemProps.index}`,
"item": itemProps,
"index": itemProps.index,
"onExecute": event => navigation.execute(itemProps.index, event)
}, {
prepend: slots['item.prepend'] ? () => slots['item.prepend']?.({
item: itemProps,
index: itemProps.index
}) : undefined,
title: slots['item.title'] ? () => slots['item.title']?.({
item: itemProps,
index: itemProps.index
}) : undefined,
append: slots['item.append'] ? () => slots['item.append']?.({
item: itemProps,
index: itemProps.index
}) : undefined
})
}) : _createElementVNode("div", {
"key": "no-data",
"class": "v-command-palette__no-data"
}, [slots['no-data']?.() || t(props.noDataText)])]), slots.append?.()]
})
});
});
}
});
//# sourceMappingURL=VCommandPalette.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,42 @@
@use '../../styles/tools';
@use './variables' as *;
@include tools.layer('components') {
.v-command-palette {
> .v-overlay__content > .v-sheet {
display: flex;
flex: 1 1 100%;
flex-direction: column;
}
@at-root {
@include tools.density('v-command-palette', $command-palette-density) using ($modifier) {
.v-command-palette__input-container {
padding-block: $command-palette-input-padding-block + $modifier;
padding-inline: $command-palette-input-padding-inline + $modifier;
}
}
}
&__content {
overflow-y: auto;
}
&__no-data {
opacity: $command-palette-no-data-opacity;
padding: $command-palette-no-data-padding;
text-align: center;
}
&__list {
.v-list-subheader {
opacity: $command-palette-subheader-opacity;
user-select: none;
}
.v-divider {
margin-block: $command-palette-divider-margin;
}
}
}
}
@@ -0,0 +1,157 @@
import type { PropType } from 'vue';
import type { VCommandPaletteActionItem } from './types.js';
export declare const makeVCommandPaletteItemProps: <Defaults extends {
item?: unknown;
index?: unknown;
onExecute?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
item: unknown extends Defaults["item"] ? {
type: PropType<VCommandPaletteActionItem>;
required: true;
} : Omit<{
type: PropType<VCommandPaletteActionItem>;
required: true;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["item"] ? VCommandPaletteActionItem : VCommandPaletteActionItem | Defaults["item"]>;
default: unknown extends Defaults["item"] ? VCommandPaletteActionItem : VCommandPaletteActionItem | Defaults["item"];
};
index: unknown extends Defaults["index"] ? {
type: NumberConstructor;
required: true;
} : Omit<{
type: NumberConstructor;
required: true;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["index"] ? number : number | Defaults["index"]>;
default: unknown extends Defaults["index"] ? number : number | Defaults["index"];
};
onExecute: unknown extends Defaults["onExecute"] ? PropType<(event: MouseEvent | KeyboardEvent) => void> : {
type: PropType<unknown extends Defaults["onExecute"] ? (event: MouseEvent | KeyboardEvent) => void : ((event: MouseEvent | KeyboardEvent) => void) | Defaults["onExecute"]>;
default: unknown extends Defaults["onExecute"] ? (event: MouseEvent | KeyboardEvent) => void : ((event: MouseEvent | KeyboardEvent) => void) | Defaults["onExecute"];
};
};
export type VCommandPaletteItemSlots = {
prepend: never;
title: never;
append: never;
};
export declare const VCommandPaletteItem: {
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
item: VCommandPaletteActionItem;
index: number;
} & {
onExecute?: ((event: MouseEvent | KeyboardEvent) => void) | undefined;
} & {
$children?: {
prepend?: (() => import("vue").VNodeChild) | undefined;
title?: (() => import("vue").VNodeChild) | undefined;
append?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | {} | import("vue").VNodeChild;
'v-slots'?: {
prepend?: false | (() => import("vue").VNodeChild) | undefined;
title?: false | (() => import("vue").VNodeChild) | undefined;
append?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:append"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:prepend"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:title"?: false | (() => import("vue").VNodeChild) | undefined;
}, void, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record<string, any>, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {}, true, {}, import("vue").SlotsType<Partial<{
prepend: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
title: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
append: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
P: {};
B: {};
D: {};
C: {};
M: {};
Defaults: {};
}, {
item: VCommandPaletteActionItem;
index: number;
} & {
onExecute?: ((event: MouseEvent | KeyboardEvent) => void) | undefined;
} & {
$children?: {
prepend?: (() => import("vue").VNodeChild) | undefined;
title?: (() => import("vue").VNodeChild) | undefined;
append?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | {} | import("vue").VNodeChild;
'v-slots'?: {
prepend?: false | (() => import("vue").VNodeChild) | undefined;
title?: false | (() => import("vue").VNodeChild) | undefined;
append?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:append"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:prepend"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:title"?: false | (() => import("vue").VNodeChild) | undefined;
}, {}, {}, {}, {}, {}>;
__isFragment?: never;
__isTeleport?: never;
__isSuspense?: never;
} & import("vue").ComponentOptionsBase<{
item: VCommandPaletteActionItem;
index: number;
} & {
onExecute?: ((event: MouseEvent | KeyboardEvent) => void) | undefined;
} & {
$children?: {
prepend?: (() => import("vue").VNodeChild) | undefined;
title?: (() => import("vue").VNodeChild) | undefined;
append?: (() => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | {} | import("vue").VNodeChild;
'v-slots'?: {
prepend?: false | (() => import("vue").VNodeChild) | undefined;
title?: false | (() => import("vue").VNodeChild) | undefined;
append?: false | (() => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:append"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:prepend"?: false | (() => import("vue").VNodeChild) | undefined;
"v-slot:title"?: false | (() => import("vue").VNodeChild) | undefined;
}, void, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record<string, any>, string, {}, {}, string, import("vue").SlotsType<Partial<{
prepend: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
title: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
append: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & import("../../util/index.js").FilterPropsOptions<{
item: {
type: PropType<VCommandPaletteActionItem>;
required: true;
};
index: {
type: NumberConstructor;
required: true;
};
onExecute: PropType<(event: MouseEvent | KeyboardEvent) => void>;
}, import("vue").ExtractPropTypes<{
item: {
type: PropType<VCommandPaletteActionItem>;
required: true;
};
index: {
type: NumberConstructor;
required: true;
};
onExecute: PropType<(event: MouseEvent | KeyboardEvent) => void>;
}>>;
export type VCommandPaletteItem = InstanceType<typeof VCommandPaletteItem>;
@@ -0,0 +1,42 @@
import { createVNode as _createVNode } from "vue";
// Components
import { VHotkey } from "../../components/VHotkey/index.js";
import { VListItem } from "../../components/VList/index.js"; // Utilities
import { genericComponent, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVCommandPaletteItemProps = propsFactory({
item: {
type: Object,
required: true
},
index: {
type: Number,
required: true
},
onExecute: Function
}, 'VCommandPaletteItem');
export const VCommandPaletteItem = genericComponent()({
name: 'VCommandPaletteItem',
props: makeVCommandPaletteItemProps(),
setup(props, {
slots
}) {
useRender(() => _createVNode(VListItem, {
"index": props.index,
"value": props.item.value,
"title": props.item.title,
"subtitle": props.item.subtitle,
"prependIcon": props.item.prependIcon,
"prependAvatar": props.item.prependAvatar,
"appendIcon": props.item.appendIcon,
"appendAvatar": props.item.appendAvatar,
"onClick": props.onExecute
}, {
prepend: slots.prepend,
title: slots.title,
append: slots.append ?? (props.item.hotkey ? () => _createVNode(VHotkey, {
"keys": props.item.hotkey
}, null) : undefined)
}));
}
});
//# sourceMappingURL=VCommandPaletteItem.js.map
@@ -0,0 +1 @@
{"version":3,"file":"VCommandPaletteItem.js","names":["VHotkey","VListItem","genericComponent","propsFactory","useRender","makeVCommandPaletteItemProps","item","type","Object","required","index","Number","onExecute","Function","VCommandPaletteItem","name","props","setup","slots","_createVNode","value","title","subtitle","prependIcon","prependAvatar","appendIcon","appendAvatar","prepend","append","hotkey","undefined"],"sources":["../../../src/labs/VCommandPalette/VCommandPaletteItem.tsx"],"sourcesContent":["// Components\nimport { VHotkey } from '@/components/VHotkey'\nimport { VListItem } from '@/components/VList'\n\n// Utilities\nimport { genericComponent, propsFactory, useRender } from '@/util'\n\n// Types\nimport type { PropType } from 'vue'\nimport type { VCommandPaletteActionItem } from './types'\n\nexport const makeVCommandPaletteItemProps = propsFactory({\n item: {\n type: Object as PropType<VCommandPaletteActionItem>,\n required: true,\n },\n index: {\n type: Number,\n required: true,\n },\n onExecute: Function as PropType<(event: MouseEvent | KeyboardEvent) => void>,\n}, 'VCommandPaletteItem')\n\nexport type VCommandPaletteItemSlots = {\n prepend: never\n title: never\n append: never\n}\n\nexport const VCommandPaletteItem = genericComponent<VCommandPaletteItemSlots>()({\n name: 'VCommandPaletteItem',\n\n props: makeVCommandPaletteItemProps(),\n\n setup (props, { slots }) {\n useRender(() => (\n <VListItem\n index={ props.index }\n value={ props.item.value }\n title={ props.item.title }\n subtitle={ props.item.subtitle }\n prependIcon={ props.item.prependIcon }\n prependAvatar={ props.item.prependAvatar }\n appendIcon={ props.item.appendIcon }\n appendAvatar={ props.item.appendAvatar }\n onClick={ props.onExecute }\n v-slots={{\n prepend: slots.prepend,\n title: slots.title,\n append: slots.append ?? (props.item.hotkey ? () => <VHotkey keys={ props.item.hotkey } /> : undefined),\n }}\n />\n ))\n },\n})\n\nexport type VCommandPaletteItem = InstanceType<typeof VCommandPaletteItem>\n"],"mappings":";AAAA;AAAA,SACSA,OAAO;AAAA,SACPC,SAAS,2CAElB;AAAA,SACSC,gBAAgB,EAAEC,YAAY,EAAEC,SAAS,+BAElD;AAIA,OAAO,MAAMC,4BAA4B,GAAGF,YAAY,CAAC;EACvDG,IAAI,EAAE;IACJC,IAAI,EAAEC,MAA6C;IACnDC,QAAQ,EAAE;EACZ,CAAC;EACDC,KAAK,EAAE;IACLH,IAAI,EAAEI,MAAM;IACZF,QAAQ,EAAE;EACZ,CAAC;EACDG,SAAS,EAAEC;AACb,CAAC,EAAE,qBAAqB,CAAC;AAQzB,OAAO,MAAMC,mBAAmB,GAAGZ,gBAAgB,CAA2B,CAAC,CAAC;EAC9Ea,IAAI,EAAE,qBAAqB;EAE3BC,KAAK,EAAEX,4BAA4B,CAAC,CAAC;EAErCY,KAAKA,CAAED,KAAK,EAAE;IAAEE;EAAM,CAAC,EAAE;IACvBd,SAAS,CAAC,MAAAe,YAAA,CAAAlB,SAAA;MAAA,SAEEe,KAAK,CAACN,KAAK;MAAA,SACXM,KAAK,CAACV,IAAI,CAACc,KAAK;MAAA,SAChBJ,KAAK,CAACV,IAAI,CAACe,KAAK;MAAA,YACbL,KAAK,CAACV,IAAI,CAACgB,QAAQ;MAAA,eAChBN,KAAK,CAACV,IAAI,CAACiB,WAAW;MAAA,iBACpBP,KAAK,CAACV,IAAI,CAACkB,aAAa;MAAA,cAC3BR,KAAK,CAACV,IAAI,CAACmB,UAAU;MAAA,gBACnBT,KAAK,CAACV,IAAI,CAACoB,YAAY;MAAA,WAC5BV,KAAK,CAACJ;IAAS,GAChB;MACPe,OAAO,EAAET,KAAK,CAACS,OAAO;MACtBN,KAAK,EAAEH,KAAK,CAACG,KAAK;MAClBO,MAAM,EAAEV,KAAK,CAACU,MAAM,KAAKZ,KAAK,CAACV,IAAI,CAACuB,MAAM,GAAG,MAAAV,YAAA,CAAAnB,OAAA;QAAA,QAAsBgB,KAAK,CAACV,IAAI,CAACuB;MAAM,QAAK,GAAGC,SAAS;IACvG,CAAC,CAEJ,CAAC;EACJ;AACF,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,7 @@
$command-palette-density: ('default': 0, 'comfortable': -1, 'compact': -2) !default;
$command-palette-input-padding-block: 8px !default;
$command-palette-input-padding-inline: 16px !default;
$command-palette-no-data-padding: 16px !default;
$command-palette-no-data-opacity: 0.6 !default;
$command-palette-subheader-opacity: 0.7 !default;
$command-palette-divider-margin: 4px !default;
@@ -0,0 +1,15 @@
import type { ComputedRef, Ref } from 'vue';
import type { VCommandPaletteItem } from '../types.js';
export interface UseCommandPaletteNavigationOptions {
filteredItems: ComputedRef<VCommandPaletteItem[]>;
onItemClick: (item: VCommandPaletteItem, event: KeyboardEvent | MouseEvent) => void;
}
export interface UseCommandPaletteNavigationReturn {
selectedIndex: Readonly<Ref<number>>;
getSelectedItem: () => VCommandPaletteItem | undefined;
execute: (index: number, event: KeyboardEvent | MouseEvent) => void;
executeSelected: (event: KeyboardEvent | MouseEvent) => void;
reset: () => void;
setSelectedIndex: (index: number) => void;
}
export declare function useCommandPaletteNavigation(options: UseCommandPaletteNavigationOptions): UseCommandPaletteNavigationReturn;
@@ -0,0 +1,89 @@
// Utilities
import { readonly, ref, shallowRef, watch } from 'vue';
// Types
import { isActionItem } from "../types.js";
function getItemKey(item) {
if (!isActionItem(item)) return undefined;
return item.value !== undefined ? String(item.value) : item.title;
}
function findFirstSelectableIndex(items) {
return items.findIndex(item => isActionItem(item));
}
export function useCommandPaletteNavigation(options) {
const selectedIndex = ref(0);
const selectedItemKey = shallowRef(undefined);
watch(() => options.filteredItems.value, (newItems, oldItems) => {
if (newItems.length === 0) {
selectedIndex.value = -1;
selectedItemKey.value = undefined;
return;
}
if (selectedItemKey.value !== undefined) {
const newIndex = newItems.findIndex(item => isActionItem(item) && getItemKey(item) === selectedItemKey.value);
if (newIndex !== -1) {
selectedIndex.value = newIndex;
return;
}
}
const firstSelectableIndex = findFirstSelectableIndex(newItems);
if (firstSelectableIndex !== -1) {
selectedIndex.value = firstSelectableIndex;
selectedItemKey.value = getItemKey(newItems[firstSelectableIndex]);
return;
}
selectedIndex.value = 0;
selectedItemKey.value = undefined;
}, {
immediate: true
});
function getSelectedItem() {
return options.filteredItems.value[selectedIndex.value];
}
function execute(index, event) {
const item = options.filteredItems.value[index];
if (item) {
options.onItemClick(item, event);
}
}
function executeSelected(event) {
const item = getSelectedItem();
if (item) {
options.onItemClick(item, event);
}
}
function reset() {
const items = options.filteredItems.value;
if (items.length === 0) {
selectedIndex.value = -1;
selectedItemKey.value = undefined;
return;
}
const firstSelectableIndex = findFirstSelectableIndex(items);
if (firstSelectableIndex !== -1) {
selectedIndex.value = firstSelectableIndex;
selectedItemKey.value = getItemKey(items[firstSelectableIndex]);
return;
}
selectedIndex.value = 0;
selectedItemKey.value = undefined;
}
function setSelectedIndex(index) {
// Ignore VList's reset to -1 when we have items - we manage selection on filter changes
if (index === -1 && options.filteredItems.value.length > 0) {
return;
}
selectedIndex.value = index;
const item = options.filteredItems.value[index];
selectedItemKey.value = item ? getItemKey(item) : undefined;
}
return {
selectedIndex: readonly(selectedIndex),
getSelectedItem,
execute,
executeSelected,
reset,
setSelectedIndex
};
}
//# sourceMappingURL=useCommandPaletteNavigation.js.map
File diff suppressed because one or more lines are too long
+2
View File
@@ -0,0 +1,2 @@
export { VCommandPalette } from './VCommandPalette.js';
export { VCommandPaletteItem } from './VCommandPaletteItem.js';
+3
View File
@@ -0,0 +1,3 @@
export { VCommandPalette } from "./VCommandPalette.js";
export { VCommandPaletteItem } from "./VCommandPaletteItem.js";
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","names":["VCommandPalette","VCommandPaletteItem"],"sources":["../../../src/labs/VCommandPalette/index.ts"],"sourcesContent":["export { VCommandPalette } from './VCommandPalette'\nexport { VCommandPaletteItem } from './VCommandPaletteItem'\n"],"mappings":"SAASA,eAAe;AAAA,SACfC,mBAAmB","ignoreList":[]}
+11
View File
@@ -0,0 +1,11 @@
import type { InjectionKey, Ref } from 'vue';
import type { VCommandPaletteItem } from './types.js';
export interface CommandPaletteProvide {
items: Ref<VCommandPaletteItem[]>;
filteredItems: Ref<VCommandPaletteItem[]>;
selectedIndex: Ref<number>;
search: Ref<string>;
setSelectedIndex: (index: number) => void;
}
export declare const VCommandPaletteSymbol: InjectionKey<CommandPaletteProvide>;
export declare function useCommandPalette(): CommandPaletteProvide;
+14
View File
@@ -0,0 +1,14 @@
// Utilities
import { inject } from 'vue';
// Types
export const VCommandPaletteSymbol = Symbol.for('vuetify:command-palette');
export function useCommandPalette() {
const commandPalette = inject(VCommandPaletteSymbol);
if (!commandPalette) {
throw new Error('[Vuetify] useCommandPalette must be used within VCommandPalette');
}
return commandPalette;
}
//# sourceMappingURL=shared.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"shared.js","names":["inject","VCommandPaletteSymbol","Symbol","for","useCommandPalette","commandPalette","Error"],"sources":["../../../src/labs/VCommandPalette/shared.ts"],"sourcesContent":["// Utilities\nimport { inject } from 'vue'\n\n// Types\nimport type { InjectionKey, Ref } from 'vue'\nimport type { VCommandPaletteItem } from './types'\n\nexport interface CommandPaletteProvide {\n items: Ref<VCommandPaletteItem[]>\n filteredItems: Ref<VCommandPaletteItem[]>\n selectedIndex: Ref<number>\n search: Ref<string>\n setSelectedIndex: (index: number) => void\n}\n\nexport const VCommandPaletteSymbol: InjectionKey<CommandPaletteProvide> = Symbol.for('vuetify:command-palette')\n\nexport function useCommandPalette () {\n const commandPalette = inject(VCommandPaletteSymbol)\n\n if (!commandPalette) {\n throw new Error('[Vuetify] useCommandPalette must be used within VCommandPalette')\n }\n\n return commandPalette\n}\n"],"mappings":"AAAA;AACA,SAASA,MAAM,QAAQ,KAAK;;AAE5B;;AAYA,OAAO,MAAMC,qBAA0D,GAAGC,MAAM,CAACC,GAAG,CAAC,yBAAyB,CAAC;AAE/G,OAAO,SAASC,iBAAiBA,CAAA,EAAI;EACnC,MAAMC,cAAc,GAAGL,MAAM,CAACC,qBAAqB,CAAC;EAEpD,IAAI,CAACI,cAAc,EAAE;IACnB,MAAM,IAAIC,KAAK,CAAC,iEAAiE,CAAC;EACpF;EAEA,OAAOD,cAAc;AACvB","ignoreList":[]}
+32
View File
@@ -0,0 +1,32 @@
// @ts-ignore
import type { RouteLocationRaw } from 'vue-router';
export interface BaseVListItem {
title?: string;
subtitle?: string;
prependIcon?: string;
appendIcon?: string;
prependAvatar?: string;
appendAvatar?: string;
}
interface NavigableItemProps {
to?: RouteLocationRaw;
href?: string;
}
export interface VCommandPaletteActionItem extends BaseVListItem, NavigableItemProps {
type?: 'item';
onClick?: (event: MouseEvent | KeyboardEvent, value?: any) => void;
value?: any;
hotkey?: string;
}
export interface VCommandPaletteSubheader {
type: 'subheader';
title: string;
inset?: boolean;
}
export interface VCommandPaletteDivider {
type: 'divider';
inset?: boolean;
}
export type VCommandPaletteItem = VCommandPaletteActionItem | VCommandPaletteSubheader | VCommandPaletteDivider;
export declare function isActionItem(item: any): item is VCommandPaletteActionItem;
+6
View File
@@ -0,0 +1,6 @@
// Types
export function isActionItem(item) {
return !item.type || item.type === 'item';
}
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","names":["isActionItem","item","type"],"sources":["../../../src/labs/VCommandPalette/types.ts"],"sourcesContent":["// Types\nimport type { RouteLocationRaw } from 'vue-router'\n\nexport interface BaseVListItem {\n title?: string\n subtitle?: string\n prependIcon?: string\n appendIcon?: string\n prependAvatar?: string\n appendAvatar?: string\n}\n\ninterface NavigableItemProps {\n to?: RouteLocationRaw\n href?: string\n}\n\nexport interface VCommandPaletteActionItem extends BaseVListItem, NavigableItemProps {\n type?: 'item'\n onClick?: (event: MouseEvent | KeyboardEvent, value?: any) => void\n value?: any\n hotkey?: string\n}\n\nexport interface VCommandPaletteSubheader {\n type: 'subheader'\n title: string\n inset?: boolean\n}\n\nexport interface VCommandPaletteDivider {\n type: 'divider'\n inset?: boolean\n}\n\nexport type VCommandPaletteItem =\n | VCommandPaletteActionItem\n | VCommandPaletteSubheader\n | VCommandPaletteDivider\n\nexport function isActionItem (item: any): item is VCommandPaletteActionItem {\n return !item.type || item.type === 'item'\n}\n"],"mappings":"AAAA;;AAwCA,OAAO,SAASA,YAAYA,CAAEC,IAAS,EAAqC;EAC1E,OAAO,CAACA,IAAI,CAACC,IAAI,IAAID,IAAI,CAACC,IAAI,KAAK,MAAM;AAC3C","ignoreList":[]}