mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: split gridSize
from enabled state & support custom gridStep
(#8364)
This commit is contained in:
parent
4320a3cf41
commit
3cfcc7b489
31 changed files with 737 additions and 278 deletions
|
@ -43,7 +43,7 @@ When saving an Excalidraw scene locally to a file, the JSON file (`.excalidraw`)
|
||||||
|
|
||||||
// editor state (canvas config, preferences, ...)
|
// editor state (canvas config, preferences, ...)
|
||||||
"appState": {
|
"appState": {
|
||||||
"gridSize": null,
|
"gridSize": 20,
|
||||||
"viewBackgroundColor": "#ffffff"
|
"viewBackgroundColor": "#ffffff"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,8 @@ export const actionClearCanvas = register({
|
||||||
exportBackground: appState.exportBackground,
|
exportBackground: appState.exportBackground,
|
||||||
exportEmbedScene: appState.exportEmbedScene,
|
exportEmbedScene: appState.exportEmbedScene,
|
||||||
gridSize: appState.gridSize,
|
gridSize: appState.gridSize,
|
||||||
|
gridStep: appState.gridStep,
|
||||||
|
gridModeEnabled: appState.gridModeEnabled,
|
||||||
stats: appState.stats,
|
stats: appState.stats,
|
||||||
pasteDialog: appState.pasteDialog,
|
pasteDialog: appState.pasteDialog,
|
||||||
activeTool:
|
activeTool:
|
||||||
|
@ -294,7 +296,6 @@ export const zoomToFitBounds = ({
|
||||||
appState.height / commonBoundsHeight,
|
appState.height / commonBoundsHeight,
|
||||||
) * clamp(viewportZoomFactor, 0.1, 1);
|
) * clamp(viewportZoomFactor, 0.1, 1);
|
||||||
|
|
||||||
// Apply clamping to newZoomValue to be between 10% and 3000%
|
|
||||||
newZoomValue = getNormalizedZoom(newZoomValue);
|
newZoomValue = getNormalizedZoom(newZoomValue);
|
||||||
|
|
||||||
let appStateWidth = appState.width;
|
let appStateWidth = appState.width;
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
import type { AppState } from "../types";
|
import type { AppState } from "../types";
|
||||||
import { fixBindingsAfterDuplication } from "../element/binding";
|
import { fixBindingsAfterDuplication } from "../element/binding";
|
||||||
import type { ActionResult } from "./types";
|
import type { ActionResult } from "./types";
|
||||||
import { GRID_SIZE } from "../constants";
|
import { DEFAULT_GRID_SIZE } from "../constants";
|
||||||
import {
|
import {
|
||||||
bindTextToShapeAfterDuplication,
|
bindTextToShapeAfterDuplication,
|
||||||
getBoundTextElement,
|
getBoundTextElement,
|
||||||
|
@ -99,8 +99,8 @@ const duplicateElements = (
|
||||||
groupIdMap,
|
groupIdMap,
|
||||||
element,
|
element,
|
||||||
{
|
{
|
||||||
x: element.x + GRID_SIZE / 2,
|
x: element.x + DEFAULT_GRID_SIZE / 2,
|
||||||
y: element.y + GRID_SIZE / 2,
|
y: element.y + DEFAULT_GRID_SIZE / 2,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
duplicatedElementsMap.set(newElement.id, newElement);
|
duplicatedElementsMap.set(newElement.id, newElement);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { CODES, KEYS } from "../keys";
|
import { CODES, KEYS } from "../keys";
|
||||||
import { register } from "./register";
|
import { register } from "./register";
|
||||||
import { GRID_SIZE } from "../constants";
|
|
||||||
import type { AppState } from "../types";
|
import type { AppState } from "../types";
|
||||||
import { gridIcon } from "../components/icons";
|
import { gridIcon } from "../components/icons";
|
||||||
import { StoreAction } from "../store";
|
import { StoreAction } from "../store";
|
||||||
|
@ -13,21 +12,21 @@ export const actionToggleGridMode = register({
|
||||||
viewMode: true,
|
viewMode: true,
|
||||||
trackEvent: {
|
trackEvent: {
|
||||||
category: "canvas",
|
category: "canvas",
|
||||||
predicate: (appState) => !appState.gridSize,
|
predicate: (appState) => appState.gridModeEnabled,
|
||||||
},
|
},
|
||||||
perform(elements, appState) {
|
perform(elements, appState) {
|
||||||
return {
|
return {
|
||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
gridSize: this.checked!(appState) ? null : GRID_SIZE,
|
gridModeEnabled: !this.checked!(appState),
|
||||||
objectsSnapModeEnabled: false,
|
objectsSnapModeEnabled: false,
|
||||||
},
|
},
|
||||||
storeAction: StoreAction.NONE,
|
storeAction: StoreAction.NONE,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
checked: (appState: AppState) => appState.gridSize !== null,
|
checked: (appState: AppState) => appState.gridModeEnabled,
|
||||||
predicate: (element, appState, props) => {
|
predicate: (element, appState, props) => {
|
||||||
return typeof props.gridModeEnabled === "undefined";
|
return props.gridModeEnabled === undefined;
|
||||||
},
|
},
|
||||||
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE,
|
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE,
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const actionToggleObjectsSnapMode = register({
|
||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
objectsSnapModeEnabled: !this.checked!(appState),
|
objectsSnapModeEnabled: !this.checked!(appState),
|
||||||
gridSize: null,
|
gridModeEnabled: false,
|
||||||
},
|
},
|
||||||
storeAction: StoreAction.NONE,
|
storeAction: StoreAction.NONE,
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,9 +5,11 @@ import {
|
||||||
DEFAULT_FONT_FAMILY,
|
DEFAULT_FONT_FAMILY,
|
||||||
DEFAULT_FONT_SIZE,
|
DEFAULT_FONT_SIZE,
|
||||||
DEFAULT_TEXT_ALIGN,
|
DEFAULT_TEXT_ALIGN,
|
||||||
|
DEFAULT_GRID_SIZE,
|
||||||
EXPORT_SCALES,
|
EXPORT_SCALES,
|
||||||
STATS_PANELS,
|
STATS_PANELS,
|
||||||
THEME,
|
THEME,
|
||||||
|
DEFAULT_GRID_STEP,
|
||||||
} from "./constants";
|
} from "./constants";
|
||||||
import type { AppState, NormalizedZoomValue } from "./types";
|
import type { AppState, NormalizedZoomValue } from "./types";
|
||||||
|
|
||||||
|
@ -59,7 +61,9 @@ export const getDefaultAppState = (): Omit<
|
||||||
exportEmbedScene: false,
|
exportEmbedScene: false,
|
||||||
exportWithDarkMode: false,
|
exportWithDarkMode: false,
|
||||||
fileHandle: null,
|
fileHandle: null,
|
||||||
gridSize: null,
|
gridSize: DEFAULT_GRID_SIZE,
|
||||||
|
gridStep: DEFAULT_GRID_STEP,
|
||||||
|
gridModeEnabled: false,
|
||||||
isBindingEnabled: true,
|
isBindingEnabled: true,
|
||||||
defaultSidebarDockedPreference: false,
|
defaultSidebarDockedPreference: false,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
@ -174,6 +178,8 @@ const APP_STATE_STORAGE_CONF = (<
|
||||||
exportWithDarkMode: { browser: true, export: false, server: false },
|
exportWithDarkMode: { browser: true, export: false, server: false },
|
||||||
fileHandle: { browser: false, export: false, server: false },
|
fileHandle: { browser: false, export: false, server: false },
|
||||||
gridSize: { browser: true, export: true, server: true },
|
gridSize: { browser: true, export: true, server: true },
|
||||||
|
gridStep: { browser: true, export: true, server: true },
|
||||||
|
gridModeEnabled: { browser: true, export: true, server: true },
|
||||||
height: { browser: false, export: false, server: false },
|
height: { browser: false, export: false, server: false },
|
||||||
isBindingEnabled: { browser: false, export: false, server: false },
|
isBindingEnabled: { browser: false, export: false, server: false },
|
||||||
defaultSidebarDockedPreference: {
|
defaultSidebarDockedPreference: {
|
||||||
|
|
|
@ -60,7 +60,6 @@ import {
|
||||||
ENV,
|
ENV,
|
||||||
EVENT,
|
EVENT,
|
||||||
FRAME_STYLE,
|
FRAME_STYLE,
|
||||||
GRID_SIZE,
|
|
||||||
IMAGE_MIME_TYPES,
|
IMAGE_MIME_TYPES,
|
||||||
IMAGE_RENDER_TIMEOUT,
|
IMAGE_RENDER_TIMEOUT,
|
||||||
isBrave,
|
isBrave,
|
||||||
|
@ -258,6 +257,7 @@ import type {
|
||||||
UnsubscribeCallback,
|
UnsubscribeCallback,
|
||||||
EmbedsValidationStatus,
|
EmbedsValidationStatus,
|
||||||
ElementsPendingErasure,
|
ElementsPendingErasure,
|
||||||
|
NullableGridSize,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import {
|
import {
|
||||||
debounce,
|
debounce,
|
||||||
|
@ -661,7 +661,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
viewModeEnabled,
|
viewModeEnabled,
|
||||||
zenModeEnabled,
|
zenModeEnabled,
|
||||||
objectsSnapModeEnabled,
|
objectsSnapModeEnabled,
|
||||||
gridSize: gridModeEnabled ? GRID_SIZE : null,
|
gridModeEnabled: gridModeEnabled ?? defaultAppState.gridModeEnabled,
|
||||||
name,
|
name,
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight,
|
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(
|
private getHTMLIFrameElement(
|
||||||
element: ExcalidrawIframeLikeElement,
|
element: ExcalidrawIframeLikeElement,
|
||||||
): HTMLIFrameElement | undefined {
|
): HTMLIFrameElement | undefined {
|
||||||
|
@ -1684,7 +1696,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
renderConfig={{
|
renderConfig={{
|
||||||
imageCache: this.imageCache,
|
imageCache: this.imageCache,
|
||||||
isExporting: false,
|
isExporting: false,
|
||||||
renderGrid: true,
|
renderGrid:
|
||||||
|
this.props.gridModeEnabled ??
|
||||||
|
this.state.gridModeEnabled,
|
||||||
canvasBackgroundColor:
|
canvasBackgroundColor:
|
||||||
this.state.viewBackgroundColor,
|
this.state.viewBackgroundColor,
|
||||||
embedsValidationStatus: this.embedsValidationStatus,
|
embedsValidationStatus: this.embedsValidationStatus,
|
||||||
|
@ -2171,7 +2185,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
if (actionResult.appState || editingElement || this.state.contextMenu) {
|
if (actionResult.appState || editingElement || this.state.contextMenu) {
|
||||||
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
|
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
|
||||||
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
||||||
let gridSize = actionResult?.appState?.gridSize || null;
|
|
||||||
const theme =
|
const theme =
|
||||||
actionResult?.appState?.theme || this.props.theme || THEME.LIGHT;
|
actionResult?.appState?.theme || this.props.theme || THEME.LIGHT;
|
||||||
const name = actionResult?.appState?.name ?? this.state.name;
|
const name = actionResult?.appState?.name ?? this.state.name;
|
||||||
|
@ -2185,10 +2198,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
zenModeEnabled = this.props.zenModeEnabled;
|
zenModeEnabled = this.props.zenModeEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof this.props.gridModeEnabled !== "undefined") {
|
|
||||||
gridSize = this.props.gridModeEnabled ? GRID_SIZE : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
editingElement = actionResult.appState?.editingElement || null;
|
editingElement = actionResult.appState?.editingElement || null;
|
||||||
|
|
||||||
// make sure editingElement points to latest element reference
|
// make sure editingElement points to latest element reference
|
||||||
|
@ -2220,7 +2229,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
editingElement,
|
editingElement,
|
||||||
viewModeEnabled,
|
viewModeEnabled,
|
||||||
zenModeEnabled,
|
zenModeEnabled,
|
||||||
gridSize,
|
|
||||||
theme,
|
theme,
|
||||||
name,
|
name,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
|
@ -2777,12 +2785,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
this.setState({ theme: this.props.theme });
|
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(
|
this.excalidrawContainerRef.current?.classList.toggle(
|
||||||
"theme--dark",
|
"theme--dark",
|
||||||
this.state.theme === THEME.DARK,
|
this.state.theme === THEME.DARK,
|
||||||
|
@ -3185,7 +3187,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
const dx = x - elementsCenterX;
|
const dx = x - elementsCenterX;
|
||||||
const dy = y - elementsCenterY;
|
const dy = y - elementsCenterY;
|
||||||
|
|
||||||
const [gridX, gridY] = getGridPoint(dx, dy, this.state.gridSize);
|
const [gridX, gridY] = getGridPoint(dx, dy, this.getEffectiveGridSize());
|
||||||
|
|
||||||
const newElements = duplicateElements(
|
const newElements = duplicateElements(
|
||||||
elements.map((element) => {
|
elements.map((element) => {
|
||||||
|
@ -3570,7 +3572,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
* Zooms on canvas viewport center
|
* Zooms on canvas viewport center
|
||||||
*/
|
*/
|
||||||
zoomCanvas = (
|
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,
|
value: number,
|
||||||
) => {
|
) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -4148,10 +4153,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
? elbowArrow.startBinding || elbowArrow.endBinding
|
? elbowArrow.startBinding || elbowArrow.endBinding
|
||||||
? 0
|
? 0
|
||||||
: ELEMENT_TRANSLATE_AMOUNT
|
: ELEMENT_TRANSLATE_AMOUNT
|
||||||
: (this.state.gridSize &&
|
: (this.getEffectiveGridSize() &&
|
||||||
(event.shiftKey
|
(event.shiftKey
|
||||||
? ELEMENT_TRANSLATE_AMOUNT
|
? ELEMENT_TRANSLATE_AMOUNT
|
||||||
: this.state.gridSize)) ||
|
: this.getEffectiveGridSize())) ||
|
||||||
(event.shiftKey
|
(event.shiftKey
|
||||||
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
|
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
|
||||||
: ELEMENT_TRANSLATE_AMOUNT);
|
: ELEMENT_TRANSLATE_AMOUNT);
|
||||||
|
@ -5496,7 +5501,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
event,
|
event,
|
||||||
scenePointerX,
|
scenePointerX,
|
||||||
scenePointerY,
|
scenePointerY,
|
||||||
this.state,
|
this,
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -5586,7 +5591,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
scenePointerY,
|
scenePointerY,
|
||||||
event[KEYS.CTRL_OR_CMD] || isElbowArrow(multiElement)
|
event[KEYS.CTRL_OR_CMD] || isElbowArrow(multiElement)
|
||||||
? null
|
? null
|
||||||
: this.state.gridSize,
|
: this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const [lastCommittedX, lastCommittedY] =
|
const [lastCommittedX, lastCommittedY] =
|
||||||
|
@ -6553,7 +6558,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
origin.y,
|
origin.y,
|
||||||
event[KEYS.CTRL_OR_CMD] || isElbowArrowOnly
|
event[KEYS.CTRL_OR_CMD] || isElbowArrowOnly
|
||||||
? null
|
? null
|
||||||
: this.state.gridSize,
|
: this.getEffectiveGridSize(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
scrollbars: isOverScrollBars(
|
scrollbars: isOverScrollBars(
|
||||||
|
@ -6730,7 +6735,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
this.state.editingLinearElement || this.state.selectedLinearElement;
|
this.state.editingLinearElement || this.state.selectedLinearElement;
|
||||||
const ret = LinearElementEditor.handlePointerDown(
|
const ret = LinearElementEditor.handlePointerDown(
|
||||||
event,
|
event,
|
||||||
this.state,
|
this,
|
||||||
this.store,
|
this.store,
|
||||||
pointerDownState.origin,
|
pointerDownState.origin,
|
||||||
linearElementEditor,
|
linearElementEditor,
|
||||||
|
@ -7093,7 +7098,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
sceneY,
|
sceneY,
|
||||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||||
? null
|
? null
|
||||||
: this.state.gridSize,
|
: this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const element = newIframeElement({
|
const element = newIframeElement({
|
||||||
|
@ -7133,7 +7138,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
sceneY,
|
sceneY,
|
||||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||||
? null
|
? null
|
||||||
: this.state.gridSize,
|
: this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const embedLink = getEmbedLink(link);
|
const embedLink = getEmbedLink(link);
|
||||||
|
@ -7186,7 +7191,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
sceneY,
|
sceneY,
|
||||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||||
? null
|
? null
|
||||||
: this.state.gridSize,
|
: this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const topLayerFrame = addToFrameUnderCursor
|
const topLayerFrame = addToFrameUnderCursor
|
||||||
|
@ -7283,7 +7288,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
const [gridX, gridY] = getGridPoint(
|
const [gridX, gridY] = getGridPoint(
|
||||||
pointerDownState.origin.x,
|
pointerDownState.origin.x,
|
||||||
pointerDownState.origin.y,
|
pointerDownState.origin.y,
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
|
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
|
||||||
|
@ -7404,7 +7409,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
pointerDownState.origin.y,
|
pointerDownState.origin.y,
|
||||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||||
? null
|
? null
|
||||||
: this.state.gridSize,
|
: this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
|
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
|
||||||
|
@ -7462,7 +7467,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
pointerDownState.origin.y,
|
pointerDownState.origin.y,
|
||||||
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
this.lastPointerDownEvent?.[KEYS.CTRL_OR_CMD]
|
||||||
? null
|
? null
|
||||||
: this.state.gridSize,
|
: this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const constructorOpts = {
|
const constructorOpts = {
|
||||||
|
@ -7598,7 +7603,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
const [gridX, gridY] = getGridPoint(
|
const [gridX, gridY] = getGridPoint(
|
||||||
pointerCoords.x,
|
pointerCoords.x,
|
||||||
pointerCoords.y,
|
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
|
// 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(
|
const ret = LinearElementEditor.addMidpoint(
|
||||||
this.state.selectedLinearElement,
|
this.state.selectedLinearElement,
|
||||||
pointerCoords,
|
pointerCoords,
|
||||||
this.state,
|
this,
|
||||||
!event[KEYS.CTRL_OR_CMD],
|
!event[KEYS.CTRL_OR_CMD],
|
||||||
elementsMap,
|
elementsMap,
|
||||||
);
|
);
|
||||||
|
@ -7688,7 +7693,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
|
|
||||||
const didDrag = LinearElementEditor.handlePointDragging(
|
const didDrag = LinearElementEditor.handlePointDragging(
|
||||||
event,
|
event,
|
||||||
this.state,
|
this,
|
||||||
pointerCoords.x,
|
pointerCoords.x,
|
||||||
pointerCoords.y,
|
pointerCoords.y,
|
||||||
(element, pointsSceneCoords) => {
|
(element, pointsSceneCoords) => {
|
||||||
|
@ -7822,7 +7827,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
dragOffset,
|
dragOffset,
|
||||||
this.scene,
|
this.scene,
|
||||||
snapOffset,
|
snapOffset,
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -9794,7 +9799,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
let [gridX, gridY] = getGridPoint(
|
let [gridX, gridY] = getGridPoint(
|
||||||
pointerCoords.x,
|
pointerCoords.x,
|
||||||
pointerCoords.y,
|
pointerCoords.y,
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const image =
|
const image =
|
||||||
|
@ -9898,7 +9903,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
let [resizeX, resizeY] = getGridPoint(
|
let [resizeX, resizeY] = getGridPoint(
|
||||||
pointerCoords.x - pointerDownState.resize.offset.x,
|
pointerCoords.x - pointerDownState.resize.offset.x,
|
||||||
pointerCoords.y - pointerDownState.resize.offset.y,
|
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<
|
const frameElementsOffsetsMap = new Map<
|
||||||
|
@ -9929,7 +9934,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
const [gridX, gridY] = getGridPoint(
|
const [gridX, gridY] = getGridPoint(
|
||||||
pointerCoords.x,
|
pointerCoords.x,
|
||||||
pointerCoords.y,
|
pointerCoords.y,
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : this.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const dragOffset = {
|
const dragOffset = {
|
||||||
|
|
|
@ -360,7 +360,7 @@ const LayerUI = ({
|
||||||
)}
|
)}
|
||||||
{shouldShowStats && (
|
{shouldShowStats && (
|
||||||
<Stats
|
<Stats
|
||||||
scene={app.scene}
|
app={app}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
actionManager.executeAction(actionToggleStats);
|
actionManager.executeAction(actionToggleStats);
|
||||||
}}
|
}}
|
||||||
|
|
67
packages/excalidraw/components/Stats/CanvasGrid.tsx
Normal file
67
packages/excalidraw/components/Stats/CanvasGrid.tsx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import StatsDragInput from "./DragInput";
|
||||||
|
import type Scene from "../../scene/Scene";
|
||||||
|
import type { AppState } from "../../types";
|
||||||
|
import { getStepSizedValue } from "./utils";
|
||||||
|
import { getNormalizedGridStep } from "../../scene";
|
||||||
|
|
||||||
|
interface PositionProps {
|
||||||
|
property: "gridStep";
|
||||||
|
scene: Scene;
|
||||||
|
appState: AppState;
|
||||||
|
setAppState: React.Component<any, AppState>["setState"];
|
||||||
|
}
|
||||||
|
|
||||||
|
const STEP_SIZE = 5;
|
||||||
|
|
||||||
|
const CanvasGrid = ({
|
||||||
|
property,
|
||||||
|
scene,
|
||||||
|
appState,
|
||||||
|
setAppState,
|
||||||
|
}: PositionProps) => {
|
||||||
|
return (
|
||||||
|
<StatsDragInput
|
||||||
|
label="Grid step"
|
||||||
|
sensitivity={8}
|
||||||
|
elements={[]}
|
||||||
|
dragInputCallback={({
|
||||||
|
nextValue,
|
||||||
|
instantChange,
|
||||||
|
shouldChangeByStepSize,
|
||||||
|
setInputValue,
|
||||||
|
}) => {
|
||||||
|
setAppState((state) => {
|
||||||
|
let nextGridStep;
|
||||||
|
|
||||||
|
if (nextValue) {
|
||||||
|
nextGridStep = nextValue;
|
||||||
|
} else if (instantChange) {
|
||||||
|
nextGridStep = shouldChangeByStepSize
|
||||||
|
? getStepSizedValue(
|
||||||
|
state.gridStep + STEP_SIZE * Math.sign(instantChange),
|
||||||
|
STEP_SIZE,
|
||||||
|
)
|
||||||
|
: state.gridStep + instantChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nextGridStep) {
|
||||||
|
setInputValue(state.gridStep);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextGridStep = getNormalizedGridStep(nextGridStep);
|
||||||
|
setInputValue(nextGridStep);
|
||||||
|
return {
|
||||||
|
gridStep: nextGridStep,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
scene={scene}
|
||||||
|
value={appState.gridStep}
|
||||||
|
property={property}
|
||||||
|
appState={appState}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CanvasGrid;
|
|
@ -18,7 +18,8 @@
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border: 1px solid var(--default-border-color);
|
border: 1px solid var(--default-border-color);
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
width: 2rem;
|
padding: 0 0.5rem 0 0.75rem;
|
||||||
|
min-width: 1rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: var(--popup-text-color);
|
color: var(--popup-text-color);
|
||||||
|
|
|
@ -29,6 +29,7 @@ export type DragInputCallbackType<
|
||||||
nextValue?: number;
|
nextValue?: number;
|
||||||
property: P;
|
property: P;
|
||||||
originalAppState: AppState;
|
originalAppState: AppState;
|
||||||
|
setInputValue: (value: number) => void;
|
||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
interface StatsDragInputProps<
|
interface StatsDragInputProps<
|
||||||
|
@ -45,6 +46,8 @@ interface StatsDragInputProps<
|
||||||
property: T;
|
property: T;
|
||||||
scene: Scene;
|
scene: Scene;
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
|
/** how many px you need to drag to get 1 unit change */
|
||||||
|
sensitivity?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatsDragInput = <
|
const StatsDragInput = <
|
||||||
|
@ -61,6 +64,7 @@ const StatsDragInput = <
|
||||||
property,
|
property,
|
||||||
scene,
|
scene,
|
||||||
appState,
|
appState,
|
||||||
|
sensitivity = 1,
|
||||||
}: StatsDragInputProps<T, E>) => {
|
}: StatsDragInputProps<T, E>) => {
|
||||||
const app = useApp();
|
const app = useApp();
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
@ -126,6 +130,7 @@ const StatsDragInput = <
|
||||||
nextValue: rounded,
|
nextValue: rounded,
|
||||||
property,
|
property,
|
||||||
originalAppState: appState,
|
originalAppState: appState,
|
||||||
|
setInputValue: (value) => setInputValue(String(value)),
|
||||||
});
|
});
|
||||||
app.syncActionResult({ storeAction: StoreAction.CAPTURE });
|
app.syncActionResult({ storeAction: StoreAction.CAPTURE });
|
||||||
}
|
}
|
||||||
|
@ -172,6 +177,8 @@ const StatsDragInput = <
|
||||||
ref={labelRef}
|
ref={labelRef}
|
||||||
onPointerDown={(event) => {
|
onPointerDown={(event) => {
|
||||||
if (inputRef.current && editable) {
|
if (inputRef.current && editable) {
|
||||||
|
document.body.classList.add("excalidraw-cursor-resize");
|
||||||
|
|
||||||
let startValue = Number(inputRef.current.value);
|
let startValue = Number(inputRef.current.value);
|
||||||
if (isNaN(startValue)) {
|
if (isNaN(startValue)) {
|
||||||
startValue = 0;
|
startValue = 0;
|
||||||
|
@ -196,27 +203,30 @@ const StatsDragInput = <
|
||||||
|
|
||||||
const originalAppState: AppState = cloneJSON(appState);
|
const originalAppState: AppState = cloneJSON(appState);
|
||||||
|
|
||||||
let accumulatedChange: number | null = null;
|
let accumulatedChange = 0;
|
||||||
|
let stepChange = 0;
|
||||||
document.body.classList.add("excalidraw-cursor-resize");
|
|
||||||
|
|
||||||
const onPointerMove = (event: PointerEvent) => {
|
const onPointerMove = (event: PointerEvent) => {
|
||||||
if (!accumulatedChange) {
|
|
||||||
accumulatedChange = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
lastPointer &&
|
lastPointer &&
|
||||||
originalElementsMap !== null &&
|
originalElementsMap !== null &&
|
||||||
originalElements !== null &&
|
originalElements !== null
|
||||||
accumulatedChange !== null
|
|
||||||
) {
|
) {
|
||||||
const instantChange = event.clientX - lastPointer.x;
|
const instantChange = event.clientX - lastPointer.x;
|
||||||
accumulatedChange += instantChange;
|
|
||||||
|
if (instantChange !== 0) {
|
||||||
|
stepChange += instantChange;
|
||||||
|
|
||||||
|
if (Math.abs(stepChange) >= sensitivity) {
|
||||||
|
stepChange =
|
||||||
|
Math.sign(stepChange) *
|
||||||
|
Math.floor(Math.abs(stepChange) / sensitivity);
|
||||||
|
|
||||||
|
accumulatedChange += stepChange;
|
||||||
|
|
||||||
dragInputCallback({
|
dragInputCallback({
|
||||||
accumulatedChange,
|
accumulatedChange,
|
||||||
instantChange,
|
instantChange: stepChange,
|
||||||
originalElements,
|
originalElements,
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
shouldKeepAspectRatio: shouldKeepAspectRatio!!,
|
shouldKeepAspectRatio: shouldKeepAspectRatio!!,
|
||||||
|
@ -224,7 +234,12 @@ const StatsDragInput = <
|
||||||
property,
|
property,
|
||||||
scene,
|
scene,
|
||||||
originalAppState,
|
originalAppState,
|
||||||
|
setInputValue: (value) => setInputValue(String(value)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
stepChange = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastPointer = {
|
lastPointer = {
|
||||||
|
@ -246,7 +261,8 @@ const StatsDragInput = <
|
||||||
app.syncActionResult({ storeAction: StoreAction.CAPTURE });
|
app.syncActionResult({ storeAction: StoreAction.CAPTURE });
|
||||||
|
|
||||||
lastPointer = null;
|
lastPointer = null;
|
||||||
accumulatedChange = null;
|
accumulatedChange = 0;
|
||||||
|
stepChange = 0;
|
||||||
originalElements = null;
|
originalElements = null;
|
||||||
originalElementsMap = null;
|
originalElementsMap = null;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,11 @@ import { useEffect, useMemo, useState, memo } from "react";
|
||||||
import { getCommonBounds } from "../../element/bounds";
|
import { getCommonBounds } from "../../element/bounds";
|
||||||
import type { NonDeletedExcalidrawElement } from "../../element/types";
|
import type { NonDeletedExcalidrawElement } from "../../element/types";
|
||||||
import { t } from "../../i18n";
|
import { t } from "../../i18n";
|
||||||
import type { AppState, ExcalidrawProps } from "../../types";
|
import type {
|
||||||
|
AppClassProperties,
|
||||||
|
AppState,
|
||||||
|
ExcalidrawProps,
|
||||||
|
} from "../../types";
|
||||||
import { CloseIcon } from "../icons";
|
import { CloseIcon } from "../icons";
|
||||||
import { Island } from "../Island";
|
import { Island } from "../Island";
|
||||||
import { throttle } from "lodash";
|
import { throttle } from "lodash";
|
||||||
|
@ -16,17 +20,17 @@ import MultiFontSize from "./MultiFontSize";
|
||||||
import Position from "./Position";
|
import Position from "./Position";
|
||||||
import MultiPosition from "./MultiPosition";
|
import MultiPosition from "./MultiPosition";
|
||||||
import Collapsible from "./Collapsible";
|
import Collapsible from "./Collapsible";
|
||||||
import type Scene from "../../scene/Scene";
|
|
||||||
import { useExcalidrawAppState, useExcalidrawSetAppState } from "../App";
|
import { useExcalidrawAppState, useExcalidrawSetAppState } from "../App";
|
||||||
import { getAtomicUnits } from "./utils";
|
import { getAtomicUnits } from "./utils";
|
||||||
import { STATS_PANELS } from "../../constants";
|
import { STATS_PANELS } from "../../constants";
|
||||||
import { isElbowArrow } from "../../element/typeChecks";
|
import { isElbowArrow } from "../../element/typeChecks";
|
||||||
|
import CanvasGrid from "./CanvasGrid";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
import "./Stats.scss";
|
import "./Stats.scss";
|
||||||
|
|
||||||
interface StatsProps {
|
interface StatsProps {
|
||||||
scene: Scene;
|
app: AppClassProperties;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
renderCustomStats: ExcalidrawProps["renderCustomStats"];
|
renderCustomStats: ExcalidrawProps["renderCustomStats"];
|
||||||
}
|
}
|
||||||
|
@ -35,11 +39,13 @@ const STATS_TIMEOUT = 50;
|
||||||
|
|
||||||
export const Stats = (props: StatsProps) => {
|
export const Stats = (props: StatsProps) => {
|
||||||
const appState = useExcalidrawAppState();
|
const appState = useExcalidrawAppState();
|
||||||
const sceneNonce = props.scene.getSceneNonce() || 1;
|
const sceneNonce = props.app.scene.getSceneNonce() || 1;
|
||||||
const selectedElements = props.scene.getSelectedElements({
|
const selectedElements = props.app.scene.getSelectedElements({
|
||||||
selectedElementIds: appState.selectedElementIds,
|
selectedElementIds: appState.selectedElementIds,
|
||||||
includeBoundTextElement: false,
|
includeBoundTextElement: false,
|
||||||
});
|
});
|
||||||
|
const gridModeEnabled =
|
||||||
|
props.app.props.gridModeEnabled ?? appState.gridModeEnabled;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StatsInner
|
<StatsInner
|
||||||
|
@ -47,6 +53,7 @@ export const Stats = (props: StatsProps) => {
|
||||||
appState={appState}
|
appState={appState}
|
||||||
sceneNonce={sceneNonce}
|
sceneNonce={sceneNonce}
|
||||||
selectedElements={selectedElements}
|
selectedElements={selectedElements}
|
||||||
|
gridModeEnabled={gridModeEnabled}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -97,17 +104,20 @@ Stats.StatsRows = StatsRows;
|
||||||
|
|
||||||
export const StatsInner = memo(
|
export const StatsInner = memo(
|
||||||
({
|
({
|
||||||
scene,
|
app,
|
||||||
onClose,
|
onClose,
|
||||||
renderCustomStats,
|
renderCustomStats,
|
||||||
selectedElements,
|
selectedElements,
|
||||||
appState,
|
appState,
|
||||||
sceneNonce,
|
sceneNonce,
|
||||||
|
gridModeEnabled,
|
||||||
}: StatsProps & {
|
}: StatsProps & {
|
||||||
sceneNonce: number;
|
sceneNonce: number;
|
||||||
selectedElements: readonly NonDeletedExcalidrawElement[];
|
selectedElements: readonly NonDeletedExcalidrawElement[];
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
|
gridModeEnabled: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
|
const scene = app.scene;
|
||||||
const elements = scene.getNonDeletedElements();
|
const elements = scene.getNonDeletedElements();
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
const setAppState = useExcalidrawSetAppState();
|
const setAppState = useExcalidrawSetAppState();
|
||||||
|
@ -189,6 +199,19 @@ export const StatsInner = memo(
|
||||||
<div>{t("stats.height")}</div>
|
<div>{t("stats.height")}</div>
|
||||||
<div>{sceneDimension.height}</div>
|
<div>{sceneDimension.height}</div>
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
|
{gridModeEnabled && (
|
||||||
|
<>
|
||||||
|
<StatsRow heading>Canvas</StatsRow>
|
||||||
|
<StatsRow>
|
||||||
|
<CanvasGrid
|
||||||
|
property="gridStep"
|
||||||
|
scene={scene}
|
||||||
|
appState={appState}
|
||||||
|
setAppState={setAppState}
|
||||||
|
/>
|
||||||
|
</StatsRow>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</StatsRows>
|
</StatsRows>
|
||||||
|
|
||||||
{renderCustomStats?.(elements, appState)}
|
{renderCustomStats?.(elements, appState)}
|
||||||
|
@ -362,7 +385,9 @@ export const StatsInner = memo(
|
||||||
return (
|
return (
|
||||||
prev.sceneNonce === next.sceneNonce &&
|
prev.sceneNonce === next.sceneNonce &&
|
||||||
prev.selectedElements === next.selectedElements &&
|
prev.selectedElements === next.selectedElements &&
|
||||||
prev.appState.stats.panels === next.appState.stats.panels
|
prev.appState.stats.panels === next.appState.stats.panels &&
|
||||||
|
prev.gridModeEnabled === next.gridModeEnabled &&
|
||||||
|
prev.appState.gridStep === next.appState.gridStep
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -41,7 +41,8 @@ export type StatsInputProperty =
|
||||||
| "width"
|
| "width"
|
||||||
| "height"
|
| "height"
|
||||||
| "angle"
|
| "angle"
|
||||||
| "fontSize";
|
| "fontSize"
|
||||||
|
| "gridStep";
|
||||||
|
|
||||||
export const SMALLEST_DELTA = 0.01;
|
export const SMALLEST_DELTA = 0.01;
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,7 @@ const getRelevantAppStateProps = (
|
||||||
exportScale: appState.exportScale,
|
exportScale: appState.exportScale,
|
||||||
selectedElementsAreBeingDragged: appState.selectedElementsAreBeingDragged,
|
selectedElementsAreBeingDragged: appState.selectedElementsAreBeingDragged,
|
||||||
gridSize: appState.gridSize,
|
gridSize: appState.gridSize,
|
||||||
|
gridStep: appState.gridStep,
|
||||||
frameRendering: appState.frameRendering,
|
frameRendering: appState.frameRendering,
|
||||||
selectedElementIds: appState.selectedElementIds,
|
selectedElementIds: appState.selectedElementIds,
|
||||||
frameToHighlight: appState.frameToHighlight,
|
frameToHighlight: appState.frameToHighlight,
|
||||||
|
|
|
@ -179,7 +179,8 @@ export const COLOR_VOICE_CALL = "#a2f1a6";
|
||||||
|
|
||||||
export const CANVAS_ONLY_ACTIONS = ["selectAll"];
|
export const CANVAS_ONLY_ACTIONS = ["selectAll"];
|
||||||
|
|
||||||
export const GRID_SIZE = 20; // TODO make it configurable?
|
export const DEFAULT_GRID_SIZE = 20;
|
||||||
|
export const DEFAULT_GRID_STEP = 5;
|
||||||
|
|
||||||
export const IMAGE_MIME_TYPES = {
|
export const IMAGE_MIME_TYPES = {
|
||||||
svg: "image/svg+xml",
|
svg: "image/svg+xml",
|
||||||
|
@ -234,7 +235,7 @@ export const VERSION_TIMEOUT = 30000;
|
||||||
export const SCROLL_TIMEOUT = 100;
|
export const SCROLL_TIMEOUT = 100;
|
||||||
export const ZOOM_STEP = 0.1;
|
export const ZOOM_STEP = 0.1;
|
||||||
export const MIN_ZOOM = 0.1;
|
export const MIN_ZOOM = 0.1;
|
||||||
export const MAX_ZOOM = 30.0;
|
export const MAX_ZOOM = 30;
|
||||||
export const HYPERLINK_TOOLTIP_DELAY = 300;
|
export const HYPERLINK_TOOLTIP_DELAY = 300;
|
||||||
|
|
||||||
// Report a user inactive after IDLE_THRESHOLD milliseconds
|
// Report a user inactive after IDLE_THRESHOLD milliseconds
|
||||||
|
|
|
@ -10,12 +10,7 @@ import type {
|
||||||
PointBinding,
|
PointBinding,
|
||||||
StrokeRoundness,
|
StrokeRoundness,
|
||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
import type {
|
import type { AppState, BinaryFiles, LibraryItem } from "../types";
|
||||||
AppState,
|
|
||||||
BinaryFiles,
|
|
||||||
LibraryItem,
|
|
||||||
NormalizedZoomValue,
|
|
||||||
} from "../types";
|
|
||||||
import type { ImportedDataState, LegacyAppState } from "./types";
|
import type { ImportedDataState, LegacyAppState } from "./types";
|
||||||
import {
|
import {
|
||||||
getNonDeletedElements,
|
getNonDeletedElements,
|
||||||
|
@ -39,11 +34,17 @@ import {
|
||||||
ROUNDNESS,
|
ROUNDNESS,
|
||||||
DEFAULT_SIDEBAR,
|
DEFAULT_SIDEBAR,
|
||||||
DEFAULT_ELEMENT_PROPS,
|
DEFAULT_ELEMENT_PROPS,
|
||||||
|
DEFAULT_GRID_SIZE,
|
||||||
|
DEFAULT_GRID_STEP,
|
||||||
} from "../constants";
|
} from "../constants";
|
||||||
import { getDefaultAppState } from "../appState";
|
import { getDefaultAppState } from "../appState";
|
||||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||||
import { bumpVersion } from "../element/mutateElement";
|
import { bumpVersion } from "../element/mutateElement";
|
||||||
import { getUpdatedTimestamp, updateActiveTool } from "../utils";
|
import {
|
||||||
|
getUpdatedTimestamp,
|
||||||
|
isFiniteNumber,
|
||||||
|
updateActiveTool,
|
||||||
|
} from "../utils";
|
||||||
import { arrayToMap } from "../utils";
|
import { arrayToMap } from "../utils";
|
||||||
import type { MarkOptional, Mutable } from "../utility-types";
|
import type { MarkOptional, Mutable } from "../utility-types";
|
||||||
import { detectLineHeight, getContainerElement } from "../element/textElement";
|
import { detectLineHeight, getContainerElement } from "../element/textElement";
|
||||||
|
@ -52,6 +53,11 @@ import { syncInvalidIndices } from "../fractionalIndex";
|
||||||
import { getSizeFromPoints } from "../points";
|
import { getSizeFromPoints } from "../points";
|
||||||
import { getLineHeight } from "../fonts";
|
import { getLineHeight } from "../fonts";
|
||||||
import { normalizeFixedPoint } from "../element/binding";
|
import { normalizeFixedPoint } from "../element/binding";
|
||||||
|
import {
|
||||||
|
getNormalizedGridSize,
|
||||||
|
getNormalizedGridStep,
|
||||||
|
getNormalizedZoom,
|
||||||
|
} from "../scene";
|
||||||
|
|
||||||
type RestoredAppState = Omit<
|
type RestoredAppState = Omit<
|
||||||
AppState,
|
AppState,
|
||||||
|
@ -614,19 +620,24 @@ export const restoreAppState = (
|
||||||
locked: nextAppState.activeTool.locked ?? false,
|
locked: nextAppState.activeTool.locked ?? false,
|
||||||
},
|
},
|
||||||
// Migrates from previous version where appState.zoom was a number
|
// Migrates from previous version where appState.zoom was a number
|
||||||
zoom:
|
zoom: {
|
||||||
typeof appState.zoom === "number"
|
value: getNormalizedZoom(
|
||||||
? {
|
isFiniteNumber(appState.zoom)
|
||||||
value: appState.zoom as NormalizedZoomValue,
|
|
||||||
}
|
|
||||||
: appState.zoom?.value
|
|
||||||
? appState.zoom
|
? appState.zoom
|
||||||
: defaultAppState.zoom,
|
: appState.zoom?.value ?? defaultAppState.zoom.value,
|
||||||
|
),
|
||||||
|
},
|
||||||
openSidebar:
|
openSidebar:
|
||||||
// string (legacy)
|
// string (legacy)
|
||||||
typeof (appState.openSidebar as any as string) === "string"
|
typeof (appState.openSidebar as any as string) === "string"
|
||||||
? { name: DEFAULT_SIDEBAR.name }
|
? { name: DEFAULT_SIDEBAR.name }
|
||||||
: nextAppState.openSidebar,
|
: nextAppState.openSidebar,
|
||||||
|
gridSize: getNormalizedGridSize(
|
||||||
|
isFiniteNumber(appState.gridSize) ? appState.gridSize : DEFAULT_GRID_SIZE,
|
||||||
|
),
|
||||||
|
gridStep: getNormalizedGridStep(
|
||||||
|
isFiniteNumber(appState.gridStep) ? appState.gridStep : DEFAULT_GRID_STEP,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,12 @@ import { getCommonBounds } from "./bounds";
|
||||||
import { mutateElement } from "./mutateElement";
|
import { mutateElement } from "./mutateElement";
|
||||||
import { getPerfectElementSize } from "./sizeHelpers";
|
import { getPerfectElementSize } from "./sizeHelpers";
|
||||||
import type { NonDeletedExcalidrawElement } from "./types";
|
import type { NonDeletedExcalidrawElement } from "./types";
|
||||||
import type { AppState, NormalizedZoomValue, PointerDownState } from "../types";
|
import type {
|
||||||
|
AppState,
|
||||||
|
NormalizedZoomValue,
|
||||||
|
NullableGridSize,
|
||||||
|
PointerDownState,
|
||||||
|
} from "../types";
|
||||||
import { getBoundTextElement, getMinTextElementWidth } from "./textElement";
|
import { getBoundTextElement, getMinTextElementWidth } from "./textElement";
|
||||||
import { getGridPoint } from "../math";
|
import { getGridPoint } from "../math";
|
||||||
import type Scene from "../scene/Scene";
|
import type Scene from "../scene/Scene";
|
||||||
|
@ -26,7 +31,7 @@ export const dragSelectedElements = (
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
},
|
},
|
||||||
gridSize: AppState["gridSize"],
|
gridSize: NullableGridSize,
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (
|
||||||
_selectedElements.length === 1 &&
|
_selectedElements.length === 1 &&
|
||||||
|
@ -101,7 +106,7 @@ const calculateOffset = (
|
||||||
commonBounds: Bounds,
|
commonBounds: Bounds,
|
||||||
dragOffset: { x: number; y: number },
|
dragOffset: { x: number; y: number },
|
||||||
snapOffset: { x: number; y: number },
|
snapOffset: { x: number; y: number },
|
||||||
gridSize: AppState["gridSize"],
|
gridSize: NullableGridSize,
|
||||||
): { x: number; y: number } => {
|
): { x: number; y: number } => {
|
||||||
const [x, y] = commonBounds;
|
const [x, y] = commonBounds;
|
||||||
let nextX = x + dragOffset.x + snapOffset.x;
|
let nextX = x + dragOffset.x + snapOffset.x;
|
||||||
|
|
|
@ -36,6 +36,8 @@ import type {
|
||||||
AppState,
|
AppState,
|
||||||
PointerCoords,
|
PointerCoords,
|
||||||
InteractiveCanvasAppState,
|
InteractiveCanvasAppState,
|
||||||
|
AppClassProperties,
|
||||||
|
NullableGridSize,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import { mutateElement } from "./mutateElement";
|
import { mutateElement } from "./mutateElement";
|
||||||
|
|
||||||
|
@ -209,7 +211,7 @@ export class LinearElementEditor {
|
||||||
/** @returns whether point was dragged */
|
/** @returns whether point was dragged */
|
||||||
static handlePointDragging(
|
static handlePointDragging(
|
||||||
event: PointerEvent,
|
event: PointerEvent,
|
||||||
appState: AppState,
|
app: AppClassProperties,
|
||||||
scenePointerX: number,
|
scenePointerX: number,
|
||||||
scenePointerY: number,
|
scenePointerY: number,
|
||||||
maybeSuggestBinding: (
|
maybeSuggestBinding: (
|
||||||
|
@ -279,7 +281,7 @@ export class LinearElementEditor {
|
||||||
elementsMap,
|
elementsMap,
|
||||||
referencePoint,
|
referencePoint,
|
||||||
[scenePointerX, scenePointerY],
|
[scenePointerX, scenePointerY],
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
LinearElementEditor.movePoints(
|
LinearElementEditor.movePoints(
|
||||||
|
@ -299,7 +301,7 @@ export class LinearElementEditor {
|
||||||
elementsMap,
|
elementsMap,
|
||||||
scenePointerX - linearElementEditor.pointerOffset.x,
|
scenePointerX - linearElementEditor.pointerOffset.x,
|
||||||
scenePointerY - linearElementEditor.pointerOffset.y,
|
scenePointerY - linearElementEditor.pointerOffset.y,
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const deltaX = newDraggingPointPosition[0] - draggingPoint[0];
|
const deltaX = newDraggingPointPosition[0] - draggingPoint[0];
|
||||||
|
@ -315,7 +317,7 @@ export class LinearElementEditor {
|
||||||
elementsMap,
|
elementsMap,
|
||||||
scenePointerX - linearElementEditor.pointerOffset.x,
|
scenePointerX - linearElementEditor.pointerOffset.x,
|
||||||
scenePointerY - linearElementEditor.pointerOffset.y,
|
scenePointerY - linearElementEditor.pointerOffset.y,
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
||||||
)
|
)
|
||||||
: ([
|
: ([
|
||||||
element.points[pointIndex][0] + deltaX,
|
element.points[pointIndex][0] + deltaX,
|
||||||
|
@ -695,7 +697,7 @@ export class LinearElementEditor {
|
||||||
|
|
||||||
static handlePointerDown(
|
static handlePointerDown(
|
||||||
event: React.PointerEvent<HTMLElement>,
|
event: React.PointerEvent<HTMLElement>,
|
||||||
appState: AppState,
|
app: AppClassProperties,
|
||||||
store: Store,
|
store: Store,
|
||||||
scenePointer: { x: number; y: number },
|
scenePointer: { x: number; y: number },
|
||||||
linearElementEditor: LinearElementEditor,
|
linearElementEditor: LinearElementEditor,
|
||||||
|
@ -705,6 +707,7 @@ export class LinearElementEditor {
|
||||||
hitElement: NonDeleted<ExcalidrawElement> | null;
|
hitElement: NonDeleted<ExcalidrawElement> | null;
|
||||||
linearElementEditor: LinearElementEditor | null;
|
linearElementEditor: LinearElementEditor | null;
|
||||||
} {
|
} {
|
||||||
|
const appState = app.state;
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
const elements = scene.getNonDeletedElements();
|
const elements = scene.getNonDeletedElements();
|
||||||
|
|
||||||
|
@ -752,7 +755,7 @@ export class LinearElementEditor {
|
||||||
elementsMap,
|
elementsMap,
|
||||||
scenePointer.x,
|
scenePointer.x,
|
||||||
scenePointer.y,
|
scenePointer.y,
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -876,9 +879,10 @@ export class LinearElementEditor {
|
||||||
event: React.PointerEvent<HTMLCanvasElement>,
|
event: React.PointerEvent<HTMLCanvasElement>,
|
||||||
scenePointerX: number,
|
scenePointerX: number,
|
||||||
scenePointerY: number,
|
scenePointerY: number,
|
||||||
appState: AppState,
|
app: AppClassProperties,
|
||||||
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
||||||
): LinearElementEditor | null {
|
): LinearElementEditor | null {
|
||||||
|
const appState = app.state;
|
||||||
if (!appState.editingLinearElement) {
|
if (!appState.editingLinearElement) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -915,7 +919,7 @@ export class LinearElementEditor {
|
||||||
elementsMap,
|
elementsMap,
|
||||||
lastCommittedPoint,
|
lastCommittedPoint,
|
||||||
[scenePointerX, scenePointerY],
|
[scenePointerX, scenePointerY],
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
|
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
newPoint = [
|
newPoint = [
|
||||||
|
@ -930,7 +934,7 @@ export class LinearElementEditor {
|
||||||
scenePointerY - appState.editingLinearElement.pointerOffset.y,
|
scenePointerY - appState.editingLinearElement.pointerOffset.y,
|
||||||
event[KEYS.CTRL_OR_CMD] || isElbowArrow(element)
|
event[KEYS.CTRL_OR_CMD] || isElbowArrow(element)
|
||||||
? null
|
? null
|
||||||
: appState.gridSize,
|
: app.getEffectiveGridSize(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1065,7 +1069,7 @@ export class LinearElementEditor {
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
scenePointerX: number,
|
scenePointerX: number,
|
||||||
scenePointerY: number,
|
scenePointerY: number,
|
||||||
gridSize: number | null,
|
gridSize: NullableGridSize,
|
||||||
): Point {
|
): Point {
|
||||||
const pointerOnGrid = getGridPoint(scenePointerX, scenePointerY, gridSize);
|
const pointerOnGrid = getGridPoint(scenePointerX, scenePointerY, gridSize);
|
||||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
||||||
|
@ -1363,7 +1367,7 @@ export class LinearElementEditor {
|
||||||
static addMidpoint(
|
static addMidpoint(
|
||||||
linearElementEditor: LinearElementEditor,
|
linearElementEditor: LinearElementEditor,
|
||||||
pointerCoords: PointerCoords,
|
pointerCoords: PointerCoords,
|
||||||
appState: AppState,
|
app: AppClassProperties,
|
||||||
snapToGrid: boolean,
|
snapToGrid: boolean,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
) {
|
) {
|
||||||
|
@ -1388,7 +1392,7 @@ export class LinearElementEditor {
|
||||||
elementsMap,
|
elementsMap,
|
||||||
pointerCoords.x,
|
pointerCoords.x,
|
||||||
pointerCoords.y,
|
pointerCoords.y,
|
||||||
snapToGrid && !isElbowArrow(element) ? appState.gridSize : null,
|
snapToGrid && !isElbowArrow(element) ? app.getEffectiveGridSize() : null,
|
||||||
);
|
);
|
||||||
const points = [
|
const points = [
|
||||||
...element.points.slice(0, segmentMidpoint.index!),
|
...element.points.slice(0, segmentMidpoint.index!),
|
||||||
|
@ -1485,7 +1489,7 @@ export class LinearElementEditor {
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
referencePoint: Point,
|
referencePoint: Point,
|
||||||
scenePointer: Point,
|
scenePointer: Point,
|
||||||
gridSize: number | null,
|
gridSize: NullableGridSize,
|
||||||
) {
|
) {
|
||||||
const referencePointCoords = LinearElementEditor.getPointGlobalCoordinates(
|
const referencePointCoords = LinearElementEditor.getPointGlobalCoordinates(
|
||||||
element,
|
element,
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import type { NormalizedZoomValue, Point, Zoom } from "./types";
|
import type {
|
||||||
|
NormalizedZoomValue,
|
||||||
|
NullableGridSize,
|
||||||
|
Point,
|
||||||
|
Zoom,
|
||||||
|
} from "./types";
|
||||||
import {
|
import {
|
||||||
DEFAULT_ADAPTIVE_RADIUS,
|
DEFAULT_ADAPTIVE_RADIUS,
|
||||||
LINE_CONFIRM_THRESHOLD,
|
LINE_CONFIRM_THRESHOLD,
|
||||||
|
@ -275,7 +280,7 @@ const doSegmentsIntersect = (p1: Point, q1: Point, p2: Point, q2: Point) => {
|
||||||
export const getGridPoint = (
|
export const getGridPoint = (
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
gridSize: number | null,
|
gridSize: NullableGridSize,
|
||||||
): [number, number] => {
|
): [number, number] => {
|
||||||
if (gridSize) {
|
if (gridSize) {
|
||||||
return [
|
return [
|
||||||
|
@ -703,3 +708,8 @@ export const aabbsOverlapping = (a: Bounds, b: Bounds) =>
|
||||||
export const clamp = (value: number, min: number, max: number) => {
|
export const clamp = (value: number, min: number, max: number) => {
|
||||||
return Math.min(Math.max(value, min), max);
|
return Math.min(Math.max(value, min), max);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const round = (value: number, precision: number) => {
|
||||||
|
const multiplier = Math.pow(10, precision);
|
||||||
|
return Math.round((value + Number.EPSILON) * multiplier) / multiplier;
|
||||||
|
};
|
||||||
|
|
|
@ -31,53 +31,77 @@ import { bootstrapCanvas, getNormalizedCanvasDimensions } from "./helpers";
|
||||||
import { throttleRAF } from "../utils";
|
import { throttleRAF } from "../utils";
|
||||||
import { getBoundTextElement } from "../element/textElement";
|
import { getBoundTextElement } from "../element/textElement";
|
||||||
|
|
||||||
|
const GridLineColor = {
|
||||||
|
Bold: "#dddddd",
|
||||||
|
Regular: "#e5e5e5",
|
||||||
|
} as const;
|
||||||
|
|
||||||
const strokeGrid = (
|
const strokeGrid = (
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
|
/** grid cell pixel size */
|
||||||
gridSize: number,
|
gridSize: number,
|
||||||
|
/** setting to 1 will disble bold lines */
|
||||||
|
gridStep: number,
|
||||||
scrollX: number,
|
scrollX: number,
|
||||||
scrollY: number,
|
scrollY: number,
|
||||||
zoom: Zoom,
|
zoom: Zoom,
|
||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
) => {
|
) => {
|
||||||
const BOLD_LINE_FREQUENCY = 5;
|
const offsetX = (scrollX % gridSize) - gridSize;
|
||||||
|
const offsetY = (scrollY % gridSize) - gridSize;
|
||||||
|
|
||||||
enum GridLineColor {
|
const actualGridSize = gridSize * zoom.value;
|
||||||
Bold = "#cccccc",
|
|
||||||
Regular = "#e5e5e5",
|
|
||||||
}
|
|
||||||
|
|
||||||
const offsetX =
|
|
||||||
-Math.round(zoom.value / gridSize) * gridSize + (scrollX % gridSize);
|
|
||||||
const offsetY =
|
|
||||||
-Math.round(zoom.value / gridSize) * gridSize + (scrollY % gridSize);
|
|
||||||
|
|
||||||
const lineWidth = Math.min(1 / zoom.value, 1);
|
|
||||||
|
|
||||||
const spaceWidth = 1 / zoom.value;
|
const spaceWidth = 1 / zoom.value;
|
||||||
const lineDash = [lineWidth * 3, spaceWidth + (lineWidth + spaceWidth)];
|
|
||||||
|
|
||||||
context.save();
|
context.save();
|
||||||
context.lineWidth = lineWidth;
|
|
||||||
|
|
||||||
|
// Offset rendering by 0.5 to ensure that 1px wide lines are crisp.
|
||||||
|
// We only do this when zoomed to 100% because otherwise the offset is
|
||||||
|
// fractional, and also visibly offsets the elements.
|
||||||
|
// We also do this per-axis, as each axis may already be offset by 0.5.
|
||||||
|
if (zoom.value === 1) {
|
||||||
|
context.translate(offsetX % 1 ? 0 : 0.5, offsetY % 1 ? 0 : 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// vertical lines
|
||||||
for (let x = offsetX; x < offsetX + width + gridSize * 2; x += gridSize) {
|
for (let x = offsetX; x < offsetX + width + gridSize * 2; x += gridSize) {
|
||||||
const isBold =
|
const isBold =
|
||||||
Math.round(x - scrollX) % (BOLD_LINE_FREQUENCY * gridSize) === 0;
|
gridStep > 1 && Math.round(x - scrollX) % (gridStep * gridSize) === 0;
|
||||||
|
// don't render regular lines when zoomed out and they're barely visible
|
||||||
|
if (!isBold && actualGridSize < 10) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lineWidth = Math.min(1 / zoom.value, isBold ? 4 : 1);
|
||||||
|
context.lineWidth = lineWidth;
|
||||||
|
const lineDash = [lineWidth * 3, spaceWidth + (lineWidth + spaceWidth)];
|
||||||
|
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
context.setLineDash(isBold ? [] : lineDash);
|
context.setLineDash(isBold ? [] : lineDash);
|
||||||
context.strokeStyle = isBold ? GridLineColor.Bold : GridLineColor.Regular;
|
context.strokeStyle = isBold ? GridLineColor.Bold : GridLineColor.Regular;
|
||||||
context.moveTo(x, offsetY - gridSize);
|
context.moveTo(x, offsetY - gridSize);
|
||||||
context.lineTo(x, offsetY + height + gridSize * 2);
|
context.lineTo(x, Math.ceil(offsetY + height + gridSize * 2));
|
||||||
context.stroke();
|
context.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let y = offsetY; y < offsetY + height + gridSize * 2; y += gridSize) {
|
for (let y = offsetY; y < offsetY + height + gridSize * 2; y += gridSize) {
|
||||||
const isBold =
|
const isBold =
|
||||||
Math.round(y - scrollY) % (BOLD_LINE_FREQUENCY * gridSize) === 0;
|
gridStep > 1 && Math.round(y - scrollY) % (gridStep * gridSize) === 0;
|
||||||
|
if (!isBold && actualGridSize < 10) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lineWidth = Math.min(1 / zoom.value, isBold ? 4 : 1);
|
||||||
|
context.lineWidth = lineWidth;
|
||||||
|
const lineDash = [lineWidth * 3, spaceWidth + (lineWidth + spaceWidth)];
|
||||||
|
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
context.setLineDash(isBold ? [] : lineDash);
|
context.setLineDash(isBold ? [] : lineDash);
|
||||||
context.strokeStyle = isBold ? GridLineColor.Bold : GridLineColor.Regular;
|
context.strokeStyle = isBold ? GridLineColor.Bold : GridLineColor.Regular;
|
||||||
context.moveTo(offsetX - gridSize, y);
|
context.moveTo(offsetX - gridSize, y);
|
||||||
context.lineTo(offsetX + width + gridSize * 2, y);
|
context.lineTo(Math.ceil(offsetX + width + gridSize * 2), y);
|
||||||
context.stroke();
|
context.stroke();
|
||||||
}
|
}
|
||||||
context.restore();
|
context.restore();
|
||||||
|
@ -199,10 +223,11 @@ const _renderStaticScene = ({
|
||||||
context.scale(appState.zoom.value, appState.zoom.value);
|
context.scale(appState.zoom.value, appState.zoom.value);
|
||||||
|
|
||||||
// Grid
|
// Grid
|
||||||
if (renderGrid && appState.gridSize) {
|
if (renderGrid) {
|
||||||
strokeGrid(
|
strokeGrid(
|
||||||
context,
|
context,
|
||||||
appState.gridSize,
|
appState.gridSize,
|
||||||
|
appState.gridStep,
|
||||||
appState.scrollX,
|
appState.scrollX,
|
||||||
appState.scrollY,
|
appState.scrollY,
|
||||||
appState.zoom,
|
appState.zoom,
|
||||||
|
|
|
@ -15,4 +15,8 @@ export {
|
||||||
getElementAtPosition,
|
getElementAtPosition,
|
||||||
getElementsAtPosition,
|
getElementsAtPosition,
|
||||||
} from "./comparisons";
|
} from "./comparisons";
|
||||||
export { getNormalizedZoom } from "./zoom";
|
export {
|
||||||
|
getNormalizedZoom,
|
||||||
|
getNormalizedGridSize,
|
||||||
|
getNormalizedGridStep,
|
||||||
|
} from "./normalize";
|
||||||
|
|
15
packages/excalidraw/scene/normalize.ts
Normal file
15
packages/excalidraw/scene/normalize.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { MAX_ZOOM, MIN_ZOOM } from "../constants";
|
||||||
|
import { clamp, round } from "../math";
|
||||||
|
import type { NormalizedZoomValue } from "../types";
|
||||||
|
|
||||||
|
export const getNormalizedZoom = (zoom: number): NormalizedZoomValue => {
|
||||||
|
return clamp(round(zoom, 6), MIN_ZOOM, MAX_ZOOM) as NormalizedZoomValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNormalizedGridSize = (gridStep: number) => {
|
||||||
|
return clamp(Math.round(gridStep), 1, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNormalizedGridStep = (gridStep: number) => {
|
||||||
|
return clamp(Math.round(gridStep), 1, 100);
|
||||||
|
};
|
|
@ -1,10 +1,5 @@
|
||||||
import { MIN_ZOOM } from "../constants";
|
|
||||||
import type { AppState, NormalizedZoomValue } from "../types";
|
import type { AppState, NormalizedZoomValue } from "../types";
|
||||||
|
|
||||||
export const getNormalizedZoom = (zoom: number): NormalizedZoomValue => {
|
|
||||||
return Math.max(MIN_ZOOM, Math.min(zoom, 30)) as NormalizedZoomValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getStateForZoom = (
|
export const getStateForZoom = (
|
||||||
{
|
{
|
||||||
viewportX,
|
viewportX,
|
||||||
|
|
|
@ -831,7 +831,9 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1034,7 +1036,9 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1247,7 +1251,9 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1575,7 +1581,9 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1903,7 +1911,9 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2116,7 +2126,9 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2353,7 +2365,9 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2651,7 +2665,9 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3017,7 +3033,9 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3489,7 +3507,9 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3809,7 +3829,9 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -4129,7 +4151,9 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -5312,7 +5336,9 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -6436,7 +6462,9 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7368,7 +7396,9 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -8277,7 +8307,9 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9168,7 +9200,9 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
|
|
@ -48,7 +48,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -647,7 +649,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1150,7 +1154,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1515,7 +1521,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1881,7 +1889,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2145,7 +2155,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2582,7 +2594,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2878,7 +2892,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3159,7 +3175,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3450,7 +3468,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3733,7 +3753,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3965,7 +3987,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -4221,7 +4245,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -4491,7 +4517,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -4719,7 +4747,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -4947,7 +4977,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -5173,7 +5205,9 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -5399,7 +5433,9 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -5655,7 +5691,9 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -5983,7 +6021,9 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -6405,7 +6445,9 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -6780,7 +6822,9 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7096,7 +7140,9 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7391,7 +7437,9 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7617,7 +7665,9 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7969,7 +8019,9 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -8321,7 +8373,9 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -8722,7 +8776,9 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9006,7 +9062,9 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9268,7 +9326,9 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9529,7 +9589,9 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9757,7 +9819,9 @@ exports[`history > multiplayer undo/redo > should override remotely added groups
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -10055,7 +10119,9 @@ exports[`history > multiplayer undo/redo > should override remotely added points
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -10392,7 +10458,9 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -10624,7 +10692,9 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -11074,7 +11144,9 @@ exports[`history > multiplayer undo/redo > should update history entries after r
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -11325,7 +11397,9 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -11561,7 +11635,9 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -11799,7 +11875,9 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -12197,7 +12275,9 @@ exports[`history > singleplayer undo/redo > should create new history entry on s
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -12441,7 +12521,9 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -12679,7 +12761,9 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -12917,7 +13001,9 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -13161,7 +13247,9 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -13490,7 +13578,9 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -13659,7 +13749,9 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -13944,7 +14036,9 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -14208,7 +14302,9 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -14480,7 +14576,9 @@ exports[`history > singleplayer undo/redo > should support appstate name or view
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -14638,7 +14736,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -15331,7 +15431,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -15948,7 +16050,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -16565,7 +16669,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -17274,7 +17380,9 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -18021,7 +18129,9 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -18492,7 +18602,9 @@ exports[`history > singleplayer undo/redo > should support duplication of groups
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -19011,7 +19123,9 @@ exports[`history > singleplayer undo/redo > should support element creation, del
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -19464,7 +19578,9 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
|
|
@ -48,7 +48,9 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -457,7 +459,9 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -857,7 +861,9 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": false,
|
"isBindingEnabled": false,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1396,7 +1402,9 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1594,7 +1602,9 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -1963,7 +1973,9 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2197,7 +2209,9 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = `
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2371,7 +2385,9 @@ exports[`regression tests > can drag element that covers another element, while
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2685,7 +2701,9 @@ exports[`regression tests > change the properties of a shape > [end of test] app
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -2925,7 +2943,9 @@ exports[`regression tests > click on an element and drag it > [dragged] appState
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3162,7 +3182,9 @@ exports[`regression tests > click on an element and drag it > [end of test] appS
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3386,7 +3408,9 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`]
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3636,7 +3660,9 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -3941,7 +3967,9 @@ exports[`regression tests > deleting last but one element in editing group shoul
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -4349,7 +4377,9 @@ exports[`regression tests > deselects group of selected elements on pointer down
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -4626,7 +4656,9 @@ exports[`regression tests > deselects group of selected elements on pointer up w
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -4873,7 +4905,9 @@ exports[`regression tests > deselects selected element on pointer down when poin
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -5077,7 +5111,9 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -5270,7 +5306,9 @@ exports[`regression tests > double click to edit a group > [end of test] appStat
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -5646,7 +5684,9 @@ exports[`regression tests > drags selected elements from point inside common bou
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -5930,7 +5970,9 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -6732,7 +6774,9 @@ exports[`regression tests > given a group of selected elements with an element t
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7056,7 +7100,9 @@ exports[`regression tests > given a selected element A and a not selected elemen
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7326,7 +7372,9 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7554,7 +7602,9 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7785,7 +7835,9 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -7959,7 +8011,9 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -8133,7 +8187,9 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -8307,7 +8363,9 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -8523,7 +8581,9 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -8738,7 +8798,9 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -8926,7 +8988,9 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9142,7 +9206,9 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9316,7 +9382,9 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9531,7 +9599,9 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9705,7 +9775,9 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -9893,7 +9965,9 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -10067,7 +10141,9 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -10575,7 +10651,9 @@ exports[`regression tests > noop interaction after undo shouldn't create history
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -10846,7 +10924,9 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -10966,7 +11046,9 @@ exports[`regression tests > shift click on selected element should deselect it o
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -11159,7 +11241,9 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -11464,7 +11548,9 @@ exports[`regression tests > should group elements and ungroup them > [end of tes
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -11870,7 +11956,9 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -12477,7 +12565,9 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -12600,7 +12690,9 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`]
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -13178,7 +13270,9 @@ exports[`regression tests > switches from group of selected elements to another
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -13510,7 +13604,9 @@ exports[`regression tests > switches selected element on pointer down > [end of
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -13769,7 +13865,9 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -13889,7 +13987,9 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -14262,7 +14362,9 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
@ -14382,7 +14484,9 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = `
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"height": 768,
|
"height": 768,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from "react";
|
||||||
import { fireEvent, GlobalTestState, toggleMenu, render } from "./test-utils";
|
import { fireEvent, GlobalTestState, toggleMenu, render } from "./test-utils";
|
||||||
import { Excalidraw, Footer, MainMenu } from "../index";
|
import { Excalidraw, Footer, MainMenu } from "../index";
|
||||||
import { queryByText, queryByTestId } from "@testing-library/react";
|
import { queryByText, queryByTestId } from "@testing-library/react";
|
||||||
import { GRID_SIZE, THEME } from "../constants";
|
import { THEME } from "../constants";
|
||||||
import { t } from "../i18n";
|
import { t } from "../i18n";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ describe("<Excalidraw/>", () => {
|
||||||
describe("Test gridModeEnabled prop", () => {
|
describe("Test gridModeEnabled prop", () => {
|
||||||
it('should show grid mode in context menu when gridModeEnabled is "undefined"', async () => {
|
it('should show grid mode in context menu when gridModeEnabled is "undefined"', async () => {
|
||||||
const { container } = await render(<Excalidraw />);
|
const { container } = await render(<Excalidraw />);
|
||||||
expect(h.state.gridSize).toBe(null);
|
expect(h.state.gridModeEnabled).toBe(false);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
container.getElementsByClassName("disable-zen-mode--visible").length,
|
container.getElementsByClassName("disable-zen-mode--visible").length,
|
||||||
|
@ -103,14 +103,14 @@ describe("<Excalidraw/>", () => {
|
||||||
});
|
});
|
||||||
const contextMenu = document.querySelector(".context-menu");
|
const contextMenu = document.querySelector(".context-menu");
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Toggle grid")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Toggle grid")!);
|
||||||
expect(h.state.gridSize).toBe(GRID_SIZE);
|
expect(h.state.gridModeEnabled).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not show grid mode in context menu when gridModeEnabled is not "undefined"', async () => {
|
it('should not show grid mode in context menu when gridModeEnabled is not "undefined"', async () => {
|
||||||
const { container } = await render(
|
const { container } = await render(
|
||||||
<Excalidraw gridModeEnabled={false} />,
|
<Excalidraw gridModeEnabled={false} />,
|
||||||
);
|
);
|
||||||
expect(h.state.gridSize).toBe(null);
|
expect(h.state.gridModeEnabled).toBe(false);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
container.getElementsByClassName("disable-zen-mode--visible").length,
|
container.getElementsByClassName("disable-zen-mode--visible").length,
|
||||||
|
@ -122,7 +122,7 @@ describe("<Excalidraw/>", () => {
|
||||||
});
|
});
|
||||||
const contextMenu = document.querySelector(".context-menu");
|
const contextMenu = document.querySelector(".context-menu");
|
||||||
expect(queryByText(contextMenu as HTMLElement, "Show grid")).toBe(null);
|
expect(queryByText(contextMenu as HTMLElement, "Show grid")).toBe(null);
|
||||||
expect(h.state.gridSize).toBe(null);
|
expect(h.state.gridModeEnabled).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ export const diagramFixture = {
|
||||||
elements: [diamondFixture, ellipseFixture, rectangleFixture],
|
elements: [diamondFixture, ellipseFixture, rectangleFixture],
|
||||||
appState: {
|
appState: {
|
||||||
viewBackgroundColor: "#ffffff",
|
viewBackgroundColor: "#ffffff",
|
||||||
gridSize: null,
|
gridModeEnabled: false,
|
||||||
},
|
},
|
||||||
files: {},
|
files: {},
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,7 +40,7 @@ import type { FileSystemHandle } from "./data/filesystem";
|
||||||
import type { IMAGE_MIME_TYPES, MIME_TYPES } from "./constants";
|
import type { IMAGE_MIME_TYPES, MIME_TYPES } from "./constants";
|
||||||
import type { ContextMenuItems } from "./components/ContextMenu";
|
import type { ContextMenuItems } from "./components/ContextMenu";
|
||||||
import type { SnapLine } from "./snapping";
|
import type { SnapLine } from "./snapping";
|
||||||
import type { Merge, MaybePromise, ValueOf } from "./utility-types";
|
import type { Merge, MaybePromise, ValueOf, MakeBrand } from "./utility-types";
|
||||||
import type { StoreActionType } from "./store";
|
import type { StoreActionType } from "./store";
|
||||||
|
|
||||||
export type Point = Readonly<RoughPoint>;
|
export type Point = Readonly<RoughPoint>;
|
||||||
|
@ -176,6 +176,7 @@ export type StaticCanvasAppState = Readonly<
|
||||||
exportScale: AppState["exportScale"];
|
exportScale: AppState["exportScale"];
|
||||||
selectedElementsAreBeingDragged: AppState["selectedElementsAreBeingDragged"];
|
selectedElementsAreBeingDragged: AppState["selectedElementsAreBeingDragged"];
|
||||||
gridSize: AppState["gridSize"];
|
gridSize: AppState["gridSize"];
|
||||||
|
gridStep: AppState["gridStep"];
|
||||||
frameRendering: AppState["frameRendering"];
|
frameRendering: AppState["frameRendering"];
|
||||||
currentHoveredFontFamily: AppState["currentHoveredFontFamily"];
|
currentHoveredFontFamily: AppState["currentHoveredFontFamily"];
|
||||||
}
|
}
|
||||||
|
@ -351,7 +352,10 @@ export interface AppState {
|
||||||
toast: { message: string; closable?: boolean; duration?: number } | null;
|
toast: { message: string; closable?: boolean; duration?: number } | null;
|
||||||
zenModeEnabled: boolean;
|
zenModeEnabled: boolean;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
gridSize: number | null;
|
/** grid cell px size */
|
||||||
|
gridSize: number;
|
||||||
|
gridStep: number;
|
||||||
|
gridModeEnabled: boolean;
|
||||||
viewModeEnabled: boolean;
|
viewModeEnabled: boolean;
|
||||||
|
|
||||||
/** top-most selected groups (i.e. does not include nested groups) */
|
/** top-most selected groups (i.e. does not include nested groups) */
|
||||||
|
@ -615,6 +619,7 @@ export type AppProps = Merge<
|
||||||
* in the app, eg Manager. Factored out into a separate type to keep DRY. */
|
* in the app, eg Manager. Factored out into a separate type to keep DRY. */
|
||||||
export type AppClassProperties = {
|
export type AppClassProperties = {
|
||||||
props: AppProps;
|
props: AppProps;
|
||||||
|
state: AppState;
|
||||||
interactiveCanvas: HTMLCanvasElement | null;
|
interactiveCanvas: HTMLCanvasElement | null;
|
||||||
/** static canvas */
|
/** static canvas */
|
||||||
canvas: HTMLCanvasElement;
|
canvas: HTMLCanvasElement;
|
||||||
|
@ -649,6 +654,7 @@ export type AppClassProperties = {
|
||||||
getName: App["getName"];
|
getName: App["getName"];
|
||||||
dismissLinearEditor: App["dismissLinearEditor"];
|
dismissLinearEditor: App["dismissLinearEditor"];
|
||||||
flowChartCreator: App["flowChartCreator"];
|
flowChartCreator: App["flowChartCreator"];
|
||||||
|
getEffectiveGridSize: App["getEffectiveGridSize"];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PointerDownState = Readonly<{
|
export type PointerDownState = Readonly<{
|
||||||
|
@ -831,3 +837,8 @@ export type EmbedsValidationStatus = Map<
|
||||||
export type ElementsPendingErasure = Set<ExcalidrawElement["id"]>;
|
export type ElementsPendingErasure = Set<ExcalidrawElement["id"]>;
|
||||||
|
|
||||||
export type PendingExcalidrawElements = ExcalidrawElement[];
|
export type PendingExcalidrawElements = ExcalidrawElement[];
|
||||||
|
|
||||||
|
/** Runtime gridSize value. Null indicates disabled grid. */
|
||||||
|
export type NullableGridSize =
|
||||||
|
| (AppState["gridSize"] & MakeBrand<"NullableGridSize">)
|
||||||
|
| null;
|
||||||
|
|
|
@ -49,7 +49,9 @@ exports[`exportToSvg > with default arguments 1`] = `
|
||||||
"outline": true,
|
"outline": true,
|
||||||
},
|
},
|
||||||
"frameToHighlight": null,
|
"frameToHighlight": null,
|
||||||
"gridSize": null,
|
"gridModeEnabled": false,
|
||||||
|
"gridSize": 20,
|
||||||
|
"gridStep": 5,
|
||||||
"isBindingEnabled": true,
|
"isBindingEnabled": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
"isResizing": false,
|
"isResizing": false,
|
||||||
|
|
|
@ -19,7 +19,7 @@ describe("embedding scene data", () => {
|
||||||
elements: sourceElements,
|
elements: sourceElements,
|
||||||
appState: {
|
appState: {
|
||||||
viewBackgroundColor: "#ffffff",
|
viewBackgroundColor: "#ffffff",
|
||||||
gridSize: null,
|
gridModeEnabled: false,
|
||||||
exportEmbedScene: true,
|
exportEmbedScene: true,
|
||||||
},
|
},
|
||||||
files: null,
|
files: null,
|
||||||
|
@ -50,7 +50,7 @@ describe("embedding scene data", () => {
|
||||||
elements: sourceElements,
|
elements: sourceElements,
|
||||||
appState: {
|
appState: {
|
||||||
viewBackgroundColor: "#ffffff",
|
viewBackgroundColor: "#ffffff",
|
||||||
gridSize: null,
|
gridModeEnabled: false,
|
||||||
exportEmbedScene: true,
|
exportEmbedScene: true,
|
||||||
},
|
},
|
||||||
files: null,
|
files: null,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue