fix: binding text to non-bindable containers and not always preferring selection (#4655)

This commit is contained in:
David Luzar 2022-03-02 17:04:09 +01:00 committed by GitHub
parent 8e26d5b500
commit 6d0716eb6b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 336 additions and 85 deletions

View file

@ -127,6 +127,7 @@ import {
isInitializedImageElement,
isLinearElement,
isLinearElementType,
isTextBindableContainer,
} from "../element/typeChecks";
import {
ExcalidrawBindableElement,
@ -140,6 +141,7 @@ import {
ExcalidrawImageElement,
FileId,
NonDeletedExcalidrawElement,
ExcalidrawTextContainer,
} from "../element/types";
import { getCenter, getDistance } from "../gesture";
import {
@ -167,7 +169,7 @@ import { renderScene } from "../renderer";
import { invalidateShapeForElement } from "../renderer/renderElement";
import {
calculateScrollCenter,
getElementContainingPosition,
getTextBindableContainerAtPosition,
getElementsAtPosition,
getElementsWithinSelection,
getNormalizedZoom,
@ -238,7 +240,7 @@ import {
bindTextToShapeAfterDuplication,
getApproxMinLineHeight,
getApproxMinLineWidth,
getBoundTextElementId,
getBoundTextElement,
} from "../element/textElement";
import { isHittingElementNotConsideringBoundingBox } from "../element/collision";
import {
@ -2157,28 +2159,40 @@ class App extends React.Component<AppProps, AppState> {
window.devicePixelRatio,
);
// bind to container when shouldBind is true or
// clicked on center of container
const container =
shouldBind || parentCenterPosition
? getElementContainingPosition(
this.scene.getElements().filter((ele) => !isTextElement(ele)),
sceneX,
sceneY,
)
: null;
let existingTextElement: NonDeleted<ExcalidrawTextElement> | null = null;
let container: ExcalidrawTextContainer | null = null;
let existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);
const selectedElements = getSelectedElements(
this.scene.getElements(),
this.state,
);
// consider bounded text element if container present
if (container) {
const boundTextElementId = getBoundTextElementId(container);
if (boundTextElementId) {
existingTextElement = this.scene.getElement(
boundTextElementId,
) as ExcalidrawTextElement;
if (selectedElements.length === 1) {
if (isTextElement(selectedElements[0])) {
existingTextElement = selectedElements[0];
} else if (isTextBindableContainer(selectedElements[0])) {
container = selectedElements[0];
existingTextElement = getBoundTextElement(container);
}
}
existingTextElement =
existingTextElement ?? this.getTextElementAtPosition(sceneX, sceneY);
// bind to container when shouldBind is true or
// clicked on center of container
if (
!container &&
!existingTextElement &&
(shouldBind || parentCenterPosition)
) {
container = getTextBindableContainerAtPosition(
this.scene.getElements().filter((ele) => !isTextElement(ele)),
sceneX,
sceneY,
);
}
if (!existingTextElement && container) {
const fontString = {
fontSize: this.state.currentItemFontSize,
@ -5432,7 +5446,7 @@ class App extends React.Component<AppProps, AppState> {
canvas: HTMLCanvasElement | null,
scale: number,
) {
const elementClickedInside = getElementContainingPosition(
const elementClickedInside = getTextBindableContainerAtPosition(
this.scene
.getElementsIncludingDeleted()
.filter((element) => !isTextElement(element)),