feat: Element locking (#4964)
Co-authored-by: dwelle <luzar.david@gmail.com> Co-authored-by: Zsolt Viczian <viczian.zsolt@gmail.com>
This commit is contained in:
parent
c2fce6d8c4
commit
327ed0e2d1
@ -18,7 +18,8 @@ export const actionSelectAll = register({
|
|||||||
selectedElementIds: elements.reduce((map, element) => {
|
selectedElementIds: elements.reduce((map, element) => {
|
||||||
if (
|
if (
|
||||||
!element.isDeleted &&
|
!element.isDeleted &&
|
||||||
!(isTextElement(element) && element.containerId)
|
!(isTextElement(element) && element.containerId) &&
|
||||||
|
element.locked === false
|
||||||
) {
|
) {
|
||||||
map[element.id] = true;
|
map[element.id] = true;
|
||||||
}
|
}
|
||||||
|
63
src/actions/actionToggleLock.ts
Normal file
63
src/actions/actionToggleLock.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { newElementWith } from "../element/mutateElement";
|
||||||
|
import { ExcalidrawElement } from "../element/types";
|
||||||
|
import { KEYS } from "../keys";
|
||||||
|
import { getSelectedElements } from "../scene";
|
||||||
|
import { arrayToMap } from "../utils";
|
||||||
|
import { register } from "./register";
|
||||||
|
|
||||||
|
export const actionToggleLock = register({
|
||||||
|
name: "toggleLock",
|
||||||
|
trackEvent: { category: "element" },
|
||||||
|
perform: (elements, appState) => {
|
||||||
|
const selectedElements = getSelectedElements(elements, appState, true);
|
||||||
|
|
||||||
|
if (!selectedElements.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const operation = getOperation(selectedElements);
|
||||||
|
const selectedElementsMap = arrayToMap(selectedElements);
|
||||||
|
|
||||||
|
return {
|
||||||
|
elements: elements.map((element) => {
|
||||||
|
if (!selectedElementsMap.has(element.id)) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newElementWith(element, { locked: operation === "lock" });
|
||||||
|
}),
|
||||||
|
appState,
|
||||||
|
commitToHistory: true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
contextItemLabel: (elements, appState) => {
|
||||||
|
const selected = getSelectedElements(elements, appState, false);
|
||||||
|
if (selected.length === 1) {
|
||||||
|
return selected[0].locked
|
||||||
|
? "labels.elementLock.unlock"
|
||||||
|
: "labels.elementLock.lock";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected.length > 1) {
|
||||||
|
return getOperation(selected) === "lock"
|
||||||
|
? "labels.elementLock.lockAll"
|
||||||
|
: "labels.elementLock.unlockAll";
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
"Unexpected zero elements to lock/unlock. This should never happen.",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
keyTest: (event, appState, elements) => {
|
||||||
|
return (
|
||||||
|
event.key.toLocaleLowerCase() === KEYS.L &&
|
||||||
|
event[KEYS.CTRL_OR_CMD] &&
|
||||||
|
event.shiftKey &&
|
||||||
|
getSelectedElements(elements, appState, false).length > 0
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const getOperation = (
|
||||||
|
elements: readonly ExcalidrawElement[],
|
||||||
|
): "lock" | "unlock" => (elements.some((el) => !el.locked) ? "lock" : "unlock");
|
@ -84,3 +84,4 @@ export { actionToggleZenMode } from "./actionToggleZenMode";
|
|||||||
export { actionToggleStats } from "./actionToggleStats";
|
export { actionToggleStats } from "./actionToggleStats";
|
||||||
export { actionUnbindText, actionBindText } from "./actionBoundText";
|
export { actionUnbindText, actionBindText } from "./actionBoundText";
|
||||||
export { actionLink } from "../element/Hyperlink";
|
export { actionLink } from "../element/Hyperlink";
|
||||||
|
export { actionToggleLock } from "./actionToggleLock";
|
||||||
|
@ -29,6 +29,7 @@ export type ShortcutName = SubtypeOf<
|
|||||||
| "flipHorizontal"
|
| "flipHorizontal"
|
||||||
| "flipVertical"
|
| "flipVertical"
|
||||||
| "hyperlink"
|
| "hyperlink"
|
||||||
|
| "toggleLock"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const shortcutMap: Record<ShortcutName, string[]> = {
|
const shortcutMap: Record<ShortcutName, string[]> = {
|
||||||
@ -67,6 +68,7 @@ const shortcutMap: Record<ShortcutName, string[]> = {
|
|||||||
flipVertical: [getShortcutKey("Shift+V")],
|
flipVertical: [getShortcutKey("Shift+V")],
|
||||||
viewMode: [getShortcutKey("Alt+R")],
|
viewMode: [getShortcutKey("Alt+R")],
|
||||||
hyperlink: [getShortcutKey("CtrlOrCmd+K")],
|
hyperlink: [getShortcutKey("CtrlOrCmd+K")],
|
||||||
|
toggleLock: [getShortcutKey("CtrlOrCmd+Shift+L")],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getShortcutFromShortcutName = (name: ShortcutName) => {
|
export const getShortcutFromShortcutName = (name: ShortcutName) => {
|
||||||
|
@ -111,7 +111,8 @@ export type ActionName =
|
|||||||
| "unbindText"
|
| "unbindText"
|
||||||
| "hyperlink"
|
| "hyperlink"
|
||||||
| "eraser"
|
| "eraser"
|
||||||
| "bindText";
|
| "bindText"
|
||||||
|
| "toggleLock";
|
||||||
|
|
||||||
export type PanelComponentProps = {
|
export type PanelComponentProps = {
|
||||||
elements: readonly ExcalidrawElement[];
|
elements: readonly ExcalidrawElement[];
|
||||||
|
@ -167,6 +167,7 @@ const commonProps = {
|
|||||||
strokeStyle: "solid",
|
strokeStyle: "solid",
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
verticalAlign: VERTICAL_ALIGN.MIDDLE,
|
verticalAlign: VERTICAL_ALIGN.MIDDLE,
|
||||||
|
locked: false,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const getChartDimentions = (spreadsheet: Spreadsheet) => {
|
const getChartDimentions = (spreadsheet: Spreadsheet) => {
|
||||||
|
@ -31,6 +31,7 @@ import {
|
|||||||
actionBindText,
|
actionBindText,
|
||||||
actionUngroup,
|
actionUngroup,
|
||||||
actionLink,
|
actionLink,
|
||||||
|
actionToggleLock,
|
||||||
} from "../actions";
|
} from "../actions";
|
||||||
import { createRedoAction, createUndoAction } from "../actions/actionHistory";
|
import { createRedoAction, createUndoAction } from "../actions/actionHistory";
|
||||||
import { ActionManager } from "../actions/manager";
|
import { ActionManager } from "../actions/manager";
|
||||||
@ -1134,7 +1135,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
prevState.activeTool !== this.state.activeTool &&
|
prevState.activeTool !== this.state.activeTool &&
|
||||||
multiElement != null &&
|
multiElement != null &&
|
||||||
isBindingEnabled(this.state) &&
|
isBindingEnabled(this.state) &&
|
||||||
isBindingElement(multiElement)
|
isBindingElement(multiElement, false)
|
||||||
) {
|
) {
|
||||||
maybeBindLinearElement(
|
maybeBindLinearElement(
|
||||||
multiElement,
|
multiElement,
|
||||||
@ -1546,6 +1547,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
fontFamily: this.state.currentItemFontFamily,
|
fontFamily: this.state.currentItemFontFamily,
|
||||||
textAlign: this.state.currentItemTextAlign,
|
textAlign: this.state.currentItemTextAlign,
|
||||||
verticalAlign: DEFAULT_VERTICAL_ALIGN,
|
verticalAlign: DEFAULT_VERTICAL_ALIGN,
|
||||||
|
locked: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.scene.replaceAllElements([
|
this.scene.replaceAllElements([
|
||||||
@ -2126,12 +2128,14 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
of all hit elements */
|
of all hit elements */
|
||||||
preferSelected?: boolean;
|
preferSelected?: boolean;
|
||||||
includeBoundTextElement?: boolean;
|
includeBoundTextElement?: boolean;
|
||||||
|
includeLockedElements?: boolean;
|
||||||
},
|
},
|
||||||
): NonDeleted<ExcalidrawElement> | null {
|
): NonDeleted<ExcalidrawElement> | null {
|
||||||
const allHitElements = this.getElementsAtPosition(
|
const allHitElements = this.getElementsAtPosition(
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
opts?.includeBoundTextElement,
|
opts?.includeBoundTextElement,
|
||||||
|
opts?.includeLockedElements,
|
||||||
);
|
);
|
||||||
if (allHitElements.length > 1) {
|
if (allHitElements.length > 1) {
|
||||||
if (opts?.preferSelected) {
|
if (opts?.preferSelected) {
|
||||||
@ -2164,13 +2168,18 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
includeBoundTextElement: boolean = false,
|
includeBoundTextElement: boolean = false,
|
||||||
|
includeLockedElements: boolean = false,
|
||||||
): NonDeleted<ExcalidrawElement>[] {
|
): NonDeleted<ExcalidrawElement>[] {
|
||||||
const elements = includeBoundTextElement
|
const elements =
|
||||||
|
includeBoundTextElement && includeLockedElements
|
||||||
? this.scene.getElements()
|
? this.scene.getElements()
|
||||||
: this.scene
|
: this.scene
|
||||||
.getElements()
|
.getElements()
|
||||||
.filter(
|
.filter(
|
||||||
(element) => !(isTextElement(element) && element.containerId),
|
(element) =>
|
||||||
|
(includeLockedElements || !element.locked) &&
|
||||||
|
(includeBoundTextElement ||
|
||||||
|
!(isTextElement(element) && element.containerId)),
|
||||||
);
|
);
|
||||||
|
|
||||||
return getElementsAtPosition(elements, (element) =>
|
return getElementsAtPosition(elements, (element) =>
|
||||||
@ -2213,7 +2222,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (selectedElements.length === 1) {
|
if (selectedElements.length === 1) {
|
||||||
if (isTextElement(selectedElements[0])) {
|
if (isTextElement(selectedElements[0])) {
|
||||||
existingTextElement = selectedElements[0];
|
existingTextElement = selectedElements[0];
|
||||||
} else if (isTextBindableContainer(selectedElements[0])) {
|
} else if (isTextBindableContainer(selectedElements[0], false)) {
|
||||||
container = selectedElements[0];
|
container = selectedElements[0];
|
||||||
existingTextElement = getBoundTextElement(container);
|
existingTextElement = getBoundTextElement(container);
|
||||||
}
|
}
|
||||||
@ -2233,7 +2242,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.scene
|
this.scene
|
||||||
.getElements()
|
.getElements()
|
||||||
.filter(
|
.filter(
|
||||||
(ele) => isTextBindableContainer(ele) && !getBoundTextElement(ele),
|
(ele) =>
|
||||||
|
isTextBindableContainer(ele, false) && !getBoundTextElement(ele),
|
||||||
),
|
),
|
||||||
sceneX,
|
sceneX,
|
||||||
sceneY,
|
sceneY,
|
||||||
@ -2291,6 +2301,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
: DEFAULT_VERTICAL_ALIGN,
|
: DEFAULT_VERTICAL_ALIGN,
|
||||||
containerId: container?.id ?? undefined,
|
containerId: container?.id ?? undefined,
|
||||||
groupIds: container?.groupIds ?? [],
|
groupIds: container?.groupIds ?? [],
|
||||||
|
locked: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setState({ editingElement: element });
|
this.setState({ editingElement: element });
|
||||||
@ -2597,7 +2608,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
// Hovering with a selected tool or creating new linear element via click
|
// Hovering with a selected tool or creating new linear element via click
|
||||||
// and point
|
// and point
|
||||||
const { draggingElement } = this.state;
|
const { draggingElement } = this.state;
|
||||||
if (isBindingElement(draggingElement)) {
|
if (isBindingElement(draggingElement, false)) {
|
||||||
this.maybeSuggestBindingsForLinearElementAtCoords(
|
this.maybeSuggestBindingsForLinearElementAtCoords(
|
||||||
draggingElement,
|
draggingElement,
|
||||||
[scenePointer],
|
[scenePointer],
|
||||||
@ -2780,7 +2791,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.isHittingCommonBoundingBoxOfSelectedElements(
|
this.isHittingCommonBoundingBoxOfSelectedElements(
|
||||||
scenePointer,
|
scenePointer,
|
||||||
selectedElements,
|
selectedElements,
|
||||||
))
|
)) &&
|
||||||
|
!hitElement?.locked
|
||||||
) {
|
) {
|
||||||
setCursor(this.canvas, CURSOR_TYPE.MOVE);
|
setCursor(this.canvas, CURSOR_TYPE.MOVE);
|
||||||
} else {
|
} else {
|
||||||
@ -2796,6 +2808,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
) => {
|
) => {
|
||||||
const updateElementIds = (elements: ExcalidrawElement[]) => {
|
const updateElementIds = (elements: ExcalidrawElement[]) => {
|
||||||
elements.forEach((element) => {
|
elements.forEach((element) => {
|
||||||
|
if (element.locked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
idsToUpdate.push(element.id);
|
idsToUpdate.push(element.id);
|
||||||
if (event.altKey) {
|
if (event.altKey) {
|
||||||
if (
|
if (
|
||||||
@ -3617,6 +3633,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
opacity: this.state.currentItemOpacity,
|
opacity: this.state.currentItemOpacity,
|
||||||
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
||||||
simulatePressure: event.pressure === 0.5,
|
simulatePressure: event.pressure === 0.5,
|
||||||
|
locked: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
@ -3672,6 +3689,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
roughness: this.state.currentItemRoughness,
|
roughness: this.state.currentItemRoughness,
|
||||||
opacity: this.state.currentItemOpacity,
|
opacity: this.state.currentItemOpacity,
|
||||||
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
||||||
|
locked: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
@ -3759,6 +3777,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
||||||
startArrowhead,
|
startArrowhead,
|
||||||
endArrowhead,
|
endArrowhead,
|
||||||
|
locked: false,
|
||||||
});
|
});
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
selectedElementIds: {
|
selectedElementIds: {
|
||||||
@ -3807,6 +3826,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
roughness: this.state.currentItemRoughness,
|
roughness: this.state.currentItemRoughness,
|
||||||
opacity: this.state.currentItemOpacity,
|
opacity: this.state.currentItemOpacity,
|
||||||
strokeSharpness: this.state.currentItemStrokeSharpness,
|
strokeSharpness: this.state.currentItemStrokeSharpness,
|
||||||
|
locked: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (element.type === "selection") {
|
if (element.type === "selection") {
|
||||||
@ -4106,7 +4126,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBindingElement(draggingElement)) {
|
if (isBindingElement(draggingElement, false)) {
|
||||||
// When creating a linear element by dragging
|
// When creating a linear element by dragging
|
||||||
this.maybeSuggestBindingsForLinearElementAtCoords(
|
this.maybeSuggestBindingsForLinearElementAtCoords(
|
||||||
draggingElement,
|
draggingElement,
|
||||||
@ -4385,7 +4405,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
||||||
if (
|
if (
|
||||||
isBindingEnabled(this.state) &&
|
isBindingEnabled(this.state) &&
|
||||||
isBindingElement(draggingElement)
|
isBindingElement(draggingElement, false)
|
||||||
) {
|
) {
|
||||||
maybeBindLinearElement(
|
maybeBindLinearElement(
|
||||||
draggingElement,
|
draggingElement,
|
||||||
@ -5303,7 +5323,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { x, y } = viewportCoordsToSceneCoords(event, this.state);
|
const { x, y } = viewportCoordsToSceneCoords(event, this.state);
|
||||||
const element = this.getElementAtPosition(x, y, { preferSelected: true });
|
const element = this.getElementAtPosition(x, y, {
|
||||||
|
preferSelected: true,
|
||||||
|
includeLockedElements: true,
|
||||||
|
});
|
||||||
|
|
||||||
const type = element ? "element" : "canvas";
|
const type = element ? "element" : "canvas";
|
||||||
|
|
||||||
@ -5615,6 +5638,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
(maybeFlipHorizontal || maybeFlipVertical) && separator,
|
(maybeFlipHorizontal || maybeFlipVertical) && separator,
|
||||||
actionLink.contextItemPredicate(elements, this.state) && actionLink,
|
actionLink.contextItemPredicate(elements, this.state) && actionLink,
|
||||||
actionDuplicateSelection,
|
actionDuplicateSelection,
|
||||||
|
actionToggleLock,
|
||||||
|
separator,
|
||||||
actionDeleteSelected,
|
actionDeleteSelected,
|
||||||
],
|
],
|
||||||
top,
|
top,
|
||||||
|
@ -363,6 +363,10 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
|
|||||||
getShortcutKey(`Alt+${t("helpDialog.drag")}`),
|
getShortcutKey(`Alt+${t("helpDialog.drag")}`),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<Shortcut
|
||||||
|
label={t("helpDialog.toggleElementLock")}
|
||||||
|
shortcuts={[getShortcutKey("CtrlOrCmd+Shift+L")]}
|
||||||
|
/>
|
||||||
<Shortcut
|
<Shortcut
|
||||||
label={t("buttons.undo")}
|
label={t("buttons.undo")}
|
||||||
shortcuts={[getShortcutKey("CtrlOrCmd+Z")]}
|
shortcuts={[getShortcutKey("CtrlOrCmd+Z")]}
|
||||||
|
@ -107,6 +107,7 @@ const restoreElementWithProperties = <
|
|||||||
: element.boundElements ?? [],
|
: element.boundElements ?? [],
|
||||||
updated: element.updated ?? getUpdatedTimestamp(),
|
updated: element.updated ?? getUpdatedTimestamp(),
|
||||||
link: element.link ?? null,
|
link: element.link ?? null,
|
||||||
|
locked: element.locked ?? false,
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -255,7 +255,8 @@ export const getHoveredElementForBinding = (
|
|||||||
const hoveredElement = getElementAtPosition(
|
const hoveredElement = getElementAtPosition(
|
||||||
scene.getElements(),
|
scene.getElements(),
|
||||||
(element) =>
|
(element) =>
|
||||||
isBindableElement(element) && bindingBorderTest(element, pointerCoords),
|
isBindableElement(element, false) &&
|
||||||
|
bindingBorderTest(element, pointerCoords),
|
||||||
);
|
);
|
||||||
return hoveredElement as NonDeleted<ExcalidrawBindableElement> | null;
|
return hoveredElement as NonDeleted<ExcalidrawBindableElement> | null;
|
||||||
};
|
};
|
||||||
@ -456,13 +457,13 @@ export const getEligibleElementsForBinding = (
|
|||||||
): SuggestedBinding[] => {
|
): SuggestedBinding[] => {
|
||||||
const includedElementIds = new Set(elements.map(({ id }) => id));
|
const includedElementIds = new Set(elements.map(({ id }) => id));
|
||||||
return elements.flatMap((element) =>
|
return elements.flatMap((element) =>
|
||||||
isBindingElement(element)
|
isBindingElement(element, false)
|
||||||
? (getElligibleElementsForBindingElement(
|
? (getElligibleElementsForBindingElement(
|
||||||
element as NonDeleted<ExcalidrawLinearElement>,
|
element as NonDeleted<ExcalidrawLinearElement>,
|
||||||
).filter(
|
).filter(
|
||||||
(element) => !includedElementIds.has(element.id),
|
(element) => !includedElementIds.has(element.id),
|
||||||
) as SuggestedBinding[])
|
) as SuggestedBinding[])
|
||||||
: isBindableElement(element)
|
: isBindableElement(element, false)
|
||||||
? getElligibleElementsForBindableElementAndWhere(element).filter(
|
? getElligibleElementsForBindableElementAndWhere(element).filter(
|
||||||
(binding) => !includedElementIds.has(binding[0].id),
|
(binding) => !includedElementIds.has(binding[0].id),
|
||||||
)
|
)
|
||||||
@ -508,7 +509,7 @@ const getElligibleElementsForBindableElementAndWhere = (
|
|||||||
return Scene.getScene(bindableElement)!
|
return Scene.getScene(bindableElement)!
|
||||||
.getElements()
|
.getElements()
|
||||||
.map((element) => {
|
.map((element) => {
|
||||||
if (!isBindingElement(element)) {
|
if (!isBindingElement(element, false)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const canBindStart = isLinearElementEligibleForNewBindingByBindable(
|
const canBindStart = isLinearElementEligibleForNewBindingByBindable(
|
||||||
|
@ -205,7 +205,7 @@ export class LinearElementEditor {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// suggest bindings for first and last point if selected
|
// suggest bindings for first and last point if selected
|
||||||
if (isBindingElement(element)) {
|
if (isBindingElement(element, false)) {
|
||||||
const coords: { x: number; y: number }[] = [];
|
const coords: { x: number; y: number }[] = [];
|
||||||
|
|
||||||
const firstSelectedIndex = selectedPointsIndices[0];
|
const firstSelectedIndex = selectedPointsIndices[0];
|
||||||
|
@ -56,6 +56,7 @@ const _newElementBase = <T extends ExcalidrawElement>(
|
|||||||
strokeSharpness,
|
strokeSharpness,
|
||||||
boundElements = null,
|
boundElements = null,
|
||||||
link = null,
|
link = null,
|
||||||
|
locked,
|
||||||
...rest
|
...rest
|
||||||
}: ElementConstructorOpts & Omit<Partial<ExcalidrawGenericElement>, "type">,
|
}: ElementConstructorOpts & Omit<Partial<ExcalidrawGenericElement>, "type">,
|
||||||
) => {
|
) => {
|
||||||
@ -83,6 +84,7 @@ const _newElementBase = <T extends ExcalidrawElement>(
|
|||||||
boundElements,
|
boundElements,
|
||||||
updated: getUpdatedTimestamp(),
|
updated: getUpdatedTimestamp(),
|
||||||
link,
|
link,
|
||||||
|
locked,
|
||||||
};
|
};
|
||||||
return element;
|
return element;
|
||||||
};
|
};
|
||||||
|
@ -222,6 +222,13 @@ export const getTransformHandles = (
|
|||||||
zoom: Zoom,
|
zoom: Zoom,
|
||||||
pointerType: PointerType = "mouse",
|
pointerType: PointerType = "mouse",
|
||||||
): TransformHandles => {
|
): TransformHandles => {
|
||||||
|
// so that when locked element is selected (especially when you toggle lock
|
||||||
|
// via keyboard) the locked element is visually distinct, indicating
|
||||||
|
// you can't move/resize
|
||||||
|
if (element.locked) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
let omitSides: { [T in TransformHandleType]?: boolean } = {};
|
let omitSides: { [T in TransformHandleType]?: boolean } = {};
|
||||||
if (
|
if (
|
||||||
element.type === "arrow" ||
|
element.type === "arrow" ||
|
||||||
|
@ -70,8 +70,13 @@ export const isLinearElementType = (
|
|||||||
|
|
||||||
export const isBindingElement = (
|
export const isBindingElement = (
|
||||||
element?: ExcalidrawElement | null,
|
element?: ExcalidrawElement | null,
|
||||||
|
includeLocked = true,
|
||||||
): element is ExcalidrawLinearElement => {
|
): element is ExcalidrawLinearElement => {
|
||||||
return element != null && isBindingElementType(element.type);
|
return (
|
||||||
|
element != null &&
|
||||||
|
(!element.locked || includeLocked === true) &&
|
||||||
|
isBindingElementType(element.type)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isBindingElementType = (
|
export const isBindingElementType = (
|
||||||
@ -82,9 +87,11 @@ export const isBindingElementType = (
|
|||||||
|
|
||||||
export const isBindableElement = (
|
export const isBindableElement = (
|
||||||
element: ExcalidrawElement | null,
|
element: ExcalidrawElement | null,
|
||||||
|
includeLocked = true,
|
||||||
): element is ExcalidrawBindableElement => {
|
): element is ExcalidrawBindableElement => {
|
||||||
return (
|
return (
|
||||||
element != null &&
|
element != null &&
|
||||||
|
(!element.locked || includeLocked === true) &&
|
||||||
(element.type === "rectangle" ||
|
(element.type === "rectangle" ||
|
||||||
element.type === "diamond" ||
|
element.type === "diamond" ||
|
||||||
element.type === "ellipse" ||
|
element.type === "ellipse" ||
|
||||||
@ -95,9 +102,11 @@ export const isBindableElement = (
|
|||||||
|
|
||||||
export const isTextBindableContainer = (
|
export const isTextBindableContainer = (
|
||||||
element: ExcalidrawElement | null,
|
element: ExcalidrawElement | null,
|
||||||
|
includeLocked = true,
|
||||||
): element is ExcalidrawTextContainer => {
|
): element is ExcalidrawTextContainer => {
|
||||||
return (
|
return (
|
||||||
element != null &&
|
element != null &&
|
||||||
|
(!element.locked || includeLocked === true) &&
|
||||||
(element.type === "rectangle" ||
|
(element.type === "rectangle" ||
|
||||||
element.type === "diamond" ||
|
element.type === "diamond" ||
|
||||||
element.type === "ellipse" ||
|
element.type === "ellipse" ||
|
||||||
|
@ -55,6 +55,7 @@ type _ExcalidrawElementBase = Readonly<{
|
|||||||
/** epoch (ms) timestamp of last element update */
|
/** epoch (ms) timestamp of last element update */
|
||||||
updated: number;
|
updated: number;
|
||||||
link: string | null;
|
link: string | null;
|
||||||
|
locked: boolean;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type ExcalidrawSelectionElement = _ExcalidrawElementBase & {
|
export type ExcalidrawSelectionElement = _ExcalidrawElementBase & {
|
||||||
|
@ -113,6 +113,12 @@
|
|||||||
"edit": "Edit link",
|
"edit": "Edit link",
|
||||||
"create": "Create link",
|
"create": "Create link",
|
||||||
"label": "Link"
|
"label": "Link"
|
||||||
|
},
|
||||||
|
"elementLock": {
|
||||||
|
"lock": "Lock",
|
||||||
|
"unlock": "Unlock",
|
||||||
|
"lockAll": "Lock all",
|
||||||
|
"unlockAll": "Unlock all"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"buttons": {
|
"buttons": {
|
||||||
@ -292,7 +298,8 @@
|
|||||||
"title": "Help",
|
"title": "Help",
|
||||||
"view": "View",
|
"view": "View",
|
||||||
"zoomToFit": "Zoom to fit all elements",
|
"zoomToFit": "Zoom to fit all elements",
|
||||||
"zoomToSelection": "Zoom to selection"
|
"zoomToSelection": "Zoom to selection",
|
||||||
|
"toggleElementLock": "Lock/unlock selection"
|
||||||
},
|
},
|
||||||
"clearCanvasDialog": {
|
"clearCanvasDialog": {
|
||||||
"title": "Clear canvas"
|
"title": "Clear canvas"
|
||||||
@ -336,7 +343,6 @@
|
|||||||
"noteItems": "Each library item must have its own name so it's filterable. The following library items will be included:",
|
"noteItems": "Each library item must have its own name so it's filterable. The following library items will be included:",
|
||||||
"atleastOneLibItem": "Please select at least one library item to get started"
|
"atleastOneLibItem": "Please select at least one library item to get started"
|
||||||
},
|
},
|
||||||
|
|
||||||
"publishSuccessDialog": {
|
"publishSuccessDialog": {
|
||||||
"title": "Library submitted",
|
"title": "Library submitted",
|
||||||
"content": "Thank you {{authorName}}. Your library has been submitted for review. You can track the status",
|
"content": "Thank you {{authorName}}. Your library has been submitted for review. You can track the status",
|
||||||
|
@ -91,5 +91,5 @@ export const getTextBindableContainerAtPosition = (
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isTextBindableContainer(hitElement) ? hitElement : null;
|
return isTextBindableContainer(hitElement, false) ? hitElement : null;
|
||||||
};
|
};
|
||||||
|
@ -17,6 +17,7 @@ export const getElementsWithinSelection = (
|
|||||||
getElementBounds(element);
|
getElementBounds(element);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
element.locked === false &&
|
||||||
element.type !== "selection" &&
|
element.type !== "selection" &&
|
||||||
!isBoundToContainer(element) &&
|
!isBoundToContainer(element) &&
|
||||||
selectionX1 <= elementX1 &&
|
selectionX1 <= elementX1 &&
|
||||||
|
@ -94,6 +94,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -149,6 +150,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -268,6 +270,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -296,6 +299,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -351,6 +355,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -390,6 +395,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -415,6 +421,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -454,6 +461,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -479,6 +487,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -598,6 +607,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -626,6 +636,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -681,6 +692,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -720,6 +732,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -745,6 +758,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -784,6 +798,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -809,6 +824,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -928,6 +944,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -983,6 +1000,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -1100,6 +1118,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": true,
|
"isDeleted": true,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1155,6 +1174,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1192,6 +1212,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": true,
|
"isDeleted": true,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1311,6 +1332,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1339,6 +1361,7 @@ Object {
|
|||||||
"id": "id0_copy",
|
"id": "id0_copy",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -1394,6 +1417,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1433,6 +1457,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1458,6 +1483,7 @@ Object {
|
|||||||
"id": "id0_copy",
|
"id": "id0_copy",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -1585,6 +1611,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1615,6 +1642,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -1670,6 +1698,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1709,6 +1738,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1734,6 +1764,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -1779,6 +1810,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1806,6 +1838,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -1925,6 +1958,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 60,
|
"opacity": 60,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -1953,6 +1987,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 60,
|
"opacity": 60,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"seed": 400692809,
|
"seed": 400692809,
|
||||||
@ -2008,6 +2043,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2047,6 +2083,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2072,6 +2109,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -2111,6 +2149,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2136,6 +2175,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -2175,6 +2215,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2200,6 +2241,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -2239,6 +2281,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2264,6 +2307,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -2303,6 +2347,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2328,6 +2373,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -2367,6 +2413,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2392,6 +2439,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -2431,6 +2479,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2456,6 +2505,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"seed": 400692809,
|
"seed": 400692809,
|
||||||
@ -2495,6 +2545,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2520,6 +2571,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 60,
|
"opacity": 60,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"seed": 400692809,
|
"seed": 400692809,
|
||||||
@ -2559,6 +2611,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 60,
|
"opacity": 60,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2584,6 +2637,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 60,
|
"opacity": 60,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"seed": 400692809,
|
"seed": 400692809,
|
||||||
@ -2703,6 +2757,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -2731,6 +2786,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2786,6 +2842,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2825,6 +2882,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -2850,6 +2908,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -2889,6 +2948,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -2914,6 +2974,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -3033,6 +3094,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -3061,6 +3123,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -3116,6 +3179,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -3155,6 +3219,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -3180,6 +3245,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -3219,6 +3285,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -3244,6 +3311,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -3367,6 +3435,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -3395,6 +3464,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
@ -3450,6 +3520,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -3489,6 +3560,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -3514,6 +3586,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
@ -3559,6 +3632,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -3586,6 +3660,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
@ -3627,6 +3702,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -3652,6 +3728,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
@ -3777,6 +3854,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -3805,6 +3883,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -3860,6 +3939,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -3899,6 +3979,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -3924,6 +4005,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 453191,
|
"seed": 453191,
|
||||||
@ -4053,6 +4135,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -4083,6 +4166,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
@ -4138,6 +4222,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -4177,6 +4262,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -4202,6 +4288,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
@ -4248,6 +4335,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -4275,6 +4363,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
@ -4582,6 +4671,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -4610,6 +4700,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
@ -4638,6 +4729,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
@ -4693,6 +4785,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 1278240551,
|
"seed": 1278240551,
|
||||||
|
@ -16,6 +16,7 @@ Object {
|
|||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
@ -58,6 +59,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
@ -88,6 +90,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
@ -119,6 +122,7 @@ Object {
|
|||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
@ -161,6 +165,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
|
@ -11,6 +11,7 @@ Object {
|
|||||||
"id": "id0_copy",
|
"id": "id0_copy",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
@ -39,6 +40,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
@ -67,6 +69,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
@ -100,6 +103,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
@ -133,6 +137,7 @@ Object {
|
|||||||
"id": "id1",
|
"id": "id1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
@ -168,6 +173,7 @@ Object {
|
|||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
|
@ -17,6 +17,7 @@ Object {
|
|||||||
110,
|
110,
|
||||||
],
|
],
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
@ -67,6 +68,7 @@ Object {
|
|||||||
110,
|
110,
|
||||||
],
|
],
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@ Object {
|
|||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
@ -57,6 +58,7 @@ Object {
|
|||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
@ -97,6 +99,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
@ -125,6 +128,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
@ -153,6 +157,7 @@ Object {
|
|||||||
"id": "id0",
|
"id": "id0",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
|
@ -36,10 +36,6 @@ const checkpoint = (name: string) => {
|
|||||||
|
|
||||||
const mouse = new Pointer("mouse");
|
const mouse = new Pointer("mouse");
|
||||||
|
|
||||||
const queryContextMenu = () => {
|
|
||||||
return GlobalTestState.renderResult.container.querySelector(".context-menu");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Unmount ReactDOM from root
|
// Unmount ReactDOM from root
|
||||||
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||||
|
|
||||||
@ -83,7 +79,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 1,
|
clientX: 1,
|
||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
const contextMenuOptions =
|
const contextMenuOptions =
|
||||||
contextMenu?.querySelectorAll(".context-menu li");
|
contextMenu?.querySelectorAll(".context-menu li");
|
||||||
const expectedShortcutNames: ShortcutName[] = [
|
const expectedShortcutNames: ShortcutName[] = [
|
||||||
@ -113,7 +109,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 1,
|
clientX: 1,
|
||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
const contextMenuOptions =
|
const contextMenuOptions =
|
||||||
contextMenu?.querySelectorAll(".context-menu li");
|
contextMenu?.querySelectorAll(".context-menu li");
|
||||||
const expectedShortcutNames: ShortcutName[] = [
|
const expectedShortcutNames: ShortcutName[] = [
|
||||||
@ -129,6 +125,7 @@ describe("contextMenu element", () => {
|
|||||||
"bringToFront",
|
"bringToFront",
|
||||||
"duplicateSelection",
|
"duplicateSelection",
|
||||||
"hyperlink",
|
"hyperlink",
|
||||||
|
"toggleLock",
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(contextMenu).not.toBeNull();
|
expect(contextMenu).not.toBeNull();
|
||||||
@ -166,7 +163,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 100,
|
clientX: 100,
|
||||||
clientY: 100,
|
clientY: 100,
|
||||||
});
|
});
|
||||||
expect(queryContextMenu()).not.toBeNull();
|
expect(UI.queryContextMenu()).not.toBeNull();
|
||||||
expect(API.getSelectedElement().id).toBe(rect1.id);
|
expect(API.getSelectedElement().id).toBe(rect1.id);
|
||||||
|
|
||||||
// higher z-index
|
// higher z-index
|
||||||
@ -176,7 +173,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 100,
|
clientX: 100,
|
||||||
clientY: 100,
|
clientY: 100,
|
||||||
});
|
});
|
||||||
expect(queryContextMenu()).not.toBeNull();
|
expect(UI.queryContextMenu()).not.toBeNull();
|
||||||
expect(API.getSelectedElement().id).toBe(rect2.id);
|
expect(API.getSelectedElement().id).toBe(rect2.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -201,7 +198,7 @@ describe("contextMenu element", () => {
|
|||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
const contextMenuOptions =
|
const contextMenuOptions =
|
||||||
contextMenu?.querySelectorAll(".context-menu li");
|
contextMenu?.querySelectorAll(".context-menu li");
|
||||||
const expectedShortcutNames: ShortcutName[] = [
|
const expectedShortcutNames: ShortcutName[] = [
|
||||||
@ -215,6 +212,7 @@ describe("contextMenu element", () => {
|
|||||||
"sendToBack",
|
"sendToBack",
|
||||||
"bringToFront",
|
"bringToFront",
|
||||||
"duplicateSelection",
|
"duplicateSelection",
|
||||||
|
"toggleLock",
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(contextMenu).not.toBeNull();
|
expect(contextMenu).not.toBeNull();
|
||||||
@ -251,7 +249,7 @@ describe("contextMenu element", () => {
|
|||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
const contextMenuOptions =
|
const contextMenuOptions =
|
||||||
contextMenu?.querySelectorAll(".context-menu li");
|
contextMenu?.querySelectorAll(".context-menu li");
|
||||||
const expectedShortcutNames: ShortcutName[] = [
|
const expectedShortcutNames: ShortcutName[] = [
|
||||||
@ -265,6 +263,7 @@ describe("contextMenu element", () => {
|
|||||||
"sendToBack",
|
"sendToBack",
|
||||||
"bringToFront",
|
"bringToFront",
|
||||||
"duplicateSelection",
|
"duplicateSelection",
|
||||||
|
"toggleLock",
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(contextMenu).not.toBeNull();
|
expect(contextMenu).not.toBeNull();
|
||||||
@ -286,7 +285,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 1,
|
clientX: 1,
|
||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
expect(copiedStyles).toBe("{}");
|
expect(copiedStyles).toBe("{}");
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Copy styles")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Copy styles")!);
|
||||||
expect(copiedStyles).not.toBe("{}");
|
expect(copiedStyles).not.toBe("{}");
|
||||||
@ -328,7 +327,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 40,
|
clientX: 40,
|
||||||
clientY: 40,
|
clientY: 40,
|
||||||
});
|
});
|
||||||
let contextMenu = queryContextMenu();
|
let contextMenu = UI.queryContextMenu();
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Copy styles")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Copy styles")!);
|
||||||
const secondRect = JSON.parse(copiedStyles);
|
const secondRect = JSON.parse(copiedStyles);
|
||||||
expect(secondRect.id).toBe(h.elements[1].id);
|
expect(secondRect.id).toBe(h.elements[1].id);
|
||||||
@ -340,7 +339,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 10,
|
clientX: 10,
|
||||||
clientY: 10,
|
clientY: 10,
|
||||||
});
|
});
|
||||||
contextMenu = queryContextMenu();
|
contextMenu = UI.queryContextMenu();
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Paste styles")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Paste styles")!);
|
||||||
|
|
||||||
const firstRect = API.getSelectedElement();
|
const firstRect = API.getSelectedElement();
|
||||||
@ -364,7 +363,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 1,
|
clientX: 1,
|
||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
fireEvent.click(queryAllByText(contextMenu as HTMLElement, "Delete")[0]);
|
fireEvent.click(queryAllByText(contextMenu as HTMLElement, "Delete")[0]);
|
||||||
expect(API.getSelectedElements()).toHaveLength(0);
|
expect(API.getSelectedElements()).toHaveLength(0);
|
||||||
expect(h.elements[0].isDeleted).toBe(true);
|
expect(h.elements[0].isDeleted).toBe(true);
|
||||||
@ -380,7 +379,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 1,
|
clientX: 1,
|
||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Add to library")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Add to library")!);
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
@ -401,7 +400,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 1,
|
clientX: 1,
|
||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Duplicate")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Duplicate")!);
|
||||||
expect(h.elements).toHaveLength(2);
|
expect(h.elements).toHaveLength(2);
|
||||||
const { id: _id0, seed: _seed0, x: _x0, y: _y0, ...rect1 } = h.elements[0];
|
const { id: _id0, seed: _seed0, x: _x0, y: _y0, ...rect1 } = h.elements[0];
|
||||||
@ -424,7 +423,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 40,
|
clientX: 40,
|
||||||
clientY: 40,
|
clientY: 40,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
const elementsBefore = h.elements;
|
const elementsBefore = h.elements;
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Send backward")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Send backward")!);
|
||||||
expect(elementsBefore[0].id).toEqual(h.elements[1].id);
|
expect(elementsBefore[0].id).toEqual(h.elements[1].id);
|
||||||
@ -446,7 +445,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 10,
|
clientX: 10,
|
||||||
clientY: 10,
|
clientY: 10,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
const elementsBefore = h.elements;
|
const elementsBefore = h.elements;
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Bring forward")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Bring forward")!);
|
||||||
expect(elementsBefore[0].id).toEqual(h.elements[1].id);
|
expect(elementsBefore[0].id).toEqual(h.elements[1].id);
|
||||||
@ -468,7 +467,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 40,
|
clientX: 40,
|
||||||
clientY: 40,
|
clientY: 40,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
const elementsBefore = h.elements;
|
const elementsBefore = h.elements;
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Send to back")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Send to back")!);
|
||||||
expect(elementsBefore[1].id).toEqual(h.elements[0].id);
|
expect(elementsBefore[1].id).toEqual(h.elements[0].id);
|
||||||
@ -489,7 +488,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 10,
|
clientX: 10,
|
||||||
clientY: 10,
|
clientY: 10,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
const elementsBefore = h.elements;
|
const elementsBefore = h.elements;
|
||||||
fireEvent.click(queryByText(contextMenu as HTMLElement, "Bring to front")!);
|
fireEvent.click(queryByText(contextMenu as HTMLElement, "Bring to front")!);
|
||||||
expect(elementsBefore[0].id).toEqual(h.elements[1].id);
|
expect(elementsBefore[0].id).toEqual(h.elements[1].id);
|
||||||
@ -514,7 +513,7 @@ describe("contextMenu element", () => {
|
|||||||
clientX: 1,
|
clientX: 1,
|
||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
fireEvent.click(
|
fireEvent.click(
|
||||||
queryByText(contextMenu as HTMLElement, "Group selection")!,
|
queryByText(contextMenu as HTMLElement, "Group selection")!,
|
||||||
);
|
);
|
||||||
@ -547,7 +546,7 @@ describe("contextMenu element", () => {
|
|||||||
clientY: 1,
|
clientY: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
const contextMenu = queryContextMenu();
|
const contextMenu = UI.queryContextMenu();
|
||||||
expect(contextMenu).not.toBeNull();
|
expect(contextMenu).not.toBeNull();
|
||||||
fireEvent.click(
|
fireEvent.click(
|
||||||
queryByText(contextMenu as HTMLElement, "Ungroup selection")!,
|
queryByText(contextMenu as HTMLElement, "Ungroup selection")!,
|
||||||
|
@ -14,6 +14,7 @@ Object {
|
|||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
@ -58,6 +59,7 @@ Object {
|
|||||||
"id": "1",
|
"id": "1",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 10,
|
"opacity": 10,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
@ -90,6 +92,7 @@ Object {
|
|||||||
"id": "2",
|
"id": "2",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 10,
|
"opacity": 10,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
@ -122,6 +125,7 @@ Object {
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 10,
|
"opacity": 10,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
@ -151,6 +155,7 @@ Object {
|
|||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [],
|
"points": Array [],
|
||||||
"pressures": Array [],
|
"pressures": Array [],
|
||||||
@ -185,6 +190,7 @@ Object {
|
|||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
@ -228,6 +234,7 @@ Object {
|
|||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"lastCommittedPoint": null,
|
"lastCommittedPoint": null,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"points": Array [
|
"points": Array [
|
||||||
Array [
|
Array [
|
||||||
@ -272,6 +279,7 @@ Object {
|
|||||||
"id": "id-text01",
|
"id": "id-text01",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"originalText": "text",
|
"originalText": "text",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
@ -308,6 +316,7 @@ Object {
|
|||||||
"id": "id-text01",
|
"id": "id-text01",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"link": null,
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"originalText": "test",
|
"originalText": "test",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
388
src/tests/elementLocking.test.tsx
Normal file
388
src/tests/elementLocking.test.tsx
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import ExcalidrawApp from "../excalidraw-app";
|
||||||
|
import { render } from "../tests/test-utils";
|
||||||
|
import { Keyboard, Pointer, UI } from "../tests/helpers/ui";
|
||||||
|
import { KEYS } from "../keys";
|
||||||
|
import { API } from "../tests/helpers/api";
|
||||||
|
import { actionSelectAll } from "../actions";
|
||||||
|
import { t } from "../i18n";
|
||||||
|
import { mutateElement } from "../element/mutateElement";
|
||||||
|
|
||||||
|
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||||
|
|
||||||
|
const mouse = new Pointer("mouse");
|
||||||
|
const h = window.h;
|
||||||
|
|
||||||
|
describe("element locking", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await render(<ExcalidrawApp />);
|
||||||
|
h.elements = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
it("click-selecting a locked element is disabled", () => {
|
||||||
|
const lockedRectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
h.elements = [lockedRectangle];
|
||||||
|
|
||||||
|
mouse.clickAt(50, 50);
|
||||||
|
expect(API.getSelectedElements().length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("box-selecting a locked element is disabled", () => {
|
||||||
|
const lockedRectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
locked: true,
|
||||||
|
x: 100,
|
||||||
|
y: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
h.elements = [lockedRectangle];
|
||||||
|
|
||||||
|
mouse.downAt(50, 50);
|
||||||
|
mouse.moveTo(250, 250);
|
||||||
|
mouse.upAt(250, 250);
|
||||||
|
expect(API.getSelectedElements().length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("dragging a locked element is disabled", () => {
|
||||||
|
const lockedRectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
h.elements = [lockedRectangle];
|
||||||
|
|
||||||
|
mouse.downAt(50, 50);
|
||||||
|
mouse.moveTo(100, 100);
|
||||||
|
mouse.upAt(100, 100);
|
||||||
|
expect(lockedRectangle).toEqual(expect.objectContaining({ x: 0, y: 0 }));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("you can drag element that's below a locked element", () => {
|
||||||
|
const rectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
});
|
||||||
|
const lockedRectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
h.elements = [rectangle, lockedRectangle];
|
||||||
|
|
||||||
|
mouse.downAt(50, 50);
|
||||||
|
mouse.moveTo(100, 100);
|
||||||
|
mouse.upAt(100, 100);
|
||||||
|
expect(lockedRectangle).toEqual(expect.objectContaining({ x: 0, y: 0 }));
|
||||||
|
expect(rectangle).toEqual(expect.objectContaining({ x: 50, y: 50 }));
|
||||||
|
expect(API.getSelectedElements().length).toBe(1);
|
||||||
|
expect(API.getSelectedElement().id).toBe(rectangle.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("selectAll shouldn't select locked elements", () => {
|
||||||
|
h.elements = [
|
||||||
|
API.createElement({ type: "rectangle" }),
|
||||||
|
API.createElement({ type: "rectangle", locked: true }),
|
||||||
|
];
|
||||||
|
h.app.actionManager.executeAction(actionSelectAll);
|
||||||
|
expect(API.getSelectedElements().length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("clicking on a locked element should select the unlocked element beneath it", () => {
|
||||||
|
const rectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
});
|
||||||
|
const lockedRectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
h.elements = [rectangle, lockedRectangle];
|
||||||
|
expect(API.getSelectedElements().length).toBe(0);
|
||||||
|
mouse.clickAt(50, 50);
|
||||||
|
expect(API.getSelectedElements().length).toBe(1);
|
||||||
|
expect(API.getSelectedElement().id).toBe(rectangle.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("right-clicking on a locked element should select it & open its contextMenu", () => {
|
||||||
|
const rectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
});
|
||||||
|
const lockedRectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
h.elements = [rectangle, lockedRectangle];
|
||||||
|
expect(API.getSelectedElements().length).toBe(0);
|
||||||
|
mouse.rightClickAt(50, 50);
|
||||||
|
expect(API.getSelectedElements().length).toBe(1);
|
||||||
|
expect(API.getSelectedElement().id).toBe(lockedRectangle.id);
|
||||||
|
|
||||||
|
const contextMenu = UI.queryContextMenu();
|
||||||
|
expect(contextMenu).not.toBeNull();
|
||||||
|
expect(
|
||||||
|
contextMenu?.querySelector(
|
||||||
|
`li[data-testid="toggleLock"] .context-menu-option__label`,
|
||||||
|
),
|
||||||
|
).toHaveTextContent(t("labels.elementLock.unlock"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("right-clicking on element covered by locked element should ignore the locked element", () => {
|
||||||
|
const rectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
});
|
||||||
|
const lockedRectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
h.elements = [rectangle, lockedRectangle];
|
||||||
|
API.setSelectedElements([rectangle]);
|
||||||
|
expect(API.getSelectedElements().length).toBe(1);
|
||||||
|
expect(API.getSelectedElement().id).toBe(rectangle.id);
|
||||||
|
mouse.rightClickAt(50, 50);
|
||||||
|
expect(API.getSelectedElements().length).toBe(1);
|
||||||
|
expect(API.getSelectedElement().id).toBe(rectangle.id);
|
||||||
|
|
||||||
|
const contextMenu = UI.queryContextMenu();
|
||||||
|
expect(contextMenu).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("selecting a group selects all elements including locked ones", () => {
|
||||||
|
const rectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
groupIds: ["g1"],
|
||||||
|
});
|
||||||
|
const lockedRectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: "red",
|
||||||
|
fillStyle: "solid",
|
||||||
|
locked: true,
|
||||||
|
groupIds: ["g1"],
|
||||||
|
x: 200,
|
||||||
|
y: 200,
|
||||||
|
});
|
||||||
|
|
||||||
|
h.elements = [rectangle, lockedRectangle];
|
||||||
|
|
||||||
|
mouse.clickAt(250, 250);
|
||||||
|
expect(API.getSelectedElements().length).toBe(0);
|
||||||
|
|
||||||
|
mouse.clickAt(50, 50);
|
||||||
|
expect(API.getSelectedElements().length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should ignore locked text element in center of container on ENTER", () => {
|
||||||
|
const container = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
});
|
||||||
|
const textSize = 20;
|
||||||
|
const text = API.createElement({
|
||||||
|
type: "text",
|
||||||
|
text: "ola",
|
||||||
|
x: container.width / 2 - textSize / 2,
|
||||||
|
y: container.height / 2 - textSize / 2,
|
||||||
|
width: textSize,
|
||||||
|
height: textSize,
|
||||||
|
containerId: container.id,
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
h.elements = [container, text];
|
||||||
|
API.setSelectedElements([container]);
|
||||||
|
Keyboard.keyPress(KEYS.ENTER);
|
||||||
|
expect(h.state.editingElement?.id).not.toBe(text.id);
|
||||||
|
expect(h.state.editingElement?.id).toBe(h.elements[2].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should ignore locked text under cursor when clicked with text tool", () => {
|
||||||
|
const text = API.createElement({
|
||||||
|
type: "text",
|
||||||
|
text: "ola",
|
||||||
|
x: 60,
|
||||||
|
y: 0,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
h.elements = [text];
|
||||||
|
UI.clickTool("text");
|
||||||
|
mouse.clickAt(text.x + 50, text.y + 50);
|
||||||
|
const editor = document.querySelector(
|
||||||
|
".excalidraw-textEditorContainer > textarea",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
expect(editor).not.toBe(null);
|
||||||
|
expect(h.state.editingElement?.id).not.toBe(text.id);
|
||||||
|
expect(h.elements.length).toBe(2);
|
||||||
|
expect(h.state.editingElement?.id).toBe(h.elements[1].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should ignore text under cursor when double-clicked with selection tool", () => {
|
||||||
|
const text = API.createElement({
|
||||||
|
type: "text",
|
||||||
|
text: "ola",
|
||||||
|
x: 60,
|
||||||
|
y: 0,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
h.elements = [text];
|
||||||
|
UI.clickTool("selection");
|
||||||
|
mouse.doubleClickAt(text.x + 50, text.y + 50);
|
||||||
|
const editor = document.querySelector(
|
||||||
|
".excalidraw-textEditorContainer > textarea",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
expect(editor).not.toBe(null);
|
||||||
|
expect(h.state.editingElement?.id).not.toBe(text.id);
|
||||||
|
expect(h.elements.length).toBe(2);
|
||||||
|
expect(h.state.editingElement?.id).toBe(h.elements[1].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("locking should include bound text", () => {
|
||||||
|
const container = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
});
|
||||||
|
const textSize = 20;
|
||||||
|
const text = API.createElement({
|
||||||
|
type: "text",
|
||||||
|
text: "ola",
|
||||||
|
x: container.width / 2 - textSize / 2,
|
||||||
|
y: container.height / 2 - textSize / 2,
|
||||||
|
width: textSize,
|
||||||
|
height: textSize,
|
||||||
|
containerId: container.id,
|
||||||
|
});
|
||||||
|
mutateElement(container, {
|
||||||
|
boundElements: [{ id: text.id, type: "text" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
h.elements = [container, text];
|
||||||
|
|
||||||
|
UI.clickTool("selection");
|
||||||
|
mouse.clickAt(container.x + 10, container.y + 10);
|
||||||
|
Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
|
||||||
|
Keyboard.keyPress(KEYS.L);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(h.elements).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: container.id,
|
||||||
|
locked: true,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: text.id,
|
||||||
|
locked: true,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("bound text shouldn't be editable via double-click", () => {
|
||||||
|
const container = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
const textSize = 20;
|
||||||
|
const text = API.createElement({
|
||||||
|
type: "text",
|
||||||
|
text: "ola",
|
||||||
|
x: container.width / 2 - textSize / 2,
|
||||||
|
y: container.height / 2 - textSize / 2,
|
||||||
|
width: textSize,
|
||||||
|
height: textSize,
|
||||||
|
containerId: container.id,
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
mutateElement(container, {
|
||||||
|
boundElements: [{ id: text.id, type: "text" }],
|
||||||
|
});
|
||||||
|
h.elements = [container, text];
|
||||||
|
|
||||||
|
UI.clickTool("selection");
|
||||||
|
mouse.doubleClickAt(container.width / 2, container.height / 2);
|
||||||
|
|
||||||
|
const editor = document.querySelector(
|
||||||
|
".excalidraw-textEditorContainer > textarea",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
expect(editor).not.toBe(null);
|
||||||
|
expect(h.state.editingElement?.id).not.toBe(text.id);
|
||||||
|
expect(h.elements.length).toBe(3);
|
||||||
|
expect(h.state.editingElement?.id).toBe(h.elements[2].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("bound text shouldn't be editable via text tool", () => {
|
||||||
|
const container = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
width: 100,
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
const textSize = 20;
|
||||||
|
const text = API.createElement({
|
||||||
|
type: "text",
|
||||||
|
text: "ola",
|
||||||
|
x: container.width / 2 - textSize / 2,
|
||||||
|
y: container.height / 2 - textSize / 2,
|
||||||
|
width: textSize,
|
||||||
|
height: textSize,
|
||||||
|
containerId: container.id,
|
||||||
|
locked: true,
|
||||||
|
});
|
||||||
|
mutateElement(container, {
|
||||||
|
boundElements: [{ id: text.id, type: "text" }],
|
||||||
|
});
|
||||||
|
h.elements = [container, text];
|
||||||
|
|
||||||
|
UI.clickTool("text");
|
||||||
|
mouse.clickAt(container.width / 2, container.height / 2);
|
||||||
|
|
||||||
|
const editor = document.querySelector(
|
||||||
|
".excalidraw-textEditorContainer > textarea",
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
expect(editor).not.toBe(null);
|
||||||
|
expect(h.state.editingElement?.id).not.toBe(text.id);
|
||||||
|
expect(h.elements.length).toBe(3);
|
||||||
|
expect(h.state.editingElement?.id).toBe(h.elements[2].id);
|
||||||
|
});
|
||||||
|
});
|
1
src/tests/fixtures/elementFixture.ts
vendored
1
src/tests/fixtures/elementFixture.ts
vendored
@ -23,6 +23,7 @@ const elementBase: Omit<ExcalidrawElement, "type"> = {
|
|||||||
boundElements: null,
|
boundElements: null,
|
||||||
updated: 1,
|
updated: 1,
|
||||||
link: null,
|
link: null,
|
||||||
|
locked: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const rectangleFixture: ExcalidrawElement = {
|
export const rectangleFixture: ExcalidrawElement = {
|
||||||
|
@ -15,6 +15,7 @@ import path from "path";
|
|||||||
import { getMimeType } from "../../data/blob";
|
import { getMimeType } from "../../data/blob";
|
||||||
import { newFreeDrawElement } from "../../element/newElement";
|
import { newFreeDrawElement } from "../../element/newElement";
|
||||||
import { Point } from "../../types";
|
import { Point } from "../../types";
|
||||||
|
import { getSelectedElements } from "../../scene/selection";
|
||||||
|
|
||||||
const readFile = util.promisify(fs.readFile);
|
const readFile = util.promisify(fs.readFile);
|
||||||
|
|
||||||
@ -30,10 +31,10 @@ export class API {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
static getSelectedElements = (): ExcalidrawElement[] => {
|
static getSelectedElements = (
|
||||||
return h.elements.filter(
|
includeBoundTextElement: boolean = false,
|
||||||
(element) => h.state.selectedElementIds[element.id],
|
): ExcalidrawElement[] => {
|
||||||
);
|
return getSelectedElements(h.elements, h.state, includeBoundTextElement);
|
||||||
};
|
};
|
||||||
|
|
||||||
static getSelectedElement = (): ExcalidrawElement => {
|
static getSelectedElement = (): ExcalidrawElement => {
|
||||||
@ -100,6 +101,7 @@ export class API {
|
|||||||
? ExcalidrawTextElement["containerId"]
|
? ExcalidrawTextElement["containerId"]
|
||||||
: never;
|
: never;
|
||||||
points?: T extends "arrow" | "line" ? readonly Point[] : never;
|
points?: T extends "arrow" | "line" ? readonly Point[] : never;
|
||||||
|
locked?: boolean;
|
||||||
}): T extends "arrow" | "line"
|
}): T extends "arrow" | "line"
|
||||||
? ExcalidrawLinearElement
|
? ExcalidrawLinearElement
|
||||||
: T extends "freedraw"
|
: T extends "freedraw"
|
||||||
@ -125,6 +127,7 @@ export class API {
|
|||||||
roughness: rest.roughness ?? appState.currentItemRoughness,
|
roughness: rest.roughness ?? appState.currentItemRoughness,
|
||||||
opacity: rest.opacity ?? appState.currentItemOpacity,
|
opacity: rest.opacity ?? appState.currentItemOpacity,
|
||||||
boundElements: rest.boundElements ?? null,
|
boundElements: rest.boundElements ?? null,
|
||||||
|
locked: rest.locked ?? false,
|
||||||
};
|
};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "rectangle":
|
case "rectangle":
|
||||||
|
@ -179,6 +179,14 @@ export class Pointer {
|
|||||||
this.upAt();
|
this.upAt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rightClickAt(x: number, y: number) {
|
||||||
|
fireEvent.contextMenu(GlobalTestState.canvas, {
|
||||||
|
button: 2,
|
||||||
|
clientX: x,
|
||||||
|
clientY: y,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
doubleClickAt(x: number, y: number) {
|
doubleClickAt(x: number, y: number) {
|
||||||
this.moveTo(x, y);
|
this.moveTo(x, y);
|
||||||
fireEvent.doubleClick(GlobalTestState.canvas, this.getEvent());
|
fireEvent.doubleClick(GlobalTestState.canvas, this.getEvent());
|
||||||
@ -309,4 +317,10 @@ export class UI {
|
|||||||
Keyboard.codePress(CODES.G);
|
Keyboard.codePress(CODES.G);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static queryContextMenu = () => {
|
||||||
|
return GlobalTestState.renderResult.container.querySelector(
|
||||||
|
".context-menu",
|
||||||
|
);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ exports[`exportToSvg with elements that have a link 1`] = `
|
|||||||
exports[`exportToSvg with exportEmbedScene 1`] = `
|
exports[`exportToSvg with exportEmbedScene 1`] = `
|
||||||
"
|
"
|
||||||
<!-- svg-source:excalidraw -->
|
<!-- svg-source:excalidraw -->
|
||||||
<!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1STU9cdTAwMDMhXHUwMDEwvfdXbPDapLtrv+ytWmNMjFx1MDAxZXpoovFAl9mFlFx1MDAwMlx1MDAwNbZcdTAwMWZp+t9cdTAwMDXaLrrx5lVcdTAwMGUk83hvZph5x06SIHtQgCZcdIJ9gTkjXHUwMDFh71DX41vQhknhnvJcdTAwMTBcdTAwMWJZ61wiMKm1atLrcelcdTAwMDRUXHUwMDFhe+ZcdTAwMDOHNVxia1x1MDAxY+PDxUlyXGa3e2HEq7ZcdTAwMGK9eZuWKyZIvinWo5fZ9Ok9SFx1MDAwM2nvOP2s38RcdTAwMDdf+HbUxDtGLHVYlqZcckaBVdS2QCwq7tuMiLFaruBBcql9IzdpOLH0XHUwMDEyXHUwMDE3q0rLWpDIyVx1MDAwNlx1MDAxOC/LyClcdTAwMTnnc3vg51x1MDAwMeCC1lx1MDAxYVCrwuLaYlx1MDAwYm90RrpcdTAwMDFHlStZUVx1MDAwMcb80EiFXHUwMDBiZlx1MDAwZq1f+f7UM1x00/1s56dYq0tcdTAwMWVkfPCtM1x1MDAwMFx1MDAxMlL1s+FgdJeOm5e43yxP2+irXHUwMDE0YddZNlx1MDAxZadpP1x1MDAxZlxyXHUwMDFiXHUwMDA2MzO3alx1MDAxYtKWmFx1MDAxYohz9CN8jDZcdTAwMTA1581jrVxiPoviVzlcdTAwMTOrNu9qR8LwWlxuglx1MDAwMn7q/jvq31F/dFx1MDAxNHDOlIGLo9xcdTAwMWR+jbBSc+tcdTAwMTI5ytlfaMtgd//LXHUwMDA2y3C8PvjRb1x1MDAxMHxXx1Pn9Fx1MDAwNbeWWs0ifQ==<!-- payload-end -->
|
<!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1SPW/CMFx1MDAxMN35XHUwMDE1kbtcIpGk4aNstFRVpapcdTAwMWRcdTAwMTiQWnUw8YVYMbaxXHUwMDFkPoT477VccsRtxNpcclx1MDAwZpbu+b278907dKJcYpm9XHUwMDA0NI5cdTAwMTDscswoUXiLulx1MDAwZd+A0lRw+5T6WIta5Z5ZXHUwMDFhI8e9XHUwMDFlXHUwMDEzVlBcbm1OfGCwXHUwMDAybrRlfNk4ilx1MDAwZf62L5Q41Wau1lx1MDAxZpOiopyk63w1fJtOXj691JN2lpMlWVx1MDAxM+9d4fthXHUwMDEzbykxpcWSOG6wXHUwMDEy6LI0LVx1MDAxMPMlc21cdTAwMDZEXHUwMDFiJSp4XHUwMDEyTCjXyF3sTyi9wHm1VKLmJHCSPsaLXCJwXG7K2Mzs2WlcdTAwMDA4L2tcdTAwMDWoVWF+abGFNzot7ICDypZcXJZcdTAwMWO0/qNcdTAwMTFcdTAwMTLn1Oxbv3L9yVfip/vdzl9iJc95kHbBr85cdTAwMDCIT5Ulg/7wIVx1MDAxZTUvYb9JXHUwMDFht9F3wf2uk2Q0iuMsXHUwMDFkXHUwMDBlXHUwMDFhXHUwMDA21VO7auPTXHUwMDE2mGlcYnN0I3xcdTAwMGU24DVjzWMtXHQ+icJXXHUwMDE55VWbZ11VXcl9cSmheCU4QVx1MDAxZT92b0a7XHUwMDE57X+MXHUwMDA2jFGp4Ww0e/thICzlzNj8lnKyXHUwMDFk2lDYPl5ZbOGP03ubusWCa/Zw7Fx1MDAxY39cdTAwMDCLqmbvIn0=<!-- payload-end -->
|
||||||
<defs>
|
<defs>
|
||||||
<style>
|
<style>
|
||||||
@font-face {
|
@font-face {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user