Resize handler detection should not be active when moving multip… (#767)
* Fix bug. * Implement `getSelectedElements`. * Explicit condition. * Respect variable naming. * Keep state consistent. * Use `isSomeElementSelected` abstraction. * Missing ones.
This commit is contained in:
parent
ad72946131
commit
6ebd41734f
@ -1,5 +1,5 @@
|
||||
import { Action } from "./types";
|
||||
import { deleteSelectedElements } from "../scene";
|
||||
import { deleteSelectedElements, isSomeElementSelected } from "../scene";
|
||||
import { KEYS } from "../keys";
|
||||
|
||||
export const actionDeleteSelected: Action = {
|
||||
@ -12,6 +12,6 @@ export const actionDeleteSelected: Action = {
|
||||
},
|
||||
contextItemLabel: "labels.delete",
|
||||
contextMenuOrder: 3,
|
||||
commitToHistory: (_, elements) => elements.some(el => el.isSelected),
|
||||
commitToHistory: (_, elements) => isSomeElementSelected(elements),
|
||||
keyTest: event => event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE,
|
||||
};
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React from "react";
|
||||
import { Action } from "./types";
|
||||
import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
|
||||
import { getCommonAttributeOfSelectedElements } from "../scene";
|
||||
import {
|
||||
getCommonAttributeOfSelectedElements,
|
||||
isSomeElementSelected,
|
||||
} from "../scene";
|
||||
import { ButtonSelect } from "../components/ButtonSelect";
|
||||
import { isTextElement, redrawTextBoundingBox } from "../element";
|
||||
import { ColorPicker } from "../components/ColorPicker";
|
||||
@ -28,7 +31,7 @@ const getFormValue = function<T>(
|
||||
): T | null {
|
||||
return (
|
||||
(editingElement && getAttribute(editingElement)) ??
|
||||
(elements.some(element => element.isSelected)
|
||||
(isSomeElementSelected(elements)
|
||||
? getCommonAttributeOfSelectedElements(elements, getAttribute)
|
||||
: defaultValue) ??
|
||||
null
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ExcalidrawElement } from "./element/types";
|
||||
import { getSelectedElements } from "./scene";
|
||||
|
||||
let CLIPBOARD = "";
|
||||
let PREFER_APP_CLIPBOARD = false;
|
||||
@ -19,9 +20,7 @@ export async function copyToAppClipboard(
|
||||
elements: readonly ExcalidrawElement[],
|
||||
) {
|
||||
CLIPBOARD = JSON.stringify(
|
||||
elements
|
||||
.filter(element => element.isSelected)
|
||||
.map(({ shape, ...el }) => el),
|
||||
getSelectedElements(elements).map(({ shape, ...el }) => el),
|
||||
);
|
||||
try {
|
||||
// when copying to in-app clipboard, clear system clipboard so that if
|
||||
|
@ -16,6 +16,7 @@ import { t } from "../i18n";
|
||||
import { KEYS } from "../keys";
|
||||
|
||||
import { probablySupportsClipboardBlob } from "../clipboard";
|
||||
import { getSelectedElements, isSomeElementSelected } from "../scene";
|
||||
|
||||
const scales = [1, 2, 3];
|
||||
const defaultScale = scales.includes(devicePixelRatio) ? devicePixelRatio : 1;
|
||||
@ -46,7 +47,7 @@ function ExportModal({
|
||||
onExportToBackend: ExportCB;
|
||||
onCloseRequest: () => void;
|
||||
}) {
|
||||
const someElementIsSelected = elements.some(element => element.isSelected);
|
||||
const someElementIsSelected = isSomeElementSelected(elements);
|
||||
const [scale, setScale] = useState(defaultScale);
|
||||
const [exportSelected, setExportSelected] = useState(someElementIsSelected);
|
||||
const previewRef = useRef<HTMLDivElement>(null);
|
||||
@ -56,7 +57,7 @@ function ExportModal({
|
||||
const onlySelectedInput = useRef<HTMLInputElement>(null);
|
||||
|
||||
const exportedElements = exportSelected
|
||||
? elements.filter(element => element.isSelected)
|
||||
? getSelectedElements(elements)
|
||||
: elements;
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { t } from "../i18n";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { getSelectedElements } from "../scene";
|
||||
|
||||
import "./HintViewer.css";
|
||||
|
||||
@ -20,7 +21,7 @@ const getHints = ({ elementType, multiMode, isResizing, elements }: Hint) => {
|
||||
}
|
||||
|
||||
if (isResizing) {
|
||||
const selectedElements = elements.filter(el => el.isSelected);
|
||||
const selectedElements = getSelectedElements(elements);
|
||||
if (
|
||||
selectedElements.length === 1 &&
|
||||
(selectedElements[0].type === "arrow" ||
|
||||
|
@ -36,6 +36,8 @@ import {
|
||||
loadFromBlob,
|
||||
getZoomOrigin,
|
||||
getNormalizedZoom,
|
||||
getSelectedElements,
|
||||
isSomeElementSelected,
|
||||
} from "./scene";
|
||||
|
||||
import { renderScene } from "./renderer";
|
||||
@ -275,7 +277,7 @@ const LayerUI = React.memo(
|
||||
const { elementType, editingElement } = appState;
|
||||
const targetElements = editingElement
|
||||
? [editingElement]
|
||||
: elements.filter(el => el.isSelected);
|
||||
: getSelectedElements(elements);
|
||||
if (!targetElements.length && elementType === "selection") {
|
||||
return null;
|
||||
}
|
||||
@ -1046,11 +1048,15 @@ export class App extends React.Component<any, AppState> {
|
||||
{ x, y },
|
||||
this.state.zoom,
|
||||
);
|
||||
|
||||
const selectedElements = getSelectedElements(elements);
|
||||
if (selectedElements.length === 1 && resizeElement) {
|
||||
this.setState({
|
||||
resizingElement: resizeElement ? resizeElement.element : null,
|
||||
resizingElement: resizeElement
|
||||
? resizeElement.element
|
||||
: null,
|
||||
});
|
||||
|
||||
if (resizeElement) {
|
||||
resizeHandle = resizeElement.resizeHandle;
|
||||
document.documentElement.style.cursor = getCursorForResizingElement(
|
||||
resizeElement,
|
||||
@ -1087,9 +1093,7 @@ export class App extends React.Component<any, AppState> {
|
||||
...element,
|
||||
isSelected: false,
|
||||
})),
|
||||
...elements
|
||||
.filter(element => element.isSelected)
|
||||
.map(element => {
|
||||
...getSelectedElements(elements).map(element => {
|
||||
const newElement = duplicateElement(element);
|
||||
newElement.isSelected = true;
|
||||
return newElement;
|
||||
@ -1328,7 +1332,7 @@ export class App extends React.Component<any, AppState> {
|
||||
if (isResizingElements && this.state.resizingElement) {
|
||||
this.setState({ isResizing: true });
|
||||
const el = this.state.resizingElement;
|
||||
const selectedElements = elements.filter(el => el.isSelected);
|
||||
const selectedElements = getSelectedElements(elements);
|
||||
if (selectedElements.length === 1) {
|
||||
const { x, y } = viewportCoordsToSceneCoords(
|
||||
e,
|
||||
@ -1555,8 +1559,8 @@ export class App extends React.Component<any, AppState> {
|
||||
// Marking that click was used for dragging to check
|
||||
// if elements should be deselected on mouseup
|
||||
draggingOccurred = true;
|
||||
const selectedElements = elements.filter(el => el.isSelected);
|
||||
if (selectedElements.length) {
|
||||
const selectedElements = getSelectedElements(elements);
|
||||
if (selectedElements.length > 0) {
|
||||
const { x, y } = viewportCoordsToSceneCoords(
|
||||
e,
|
||||
this.state,
|
||||
@ -1638,7 +1642,7 @@ export class App extends React.Component<any, AppState> {
|
||||
draggingElement.shape = null;
|
||||
|
||||
if (this.state.elementType === "selection") {
|
||||
if (!e.shiftKey && elements.some(el => el.isSelected)) {
|
||||
if (!e.shiftKey && isSomeElementSelected(elements)) {
|
||||
elements = clearSelection(elements);
|
||||
}
|
||||
const elementsWithinSelection = getElementsWithinSelection(
|
||||
@ -1772,7 +1776,7 @@ export class App extends React.Component<any, AppState> {
|
||||
|
||||
if (
|
||||
elementType !== "selection" ||
|
||||
elements.some(el => el.isSelected)
|
||||
isSomeElementSelected(elements)
|
||||
) {
|
||||
history.resumeRecording();
|
||||
}
|
||||
@ -1941,9 +1945,8 @@ export class App extends React.Component<any, AppState> {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedElements = elements.filter(e => e.isSelected)
|
||||
.length;
|
||||
if (selectedElements === 1) {
|
||||
const selectedElements = getSelectedElements(elements);
|
||||
if (selectedElements.length === 1) {
|
||||
const resizeElement = getElementWithResizeHandler(
|
||||
elements,
|
||||
{ x, y },
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
SCROLLBAR_WIDTH,
|
||||
} from "../scene/scrollbars";
|
||||
import { getZoomTranslation } from "../scene/zoom";
|
||||
import { getSelectedElements } from "../scene/selection";
|
||||
|
||||
import { renderElement, renderElementToSvg } from "./renderElement";
|
||||
|
||||
@ -135,7 +136,7 @@ export function renderScene(
|
||||
|
||||
// Pain selected elements
|
||||
if (renderSelection) {
|
||||
const selectedElements = elements.filter(element => element.isSelected);
|
||||
const selectedElements = getSelectedElements(elements);
|
||||
const dashledLinePadding = 4 / sceneState.zoom;
|
||||
|
||||
context.save();
|
||||
|
@ -3,9 +3,10 @@ export {
|
||||
clearSelection,
|
||||
getSelectedIndices,
|
||||
deleteSelectedElements,
|
||||
someElementIsSelected,
|
||||
isSomeElementSelected,
|
||||
getElementsWithinSelection,
|
||||
getCommonAttributeOfSelectedElements,
|
||||
getSelectedElements,
|
||||
} from "./selection";
|
||||
export {
|
||||
exportCanvas,
|
||||
|
@ -55,8 +55,11 @@ export function getSelectedIndices(elements: readonly ExcalidrawElement[]) {
|
||||
return selectedIndices;
|
||||
}
|
||||
|
||||
export const someElementIsSelected = (elements: readonly ExcalidrawElement[]) =>
|
||||
elements.some(element => element.isSelected);
|
||||
export function isSomeElementSelected(
|
||||
elements: readonly ExcalidrawElement[],
|
||||
): boolean {
|
||||
return elements.some(element => element.isSelected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns common attribute (picked by `getAttribute` callback) of selected
|
||||
@ -68,10 +71,14 @@ export function getCommonAttributeOfSelectedElements<T>(
|
||||
): T | null {
|
||||
const attributes = Array.from(
|
||||
new Set(
|
||||
elements
|
||||
.filter(element => element.isSelected)
|
||||
.map(element => getAttribute(element)),
|
||||
getSelectedElements(elements).map(element => getAttribute(element)),
|
||||
),
|
||||
);
|
||||
return attributes.length === 1 ? attributes[0] : null;
|
||||
}
|
||||
|
||||
export function getSelectedElements(
|
||||
elements: readonly ExcalidrawElement[],
|
||||
): readonly ExcalidrawElement[] {
|
||||
return elements.filter(element => element.isSelected);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user