Skip to content

Commit 1ded5d4

Browse files
committed
ENG-1438: Port Keyboard shortcut keys/triggers settings
1 parent 1e3c7ee commit 1ded5d4

File tree

6 files changed

+48
-74
lines changed

6 files changed

+48
-74
lines changed

apps/roam/src/components/DiscourseNodeMenu.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { getNewDiscourseNodeText } from "~/utils/formatUtils";
2727
import { OnloadArgs } from "roamjs-components/types";
2828
import { formatHexColor } from "./settings/DiscourseNodeCanvasSettings";
2929
import posthog from "posthog-js";
30+
import { setPersonalSetting } from "~/components/settings/utils/accessors";
3031

3132
type Props = {
3233
textarea?: HTMLTextAreaElement;
@@ -406,6 +407,13 @@ export const getModifiersFromCombo = (comboKey: IKeyCombo) => {
406407
].filter(Boolean);
407408
};
408409

410+
export const comboToString = (combo: IKeyCombo): string => {
411+
if (!combo.key) return "";
412+
const modifiers = getModifiersFromCombo(combo);
413+
const comboString = [...modifiers, combo.key].join("+");
414+
return normalizeKeyCombo(comboString).join("+");
415+
};
416+
409417
export const NodeMenuTriggerComponent = ({
410418
extensionAPI,
411419
}: {
@@ -427,19 +435,15 @@ export const NodeMenuTriggerComponent = ({
427435
const comboObj = getKeyCombo(e.nativeEvent);
428436
if (!comboObj.key) return;
429437

430-
setComboKey({ key: comboObj.key, modifiers: comboObj.modifiers });
431-
extensionAPI.settings.set("personal-node-menu-trigger", comboObj);
438+
const combo = { key: comboObj.key, modifiers: comboObj.modifiers };
439+
setComboKey(combo);
440+
void extensionAPI.settings.set("personal-node-menu-trigger", combo);
441+
setPersonalSetting(["Personal node menu trigger"], combo);
432442
},
433443
[extensionAPI],
434444
);
435445

436-
const shortcut = useMemo(() => {
437-
if (!comboKey.key) return "";
438-
439-
const modifiers = getModifiersFromCombo(comboKey);
440-
const comboString = [...modifiers, comboKey.key].join("+");
441-
return normalizeKeyCombo(comboString).join("+");
442-
}, [comboKey]);
446+
const shortcut = useMemo(() => comboToString(comboKey), [comboKey]);
443447

444448
return (
445449
<InputGroup
@@ -455,7 +459,8 @@ export const NodeMenuTriggerComponent = ({
455459
icon={"remove"}
456460
onClick={() => {
457461
setComboKey({ modifiers: 0, key: "" });
458-
extensionAPI.settings.set("personal-node-menu-trigger", "");
462+
void extensionAPI.settings.set("personal-node-menu-trigger", "");
463+
setPersonalSetting(["Personal node menu trigger"], "");
459464
}}
460465
minimal
461466
/>

apps/roam/src/components/DiscourseNodeSearchMenu.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import getDiscourseNodeFormatExpression from "~/utils/getDiscourseNodeFormatExpr
2626
import { Result } from "~/utils/types";
2727
import { getSetting } from "~/utils/extensionSettings";
2828
import MiniSearch from "minisearch";
29+
import { setPersonalSetting } from "~/components/settings/utils/accessors";
2930

3031
type Props = {
3132
textarea: HTMLTextAreaElement;
@@ -724,7 +725,8 @@ export const NodeSearchMenuTriggerSetting = ({
724725
.trim();
725726

726727
setNodeSearchTrigger(trigger);
727-
extensionAPI.settings.set("node-search-trigger", trigger);
728+
void extensionAPI.settings.set("node-search-trigger", trigger);
729+
setPersonalSetting(["Node search menu trigger"], trigger);
728730
};
729731
return (
730732
<InputGroup

apps/roam/src/components/settings/HomePersonalSettings.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const HomePersonalSettings = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
5858
<KeyboardShortcutInput
5959
onloadArgs={onloadArgs}
6060
settingKey={DISCOURSE_TOOL_SHORTCUT_KEY}
61+
blockPropKey="Discourse tool shortcut"
6162
label="Discourse tool keyboard shortcut"
6263
description="Set a single key to activate the discourse tool in tldraw. Only single keys (no modifiers) are supported. Leave empty for no shortcut."
6364
placeholder="Click to set single key"

apps/roam/src/components/settings/KeyboardShortcutInput.tsx

Lines changed: 16 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,62 +9,22 @@ import {
99
} from "@blueprintjs/core";
1010
import Description from "roamjs-components/components/Description";
1111
import { DISCOURSE_TOOL_SHORTCUT_KEY } from "~/data/userSettings";
12+
import { setPersonalSetting } from "~/components/settings/utils/accessors";
13+
import { comboToString } from "~/components/DiscourseNodeMenu";
1214

1315
type KeyboardShortcutInputProps = {
1416
onloadArgs: OnloadArgs;
1517
settingKey: string;
18+
blockPropKey: string;
1619
label: string;
1720
description: string;
1821
placeholder?: string;
1922
};
2023

21-
// Reuse the keyboard combo utilities from NodeMenuTriggerComponent
22-
const isMac = () => {
23-
const platform =
24-
typeof navigator !== "undefined" ? navigator.platform : undefined;
25-
return platform == null ? false : /Mac|iPod|iPhone|iPad/.test(platform);
26-
};
27-
28-
const MODIFIER_BIT_MASKS = {
29-
alt: 1,
30-
ctrl: 2,
31-
meta: 4,
32-
shift: 8,
33-
};
34-
35-
const ALIASES: { [key: string]: string } = {
36-
cmd: "meta",
37-
command: "meta",
38-
escape: "esc",
39-
minus: "-",
40-
mod: isMac() ? "meta" : "ctrl",
41-
option: "alt",
42-
plus: "+",
43-
return: "enter",
44-
win: "meta",
45-
};
46-
47-
const normalizeKeyCombo = (combo: string) => {
48-
const keys = combo.replace(/\s/g, "").split("+");
49-
return keys.map((key) => {
50-
const keyName = ALIASES[key] != null ? ALIASES[key] : key;
51-
return keyName === "meta" ? (isMac() ? "cmd" : "win") : keyName;
52-
});
53-
};
54-
55-
const getModifiersFromCombo = (comboKey: IKeyCombo) => {
56-
if (!comboKey) return [];
57-
return [
58-
comboKey.modifiers & MODIFIER_BIT_MASKS.alt && "alt",
59-
comboKey.modifiers & MODIFIER_BIT_MASKS.ctrl && "ctrl",
60-
comboKey.modifiers & MODIFIER_BIT_MASKS.shift && "shift",
61-
comboKey.modifiers & MODIFIER_BIT_MASKS.meta && "meta",
62-
].filter(Boolean);
63-
};
64-
6524
const KeyboardShortcutInput = ({
6625
onloadArgs,
6726
settingKey,
27+
blockPropKey,
6828
label,
6929
description,
7030
placeholder = "Click to set shortcut",
@@ -104,6 +64,7 @@ const KeyboardShortcutInput = ({
10464
extensionAPI.settings
10565
.set(settingKey, comboObj)
10666
.catch(() => console.error("Failed to set setting"));
67+
setPersonalSetting([blockPropKey], comboObj);
10768
}
10869
return;
10970
}
@@ -112,28 +73,26 @@ const KeyboardShortcutInput = ({
11273
const comboObj = getKeyCombo(e.nativeEvent);
11374
if (!comboObj.key) return;
11475

115-
setComboKey({ key: comboObj.key, modifiers: comboObj.modifiers });
76+
const combo = { key: comboObj.key, modifiers: comboObj.modifiers };
77+
setComboKey(combo);
11678
extensionAPI.settings
117-
.set(settingKey, comboObj)
79+
.set(settingKey, combo)
11880
.catch(() => console.error("Failed to set setting"));
81+
setPersonalSetting([blockPropKey], combo);
11982
},
120-
[extensionAPI, settingKey],
83+
[extensionAPI, settingKey, blockPropKey],
12184
);
12285

123-
const shortcut = useMemo(() => {
124-
if (!comboKey.key) return "";
125-
126-
const modifiers = getModifiersFromCombo(comboKey);
127-
const comboString = [...modifiers, comboKey.key].join("+");
128-
return normalizeKeyCombo(comboString).join("+");
129-
}, [comboKey]);
86+
const shortcut = useMemo(() => comboToString(comboKey), [comboKey]);
13087

13188
const handleClear = useCallback(() => {
132-
setComboKey({ modifiers: 0, key: "" });
89+
const clearedCombo = { modifiers: 0, key: "" };
90+
setComboKey(clearedCombo);
13391
extensionAPI.settings
134-
.set(settingKey, { modifiers: 0, key: "" })
92+
.set(settingKey, clearedCombo)
13593
.catch(() => console.error("Failed to set setting"));
136-
}, [extensionAPI, settingKey]);
94+
setPersonalSetting([blockPropKey], clearedCombo);
95+
}, [extensionAPI, settingKey, blockPropKey]);
13796

13897
return (
13998
<Label>

apps/roam/src/components/settings/utils/zodSchema.example.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -355,9 +355,9 @@ const personalSettings: PersonalSettings = {
355355
},
356356
},
357357
},
358-
"Personal node menu trigger": ";;",
358+
"Personal node menu trigger": { modifiers: 0, key: ";;" },
359359
"Node search menu trigger": "//",
360-
"Discourse tool shortcut": "d",
360+
"Discourse tool shortcut": { modifiers: 0, key: "d" },
361361
"Discourse context overlay": true,
362362
"Suggestive mode overlay": true,
363363
"Overlay in canvas": false,
@@ -383,9 +383,9 @@ const personalSettings: PersonalSettings = {
383383

384384
const defaultPersonalSettings: PersonalSettings = {
385385
"Left sidebar": {},
386-
"Personal node menu trigger": "",
386+
"Personal node menu trigger": { modifiers: 0, key: "" },
387387
"Node search menu trigger": "",
388-
"Discourse tool shortcut": "",
388+
"Discourse tool shortcut": { modifiers: 0, key: "" },
389389
"Discourse context overlay": false,
390390
"Suggestive mode overlay": false,
391391
"Overlay in canvas": false,

apps/roam/src/components/settings/utils/zodSchema.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,16 @@ export const QuerySettingsSchema = z.object({
236236

237237
export const PersonalSettingsSchema = z.object({
238238
"Left sidebar": LeftSidebarPersonalSettingsSchema,
239-
"Personal node menu trigger": z.string().default(""),
239+
"Personal node menu trigger": z
240+
.union([
241+
z.object({ modifiers: z.number(), key: z.string() }),
242+
z.literal(""),
243+
])
244+
.default({ modifiers: 0, key: "" }),
240245
"Node search menu trigger": z.string().default("@"),
241-
"Discourse tool shortcut": z.string().default(""),
246+
"Discourse tool shortcut": z
247+
.object({ modifiers: z.number(), key: z.string() })
248+
.default({ modifiers: 0, key: "" }),
242249
"Discourse context overlay": z.boolean().default(false),
243250
"Suggestive mode overlay": z.boolean().default(false),
244251
"Overlay in canvas": z.boolean().default(false),

0 commit comments

Comments
 (0)