mirror of
				https://github.com/excalidraw/excalidraw.git
				synced 2025-10-31 02:44:50 +01:00 
			
		
		
		
	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:
		| @@ -6,6 +6,7 @@ import { ToolButton } from "../components/ToolButton"; | ||||
| import { t } from "../i18n"; | ||||
| import { getNormalizedZoom } from "../scene"; | ||||
| import { KEYS } from "../keys"; | ||||
| import { getShortcutKey } from "../utils"; | ||||
| import useIsMobile from "../is-mobile"; | ||||
| import { register } from "./register"; | ||||
|  | ||||
| @@ -83,7 +84,7 @@ export const actionZoomIn = register({ | ||||
|     <ToolButton | ||||
|       type="button" | ||||
|       icon={zoomIn} | ||||
|       title={t("buttons.zoomIn")} | ||||
|       title={`${t("buttons.zoomIn")} ${getShortcutKey("CtrlOrCmd++")}`} | ||||
|       aria-label={t("buttons.zoomIn")} | ||||
|       onClick={() => { | ||||
|         updateData(null); | ||||
| @@ -92,7 +93,7 @@ export const actionZoomIn = register({ | ||||
|   ), | ||||
|   keyTest: event => | ||||
|     (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({ | ||||
| @@ -109,7 +110,7 @@ export const actionZoomOut = register({ | ||||
|     <ToolButton | ||||
|       type="button" | ||||
|       icon={zoomOut} | ||||
|       title={t("buttons.zoomOut")} | ||||
|       title={`${t("buttons.zoomOut")} ${getShortcutKey("CtrlOrCmd+-")}`} | ||||
|       aria-label={t("buttons.zoomOut")} | ||||
|       onClick={() => { | ||||
|         updateData(null); | ||||
| @@ -118,7 +119,7 @@ export const actionZoomOut = register({ | ||||
|   ), | ||||
|   keyTest: event => | ||||
|     (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({ | ||||
| @@ -144,5 +145,5 @@ export const actionResetZoom = register({ | ||||
|   ), | ||||
|   keyTest: event => | ||||
|     (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) => | ||||
|   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; | ||||
|  | ||||
|   | ||||
| @@ -14,5 +14,5 @@ export const actionSelectAll = register({ | ||||
|     }; | ||||
|   }, | ||||
|   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 {}; | ||||
|   }, | ||||
|   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, | ||||
| }); | ||||
|  | ||||
| @@ -54,6 +55,7 @@ export const actionPasteStyles = register({ | ||||
|   }, | ||||
|   commitToHistory: () => true, | ||||
|   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, | ||||
| }); | ||||
|   | ||||
| @@ -6,8 +6,9 @@ import { | ||||
|   moveAllRight, | ||||
| } from "../zindex"; | ||||
| import { getSelectedIndices } from "../scene"; | ||||
| import { KEYS } from "../keys"; | ||||
| import { KEYS, isDarwin } from "../keys"; | ||||
| import { t } from "../i18n"; | ||||
| import { getShortcutKey } from "../utils"; | ||||
| import { register } from "./register"; | ||||
| import { | ||||
|   sendBackward, | ||||
| @@ -30,13 +31,14 @@ export const actionSendBackward = register({ | ||||
|   contextItemLabel: "labels.sendBackward", | ||||
|   keyPriority: 40, | ||||
|   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 }) => ( | ||||
|     <button | ||||
|       type="button" | ||||
|       className="zIndexButton" | ||||
|       onClick={() => updateData(null)} | ||||
|       title={t("labels.sendBackward")} | ||||
|       title={`${t("labels.sendBackward")} ${getShortcutKey("CtrlOrCmd+[")}`} | ||||
|     > | ||||
|       {sendBackward} | ||||
|     </button> | ||||
| @@ -57,13 +59,14 @@ export const actionBringForward = register({ | ||||
|   contextItemLabel: "labels.bringForward", | ||||
|   keyPriority: 40, | ||||
|   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 }) => ( | ||||
|     <button | ||||
|       type="button" | ||||
|       className="zIndexButton" | ||||
|       onClick={() => updateData(null)} | ||||
|       title={t("labels.bringForward")} | ||||
|       title={`${t("labels.bringForward")} ${getShortcutKey("CtrlOrCmd+]")}`} | ||||
|     > | ||||
|       {bringForward} | ||||
|     </button> | ||||
| @@ -83,13 +86,23 @@ export const actionSendToBack = register({ | ||||
|   }, | ||||
|   contextItemLabel: "labels.sendToBack", | ||||
|   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 }) => ( | ||||
|     <button | ||||
|       type="button" | ||||
|       className="zIndexButton" | ||||
|       onClick={() => updateData(null)} | ||||
|       title={t("labels.sendToBack")} | ||||
|       title={`${t("labels.sendToBack")} ${ | ||||
|         isDarwin | ||||
|           ? getShortcutKey("CtrlOrCmd+Alt+[") | ||||
|           : getShortcutKey("CtrlOrCmd+Shift+[") | ||||
|       }`} | ||||
|     > | ||||
|       {sendToBack} | ||||
|     </button> | ||||
| @@ -109,13 +122,23 @@ export const actionBringToFront = register({ | ||||
|   }, | ||||
|   commitToHistory: () => true, | ||||
|   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 }) => ( | ||||
|     <button | ||||
|       type="button" | ||||
|       className="zIndexButton" | ||||
|       onClick={event => updateData(null)} | ||||
|       title={t("labels.bringToFront")} | ||||
|       title={`${t("labels.bringToFront")} ${ | ||||
|         isDarwin | ||||
|           ? getShortcutKey("CtrlOrCmd+Alt+]") | ||||
|           : getShortcutKey("CtrlOrCmd+Shift+]") | ||||
|       }`} | ||||
|     > | ||||
|       {bringToFront} | ||||
|     </button> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import { hasBackground, hasStroke, hasText } from "../scene"; | ||||
| import { t } from "../i18n"; | ||||
| import { SHAPES } from "../shapes"; | ||||
| import { ToolButton } from "./ToolButton"; | ||||
| import { capitalizeString } from "../utils"; | ||||
| import { capitalizeString, getShortcutKey } from "../utils"; | ||||
| import { CURSOR_TYPE } from "../constants"; | ||||
| import Stack from "./Stack"; | ||||
|  | ||||
| @@ -78,6 +78,9 @@ export function ShapesSwitcher({ | ||||
|     <> | ||||
|       {SHAPES.map(({ value, icon }, index) => { | ||||
|         const label = t(`toolBar.${value}`); | ||||
|         const shortcut = getShortcutKey( | ||||
|           `${capitalizeString(value)[0]}, ${index + 1}`, | ||||
|         ); | ||||
|         return ( | ||||
|           <ToolButton | ||||
|             key={value} | ||||
| @@ -85,9 +88,7 @@ export function ShapesSwitcher({ | ||||
|             icon={icon} | ||||
|             checked={elementType === value} | ||||
|             name="editor-current-shape" | ||||
|             title={`${capitalizeString(label)} — ${ | ||||
|               capitalizeString(value)[0] | ||||
|             }, ${index + 1}`} | ||||
|             title={`${capitalizeString(label)} ${shortcut}`} | ||||
|             keyBindingLabel={`${index + 1}`} | ||||
|             aria-label={capitalizeString(label)} | ||||
|             aria-keyshortcuts={`${label[0]} ${index + 1}`} | ||||
|   | ||||
| @@ -1769,7 +1769,7 @@ export class App extends React.Component<any, AppState> { | ||||
|     event.preventDefault(); | ||||
|     const { deltaX, deltaY } = event; | ||||
|  | ||||
|     if (event.metaKey || event.ctrlKey) { | ||||
|     if (event[KEYS.CTRL_OR_CMD]) { | ||||
|       const sign = Math.sign(deltaY); | ||||
|       const MAX_STEP = 10; | ||||
|       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 = { | ||||
|   ARROW_LEFT: "ArrowLeft", | ||||
|   ARROW_RIGHT: "ArrowRight", | ||||
| @@ -7,14 +9,10 @@ export const KEYS = { | ||||
|   ESCAPE: "Escape", | ||||
|   DELETE: "Delete", | ||||
|   BACKSPACE: "Backspace", | ||||
|   get META() { | ||||
|     return /Mac|iPod|iPhone|iPad/.test(window.navigator.platform) | ||||
|       ? "metaKey" | ||||
|       : "ctrlKey"; | ||||
|   }, | ||||
|   CTRL_OR_CMD: isDarwin ? "metaKey" : "ctrlKey", | ||||
|   TAB: "Tab", | ||||
|   SPACE: " ", | ||||
| }; | ||||
| } as const; | ||||
|  | ||||
| export function isArrowKey(keyCode: string) { | ||||
|   return ( | ||||
|   | ||||
							
								
								
									
										11
									
								
								src/utils.ts
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/utils.ts
									
									
									
									
									
								
							| @@ -134,6 +134,17 @@ export function resetCursor() { | ||||
|   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( | ||||
|   { clientX, clientY }: { clientX: number; clientY: number }, | ||||
|   { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Lipis
					Lipis