@leavepulse/ui 0.41.0 → 0.43.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-DyT6aGdW.css → LpCommandPalette-s_kKuCRf.css} +21 -21
- package/dist/chunks/{LpAddressInput-CMjaPQVw.js → LpAddressInput-B-Zvxsn7.js} +1 -1
- package/dist/chunks/{LpAppShell-Bcv6EhqU.js → LpAppShell-BGQVIY-3.js} +1 -1
- package/dist/chunks/{LpConfirmDialog-BNAvOR24.js → LpConfirmDialog-Q-bxff8z.js} +1 -1
- package/dist/chunks/{LpDrawer-DgaS2s2i.js → LpDrawer-BZ6k3hvo.js} +3 -3
- package/dist/chunks/{LpLightbox-oLqyjOln.js → LpLightbox-2sYVMY-S.js} +12 -4
- package/dist/chunks/{LpMediaGallery-Cid7PGYx.js → LpMediaGallery-FF-NquIo.js} +1 -1
- package/dist/chunks/{LpModal-8bja5bWS.js → LpModal-Bt0pQCI_.js} +2 -2
- package/dist/chunks/{LpModalNav-w9kfwHqO.js → LpModalNav-YaifHrXC.js} +2 -2
- package/dist/chunks/{LpSidebar-DlTn5nXc.js → LpSidebar-ClBUwoEz.js} +1 -1
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +124 -115
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpShortcutsDialog.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/commandSearch.js +66 -0
- package/dist/components/modalDepth.js +3 -2
- package/dist/composables/useHotkeys.js +41 -21
- package/dist/index.js +13 -9
- package/package.json +3 -3
- package/src/components/LpCommandPalette.vue +81 -99
- package/src/components/LpDrawer.vue +3 -3
- package/src/components/LpLightbox.vue +11 -5
- package/src/components/LpModal.vue +2 -2
- package/src/components/commandSearch.ts +92 -0
- package/src/components/modalDepth.ts +4 -48
- package/src/composables/useHotkeys.ts +54 -33
- package/src/index.ts +2 -0
- package/src/tokens/tokens.css +13 -19
- package/dist/component-names.d.ts +0 -1
- package/dist/components/LayoutCanvas.vue.d.ts +0 -28
- package/dist/components/LayoutNode.vue.d.ts +0 -40
- package/dist/components/LpActionBar.vue.d.ts +0 -84
- package/dist/components/LpAddressInput.vue.d.ts +0 -70
- package/dist/components/LpAlert.vue.d.ts +0 -44
- package/dist/components/LpAppShell.vue.d.ts +0 -123
- package/dist/components/LpAutocomplete.vue.d.ts +0 -50
- package/dist/components/LpAvatar.vue.d.ts +0 -34
- package/dist/components/LpBadge.vue.d.ts +0 -20
- package/dist/components/LpBreadcrumbs.vue.d.ts +0 -32
- package/dist/components/LpButton.vue.d.ts +0 -113
- package/dist/components/LpCalendar.vue.d.ts +0 -29
- package/dist/components/LpCard.vue.d.ts +0 -60
- package/dist/components/LpChart.vue.d.ts +0 -130
- package/dist/components/LpCheckbox.vue.d.ts +0 -32
- package/dist/components/LpCodeBlock.vue.d.ts +0 -58
- package/dist/components/LpColorPicker.vue.d.ts +0 -124
- package/dist/components/LpCommandPalette.vue.d.ts +0 -206
- package/dist/components/LpConfirmDialog.vue.d.ts +0 -59
- package/dist/components/LpContextMenu.vue.d.ts +0 -44
- package/dist/components/LpDatePicker.vue.d.ts +0 -33
- package/dist/components/LpDisclosure.vue.d.ts +0 -47
- package/dist/components/LpDivider.vue.d.ts +0 -17
- package/dist/components/LpDrawer.vue.d.ts +0 -170
- package/dist/components/LpDropdownMenu.vue.d.ts +0 -23
- package/dist/components/LpDropzone.vue.d.ts +0 -90
- package/dist/components/LpEmptyState.vue.d.ts +0 -28
- package/dist/components/LpFileTree.vue.d.ts +0 -126
- package/dist/components/LpFileTreeNode.vue.d.ts +0 -62
- package/dist/components/LpFormField.vue.d.ts +0 -24
- package/dist/components/LpIcon.vue.d.ts +0 -8
- package/dist/components/LpImageEditor.vue.d.ts +0 -106
- package/dist/components/LpInfraNode.vue.d.ts +0 -65
- package/dist/components/LpInput.vue.d.ts +0 -80
- package/dist/components/LpLaneNode.vue.d.ts +0 -24
- package/dist/components/LpLightbox.vue.d.ts +0 -62
- package/dist/components/LpLink.vue.d.ts +0 -93
- package/dist/components/LpLogViewer.vue.d.ts +0 -153
- package/dist/components/LpMapPicker.vue.d.ts +0 -59
- package/dist/components/LpMediaGallery.vue.d.ts +0 -80
- package/dist/components/LpModal.vue.d.ts +0 -66
- package/dist/components/LpModalNav.vue.d.ts +0 -66
- package/dist/components/LpNotificationBell.vue.d.ts +0 -85
- package/dist/components/LpNumberField.vue.d.ts +0 -21
- package/dist/components/LpNumberFlow.vue.d.ts +0 -35
- package/dist/components/LpOtpInput.vue.d.ts +0 -39
- package/dist/components/LpPagination.vue.d.ts +0 -35
- package/dist/components/LpPasswordInput.vue.d.ts +0 -36
- package/dist/components/LpPhoneInput.vue.d.ts +0 -49
- package/dist/components/LpPie.vue.d.ts +0 -196
- package/dist/components/LpPopover.vue.d.ts +0 -34
- package/dist/components/LpProgress.vue.d.ts +0 -66
- package/dist/components/LpRadio.vue.d.ts +0 -18
- package/dist/components/LpRadioGroup.vue.d.ts +0 -26
- package/dist/components/LpRollingText.vue.d.ts +0 -33
- package/dist/components/LpScrollArea.vue.d.ts +0 -28
- package/dist/components/LpSection.vue.d.ts +0 -120
- package/dist/components/LpSegmented.vue.d.ts +0 -30
- package/dist/components/LpSelect.vue.d.ts +0 -47
- package/dist/components/LpServiceNode.vue.d.ts +0 -14
- package/dist/components/LpShift.vue.d.ts +0 -36
- package/dist/components/LpShortcutsDialog.vue.d.ts +0 -24
- package/dist/components/LpSidebar.vue.d.ts +0 -146
- package/dist/components/LpSidebarNav.vue.d.ts +0 -54
- package/dist/components/LpSkeleton.vue.d.ts +0 -16
- package/dist/components/LpSlider.vue.d.ts +0 -30
- package/dist/components/LpSparkline.vue.d.ts +0 -48
- package/dist/components/LpStat.vue.d.ts +0 -69
- package/dist/components/LpStepper.vue.d.ts +0 -36
- package/dist/components/LpSwitch.vue.d.ts +0 -42
- package/dist/components/LpTable.vue.d.ts +0 -124
- package/dist/components/LpTableOfContents.vue.d.ts +0 -19
- package/dist/components/LpTabs.vue.d.ts +0 -47
- package/dist/components/LpTextarea.vue.d.ts +0 -22
- package/dist/components/LpThemeSwitcher.vue.d.ts +0 -47
- package/dist/components/LpTilt.vue.d.ts +0 -31
- package/dist/components/LpTimeField.vue.d.ts +0 -24
- package/dist/components/LpToaster.vue.d.ts +0 -3
- package/dist/components/LpTooltip.vue.d.ts +0 -58
- package/dist/components/LpTopologyCanvas.vue.d.ts +0 -205
- package/dist/components/LpUptimeBar.vue.d.ts +0 -46
- package/dist/components/LpWaypointEdge.vue.d.ts +0 -21
- package/dist/components/actionBar.d.ts +0 -19
- package/dist/components/address.d.ts +0 -107
- package/dist/components/chart.d.ts +0 -180
- package/dist/components/codeHighlight.d.ts +0 -8
- package/dist/components/color.d.ts +0 -65
- package/dist/components/countries-data.d.ts +0 -2
- package/dist/components/countries.d.ts +0 -20
- package/dist/components/dropdown.d.ts +0 -29
- package/dist/components/fileTree.d.ts +0 -79
- package/dist/components/lightbox.d.ts +0 -24
- package/dist/components/modalDepth.d.ts +0 -15
- package/dist/components/sidebar.d.ts +0 -42
- package/dist/composables/easing.d.ts +0 -46
- package/dist/composables/useAsyncTask.d.ts +0 -18
- package/dist/composables/useClipboard.d.ts +0 -46
- package/dist/composables/useFormDraft.d.ts +0 -67
- package/dist/composables/useGlass.d.ts +0 -9
- package/dist/composables/useHotkeys.d.ts +0 -99
- package/dist/composables/useInputFilter.d.ts +0 -14
- package/dist/composables/useMergedClass.d.ts +0 -42
- package/dist/composables/usePillTransition.d.ts +0 -21
- package/dist/composables/useReveal.d.ts +0 -26
- package/dist/composables/useRovingFocus.d.ts +0 -49
- package/dist/composables/useSettled.d.ts +0 -26
- package/dist/composables/useShift.d.ts +0 -35
- package/dist/composables/useTilt.d.ts +0 -23
- package/dist/composables/useToast.d.ts +0 -41
- package/dist/composables/useZoomPan.d.ts +0 -58
- package/dist/icons.d.ts +0 -1
- package/dist/index.d.ts +0 -160
- package/dist/layout/registry.d.ts +0 -26
- package/dist/layout/tree.d.ts +0 -75
- package/dist/layout/useLayout.d.ts +0 -39
- package/dist/theme/backdrop.d.ts +0 -9
- package/dist/theme/config.d.ts +0 -16
- package/dist/theme/define.d.ts +0 -12
- package/dist/theme/presets.d.ts +0 -20
- package/dist/theme/tokens.d.ts +0 -75
- package/dist/theme/useTheme.d.ts +0 -46
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const QUERY_TOKEN = /(-?)(?:(in):)?(?:"([^"]*)"|(\S+))/giu;
|
|
2
|
+
const LATIN = "qwertyuiop[]asdfghjkl;'zxcvbnm,.`";
|
|
3
|
+
const CYRILLIC = "йцукенгшщзхъфывапролджэячсмитьбюё";
|
|
4
|
+
const SWAP = /* @__PURE__ */ new Map();
|
|
5
|
+
for (let i = 0; i < LATIN.length; i++) {
|
|
6
|
+
SWAP.set(LATIN[i], CYRILLIC[i]);
|
|
7
|
+
SWAP.set(CYRILLIC[i], LATIN[i]);
|
|
8
|
+
}
|
|
9
|
+
function parseCommandQuery(value) {
|
|
10
|
+
const out = { include: [], exclude: [], groups: [] };
|
|
11
|
+
QUERY_TOKEN.lastIndex = 0;
|
|
12
|
+
for (let match; match = QUERY_TOKEN.exec(value); ) {
|
|
13
|
+
const text = (match[3] ?? match[4] ?? "").trim().toLowerCase();
|
|
14
|
+
if (!text) continue;
|
|
15
|
+
if (match[2] && !match[1]) out.groups.push(text);
|
|
16
|
+
else if (match[1]) out.exclude.push(text);
|
|
17
|
+
else out.include.push(text);
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
function swapCommandTerms(terms) {
|
|
22
|
+
const swap = (term) => [...term].map((ch) => SWAP.get(ch) ?? ch).join("");
|
|
23
|
+
return {
|
|
24
|
+
include: terms.include.map(swap),
|
|
25
|
+
exclude: terms.exclude.map(swap),
|
|
26
|
+
groups: terms.groups.map(swap)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function matches(command, term) {
|
|
30
|
+
return command.label.toLowerCase().includes(term) || (command.keywords ?? []).some((keyword) => keyword.toLowerCase().includes(term)) || (command.description?.toLowerCase().includes(term) ?? false);
|
|
31
|
+
}
|
|
32
|
+
function withinOne(a, b) {
|
|
33
|
+
if (Math.abs(a.length - b.length) > 1) return false;
|
|
34
|
+
let i = 0;
|
|
35
|
+
while (i < a.length && i < b.length && a[i] === b[i]) i++;
|
|
36
|
+
if (i === a.length || i === b.length) return true;
|
|
37
|
+
const rest = (x, y) => a.slice(i + x) === b.slice(i + y);
|
|
38
|
+
return rest(1, 1) || rest(1, 0) || rest(0, 1) || a[i] === b[i + 1] && a[i + 1] === b[i] && rest(2, 2);
|
|
39
|
+
}
|
|
40
|
+
function nearWord(term, label) {
|
|
41
|
+
if (term.length < 5) return false;
|
|
42
|
+
return label.split(/[^\p{L}\p{N}]+/u).some((word) => withinOne(term, word) || word.length > term.length && withinOne(term, word.slice(0, term.length)));
|
|
43
|
+
}
|
|
44
|
+
function score(command, terms) {
|
|
45
|
+
const label = command.label.toLowerCase();
|
|
46
|
+
const keywords = (command.keywords ?? []).map((keyword) => keyword.toLowerCase());
|
|
47
|
+
const description = command.description?.toLowerCase() ?? "";
|
|
48
|
+
const group = command.group?.toLowerCase() ?? "";
|
|
49
|
+
if (terms.exclude.some((term) => matches(command, term)) || terms.groups.some((term) => !group.includes(term))) return 0;
|
|
50
|
+
let total = terms.include.length ? 0 : 1;
|
|
51
|
+
for (const term of terms.include) {
|
|
52
|
+
let hit = (label.includes(term) ? 4 : 0) + (keywords.some((keyword) => keyword.includes(term)) ? 3 : 0) + (description.includes(term) ? 2 : 0);
|
|
53
|
+
if (!hit && nearWord(term, label)) hit = 1;
|
|
54
|
+
if (!hit) return 0;
|
|
55
|
+
total += hit;
|
|
56
|
+
}
|
|
57
|
+
return total;
|
|
58
|
+
}
|
|
59
|
+
function rankCommandItems(items, terms) {
|
|
60
|
+
return items.map((command) => ({ command, score: score(command, terms) })).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.command.label.localeCompare(b.command.label)).map((entry) => entry.command);
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
parseCommandQuery,
|
|
64
|
+
rankCommandItems,
|
|
65
|
+
swapCommandTerms
|
|
66
|
+
};
|
|
@@ -18,8 +18,9 @@ function useModalLayer() {
|
|
|
18
18
|
layer: computed(() => {
|
|
19
19
|
const drop = fromTop.value * STEP;
|
|
20
20
|
return {
|
|
21
|
-
scrim: `calc(var(--z-
|
|
22
|
-
panel: `calc(var(--z-
|
|
21
|
+
scrim: `calc(var(--z-toast) - 20 - ${drop})`,
|
|
22
|
+
panel: `calc(var(--z-toast) - 10 - ${drop})`,
|
|
23
|
+
nested: stack.value.indexOf(id) > 0
|
|
23
24
|
};
|
|
24
25
|
})
|
|
25
26
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { shallowReactive, computed, onMounted, onBeforeUnmount
|
|
1
|
+
import { shallowReactive, computed, toValue, onMounted, onBeforeUnmount } from "vue";
|
|
2
2
|
const isAppleKeyboard = typeof navigator !== "undefined" && /Mac|iPhone|iPad|iPod/.test(navigator.platform || "");
|
|
3
3
|
function appleModifierLabel(key) {
|
|
4
4
|
if (!isAppleKeyboard) return key;
|
|
@@ -31,18 +31,24 @@ function matches(event, binding) {
|
|
|
31
31
|
if (event.altKey !== Boolean(binding.alt)) return false;
|
|
32
32
|
return event.key.toLowerCase() === binding.key.toLowerCase() || binding.code !== void 0 && event.code === binding.code;
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
const mounted = shallowReactive(/* @__PURE__ */ new Set());
|
|
35
|
+
let mountOrder = 0;
|
|
36
|
+
let listening = false;
|
|
37
|
+
function inScope(target, scope) {
|
|
38
|
+
const el = toValue(scope);
|
|
39
|
+
if (!el) return true;
|
|
40
|
+
const node = target instanceof Node ? target : null;
|
|
41
|
+
return !!node && (el === node || el.contains(node));
|
|
42
|
+
}
|
|
43
|
+
function onKeydown(event) {
|
|
44
|
+
if (event.isComposing) return;
|
|
45
|
+
const inTextEntry = isTextEntry(event.target);
|
|
46
|
+
const entries = [...mounted].sort(
|
|
47
|
+
(a, b) => Number(toValue(b.priority) || 0) - Number(toValue(a.priority) || 0) || b.order - a.order
|
|
48
|
+
);
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
if (toValue(entry.enabled) === false || !inScope(event.target, entry.scope)) continue;
|
|
51
|
+
for (const binding of entry.read()) {
|
|
46
52
|
if (inTextEntry && !binding.allowInInput) continue;
|
|
47
53
|
if (!matches(event, binding)) continue;
|
|
48
54
|
if (binding.handler(event) === false) continue;
|
|
@@ -50,17 +56,30 @@ function useHotkeys(bindings, options = {}) {
|
|
|
50
56
|
return;
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
|
-
|
|
59
|
+
}
|
|
60
|
+
function useHotkeys(bindings, options = {}) {
|
|
61
|
+
const entry = {
|
|
62
|
+
read: () => toValue(bindings),
|
|
63
|
+
scope: options.scope,
|
|
64
|
+
enabled: options.enabled,
|
|
65
|
+
priority: options.priority,
|
|
66
|
+
order: ++mountOrder
|
|
67
|
+
};
|
|
54
68
|
onMounted(() => {
|
|
55
|
-
|
|
56
|
-
|
|
69
|
+
mounted.add(entry);
|
|
70
|
+
if (!listening) {
|
|
71
|
+
window.addEventListener("keydown", onKeydown);
|
|
72
|
+
listening = true;
|
|
73
|
+
}
|
|
57
74
|
});
|
|
58
75
|
onBeforeUnmount(() => {
|
|
59
|
-
|
|
60
|
-
mounted.
|
|
76
|
+
mounted.delete(entry);
|
|
77
|
+
if (!mounted.size && listening) {
|
|
78
|
+
window.removeEventListener("keydown", onKeydown);
|
|
79
|
+
listening = false;
|
|
80
|
+
}
|
|
61
81
|
});
|
|
62
82
|
}
|
|
63
|
-
const mounted = shallowReactive(/* @__PURE__ */ new Set());
|
|
64
83
|
const KEY_NAMES = {
|
|
65
84
|
escape: "Esc",
|
|
66
85
|
enter: "Enter",
|
|
@@ -80,8 +99,9 @@ function comboOf(binding) {
|
|
|
80
99
|
}
|
|
81
100
|
const activeShortcuts = computed(() => {
|
|
82
101
|
const groups = /* @__PURE__ */ new Map();
|
|
83
|
-
for (const
|
|
84
|
-
|
|
102
|
+
for (const entry of mounted) {
|
|
103
|
+
if (toValue(entry.enabled) === false) continue;
|
|
104
|
+
for (const binding of entry.read()) {
|
|
85
105
|
if (!binding.help) continue;
|
|
86
106
|
const combo = binding.help.combo ?? comboOf(binding);
|
|
87
107
|
const entries = groups.get(binding.help.group) ?? [];
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { _ } from "./chunks/LayoutCanvas-Dd20boUG.js";
|
|
2
|
-
import { _ as _2 } from "./chunks/LpAddressInput-
|
|
2
|
+
import { _ as _2 } from "./chunks/LpAddressInput-B-Zvxsn7.js";
|
|
3
3
|
import { _ as _3 } from "./chunks/LpMapPicker-ul4oYno6.js";
|
|
4
4
|
import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
|
|
5
5
|
import { _ as _4 } from "./chunks/LpActionBar-BlvtGB2P.js";
|
|
6
6
|
import { _ as _5 } from "./chunks/LpAlert-BAYHDSS1.js";
|
|
7
|
-
import { _ as _6 } from "./chunks/LpAppShell-
|
|
7
|
+
import { _ as _6 } from "./chunks/LpAppShell-BGQVIY-3.js";
|
|
8
8
|
import { _ as _7 } from "./chunks/LpAutocomplete-DExlIZe_.js";
|
|
9
9
|
import { _ as _8 } from "./chunks/LpAvatar-B3-xAOH3.js";
|
|
10
10
|
import { _ as _9 } from "./chunks/LpBadge-Fe0D1bYx.js";
|
|
@@ -19,12 +19,13 @@ import { _ as _15 } from "./chunks/LpCodeBlock-Bo0B4TFR.js";
|
|
|
19
19
|
import { _ as _16 } from "./chunks/LpColorPicker-BlXea7LM.js";
|
|
20
20
|
import { DEFAULT_SWATCHES, clampHsv, formatColor, hsvToHsl, hsvToRgb, isLight, normalizeHue, opaqueCss, parseColor, parseHex, rgbToHex, rgbToHsv } from "./components/color.js";
|
|
21
21
|
import { default as default3 } from "./components/LpCommandPalette.vue.js";
|
|
22
|
-
import {
|
|
22
|
+
import { parseCommandQuery, rankCommandItems, swapCommandTerms } from "./components/commandSearch.js";
|
|
23
|
+
import { _ as _17 } from "./chunks/LpConfirmDialog-Q-bxff8z.js";
|
|
23
24
|
import { _ as _18 } from "./chunks/LpContextMenu-CwW1QXe_.js";
|
|
24
25
|
import { _ as _19 } from "./chunks/LpDatePicker-CwOToxGq.js";
|
|
25
26
|
import { _ as _20 } from "./chunks/LpDisclosure-ChQYmjlR.js";
|
|
26
27
|
import { _ as _21 } from "./chunks/LpDivider-CUX46KR0.js";
|
|
27
|
-
import { _ as _22 } from "./chunks/LpDrawer-
|
|
28
|
+
import { _ as _22 } from "./chunks/LpDrawer-BZ6k3hvo.js";
|
|
28
29
|
import { _ as _23 } from "./chunks/LpDropdownMenu-DJpoqRCb.js";
|
|
29
30
|
import { default as default4 } from "./components/LpDropzone.vue.js";
|
|
30
31
|
import { _ as _24 } from "./chunks/LpEmptyState-Dsdqz1Wj.js";
|
|
@@ -35,13 +36,13 @@ import { _ as _27 } from "./chunks/LpIcon-CCnX5_2j.js";
|
|
|
35
36
|
import { default as default5 } from "./components/LpImageEditor.vue.js";
|
|
36
37
|
import { _ as _28 } from "./chunks/LpInfraNode-Ds_8SZgN.js";
|
|
37
38
|
import { _ as _29 } from "./chunks/LpInput-9EXWUM9B.js";
|
|
38
|
-
import { _ as _30 } from "./chunks/LpLightbox-
|
|
39
|
+
import { _ as _30 } from "./chunks/LpLightbox-2sYVMY-S.js";
|
|
39
40
|
import { fileNameOf } from "./components/lightbox.js";
|
|
40
41
|
import { _ as _31 } from "./chunks/LpLink-DCND-zyu.js";
|
|
41
42
|
import { _ as _32 } from "./chunks/LpLogViewer-CaRy5MeS.js";
|
|
42
|
-
import { _ as _33 } from "./chunks/LpMediaGallery-
|
|
43
|
-
import { _ as _34 } from "./chunks/LpModal-
|
|
44
|
-
import { _ as _35 } from "./chunks/LpModalNav-
|
|
43
|
+
import { _ as _33 } from "./chunks/LpMediaGallery-FF-NquIo.js";
|
|
44
|
+
import { _ as _34 } from "./chunks/LpModal-Bt0pQCI_.js";
|
|
45
|
+
import { _ as _35 } from "./chunks/LpModalNav-YaifHrXC.js";
|
|
45
46
|
import { _ as _36 } from "./chunks/LpNotificationBell-DyGGsMAM.js";
|
|
46
47
|
import { _ as _37 } from "./chunks/LpNumberField-CWuX08iX.js";
|
|
47
48
|
import { _ as _38 } from "./chunks/LpTimeField-K6nAGboX.js";
|
|
@@ -64,7 +65,7 @@ import { _ as _53 } from "./chunks/LpSelect-ANIVtrpM.js";
|
|
|
64
65
|
import { _ as _54 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
65
66
|
import { _ as _55 } from "./chunks/LpShift-DXNsauQZ.js";
|
|
66
67
|
import { default as default6 } from "./components/LpShortcutsDialog.vue.js";
|
|
67
|
-
import { _ as _56 } from "./chunks/LpSidebar-
|
|
68
|
+
import { _ as _56 } from "./chunks/LpSidebar-ClBUwoEz.js";
|
|
68
69
|
import { _ as _57 } from "./chunks/LpSkeleton-CTI-vBgW.js";
|
|
69
70
|
import { _ as _58 } from "./chunks/LpSlider-BwNIBkAK.js";
|
|
70
71
|
import { _ as _59 } from "./chunks/LpSparkline-C6xQ2dwv.js";
|
|
@@ -270,6 +271,7 @@ export {
|
|
|
270
271
|
normalizeHue,
|
|
271
272
|
opaqueCss,
|
|
272
273
|
parseColor,
|
|
274
|
+
parseCommandQuery,
|
|
273
275
|
parseConfig,
|
|
274
276
|
parseHex,
|
|
275
277
|
parseTheme,
|
|
@@ -277,6 +279,7 @@ export {
|
|
|
277
279
|
presets,
|
|
278
280
|
project,
|
|
279
281
|
provideGlass,
|
|
282
|
+
rankCommandItems,
|
|
280
283
|
removeBlock,
|
|
281
284
|
removeLeaf,
|
|
282
285
|
reorderTab,
|
|
@@ -292,6 +295,7 @@ export {
|
|
|
292
295
|
sortNodes,
|
|
293
296
|
subtreeIds,
|
|
294
297
|
subtreeSize,
|
|
298
|
+
swapCommandTerms,
|
|
295
299
|
t as themeFromCookie,
|
|
296
300
|
k as themeToCssRule,
|
|
297
301
|
m as themeToCssVars,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leavepulse/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "LeavePulse token-driven Vue component kit.",
|
|
6
6
|
"repository": {
|
|
@@ -45,10 +45,11 @@
|
|
|
45
45
|
"scripts": {
|
|
46
46
|
"dev": "vite",
|
|
47
47
|
"gen:names": "node scripts/gen-component-names.mjs",
|
|
48
|
-
"build": "node scripts/gen-component-names.mjs && vue-tsc --noEmit -p tsconfig.build.json && vite build --config vite.lib.config.ts",
|
|
48
|
+
"build": "node scripts/gen-component-names.mjs && vue-tsc --noEmit -p tsconfig.build.json && vite build --config vite.lib.config.ts && vue-tsc --declaration --emitDeclarationOnly --noEmit false -p tsconfig.build.json --outDir dist",
|
|
49
49
|
"dev:dist": "vite build --watch --config vite.lib.config.ts",
|
|
50
50
|
"prepublishOnly": "node scripts/gen-component-names.mjs && vue-tsc --noEmit -p tsconfig.build.json && vite build --config vite.lib.config.ts",
|
|
51
51
|
"typecheck": "vue-tsc --noEmit",
|
|
52
|
+
"test": "bun test",
|
|
52
53
|
"release": "npm version patch -m \"chore: release v%s\" && git push --follow-tags",
|
|
53
54
|
"release:minor": "npm version minor -m \"chore: release v%s\" && git push --follow-tags",
|
|
54
55
|
"release:major": "npm version major -m \"chore: release v%s\" && git push --follow-tags"
|
|
@@ -83,7 +84,6 @@
|
|
|
83
84
|
"tailwindcss": "^4.2.4",
|
|
84
85
|
"typescript": "^5.6.3",
|
|
85
86
|
"vite": "^7.0.0",
|
|
86
|
-
"vite-plugin-dts": "^5.0.2",
|
|
87
87
|
"vite-plugin-lib-inject-css": "^2.2.2",
|
|
88
88
|
"vue": "3.5.31",
|
|
89
89
|
"vue-tsc": "^3.0.0"
|
|
@@ -36,13 +36,15 @@ import {
|
|
|
36
36
|
DialogRoot,
|
|
37
37
|
DialogTitle,
|
|
38
38
|
} from "reka-ui"
|
|
39
|
-
import { computed, nextTick, ref, shallowRef, useId, watch } from "vue"
|
|
39
|
+
import { computed, nextTick, onBeforeUnmount, ref, shallowRef, useId, watch } from "vue"
|
|
40
40
|
import LpIcon from "./LpIcon.vue"
|
|
41
41
|
import LpScrollArea from "./LpScrollArea.vue"
|
|
42
42
|
import { useAsyncTask } from "../composables/useAsyncTask"
|
|
43
43
|
import { useGlass } from "../composables/useGlass"
|
|
44
44
|
import { useClipboard } from "../composables/useClipboard"
|
|
45
45
|
import { useHotkeys } from "../composables/useHotkeys"
|
|
46
|
+
import { useModalLayer } from "./modalDepth"
|
|
47
|
+
import { parseCommandQuery, rankCommandItems, swapCommandTerms } from "./commandSearch"
|
|
46
48
|
|
|
47
49
|
export interface Command {
|
|
48
50
|
id: string
|
|
@@ -234,6 +236,7 @@ const props = withDefaults(
|
|
|
234
236
|
)
|
|
235
237
|
|
|
236
238
|
const frosted = useGlass(() => props.glass)
|
|
239
|
+
const { claim, release, layer } = useModalLayer()
|
|
237
240
|
|
|
238
241
|
const DEFAULT_LABELS: PaletteLabels = {
|
|
239
242
|
navigate: "navigate",
|
|
@@ -276,6 +279,7 @@ function optionId(index: number): string {
|
|
|
276
279
|
}
|
|
277
280
|
const activeId = computed(() => (flat.value.length ? optionId(selectedIndex.value) : undefined))
|
|
278
281
|
const selectedIndex = ref(0)
|
|
282
|
+
const selectedId = ref<string | null>(null)
|
|
279
283
|
const inputRef = ref<HTMLInputElement | null>(null)
|
|
280
284
|
const scrollRef = ref<{ viewportEl: HTMLElement | null } | null>(null)
|
|
281
285
|
|
|
@@ -290,6 +294,7 @@ const scrollRef = ref<{ viewportEl: HTMLElement | null } | null>(null)
|
|
|
290
294
|
* a row of data), and deep-tracking them would walk it on every keystroke.
|
|
291
295
|
*/
|
|
292
296
|
const trail = shallowRef<Command[]>([])
|
|
297
|
+
const trailState = shallowRef<{ query: string; selectedId: string | null }[]>([])
|
|
293
298
|
const mode = computed<Command | null>(() => trail.value[trail.value.length - 1] ?? null)
|
|
294
299
|
|
|
295
300
|
/*
|
|
@@ -332,21 +337,20 @@ const selectedActions = computed(() => actionsOf(flat.value[selectedIndex.value]
|
|
|
332
337
|
* actions it keeps that default.
|
|
333
338
|
*/
|
|
334
339
|
function onTab(event: KeyboardEvent) {
|
|
340
|
+
event.preventDefault()
|
|
341
|
+
event.stopPropagation()
|
|
335
342
|
if (event.shiftKey) return
|
|
336
343
|
const c = flat.value[selectedIndex.value]
|
|
337
344
|
const actions = selectedActions.value
|
|
338
345
|
if (!c || !actions.length) return
|
|
339
|
-
// The dialog's focus trap handles Tab too, and would hand focus to the
|
|
340
|
-
// mode chip this is about to render.
|
|
341
|
-
event.preventDefault()
|
|
342
|
-
event.stopPropagation()
|
|
343
346
|
enter({ id: `${c.id}:actions`, label: c.label, icon: c.icon, children: actions })
|
|
344
347
|
}
|
|
345
348
|
|
|
346
349
|
function enter(c: Command) {
|
|
350
|
+
trailState.value = [...trailState.value, { query: query.value, selectedId: selectedId.value }]
|
|
347
351
|
trail.value = [...trail.value, c]
|
|
348
352
|
query.value = ""
|
|
349
|
-
|
|
353
|
+
select(0)
|
|
350
354
|
modeItems.value = Array.isArray(c.children) ? c.children : []
|
|
351
355
|
refresh()
|
|
352
356
|
// Entering by click leaves the focus on the button that no longer exists,
|
|
@@ -357,13 +361,19 @@ function enter(c: Command) {
|
|
|
357
361
|
|
|
358
362
|
/** Unwind the trail to `depth` entries — 0 is the root. */
|
|
359
363
|
function popTo(depth: number) {
|
|
364
|
+
const state = trailState.value[depth] || { query: "", selectedId: null }
|
|
360
365
|
const next = trail.value.slice(0, Math.max(0, depth))
|
|
366
|
+
trailState.value = trailState.value.slice(0, Math.max(0, depth))
|
|
361
367
|
trail.value = next
|
|
362
|
-
query.value = ""
|
|
363
|
-
selectedIndex.value = 0
|
|
364
368
|
const parent = next[next.length - 1]
|
|
365
369
|
modeItems.value = parent && Array.isArray(parent.children) ? parent.children : []
|
|
370
|
+
query.value = state.query
|
|
371
|
+
select(0)
|
|
366
372
|
refresh()
|
|
373
|
+
void nextTick(() => {
|
|
374
|
+
const index = state.selectedId ? flat.value.findIndex((c) => c.id === state.selectedId) : -1
|
|
375
|
+
select(index >= 0 ? index : 0)
|
|
376
|
+
})
|
|
367
377
|
inputRef.value?.focus()
|
|
368
378
|
}
|
|
369
379
|
|
|
@@ -446,88 +456,23 @@ const source = computed<Command[]>(() => (mode.value ? modeItems.value : props.c
|
|
|
446
456
|
* the one bilingual setup common enough to be worth a table — and it is a
|
|
447
457
|
* fallback, tried only when the query as typed matches nothing.
|
|
448
458
|
*/
|
|
449
|
-
const LATIN = "qwertyuiop[]asdfghjkl;'zxcvbnm,.`"
|
|
450
|
-
const CYRILLIC = "йцукенгшщзхъфывапролджэячсмитьбюё"
|
|
451
|
-
const SWAP = new Map<string, string>()
|
|
452
|
-
for (let i = 0; i < LATIN.length; i++) {
|
|
453
|
-
SWAP.set(LATIN[i]!, CYRILLIC[i]!)
|
|
454
|
-
SWAP.set(CYRILLIC[i]!, LATIN[i]!)
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
function swapLayout(term: string): string {
|
|
458
|
-
return [...term].map((ch) => SWAP.get(ch) ?? ch).join("")
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
/** Damerau-Levenshtein distance, giving up past 1: all a typo check needs. */
|
|
462
|
-
function withinOne(a: string, b: string): boolean {
|
|
463
|
-
if (Math.abs(a.length - b.length) > 1) return false
|
|
464
|
-
let i = 0
|
|
465
|
-
while (i < a.length && i < b.length && a[i] === b[i]) i++
|
|
466
|
-
if (i === a.length || i === b.length) return true
|
|
467
|
-
const rest = (x: number, y: number) => a.slice(i + x) === b.slice(i + y)
|
|
468
|
-
return rest(1, 1) || rest(1, 0) || rest(0, 1) || (a[i] === b[i + 1] && a[i + 1] === b[i] && rest(2, 2))
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/*
|
|
472
|
-
* A typo in a word long enough to have one: a slip in a three-letter word
|
|
473
|
-
* makes it a different word. Compared against the word and its start, so
|
|
474
|
-
* "deplyo" finds "deploy" and "deployment" alike.
|
|
475
|
-
*/
|
|
476
|
-
const TYPO_MIN = 5
|
|
477
|
-
function nearWord(term: string, label: string): boolean {
|
|
478
|
-
if (term.length < TYPO_MIN) return false
|
|
479
|
-
return label
|
|
480
|
-
.split(/[^\p{L}\p{N}]+/u)
|
|
481
|
-
.some((word) => withinOne(term, word) || (word.length > term.length && withinOne(term, word.slice(0, term.length))))
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
/*
|
|
485
|
-
* Every word of the query has to land somewhere, in any order: "branch deploy"
|
|
486
|
-
* finds "Deploy current branch". Per word, label > keywords > description,
|
|
487
|
-
* the same weights the palette always had; a typo match ranks below all of
|
|
488
|
-
* them, so an exact hit is never outranked by a near one.
|
|
489
|
-
*/
|
|
490
|
-
function score(c: Command, terms: string[]): number {
|
|
491
|
-
const label = c.label.toLowerCase()
|
|
492
|
-
const keywords = (c.keywords ?? []).map((k) => k.toLowerCase())
|
|
493
|
-
const description = c.description?.toLowerCase() ?? ""
|
|
494
|
-
let total = 0
|
|
495
|
-
for (const term of terms) {
|
|
496
|
-
let hit =
|
|
497
|
-
(label.includes(term) ? 4 : 0) +
|
|
498
|
-
(keywords.some((k) => k.includes(term)) ? 3 : 0) +
|
|
499
|
-
(description.includes(term) ? 2 : 0)
|
|
500
|
-
if (!hit && nearWord(term, label)) hit = 1
|
|
501
|
-
if (!hit) return 0
|
|
502
|
-
total += hit
|
|
503
|
-
}
|
|
504
|
-
return total
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
function rank(items: Command[], terms: string[]): Command[] {
|
|
508
|
-
return items
|
|
509
|
-
.map((c) => ({ c, score: score(c, terms) }))
|
|
510
|
-
.filter((e) => e.score > 0)
|
|
511
|
-
.sort((a, b) => b.score - a.score || a.c.label.localeCompare(b.c.label))
|
|
512
|
-
.map((e) => e.c)
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
const typedTerms = computed(() => query.value.trim().toLowerCase().split(/\s+/).filter(Boolean))
|
|
516
|
-
|
|
517
459
|
/*
|
|
518
460
|
* The local match and the terms it matched with — the swapped ones when the
|
|
519
461
|
* layout fallback is what found it, so the highlight marks what actually hit.
|
|
520
462
|
*/
|
|
521
463
|
const local = computed<{ items: Command[]; terms: string[] }>(() => {
|
|
522
|
-
const terms =
|
|
464
|
+
const terms = parseCommandQuery(query.value)
|
|
465
|
+
const filtered = query.value.trim()
|
|
466
|
+
? source.value
|
|
467
|
+
: source.value.filter((c) => !c.hidden)
|
|
523
468
|
// Empty query: show everything EXCEPT hidden commands (they only surface once
|
|
524
469
|
// typed). With a query, hidden commands rank like any other.
|
|
525
|
-
if (!terms.length) return { items:
|
|
526
|
-
const items =
|
|
527
|
-
if (items.length || !props.layoutFallback) return { items, terms }
|
|
528
|
-
const swapped = terms
|
|
529
|
-
const other =
|
|
530
|
-
return other.length ? { items: other, terms: swapped } : { items, terms }
|
|
470
|
+
if (!terms.include.length && !terms.exclude.length && !terms.groups.length) return { items: filtered, terms: [] }
|
|
471
|
+
const items = rankCommandItems(filtered, terms)
|
|
472
|
+
if (items.length || !props.layoutFallback) return { items, terms: terms.include }
|
|
473
|
+
const swapped = swapCommandTerms(terms)
|
|
474
|
+
const other = rankCommandItems(filtered, swapped)
|
|
475
|
+
return other.length ? { items: other, terms: swapped.include } : { items, terms: terms.include }
|
|
531
476
|
})
|
|
532
477
|
|
|
533
478
|
const ranked = computed<Command[]>(() => local.value.items)
|
|
@@ -706,16 +651,17 @@ function highlight(value: string, extra: string[] = []): Part[] {
|
|
|
706
651
|
|
|
707
652
|
// ── selection + keyboard ─────────────────────────────────────
|
|
708
653
|
watch(query, () => {
|
|
709
|
-
|
|
654
|
+
select(0)
|
|
710
655
|
refresh()
|
|
711
656
|
})
|
|
712
657
|
watch([query, trail, () => props.open], () => {
|
|
713
658
|
expanded.value = new Set()
|
|
714
659
|
})
|
|
715
660
|
watch(
|
|
716
|
-
() => flat.value.
|
|
717
|
-
(
|
|
718
|
-
|
|
661
|
+
() => flat.value.map((c) => c.id).join("|"),
|
|
662
|
+
() => {
|
|
663
|
+
const index = selectedId.value ? flat.value.findIndex((c) => c.id === selectedId.value) : -1
|
|
664
|
+
select(index >= 0 ? index : 0)
|
|
719
665
|
},
|
|
720
666
|
)
|
|
721
667
|
watch([selectedIndex, () => flat.value.map((c) => c.id).join("|")], async () => {
|
|
@@ -730,13 +676,42 @@ function scrollSelectedIntoView() {
|
|
|
730
676
|
el?.scrollIntoView({ block: "nearest" })
|
|
731
677
|
}
|
|
732
678
|
|
|
679
|
+
const keyboardSelection = ref(false)
|
|
680
|
+
|
|
681
|
+
function select(index: number, keyboard = false) {
|
|
682
|
+
const len = flat.value.length
|
|
683
|
+
selectedIndex.value = len ? Math.max(0, Math.min(index, len - 1)) : 0
|
|
684
|
+
selectedId.value = flat.value[selectedIndex.value]?.id ?? null
|
|
685
|
+
if (keyboard) keyboardSelection.value = true
|
|
686
|
+
}
|
|
687
|
+
|
|
733
688
|
function moveDown() {
|
|
734
689
|
const len = flat.value.length
|
|
735
|
-
if (len)
|
|
690
|
+
if (len) select((selectedIndex.value + 1) % len, true)
|
|
736
691
|
}
|
|
737
692
|
function moveUp() {
|
|
738
693
|
const len = flat.value.length
|
|
739
|
-
if (len)
|
|
694
|
+
if (len) select((selectedIndex.value - 1 + len) % len, true)
|
|
695
|
+
}
|
|
696
|
+
function movePage(direction: -1 | 1) {
|
|
697
|
+
select(selectedIndex.value + direction * 8, true)
|
|
698
|
+
}
|
|
699
|
+
function onPaletteKeydown(event: KeyboardEvent) {
|
|
700
|
+
if (event.isComposing) return
|
|
701
|
+
if (!(["ArrowDown", "ArrowUp", "Home", "End", "PageDown", "PageUp"] as string[]).includes(event.key)) return
|
|
702
|
+
event.preventDefault()
|
|
703
|
+
event.stopPropagation()
|
|
704
|
+
if (event.key === "ArrowDown") moveDown()
|
|
705
|
+
else if (event.key === "ArrowUp") moveUp()
|
|
706
|
+
else if (event.key === "Home") select(0, true)
|
|
707
|
+
else if (event.key === "End") select(flat.value.length - 1, true)
|
|
708
|
+
else movePage(event.key === "PageDown" ? 1 : -1)
|
|
709
|
+
}
|
|
710
|
+
function onPointerMove() {
|
|
711
|
+
keyboardSelection.value = false
|
|
712
|
+
}
|
|
713
|
+
function onPointerEnter(c: Command) {
|
|
714
|
+
if (!keyboardSelection.value) select(flatIndexOf(c))
|
|
740
715
|
}
|
|
741
716
|
function runSelected(event?: KeyboardEvent) {
|
|
742
717
|
const c = flat.value[selectedIndex.value]
|
|
@@ -789,7 +764,7 @@ function run(c: Command | undefined) {
|
|
|
789
764
|
// Back to the top of a fresh list: the query that found this command is
|
|
790
765
|
// spent, and leaving it would hide whatever the action just changed.
|
|
791
766
|
query.value = ""
|
|
792
|
-
|
|
767
|
+
select(0)
|
|
793
768
|
inputRef.value?.focus()
|
|
794
769
|
return
|
|
795
770
|
}
|
|
@@ -831,10 +806,14 @@ function onEscape(event: KeyboardEvent) {
|
|
|
831
806
|
watch(
|
|
832
807
|
() => props.open,
|
|
833
808
|
async (o) => {
|
|
809
|
+
if (o) claim()
|
|
810
|
+
else release()
|
|
834
811
|
cancel()
|
|
835
812
|
query.value = ""
|
|
836
|
-
|
|
813
|
+
select(0)
|
|
814
|
+
selectedId.value = null
|
|
837
815
|
trail.value = []
|
|
816
|
+
trailState.value = []
|
|
838
817
|
modeItems.value = []
|
|
839
818
|
found.value = []
|
|
840
819
|
failed.value = false
|
|
@@ -846,6 +825,8 @@ watch(
|
|
|
846
825
|
{ immediate: true },
|
|
847
826
|
)
|
|
848
827
|
|
|
828
|
+
onBeforeUnmount(release)
|
|
829
|
+
|
|
849
830
|
// Through useHotkeys rather than a listener of its own: the palette is the one
|
|
850
831
|
// shortcut that has to work from inside a text field, and `code` is what makes
|
|
851
832
|
// it fire on a layout where Ctrl-K arrives as "л".
|
|
@@ -868,14 +849,17 @@ useHotkeys(() =>
|
|
|
868
849
|
<DialogRoot :open="open" @update:open="(v) => emit('update:open', v)">
|
|
869
850
|
<DialogPortal>
|
|
870
851
|
<DialogOverlay
|
|
871
|
-
:class="{ 'lp-scrim--light': frosted }"
|
|
872
|
-
class="lp-scrim fixed inset-0
|
|
852
|
+
:class="{ 'lp-scrim--light': frosted, 'lp-scrim--nested': layer.nested }"
|
|
853
|
+
class="lp-scrim fixed inset-0 data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]"
|
|
854
|
+
:style="{ zIndex: layer.scrim }"
|
|
873
855
|
/>
|
|
874
856
|
<DialogContent
|
|
875
|
-
class="lp-cmd-dialog fixed left-1/2 top-[12vh]
|
|
876
|
-
:class="[frosted ? 'lp-glass-overlay' : 'bg-surface-raised', previewPane && 'lp-cmd-split']"
|
|
857
|
+
class="lp-cmd-dialog fixed left-1/2 top-[12vh] flex max-h-[76vh] -translate-x-1/2 flex-col overflow-hidden rounded-card border border-line shadow-panel outline-none data-[state=open]:animate-[pop-in_160ms_var(--ease-emphasized)] data-[state=closed]:animate-[pop-out_130ms_ease]"
|
|
858
|
+
:class="[frosted ? (layer.nested ? 'lp-glass-overlay--nested' : 'lp-glass-overlay') : 'bg-surface-raised', previewPane && 'lp-cmd-split']"
|
|
859
|
+
:style="{ zIndex: layer.panel }"
|
|
877
860
|
:data-pane="paneOpen ? 'open' : undefined"
|
|
878
861
|
@open-auto-focus.prevent
|
|
862
|
+
@keydown.capture="onPaletteKeydown"
|
|
879
863
|
>
|
|
880
864
|
<DialogTitle class="sr-only">Command palette</DialogTitle>
|
|
881
865
|
<DialogDescription class="sr-only">Search and run a command.</DialogDescription>
|
|
@@ -916,8 +900,6 @@ useHotkeys(() =>
|
|
|
916
900
|
:aria-activedescendant="activeId"
|
|
917
901
|
:placeholder="mode?.childPlaceholder ?? placeholder"
|
|
918
902
|
class="h-12 min-w-0 flex-1 bg-transparent text-sm text-ink outline-none placeholder:text-muted"
|
|
919
|
-
@keydown.down.prevent="moveDown"
|
|
920
|
-
@keydown.up.prevent="moveUp"
|
|
921
903
|
@keydown.enter.prevent="runSelected"
|
|
922
904
|
@keydown.backspace="onBackspace"
|
|
923
905
|
@keydown.esc="onEscape"
|
|
@@ -927,7 +909,7 @@ useHotkeys(() =>
|
|
|
927
909
|
</div>
|
|
928
910
|
|
|
929
911
|
<!-- Results -->
|
|
930
|
-
<div class="flex min-h-0 flex-1">
|
|
912
|
+
<div class="flex min-h-0 flex-1" @pointermove="onPointerMove">
|
|
931
913
|
<LpScrollArea ref="scrollRef" class="lp-cmd-list min-h-0 min-w-0 flex-1" content-class="p-2">
|
|
932
914
|
<!-- While a request is out there is nothing to say yet: "no results"
|
|
933
915
|
under a spinner reads as an answer, and it is not one. -->
|
|
@@ -974,7 +956,7 @@ useHotkeys(() =>
|
|
|
974
956
|
: 'text-ink hover:bg-surface-soft/60',
|
|
975
957
|
]"
|
|
976
958
|
@click="onRowClick($event, c)"
|
|
977
|
-
@pointerenter="
|
|
959
|
+
@pointerenter="onPointerEnter(c)"
|
|
978
960
|
>
|
|
979
961
|
<LpIcon v-if="c.icon" :name="c.icon" :size="16" class="shrink-0" :class="{ 'mt-0.5': c.excerpt }" />
|
|
980
962
|
<span class="min-w-0 flex-1">
|
|
@@ -153,7 +153,7 @@ watch(() => props.open, (open) => (open ? claim() : release()), { immediate: tru
|
|
|
153
153
|
onBeforeUnmount(release)
|
|
154
154
|
|
|
155
155
|
const contentClass = computed(() => {
|
|
156
|
-
const surface = frosted.value ? "lp-glass-overlay" : "bg-surface-raised"
|
|
156
|
+
const surface = frosted.value ? (layer.value.nested ? "lp-glass-overlay--nested" : "lp-glass-overlay") : "bg-surface-raised"
|
|
157
157
|
const base = `fixed z-(--z-modal) flex flex-col border-line ${surface} shadow-panel outline-none`
|
|
158
158
|
const map: Record<Direction, string> = {
|
|
159
159
|
left: "inset-y-0 left-0 border-r rounded-r-card",
|
|
@@ -443,7 +443,7 @@ const previewStyle = computed(() => {
|
|
|
443
443
|
<div
|
|
444
444
|
v-show="peeking || peek > 0"
|
|
445
445
|
class="lp-scrim pointer-events-none fixed inset-0"
|
|
446
|
-
:class="{ 'lp-scrim--light': frosted }"
|
|
446
|
+
:class="{ 'lp-scrim--light': frosted, 'lp-scrim--nested': layer.nested }"
|
|
447
447
|
:style="{ zIndex: layer.scrim, opacity: peek, transition: peeking || reducedMotion() ? 'none' : 'opacity 0.18s ease-out' }"
|
|
448
448
|
/>
|
|
449
449
|
<div
|
|
@@ -476,7 +476,7 @@ const previewStyle = computed(() => {
|
|
|
476
476
|
<DrawerOverlay
|
|
477
477
|
:style="{ zIndex: layer.scrim }"
|
|
478
478
|
class="lp-scrim fixed inset-0 z-(--z-overlay) data-[state=open]:animate-[fade-in_150ms_ease] data-[state=closed]:animate-[fade-out_130ms_ease]"
|
|
479
|
-
:class="{ 'lp-scrim--light': frosted }"
|
|
479
|
+
:class="{ 'lp-scrim--light': frosted, 'lp-scrim--nested': layer.nested }"
|
|
480
480
|
/>
|
|
481
481
|
<DrawerContent
|
|
482
482
|
:class="contentClass"
|