feat: stop storing selection element into appState.draggingElement
This commit is contained in:
parent
44d9d5fcac
commit
add575a419
@ -170,6 +170,7 @@ export const actionFinalize = register({
|
|||||||
: activeTool,
|
: activeTool,
|
||||||
activeEmbeddable: null,
|
activeEmbeddable: null,
|
||||||
draggingElement: null,
|
draggingElement: null,
|
||||||
|
selectionElement: null,
|
||||||
multiElement: null,
|
multiElement: null,
|
||||||
editingElement: null,
|
editingElement: null,
|
||||||
startBoundElement: null,
|
startBoundElement: null,
|
||||||
@ -196,7 +197,9 @@ export const actionFinalize = register({
|
|||||||
keyTest: (event, appState) =>
|
keyTest: (event, appState) =>
|
||||||
(event.key === KEYS.ESCAPE &&
|
(event.key === KEYS.ESCAPE &&
|
||||||
(appState.editingLinearElement !== null ||
|
(appState.editingLinearElement !== null ||
|
||||||
(!appState.draggingElement && appState.multiElement === null))) ||
|
(!appState.selectionElement &&
|
||||||
|
!appState.draggingElement &&
|
||||||
|
appState.multiElement === null))) ||
|
||||||
((event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) &&
|
((event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) &&
|
||||||
appState.multiElement !== null),
|
appState.multiElement !== null),
|
||||||
PanelComponent: ({ appState, updateData, data }) => (
|
PanelComponent: ({ appState, updateData, data }) => (
|
||||||
|
@ -21,6 +21,7 @@ const writeData = (
|
|||||||
!appState.multiElement &&
|
!appState.multiElement &&
|
||||||
!appState.resizingElement &&
|
!appState.resizingElement &&
|
||||||
!appState.editingElement &&
|
!appState.editingElement &&
|
||||||
|
!appState.selectionElement &&
|
||||||
!appState.draggingElement
|
!appState.draggingElement
|
||||||
) {
|
) {
|
||||||
const data = updater();
|
const data = updater();
|
||||||
|
@ -3014,7 +3014,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
!event.ctrlKey &&
|
!event.ctrlKey &&
|
||||||
!event.altKey &&
|
!event.altKey &&
|
||||||
!event.metaKey &&
|
!event.metaKey &&
|
||||||
this.state.draggingElement === null
|
!this.state.draggingElement &&
|
||||||
|
!this.state.selectionElement
|
||||||
) {
|
) {
|
||||||
const shape = findShapeByKey(event.key);
|
const shape = findShapeByKey(event.key);
|
||||||
if (shape) {
|
if (shape) {
|
||||||
@ -3343,6 +3344,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
draggingElement: null,
|
draggingElement: null,
|
||||||
|
selectionElement: null,
|
||||||
editingElement: null,
|
editingElement: null,
|
||||||
});
|
});
|
||||||
if (this.state.activeTool.locked) {
|
if (this.state.activeTool.locked) {
|
||||||
@ -4421,8 +4423,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
// finger is lifted
|
// finger is lifted
|
||||||
if (
|
if (
|
||||||
event.pointerType === "touch" &&
|
event.pointerType === "touch" &&
|
||||||
this.state.draggingElement &&
|
this.state.draggingElement?.type === "freedraw"
|
||||||
this.state.draggingElement.type === "freedraw"
|
|
||||||
) {
|
) {
|
||||||
const element = this.state.draggingElement as ExcalidrawFreeDrawElement;
|
const element = this.state.draggingElement as ExcalidrawFreeDrawElement;
|
||||||
this.updateScene({
|
this.updateScene({
|
||||||
@ -4434,6 +4435,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
appState: {
|
appState: {
|
||||||
|
selectionElement: null,
|
||||||
draggingElement: null,
|
draggingElement: null,
|
||||||
editingElement: null,
|
editingElement: null,
|
||||||
startBoundElement: null,
|
startBoundElement: null,
|
||||||
@ -4561,13 +4563,16 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
// retrieve the latest element as the state may be stale
|
// retrieve the latest element as the state may be stale
|
||||||
const pendingImageElement =
|
const pendingImageElement =
|
||||||
this.state.pendingImageElementId &&
|
this.state.pendingImageElementId &&
|
||||||
this.scene.getElement(this.state.pendingImageElementId);
|
this.scene.getElement<ExcalidrawImageElement>(
|
||||||
|
this.state.pendingImageElementId,
|
||||||
|
);
|
||||||
|
|
||||||
if (!pendingImageElement) {
|
if (!pendingImageElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
selectionElement: null,
|
||||||
draggingElement: pendingImageElement,
|
draggingElement: pendingImageElement,
|
||||||
editingElement: pendingImageElement,
|
editingElement: pendingImageElement,
|
||||||
pendingImageElementId: null,
|
pendingImageElementId: null,
|
||||||
@ -5374,6 +5379,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
);
|
);
|
||||||
this.scene.addNewElement(element);
|
this.scene.addNewElement(element);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
selectionElement: null,
|
||||||
draggingElement: element,
|
draggingElement: element,
|
||||||
editingElement: element,
|
editingElement: element,
|
||||||
startBoundElement: boundElement,
|
startBoundElement: boundElement,
|
||||||
@ -5593,6 +5599,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
this.scene.addNewElement(element);
|
this.scene.addNewElement(element);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
selectionElement: null,
|
||||||
draggingElement: element,
|
draggingElement: element,
|
||||||
editingElement: element,
|
editingElement: element,
|
||||||
startBoundElement: boundElement,
|
startBoundElement: boundElement,
|
||||||
@ -5667,12 +5674,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (element.type === "selection") {
|
if (element.type === "selection") {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectionElement: element,
|
selectionElement: element,
|
||||||
draggingElement: element,
|
draggingElement: null,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.scene.addNewElement(element);
|
this.scene.addNewElement(element);
|
||||||
this.setState({
|
this.setState({
|
||||||
multiElement: null,
|
multiElement: null,
|
||||||
|
selectionElement: null,
|
||||||
draggingElement: element,
|
draggingElement: element,
|
||||||
editingElement: element,
|
editingElement: element,
|
||||||
});
|
});
|
||||||
@ -5705,6 +5713,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
multiElement: null,
|
multiElement: null,
|
||||||
|
selectionElement: null,
|
||||||
draggingElement: frame,
|
draggingElement: frame,
|
||||||
editingElement: frame,
|
editingElement: frame,
|
||||||
});
|
});
|
||||||
@ -5763,7 +5772,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (this.maybeHandleResize(pointerDownState, event)) {
|
if (this.maybeHandleResize(pointerDownState, event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.maybeDragNewGenericElement(pointerDownState, event);
|
if (!this.maybeUpdateSelectionElement(pointerDownState, event)) {
|
||||||
|
this.maybeDragNewGenericElement(pointerDownState, event);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5776,7 +5787,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (this.maybeHandleResize(pointerDownState, event)) {
|
if (this.maybeHandleResize(pointerDownState, event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.maybeDragNewGenericElement(pointerDownState, event);
|
if (!this.maybeUpdateSelectionElement(pointerDownState, event)) {
|
||||||
|
this.maybeDragNewGenericElement(pointerDownState, event);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6132,6 +6145,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pointerDownState.lastCoords.x = pointerCoords.x;
|
||||||
|
pointerDownState.lastCoords.y = pointerCoords.y;
|
||||||
|
|
||||||
|
if (this.maybeHandleBoxSelection(pointerDownState, event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// It is very important to read this.state within each move event,
|
// It is very important to read this.state within each move event,
|
||||||
// otherwise we would read a stale one!
|
// otherwise we would read a stale one!
|
||||||
const draggingElement = this.state.draggingElement;
|
const draggingElement = this.state.draggingElement;
|
||||||
@ -6199,105 +6219,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
pointerDownState.lastCoords.y = pointerCoords.y;
|
pointerDownState.lastCoords.y = pointerCoords.y;
|
||||||
this.maybeDragNewGenericElement(pointerDownState, event);
|
this.maybeDragNewGenericElement(pointerDownState, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.activeTool.type === "selection") {
|
|
||||||
pointerDownState.boxSelection.hasOccurred = true;
|
|
||||||
|
|
||||||
const elements = this.scene.getNonDeletedElements();
|
|
||||||
|
|
||||||
// box-select line editor points
|
|
||||||
if (this.state.editingLinearElement) {
|
|
||||||
LinearElementEditor.handleBoxSelection(
|
|
||||||
event,
|
|
||||||
this.state,
|
|
||||||
this.setState.bind(this),
|
|
||||||
);
|
|
||||||
// regular box-select
|
|
||||||
} else {
|
|
||||||
let shouldReuseSelection = true;
|
|
||||||
|
|
||||||
if (!event.shiftKey && isSomeElementSelected(elements, this.state)) {
|
|
||||||
if (
|
|
||||||
pointerDownState.withCmdOrCtrl &&
|
|
||||||
pointerDownState.hit.element
|
|
||||||
) {
|
|
||||||
this.setState((prevState) =>
|
|
||||||
selectGroupsForSelectedElements(
|
|
||||||
{
|
|
||||||
...prevState,
|
|
||||||
selectedElementIds: {
|
|
||||||
[pointerDownState.hit.element!.id]: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
this.scene.getNonDeletedElements(),
|
|
||||||
prevState,
|
|
||||||
this,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
shouldReuseSelection = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const elementsWithinSelection = getElementsWithinSelection(
|
|
||||||
elements,
|
|
||||||
draggingElement,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.setState((prevState) => {
|
|
||||||
const nextSelectedElementIds = {
|
|
||||||
...(shouldReuseSelection && prevState.selectedElementIds),
|
|
||||||
...elementsWithinSelection.reduce(
|
|
||||||
(acc: Record<ExcalidrawElement["id"], true>, element) => {
|
|
||||||
acc[element.id] = true;
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (pointerDownState.hit.element) {
|
|
||||||
// if using ctrl/cmd, select the hitElement only if we
|
|
||||||
// haven't box-selected anything else
|
|
||||||
if (!elementsWithinSelection.length) {
|
|
||||||
nextSelectedElementIds[pointerDownState.hit.element.id] = true;
|
|
||||||
} else {
|
|
||||||
delete nextSelectedElementIds[pointerDownState.hit.element.id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prevState = !shouldReuseSelection
|
|
||||||
? { ...prevState, selectedGroupIds: {}, editingGroupId: null }
|
|
||||||
: prevState;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...selectGroupsForSelectedElements(
|
|
||||||
{
|
|
||||||
editingGroupId: prevState.editingGroupId,
|
|
||||||
selectedElementIds: nextSelectedElementIds,
|
|
||||||
},
|
|
||||||
this.scene.getNonDeletedElements(),
|
|
||||||
prevState,
|
|
||||||
this,
|
|
||||||
),
|
|
||||||
// select linear element only when we haven't box-selected anything else
|
|
||||||
selectedLinearElement:
|
|
||||||
elementsWithinSelection.length === 1 &&
|
|
||||||
isLinearElement(elementsWithinSelection[0])
|
|
||||||
? new LinearElementEditor(
|
|
||||||
elementsWithinSelection[0],
|
|
||||||
this.scene,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
showHyperlinkPopup:
|
|
||||||
elementsWithinSelection.length === 1 &&
|
|
||||||
(elementsWithinSelection[0].link ||
|
|
||||||
isEmbeddableElement(elementsWithinSelection[0]))
|
|
||||||
? "info"
|
|
||||||
: false,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6558,6 +6479,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
resetCursor(this.interactiveCanvas);
|
resetCursor(this.interactiveCanvas);
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
draggingElement: null,
|
draggingElement: null,
|
||||||
|
selectionElement: null,
|
||||||
activeTool: updateActiveTool(this.state, {
|
activeTool: updateActiveTool(this.state, {
|
||||||
type: "selection",
|
type: "selection",
|
||||||
}),
|
}),
|
||||||
@ -6576,6 +6498,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
} else {
|
} else {
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
draggingElement: null,
|
draggingElement: null,
|
||||||
|
selectionElement: null,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6595,140 +6518,137 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
);
|
);
|
||||||
this.setState({
|
this.setState({
|
||||||
draggingElement: null,
|
draggingElement: null,
|
||||||
|
selectionElement: null,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draggingElement) {
|
if (pointerDownState.drag.hasOccurred) {
|
||||||
if (pointerDownState.drag.hasOccurred) {
|
const sceneCoords = viewportCoordsToSceneCoords(childEvent, this.state);
|
||||||
const sceneCoords = viewportCoordsToSceneCoords(
|
|
||||||
childEvent,
|
// when editing the points of a linear element, we check if the
|
||||||
this.state,
|
// linear element still is in the frame afterwards
|
||||||
|
// if not, the linear element will be removed from its frame (if any)
|
||||||
|
if (
|
||||||
|
this.state.selectedLinearElement &&
|
||||||
|
this.state.selectedLinearElement.isDragging
|
||||||
|
) {
|
||||||
|
const linearElement = this.scene.getElement(
|
||||||
|
this.state.selectedLinearElement.elementId,
|
||||||
);
|
);
|
||||||
|
|
||||||
// when editing the points of a linear element, we check if the
|
if (linearElement?.frameId) {
|
||||||
// linear element still is in the frame afterwards
|
const frame = getContainingFrame(linearElement);
|
||||||
// if not, the linear element will be removed from its frame (if any)
|
|
||||||
if (
|
|
||||||
this.state.selectedLinearElement &&
|
|
||||||
this.state.selectedLinearElement.isDragging
|
|
||||||
) {
|
|
||||||
const linearElement = this.scene.getElement(
|
|
||||||
this.state.selectedLinearElement.elementId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (linearElement?.frameId) {
|
if (frame && linearElement) {
|
||||||
const frame = getContainingFrame(linearElement);
|
if (!elementOverlapsWithFrame(linearElement, frame)) {
|
||||||
|
// remove the linear element from all groups
|
||||||
|
// before removing it from the frame as well
|
||||||
|
mutateElement(linearElement, {
|
||||||
|
groupIds: [],
|
||||||
|
});
|
||||||
|
|
||||||
if (frame && linearElement) {
|
this.scene.replaceAllElements(
|
||||||
if (!elementOverlapsWithFrame(linearElement, frame)) {
|
removeElementsFromFrame(
|
||||||
// remove the linear element from all groups
|
this.scene.getElementsIncludingDeleted(),
|
||||||
// before removing it from the frame as well
|
[linearElement],
|
||||||
mutateElement(linearElement, {
|
this.state,
|
||||||
groupIds: [],
|
),
|
||||||
});
|
);
|
||||||
|
|
||||||
this.scene.replaceAllElements(
|
|
||||||
removeElementsFromFrame(
|
|
||||||
this.scene.getElementsIncludingDeleted(),
|
|
||||||
[linearElement],
|
|
||||||
this.state,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// update the relationships between selected elements and frames
|
} else {
|
||||||
const topLayerFrame =
|
// update the relationships between selected elements and frames
|
||||||
this.getTopLayerFrameAtSceneCoords(sceneCoords);
|
const topLayerFrame = this.getTopLayerFrameAtSceneCoords(sceneCoords);
|
||||||
|
|
||||||
const selectedElements = this.scene.getSelectedElements(this.state);
|
const selectedElements = this.scene.getSelectedElements(this.state);
|
||||||
let nextElements = this.scene.getElementsIncludingDeleted();
|
let nextElements = this.scene.getElementsIncludingDeleted();
|
||||||
|
|
||||||
const updateGroupIdsAfterEditingGroup = (
|
const updateGroupIdsAfterEditingGroup = (
|
||||||
elements: ExcalidrawElement[],
|
elements: ExcalidrawElement[],
|
||||||
) => {
|
) => {
|
||||||
if (elements.length > 0) {
|
if (elements.length > 0) {
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
const index = element.groupIds.indexOf(
|
const index = element.groupIds.indexOf(
|
||||||
this.state.editingGroupId!,
|
this.state.editingGroupId!,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
mutateElement(
|
||||||
|
element,
|
||||||
|
{
|
||||||
|
groupIds: element.groupIds.slice(0, index),
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextElements.forEach((element) => {
|
||||||
|
if (
|
||||||
|
element.groupIds.length &&
|
||||||
|
getElementsInGroup(
|
||||||
|
nextElements,
|
||||||
|
element.groupIds[element.groupIds.length - 1],
|
||||||
|
).length < 2
|
||||||
|
) {
|
||||||
mutateElement(
|
mutateElement(
|
||||||
element,
|
element,
|
||||||
{
|
{
|
||||||
groupIds: element.groupIds.slice(0, index),
|
groupIds: [],
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
nextElements.forEach((element) => {
|
this.setState({
|
||||||
if (
|
editingGroupId: null,
|
||||||
element.groupIds.length &&
|
});
|
||||||
getElementsInGroup(
|
|
||||||
nextElements,
|
|
||||||
element.groupIds[element.groupIds.length - 1],
|
|
||||||
).length < 2
|
|
||||||
) {
|
|
||||||
mutateElement(
|
|
||||||
element,
|
|
||||||
{
|
|
||||||
groupIds: [],
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
editingGroupId: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (
|
|
||||||
topLayerFrame &&
|
|
||||||
!this.state.selectedElementIds[topLayerFrame.id]
|
|
||||||
) {
|
|
||||||
const elementsToAdd = selectedElements.filter(
|
|
||||||
(element) =>
|
|
||||||
element.frameId !== topLayerFrame.id &&
|
|
||||||
isElementInFrame(element, nextElements, this.state),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.state.editingGroupId) {
|
|
||||||
updateGroupIdsAfterEditingGroup(elementsToAdd);
|
|
||||||
}
|
|
||||||
|
|
||||||
nextElements = addElementsToFrame(
|
|
||||||
nextElements,
|
|
||||||
elementsToAdd,
|
|
||||||
topLayerFrame,
|
|
||||||
);
|
|
||||||
} else if (!topLayerFrame) {
|
|
||||||
if (this.state.editingGroupId) {
|
|
||||||
const elementsToRemove = selectedElements.filter(
|
|
||||||
(element) =>
|
|
||||||
element.frameId &&
|
|
||||||
!isElementInFrame(element, nextElements, this.state),
|
|
||||||
);
|
|
||||||
|
|
||||||
updateGroupIdsAfterEditingGroup(elementsToRemove);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
nextElements = updateFrameMembershipOfSelectedElements(
|
if (
|
||||||
nextElements,
|
topLayerFrame &&
|
||||||
this.state,
|
!this.state.selectedElementIds[topLayerFrame.id]
|
||||||
this,
|
) {
|
||||||
|
const elementsToAdd = selectedElements.filter(
|
||||||
|
(element) =>
|
||||||
|
element.frameId !== topLayerFrame.id &&
|
||||||
|
isElementInFrame(element, nextElements, this.state),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.scene.replaceAllElements(nextElements);
|
if (this.state.editingGroupId) {
|
||||||
}
|
updateGroupIdsAfterEditingGroup(elementsToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextElements = addElementsToFrame(
|
||||||
|
nextElements,
|
||||||
|
elementsToAdd,
|
||||||
|
topLayerFrame,
|
||||||
|
);
|
||||||
|
} else if (!topLayerFrame) {
|
||||||
|
if (this.state.editingGroupId) {
|
||||||
|
const elementsToRemove = selectedElements.filter(
|
||||||
|
(element) =>
|
||||||
|
element.frameId &&
|
||||||
|
!isElementInFrame(element, nextElements, this.state),
|
||||||
|
);
|
||||||
|
|
||||||
|
updateGroupIdsAfterEditingGroup(elementsToRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextElements = updateFrameMembershipOfSelectedElements(
|
||||||
|
nextElements,
|
||||||
|
this.state,
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.scene.replaceAllElements(nextElements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (draggingElement) {
|
||||||
if (draggingElement.type === "frame") {
|
if (draggingElement.type === "frame") {
|
||||||
const elementsInsideFrame = getElementsInNewFrame(
|
const elementsInsideFrame = getElementsInNewFrame(
|
||||||
this.scene.getElementsIncludingDeleted(),
|
this.scene.getElementsIncludingDeleted(),
|
||||||
@ -7032,8 +6952,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (
|
if (
|
||||||
!activeTool.locked &&
|
!activeTool.locked &&
|
||||||
activeTool.type !== "freedraw" &&
|
activeTool.type !== "freedraw" &&
|
||||||
draggingElement &&
|
draggingElement
|
||||||
draggingElement.type !== "selection"
|
|
||||||
) {
|
) {
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
selectedElementIds: makeNextSelectedElementIds(
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
@ -7072,12 +6991,14 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
resetCursor(this.interactiveCanvas);
|
resetCursor(this.interactiveCanvas);
|
||||||
this.setState({
|
this.setState({
|
||||||
draggingElement: null,
|
draggingElement: null,
|
||||||
|
selectionElement: null,
|
||||||
suggestedBindings: [],
|
suggestedBindings: [],
|
||||||
activeTool: updateActiveTool(this.state, { type: "selection" }),
|
activeTool: updateActiveTool(this.state, { type: "selection" }),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
draggingElement: null,
|
draggingElement: null,
|
||||||
|
selectionElement: null,
|
||||||
suggestedBindings: [],
|
suggestedBindings: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -7876,6 +7797,139 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private maybeUpdateSelectionElement = (
|
||||||
|
pointerDownState: PointerDownState,
|
||||||
|
event: PointerEvent | KeyboardEvent,
|
||||||
|
): boolean => {
|
||||||
|
const { selectionElement } = this.state;
|
||||||
|
|
||||||
|
if (!selectionElement || this.state.activeTool.type !== "selection") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pointerCoords = pointerDownState.lastCoords;
|
||||||
|
|
||||||
|
dragNewElement(
|
||||||
|
selectionElement,
|
||||||
|
this.state.activeTool.type,
|
||||||
|
pointerDownState.origin.x,
|
||||||
|
pointerDownState.origin.y,
|
||||||
|
pointerCoords.x,
|
||||||
|
pointerCoords.y,
|
||||||
|
distance(pointerDownState.origin.x, pointerCoords.x),
|
||||||
|
distance(pointerDownState.origin.y, pointerCoords.y),
|
||||||
|
shouldMaintainAspectRatio(event),
|
||||||
|
shouldResizeFromCenter(event),
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
private maybeHandleBoxSelection = (
|
||||||
|
pointerDownState: PointerDownState,
|
||||||
|
event: PointerEvent,
|
||||||
|
): boolean => {
|
||||||
|
const { selectionElement } = this.state;
|
||||||
|
|
||||||
|
if (!selectionElement || this.state.activeTool.type !== "selection") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maybeUpdateSelectionElement(pointerDownState, event);
|
||||||
|
|
||||||
|
pointerDownState.boxSelection.hasOccurred = true;
|
||||||
|
|
||||||
|
const elements = this.scene.getNonDeletedElements();
|
||||||
|
|
||||||
|
// box-select line editor points
|
||||||
|
if (this.state.editingLinearElement) {
|
||||||
|
LinearElementEditor.handleBoxSelection(
|
||||||
|
event,
|
||||||
|
this.state,
|
||||||
|
this.setState.bind(this),
|
||||||
|
);
|
||||||
|
// regular box-select
|
||||||
|
} else {
|
||||||
|
let shouldReuseSelection = true;
|
||||||
|
|
||||||
|
if (!event.shiftKey && isSomeElementSelected(elements, this.state)) {
|
||||||
|
if (pointerDownState.withCmdOrCtrl && pointerDownState.hit.element) {
|
||||||
|
this.setState((prevState) =>
|
||||||
|
selectGroupsForSelectedElements(
|
||||||
|
{
|
||||||
|
...prevState,
|
||||||
|
selectedElementIds: {
|
||||||
|
[pointerDownState.hit.element!.id]: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
prevState,
|
||||||
|
this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
shouldReuseSelection = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const elementsWithinSelection = getElementsWithinSelection(
|
||||||
|
elements,
|
||||||
|
selectionElement,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.setState((prevState) => {
|
||||||
|
const nextSelectedElementIds = {
|
||||||
|
...(shouldReuseSelection && prevState.selectedElementIds),
|
||||||
|
...elementsWithinSelection.reduce(
|
||||||
|
(acc: Record<ExcalidrawElement["id"], true>, element) => {
|
||||||
|
acc[element.id] = true;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (pointerDownState.hit.element) {
|
||||||
|
// if using ctrl/cmd, select the hitElement only if we
|
||||||
|
// haven't box-selected anything else
|
||||||
|
if (!elementsWithinSelection.length) {
|
||||||
|
nextSelectedElementIds[pointerDownState.hit.element.id] = true;
|
||||||
|
} else {
|
||||||
|
delete nextSelectedElementIds[pointerDownState.hit.element.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prevState = !shouldReuseSelection
|
||||||
|
? { ...prevState, selectedGroupIds: {}, editingGroupId: null }
|
||||||
|
: prevState;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...selectGroupsForSelectedElements(
|
||||||
|
{
|
||||||
|
editingGroupId: prevState.editingGroupId,
|
||||||
|
selectedElementIds: nextSelectedElementIds,
|
||||||
|
},
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
prevState,
|
||||||
|
this,
|
||||||
|
),
|
||||||
|
// select linear element only when we haven't box-selected anything else
|
||||||
|
selectedLinearElement:
|
||||||
|
elementsWithinSelection.length === 1 &&
|
||||||
|
isLinearElement(elementsWithinSelection[0])
|
||||||
|
? new LinearElementEditor(elementsWithinSelection[0], this.scene)
|
||||||
|
: null,
|
||||||
|
showHyperlinkPopup:
|
||||||
|
elementsWithinSelection.length === 1 &&
|
||||||
|
(elementsWithinSelection[0].link ||
|
||||||
|
isEmbeddableElement(elementsWithinSelection[0]))
|
||||||
|
? "info"
|
||||||
|
: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
private maybeDragNewGenericElement = (
|
private maybeDragNewGenericElement = (
|
||||||
pointerDownState: PointerDownState,
|
pointerDownState: PointerDownState,
|
||||||
event: MouseEvent | KeyboardEvent,
|
event: MouseEvent | KeyboardEvent,
|
||||||
@ -7885,93 +7939,73 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (!draggingElement) {
|
if (!draggingElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
let [gridX, gridY] = getGridPoint(
|
||||||
draggingElement.type === "selection" &&
|
pointerCoords.x,
|
||||||
this.state.activeTool.type !== "eraser"
|
pointerCoords.y,
|
||||||
) {
|
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
||||||
dragNewElement(
|
);
|
||||||
draggingElement,
|
|
||||||
this.state.activeTool.type,
|
|
||||||
pointerDownState.origin.x,
|
|
||||||
pointerDownState.origin.y,
|
|
||||||
pointerCoords.x,
|
|
||||||
pointerCoords.y,
|
|
||||||
distance(pointerDownState.origin.x, pointerCoords.x),
|
|
||||||
distance(pointerDownState.origin.y, pointerCoords.y),
|
|
||||||
shouldMaintainAspectRatio(event),
|
|
||||||
shouldResizeFromCenter(event),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let [gridX, gridY] = getGridPoint(
|
|
||||||
pointerCoords.x,
|
|
||||||
pointerCoords.y,
|
|
||||||
event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
|
|
||||||
);
|
|
||||||
|
|
||||||
const image =
|
const image =
|
||||||
isInitializedImageElement(draggingElement) &&
|
isInitializedImageElement(draggingElement) &&
|
||||||
this.imageCache.get(draggingElement.fileId)?.image;
|
this.imageCache.get(draggingElement.fileId)?.image;
|
||||||
const aspectRatio =
|
const aspectRatio =
|
||||||
image && !(image instanceof Promise)
|
image && !(image instanceof Promise) ? image.width / image.height : null;
|
||||||
? image.width / image.height
|
|
||||||
: null;
|
|
||||||
|
|
||||||
this.maybeCacheReferenceSnapPoints(event, [draggingElement]);
|
this.maybeCacheReferenceSnapPoints(event, [draggingElement]);
|
||||||
|
|
||||||
const { snapOffset, snapLines } = snapNewElement(
|
const { snapOffset, snapLines } = snapNewElement(
|
||||||
draggingElement,
|
draggingElement,
|
||||||
this.state,
|
this.state,
|
||||||
event,
|
event,
|
||||||
{
|
{
|
||||||
x:
|
x:
|
||||||
pointerDownState.originInGrid.x +
|
pointerDownState.originInGrid.x +
|
||||||
(this.state.originSnapOffset?.x ?? 0),
|
(this.state.originSnapOffset?.x ?? 0),
|
||||||
y:
|
y:
|
||||||
pointerDownState.originInGrid.y +
|
pointerDownState.originInGrid.y +
|
||||||
(this.state.originSnapOffset?.y ?? 0),
|
(this.state.originSnapOffset?.y ?? 0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: gridX - pointerDownState.originInGrid.x,
|
x: gridX - pointerDownState.originInGrid.x,
|
||||||
y: gridY - pointerDownState.originInGrid.y,
|
y: gridY - pointerDownState.originInGrid.y,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
gridX += snapOffset.x;
|
gridX += snapOffset.x;
|
||||||
gridY += snapOffset.y;
|
gridY += snapOffset.y;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
snapLines,
|
||||||
|
});
|
||||||
|
|
||||||
|
dragNewElement(
|
||||||
|
draggingElement,
|
||||||
|
this.state.activeTool.type,
|
||||||
|
pointerDownState.originInGrid.x,
|
||||||
|
pointerDownState.originInGrid.y,
|
||||||
|
gridX,
|
||||||
|
gridY,
|
||||||
|
distance(pointerDownState.originInGrid.x, gridX),
|
||||||
|
distance(pointerDownState.originInGrid.y, gridY),
|
||||||
|
isImageElement(draggingElement)
|
||||||
|
? !shouldMaintainAspectRatio(event)
|
||||||
|
: shouldMaintainAspectRatio(event),
|
||||||
|
shouldResizeFromCenter(event),
|
||||||
|
aspectRatio,
|
||||||
|
this.state.originSnapOffset,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.maybeSuggestBindingForAll([draggingElement]);
|
||||||
|
|
||||||
|
// highlight elements that are to be added to frames on frames creation
|
||||||
|
if (this.state.activeTool.type === "frame") {
|
||||||
this.setState({
|
this.setState({
|
||||||
snapLines,
|
elementsToHighlight: getElementsInResizingFrame(
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
draggingElement as ExcalidrawFrameElement,
|
||||||
|
this.state,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
dragNewElement(
|
|
||||||
draggingElement,
|
|
||||||
this.state.activeTool.type,
|
|
||||||
pointerDownState.originInGrid.x,
|
|
||||||
pointerDownState.originInGrid.y,
|
|
||||||
gridX,
|
|
||||||
gridY,
|
|
||||||
distance(pointerDownState.originInGrid.x, gridX),
|
|
||||||
distance(pointerDownState.originInGrid.y, gridY),
|
|
||||||
isImageElement(draggingElement)
|
|
||||||
? !shouldMaintainAspectRatio(event)
|
|
||||||
: shouldMaintainAspectRatio(event),
|
|
||||||
shouldResizeFromCenter(event),
|
|
||||||
aspectRatio,
|
|
||||||
this.state.originSnapOffset,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.maybeSuggestBindingForAll([draggingElement]);
|
|
||||||
|
|
||||||
// highlight elements that are to be added to frames on frames creation
|
|
||||||
if (this.state.activeTool.type === "frame") {
|
|
||||||
this.setState({
|
|
||||||
elementsToHighlight: getElementsInResizingFrame(
|
|
||||||
this.scene.getNonDeletedElements(),
|
|
||||||
draggingElement as ExcalidrawFrameElement,
|
|
||||||
this.state,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,8 +82,9 @@ const getHints = ({ appState, isMobile, device, app }: HintViewerProps) => {
|
|||||||
|
|
||||||
if (activeTool.type === "selection") {
|
if (activeTool.type === "selection") {
|
||||||
if (
|
if (
|
||||||
appState.draggingElement?.type === "selection" &&
|
appState.selectionElement &&
|
||||||
!selectedElements.length &&
|
!selectedElements.length &&
|
||||||
|
!appState.draggingElement &&
|
||||||
!appState.editingElement &&
|
!appState.editingElement &&
|
||||||
!appState.editingLinearElement
|
!appState.editingLinearElement
|
||||||
) {
|
) {
|
||||||
|
@ -210,6 +210,7 @@ export const Hyperlink = ({
|
|||||||
};
|
};
|
||||||
const { x, y } = getCoordsForPopover(element, appState);
|
const { x, y } = getCoordsForPopover(element, appState);
|
||||||
if (
|
if (
|
||||||
|
appState.selectionElement ||
|
||||||
appState.draggingElement ||
|
appState.draggingElement ||
|
||||||
appState.resizingElement ||
|
appState.resizingElement ||
|
||||||
appState.isRotating ||
|
appState.isRotating ||
|
||||||
|
@ -134,10 +134,7 @@ export class LinearElementEditor {
|
|||||||
appState: AppState,
|
appState: AppState,
|
||||||
setState: React.Component<any, AppState>["setState"],
|
setState: React.Component<any, AppState>["setState"],
|
||||||
) {
|
) {
|
||||||
if (
|
if (!appState.editingLinearElement || !appState.selectionElement) {
|
||||||
!appState.editingLinearElement ||
|
|
||||||
appState.draggingElement?.type !== "selection"
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const { editingLinearElement } = appState;
|
const { editingLinearElement } = appState;
|
||||||
@ -149,7 +146,7 @@ export class LinearElementEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [selectionX1, selectionY1, selectionX2, selectionY2] =
|
const [selectionX1, selectionY1, selectionX2, selectionY2] =
|
||||||
getElementAbsoluteCoords(appState.draggingElement);
|
getElementAbsoluteCoords(appState.selectionElement);
|
||||||
|
|
||||||
const pointsSceneCoords =
|
const pointsSceneCoords =
|
||||||
LinearElementEditor.getPointsGlobalCoordinates(element);
|
LinearElementEditor.getPointsGlobalCoordinates(element);
|
||||||
|
@ -5152,35 +5152,7 @@ exports[`regression tests > deselects group of selected elements on pointer down
|
|||||||
"currentItemTextAlign": "left",
|
"currentItemTextAlign": "left",
|
||||||
"cursorButton": "down",
|
"cursorButton": "down",
|
||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"draggingElement": {
|
"draggingElement": null,
|
||||||
"angle": 0,
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"boundElements": null,
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
|
||||||
"height": 0,
|
|
||||||
"id": "id3",
|
|
||||||
"isDeleted": false,
|
|
||||||
"link": null,
|
|
||||||
"locked": false,
|
|
||||||
"opacity": 100,
|
|
||||||
"roughness": 1,
|
|
||||||
"roundness": {
|
|
||||||
"type": 2,
|
|
||||||
},
|
|
||||||
"seed": 400692809,
|
|
||||||
"strokeColor": "#1e1e1e",
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"type": "selection",
|
|
||||||
"updated": 1,
|
|
||||||
"version": 1,
|
|
||||||
"versionNonce": 0,
|
|
||||||
"width": 0,
|
|
||||||
"x": 500,
|
|
||||||
"y": 500,
|
|
||||||
},
|
|
||||||
"editingElement": null,
|
"editingElement": null,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
@ -5449,35 +5421,7 @@ exports[`regression tests > deselects group of selected elements on pointer up w
|
|||||||
"currentItemTextAlign": "left",
|
"currentItemTextAlign": "left",
|
||||||
"cursorButton": "up",
|
"cursorButton": "up",
|
||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"draggingElement": {
|
"draggingElement": null,
|
||||||
"angle": 0,
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"boundElements": null,
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
|
||||||
"height": 0,
|
|
||||||
"id": "id3",
|
|
||||||
"isDeleted": false,
|
|
||||||
"link": null,
|
|
||||||
"locked": false,
|
|
||||||
"opacity": 100,
|
|
||||||
"roughness": 1,
|
|
||||||
"roundness": {
|
|
||||||
"type": 2,
|
|
||||||
},
|
|
||||||
"seed": 400692809,
|
|
||||||
"strokeColor": "#1e1e1e",
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"type": "selection",
|
|
||||||
"updated": 1,
|
|
||||||
"version": 1,
|
|
||||||
"versionNonce": 0,
|
|
||||||
"width": 0,
|
|
||||||
"x": 50,
|
|
||||||
"y": 50,
|
|
||||||
},
|
|
||||||
"editingElement": null,
|
"editingElement": null,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
@ -5718,35 +5662,7 @@ exports[`regression tests > deselects selected element on pointer down when poin
|
|||||||
"currentItemTextAlign": "left",
|
"currentItemTextAlign": "left",
|
||||||
"cursorButton": "down",
|
"cursorButton": "down",
|
||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"draggingElement": {
|
"draggingElement": null,
|
||||||
"angle": 0,
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"boundElements": null,
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
|
||||||
"height": 0,
|
|
||||||
"id": "id1",
|
|
||||||
"isDeleted": false,
|
|
||||||
"link": null,
|
|
||||||
"locked": false,
|
|
||||||
"opacity": 100,
|
|
||||||
"roughness": 1,
|
|
||||||
"roundness": {
|
|
||||||
"type": 2,
|
|
||||||
},
|
|
||||||
"seed": 2019559783,
|
|
||||||
"strokeColor": "#1e1e1e",
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"type": "selection",
|
|
||||||
"updated": 1,
|
|
||||||
"version": 1,
|
|
||||||
"versionNonce": 0,
|
|
||||||
"width": 0,
|
|
||||||
"x": 110,
|
|
||||||
"y": 110,
|
|
||||||
},
|
|
||||||
"editingElement": null,
|
"editingElement": null,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
@ -16262,35 +16178,7 @@ exports[`regression tests > switches from group of selected elements to another
|
|||||||
"currentItemTextAlign": "left",
|
"currentItemTextAlign": "left",
|
||||||
"cursorButton": "down",
|
"cursorButton": "down",
|
||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"draggingElement": {
|
"draggingElement": null,
|
||||||
"angle": 0,
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"boundElements": null,
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
|
||||||
"height": 0,
|
|
||||||
"id": "id4",
|
|
||||||
"isDeleted": false,
|
|
||||||
"link": null,
|
|
||||||
"locked": false,
|
|
||||||
"opacity": 100,
|
|
||||||
"roughness": 1,
|
|
||||||
"roundness": {
|
|
||||||
"type": 2,
|
|
||||||
},
|
|
||||||
"seed": 493213705,
|
|
||||||
"strokeColor": "#1e1e1e",
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"type": "selection",
|
|
||||||
"updated": 1,
|
|
||||||
"version": 1,
|
|
||||||
"versionNonce": 0,
|
|
||||||
"width": 0,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
},
|
|
||||||
"editingElement": null,
|
"editingElement": null,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
@ -16662,35 +16550,7 @@ exports[`regression tests > switches selected element on pointer down > [end of
|
|||||||
"currentItemTextAlign": "left",
|
"currentItemTextAlign": "left",
|
||||||
"cursorButton": "down",
|
"cursorButton": "down",
|
||||||
"defaultSidebarDockedPreference": false,
|
"defaultSidebarDockedPreference": false,
|
||||||
"draggingElement": {
|
"draggingElement": null,
|
||||||
"angle": 0,
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"boundElements": null,
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"frameId": null,
|
|
||||||
"groupIds": [],
|
|
||||||
"height": 0,
|
|
||||||
"id": "id2",
|
|
||||||
"isDeleted": false,
|
|
||||||
"link": null,
|
|
||||||
"locked": false,
|
|
||||||
"opacity": 100,
|
|
||||||
"roughness": 1,
|
|
||||||
"roundness": {
|
|
||||||
"type": 2,
|
|
||||||
},
|
|
||||||
"seed": 238820263,
|
|
||||||
"strokeColor": "#1e1e1e",
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"type": "selection",
|
|
||||||
"updated": 1,
|
|
||||||
"version": 1,
|
|
||||||
"versionNonce": 0,
|
|
||||||
"width": 0,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
},
|
|
||||||
"editingElement": null,
|
"editingElement": null,
|
||||||
"editingFrame": null,
|
"editingFrame": null,
|
||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
|
29
src/types.ts
29
src/types.ts
@ -17,6 +17,7 @@ import {
|
|||||||
StrokeRoundness,
|
StrokeRoundness,
|
||||||
ExcalidrawFrameElement,
|
ExcalidrawFrameElement,
|
||||||
ExcalidrawEmbeddableElement,
|
ExcalidrawEmbeddableElement,
|
||||||
|
ExcalidrawSelectionElement,
|
||||||
} from "./element/types";
|
} from "./element/types";
|
||||||
import { Point as RoughPoint } from "roughjs/bin/geometry";
|
import { Point as RoughPoint } from "roughjs/bin/geometry";
|
||||||
import { LinearElementEditor } from "./element/linearElementEditor";
|
import { LinearElementEditor } from "./element/linearElementEditor";
|
||||||
@ -182,10 +183,25 @@ export type AppState = {
|
|||||||
element: NonDeletedExcalidrawElement;
|
element: NonDeletedExcalidrawElement;
|
||||||
state: "hover" | "active";
|
state: "hover" | "active";
|
||||||
} | null;
|
} | null;
|
||||||
draggingElement: NonDeletedExcalidrawElement | null;
|
/** element that's being dragged or created */
|
||||||
|
draggingElement: Exclude<
|
||||||
|
NonDeletedExcalidrawElement,
|
||||||
|
ExcalidrawSelectionElement
|
||||||
|
> | null;
|
||||||
|
/**
|
||||||
|
* Element that's being resized.
|
||||||
|
* NOTE not set when resizing a group or linear element
|
||||||
|
*/
|
||||||
resizingElement: NonDeletedExcalidrawElement | null;
|
resizingElement: NonDeletedExcalidrawElement | null;
|
||||||
|
/** multi-point linear element when it's being created */
|
||||||
multiElement: NonDeleted<ExcalidrawLinearElement> | null;
|
multiElement: NonDeleted<ExcalidrawLinearElement> | null;
|
||||||
selectionElement: NonDeletedExcalidrawElement | null;
|
/**
|
||||||
|
* The selection box (we currently use an excalidraw element).
|
||||||
|
*
|
||||||
|
* Checking for this attribute is a good way to determine whether the user is
|
||||||
|
* selecting.
|
||||||
|
*/
|
||||||
|
selectionElement: ExcalidrawSelectionElement | null;
|
||||||
isBindingEnabled: boolean;
|
isBindingEnabled: boolean;
|
||||||
startBoundElement: NonDeleted<ExcalidrawBindableElement> | null;
|
startBoundElement: NonDeleted<ExcalidrawBindableElement> | null;
|
||||||
suggestedBindings: SuggestedBinding[];
|
suggestedBindings: SuggestedBinding[];
|
||||||
@ -198,9 +214,14 @@ export type AppState = {
|
|||||||
};
|
};
|
||||||
editingFrame: string | null;
|
editingFrame: string | null;
|
||||||
elementsToHighlight: NonDeleted<ExcalidrawElement>[] | null;
|
elementsToHighlight: NonDeleted<ExcalidrawElement>[] | null;
|
||||||
// element being edited, but not necessarily added to elements array yet
|
/**
|
||||||
// (e.g. text element when typing into the input)
|
* Text that's being element, or new element being created.
|
||||||
|
*/
|
||||||
editingElement: NonDeletedExcalidrawElement | null;
|
editingElement: NonDeletedExcalidrawElement | null;
|
||||||
|
/**
|
||||||
|
* Linear element that's being edited (when in the linear element editor).
|
||||||
|
* Not set when creating multi-point linear element.
|
||||||
|
*/
|
||||||
editingLinearElement: LinearElementEditor | null;
|
editingLinearElement: LinearElementEditor | null;
|
||||||
activeTool: {
|
activeTool: {
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user