Update send/bring shortcuts and show them properly per operating… (#784)
* Show proper shortcuts * sort * Add shortcuts to bring/send * fix hotkeys matching greedily * Space * align zindex shortcuts with figma * switch to event.code & change Darwin shortcuts Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
parent
f9edb1b4ac
commit
9de3716324
@ -6,6 +6,7 @@ import { ToolButton } from "../components/ToolButton";
|
|||||||
import { t } from "../i18n";
|
import { t } from "../i18n";
|
||||||
import { getNormalizedZoom } from "../scene";
|
import { getNormalizedZoom } from "../scene";
|
||||||
import { KEYS } from "../keys";
|
import { KEYS } from "../keys";
|
||||||
|
import { getShortcutKey } from "../utils";
|
||||||
import useIsMobile from "../is-mobile";
|
import useIsMobile from "../is-mobile";
|
||||||
import { register } from "./register";
|
import { register } from "./register";
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ export const actionZoomIn = register({
|
|||||||
<ToolButton
|
<ToolButton
|
||||||
type="button"
|
type="button"
|
||||||
icon={zoomIn}
|
icon={zoomIn}
|
||||||
title={t("buttons.zoomIn")}
|
title={`${t("buttons.zoomIn")} ${getShortcutKey("CtrlOrCmd++")}`}
|
||||||
aria-label={t("buttons.zoomIn")}
|
aria-label={t("buttons.zoomIn")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
updateData(null);
|
updateData(null);
|
||||||
@ -92,7 +93,7 @@ export const actionZoomIn = register({
|
|||||||
),
|
),
|
||||||
keyTest: event =>
|
keyTest: event =>
|
||||||
(event.code === KEY_CODES.EQUAL || event.code === KEY_CODES.NUM_ADD) &&
|
(event.code === KEY_CODES.EQUAL || event.code === KEY_CODES.NUM_ADD) &&
|
||||||
(event[KEYS.META] || event.shiftKey),
|
(event[KEYS.CTRL_OR_CMD] || event.shiftKey),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const actionZoomOut = register({
|
export const actionZoomOut = register({
|
||||||
@ -109,7 +110,7 @@ export const actionZoomOut = register({
|
|||||||
<ToolButton
|
<ToolButton
|
||||||
type="button"
|
type="button"
|
||||||
icon={zoomOut}
|
icon={zoomOut}
|
||||||
title={t("buttons.zoomOut")}
|
title={`${t("buttons.zoomOut")} ${getShortcutKey("CtrlOrCmd+-")}`}
|
||||||
aria-label={t("buttons.zoomOut")}
|
aria-label={t("buttons.zoomOut")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
updateData(null);
|
updateData(null);
|
||||||
@ -118,7 +119,7 @@ export const actionZoomOut = register({
|
|||||||
),
|
),
|
||||||
keyTest: event =>
|
keyTest: event =>
|
||||||
(event.code === KEY_CODES.MINUS || event.code === KEY_CODES.NUM_SUBTRACT) &&
|
(event.code === KEY_CODES.MINUS || event.code === KEY_CODES.NUM_SUBTRACT) &&
|
||||||
(event[KEYS.META] || event.shiftKey),
|
(event[KEYS.CTRL_OR_CMD] || event.shiftKey),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const actionResetZoom = register({
|
export const actionResetZoom = register({
|
||||||
@ -144,5 +145,5 @@ export const actionResetZoom = register({
|
|||||||
),
|
),
|
||||||
keyTest: event =>
|
keyTest: event =>
|
||||||
(event.code === KEY_CODES.ZERO || event.code === KEY_CODES.NUM_ZERO) &&
|
(event.code === KEY_CODES.ZERO || event.code === KEY_CODES.NUM_ZERO) &&
|
||||||
(event[KEYS.META] || event.shiftKey),
|
(event[KEYS.CTRL_OR_CMD] || event.shiftKey),
|
||||||
});
|
});
|
||||||
|
@ -31,7 +31,7 @@ const writeData = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
const testUndo = (shift: boolean) => (event: KeyboardEvent) =>
|
const testUndo = (shift: boolean) => (event: KeyboardEvent) =>
|
||||||
event[KEYS.META] && /z/i.test(event.key) && event.shiftKey === shift;
|
event[KEYS.CTRL_OR_CMD] && /z/i.test(event.key) && event.shiftKey === shift;
|
||||||
|
|
||||||
type ActionCreator = (history: SceneHistory) => Action;
|
type ActionCreator = (history: SceneHistory) => Action;
|
||||||
|
|
||||||
|
@ -14,5 +14,5 @@ export const actionSelectAll = register({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
contextItemLabel: "labels.selectAll",
|
contextItemLabel: "labels.selectAll",
|
||||||
keyTest: event => event[KEYS.META] && event.key === "a",
|
keyTest: event => event[KEYS.CTRL_OR_CMD] && event.key === "a",
|
||||||
});
|
});
|
||||||
|
@ -19,7 +19,8 @@ export const actionCopyStyles = register({
|
|||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
contextItemLabel: "labels.copyStyles",
|
contextItemLabel: "labels.copyStyles",
|
||||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.key === "C",
|
keyTest: event =>
|
||||||
|
event[KEYS.CTRL_OR_CMD] && event.shiftKey && event.key === "C",
|
||||||
contextMenuOrder: 0,
|
contextMenuOrder: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -54,6 +55,7 @@ export const actionPasteStyles = register({
|
|||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
commitToHistory: () => true,
|
||||||
contextItemLabel: "labels.pasteStyles",
|
contextItemLabel: "labels.pasteStyles",
|
||||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.key === "V",
|
keyTest: event =>
|
||||||
|
event[KEYS.CTRL_OR_CMD] && event.shiftKey && event.key === "V",
|
||||||
contextMenuOrder: 1,
|
contextMenuOrder: 1,
|
||||||
});
|
});
|
||||||
|
@ -6,8 +6,9 @@ import {
|
|||||||
moveAllRight,
|
moveAllRight,
|
||||||
} from "../zindex";
|
} from "../zindex";
|
||||||
import { getSelectedIndices } from "../scene";
|
import { getSelectedIndices } from "../scene";
|
||||||
import { KEYS } from "../keys";
|
import { KEYS, isDarwin } from "../keys";
|
||||||
import { t } from "../i18n";
|
import { t } from "../i18n";
|
||||||
|
import { getShortcutKey } from "../utils";
|
||||||
import { register } from "./register";
|
import { register } from "./register";
|
||||||
import {
|
import {
|
||||||
sendBackward,
|
sendBackward,
|
||||||
@ -30,13 +31,14 @@ export const actionSendBackward = register({
|
|||||||
contextItemLabel: "labels.sendBackward",
|
contextItemLabel: "labels.sendBackward",
|
||||||
keyPriority: 40,
|
keyPriority: 40,
|
||||||
commitToHistory: () => true,
|
commitToHistory: () => true,
|
||||||
keyTest: event => event[KEYS.META] && event.altKey && event.key === "B",
|
keyTest: event =>
|
||||||
|
event[KEYS.CTRL_OR_CMD] && !event.shiftKey && event.code === "BracketLeft",
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="zIndexButton"
|
className="zIndexButton"
|
||||||
onClick={() => updateData(null)}
|
onClick={() => updateData(null)}
|
||||||
title={t("labels.sendBackward")}
|
title={`${t("labels.sendBackward")} ${getShortcutKey("CtrlOrCmd+[")}`}
|
||||||
>
|
>
|
||||||
{sendBackward}
|
{sendBackward}
|
||||||
</button>
|
</button>
|
||||||
@ -57,13 +59,14 @@ export const actionBringForward = register({
|
|||||||
contextItemLabel: "labels.bringForward",
|
contextItemLabel: "labels.bringForward",
|
||||||
keyPriority: 40,
|
keyPriority: 40,
|
||||||
commitToHistory: () => true,
|
commitToHistory: () => true,
|
||||||
keyTest: event => event[KEYS.META] && event.altKey && event.key === "F",
|
keyTest: event =>
|
||||||
|
event[KEYS.CTRL_OR_CMD] && !event.shiftKey && event.code === "BracketRight",
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="zIndexButton"
|
className="zIndexButton"
|
||||||
onClick={() => updateData(null)}
|
onClick={() => updateData(null)}
|
||||||
title={t("labels.bringForward")}
|
title={`${t("labels.bringForward")} ${getShortcutKey("CtrlOrCmd+]")}`}
|
||||||
>
|
>
|
||||||
{bringForward}
|
{bringForward}
|
||||||
</button>
|
</button>
|
||||||
@ -83,13 +86,23 @@ export const actionSendToBack = register({
|
|||||||
},
|
},
|
||||||
contextItemLabel: "labels.sendToBack",
|
contextItemLabel: "labels.sendToBack",
|
||||||
commitToHistory: () => true,
|
commitToHistory: () => true,
|
||||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.key === "B",
|
keyTest: event => {
|
||||||
|
return isDarwin
|
||||||
|
? event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === "BracketLeft"
|
||||||
|
: event[KEYS.CTRL_OR_CMD] &&
|
||||||
|
event.shiftKey &&
|
||||||
|
event.code === "BracketLeft";
|
||||||
|
},
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="zIndexButton"
|
className="zIndexButton"
|
||||||
onClick={() => updateData(null)}
|
onClick={() => updateData(null)}
|
||||||
title={t("labels.sendToBack")}
|
title={`${t("labels.sendToBack")} ${
|
||||||
|
isDarwin
|
||||||
|
? getShortcutKey("CtrlOrCmd+Alt+[")
|
||||||
|
: getShortcutKey("CtrlOrCmd+Shift+[")
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{sendToBack}
|
{sendToBack}
|
||||||
</button>
|
</button>
|
||||||
@ -109,13 +122,23 @@ export const actionBringToFront = register({
|
|||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
commitToHistory: () => true,
|
||||||
contextItemLabel: "labels.bringToFront",
|
contextItemLabel: "labels.bringToFront",
|
||||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.key === "F",
|
keyTest: event => {
|
||||||
|
return isDarwin
|
||||||
|
? event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === "BracketRight"
|
||||||
|
: event[KEYS.CTRL_OR_CMD] &&
|
||||||
|
event.shiftKey &&
|
||||||
|
event.code === "BracketRight";
|
||||||
|
},
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="zIndexButton"
|
className="zIndexButton"
|
||||||
onClick={event => updateData(null)}
|
onClick={event => updateData(null)}
|
||||||
title={t("labels.bringToFront")}
|
title={`${t("labels.bringToFront")} ${
|
||||||
|
isDarwin
|
||||||
|
? getShortcutKey("CtrlOrCmd+Alt+]")
|
||||||
|
: getShortcutKey("CtrlOrCmd+Shift+]")
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{bringToFront}
|
{bringToFront}
|
||||||
</button>
|
</button>
|
||||||
|
@ -5,7 +5,7 @@ import { hasBackground, hasStroke, hasText } from "../scene";
|
|||||||
import { t } from "../i18n";
|
import { t } from "../i18n";
|
||||||
import { SHAPES } from "../shapes";
|
import { SHAPES } from "../shapes";
|
||||||
import { ToolButton } from "./ToolButton";
|
import { ToolButton } from "./ToolButton";
|
||||||
import { capitalizeString } from "../utils";
|
import { capitalizeString, getShortcutKey } from "../utils";
|
||||||
import { CURSOR_TYPE } from "../constants";
|
import { CURSOR_TYPE } from "../constants";
|
||||||
import Stack from "./Stack";
|
import Stack from "./Stack";
|
||||||
|
|
||||||
@ -78,6 +78,9 @@ export function ShapesSwitcher({
|
|||||||
<>
|
<>
|
||||||
{SHAPES.map(({ value, icon }, index) => {
|
{SHAPES.map(({ value, icon }, index) => {
|
||||||
const label = t(`toolBar.${value}`);
|
const label = t(`toolBar.${value}`);
|
||||||
|
const shortcut = getShortcutKey(
|
||||||
|
`${capitalizeString(value)[0]}, ${index + 1}`,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
key={value}
|
key={value}
|
||||||
@ -85,9 +88,7 @@ export function ShapesSwitcher({
|
|||||||
icon={icon}
|
icon={icon}
|
||||||
checked={elementType === value}
|
checked={elementType === value}
|
||||||
name="editor-current-shape"
|
name="editor-current-shape"
|
||||||
title={`${capitalizeString(label)} — ${
|
title={`${capitalizeString(label)} ${shortcut}`}
|
||||||
capitalizeString(value)[0]
|
|
||||||
}, ${index + 1}`}
|
|
||||||
keyBindingLabel={`${index + 1}`}
|
keyBindingLabel={`${index + 1}`}
|
||||||
aria-label={capitalizeString(label)}
|
aria-label={capitalizeString(label)}
|
||||||
aria-keyshortcuts={`${label[0]} ${index + 1}`}
|
aria-keyshortcuts={`${label[0]} ${index + 1}`}
|
||||||
|
@ -1769,7 +1769,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const { deltaX, deltaY } = event;
|
const { deltaX, deltaY } = event;
|
||||||
|
|
||||||
if (event.metaKey || event.ctrlKey) {
|
if (event[KEYS.CTRL_OR_CMD]) {
|
||||||
const sign = Math.sign(deltaY);
|
const sign = Math.sign(deltaY);
|
||||||
const MAX_STEP = 10;
|
const MAX_STEP = 10;
|
||||||
let delta = Math.abs(deltaY);
|
let delta = Math.abs(deltaY);
|
||||||
|
10
src/keys.ts
10
src/keys.ts
@ -1,3 +1,5 @@
|
|||||||
|
export const isDarwin = /Mac|iPod|iPhone|iPad/.test(window.navigator.platform);
|
||||||
|
|
||||||
export const KEYS = {
|
export const KEYS = {
|
||||||
ARROW_LEFT: "ArrowLeft",
|
ARROW_LEFT: "ArrowLeft",
|
||||||
ARROW_RIGHT: "ArrowRight",
|
ARROW_RIGHT: "ArrowRight",
|
||||||
@ -7,14 +9,10 @@ export const KEYS = {
|
|||||||
ESCAPE: "Escape",
|
ESCAPE: "Escape",
|
||||||
DELETE: "Delete",
|
DELETE: "Delete",
|
||||||
BACKSPACE: "Backspace",
|
BACKSPACE: "Backspace",
|
||||||
get META() {
|
CTRL_OR_CMD: isDarwin ? "metaKey" : "ctrlKey",
|
||||||
return /Mac|iPod|iPhone|iPad/.test(window.navigator.platform)
|
|
||||||
? "metaKey"
|
|
||||||
: "ctrlKey";
|
|
||||||
},
|
|
||||||
TAB: "Tab",
|
TAB: "Tab",
|
||||||
SPACE: " ",
|
SPACE: " ",
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export function isArrowKey(keyCode: string) {
|
export function isArrowKey(keyCode: string) {
|
||||||
return (
|
return (
|
||||||
|
11
src/utils.ts
11
src/utils.ts
@ -134,6 +134,17 @@ export function resetCursor() {
|
|||||||
document.documentElement.style.cursor = "";
|
document.documentElement.style.cursor = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getShortcutKey = (shortcut: string): string => {
|
||||||
|
const isMac = /Mac|iPod|iPhone|iPad/.test(window.navigator.platform);
|
||||||
|
if (isMac) {
|
||||||
|
return ` — ${shortcut
|
||||||
|
.replace("CtrlOrCmd+", "⌘")
|
||||||
|
.replace("Alt+", "⌥")
|
||||||
|
.replace("Ctrl+", "⌃")
|
||||||
|
.replace("Shift+", "⇧")}`;
|
||||||
|
}
|
||||||
|
return ` — ${shortcut.replace("CtrlOrCmd", "Ctrl")}`;
|
||||||
|
};
|
||||||
export function viewportCoordsToSceneCoords(
|
export function viewportCoordsToSceneCoords(
|
||||||
{ clientX, clientY }: { clientX: number; clientY: number },
|
{ clientX, clientY }: { clientX: number; clientY: number },
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user