feat: split gridSize from enabled state & support custom gridStep (#8364)

This commit is contained in:
David Luzar 2024-08-14 14:59:14 +02:00 committed by GitHub
parent 4320a3cf41
commit 3cfcc7b489
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 737 additions and 278 deletions

View file

@ -60,7 +60,6 @@ import {
ENV,
EVENT,
FRAME_STYLE,
GRID_SIZE,
IMAGE_MIME_TYPES,
IMAGE_RENDER_TIMEOUT,
isBrave,
@ -258,6 +257,7 @@ import type {
UnsubscribeCallback,
EmbedsValidationStatus,
ElementsPendingErasure,
NullableGridSize,
} from "../types";
import {
debounce,
@ -661,7 +661,7 @@ class App extends React.Component<AppProps, AppState> {
viewModeEnabled,
zenModeEnabled,
objectsSnapModeEnabled,
gridSize: gridModeEnabled ? GRID_SIZE : null,
gridModeEnabled: gridModeEnabled ?? defaultAppState.gridModeEnabled,
name,
width: window.innerWidth,
height: window.innerHeight,
@ -812,6 +812,18 @@ class App extends React.Component<AppProps, AppState> {
}
}
/**
* Returns gridSize taking into account `gridModeEnabled`.
* If disabled, returns null.
*/
public getEffectiveGridSize = () => {
return (
this.props.gridModeEnabled ?? this.state.gridModeEnabled
? this.state.gridSize
: null
) as NullableGridSize;
};
private getHTMLIFrameElement(
element: ExcalidrawIframeLikeElement,
): HTMLIFrameElement | undefined {
@ -1684,7 +1696,9 @@ class App extends React.Component<AppProps, AppState> {
renderConfig={{
imageCache: this.imageCache,
isExporting: false,
renderGrid: true,
renderGrid:
this.props.gridModeEnabled ??
this.state.gridModeEnabled,
canvasBackgroundColor:
this.state.viewBackgroundColor,
embedsValidationStatus: this.embedsValidationStatus,
@ -2171,7 +2185,6 @@ class App extends React.Component<AppProps, AppState> {
if (actionResult.appState || editingElement || this.state.contextMenu) {
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
let gridSize = actionResult?.appState?.gridSize || null;
const theme =
actionResult?.appState?.theme || this.props.theme || THEME.LIGHT;
const name = actionResult?.appState?.name ?? this.state.name;
@ -2185,10 +2198,6 @@ class App extends React.Component<AppProps, AppState> {
zenModeEnabled = this.props.zenModeEnabled;
}
if (typeof this.props.gridModeEnabled !== "undefined") {
gridSize = this.props.gridModeEnabled ? GRID_SIZE : null;
}
editingElement = actionResult.appState?.editingElement || null;
// make sure editingElement points to latest element reference
@ -2220,7 +2229,6 @@ class App extends React.Component<AppProps, AppState> {
editingElement,
viewModeEnabled,
zenModeEnabled,
gridSize,
theme,
name,
errorMessage,
@ -2777,12 +2785,6 @@ class App extends React.Component<AppProps, AppState> {
this.setState({ theme: this.props.theme });
}
if (prevProps.gridModeEnabled !== this.props.gridModeEnabled) {
this.setState({
gridSize: this.props.gridModeEnabled ? GRID_SIZE : null,
});
}
this.excalidrawContainerRef.current?.classList.toggle(
"theme--dark",
this.state.theme === THEME.DARK,
@ -3185,7 +3187,7 @@ class App extends React.Component<AppProps, AppState> {
const dx = x - elementsCenterX;
const dy = y - elementsCenterY;
const [gridX, gridY] = getGridPoint(dx, dy, this.state.gridSize);
const [gridX, gridY] = getGridPoint(dx, dy, this.getEffectiveGridSize());
const newElements = duplicateElements(
elements.map((element) => {
@ -3570,7 +3572,10 @@ class App extends React.Component<AppProps, AppState> {
* Zooms on canvas viewport center
*/
zoomCanvas = (
/** decimal fraction between 0.1 (10% zoom) and 30 (3000% zoom) */
/**
* Decimal fraction, auto-clamped between MIN_ZOOM and MAX_ZOOM.
* 1 = 100% zoom, 2 = 200% zoom, 0.5 = 50% zoom
*/
value: number,
) => {
this.setState({
@ -4148,10 +4153,10 @@ class App extends React.Component<AppProps, AppState> {
? elbowArrow.startBinding || elbowArrow.endBinding
? 0
: ELEMENT_TRANSLATE_AMOUNT
: (this.state.gridSize &&
: (this.getEffectiveGridSize() &&
(event.shiftKey
? ELEMENT_TRANSLATE_AMOUNT
: this.state.gridSize)) ||
: this.getEffectiveGridSize())) ||
(event.shiftKey
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
: ELEMENT_TRANSLATE_AMOUNT);
@ -5496,7 +5501,7 @@ class App extends React.Component<AppProps, AppState> {
event,
scenePointerX,
scenePointerY,
this.state,
this,
this.scene.getNonDeletedElementsMap(),
);
@ -5586,7 +5591,7 @@ class App extends React.Component<AppProps, AppState> {
scenePointerY,
event[KEYS.CTRL_OR_CMD] || isElbowArrow(multiElement)
? null
: this.state.gridSize,
: this.getEffectiveGridSize(),
);
const [lastCommittedX, lastCommittedY] =
@ -6553,7 +6558,7 @@ class App extends React.Component<AppProps, AppState> {
origin.y,
event[KEYS.CTRL_OR_CMD] || isElbowArrowOnly
? null
: this.state.gridSize,
: this.getEffectiveGridSize(),
),
),
scrollbars: isOverScrollBars(
@ -6730,7 +6735,7 @@ class App extends React.Component<AppProps, AppState> {
this.state.editingLinearElement || this.state.selectedLinearElement;
const ret = LinearElementEditor.handlePointerDown(
event,
this.state,
this,
this.store,
pointerDownState.origin,
linearElementEditor,
@ -7093,7 +7098,7 @@ class App extends React.Component<AppProps, AppState> {
sceneY,
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
? null
: this.state.gridSize,
: this.getEffectiveGridSize(),
);
const element = newIframeElement({
@ -7133,7 +7138,7 @@ class App extends React.Component<AppProps, AppState> {
sceneY,
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
? null
: this.state.gridSize,
: this.getEffectiveGridSize(),
);
const embedLink = getEmbedLink(link);
@ -7186,7 +7191,7 @@ class App extends React.Component<AppProps, AppState> {
sceneY,
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
? null
: this.state.gridSize,
: this.getEffectiveGridSize(),
);
const topLayerFrame = addToFrameUnderCursor
@ -7283,7 +7288,7 @@ class App extends React.Component<AppProps, AppState> {
const [gridX, gridY] = getGridPoint(
pointerDownState.origin.x,
pointerDownState.origin.y,
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
);
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
@ -7404,7 +7409,7 @@ class App extends React.Component<AppProps, AppState> {
pointerDownState.origin.y,
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
? null
: this.state.gridSize,
: this.getEffectiveGridSize(),
);
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
@ -7462,7 +7467,7 @@ class App extends React.Component<AppProps, AppState> {
pointerDownState.origin.y,
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
? null
: this.state.gridSize,
: this.getEffectiveGridSize(),
);
const constructorOpts = {
@ -7598,7 +7603,7 @@ class App extends React.Component<AppProps, AppState> {
const [gridX, gridY] = getGridPoint(
pointerCoords.x,
pointerCoords.y,
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
);
// for arrows/lines, don't start dragging until a given threshold
@ -7645,7 +7650,7 @@ class App extends React.Component<AppProps, AppState> {
const ret = LinearElementEditor.addMidpoint(
this.state.selectedLinearElement,
pointerCoords,
this.state,
this,
!event[KEYS.CTRL_OR_CMD],
elementsMap,
);
@ -7688,7 +7693,7 @@ class App extends React.Component<AppProps, AppState> {
const didDrag = LinearElementEditor.handlePointDragging(
event,
this.state,
this,
pointerCoords.x,
pointerCoords.y,
(element, pointsSceneCoords) => {
@ -7822,7 +7827,7 @@ class App extends React.Component<AppProps, AppState> {
dragOffset,
this.scene,
snapOffset,
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
);
this.setState({
@ -9794,7 +9799,7 @@ class App extends React.Component<AppProps, AppState> {
let [gridX, gridY] = getGridPoint(
pointerCoords.x,
pointerCoords.y,
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
);
const image =
@ -9898,7 +9903,7 @@ class App extends React.Component<AppProps, AppState> {
let [resizeX, resizeY] = getGridPoint(
pointerCoords.x - pointerDownState.resize.offset.x,
pointerCoords.y - pointerDownState.resize.offset.y,
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
);
const frameElementsOffsetsMap = new Map<
@ -9929,7 +9934,7 @@ class App extends React.Component<AppProps, AppState> {
const [gridX, gridY] = getGridPoint(
pointerCoords.x,
pointerCoords.y,
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
);
const dragOffset = {