@qilin-agent/client-ui-shortcuts 0.0.0-stage → 3.1.3
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/LICENSE +21 -0
- package/README.i18n.yaml +37 -0
- package/README.md +86 -2
- package/README.zh.md +87 -0
- package/lib/client.js +1163 -0
- package/lib/index.js +6 -0
- package/lib/types/client/Editor.d.ts +18 -0
- package/lib/types/client/Icons.d.ts +17 -0
- package/lib/types/client/Reference.d.ts +33 -0
- package/lib/types/client/feedback.d.ts +22 -0
- package/lib/types/client/fixed.d.ts +10 -0
- package/lib/types/client/index.d.ts +17 -0
- package/lib/types/client/locales.d.ts +62 -0
- package/lib/types/client/store.d.ts +19 -0
- package/lib/types/index.d.ts +4 -0
- package/package.json +68 -3
package/lib/client.js
ADDED
|
@@ -0,0 +1,1163 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@qilin-agent/client-ui-shortcuts",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let _qilin_agent_client_ui_primitives = require("@qilin-agent/client-ui-primitives");
|
|
8
|
+
let _qilin_agent_client_store = require("@qilin-agent/client-store");
|
|
9
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
+
let react = require("react");
|
|
11
|
+
//#region lib/types/client/store.js
|
|
12
|
+
/** Shortcut reference visibility and search state, shared by its entry points. */
|
|
13
|
+
/**
|
|
14
|
+
* Declare the reference dialog store.
|
|
15
|
+
* @returns root-scoped visibility, focus request, and search actions.
|
|
16
|
+
*/
|
|
17
|
+
function createShortcutsStore() {
|
|
18
|
+
return (0, _qilin_agent_client_store.defineStore)({
|
|
19
|
+
init: () => ({
|
|
20
|
+
open: false,
|
|
21
|
+
query: "",
|
|
22
|
+
focusRequest: 0
|
|
23
|
+
}),
|
|
24
|
+
actions: {
|
|
25
|
+
open: (d) => {
|
|
26
|
+
d.open = true;
|
|
27
|
+
d.focusRequest++;
|
|
28
|
+
},
|
|
29
|
+
close: (d) => {
|
|
30
|
+
d.open = false;
|
|
31
|
+
d.query = "";
|
|
32
|
+
},
|
|
33
|
+
search: (d, query) => {
|
|
34
|
+
d.query = query;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region ../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
|
|
41
|
+
function r(e) {
|
|
42
|
+
var t, f, n = "";
|
|
43
|
+
if ("string" == typeof e || "number" == typeof e) n += e;
|
|
44
|
+
else if ("object" == typeof e) if (Array.isArray(e)) {
|
|
45
|
+
var o = e.length;
|
|
46
|
+
for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
|
|
47
|
+
} else for (f in e) e[f] && (n && (n += " "), n += f);
|
|
48
|
+
return n;
|
|
49
|
+
}
|
|
50
|
+
function clsx() {
|
|
51
|
+
for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
|
|
52
|
+
return n;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region lib/types/client/feedback.js
|
|
56
|
+
/**
|
|
57
|
+
* Identify the unreadable preferences, their recovery path, and the bindings still in use.
|
|
58
|
+
* @param config - failed read and last accepted preferences.
|
|
59
|
+
* @param runtime - storage owner whose location and reload action to show.
|
|
60
|
+
* @param t - shortcut dictionary.
|
|
61
|
+
* @returns localized recovery guidance without replacing the stored document.
|
|
62
|
+
*/
|
|
63
|
+
function shortcutReadFailure(config, runtime, t) {
|
|
64
|
+
const location = t(runtime === "desktop" ? "desktop-document" : "web-document");
|
|
65
|
+
const reload = t(runtime === "desktop" ? "desktop-reload" : "web-reload");
|
|
66
|
+
return `${t(config.error ?? "read", {
|
|
67
|
+
location,
|
|
68
|
+
reload
|
|
69
|
+
})} ${t(config.usingDefaults ? "using-defaults" : "using-accepted")}`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Describe an unsuccessful preference write without losing command names.
|
|
73
|
+
* @param result - rejected operation result.
|
|
74
|
+
* @param catalog - current command labels.
|
|
75
|
+
* @param t - shortcut dictionary.
|
|
76
|
+
* @param runtime - storage owner for unreadable-document recovery guidance.
|
|
77
|
+
* @returns localized diagnosis for a system toast and accessible field description.
|
|
78
|
+
*/
|
|
79
|
+
function shortcutFailure(result, catalog, t, runtime) {
|
|
80
|
+
if (result.status === "unreadable") return shortcutReadFailure(result.snapshot, runtime, t);
|
|
81
|
+
return result.issue ? t(result.issue) : result.status === "conflict" ? t("conflict", { commands: result.conflicts?.map((id) => catalog.find((row) => row.id === id)?.label ?? id).join(", ") ?? "" }) : t(result.status);
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-shortcuts/src/client/Reference.module.css.mjs
|
|
85
|
+
const css = ".JRJerq_setting,.JRJerq_row,.JRJerq_binding{justify-content:space-between;align-items:center;gap:8px;display:flex}.JRJerq_setting{box-sizing:border-box;border-bottom:.5px solid var(--qilin-alias-border-l2);min-height:60px;padding:16px 0}.JRJerq_settingText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.JRJerq_settingTitle{color:var(--qilin-alias-label-primary);font-size:14px;line-height:22px}.JRJerq_settingDescription{color:var(--qilin-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.JRJerq_button{border-radius:var(--qilin-radius-md);background:var(--qilin-alias-bg-module-platform);min-width:90px;max-width:280px;height:36px;color:var(--qilin-alias-label-primary);font:inherit;cursor:pointer;white-space:nowrap;border:none;flex-shrink:0;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.JRJerq_button:hover{background:var(--qilin-alias-interactive-bg-hover)}.JRJerq_dialog{box-sizing:border-box;border-radius:24px;gap:0;width:min(480px,100%);height:600px;max-height:calc(100dvh - 108px);padding:0;transform:translateY(30px);box-shadow:0 0 1px #0003,0 0 4px #00000005,0 12px 32px #00000014}.JRJerq_dialog:focus{outline:none}.JRJerq_contents{flex-direction:column;flex:1;min-height:0;display:flex}.JRJerq_header{box-sizing:border-box;flex:0 0 46px;padding:22px 54px 0 24px;position:relative}.JRJerq_title{color:var(--qilin-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.JRJerq_close{width:28px;height:28px;color:var(--qilin-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex;position:absolute;top:20px;right:14px}.JRJerq_close:hover{background:var(--qilin-alias-interactive-bg-hover)}.JRJerq_searchRow{box-sizing:border-box;flex:0 0 60px;align-items:center;padding:14px 20px 10px;display:flex}.JRJerq_searchField{box-sizing:border-box;border:.5px solid var(--qilin-alias-border-l2);background:var(--qilin-alias-markdown-code-block);border-radius:12px;align-items:center;gap:8px;width:100%;height:36px;padding:8px 14px;display:flex}.JRJerq_searchIcon{color:var(--qilin-alias-label-caption);flex:none}.JRJerq_search{width:100%;min-width:0;color:var(--qilin-alias-label-primary);font:inherit;background:0 0;border:0;outline:none;padding:0;font-size:13px;line-height:18px}.JRJerq_search::placeholder{color:var(--qilin-alias-label-tertiary);opacity:1}.JRJerq_list{--qilin-scrollbar-thumb:var(--qilin-alias-scrollbar-bg-l2);--qilin-scrollbar-thumb-hover:var(--qilin-alias-scrollbar-hover-l2);overscroll-behavior:contain;flex:1;min-height:0;padding:0 16px 18px;overflow-y:auto}.JRJerq_footer{border-top:.5px solid var(--qilin-alias-border-l2);flex:none;justify-content:space-between;align-items:center;gap:12px;min-height:52px;padding:0 24px;font-size:12px;line-height:18px;display:flex}.JRJerq_resetAll{color:var(--qilin-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;border-radius:4px;align-items:center;gap:8px;padding:6px 0;display:inline-flex}.JRJerq_resetAll:enabled:hover{color:var(--qilin-alias-label-secondary)}.JRJerq_resetAll:focus-visible{outline:1px solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px}.JRJerq_resetAll:disabled{cursor:default;opacity:.45}.JRJerq_modifiedCount{color:var(--qilin-alias-label-tertiary)}.JRJerq_group{color:var(--qilin-alias-label-tertiary);margin:18px 8px 4px;font-size:12px;font-weight:400;line-height:18px}.JRJerq_rows{margin:0;padding:0;list-style:none}.JRJerq_row{border-radius:var(--qilin-radius-md);box-sizing:border-box;min-height:42px;color:var(--qilin-alias-label-primary);padding:8px;font-size:13px;line-height:18px;position:relative}.JRJerq_binding{pointer-events:none;flex-shrink:0;position:relative}.JRJerq_binding:has(.JRJerq_inlineEditor){pointer-events:auto}.JRJerq_commandLabel{pointer-events:none;text-overflow:ellipsis;white-space:nowrap;min-width:0;position:relative;overflow:hidden}.JRJerq_hint{color:var(--qilin-alias-label-tertiary);font-size:12px;line-height:18px}p.JRJerq_hint{margin:6px 0}.JRJerq_rowActions{width:20px;height:26px;color:var(--qilin-alias-label-tertiary);opacity:0;justify-content:center;align-items:center;display:inline-flex}.JRJerq_row:hover .JRJerq_rowActions,.JRJerq_row:has(:focus-visible) .JRJerq_rowActions{opacity:1}.JRJerq_inlineAction:focus-visible{outline:1px solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px;border-radius:4px}.JRJerq_rowButton{border-radius:inherit;cursor:pointer;background:0 0;border:0;width:100%;height:100%;position:absolute;inset:0}.JRJerq_row:has(.JRJerq_rowButton:enabled):hover{background:var(--qilin-alias-interactive-bg-hover)}.JRJerq_rowButton:focus-visible{outline:1px solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:-1px}.JRJerq_binding .JRJerq_keyBadge{color:var(--qilin-alias-label-secondary)}.JRJerq_binding .JRJerq_fixedKeyBadge{height:26px;color:var(--qilin-alias-label-tertiary)}.JRJerq_keyBadge{box-sizing:border-box;background:var(--qilin-alias-bg-module-platform);border-radius:10px;justify-content:center;height:26px;padding:0 12px}.JRJerq_unbound{box-sizing:border-box;background:var(--qilin-alias-bg-module-platform);height:26px;color:var(--qilin-alias-label-tertiary);white-space:nowrap;border-radius:10px;justify-content:center;align-items:center;padding:6px 16px;font-size:12px;line-height:14px;display:inline-flex}.JRJerq_inlineEditor{flex-direction:column;align-items:flex-end;gap:6px;display:flex}.JRJerq_binding:has(.JRJerq_inlineEditor){max-width:100%}.JRJerq_inlineControls{justify-content:flex-end;align-items:center;gap:8px;display:flex}.JRJerq_inlineAction{color:var(--qilin-alias-label-tertiary);font:inherit;white-space:nowrap;cursor:pointer;background:0 0;border:0;padding:0;font-size:12px;line-height:18px}.JRJerq_recorder{box-sizing:border-box;border:.5px solid var(--qilin-alias-border-l4);background:var(--qilin-alias-bg-module-platform);min-width:96px;height:26px;color:var(--qilin-alias-label-secondary);font:inherit;white-space:nowrap;cursor:pointer;border-radius:10px;justify-content:center;align-items:center;padding:3px 14px;font-size:12px;line-height:18px;display:inline-flex}.JRJerq_recorder:focus-visible{outline:1px solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px}.JRJerq_recorder.JRJerq_invalid{border:1px solid var(--qilin-alias-state-error-primary);box-shadow:none}.JRJerq_recorded{height:auto;color:inherit;background:0 0;padding:0}.JRJerq_review{color:var(--qilin-alias-label-tertiary);flex-direction:column;align-items:flex-end;gap:4px;font-size:12px;line-height:18px;display:flex}.JRJerq_toastSuccess{color:var(--qilin-alias-state-success-secondary)}.JRJerq_toastError{color:var(--qilin-alias-state-warn-secondary)}.JRJerq_srOnly{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@media (hover:none){.JRJerq_rowActions{opacity:1}}.JRJerq_button:disabled,.JRJerq_rowButton:disabled,.JRJerq_inlineAction:disabled,.JRJerq_recorder[aria-disabled=true]{cursor:default;opacity:.45}.JRJerq_search::-webkit-search-cancel-button{-webkit-appearance:none}.JRJerq_clearSearch{box-sizing:border-box;border:.5px solid var(--qilin-alias-label-tertiary);corner-shape:round;width:16px;height:16px;color:var(--qilin-alias-label-secondary);cursor:pointer;background:0 0;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.JRJerq_clearSearch:hover{background:var(--qilin-alias-interactive-bg-hover)}.JRJerq_clearSearch:focus-visible{outline:1px solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px}";
|
|
86
|
+
const tagId = "@qilin-agent/client-ui-shortcuts/Reference.module.css";
|
|
87
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
88
|
+
const tag = document.createElement("style");
|
|
89
|
+
tag.dataset.plugin = "@qilin-agent/client-ui-shortcuts";
|
|
90
|
+
tag.dataset.pluginCss = tagId;
|
|
91
|
+
tag.textContent = css;
|
|
92
|
+
document.head.appendChild(tag);
|
|
93
|
+
}
|
|
94
|
+
var Reference_module_css_default = {
|
|
95
|
+
"binding": "JRJerq_binding",
|
|
96
|
+
"button": "JRJerq_button",
|
|
97
|
+
"clearSearch": "JRJerq_clearSearch",
|
|
98
|
+
"close": "JRJerq_close",
|
|
99
|
+
"commandLabel": "JRJerq_commandLabel",
|
|
100
|
+
"contents": "JRJerq_contents",
|
|
101
|
+
"dialog": "JRJerq_dialog",
|
|
102
|
+
"fixedKeyBadge": "JRJerq_fixedKeyBadge",
|
|
103
|
+
"footer": "JRJerq_footer",
|
|
104
|
+
"group": "JRJerq_group",
|
|
105
|
+
"header": "JRJerq_header",
|
|
106
|
+
"hint": "JRJerq_hint",
|
|
107
|
+
"inlineAction": "JRJerq_inlineAction",
|
|
108
|
+
"inlineControls": "JRJerq_inlineControls",
|
|
109
|
+
"inlineEditor": "JRJerq_inlineEditor",
|
|
110
|
+
"invalid": "JRJerq_invalid",
|
|
111
|
+
"keyBadge": "JRJerq_keyBadge",
|
|
112
|
+
"list": "JRJerq_list",
|
|
113
|
+
"modifiedCount": "JRJerq_modifiedCount",
|
|
114
|
+
"recorded": "JRJerq_recorded",
|
|
115
|
+
"recorder": "JRJerq_recorder",
|
|
116
|
+
"resetAll": "JRJerq_resetAll",
|
|
117
|
+
"review": "JRJerq_review",
|
|
118
|
+
"row": "JRJerq_row",
|
|
119
|
+
"rowActions": "JRJerq_rowActions",
|
|
120
|
+
"rowButton": "JRJerq_rowButton",
|
|
121
|
+
"rows": "JRJerq_rows",
|
|
122
|
+
"search": "JRJerq_search",
|
|
123
|
+
"searchField": "JRJerq_searchField",
|
|
124
|
+
"searchIcon": "JRJerq_searchIcon",
|
|
125
|
+
"searchRow": "JRJerq_searchRow",
|
|
126
|
+
"setting": "JRJerq_setting",
|
|
127
|
+
"settingDescription": "JRJerq_settingDescription",
|
|
128
|
+
"settingText": "JRJerq_settingText",
|
|
129
|
+
"settingTitle": "JRJerq_settingTitle",
|
|
130
|
+
"srOnly": "JRJerq_srOnly",
|
|
131
|
+
"title": "JRJerq_title",
|
|
132
|
+
"toastError": "JRJerq_toastError",
|
|
133
|
+
"toastSuccess": "JRJerq_toastSuccess",
|
|
134
|
+
"unbound": "JRJerq_unbound"
|
|
135
|
+
};
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region lib/types/client/Editor.js
|
|
138
|
+
/** Inline physical-key recording and revision-aware command editing. */
|
|
139
|
+
/**
|
|
140
|
+
* Save a released physical combination against the configuration the user reviewed.
|
|
141
|
+
* @param props - command, accepted snapshots, and storage/feedback callbacks.
|
|
142
|
+
* @returns inline command controls; failures retain the draft and allow another recording.
|
|
143
|
+
*/
|
|
144
|
+
function ShortcutEditor({ target, onClose, onSaved, onError, useCatalog, useConfig, useFixedCatalog, edit, recording, describeBinding, runtime, platform, t }) {
|
|
145
|
+
const config = useConfig((value) => value);
|
|
146
|
+
const catalog = useCatalog((value) => value);
|
|
147
|
+
const fixed = useFixedCatalog((value) => value);
|
|
148
|
+
const [revision, setRevision] = (0, react.useState)(config.revision);
|
|
149
|
+
const [candidate, setCandidate] = (0, react.useState)(null);
|
|
150
|
+
const [captured, setCaptured] = (0, react.useState)(false);
|
|
151
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
152
|
+
const [nativeReady, setNativeReady] = (0, react.useState)(runtime === "web");
|
|
153
|
+
const [message, setMessage] = (0, react.useState)("");
|
|
154
|
+
const [retry, setRetry] = (0, react.useState)(null);
|
|
155
|
+
const descriptionId = (0, react.useId)();
|
|
156
|
+
const recorder = (0, react.useRef)(null);
|
|
157
|
+
const mounted = (0, react.useRef)(true);
|
|
158
|
+
const writing = (0, react.useRef)(false);
|
|
159
|
+
/* v8 ignore next -- The effect installs reset before the recorder is enabled. */
|
|
160
|
+
const restart = (0, react.useRef)(() => {});
|
|
161
|
+
const desktopChords = runtime === "desktop" && (platform === "macos" || platform === "windows");
|
|
162
|
+
const targetId = target.id;
|
|
163
|
+
const stale = revision !== config.revision;
|
|
164
|
+
const report = (text) => {
|
|
165
|
+
setMessage(text);
|
|
166
|
+
onError(text);
|
|
167
|
+
};
|
|
168
|
+
const save = async (operation, reviewedRevision = revision) => {
|
|
169
|
+
if (writing.current) return;
|
|
170
|
+
writing.current = true;
|
|
171
|
+
setBusy(true);
|
|
172
|
+
const result = await edit(operation, reviewedRevision);
|
|
173
|
+
if (!mounted.current) return;
|
|
174
|
+
writing.current = false;
|
|
175
|
+
setBusy(false);
|
|
176
|
+
if (result.status === "saved") onSaved();
|
|
177
|
+
else {
|
|
178
|
+
setRetry(operation.type === "set" ? operation.binding : null);
|
|
179
|
+
report(shortcutFailure(result, [...catalog, ...fixed], t, runtime));
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const capture = (binding, id) => {
|
|
183
|
+
setCandidate(binding);
|
|
184
|
+
setCaptured(true);
|
|
185
|
+
setRetry(null);
|
|
186
|
+
const described = describeBinding(binding);
|
|
187
|
+
const conflicts = described.conflicts.filter((value) => value !== id).map((value) => [...catalog, ...fixed].find((row) => row.id === value)?.label ?? value);
|
|
188
|
+
if (described.issue !== null) {
|
|
189
|
+
report(t(described.issue));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (conflicts.length > 0) {
|
|
193
|
+
report(t("conflict", { commands: conflicts.join(", ") }));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (stale) {
|
|
197
|
+
setRetry(binding);
|
|
198
|
+
report(t("stale"));
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (config.status !== "ready") {
|
|
202
|
+
report(config.status === "loading" ? t("not-ready") : shortcutReadFailure(config, runtime, t));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
save({
|
|
206
|
+
type: "set",
|
|
207
|
+
id,
|
|
208
|
+
binding
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
const handlers = (0, react.useRef)({
|
|
212
|
+
capture,
|
|
213
|
+
report,
|
|
214
|
+
onClose
|
|
215
|
+
});
|
|
216
|
+
(0, react.useLayoutEffect)(() => {
|
|
217
|
+
handlers.current = {
|
|
218
|
+
capture,
|
|
219
|
+
report,
|
|
220
|
+
onClose
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
(0, react.useEffect)(() => {
|
|
224
|
+
mounted.current = true;
|
|
225
|
+
return () => {
|
|
226
|
+
mounted.current = false;
|
|
227
|
+
};
|
|
228
|
+
}, []);
|
|
229
|
+
(0, react.useEffect)(() => {
|
|
230
|
+
let disposed = false;
|
|
231
|
+
recording(true).then(() => {
|
|
232
|
+
if (!disposed) setNativeReady(true);
|
|
233
|
+
}, () => {
|
|
234
|
+
if (!disposed) handlers.current.report(t("native-failed"));
|
|
235
|
+
});
|
|
236
|
+
const composition = (0, _qilin_agent_client_ui_primitives.observeComposition)(document);
|
|
237
|
+
let pending = null;
|
|
238
|
+
let dead = false;
|
|
239
|
+
let blocked = false;
|
|
240
|
+
const held = /* @__PURE__ */ new Set();
|
|
241
|
+
const reset = () => {
|
|
242
|
+
pending = null;
|
|
243
|
+
held.clear();
|
|
244
|
+
blocked = false;
|
|
245
|
+
dead = false;
|
|
246
|
+
};
|
|
247
|
+
restart.current = reset;
|
|
248
|
+
const down = (event) => {
|
|
249
|
+
if (composition.guards(event) || event.getModifierState("AltGraph")) {
|
|
250
|
+
if (desktopChords) reset();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if ((!desktopChords || document.activeElement !== recorder.current) && event.key === "Escape" && !event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey) {
|
|
254
|
+
event.preventDefault();
|
|
255
|
+
event.stopPropagation();
|
|
256
|
+
if (!event.repeat && !writing.current) handlers.current.onClose();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const commandDeadKey = runtime === "web" && platform === "macos" && document.activeElement === recorder.current && event.code === "KeyN" && event.metaKey && event.altKey && !event.ctrlKey && !event.shiftKey;
|
|
260
|
+
if (event.key === "Dead" && !commandDeadKey) {
|
|
261
|
+
if (desktopChords) reset();
|
|
262
|
+
dead = true;
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (dead) {
|
|
266
|
+
dead = false;
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const modifiers = [
|
|
270
|
+
"control",
|
|
271
|
+
"alt",
|
|
272
|
+
"shift",
|
|
273
|
+
"meta"
|
|
274
|
+
].filter((value) => ({
|
|
275
|
+
control: event.ctrlKey,
|
|
276
|
+
alt: event.altKey,
|
|
277
|
+
shift: event.shiftKey,
|
|
278
|
+
meta: event.metaKey
|
|
279
|
+
})[value]);
|
|
280
|
+
const recordTab = desktopChords || (platform === "macos" || platform === "windows") && modifiers.length >= 3;
|
|
281
|
+
if (document.activeElement !== recorder.current || event.key === "Tab" && !recordTab) return;
|
|
282
|
+
event.preventDefault();
|
|
283
|
+
event.stopPropagation();
|
|
284
|
+
if (writing.current || event.repeat) return;
|
|
285
|
+
if (/^(Control|Alt|Shift|Meta)(Left|Right)$/u.test(event.code)) {
|
|
286
|
+
if (desktopChords && pending !== null) {
|
|
287
|
+
reset();
|
|
288
|
+
setCandidate(null);
|
|
289
|
+
setCaptured(false);
|
|
290
|
+
}
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (desktopChords) {
|
|
294
|
+
held.add(event.code);
|
|
295
|
+
if (blocked) return;
|
|
296
|
+
if (held.size > 2) {
|
|
297
|
+
blocked = true;
|
|
298
|
+
pending = null;
|
|
299
|
+
handlers.current.report(t("too-many-keys"));
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
const codes = [event.code, ...desktopChords ? [...held].filter((value) => value !== event.code) : []];
|
|
305
|
+
pending = describeBinding({
|
|
306
|
+
code: codes[0],
|
|
307
|
+
...codes[1] === void 0 ? {} : { secondCode: codes[1] },
|
|
308
|
+
modifiers
|
|
309
|
+
}).binding;
|
|
310
|
+
setCandidate(pending);
|
|
311
|
+
setCaptured(desktopChords);
|
|
312
|
+
setMessage("");
|
|
313
|
+
setRetry(null);
|
|
314
|
+
} catch (_error) {
|
|
315
|
+
blocked = desktopChords;
|
|
316
|
+
pending = null;
|
|
317
|
+
handlers.current.report(t("unsupported-key"));
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const up = (event) => {
|
|
321
|
+
held.delete(event.code);
|
|
322
|
+
if (desktopChords && document.activeElement === recorder.current) {
|
|
323
|
+
event.preventDefault();
|
|
324
|
+
event.stopPropagation();
|
|
325
|
+
}
|
|
326
|
+
const binding = pending !== null && (pending.code === event.code || pending.secondCode === event.code || pending.modifiers.some((modifier) => modifier === event.code.replace(/(Left|Right)$/u, "").toLowerCase())) ? pending : null;
|
|
327
|
+
if (binding !== null) {
|
|
328
|
+
pending = null;
|
|
329
|
+
blocked = desktopChords;
|
|
330
|
+
}
|
|
331
|
+
if (desktopChords && (held.size === 0 || platform === "macos" && /^Meta(Left|Right)$/u.test(event.code))) {
|
|
332
|
+
held.clear();
|
|
333
|
+
blocked = false;
|
|
334
|
+
}
|
|
335
|
+
if (binding === null) return;
|
|
336
|
+
handlers.current.capture(binding, targetId);
|
|
337
|
+
};
|
|
338
|
+
const blur = () => {
|
|
339
|
+
reset();
|
|
340
|
+
if (desktopChords) {
|
|
341
|
+
setCandidate(null);
|
|
342
|
+
setCaptured(false);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const focus = () => {
|
|
346
|
+
if (document.activeElement !== recorder.current) blur();
|
|
347
|
+
};
|
|
348
|
+
document.addEventListener("keydown", down, true);
|
|
349
|
+
document.addEventListener("keyup", up, true);
|
|
350
|
+
window.addEventListener("blur", blur);
|
|
351
|
+
if (desktopChords) {
|
|
352
|
+
document.addEventListener("focusin", focus, true);
|
|
353
|
+
document.addEventListener("compositionstart", blur, true);
|
|
354
|
+
}
|
|
355
|
+
return () => {
|
|
356
|
+
disposed = true;
|
|
357
|
+
composition.dispose();
|
|
358
|
+
document.removeEventListener("keydown", down, true);
|
|
359
|
+
document.removeEventListener("keyup", up, true);
|
|
360
|
+
window.removeEventListener("blur", blur);
|
|
361
|
+
document.removeEventListener("focusin", focus, true);
|
|
362
|
+
document.removeEventListener("compositionstart", blur, true);
|
|
363
|
+
recording(false).catch(() => {});
|
|
364
|
+
};
|
|
365
|
+
}, [
|
|
366
|
+
describeBinding,
|
|
367
|
+
recording,
|
|
368
|
+
t,
|
|
369
|
+
targetId,
|
|
370
|
+
runtime,
|
|
371
|
+
platform,
|
|
372
|
+
desktopChords
|
|
373
|
+
]);
|
|
374
|
+
(0, react.useEffect)(() => {
|
|
375
|
+
const element = recorder.current;
|
|
376
|
+
if (nativeReady && element !== null) (0, _qilin_agent_client_ui_primitives.focusWithoutRing)(element);
|
|
377
|
+
}, [nativeReady]);
|
|
378
|
+
const readonly = busy || stale || config.status !== "ready";
|
|
379
|
+
const review = stale && (0, react_jsx_runtime.jsxs)("div", {
|
|
380
|
+
className: Reference_module_css_default.review,
|
|
381
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("stale") }), (0, react_jsx_runtime.jsx)("button", {
|
|
382
|
+
type: "button",
|
|
383
|
+
className: Reference_module_css_default.inlineAction,
|
|
384
|
+
disabled: busy,
|
|
385
|
+
onClick: () => {
|
|
386
|
+
setRevision(config.revision);
|
|
387
|
+
setMessage("");
|
|
388
|
+
},
|
|
389
|
+
children: t("review")
|
|
390
|
+
})]
|
|
391
|
+
});
|
|
392
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
393
|
+
className: Reference_module_css_default.inlineEditor,
|
|
394
|
+
role: "group",
|
|
395
|
+
"aria-label": target.label,
|
|
396
|
+
"data-shortcut-modal": "shortcut-edit",
|
|
397
|
+
"aria-busy": busy,
|
|
398
|
+
children: [
|
|
399
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
400
|
+
className: Reference_module_css_default.inlineControls,
|
|
401
|
+
children: [
|
|
402
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
403
|
+
type: "button",
|
|
404
|
+
className: Reference_module_css_default.inlineAction,
|
|
405
|
+
disabled: readonly,
|
|
406
|
+
onClick: () => {
|
|
407
|
+
save({
|
|
408
|
+
type: "reset",
|
|
409
|
+
id: target.id
|
|
410
|
+
});
|
|
411
|
+
},
|
|
412
|
+
children: t("reset")
|
|
413
|
+
}),
|
|
414
|
+
target.binding !== null && (0, react_jsx_runtime.jsx)("button", {
|
|
415
|
+
type: "button",
|
|
416
|
+
className: Reference_module_css_default.inlineAction,
|
|
417
|
+
disabled: readonly,
|
|
418
|
+
onClick: () => {
|
|
419
|
+
save({
|
|
420
|
+
type: "set",
|
|
421
|
+
id: target.id,
|
|
422
|
+
binding: null
|
|
423
|
+
});
|
|
424
|
+
},
|
|
425
|
+
children: t("clear")
|
|
426
|
+
}),
|
|
427
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
428
|
+
ref: recorder,
|
|
429
|
+
type: "button",
|
|
430
|
+
className: clsx(Reference_module_css_default.recorder, message && Reference_module_css_default.invalid),
|
|
431
|
+
disabled: !nativeReady,
|
|
432
|
+
"aria-disabled": busy || !nativeReady,
|
|
433
|
+
onBlur: () => {
|
|
434
|
+
restart.current();
|
|
435
|
+
},
|
|
436
|
+
"aria-label": t("record"),
|
|
437
|
+
"aria-invalid": message !== "",
|
|
438
|
+
"aria-describedby": descriptionId,
|
|
439
|
+
onClick: () => {
|
|
440
|
+
if (!writing.current) {
|
|
441
|
+
restart.current();
|
|
442
|
+
setCaptured(false);
|
|
443
|
+
setMessage("");
|
|
444
|
+
setRetry(null);
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
children: captured && message === "" ? (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.ShortcutKeys, {
|
|
448
|
+
keys: describeBinding(candidate).keys,
|
|
449
|
+
className: Reference_module_css_default.recorded
|
|
450
|
+
}) : t("record")
|
|
451
|
+
})
|
|
452
|
+
]
|
|
453
|
+
}),
|
|
454
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
455
|
+
id: descriptionId,
|
|
456
|
+
className: Reference_module_css_default.srOnly,
|
|
457
|
+
children: message || (desktopChords ? "" : t(runtime === "web" ? platform === "windows" ? "windows-web-help" : platform === "macos" ? "macos-web-help" : "web-help" : "record-help"))
|
|
458
|
+
}),
|
|
459
|
+
review,
|
|
460
|
+
retry !== null && !stale && (0, react_jsx_runtime.jsx)("button", {
|
|
461
|
+
type: "button",
|
|
462
|
+
className: Reference_module_css_default.inlineAction,
|
|
463
|
+
disabled: readonly,
|
|
464
|
+
onClick: () => {
|
|
465
|
+
capture(retry, target.id);
|
|
466
|
+
},
|
|
467
|
+
children: t("retry-save")
|
|
468
|
+
})
|
|
469
|
+
]
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region lib/types/client/Icons.js
|
|
474
|
+
/** Supplied shortcut-control and feedback artwork, colored by the owning UI. */
|
|
475
|
+
const artwork = {
|
|
476
|
+
edit: (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: (0, react_jsx_runtime.jsx)("path", { d: "M7.4553 1.01221C8.02829 0.676881 8.73746 0.676959 9.31048 1.01221C9.52928 1.14026 9.72631 1.34353 9.98255 1.59978C10.2388 1.85601 10.4421 2.05305 10.5701 2.27185C10.9053 2.84485 10.9054 3.55407 10.5701 4.12703C10.4421 4.34576 10.2387 4.54293 9.98255 4.7991L4.99422 9.78744C4.71024 10.0714 4.50494 10.2832 4.2488 10.4324C3.99266 10.5815 3.70709 10.6557 3.32001 10.7625L2.43268 11.0072C2.08118 11.1042 1.75876 11.1948 1.50071 11.2265C1.2387 11.2585 0.884455 11.2512 0.607798 10.9745C0.331166 10.6979 0.323805 10.3436 0.35587 10.0816C0.387501 9.82358 0.47815 9.50112 0.575111 9.14964L0.819864 8.26232C0.926638 7.87525 1.00083 7.58966 1.14992 7.33353C1.2991 7.07739 1.5109 6.87209 1.79489 6.58811L6.78322 1.59978C7.03941 1.34359 7.23656 1.14027 7.4553 1.01221ZM11.6568 11.13H5.6639L6.72503 10.0689H11.6568V11.13ZM2.54509 7.33831C2.22348 7.65993 2.13155 7.75784 2.06755 7.86768C2.0036 7.97757 1.96369 8.10606 1.84272 8.54454L1.59797 9.43187C1.5011 9.78304 1.44118 10.0065 1.4162 10.1653C1.57504 10.1404 1.79876 10.0814 2.15046 9.98436L3.03779 9.7396C3.47631 9.61863 3.60475 9.57874 3.71464 9.51478C3.82448 9.45077 3.92239 9.35885 4.24401 9.03723L8.04047 5.23998L6.34155 3.54106L2.54509 7.33831ZM8.77473 1.92824C8.53277 1.78664 8.233 1.78664 7.99104 1.92824C7.91987 1.97 7.83628 2.04713 7.53343 2.34998L7.09176 2.79085L8.79068 4.48977L9.23235 4.0489C9.53517 3.74608 9.61232 3.66245 9.65409 3.59128C9.79567 3.34935 9.79564 3.04954 9.65409 2.8076C9.61237 2.73635 9.53565 2.65329 9.23235 2.34998C8.92899 2.04662 8.84598 1.96995 8.77473 1.92824Z" }) }),
|
|
477
|
+
error: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
478
|
+
(0, react_jsx_runtime.jsx)("path", { d: "M8.90039 3.97328V9.07973H7.09961V3.97328H8.90039Z" }),
|
|
479
|
+
(0, react_jsx_runtime.jsx)("path", { d: "M8.90039 10.341V12.3654H7.09961V10.341H8.90039Z" }),
|
|
480
|
+
(0, react_jsx_runtime.jsx)("path", { d: "M14.5996 8C14.5996 4.35492 11.6451 1.40039 8 1.40039C4.35492 1.40039 1.40039 4.35492 1.40039 8C1.40039 11.6451 4.35492 14.5996 8 14.5996C11.6451 14.5996 14.5996 11.6451 14.5996 8ZM15.9004 8C15.9004 12.363 12.363 15.9004 8 15.9004C3.63695 15.9004 0.0996094 12.363 0.0996094 8C0.0996094 3.63695 3.63695 0.0996094 8 0.0996094C12.363 0.0996094 15.9004 3.63695 15.9004 8Z" })
|
|
481
|
+
] }),
|
|
482
|
+
success: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("path", { d: "M12.5303 6.53027L8.80273 10.2578C8.54967 10.5109 8.31796 10.7439 8.10645 10.9141C7.88375 11.0932 7.616 11.2602 7.27344 11.3145C7.09229 11.3431 6.90771 11.3431 6.72656 11.3145C6.384 11.2602 6.11625 11.0932 5.89355 10.9141C5.68204 10.7439 5.45033 10.5109 5.19727 10.2578L3.46973 8.53027L4.53027 7.46973L6.25781 9.19727C6.53457 9.47402 6.70036 9.63859 6.83398 9.74609C6.95637 9.84453 6.98241 9.83644 6.96094 9.83301C6.98679 9.83709 7.01321 9.83709 7.03906 9.83301C7.01759 9.83644 7.04363 9.84453 7.16602 9.74609C7.29964 9.63859 7.46543 9.47402 7.74219 9.19727L11.4697 5.46973L12.5303 6.53027Z" }), (0, react_jsx_runtime.jsx)("path", { d: "M14.5996 8C14.5996 4.35492 11.6451 1.40039 8 1.40039C4.35492 1.40039 1.40039 4.35492 1.40039 8C1.40039 11.6451 4.35492 14.5996 8 14.5996C11.6451 14.5996 14.5996 11.6451 14.5996 8ZM15.9004 8C15.9004 12.363 12.363 15.9004 8 15.9004C3.63695 15.9004 0.0996094 12.363 0.0996094 8C0.0996094 3.63695 3.63695 0.0996094 8 0.0996094C12.363 0.0996094 15.9004 3.63695 15.9004 8Z" })] })
|
|
483
|
+
};
|
|
484
|
+
/**
|
|
485
|
+
* Render the shortcut design artwork at its supplied size.
|
|
486
|
+
* @param props - glyph kind and semantic color class.
|
|
487
|
+
* @returns an ornamental SVG hidden from assistive technology.
|
|
488
|
+
*/
|
|
489
|
+
function ShortcutIcon({ kind, className }) {
|
|
490
|
+
const size = kind === "edit" ? 12 : 16;
|
|
491
|
+
return (0, react_jsx_runtime.jsx)("svg", {
|
|
492
|
+
width: size,
|
|
493
|
+
height: size,
|
|
494
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
495
|
+
fill: "currentColor",
|
|
496
|
+
className,
|
|
497
|
+
"aria-hidden": "true",
|
|
498
|
+
children: artwork[kind]
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
//#endregion
|
|
502
|
+
//#region lib/types/client/Reference.js
|
|
503
|
+
/** Searchable editable shortcut reference and its General Settings row. */
|
|
504
|
+
/** Core reference positions are independent of labels and plugin registration order. */
|
|
505
|
+
const coreActionOrder = new Map([
|
|
506
|
+
"shortcuts.open",
|
|
507
|
+
"session.new",
|
|
508
|
+
"sidebar.left.toggle",
|
|
509
|
+
"session.search",
|
|
510
|
+
"workspace.add",
|
|
511
|
+
"session.rename",
|
|
512
|
+
"session.fork",
|
|
513
|
+
"session.archive",
|
|
514
|
+
"settings.open",
|
|
515
|
+
"workspace.openLocal",
|
|
516
|
+
"sidebar.right.toggle",
|
|
517
|
+
"workspace.files",
|
|
518
|
+
"browser.new",
|
|
519
|
+
"terminal.new",
|
|
520
|
+
"pane.split",
|
|
521
|
+
"pane.fullscreen.toggle",
|
|
522
|
+
"page.refresh",
|
|
523
|
+
"page.close"
|
|
524
|
+
].map((id, index) => [id, index]));
|
|
525
|
+
/**
|
|
526
|
+
* Render the General Settings action that opens the shortcut reference.
|
|
527
|
+
* @param props - shared dialog action and localized labels.
|
|
528
|
+
* @returns the settings row.
|
|
529
|
+
*/
|
|
530
|
+
function ShortcutsRow({ actions, t, useCatalog }) {
|
|
531
|
+
const shortcut = useCatalog((rows) => rows.find((row) => row.id === "shortcuts.open"));
|
|
532
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
533
|
+
className: Reference_module_css_default.setting,
|
|
534
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
535
|
+
className: Reference_module_css_default.settingText,
|
|
536
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
537
|
+
className: Reference_module_css_default.settingTitle,
|
|
538
|
+
children: t("settings")
|
|
539
|
+
}), (0, react_jsx_runtime.jsx)("p", {
|
|
540
|
+
className: Reference_module_css_default.settingDescription,
|
|
541
|
+
children: t("description")
|
|
542
|
+
})]
|
|
543
|
+
}), (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Tooltip, {
|
|
544
|
+
disabled: !shortcut?.keys.length,
|
|
545
|
+
label: t("global-hint"),
|
|
546
|
+
shortcutKeys: shortcut?.keys,
|
|
547
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
548
|
+
className: Reference_module_css_default.button,
|
|
549
|
+
type: "button",
|
|
550
|
+
"aria-label": t("view"),
|
|
551
|
+
"aria-keyshortcuts": shortcut?.aria,
|
|
552
|
+
onClick: () => {
|
|
553
|
+
actions.open();
|
|
554
|
+
},
|
|
555
|
+
children: t("view")
|
|
556
|
+
})
|
|
557
|
+
})]
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Render core actions in product order, then other commands by ID within each group. Search relevance takes precedence.
|
|
562
|
+
* @param props - root store, effective catalog, and localized copy.
|
|
563
|
+
* @returns the single reference dialog when open.
|
|
564
|
+
*/
|
|
565
|
+
function ShortcutReference({ useStore, actions, useCatalog, useConfig, useFixedCatalog, platform, runtime, edit, recording, describeBinding, t }) {
|
|
566
|
+
const { open, query, focusRequest } = useStore((state) => state);
|
|
567
|
+
const catalog = useCatalog((value) => value);
|
|
568
|
+
const config = useConfig((value) => value);
|
|
569
|
+
const fixedCatalog = useFixedCatalog((value) => value);
|
|
570
|
+
const [target, setTarget] = (0, react.useState)(null);
|
|
571
|
+
const [resetRevision, setResetRevision] = (0, react.useState)(null);
|
|
572
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
573
|
+
const [toast, setToast] = (0, react.useState)(null);
|
|
574
|
+
const mounted = (0, react.useRef)(true);
|
|
575
|
+
const search = (0, react.useRef)(null);
|
|
576
|
+
(0, react.useEffect)(() => {
|
|
577
|
+
mounted.current = true;
|
|
578
|
+
return () => {
|
|
579
|
+
mounted.current = false;
|
|
580
|
+
};
|
|
581
|
+
}, []);
|
|
582
|
+
const dismissToast = (0, react.useCallback)(() => {
|
|
583
|
+
setToast(null);
|
|
584
|
+
}, []);
|
|
585
|
+
const notify = (0, react.useCallback)((text, error = false) => {
|
|
586
|
+
setToast((previous) => {
|
|
587
|
+
if (error && previous?.error && previous.text === text) return previous;
|
|
588
|
+
return {
|
|
589
|
+
text,
|
|
590
|
+
error,
|
|
591
|
+
seq: (previous?.seq ?? 0) + 1
|
|
592
|
+
};
|
|
593
|
+
});
|
|
594
|
+
}, []);
|
|
595
|
+
(0, react.useEffect)(() => {
|
|
596
|
+
if (open && config.status === "unreadable") notify(shortcutReadFailure(config, runtime, t), true);
|
|
597
|
+
}, [
|
|
598
|
+
open,
|
|
599
|
+
config,
|
|
600
|
+
runtime,
|
|
601
|
+
notify,
|
|
602
|
+
t
|
|
603
|
+
]);
|
|
604
|
+
const closeEditor = () => {
|
|
605
|
+
setTarget(null);
|
|
606
|
+
const dialog = search.current?.closest("[role=\"dialog\"]");
|
|
607
|
+
/* v8 ignore next -- Editor callbacks run while its reference dialog and search input are mounted. */
|
|
608
|
+
if (dialog != null) (0, _qilin_agent_client_ui_primitives.focusWithoutRing)(dialog, { preventScroll: true });
|
|
609
|
+
};
|
|
610
|
+
const closeReference = () => {
|
|
611
|
+
if (busy) return;
|
|
612
|
+
/* v8 ignore next -- The confirmation modal blocks the reference's close control. */
|
|
613
|
+
if (resetRevision !== null) setResetRevision(null);
|
|
614
|
+
else if (target !== null) closeEditor();
|
|
615
|
+
else actions.close();
|
|
616
|
+
};
|
|
617
|
+
(0, react.useEffect)(() => {
|
|
618
|
+
if (!open) setResetRevision(null);
|
|
619
|
+
}, [open]);
|
|
620
|
+
const persist = async (...args) => {
|
|
621
|
+
setBusy(true);
|
|
622
|
+
const result = await edit(...args);
|
|
623
|
+
if (mounted.current) setBusy(false);
|
|
624
|
+
return result;
|
|
625
|
+
};
|
|
626
|
+
const resetAll = async () => {
|
|
627
|
+
/* v8 ignore next -- The reset control is accessible only while its confirmation is open. */
|
|
628
|
+
if (resetRevision === null) return;
|
|
629
|
+
const result = await persist({ type: "reset-all" }, resetRevision);
|
|
630
|
+
if (!mounted.current) return;
|
|
631
|
+
if (result.status === "saved" || result.status === "stale") setResetRevision(null);
|
|
632
|
+
notify(result.status === "saved" ? t("reset-saved") : result.status === "write-failed" ? t("reset-failed") : shortcutFailure(result, catalog, t, runtime), result.status !== "saved");
|
|
633
|
+
};
|
|
634
|
+
const editorProps = {
|
|
635
|
+
useCatalog,
|
|
636
|
+
useConfig,
|
|
637
|
+
useFixedCatalog,
|
|
638
|
+
platform,
|
|
639
|
+
runtime,
|
|
640
|
+
edit: persist,
|
|
641
|
+
recording,
|
|
642
|
+
describeBinding,
|
|
643
|
+
t,
|
|
644
|
+
onClose: closeEditor,
|
|
645
|
+
onSaved: () => {
|
|
646
|
+
notify(t("saved"));
|
|
647
|
+
closeEditor();
|
|
648
|
+
},
|
|
649
|
+
onError: (message) => {
|
|
650
|
+
notify(message, true);
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
(0, react.useLayoutEffect)(() => {
|
|
654
|
+
const input = search.current;
|
|
655
|
+
if (open && input !== null && !(0, _qilin_agent_client_ui_primitives.isBehindModal)(input)) (0, _qilin_agent_client_ui_primitives.focusWithoutRing)(input);
|
|
656
|
+
}, [open, focusRequest]);
|
|
657
|
+
const ranked = (0, _qilin_agent_client_ui_primitives.rankByName)([...catalog.map((row) => ({
|
|
658
|
+
...row,
|
|
659
|
+
names: [
|
|
660
|
+
...row.aliases,
|
|
661
|
+
row.keys.filter((key) => key !== "+").join("+"),
|
|
662
|
+
row.keys.filter((key) => key !== "+").join(""),
|
|
663
|
+
row.aria ?? "",
|
|
664
|
+
row.aria?.replace("Meta", "Cmd") ?? ""
|
|
665
|
+
],
|
|
666
|
+
group: "application"
|
|
667
|
+
})), ...fixedCatalog.map((row) => ({
|
|
668
|
+
...row,
|
|
669
|
+
names: [row.id, row.keys.join(" ")]
|
|
670
|
+
}))].sort((left, right) => Number(left.id === "response.stop") - Number(right.id === "response.stop") || (coreActionOrder.get(left.id) ?? coreActionOrder.size) - (coreActionOrder.get(right.id) ?? coreActionOrder.size) || Number(left.id > right.id) - Number(left.id < right.id)).flatMap((row) => row.names.map((name) => ({
|
|
671
|
+
name,
|
|
672
|
+
label: row.label,
|
|
673
|
+
row
|
|
674
|
+
}))), query.trim());
|
|
675
|
+
const matches = [...new Set(ranked.map((match) => match.row))];
|
|
676
|
+
const modifiedCount = Object.keys(config.document.profiles[`${runtime}:${platform}`] ?? {}).length;
|
|
677
|
+
(0, react.useLayoutEffect)(() => {
|
|
678
|
+
const input = search.current;
|
|
679
|
+
if (open && resetRevision === null && modifiedCount === 0 && document.activeElement === document.body && input !== null) (0, _qilin_agent_client_ui_primitives.focusWithoutRing)(input);
|
|
680
|
+
}, [
|
|
681
|
+
open,
|
|
682
|
+
resetRevision,
|
|
683
|
+
modifiedCount
|
|
684
|
+
]);
|
|
685
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
686
|
+
(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Modal, {
|
|
687
|
+
open,
|
|
688
|
+
onClose: closeReference,
|
|
689
|
+
title: t("title"),
|
|
690
|
+
headless: true,
|
|
691
|
+
shortcutModal: "shortcuts",
|
|
692
|
+
className: Reference_module_css_default.dialog,
|
|
693
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
694
|
+
className: Reference_module_css_default.contents,
|
|
695
|
+
onPointerDownCapture: (event) => {
|
|
696
|
+
if (target === null || busy || !(event.target instanceof Element) || event.target.closest("button, input, a, [contenteditable=\"true\"], [role=\"group\"]") !== null) return;
|
|
697
|
+
event.preventDefault();
|
|
698
|
+
closeEditor();
|
|
699
|
+
},
|
|
700
|
+
children: [
|
|
701
|
+
(0, react_jsx_runtime.jsxs)("header", {
|
|
702
|
+
className: Reference_module_css_default.header,
|
|
703
|
+
children: [(0, react_jsx_runtime.jsx)("h2", {
|
|
704
|
+
className: Reference_module_css_default.title,
|
|
705
|
+
children: t("title")
|
|
706
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
707
|
+
type: "button",
|
|
708
|
+
className: Reference_module_css_default.close,
|
|
709
|
+
"aria-label": t("close"),
|
|
710
|
+
disabled: busy,
|
|
711
|
+
onClick: closeReference,
|
|
712
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconCloseOutline16, { size: 14 })
|
|
713
|
+
})]
|
|
714
|
+
}),
|
|
715
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
716
|
+
className: Reference_module_css_default.searchRow,
|
|
717
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
718
|
+
className: Reference_module_css_default.searchField,
|
|
719
|
+
role: "search",
|
|
720
|
+
"aria-label": t("search"),
|
|
721
|
+
children: [
|
|
722
|
+
(0, react_jsx_runtime.jsxs)("svg", {
|
|
723
|
+
className: Reference_module_css_default.searchIcon,
|
|
724
|
+
width: "14",
|
|
725
|
+
height: "14",
|
|
726
|
+
viewBox: "0 0 14 14",
|
|
727
|
+
fill: "none",
|
|
728
|
+
"aria-hidden": "true",
|
|
729
|
+
children: [(0, react_jsx_runtime.jsx)("path", {
|
|
730
|
+
d: "M10.28 5.86536C10.28 3.41381 8.29245 1.42644 5.84094 1.42627C3.38929 1.42627 1.40186 3.4137 1.40186 5.86536C1.40203 8.31686 3.38939 10.3044 5.84094 10.3044C8.29234 10.3043 10.2799 8.31676 10.28 5.86536ZM11.4174 5.86536C11.4172 8.94498 8.92057 11.4416 5.84094 11.4418C2.76117 11.4418 0.263843 8.94509 0.263672 5.86536C0.263672 2.78548 2.76106 0.288086 5.84094 0.288086C8.92067 0.288258 11.4174 2.78559 11.4174 5.86536Z",
|
|
731
|
+
fill: "currentColor"
|
|
732
|
+
}), (0, react_jsx_runtime.jsx)("path", {
|
|
733
|
+
d: "M13.7372 12.9078L12.9323 13.7127L9.9732 10.7536L10.7781 9.94867L13.7372 12.9078Z",
|
|
734
|
+
fill: "currentColor"
|
|
735
|
+
})]
|
|
736
|
+
}),
|
|
737
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
738
|
+
ref: search,
|
|
739
|
+
"data-modal-autofocus": true,
|
|
740
|
+
className: Reference_module_css_default.search,
|
|
741
|
+
type: "search",
|
|
742
|
+
"aria-label": t("search"),
|
|
743
|
+
placeholder: t("search"),
|
|
744
|
+
value: query,
|
|
745
|
+
onChange: (event) => {
|
|
746
|
+
actions.search(event.target.value);
|
|
747
|
+
}
|
|
748
|
+
}),
|
|
749
|
+
query !== "" && (0, react_jsx_runtime.jsx)("button", {
|
|
750
|
+
type: "button",
|
|
751
|
+
className: Reference_module_css_default.clearSearch,
|
|
752
|
+
"aria-label": t("clear-search"),
|
|
753
|
+
onClick: () => {
|
|
754
|
+
actions.search("");
|
|
755
|
+
search.current?.focus();
|
|
756
|
+
},
|
|
757
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconCloseOutline16, { size: 10 })
|
|
758
|
+
})
|
|
759
|
+
]
|
|
760
|
+
})
|
|
761
|
+
}),
|
|
762
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
763
|
+
className: Reference_module_css_default.list,
|
|
764
|
+
"aria-busy": config.status === "loading",
|
|
765
|
+
children: [[
|
|
766
|
+
"application",
|
|
767
|
+
"input",
|
|
768
|
+
"menus",
|
|
769
|
+
"approval"
|
|
770
|
+
].map((group) => {
|
|
771
|
+
const rows = matches.filter((row) => row.group === group);
|
|
772
|
+
if (rows.length === 0) return null;
|
|
773
|
+
return (0, react_jsx_runtime.jsxs)("section", {
|
|
774
|
+
"aria-label": t(group),
|
|
775
|
+
children: [group !== "application" && (0, react_jsx_runtime.jsx)("h3", {
|
|
776
|
+
className: Reference_module_css_default.group,
|
|
777
|
+
children: t(group)
|
|
778
|
+
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
779
|
+
className: Reference_module_css_default.rows,
|
|
780
|
+
children: rows.map((row) => (0, react_jsx_runtime.jsxs)("li", {
|
|
781
|
+
className: Reference_module_css_default.row,
|
|
782
|
+
children: [
|
|
783
|
+
"modified" in row && target?.id !== row.id && (0, react_jsx_runtime.jsx)("button", {
|
|
784
|
+
type: "button",
|
|
785
|
+
className: Reference_module_css_default.rowButton,
|
|
786
|
+
"aria-label": t("edit-label", { command: row.label }),
|
|
787
|
+
disabled: busy || config.status !== "ready",
|
|
788
|
+
onClick: () => {
|
|
789
|
+
setTarget(row);
|
|
790
|
+
}
|
|
791
|
+
}),
|
|
792
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
793
|
+
className: Reference_module_css_default.commandLabel,
|
|
794
|
+
children: row.label
|
|
795
|
+
}),
|
|
796
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
797
|
+
className: Reference_module_css_default.binding,
|
|
798
|
+
children: "modified" in row ? target?.id === row.id ? (0, react_jsx_runtime.jsx)(ShortcutEditor, {
|
|
799
|
+
target: row,
|
|
800
|
+
...editorProps
|
|
801
|
+
}, row.id) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
|
|
802
|
+
className: Reference_module_css_default.rowActions,
|
|
803
|
+
children: (0, react_jsx_runtime.jsx)(ShortcutIcon, { kind: "edit" })
|
|
804
|
+
}), row.keys.length === 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
805
|
+
className: Reference_module_css_default.unbound,
|
|
806
|
+
children: t("unbound")
|
|
807
|
+
}) : (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.ShortcutKeys, {
|
|
808
|
+
keys: row.keys,
|
|
809
|
+
className: Reference_module_css_default.keyBadge
|
|
810
|
+
})] }) : (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.ShortcutKeys, {
|
|
811
|
+
keys: row.keys,
|
|
812
|
+
className: Reference_module_css_default.fixedKeyBadge
|
|
813
|
+
})
|
|
814
|
+
})
|
|
815
|
+
]
|
|
816
|
+
}, row.id))
|
|
817
|
+
})]
|
|
818
|
+
}, group);
|
|
819
|
+
}), matches.length === 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
820
|
+
className: Reference_module_css_default.hint,
|
|
821
|
+
role: "status",
|
|
822
|
+
children: t("empty")
|
|
823
|
+
})]
|
|
824
|
+
}),
|
|
825
|
+
(0, react_jsx_runtime.jsxs)("footer", {
|
|
826
|
+
className: Reference_module_css_default.footer,
|
|
827
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
828
|
+
type: "button",
|
|
829
|
+
className: Reference_module_css_default.resetAll,
|
|
830
|
+
disabled: busy || config.status !== "ready" || modifiedCount === 0,
|
|
831
|
+
onClick: (event) => {
|
|
832
|
+
event.currentTarget.focus();
|
|
833
|
+
setTarget(null);
|
|
834
|
+
setResetRevision(config.revision);
|
|
835
|
+
},
|
|
836
|
+
children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconRefreshOutline16, { size: 12 }), t("reset-all")]
|
|
837
|
+
}), modifiedCount > 0 && (0, react_jsx_runtime.jsx)("span", {
|
|
838
|
+
className: Reference_module_css_default.modifiedCount,
|
|
839
|
+
children: t("modified-count", { count: modifiedCount })
|
|
840
|
+
})]
|
|
841
|
+
})
|
|
842
|
+
]
|
|
843
|
+
})
|
|
844
|
+
}),
|
|
845
|
+
(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Modal, {
|
|
846
|
+
open: open && resetRevision !== null,
|
|
847
|
+
title: t("reset-title"),
|
|
848
|
+
description: t("reset-description"),
|
|
849
|
+
closeLabel: t("close-confirmation"),
|
|
850
|
+
onClose: () => {
|
|
851
|
+
if (!busy) setResetRevision(null);
|
|
852
|
+
},
|
|
853
|
+
footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Button, {
|
|
854
|
+
"data-modal-autofocus": true,
|
|
855
|
+
disabled: busy,
|
|
856
|
+
onClick: () => {
|
|
857
|
+
setResetRevision(null);
|
|
858
|
+
},
|
|
859
|
+
children: t("cancel")
|
|
860
|
+
}), (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Button, {
|
|
861
|
+
variant: "primary",
|
|
862
|
+
disabled: busy || config.status !== "ready",
|
|
863
|
+
onClick: () => {
|
|
864
|
+
resetAll();
|
|
865
|
+
},
|
|
866
|
+
children: t("reset")
|
|
867
|
+
})] })
|
|
868
|
+
}),
|
|
869
|
+
toast !== null && (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Toast, {
|
|
870
|
+
text: toast.text,
|
|
871
|
+
onDone: dismissToast,
|
|
872
|
+
icon: (0, react_jsx_runtime.jsx)(ShortcutIcon, {
|
|
873
|
+
kind: toast.error ? "error" : "success",
|
|
874
|
+
className: toast.error ? Reference_module_css_default.toastError : Reference_module_css_default.toastSuccess
|
|
875
|
+
})
|
|
876
|
+
}, toast.seq)
|
|
877
|
+
] });
|
|
878
|
+
}
|
|
879
|
+
//#endregion
|
|
880
|
+
//#region lib/types/client/locales.js
|
|
881
|
+
/** Shortcut reference copy; only implemented operations appear in the catalog. */
|
|
882
|
+
const zh = {
|
|
883
|
+
"edit-label": "修改{command}快捷键",
|
|
884
|
+
record: "按下快捷键",
|
|
885
|
+
"record-help": "松开组合键即保存。Tab 切换操作,Esc 退出录键。",
|
|
886
|
+
"web-help": "浏览器可用组合:Mod+/、Mod+Shift+,、Mod+Shift+.。Mod 在 Mac 上为 Command,其他系统为 Ctrl。",
|
|
887
|
+
"unsupported-key": "暂不支持这个按键。",
|
|
888
|
+
reserved: "此组合由系统或文本编辑操作保留。",
|
|
889
|
+
"modifier-required": "请同时按下 Command、Ctrl 或 Alt 修饰键。",
|
|
890
|
+
"too-many-keys": "最多同时按下两个非修饰键。请松开后重试。",
|
|
891
|
+
"macos-web-help": "可设置 Command+/、Command+,、Command+反斜杠、Control+反引号、Command+Option+按键或 Command+Shift+按键。也支持三个或四个不同修饰键的组合。浏览器或系统占用的组合可能无法送达页面。",
|
|
892
|
+
"windows-web-help": "可设置 Ctrl+/、Ctrl+,、Ctrl+Alt+按键或 Ctrl+Shift+按键。也支持三个或四个不同修饰键的组合。浏览器或系统占用的组合可能无法送达页面。",
|
|
893
|
+
"unsupported-browser": "此浏览器暂不支持该组合。",
|
|
894
|
+
conflict: "已被「{commands}」占用",
|
|
895
|
+
saved: "已修改",
|
|
896
|
+
clear: "移除",
|
|
897
|
+
"retry-save": "重试保存",
|
|
898
|
+
reset: "恢复默认",
|
|
899
|
+
"reset-all": "恢复全部默认",
|
|
900
|
+
"modified-count": "{count} 项已自定义",
|
|
901
|
+
"reset-title": "恢复全部默认快捷键?",
|
|
902
|
+
"reset-description": "将恢复当前平台的默认快捷键。你修改或移除的快捷键都会恢复,其他平台不受影响。",
|
|
903
|
+
cancel: "取消",
|
|
904
|
+
"reset-saved": "已恢复默认快捷键",
|
|
905
|
+
"close-confirmation": "关闭确认",
|
|
906
|
+
"reset-failed": "恢复默认失败。原快捷键已保留,请重试。",
|
|
907
|
+
review: "已核对最新配置",
|
|
908
|
+
stale: "快捷键配置或可用命令已更新。请核对最新键位后再保存。",
|
|
909
|
+
"write-failed": "保存失败。原快捷键和当前草稿已保留,请重试。",
|
|
910
|
+
"not-ready": "快捷键尚未准备好,请稍后重试。",
|
|
911
|
+
read: "无法读取 {location}。请检查访问权限后{reload}。",
|
|
912
|
+
invalid: "{location} 的快捷键配置内容损坏。请先备份并修复该配置,然后{reload}。",
|
|
913
|
+
future: "{location} 的快捷键配置由更新版本创建。请升级 QiLin 后重试。",
|
|
914
|
+
"web-document": "当前网站本地存储中的 qilin.keybindings.v1",
|
|
915
|
+
"desktop-document": "userData/keybindings.json",
|
|
916
|
+
"web-reload": "刷新页面",
|
|
917
|
+
"desktop-reload": "重新启动 QiLin",
|
|
918
|
+
"using-defaults": "当前使用默认键位。",
|
|
919
|
+
"using-accepted": "当前继续使用上次读取成功的键位。",
|
|
920
|
+
"native-failed": "无法启用桌面录键保护,请关闭后重试。",
|
|
921
|
+
"global-hint": "全局唤起查看",
|
|
922
|
+
"clear-search": "清空搜索",
|
|
923
|
+
title: "快捷键",
|
|
924
|
+
open: "快捷键速查",
|
|
925
|
+
settings: "快捷键",
|
|
926
|
+
view: "编辑快捷键",
|
|
927
|
+
description: "查看和编辑当前可用的快捷键和输入操作",
|
|
928
|
+
search: "搜索快捷键",
|
|
929
|
+
close: "关闭快捷键",
|
|
930
|
+
application: "应用操作",
|
|
931
|
+
input: "消息输入",
|
|
932
|
+
menus: "菜单与弹层",
|
|
933
|
+
approval: "审批区域",
|
|
934
|
+
unbound: "暂无快捷键",
|
|
935
|
+
empty: "没有匹配的快捷键",
|
|
936
|
+
move: "移动菜单选择",
|
|
937
|
+
select: "选择菜单项",
|
|
938
|
+
dismiss: "关闭菜单或顶层弹窗"
|
|
939
|
+
};
|
|
940
|
+
/** Typed English counterpart. */
|
|
941
|
+
const en = {
|
|
942
|
+
"edit-label": "Edit shortcut for {command}",
|
|
943
|
+
record: "Press a shortcut",
|
|
944
|
+
"record-help": "Release the keys to save. Tab moves between actions; Esc cancels.",
|
|
945
|
+
"web-help": "Browser combinations: Mod+/, Mod+Shift+,, Mod+Shift+.. Mod is Command on Mac and Ctrl elsewhere.",
|
|
946
|
+
"unsupported-key": "This key is not supported.",
|
|
947
|
+
reserved: "This combination is reserved for system or text editing actions.",
|
|
948
|
+
"modifier-required": "Include Command, Ctrl, or Alt in the combination.",
|
|
949
|
+
"too-many-keys": "Hold at most two non-modifier keys. Release the keys to try again.",
|
|
950
|
+
"macos-web-help": "Use Command+/, Command+,, Command+Backslash, Control+Backquote, Command+Option+key, or Command+Shift+key. Combinations with three or four distinct modifiers are also supported. Browser or system shortcuts may not reach the page.",
|
|
951
|
+
"windows-web-help": "Use Ctrl+/, Ctrl+,, Ctrl+Alt+key, or Ctrl+Shift+key. Combinations with three or four distinct modifiers are also supported. Browser or system shortcuts may not reach the page.",
|
|
952
|
+
"unsupported-browser": "This browser does not support this combination yet.",
|
|
953
|
+
conflict: "Already used by “{commands}”",
|
|
954
|
+
saved: "Modified",
|
|
955
|
+
clear: "Remove",
|
|
956
|
+
"retry-save": "Retry save",
|
|
957
|
+
reset: "Restore default",
|
|
958
|
+
"reset-all": "Restore all defaults",
|
|
959
|
+
"modified-count": "{count} customized",
|
|
960
|
+
"reset-title": "Restore all default shortcuts?",
|
|
961
|
+
"reset-description": "Restore the default shortcuts for this platform. All modified or removed shortcuts will be restored. Other platforms are unaffected.",
|
|
962
|
+
cancel: "Cancel",
|
|
963
|
+
"reset-saved": "Default shortcuts restored",
|
|
964
|
+
"close-confirmation": "Close confirmation",
|
|
965
|
+
"reset-failed": "Could not restore defaults. Your shortcuts are unchanged. Please retry.",
|
|
966
|
+
review: "I have reviewed the latest configuration",
|
|
967
|
+
stale: "Shortcut configuration or available commands changed. Review the latest bindings before saving.",
|
|
968
|
+
"write-failed": "Could not save. Your previous shortcuts and current draft are preserved. Please retry.",
|
|
969
|
+
"not-ready": "Shortcuts are not ready. Please try again.",
|
|
970
|
+
read: "Could not read {location}. Check access permissions, then {reload}.",
|
|
971
|
+
invalid: "Shortcut configuration in {location} is damaged. Back up and repair this configuration, then {reload}.",
|
|
972
|
+
future: "Shortcut configuration in {location} was created by a newer version. Upgrade QiLin and try again.",
|
|
973
|
+
"web-document": "this site’s localStorage entry qilin.keybindings.v1",
|
|
974
|
+
"desktop-document": "userData/keybindings.json",
|
|
975
|
+
"web-reload": "reload the page",
|
|
976
|
+
"desktop-reload": "restart QiLin",
|
|
977
|
+
"using-defaults": "Default bindings are active.",
|
|
978
|
+
"using-accepted": "The last successfully read bindings remain active.",
|
|
979
|
+
"native-failed": "Could not protect desktop key recording. Exit recording and try again.",
|
|
980
|
+
"global-hint": "Open from anywhere",
|
|
981
|
+
"clear-search": "Clear search",
|
|
982
|
+
title: "Keyboard shortcuts",
|
|
983
|
+
open: "Open keyboard shortcuts",
|
|
984
|
+
settings: "Keyboard shortcuts",
|
|
985
|
+
view: "Edit shortcuts",
|
|
986
|
+
description: "View and edit available shortcuts and input actions",
|
|
987
|
+
search: "Search shortcuts",
|
|
988
|
+
close: "Close keyboard shortcuts",
|
|
989
|
+
application: "Application",
|
|
990
|
+
input: "Message input",
|
|
991
|
+
menus: "Menus and dialogs",
|
|
992
|
+
approval: "Approval area",
|
|
993
|
+
unbound: "No shortcut",
|
|
994
|
+
empty: "No matching shortcuts",
|
|
995
|
+
move: "Move menu selection",
|
|
996
|
+
select: "Select menu item",
|
|
997
|
+
dismiss: "Close menu or top dialog"
|
|
998
|
+
};
|
|
999
|
+
//#endregion
|
|
1000
|
+
//#region lib/types/client/fixed.js
|
|
1001
|
+
/**
|
|
1002
|
+
* Describe shared menu actions for display and conflict checking.
|
|
1003
|
+
* @param t - shortcut dictionary.
|
|
1004
|
+
* @returns read-only actions and each physical combination they occupy.
|
|
1005
|
+
*/
|
|
1006
|
+
function fixedCommands(t) {
|
|
1007
|
+
return [
|
|
1008
|
+
{
|
|
1009
|
+
id: "move",
|
|
1010
|
+
keys: ["↑", "↓"],
|
|
1011
|
+
bindings: [{
|
|
1012
|
+
code: "ArrowUp",
|
|
1013
|
+
modifiers: []
|
|
1014
|
+
}, {
|
|
1015
|
+
code: "ArrowDown",
|
|
1016
|
+
modifiers: []
|
|
1017
|
+
}],
|
|
1018
|
+
group: "menus"
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
id: "select",
|
|
1022
|
+
keys: ["Enter"],
|
|
1023
|
+
bindings: [{
|
|
1024
|
+
code: "Enter",
|
|
1025
|
+
modifiers: []
|
|
1026
|
+
}],
|
|
1027
|
+
group: "menus"
|
|
1028
|
+
},
|
|
1029
|
+
{
|
|
1030
|
+
id: "dismiss",
|
|
1031
|
+
keys: ["Esc"],
|
|
1032
|
+
bindings: [{
|
|
1033
|
+
code: "Escape",
|
|
1034
|
+
modifiers: []
|
|
1035
|
+
}],
|
|
1036
|
+
group: "menus"
|
|
1037
|
+
}
|
|
1038
|
+
].map((row) => ({
|
|
1039
|
+
...row,
|
|
1040
|
+
id: `fixed.${row.id}`,
|
|
1041
|
+
label: () => t(row.id)
|
|
1042
|
+
}));
|
|
1043
|
+
}
|
|
1044
|
+
//#endregion
|
|
1045
|
+
//#region lib/types/client/index.js
|
|
1046
|
+
/** Required command, locale, and slot services. */
|
|
1047
|
+
const inject = [
|
|
1048
|
+
"shortcuts",
|
|
1049
|
+
"locale",
|
|
1050
|
+
"slots"
|
|
1051
|
+
];
|
|
1052
|
+
/**
|
|
1053
|
+
* Register the reference command, settings row, and single shell overlay.
|
|
1054
|
+
* @param ctx - plugin-owned client context.
|
|
1055
|
+
*/
|
|
1056
|
+
function apply(ctx) {
|
|
1057
|
+
ctx.effect(() => ctx.locale.register("shortcuts", {
|
|
1058
|
+
zh,
|
|
1059
|
+
en
|
|
1060
|
+
}), "shortcuts: dictionaries");
|
|
1061
|
+
const t = ctx.locale.bind("shortcuts");
|
|
1062
|
+
const handle = createShortcutsStore();
|
|
1063
|
+
const instance = handle.create();
|
|
1064
|
+
const store = {
|
|
1065
|
+
...handle,
|
|
1066
|
+
create: () => instance
|
|
1067
|
+
};
|
|
1068
|
+
const edit = (...args) => ctx.shortcuts.edit(...args);
|
|
1069
|
+
const recording = (active) => ctx.shortcuts.recording(active);
|
|
1070
|
+
const describeBinding = (binding) => ctx.shortcuts.describeBinding(binding);
|
|
1071
|
+
for (const command of fixedCommands(t)) ctx.effect(() => ctx.shortcuts.registerFixed(command), `shortcuts: ${command.id}`);
|
|
1072
|
+
const injected = () => ({
|
|
1073
|
+
platform: ctx.shortcuts.platform,
|
|
1074
|
+
runtime: ctx.shortcuts.runtime,
|
|
1075
|
+
edit,
|
|
1076
|
+
recording,
|
|
1077
|
+
describeBinding,
|
|
1078
|
+
hooks: {
|
|
1079
|
+
catalog: ctx.shortcuts.catalog,
|
|
1080
|
+
config: ctx.shortcuts.config,
|
|
1081
|
+
fixedCatalog: ctx.shortcuts.fixedCatalog
|
|
1082
|
+
}
|
|
1083
|
+
});
|
|
1084
|
+
ctx.slots.inject("settings.general.item", () => ctx.slots.register({
|
|
1085
|
+
name: "settings.general.item",
|
|
1086
|
+
id: "shortcuts",
|
|
1087
|
+
order: 20,
|
|
1088
|
+
locale: "shortcuts",
|
|
1089
|
+
store,
|
|
1090
|
+
inject: injected
|
|
1091
|
+
}, ShortcutsRow));
|
|
1092
|
+
ctx.slots.inject("shell.overlay", () => {
|
|
1093
|
+
const disposeCommand = ctx.shortcuts.register({
|
|
1094
|
+
id: "shortcuts.open",
|
|
1095
|
+
label: () => t("open"),
|
|
1096
|
+
aliases: ["shortcuts", "keyboard shortcuts"],
|
|
1097
|
+
defaults: {
|
|
1098
|
+
"desktop:macos": {
|
|
1099
|
+
code: "Slash",
|
|
1100
|
+
modifiers: ["primary"]
|
|
1101
|
+
},
|
|
1102
|
+
"desktop:windows": {
|
|
1103
|
+
code: "Slash",
|
|
1104
|
+
modifiers: ["primary"]
|
|
1105
|
+
},
|
|
1106
|
+
"desktop:linux": {
|
|
1107
|
+
code: "Slash",
|
|
1108
|
+
modifiers: ["primary"]
|
|
1109
|
+
},
|
|
1110
|
+
"web:macos": {
|
|
1111
|
+
code: "Slash",
|
|
1112
|
+
modifiers: ["primary"]
|
|
1113
|
+
},
|
|
1114
|
+
"web:windows": {
|
|
1115
|
+
code: "Slash",
|
|
1116
|
+
modifiers: ["primary"]
|
|
1117
|
+
},
|
|
1118
|
+
"web:linux": {
|
|
1119
|
+
code: "Slash",
|
|
1120
|
+
modifiers: ["primary"]
|
|
1121
|
+
}
|
|
1122
|
+
},
|
|
1123
|
+
regions: [
|
|
1124
|
+
"page",
|
|
1125
|
+
"editable",
|
|
1126
|
+
"terminal"
|
|
1127
|
+
],
|
|
1128
|
+
modals: ["settings", "shortcuts"],
|
|
1129
|
+
resolve: ({ modal }) => {
|
|
1130
|
+
if (modal !== null && modal !== "settings" && modal !== "shortcuts") return {
|
|
1131
|
+
status: "blocked",
|
|
1132
|
+
reason: "modal"
|
|
1133
|
+
};
|
|
1134
|
+
return {
|
|
1135
|
+
status: "handled",
|
|
1136
|
+
run: () => {
|
|
1137
|
+
if (modal === "shortcuts") (0, _qilin_agent_client_ui_primitives.closeTopModal)(document);
|
|
1138
|
+
else instance.actions.open();
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
});
|
|
1143
|
+
const disposeSlot = ctx.slots.register({
|
|
1144
|
+
name: "shell.overlay",
|
|
1145
|
+
id: "shortcuts",
|
|
1146
|
+
locale: "shortcuts",
|
|
1147
|
+
store,
|
|
1148
|
+
inject: injected
|
|
1149
|
+
}, ShortcutReference);
|
|
1150
|
+
return () => {
|
|
1151
|
+
disposeCommand();
|
|
1152
|
+
disposeSlot();
|
|
1153
|
+
};
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
//#endregion
|
|
1157
|
+
exports.apply = apply;
|
|
1158
|
+
exports.inject = inject;
|
|
1159
|
+
return module.exports;
|
|
1160
|
+
}
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
//# sourceMappingURL=client.js.map
|