mirror of
https://github.com/excalidraw/excalidraw.git
synced 2024-11-02 03:25:53 +01:00
feat: Scroll using PageUp and PageDown (#6038)
* feat: Scroll using PageUp and PageDown * support x-axis via `shift` & enable in viewMode * tweak test Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
parent
c8370b394c
commit
fdd8552637
@ -2008,6 +2008,20 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.key === KEYS.PAGE_UP || event.key === KEYS.PAGE_DOWN) {
|
||||||
|
let offset =
|
||||||
|
(event.shiftKey ? this.state.width : this.state.height) /
|
||||||
|
this.state.zoom.value;
|
||||||
|
if (event.key === KEYS.PAGE_DOWN) {
|
||||||
|
offset = -offset;
|
||||||
|
}
|
||||||
|
if (event.shiftKey) {
|
||||||
|
this.setState((state) => ({ scrollX: state.scrollX + offset }));
|
||||||
|
} else {
|
||||||
|
this.setState((state) => ({ scrollY: state.scrollY + offset }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.actionManager.handleKeyDown(event)) {
|
if (this.actionManager.handleKeyDown(event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2030,12 +2044,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
|
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
|
||||||
: ELEMENT_TRANSLATE_AMOUNT);
|
: ELEMENT_TRANSLATE_AMOUNT);
|
||||||
|
|
||||||
const selectedElements = getSelectedElements(
|
|
||||||
this.scene.getNonDeletedElements(),
|
|
||||||
this.state,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
let offsetX = 0;
|
let offsetX = 0;
|
||||||
let offsetY = 0;
|
let offsetY = 0;
|
||||||
|
|
||||||
@ -2049,6 +2057,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
offsetY = step;
|
offsetY = step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectedElements = getSelectedElements(
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
this.state,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
selectedElements.forEach((element) => {
|
selectedElements.forEach((element) => {
|
||||||
mutateElement(element, {
|
mutateElement(element, {
|
||||||
x: element.x + offsetX,
|
x: element.x + offsetX,
|
||||||
|
@ -230,6 +230,14 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
|
|||||||
label={t("helpDialog.zoomToSelection")}
|
label={t("helpDialog.zoomToSelection")}
|
||||||
shortcuts={["Shift+2"]}
|
shortcuts={["Shift+2"]}
|
||||||
/>
|
/>
|
||||||
|
<Shortcut
|
||||||
|
label={t("helpDialog.movePageUpDown")}
|
||||||
|
shortcuts={["PgUp/PgDn"]}
|
||||||
|
/>
|
||||||
|
<Shortcut
|
||||||
|
label={t("helpDialog.movePageLeftRight")}
|
||||||
|
shortcuts={["Shift+PgUp/PgDn"]}
|
||||||
|
/>
|
||||||
<Shortcut label={t("buttons.fullScreen")} shortcuts={["F"]} />
|
<Shortcut label={t("buttons.fullScreen")} shortcuts={["F"]} />
|
||||||
<Shortcut
|
<Shortcut
|
||||||
label={t("buttons.zenMode")}
|
label={t("buttons.zenMode")}
|
||||||
|
@ -29,6 +29,8 @@ export const KEYS = {
|
|||||||
ARROW_LEFT: "ArrowLeft",
|
ARROW_LEFT: "ArrowLeft",
|
||||||
ARROW_RIGHT: "ArrowRight",
|
ARROW_RIGHT: "ArrowRight",
|
||||||
ARROW_UP: "ArrowUp",
|
ARROW_UP: "ArrowUp",
|
||||||
|
PAGE_UP: "PageUp",
|
||||||
|
PAGE_DOWN: "PageDown",
|
||||||
BACKSPACE: "Backspace",
|
BACKSPACE: "Backspace",
|
||||||
ALT: "Alt",
|
ALT: "Alt",
|
||||||
CTRL_OR_CMD: isDarwin ? "metaKey" : "ctrlKey",
|
CTRL_OR_CMD: isDarwin ? "metaKey" : "ctrlKey",
|
||||||
|
@ -312,7 +312,9 @@
|
|||||||
"view": "View",
|
"view": "View",
|
||||||
"zoomToFit": "Zoom to fit all elements",
|
"zoomToFit": "Zoom to fit all elements",
|
||||||
"zoomToSelection": "Zoom to selection",
|
"zoomToSelection": "Zoom to selection",
|
||||||
"toggleElementLock": "Lock/unlock selection"
|
"toggleElementLock": "Lock/unlock selection",
|
||||||
|
"movePageUpDown": "Move page up/down",
|
||||||
|
"movePageLeftRight": "Move page left/right"
|
||||||
},
|
},
|
||||||
"clearCanvasDialog": {
|
"clearCanvasDialog": {
|
||||||
"title": "Clear canvas"
|
"title": "Clear canvas"
|
||||||
|
@ -6,6 +6,9 @@ import {
|
|||||||
} from "./test-utils";
|
} from "./test-utils";
|
||||||
import { Excalidraw } from "../packages/excalidraw/index";
|
import { Excalidraw } from "../packages/excalidraw/index";
|
||||||
import { API } from "./helpers/api";
|
import { API } from "./helpers/api";
|
||||||
|
import { Keyboard } from "./helpers/ui";
|
||||||
|
import { KEYS } from "../keys";
|
||||||
|
import ExcalidrawApp from "../excalidraw-app";
|
||||||
|
|
||||||
const { h } = window;
|
const { h } = window;
|
||||||
|
|
||||||
@ -50,4 +53,60 @@ describe("appState", () => {
|
|||||||
});
|
});
|
||||||
restoreOriginalGetBoundingClientRect();
|
restoreOriginalGetBoundingClientRect();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("moving by page up/down/left/right", async () => {
|
||||||
|
mockBoundingClientRect();
|
||||||
|
await render(<ExcalidrawApp />, {});
|
||||||
|
|
||||||
|
const scrollTest = () => {
|
||||||
|
const initialScrollY = h.state.scrollY;
|
||||||
|
const initialScrollX = h.state.scrollX;
|
||||||
|
const pageStepY = h.state.height / h.state.zoom.value;
|
||||||
|
const pageStepX = h.state.width / h.state.zoom.value;
|
||||||
|
// Assert the following assertions have meaning
|
||||||
|
expect(pageStepY).toBeGreaterThan(0);
|
||||||
|
expect(pageStepX).toBeGreaterThan(0);
|
||||||
|
// Assert we scroll up
|
||||||
|
Keyboard.keyPress(KEYS.PAGE_UP);
|
||||||
|
expect(h.state.scrollY).toBe(initialScrollY + pageStepY);
|
||||||
|
// x-axis unchanged
|
||||||
|
expect(h.state.scrollX).toBe(initialScrollX);
|
||||||
|
|
||||||
|
// Assert we scroll down
|
||||||
|
Keyboard.keyPress(KEYS.PAGE_DOWN);
|
||||||
|
Keyboard.keyPress(KEYS.PAGE_DOWN);
|
||||||
|
expect(h.state.scrollY).toBe(initialScrollY - pageStepY);
|
||||||
|
// x-axis unchanged
|
||||||
|
expect(h.state.scrollX).toBe(initialScrollX);
|
||||||
|
|
||||||
|
// Assert we scroll left
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
Keyboard.keyPress(KEYS.PAGE_UP);
|
||||||
|
});
|
||||||
|
expect(h.state.scrollX).toBe(initialScrollX + pageStepX);
|
||||||
|
// y-axis unchanged
|
||||||
|
expect(h.state.scrollY).toBe(initialScrollY - pageStepY);
|
||||||
|
|
||||||
|
// Assert we scroll right
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
Keyboard.keyPress(KEYS.PAGE_DOWN);
|
||||||
|
Keyboard.keyPress(KEYS.PAGE_DOWN);
|
||||||
|
});
|
||||||
|
expect(h.state.scrollX).toBe(initialScrollX - pageStepX);
|
||||||
|
// y-axis unchanged
|
||||||
|
expect(h.state.scrollY).toBe(initialScrollY - pageStepY);
|
||||||
|
};
|
||||||
|
|
||||||
|
const zoom = h.state.zoom.value;
|
||||||
|
// Assert we scroll properly when zoomed in
|
||||||
|
h.setState({ zoom: { value: (zoom * 1.1) as typeof zoom } });
|
||||||
|
scrollTest();
|
||||||
|
// Assert we scroll properly when zoomed out
|
||||||
|
h.setState({ zoom: { value: (zoom * 0.9) as typeof zoom } });
|
||||||
|
scrollTest();
|
||||||
|
// Assert we scroll properly with normal zoom
|
||||||
|
h.setState({ zoom: { value: zoom } });
|
||||||
|
scrollTest();
|
||||||
|
restoreOriginalGetBoundingClientRect();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user