@leavepulse/ui 0.33.1 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{LpCommandPalette-CEY-pajO.css → LpCommandPalette-BERCHiev.css} +4 -4
- package/dist/components/LpActionBar.vue.d.ts +1 -1
- package/dist/components/LpAddressInput.vue.d.ts +3 -3
- package/dist/components/LpAppShell.vue.d.ts +1 -4
- package/dist/components/LpAutocomplete.vue.d.ts +1 -1
- package/dist/components/LpBadge.vue.d.ts +2 -2
- package/dist/components/LpCodeBlock.vue.d.ts +1 -1
- package/dist/components/LpColorPicker.vue.d.ts +4 -9
- package/dist/components/LpCommandPalette.vue.d.ts +62 -0
- package/dist/components/LpCommandPalette.vue.js +237 -56
- package/dist/components/LpDropzone.vue.d.ts +4 -4
- package/dist/components/LpFileTree.vue.d.ts +4 -4
- package/dist/components/LpFormField.vue.d.ts +1 -1
- package/dist/components/LpLaneNode.vue.d.ts +0 -11
- package/dist/components/LpLightbox.vue.d.ts +2 -2
- package/dist/components/LpLogViewer.vue.d.ts +1 -1
- package/dist/components/LpMapPicker.vue.d.ts +1 -1
- package/dist/components/LpMediaGallery.vue.d.ts +1 -1
- package/dist/components/LpPie.vue.d.ts +4 -22
- package/dist/components/LpPopover.vue.d.ts +1 -1
- package/dist/components/LpProgress.vue.d.ts +2 -2
- package/dist/components/LpRollingText.vue.d.ts +3 -3
- package/dist/components/LpSelect.vue.d.ts +6 -6
- package/dist/components/LpShift.vue.d.ts +1 -1
- package/dist/components/LpShortcutsDialog.vue.d.ts +1 -1
- package/dist/components/LpSidebar.vue.d.ts +1 -7
- package/dist/components/LpSidebarNav.vue.d.ts +2 -2
- package/dist/components/LpSlider.vue.d.ts +2 -2
- package/dist/components/LpSparkline.vue.d.ts +2 -2
- package/dist/components/LpTable.vue.d.ts +9 -9
- package/dist/components/LpTabs.vue.d.ts +1 -1
- package/dist/components/LpThemeSwitcher.vue.d.ts +1 -1
- package/dist/components/LpTilt.vue.d.ts +1 -1
- package/dist/components/LpTooltip.vue.d.ts +1 -1
- package/dist/components/LpTopologyCanvas.vue.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/LpCommandPalette.vue +369 -21
- package/src/index.ts +1 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
|
|
2
2
|
/* Each result eases in; honours reduced motion. */
|
|
3
|
-
.lp-cmd-item[data-v-
|
|
4
|
-
animation: lp-cmd-in-
|
|
3
|
+
.lp-cmd-item[data-v-d0e03a58] {
|
|
4
|
+
animation: lp-cmd-in-d0e03a58 140ms ease-out both;
|
|
5
5
|
}
|
|
6
|
-
@keyframes lp-cmd-in-
|
|
6
|
+
@keyframes lp-cmd-in-d0e03a58 {
|
|
7
7
|
from {
|
|
8
8
|
opacity: 0;
|
|
9
9
|
transform: translateY(3px);
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
@media (prefers-reduced-motion: reduce) {
|
|
13
|
-
.lp-cmd-item[data-v-
|
|
13
|
+
.lp-cmd-item[data-v-d0e03a58] {
|
|
14
14
|
animation: none;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -70,8 +70,8 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
70
70
|
onDismiss?: (() => any) | undefined;
|
|
71
71
|
}>, {
|
|
72
72
|
width: "contained" | "full";
|
|
73
|
-
open: boolean;
|
|
74
73
|
variant: "default" | "danger";
|
|
74
|
+
open: boolean;
|
|
75
75
|
actions: ActionBarAction[];
|
|
76
76
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
77
77
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -58,9 +58,9 @@ declare const __VLS_export: __VLS_WithSlots<import('vue').DefineComponent<{
|
|
|
58
58
|
debounce: number;
|
|
59
59
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>, {
|
|
60
60
|
map?: (props: {
|
|
61
|
-
point:
|
|
62
|
-
setPoint:
|
|
63
|
-
tiles:
|
|
61
|
+
point: any;
|
|
62
|
+
setPoint: any;
|
|
63
|
+
tiles: any;
|
|
64
64
|
}) => any;
|
|
65
65
|
}>;
|
|
66
66
|
type __VLS_WithSlots<T, S> = T & {
|
|
@@ -101,10 +101,7 @@ declare const __VLS_export: __VLS_WithSlots<import('vue').DefineComponent<{
|
|
|
101
101
|
} & {
|
|
102
102
|
'sidebar-footer'?: (props: {}) => any;
|
|
103
103
|
} & {
|
|
104
|
-
'sidebar-item'?: (props:
|
|
105
|
-
item: SidebarItem;
|
|
106
|
-
active: boolean;
|
|
107
|
-
}) => any;
|
|
104
|
+
'sidebar-item'?: (props: any) => any;
|
|
108
105
|
} & {
|
|
109
106
|
'header-title'?: (props: {}) => any;
|
|
110
107
|
} & {
|
|
@@ -40,9 +40,9 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {
|
|
|
40
40
|
size: "sm" | "md" | "lg";
|
|
41
41
|
filter: boolean;
|
|
42
42
|
placeholder: string;
|
|
43
|
-
loading: boolean;
|
|
44
43
|
clearable: boolean;
|
|
45
44
|
emptyText: string;
|
|
45
|
+
loading: boolean;
|
|
46
46
|
loadingText: string;
|
|
47
47
|
minChars: number;
|
|
48
48
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
declare const _default: typeof __VLS_export;
|
|
2
2
|
export default _default;
|
|
3
3
|
declare const __VLS_export: __VLS_WithSlots<import('vue').DefineComponent<{
|
|
4
|
-
tone?: "
|
|
4
|
+
tone?: "danger" | "action" | "outline" | "success" | "warning" | "neutral" | "brand" | undefined;
|
|
5
5
|
/** `sm` is the one that does not disturb a text-sm line it sits on. */
|
|
6
6
|
size?: "sm" | "md" | "lg" | undefined;
|
|
7
7
|
dot?: boolean;
|
|
8
8
|
}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{
|
|
9
|
-
tone?: "
|
|
9
|
+
tone?: "danger" | "action" | "outline" | "success" | "warning" | "neutral" | "brand" | undefined;
|
|
10
10
|
/** `sm` is the one that does not disturb a text-sm line it sits on. */
|
|
11
11
|
size?: "sm" | "md" | "lg" | undefined;
|
|
12
12
|
dot?: boolean;
|
|
@@ -49,8 +49,8 @@ declare const __VLS_export: import('vue').DefineComponent<{
|
|
|
49
49
|
"onUpdate:locked"?: ((value: boolean) => any) | undefined;
|
|
50
50
|
}>, {
|
|
51
51
|
lang: CodeLang;
|
|
52
|
-
wrap: boolean;
|
|
53
52
|
lineNumbers: boolean;
|
|
53
|
+
wrap: boolean;
|
|
54
54
|
locked: boolean;
|
|
55
55
|
lockToggle: boolean;
|
|
56
56
|
copyable: boolean;
|
|
@@ -82,13 +82,8 @@ type __VLS_Props = {
|
|
|
82
82
|
copyToast?: string | false;
|
|
83
83
|
};
|
|
84
84
|
declare var __VLS_56: {
|
|
85
|
-
color:
|
|
86
|
-
hsv:
|
|
87
|
-
h: number;
|
|
88
|
-
s: number;
|
|
89
|
-
v: number;
|
|
90
|
-
a: number;
|
|
91
|
-
};
|
|
85
|
+
color: any;
|
|
86
|
+
hsv: any;
|
|
92
87
|
};
|
|
93
88
|
type __VLS_Slots = {} & {
|
|
94
89
|
default?: (props: typeof __VLS_56) => any;
|
|
@@ -103,10 +98,10 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {
|
|
|
103
98
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
104
99
|
}>, {
|
|
105
100
|
size: "sm" | "md" | "lg";
|
|
106
|
-
format: ColorFormat;
|
|
107
|
-
align: "start" | "center" | "end";
|
|
108
101
|
modelValue: string;
|
|
102
|
+
format: ColorFormat;
|
|
109
103
|
side: "top" | "right" | "bottom" | "left";
|
|
104
|
+
align: "start" | "center" | "end";
|
|
110
105
|
alpha: boolean;
|
|
111
106
|
swatches: readonly string[];
|
|
112
107
|
recent: boolean;
|
|
@@ -17,8 +17,35 @@ export interface Command {
|
|
|
17
17
|
* decommission, …) that shouldn't clutter the palette but stay reachable.
|
|
18
18
|
*/
|
|
19
19
|
hidden?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Picking this opens a mode instead of closing: a nested list, either given
|
|
22
|
+
* outright or fetched from the query typed inside it. This is what keeps a
|
|
23
|
+
* palette from flattening "restart <service>" into one row per service —
|
|
24
|
+
* and what lets the second step search a list too big to enumerate.
|
|
25
|
+
*
|
|
26
|
+
* `onSelect` still runs when the mode opens, so a command can both act and
|
|
27
|
+
* drill in.
|
|
28
|
+
*/
|
|
29
|
+
children?: Command[] | ((query: string) => Command[] | Promise<Command[]>);
|
|
30
|
+
/** Placeholder while inside this command's mode. */
|
|
31
|
+
childPlaceholder?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Keep the palette open after this runs. For a command that toggles
|
|
34
|
+
* something the user may want to toggle again (a theme, a filter) without
|
|
35
|
+
* reopening and retyping.
|
|
36
|
+
*/
|
|
37
|
+
keepOpen?: boolean;
|
|
20
38
|
onSelect?: () => void;
|
|
21
39
|
}
|
|
40
|
+
/** Footer hints and the mode chip, spelled out so an app can translate them. */
|
|
41
|
+
export interface PaletteLabels {
|
|
42
|
+
navigate: string;
|
|
43
|
+
select: string;
|
|
44
|
+
close: string;
|
|
45
|
+
/** Hint for leaving a mode, shown only while inside one. */
|
|
46
|
+
back: string;
|
|
47
|
+
searching: string;
|
|
48
|
+
}
|
|
22
49
|
type __VLS_Props = {
|
|
23
50
|
open?: boolean;
|
|
24
51
|
commands: Command[];
|
|
@@ -26,17 +53,52 @@ type __VLS_Props = {
|
|
|
26
53
|
emptyText?: string;
|
|
27
54
|
/** Bind a global ⌘K / Ctrl-K toggle. */
|
|
28
55
|
hotkey?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Commands fetched from the typed query — what reaches the things too many
|
|
58
|
+
* (or too remote) to hand over as a list: people, files, tickets. Called
|
|
59
|
+
* debounced, never for a query shorter than `minChars`, and only its
|
|
60
|
+
* newest call counts: an earlier one that lands late is dropped, so a slow
|
|
61
|
+
* response can't overwrite a fresher list.
|
|
62
|
+
*
|
|
63
|
+
* Results join the static commands, so a palette can do both.
|
|
64
|
+
*/
|
|
65
|
+
search?: (query: string, signal: AbortSignal) => Command[] | Promise<Command[]>;
|
|
66
|
+
/** Wait after the last keystroke before `search` runs. */
|
|
67
|
+
debounce?: number;
|
|
68
|
+
/** Shortest query `search` runs for. */
|
|
69
|
+
minChars?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Ids of recently picked commands, newest first — bind it to storage and
|
|
72
|
+
* the palette opens on what this person actually uses. It only reorders
|
|
73
|
+
* commands already in the list; an id that no longer resolves is skipped,
|
|
74
|
+
* so a stored history never resurrects a command that has gone away.
|
|
75
|
+
*/
|
|
76
|
+
recent?: string[];
|
|
77
|
+
/** How many recent commands to surface. */
|
|
78
|
+
recentLimit?: number;
|
|
79
|
+
/** Headings the palette adds itself. */
|
|
80
|
+
recentLabel?: string;
|
|
81
|
+
resultsLabel?: string;
|
|
82
|
+
/** Footer hints and the mode chip, spelled out for translation. */
|
|
83
|
+
labels?: Partial<PaletteLabels>;
|
|
29
84
|
};
|
|
30
85
|
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
31
86
|
select: (command: Command) => any;
|
|
32
87
|
"update:open": (value: boolean) => any;
|
|
88
|
+
run: (id: string, command: Command) => any;
|
|
33
89
|
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
34
90
|
onSelect?: ((command: Command) => any) | undefined;
|
|
35
91
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
92
|
+
onRun?: ((id: string, command: Command) => any) | undefined;
|
|
36
93
|
}>, {
|
|
37
94
|
placeholder: string;
|
|
38
95
|
emptyText: string;
|
|
96
|
+
minChars: number;
|
|
97
|
+
debounce: number;
|
|
98
|
+
recentLimit: number;
|
|
39
99
|
hotkey: boolean;
|
|
100
|
+
recentLabel: string;
|
|
101
|
+
resultsLabel: string;
|
|
40
102
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
41
103
|
declare const _default: typeof __VLS_export;
|
|
42
104
|
export default _default;
|
|
@@ -1,38 +1,47 @@
|
|
|
1
|
-
import { defineComponent, ref,
|
|
1
|
+
import { defineComponent, computed, ref, shallowRef, onBeforeUnmount, watch, nextTick, openBlock, createBlock, unref, withCtx, createVNode, withModifiers, createTextVNode, createElementVNode, createElementBlock, Fragment, renderList, createCommentVNode, toDisplayString, withDirectives, withKeys, vModelText, normalizeClass } from "vue";
|
|
2
2
|
import { DialogRoot, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription } from "reka-ui";
|
|
3
3
|
import { _ as _sfc_main$1 } from "../chunks/LpIcon-CCnX5_2j.js";
|
|
4
4
|
import { _ as _sfc_main$2 } from "../chunks/LpScrollArea-D8xyKXcF.js";
|
|
5
5
|
import { useHotkeys } from "../composables/useHotkeys.js";
|
|
6
6
|
import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
|
|
7
|
-
import '../assets/LpCommandPalette-
|
|
8
|
-
const _hoisted_2 = ["
|
|
9
|
-
const _hoisted_3 =
|
|
7
|
+
import '../assets/LpCommandPalette-BERCHiev.css';const _hoisted_1 = { class: "flex shrink-0 items-center gap-2.5 border-b border-line px-4" };
|
|
8
|
+
const _hoisted_2 = ["title", "onClick"];
|
|
9
|
+
const _hoisted_3 = ["placeholder", "onKeydown"];
|
|
10
|
+
const _hoisted_4 = {
|
|
10
11
|
key: 0,
|
|
11
12
|
class: "px-2 py-10 text-center text-sm text-muted"
|
|
12
13
|
};
|
|
13
|
-
const
|
|
14
|
+
const _hoisted_5 = {
|
|
14
15
|
key: 0,
|
|
15
16
|
class: "px-2 pb-1 pt-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted"
|
|
16
17
|
};
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
18
|
+
const _hoisted_6 = ["data-cmd-index", "disabled", "onClick", "onPointerenter"];
|
|
19
|
+
const _hoisted_7 = { class: "min-w-0 flex-1" };
|
|
20
|
+
const _hoisted_8 = { class: "block truncate font-medium" };
|
|
21
|
+
const _hoisted_9 = {
|
|
21
22
|
key: 0,
|
|
22
23
|
class: "rounded-xs bg-brand/25 text-ink"
|
|
23
24
|
};
|
|
24
|
-
const
|
|
25
|
+
const _hoisted_10 = {
|
|
25
26
|
key: 0,
|
|
26
27
|
class: "mt-0.5 block truncate text-xs text-muted"
|
|
27
28
|
};
|
|
28
|
-
const
|
|
29
|
+
const _hoisted_11 = {
|
|
29
30
|
key: 0,
|
|
30
31
|
class: "rounded-xs bg-brand/20 text-ink"
|
|
31
32
|
};
|
|
32
|
-
const
|
|
33
|
+
const _hoisted_12 = {
|
|
33
34
|
key: 1,
|
|
34
35
|
class: "shrink-0 text-xs text-muted"
|
|
35
36
|
};
|
|
37
|
+
const _hoisted_13 = { class: "flex shrink-0 items-center gap-4 border-t border-line px-4 py-2.5 text-[11px] text-muted" };
|
|
38
|
+
const _hoisted_14 = { class: "flex items-center gap-1" };
|
|
39
|
+
const _hoisted_15 = { class: "flex items-center gap-1" };
|
|
40
|
+
const _hoisted_16 = {
|
|
41
|
+
key: 0,
|
|
42
|
+
class: "flex items-center gap-1"
|
|
43
|
+
};
|
|
44
|
+
const _hoisted_17 = { class: "ml-auto flex items-center gap-1" };
|
|
36
45
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
37
46
|
__name: "LpCommandPalette",
|
|
38
47
|
props: {
|
|
@@ -40,20 +49,107 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
40
49
|
commands: {},
|
|
41
50
|
placeholder: { default: "Type a command or search…" },
|
|
42
51
|
emptyText: { default: "No results" },
|
|
43
|
-
hotkey: { type: Boolean, default: true }
|
|
52
|
+
hotkey: { type: Boolean, default: true },
|
|
53
|
+
search: {},
|
|
54
|
+
debounce: { default: 250 },
|
|
55
|
+
minChars: { default: 1 },
|
|
56
|
+
recent: {},
|
|
57
|
+
recentLimit: { default: 5 },
|
|
58
|
+
recentLabel: { default: "Recent" },
|
|
59
|
+
resultsLabel: { default: "Results" },
|
|
60
|
+
labels: {}
|
|
44
61
|
},
|
|
45
|
-
emits: ["update:open", "select"],
|
|
62
|
+
emits: ["update:open", "select", "run"],
|
|
46
63
|
setup(__props, { emit: __emit }) {
|
|
47
64
|
const props = __props;
|
|
65
|
+
const DEFAULT_LABELS = {
|
|
66
|
+
navigate: "navigate",
|
|
67
|
+
select: "select",
|
|
68
|
+
close: "close",
|
|
69
|
+
back: "back",
|
|
70
|
+
searching: "Searching…"
|
|
71
|
+
};
|
|
72
|
+
const text = computed(() => ({ ...DEFAULT_LABELS, ...props.labels }));
|
|
48
73
|
const emit = __emit;
|
|
49
74
|
const query = ref("");
|
|
50
75
|
const selectedIndex = ref(0);
|
|
51
76
|
const inputRef = ref(null);
|
|
52
77
|
const scrollRef = ref(null);
|
|
78
|
+
const trail = shallowRef([]);
|
|
79
|
+
const mode = computed(() => trail.value[trail.value.length - 1] ?? null);
|
|
80
|
+
const modeItems = shallowRef([]);
|
|
81
|
+
function enter(c) {
|
|
82
|
+
trail.value = [...trail.value, c];
|
|
83
|
+
query.value = "";
|
|
84
|
+
selectedIndex.value = 0;
|
|
85
|
+
modeItems.value = Array.isArray(c.children) ? c.children : [];
|
|
86
|
+
refresh();
|
|
87
|
+
inputRef.value?.focus();
|
|
88
|
+
}
|
|
89
|
+
function popTo(depth) {
|
|
90
|
+
const next = trail.value.slice(0, Math.max(0, depth));
|
|
91
|
+
trail.value = next;
|
|
92
|
+
query.value = "";
|
|
93
|
+
selectedIndex.value = 0;
|
|
94
|
+
const parent = next[next.length - 1];
|
|
95
|
+
modeItems.value = parent && Array.isArray(parent.children) ? parent.children : [];
|
|
96
|
+
refresh();
|
|
97
|
+
inputRef.value?.focus();
|
|
98
|
+
}
|
|
99
|
+
function back() {
|
|
100
|
+
if (!trail.value.length) return false;
|
|
101
|
+
popTo(trail.value.length - 1);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
const found = shallowRef([]);
|
|
105
|
+
const searching = ref(false);
|
|
106
|
+
let timer;
|
|
107
|
+
let controller;
|
|
108
|
+
let token = 0;
|
|
109
|
+
function fetcher() {
|
|
110
|
+
const current = mode.value;
|
|
111
|
+
if (current) {
|
|
112
|
+
return typeof current.children === "function" ? (q) => current.children(q) : null;
|
|
113
|
+
}
|
|
114
|
+
return props.search ?? null;
|
|
115
|
+
}
|
|
116
|
+
function cancel() {
|
|
117
|
+
if (timer) clearTimeout(timer);
|
|
118
|
+
timer = void 0;
|
|
119
|
+
controller?.abort();
|
|
120
|
+
controller = void 0;
|
|
121
|
+
token += 1;
|
|
122
|
+
searching.value = false;
|
|
123
|
+
}
|
|
124
|
+
function refresh() {
|
|
125
|
+
cancel();
|
|
126
|
+
found.value = [];
|
|
127
|
+
const run2 = fetcher();
|
|
128
|
+
if (!run2) return;
|
|
129
|
+
const q = query.value.trim();
|
|
130
|
+
const inMode = mode.value !== null;
|
|
131
|
+
if (!inMode && q.length < Math.max(1, props.minChars)) return;
|
|
132
|
+
searching.value = true;
|
|
133
|
+
const mine = ++token;
|
|
134
|
+
timer = setTimeout(async () => {
|
|
135
|
+
controller = new AbortController();
|
|
136
|
+
try {
|
|
137
|
+
const hits = await run2(q, controller.signal);
|
|
138
|
+
if (mine !== token) return;
|
|
139
|
+
found.value = hits;
|
|
140
|
+
} catch {
|
|
141
|
+
if (mine === token) found.value = [];
|
|
142
|
+
} finally {
|
|
143
|
+
if (mine === token) searching.value = false;
|
|
144
|
+
}
|
|
145
|
+
}, props.debounce);
|
|
146
|
+
}
|
|
147
|
+
onBeforeUnmount(cancel);
|
|
148
|
+
const source = computed(() => mode.value ? modeItems.value : props.commands);
|
|
53
149
|
const ranked = computed(() => {
|
|
54
150
|
const q = query.value.trim().toLowerCase();
|
|
55
|
-
if (!q) return
|
|
56
|
-
return
|
|
151
|
+
if (!q) return source.value.filter((c) => !c.hidden);
|
|
152
|
+
return source.value.map((c) => {
|
|
57
153
|
const label = c.label.toLowerCase().includes(q);
|
|
58
154
|
const kw = (c.keywords ?? []).some((k) => k.toLowerCase().includes(q));
|
|
59
155
|
const desc = c.description?.toLowerCase().includes(q) ?? false;
|
|
@@ -61,17 +157,36 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
61
157
|
return { c, score };
|
|
62
158
|
}).filter((e) => e.score > 0).sort((a, b) => b.score - a.score || a.c.label.localeCompare(b.c.label)).map((e) => e.c);
|
|
63
159
|
});
|
|
160
|
+
const fetched = computed(() => {
|
|
161
|
+
if (!found.value.length) return [];
|
|
162
|
+
const seen = new Set(ranked.value.map((c) => c.id));
|
|
163
|
+
return found.value.filter((c) => !seen.has(c.id)).map((c) => c.group ? c : { ...c, group: props.resultsLabel });
|
|
164
|
+
});
|
|
165
|
+
const recentItems = computed(() => {
|
|
166
|
+
if (mode.value || query.value.trim() || !props.recent?.length) return [];
|
|
167
|
+
const byId = new Map(props.commands.map((c) => [c.id, c]));
|
|
168
|
+
const out = [];
|
|
169
|
+
for (const id of props.recent) {
|
|
170
|
+
const c = byId.get(id);
|
|
171
|
+
if (c && !c.disabled && !out.includes(c)) out.push(c);
|
|
172
|
+
if (out.length >= props.recentLimit) break;
|
|
173
|
+
}
|
|
174
|
+
return out;
|
|
175
|
+
});
|
|
64
176
|
const grouped = computed(() => {
|
|
65
177
|
const order = [];
|
|
66
178
|
const map = /* @__PURE__ */ new Map();
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
order.push(g);
|
|
179
|
+
const push = (c, group) => {
|
|
180
|
+
if (!map.has(group)) {
|
|
181
|
+
map.set(group, []);
|
|
182
|
+
order.push(group);
|
|
72
183
|
}
|
|
73
|
-
map.get(
|
|
74
|
-
}
|
|
184
|
+
map.get(group).push(c);
|
|
185
|
+
};
|
|
186
|
+
const recent = recentItems.value;
|
|
187
|
+
for (const c of recent) push(c, props.recentLabel);
|
|
188
|
+
for (const c of ranked.value) if (!recent.includes(c)) push(c, c.group ?? "");
|
|
189
|
+
for (const c of fetched.value) push(c, c.group ?? "");
|
|
75
190
|
return order.map((name) => ({ name, items: map.get(name) }));
|
|
76
191
|
});
|
|
77
192
|
const flat = computed(() => grouped.value.flatMap((g) => g.items));
|
|
@@ -90,9 +205,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
90
205
|
let at = -1;
|
|
91
206
|
let term = "";
|
|
92
207
|
for (const t of terms) {
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
95
|
-
at =
|
|
208
|
+
const found2 = lower.indexOf(t, i);
|
|
209
|
+
if (found2 !== -1 && (at === -1 || found2 < at || found2 === at && t.length > term.length)) {
|
|
210
|
+
at = found2;
|
|
96
211
|
term = t;
|
|
97
212
|
}
|
|
98
213
|
}
|
|
@@ -106,7 +221,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
106
221
|
}
|
|
107
222
|
return parts;
|
|
108
223
|
}
|
|
109
|
-
watch(query, () =>
|
|
224
|
+
watch(query, () => {
|
|
225
|
+
selectedIndex.value = 0;
|
|
226
|
+
refresh();
|
|
227
|
+
});
|
|
110
228
|
watch(
|
|
111
229
|
() => flat.value.length,
|
|
112
230
|
(len) => {
|
|
@@ -138,14 +256,39 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
138
256
|
if (!c || c.disabled) return;
|
|
139
257
|
emit("select", c);
|
|
140
258
|
c.onSelect?.();
|
|
259
|
+
if (c.children) {
|
|
260
|
+
enter(c);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
emit("run", c.id, c);
|
|
264
|
+
if (c.keepOpen) {
|
|
265
|
+
query.value = "";
|
|
266
|
+
selectedIndex.value = 0;
|
|
267
|
+
inputRef.value?.focus();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
141
270
|
emit("update:open", false);
|
|
142
271
|
}
|
|
272
|
+
function onBackspace(event) {
|
|
273
|
+
if (query.value) return;
|
|
274
|
+
if (back()) event.preventDefault();
|
|
275
|
+
}
|
|
276
|
+
function onEscape(event) {
|
|
277
|
+
if (!trail.value.length) return;
|
|
278
|
+
event.preventDefault();
|
|
279
|
+
event.stopPropagation();
|
|
280
|
+
back();
|
|
281
|
+
}
|
|
143
282
|
watch(
|
|
144
283
|
() => props.open,
|
|
145
284
|
async (o) => {
|
|
285
|
+
cancel();
|
|
286
|
+
query.value = "";
|
|
287
|
+
selectedIndex.value = 0;
|
|
288
|
+
trail.value = [];
|
|
289
|
+
modeItems.value = [];
|
|
290
|
+
found.value = [];
|
|
146
291
|
if (o) {
|
|
147
|
-
query.value = "";
|
|
148
|
-
selectedIndex.value = 0;
|
|
149
292
|
await nextTick();
|
|
150
293
|
inputRef.value?.focus();
|
|
151
294
|
}
|
|
@@ -190,24 +333,53 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
190
333
|
_: 1
|
|
191
334
|
}),
|
|
192
335
|
createElementVNode("div", _hoisted_1, [
|
|
193
|
-
|
|
336
|
+
!searching.value ? (openBlock(), createBlock(_sfc_main$1, {
|
|
337
|
+
key: 0,
|
|
194
338
|
name: "lucide:search",
|
|
195
339
|
size: 18,
|
|
196
340
|
class: "shrink-0 text-muted"
|
|
197
|
-
}),
|
|
341
|
+
})) : (openBlock(), createBlock(_sfc_main$1, {
|
|
342
|
+
key: 1,
|
|
343
|
+
name: "lucide:loader-circle",
|
|
344
|
+
size: 18,
|
|
345
|
+
class: "shrink-0 animate-spin text-muted"
|
|
346
|
+
})),
|
|
347
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(trail.value, (step, i) => {
|
|
348
|
+
return openBlock(), createElementBlock("button", {
|
|
349
|
+
key: step.id,
|
|
350
|
+
type: "button",
|
|
351
|
+
class: "flex shrink-0 items-center gap-1.5 rounded-md bg-brand-soft px-2 py-1 text-xs font-medium text-brand transition-opacity hover:opacity-80",
|
|
352
|
+
title: text.value.back,
|
|
353
|
+
onClick: ($event) => popTo(i)
|
|
354
|
+
}, [
|
|
355
|
+
step.icon ? (openBlock(), createBlock(_sfc_main$1, {
|
|
356
|
+
key: 0,
|
|
357
|
+
name: step.icon,
|
|
358
|
+
size: 13
|
|
359
|
+
}, null, 8, ["name"])) : createCommentVNode("", true),
|
|
360
|
+
createTextVNode(" " + toDisplayString(step.label) + " ", 1),
|
|
361
|
+
createVNode(_sfc_main$1, {
|
|
362
|
+
name: "lucide:x",
|
|
363
|
+
size: 12,
|
|
364
|
+
class: "opacity-60"
|
|
365
|
+
})
|
|
366
|
+
], 8, _hoisted_2);
|
|
367
|
+
}), 128)),
|
|
198
368
|
withDirectives(createElementVNode("input", {
|
|
199
369
|
ref_key: "inputRef",
|
|
200
370
|
ref: inputRef,
|
|
201
371
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => query.value = $event),
|
|
202
372
|
type: "text",
|
|
203
|
-
placeholder: __props.placeholder,
|
|
373
|
+
placeholder: mode.value?.childPlaceholder ?? __props.placeholder,
|
|
204
374
|
class: "h-12 min-w-0 flex-1 bg-transparent text-sm text-ink outline-none placeholder:text-muted",
|
|
205
375
|
onKeydown: [
|
|
206
376
|
withKeys(withModifiers(moveDown, ["prevent"]), ["down"]),
|
|
207
377
|
withKeys(withModifiers(moveUp, ["prevent"]), ["up"]),
|
|
208
|
-
withKeys(withModifiers(runSelected, ["prevent"]), ["enter"])
|
|
378
|
+
withKeys(withModifiers(runSelected, ["prevent"]), ["enter"]),
|
|
379
|
+
withKeys(onBackspace, ["backspace"]),
|
|
380
|
+
withKeys(onEscape, ["esc"])
|
|
209
381
|
]
|
|
210
|
-
}, null, 40,
|
|
382
|
+
}, null, 40, _hoisted_3), [
|
|
211
383
|
[vModelText, query.value]
|
|
212
384
|
]),
|
|
213
385
|
_cache[5] || (_cache[5] = createElementVNode("kbd", { class: "shrink-0 rounded border border-line px-1.5 py-0.5 text-[10px] text-muted" }, "esc", -1))
|
|
@@ -219,12 +391,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
219
391
|
"content-class": "p-2"
|
|
220
392
|
}, {
|
|
221
393
|
default: withCtx(() => [
|
|
222
|
-
flat.value.length === 0 ? (openBlock(), createElementBlock("p",
|
|
394
|
+
flat.value.length === 0 ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString(searching.value ? text.value.searching : __props.emptyText), 1)) : createCommentVNode("", true),
|
|
223
395
|
(openBlock(true), createElementBlock(Fragment, null, renderList(grouped.value, (group) => {
|
|
224
396
|
return openBlock(), createElementBlock(Fragment, {
|
|
225
397
|
key: group.name
|
|
226
398
|
}, [
|
|
227
|
-
group.name ? (openBlock(), createElementBlock("div",
|
|
399
|
+
group.name ? (openBlock(), createElementBlock("div", _hoisted_5, toDisplayString(group.name), 1)) : createCommentVNode("", true),
|
|
228
400
|
(openBlock(true), createElementBlock(Fragment, null, renderList(group.items, (c) => {
|
|
229
401
|
return openBlock(), createElementBlock("button", {
|
|
230
402
|
key: c.id,
|
|
@@ -241,53 +413,62 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
241
413
|
size: 16,
|
|
242
414
|
class: "shrink-0"
|
|
243
415
|
}, null, 8, ["name"])) : createCommentVNode("", true),
|
|
244
|
-
createElementVNode("span",
|
|
245
|
-
createElementVNode("span",
|
|
416
|
+
createElementVNode("span", _hoisted_7, [
|
|
417
|
+
createElementVNode("span", _hoisted_8, [
|
|
246
418
|
(openBlock(true), createElementBlock(Fragment, null, renderList(highlight(c.label), (p, pi) => {
|
|
247
419
|
return openBlock(), createElementBlock(Fragment, {
|
|
248
420
|
key: `l${pi}`
|
|
249
421
|
}, [
|
|
250
|
-
p.hit ? (openBlock(), createElementBlock("mark",
|
|
422
|
+
p.hit ? (openBlock(), createElementBlock("mark", _hoisted_9, toDisplayString(p.text), 1)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
251
423
|
createTextVNode(toDisplayString(p.text), 1)
|
|
252
424
|
], 64))
|
|
253
425
|
], 64);
|
|
254
426
|
}), 128))
|
|
255
427
|
]),
|
|
256
|
-
c.description ? (openBlock(), createElementBlock("span",
|
|
428
|
+
c.description ? (openBlock(), createElementBlock("span", _hoisted_10, [
|
|
257
429
|
(openBlock(true), createElementBlock(Fragment, null, renderList(highlight(c.description), (p, pi) => {
|
|
258
430
|
return openBlock(), createElementBlock(Fragment, {
|
|
259
431
|
key: `d${pi}`
|
|
260
432
|
}, [
|
|
261
|
-
p.hit ? (openBlock(), createElementBlock("mark",
|
|
433
|
+
p.hit ? (openBlock(), createElementBlock("mark", _hoisted_11, toDisplayString(p.text), 1)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
262
434
|
createTextVNode(toDisplayString(p.text), 1)
|
|
263
435
|
], 64))
|
|
264
436
|
], 64);
|
|
265
437
|
}), 128))
|
|
266
438
|
])) : createCommentVNode("", true)
|
|
267
439
|
]),
|
|
268
|
-
c.shortcut ? (openBlock(), createElementBlock("kbd",
|
|
269
|
-
|
|
440
|
+
c.shortcut ? (openBlock(), createElementBlock("kbd", _hoisted_12, toDisplayString(c.shortcut), 1)) : c.children ? (openBlock(), createBlock(_sfc_main$1, {
|
|
441
|
+
key: 2,
|
|
442
|
+
name: "lucide:chevron-right",
|
|
443
|
+
size: 14,
|
|
444
|
+
class: "shrink-0 text-muted"
|
|
445
|
+
})) : createCommentVNode("", true)
|
|
446
|
+
], 42, _hoisted_6);
|
|
270
447
|
}), 128))
|
|
271
448
|
], 64);
|
|
272
449
|
}), 128))
|
|
273
450
|
]),
|
|
274
451
|
_: 1
|
|
275
452
|
}, 512),
|
|
276
|
-
|
|
277
|
-
createElementVNode("span",
|
|
278
|
-
createElementVNode("kbd", { class: "rounded border border-line px-1 text-[10px]" }, "↑"),
|
|
279
|
-
createElementVNode("kbd", { class: "rounded border border-line px-1 text-[10px]" }, "↓"),
|
|
280
|
-
createTextVNode(" navigate
|
|
453
|
+
createElementVNode("div", _hoisted_13, [
|
|
454
|
+
createElementVNode("span", _hoisted_14, [
|
|
455
|
+
_cache[6] || (_cache[6] = createElementVNode("kbd", { class: "rounded border border-line px-1 text-[10px]" }, "↑", -1)),
|
|
456
|
+
_cache[7] || (_cache[7] = createElementVNode("kbd", { class: "rounded border border-line px-1 text-[10px]" }, "↓", -1)),
|
|
457
|
+
createTextVNode(" " + toDisplayString(text.value.navigate), 1)
|
|
281
458
|
]),
|
|
282
|
-
createElementVNode("span",
|
|
283
|
-
createElementVNode("kbd", { class: "rounded border border-line px-1 text-[10px]" }, "↵"),
|
|
284
|
-
createTextVNode(" select
|
|
459
|
+
createElementVNode("span", _hoisted_15, [
|
|
460
|
+
_cache[8] || (_cache[8] = createElementVNode("kbd", { class: "rounded border border-line px-1 text-[10px]" }, "↵", -1)),
|
|
461
|
+
createTextVNode(" " + toDisplayString(text.value.select), 1)
|
|
285
462
|
]),
|
|
286
|
-
|
|
287
|
-
createElementVNode("kbd", { class: "rounded border border-line px-1 text-[10px]" }, "
|
|
288
|
-
createTextVNode("
|
|
463
|
+
trail.value.length ? (openBlock(), createElementBlock("span", _hoisted_16, [
|
|
464
|
+
_cache[9] || (_cache[9] = createElementVNode("kbd", { class: "rounded border border-line px-1 text-[10px]" }, "⌫", -1)),
|
|
465
|
+
createTextVNode(" " + toDisplayString(text.value.back), 1)
|
|
466
|
+
])) : createCommentVNode("", true),
|
|
467
|
+
createElementVNode("span", _hoisted_17, [
|
|
468
|
+
_cache[10] || (_cache[10] = createElementVNode("kbd", { class: "rounded border border-line px-1 text-[10px]" }, "esc", -1)),
|
|
469
|
+
createTextVNode(" " + toDisplayString(text.value.close), 1)
|
|
289
470
|
])
|
|
290
|
-
]
|
|
471
|
+
])
|
|
291
472
|
]),
|
|
292
473
|
_: 1
|
|
293
474
|
})
|
|
@@ -300,7 +481,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
300
481
|
};
|
|
301
482
|
}
|
|
302
483
|
});
|
|
303
|
-
const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
484
|
+
const LpCommandPalette = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d0e03a58"]]);
|
|
304
485
|
export {
|
|
305
486
|
LpCommandPalette as default
|
|
306
487
|
};
|