@poveste/app 0.20.0 → 0.21.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/bundled/app.css +55 -27
- package/dist/bundled/components/layout/LayoutModal.vue_vue_type_script_setup_true_lang.js +44 -5
- package/dist/bundled/components/panel/ComponentDocs.js +1 -1
- package/dist/bundled/components/panel/ComponentDocs.vue_vue_type_script_setup_true_lang.js +72 -40
- package/dist/bundled/components/panel/StoryDocs.vue_vue_type_script_setup_true_lang.js +34 -10
- package/dist/bundled/components/panel/StorySourceCode.js +1 -1
- package/dist/bundled/components/panel/StorySourceCode.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/bundled/components/story/StoryResponsivePreview.js +1 -1
- package/dist/bundled/components/story/StoryResponsivePreview.vue_vue_type_script_setup_true_lang.js +5 -3
- package/dist/bundled/components/story/StoryVariantGridItem.js +1 -1
- package/dist/bundled/components/story/StoryVariantGridItem.vue_vue_type_script_setup_true_lang.js +5 -3
- package/dist/bundled/components/story/StoryVariantSinglePreviewRemote.vue_vue_type_script_setup_true_lang.js +3 -2
- package/dist/bundled/index.js +5 -1
- package/dist/bundled/sandbox.js +2 -0
- package/dist/bundled/util/component-docs-data.js +5 -1
- package/dist/bundled/util/component-docs.js +90 -14
- package/dist/bundled/util/dark.js +3 -1
- package/dist/bundled/util/docs.js +12 -2
- package/dist/bundled/util/highlighter.js +1 -1
- package/dist/bundled/util/icons.generated.js +1 -0
- package/dist/bundled/util/keyboard.js +5 -4
- package/dist/style.css +317 -150
- package/package.json +7 -7
- package/src/app/components/layout/LayoutModal.vue +55 -2
- package/src/app/components/panel/ComponentDocs.vue +83 -17
- package/src/app/components/panel/StoryDocs.vue +30 -3
- package/src/app/components/panel/StorySourceCode.vue +2 -2
- package/src/app/components/story/StoryResponsivePreview.vue +4 -1
- package/src/app/components/story/StoryVariantGridItem.vue +4 -1
- package/src/app/components/story/StoryVariantSinglePreviewRemote.vue +6 -4
- package/src/app/index.ts +12 -3
- package/src/app/sandbox.ts +5 -0
- package/src/app/util/component-docs-data.ts +6 -3
- package/src/app/util/component-docs.ts +102 -11
- package/src/app/util/dark.ts +6 -0
- package/src/app/util/docs.ts +18 -2
- package/src/app/util/highlighter.ts +2 -1
- package/src/app/util/icons.generated.ts +1 -1
- package/src/app/util/keyboard.ts +8 -4
package/dist/bundled/components/story/StoryVariantGridItem.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -35,8 +35,8 @@ var StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE
|
|
|
35
35
|
emits: { resize: (_width, _height) => true },
|
|
36
36
|
setup(__props, { emit: __emit }) {
|
|
37
37
|
useCssVars((_ctx) => ({
|
|
38
|
-
"
|
|
39
|
-
"
|
|
38
|
+
"ff0ecc2c": unref(variant).iconColor,
|
|
39
|
+
"v59a40d7e": unref(settings).backgroundColor
|
|
40
40
|
}));
|
|
41
41
|
const props = __props;
|
|
42
42
|
const emit = __emit;
|
|
@@ -104,7 +104,9 @@ var StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE
|
|
|
104
104
|
variant: unref(variant),
|
|
105
105
|
story: __props.story
|
|
106
106
|
}, null, 8, ["variant", "story"])])]), createElementVNode("div", {
|
|
107
|
-
class: normalizeClass(["border
|
|
107
|
+
class: normalizeClass(["border rounded flex-1 p-4 relative", {
|
|
108
|
+
"bg-gray-700": unref(previewDark),
|
|
109
|
+
"bg-white": !unref(previewDark),
|
|
108
110
|
"border-gray-100 dark:border-gray-800": !unref(isActive),
|
|
109
111
|
"border-primary-200 dark:border-primary-900": unref(isActive)
|
|
110
112
|
}]),
|
|
@@ -59,7 +59,7 @@ var StoryVariantSinglePreviewRemote_vue_vue_type_script_setup_true_lang_default
|
|
|
59
59
|
iframe.value?.contentWindow?.postMessage({
|
|
60
60
|
type: STATE_SYNC,
|
|
61
61
|
state: changes
|
|
62
|
-
});
|
|
62
|
+
}, window.location.origin);
|
|
63
63
|
}
|
|
64
64
|
let bridge = createStateBridge(postState);
|
|
65
65
|
function syncState() {
|
|
@@ -79,6 +79,7 @@ var StoryVariantSinglePreviewRemote_vue_vue_type_script_setup_true_lang_default
|
|
|
79
79
|
}
|
|
80
80
|
useEventListener(window, "message", (event) => {
|
|
81
81
|
if (event.source !== iframe.value?.contentWindow) return;
|
|
82
|
+
if (event.origin !== window.location.origin) return;
|
|
82
83
|
switch (event.data?.type) {
|
|
83
84
|
case STATE_SYNC:
|
|
84
85
|
if (!fromCurrentOccupant(event.data)) break;
|
|
@@ -193,7 +194,7 @@ var StoryVariantSinglePreviewRemote_vue_vue_type_script_setup_true_lang_default
|
|
|
193
194
|
if (iframe.value?.contentWindow) iframe.value.contentWindow.postMessage({
|
|
194
195
|
type: PREVIEW_SETTINGS_SYNC,
|
|
195
196
|
settings: toRaw(settings)
|
|
196
|
-
});
|
|
197
|
+
}, window.location.origin);
|
|
197
198
|
}
|
|
198
199
|
watch(() => settings, () => {
|
|
199
200
|
syncSettings();
|
package/dist/bundled/index.js
CHANGED
|
@@ -7,11 +7,15 @@ import { iconCollections } from "./util/icons.generated.js";
|
|
|
7
7
|
import { createApp, watch } from "@poveste/vendors/vue";
|
|
8
8
|
import { addCollection } from "@poveste/vendors/iconify";
|
|
9
9
|
import { createPinia } from "@poveste/vendors/pinia";
|
|
10
|
-
import { generation } from "virtual:$poveste-stories";
|
|
10
|
+
import { generation, icons, onUpdate } from "virtual:$poveste-stories";
|
|
11
11
|
import "virtual:$poveste-theme";
|
|
12
12
|
//#region src/app/index.ts
|
|
13
13
|
async function mountMainApp() {
|
|
14
14
|
for (const collection of iconCollections) addCollection(collection);
|
|
15
|
+
for (const collection of icons) addCollection(collection);
|
|
16
|
+
onUpdate((_files, _tree, icons = []) => {
|
|
17
|
+
for (const collection of icons) addCollection(collection);
|
|
18
|
+
});
|
|
15
19
|
watch(isDark, (dark) => {
|
|
16
20
|
document.documentElement.style.colorScheme = dark ? "dark" : "light";
|
|
17
21
|
}, { immediate: true });
|
package/dist/bundled/sandbox.js
CHANGED
|
@@ -17,6 +17,7 @@ import { createPinia } from "@poveste/vendors/pinia";
|
|
|
17
17
|
import { files, onUpdate } from "virtual:$poveste-stories";
|
|
18
18
|
import { parseQuery } from "@poveste/vendors/vue-router";
|
|
19
19
|
import { reportStoryError } from "@poveste/shared";
|
|
20
|
+
import "virtual:$poveste-theme";
|
|
20
21
|
//#region src/app/sandbox.ts
|
|
21
22
|
var query = parseQuery(window.location.search);
|
|
22
23
|
var storyId = ref(typeof query["storyId"] === "string" ? query["storyId"] : null);
|
|
@@ -56,6 +57,7 @@ watch(previewDark, (value) => {
|
|
|
56
57
|
if (!el) continue;
|
|
57
58
|
for (const className of previewDarkClasses()) el.classList.toggle(className, value);
|
|
58
59
|
}
|
|
60
|
+
document.documentElement.classList.toggle("ptw-dark", value);
|
|
59
61
|
}, { immediate: true });
|
|
60
62
|
var reportedColorScheme = "";
|
|
61
63
|
function reportColorScheme() {
|
|
@@ -1 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { componentDocs as componentDocs$1 } from "virtual:$poveste-component-docs";
|
|
2
|
+
//#region src/app/util/component-docs-data.ts
|
|
3
|
+
var componentDocs = componentDocs$1;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { componentDocs };
|
|
@@ -1,13 +1,57 @@
|
|
|
1
1
|
import { onBeforeUnmount, ref, watch } from "@poveste/vendors/vue";
|
|
2
2
|
//#region src/app/util/component-docs.ts
|
|
3
3
|
function toEntries(result) {
|
|
4
|
-
return Object.entries(result.components).map(([file, { doc, error }]) => ({
|
|
4
|
+
return Object.entries(result.components).map(([file, { doc, error, name }]) => ({
|
|
5
5
|
file,
|
|
6
|
-
name: file.split("/").pop().replace(
|
|
6
|
+
name: doc?.name ?? name ?? file.split("/").pop().replace(/(?:\.story)?\.[^.]+$/, ""),
|
|
7
7
|
...doc ? { doc } : {},
|
|
8
8
|
...error ? { error } : {}
|
|
9
9
|
}));
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Only the sections a story's `autoDocs` names, in the table's own order. A component
|
|
13
|
+
* left with nothing to show is dropped; one that failed keeps its error (#1398).
|
|
14
|
+
*/
|
|
15
|
+
function onlySections(entries, autoDocs) {
|
|
16
|
+
if (!Array.isArray(autoDocs)) return entries;
|
|
17
|
+
return entries.flatMap((entry) => {
|
|
18
|
+
if (!entry.doc) return [entry];
|
|
19
|
+
const doc = {
|
|
20
|
+
...entry.doc,
|
|
21
|
+
props: autoDocs.includes("props") ? entry.doc.props : [],
|
|
22
|
+
slots: autoDocs.includes("slots") ? entry.doc.slots : [],
|
|
23
|
+
events: autoDocs.includes("events") ? entry.doc.events : []
|
|
24
|
+
};
|
|
25
|
+
return doc.props.length || doc.slots.length || doc.events.length ? [{
|
|
26
|
+
...entry,
|
|
27
|
+
doc
|
|
28
|
+
}] : [];
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A compound component's root first, `SelectRoot` before `SelectTrigger`, else the order
|
|
33
|
+
* they came in. A story rendering two families, such as a Select inside a Calendar, opens
|
|
34
|
+
* the root its own folder or file is named for: `Calendar/story/CalendarSelect.story.vue`
|
|
35
|
+
* opens `CalendarRoot`, not the `SelectRoot` it imported first.
|
|
36
|
+
*/
|
|
37
|
+
function rootFirst(entries, storyFile) {
|
|
38
|
+
const roots = entries.filter((entry) => entry.name.endsWith("Root"));
|
|
39
|
+
const family = (entry) => entry.name.slice(0, -4);
|
|
40
|
+
const segments = storyFile?.split(/[\\/]/) ?? [];
|
|
41
|
+
const fileName = segments.at(-1) ?? "";
|
|
42
|
+
const root = roots.find((entry) => segments.slice(0, -1).includes(family(entry))) ?? roots.find((entry) => fileName.startsWith(family(entry))) ?? roots[0];
|
|
43
|
+
return root ? [root, ...entries.filter((entry) => entry !== root)] : entries;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The `v-model` a prop and its `update:` event make together, as a template writes it:
|
|
47
|
+
* `v-model` for `modelValue`, `v-model:open` for `open` (#1436). Asked with either name,
|
|
48
|
+
* so the two rows of a pair, one under Props and one under Events, carry the same mark.
|
|
49
|
+
*/
|
|
50
|
+
function modelLabel(doc, name) {
|
|
51
|
+
const prop = name.startsWith("update:") ? name.slice(7) : name;
|
|
52
|
+
if (!(doc.props.some((candidate) => candidate.name === prop) && doc.events.some((event) => event.name === `update:${prop}`))) return;
|
|
53
|
+
return prop === "modelValue" ? "v-model" : `v-model:${prop}`;
|
|
54
|
+
}
|
|
11
55
|
function tagText(tags, name) {
|
|
12
56
|
const tag = tags.find((tag) => tag.name === name);
|
|
13
57
|
return tag ? tag.text ?? "" : void 0;
|
|
@@ -23,23 +67,49 @@ function tagHref(text) {
|
|
|
23
67
|
*/
|
|
24
68
|
function useComponentDocs(storyId) {
|
|
25
69
|
const components = ref();
|
|
70
|
+
const pending = ref(false);
|
|
71
|
+
const off = ref();
|
|
26
72
|
const hot = import.meta.hot;
|
|
27
73
|
if (!hot) {
|
|
28
|
-
watch(storyId, async (id) => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
74
|
+
watch(storyId, async (id, _, onCleanup) => {
|
|
75
|
+
let stale = false;
|
|
76
|
+
onCleanup(() => stale = true);
|
|
77
|
+
pending.value = true;
|
|
78
|
+
try {
|
|
79
|
+
const { componentDocs } = await import("./component-docs-data.js");
|
|
80
|
+
const loaders = id ? componentDocs[id] : void 0;
|
|
81
|
+
const docs = loaders && Object.fromEntries(await Promise.all(Object.entries(loaders).map(async ([file, load]) => [file, (await load()).default])));
|
|
82
|
+
if (!stale) components.value = id && docs ? toEntries({
|
|
83
|
+
storyId: id,
|
|
84
|
+
components: docs
|
|
85
|
+
}) : void 0;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (!stale) {
|
|
88
|
+
components.value = void 0;
|
|
89
|
+
console.error("[poveste] could not load this story's component docs:", error);
|
|
90
|
+
}
|
|
91
|
+
} finally {
|
|
92
|
+
if (!stale) pending.value = false;
|
|
93
|
+
}
|
|
35
94
|
}, { immediate: true });
|
|
36
|
-
return {
|
|
95
|
+
return {
|
|
96
|
+
components,
|
|
97
|
+
pending,
|
|
98
|
+
off
|
|
99
|
+
};
|
|
37
100
|
}
|
|
38
101
|
function ask() {
|
|
39
|
-
if (storyId.value)
|
|
102
|
+
if (storyId.value) {
|
|
103
|
+
pending.value = true;
|
|
104
|
+
hot.send("poveste:docgen-request", { storyId: storyId.value });
|
|
105
|
+
}
|
|
40
106
|
}
|
|
41
107
|
function onResult(result) {
|
|
42
|
-
if (result.storyId === storyId.value)
|
|
108
|
+
if (result.storyId === storyId.value) {
|
|
109
|
+
components.value = toEntries(result);
|
|
110
|
+
off.value = result.off;
|
|
111
|
+
pending.value = false;
|
|
112
|
+
}
|
|
43
113
|
}
|
|
44
114
|
hot.on("poveste:docgen-result", onResult);
|
|
45
115
|
hot.on("poveste:docgen-stale", ask);
|
|
@@ -49,9 +119,15 @@ function useComponentDocs(storyId) {
|
|
|
49
119
|
});
|
|
50
120
|
watch(storyId, () => {
|
|
51
121
|
components.value = void 0;
|
|
122
|
+
off.value = void 0;
|
|
123
|
+
pending.value = false;
|
|
52
124
|
ask();
|
|
53
125
|
}, { immediate: true });
|
|
54
|
-
return {
|
|
126
|
+
return {
|
|
127
|
+
components,
|
|
128
|
+
pending,
|
|
129
|
+
off
|
|
130
|
+
};
|
|
55
131
|
}
|
|
56
132
|
//#endregion
|
|
57
|
-
export { tagHref, tagText, toEntries, useComponentDocs };
|
|
133
|
+
export { modelLabel, onlySections, rootFirst, tagHref, tagText, toEntries, useComponentDocs };
|
|
@@ -2,11 +2,13 @@ import { povesteConfig } from "./config.js";
|
|
|
2
2
|
import { useDark, useToggle } from "@poveste/vendors/vue-use";
|
|
3
3
|
import { watch } from "@poveste/vendors/vue";
|
|
4
4
|
//#region src/app/util/dark.ts
|
|
5
|
+
var inSandbox = location.href.includes("__sandbox");
|
|
5
6
|
var isDark = useDark({
|
|
6
7
|
valueDark: "ptw-dark",
|
|
7
8
|
...povesteConfig.theme.defaultColorScheme ? { initialValue: povesteConfig.theme.defaultColorScheme } : {},
|
|
8
9
|
storageKey: "poveste-color-scheme",
|
|
9
|
-
storage: povesteConfig.theme.storeColorScheme ? localStorage : sessionStorage
|
|
10
|
+
storage: povesteConfig.theme.storeColorScheme ? localStorage : sessionStorage,
|
|
11
|
+
...inSandbox ? { onChanged: () => {} } : {}
|
|
10
12
|
});
|
|
11
13
|
var toggleDark = useToggle(isDark);
|
|
12
14
|
function applyDarkToControls() {
|
|
@@ -3,7 +3,9 @@ import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
|
|
|
3
3
|
//#region src/app/util/docs.ts
|
|
4
4
|
/** What the variant declares, or what its framework generates from it; `undefined` when neither has anything. */
|
|
5
5
|
async function getDynamicSourceCode(variant, generate) {
|
|
6
|
-
|
|
6
|
+
const source = variant.source;
|
|
7
|
+
if (typeof source === "function") return source(variant.state) || void 0;
|
|
8
|
+
if (source) return source;
|
|
7
9
|
const sourceSlot = variant.slots?.().source;
|
|
8
10
|
if (sourceSlot) {
|
|
9
11
|
const source = sourceSlot()[0].children;
|
|
@@ -11,6 +13,14 @@ async function getDynamicSourceCode(variant, generate) {
|
|
|
11
13
|
}
|
|
12
14
|
return await generate?.(variant) || void 0;
|
|
13
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* The grammar a story's source reads in: a Vue or Svelte story is HTML with script
|
|
18
|
+
* inside, and a Solid or React story file is TypeScript with JSX, which the HTML
|
|
19
|
+
* grammar left plain (#1521). A variant's own source follows its story's.
|
|
20
|
+
*/
|
|
21
|
+
function sourceLang(story) {
|
|
22
|
+
return /\.[cm]?[jt]sx$/.test(story?.file?.filePath ?? "") ? "tsx" : "html";
|
|
23
|
+
}
|
|
14
24
|
async function getStaticSourceCode(story) {
|
|
15
25
|
const sourceLoader = story.file?.source;
|
|
16
26
|
return sourceLoader ? (await sourceLoader()).default : void 0;
|
|
@@ -25,4 +35,4 @@ async function getSourceCode(story, variant) {
|
|
|
25
35
|
return await getDynamicSourceCode(variant, generate) || getStaticSourceCode(story);
|
|
26
36
|
}
|
|
27
37
|
//#endregion
|
|
28
|
-
export { getDynamicSourceCode, getSourceCode, getStaticSourceCode, loadGenerateSourceCode };
|
|
38
|
+
export { getDynamicSourceCode, getSourceCode, getStaticSourceCode, loadGenerateSourceCode, sourceLang };
|
|
@@ -17,7 +17,7 @@ var highlighterPromise;
|
|
|
17
17
|
*/
|
|
18
18
|
function getHighlighter() {
|
|
19
19
|
highlighterPromise ??= createHighlighterCore({
|
|
20
|
-
langs: [import("shiki/langs/html.mjs"), import("shiki/langs/
|
|
20
|
+
langs: [import("shiki/langs/html.mjs"), import("shiki/langs/tsx.mjs")],
|
|
21
21
|
themes: [import("shiki/themes/github-light-high-contrast.mjs"), import("shiki/themes/github-dark.mjs")],
|
|
22
22
|
engine: createOnigurumaEngine(import("shiki/wasm"))
|
|
23
23
|
}).catch((e) => {
|
|
@@ -15,6 +15,7 @@ var iconCollections = [
|
|
|
15
15
|
"chevron-left": { "body": "<path fill=\"currentColor\" d=\"M10 16L20 6l1.4 1.4l-8.6 8.6l8.6 8.6L20 26z\"/>" },
|
|
16
16
|
"chevron-right": { "body": "<path fill=\"currentColor\" d=\"M22 16L12 26l-1.4-1.4l8.6-8.6l-8.6-8.6L12 6z\"/>" },
|
|
17
17
|
"chevron-sort": { "body": "<path fill=\"currentColor\" d=\"m16 28l-7-7l1.41-1.41L16 25.17l5.59-5.58L23 21zm0-24l7 7l-1.41 1.41L16 6.83l-5.59 5.58L9 11z\"/>" },
|
|
18
|
+
"circle-dash": { "body": "<path fill=\"currentColor\" d=\"M7.7 4.7a14.7 14.7 0 0 0-3 3.1L6.3 9a13.3 13.3 0 0 1 2.6-2.7Zm-3.1 7.6l-1.9-.6A12.5 12.5 0 0 0 2 16h2a11.5 11.5 0 0 1 .6-3.7m-1.9 8.1a14.4 14.4 0 0 0 2 3.9l1.6-1.2a12.9 12.9 0 0 1-1.7-3.3Zm5.1 6.9a14.4 14.4 0 0 0 3.9 2l.6-1.9A12.9 12.9 0 0 1 9 25.7Zm3.9-24.6l.6 1.9A11.5 11.5 0 0 1 16 4V2a12.5 12.5 0 0 0-4.3.7m12.5 24.6a15.2 15.2 0 0 0 3.1-3.1L25.7 23a11.5 11.5 0 0 1-2.7 2.7Zm3.2-7.6l1.9.6A15.5 15.5 0 0 0 30 16h-2a11.5 11.5 0 0 1-.6 3.7m1.8-8.1a14.4 14.4 0 0 0-2-3.9l-1.6 1.2a12.9 12.9 0 0 1 1.7 3.3Zm-5.1-7a14.4 14.4 0 0 0-3.9-2l-.6 1.9a12.9 12.9 0 0 1 3.3 1.7Zm-3.8 24.7l-.6-1.9a11.5 11.5 0 0 1-3.7.6v2a21.4 21.4 0 0 0 4.3-.7\"/>" },
|
|
18
19
|
"close": { "body": "<path fill=\"currentColor\" d=\"M17.414 16L24 9.414L22.586 8L16 14.586L9.414 8L8 9.414L14.586 16L8 22.586L9.414 24L16 17.414L22.586 24L24 22.586z\"/>" },
|
|
19
20
|
"code": { "body": "<path fill=\"currentColor\" d=\"m31 16l-7 7l-1.41-1.41L28.17 16l-5.58-5.59L24 9zM1 16l7-7l1.41 1.41L3.83 16l5.58 5.59L8 23zm11.42 9.484L17.64 6l1.932.517L14.352 26z\"/>" },
|
|
20
21
|
"code-hide": { "body": "<path fill=\"currentColor\" d=\"m17.713 13.471l1.863-6.953L17.645 6l-1.565 5.838zm6.494 6.494l1.414 1.414L31 16l-7-7l-1.414 1.414L28.172 16zM30 28.586L3.414 2L2 3.414l5.793 5.793L1 16l7 7l1.414-1.414L3.828 16l5.379-5.379l5.677 5.677l-2.461 9.184l1.932.518l2.162-8.069L28.586 30z\"/>" },
|
|
@@ -72,17 +72,18 @@ function onKeyboardShortcut(shortcut, handler, options = {}) {
|
|
|
72
72
|
modifiers.alt.pressed = event.altKey;
|
|
73
73
|
modifiers.shift.pressed = event.shiftKey;
|
|
74
74
|
modifiers.meta.pressed = event.metaKey;
|
|
75
|
-
if (isMatchingShortcut(isRef(shortcut) ? shortcut.value : shortcut)) handler(event);
|
|
75
|
+
if (isMatchingShortcut(isRef(shortcut) ? shortcut.value : shortcut, event.key.toLocaleLowerCase())) handler(event);
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
-
function isMatchingShortcut(shortcut) {
|
|
79
|
-
for (const combination of shortcut) if (isMatchingCombination(combination.toLowerCase())) return true;
|
|
78
|
+
function isMatchingShortcut(shortcut, eventKey) {
|
|
79
|
+
for (const combination of shortcut) if (isMatchingCombination(combination.toLowerCase(), eventKey)) return true;
|
|
80
80
|
return false;
|
|
81
81
|
}
|
|
82
|
-
function isMatchingCombination(combination) {
|
|
82
|
+
function isMatchingCombination(combination, eventKey) {
|
|
83
83
|
const splitted = combination.split("+").map((key) => key.trim());
|
|
84
84
|
const targetKey = splitted.pop();
|
|
85
85
|
if (!targetKey) return false;
|
|
86
|
+
if (eventKey !== targetKey) return false;
|
|
86
87
|
for (const [name, mod] of Object.entries(modifiers)) if (splitted.includes(name) !== mod.pressed) return false;
|
|
87
88
|
return pressedKeys.has(targetKey);
|
|
88
89
|
}
|