feat: add container to multiple text elements (#6428)
Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
parent
d61b3cf83d
commit
68692b9d4c
@ -23,6 +23,7 @@ import {
|
|||||||
ExcalidrawTextElement,
|
ExcalidrawTextElement,
|
||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
import { getSelectedElements } from "../scene";
|
import { getSelectedElements } from "../scene";
|
||||||
|
import { AppState } from "../types";
|
||||||
import { getFontString } from "../utils";
|
import { getFontString } from "../utils";
|
||||||
import { register } from "./register";
|
import { register } from "./register";
|
||||||
|
|
||||||
@ -185,107 +186,110 @@ export const actionCreateContainerFromText = register({
|
|||||||
trackEvent: { category: "element" },
|
trackEvent: { category: "element" },
|
||||||
predicate: (elements, appState) => {
|
predicate: (elements, appState) => {
|
||||||
const selectedElements = getSelectedElements(elements, appState);
|
const selectedElements = getSelectedElements(elements, appState);
|
||||||
return selectedElements.length === 1 && isTextElement(selectedElements[0]);
|
const areTextElements = selectedElements.every((el) => isTextElement(el));
|
||||||
|
return selectedElements.length > 0 && areTextElements;
|
||||||
},
|
},
|
||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
const selectedElements = getSelectedElements(
|
const selectedElements = getSelectedElements(
|
||||||
getNonDeletedElements(elements),
|
getNonDeletedElements(elements),
|
||||||
appState,
|
appState,
|
||||||
);
|
);
|
||||||
const updatedElements = elements.slice();
|
let updatedElements: readonly ExcalidrawElement[] = elements.slice();
|
||||||
if (selectedElements.length === 1 && isTextElement(selectedElements[0])) {
|
const containerIds: AppState["selectedElementIds"] = {};
|
||||||
const textElement = selectedElements[0];
|
|
||||||
const container = newElement({
|
|
||||||
type: "rectangle",
|
|
||||||
backgroundColor: appState.currentItemBackgroundColor,
|
|
||||||
boundElements: [
|
|
||||||
...(textElement.boundElements || []),
|
|
||||||
{ id: textElement.id, type: "text" },
|
|
||||||
],
|
|
||||||
angle: textElement.angle,
|
|
||||||
fillStyle: appState.currentItemFillStyle,
|
|
||||||
strokeColor: appState.currentItemStrokeColor,
|
|
||||||
roughness: appState.currentItemRoughness,
|
|
||||||
strokeWidth: appState.currentItemStrokeWidth,
|
|
||||||
strokeStyle: appState.currentItemStrokeStyle,
|
|
||||||
roundness:
|
|
||||||
appState.currentItemRoundness === "round"
|
|
||||||
? {
|
|
||||||
type: isUsingAdaptiveRadius("rectangle")
|
|
||||||
? ROUNDNESS.ADAPTIVE_RADIUS
|
|
||||||
: ROUNDNESS.PROPORTIONAL_RADIUS,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
opacity: 100,
|
|
||||||
locked: false,
|
|
||||||
x: textElement.x - BOUND_TEXT_PADDING,
|
|
||||||
y: textElement.y - BOUND_TEXT_PADDING,
|
|
||||||
width: computeContainerDimensionForBoundText(
|
|
||||||
textElement.width,
|
|
||||||
"rectangle",
|
|
||||||
),
|
|
||||||
height: computeContainerDimensionForBoundText(
|
|
||||||
textElement.height,
|
|
||||||
"rectangle",
|
|
||||||
),
|
|
||||||
groupIds: textElement.groupIds,
|
|
||||||
});
|
|
||||||
|
|
||||||
// update bindings
|
for (const textElement of selectedElements) {
|
||||||
if (textElement.boundElements?.length) {
|
if (isTextElement(textElement)) {
|
||||||
const linearElementIds = textElement.boundElements
|
const container = newElement({
|
||||||
.filter((ele) => ele.type === "arrow")
|
type: "rectangle",
|
||||||
.map((el) => el.id);
|
backgroundColor: appState.currentItemBackgroundColor,
|
||||||
const linearElements = updatedElements.filter((ele) =>
|
boundElements: [
|
||||||
linearElementIds.includes(ele.id),
|
...(textElement.boundElements || []),
|
||||||
) as ExcalidrawLinearElement[];
|
{ id: textElement.id, type: "text" },
|
||||||
linearElements.forEach((ele) => {
|
],
|
||||||
let startBinding = ele.startBinding;
|
angle: textElement.angle,
|
||||||
let endBinding = ele.endBinding;
|
fillStyle: appState.currentItemFillStyle,
|
||||||
|
strokeColor: appState.currentItemStrokeColor,
|
||||||
if (startBinding?.elementId === textElement.id) {
|
roughness: appState.currentItemRoughness,
|
||||||
startBinding = {
|
strokeWidth: appState.currentItemStrokeWidth,
|
||||||
...startBinding,
|
strokeStyle: appState.currentItemStrokeStyle,
|
||||||
elementId: container.id,
|
roundness:
|
||||||
};
|
appState.currentItemRoundness === "round"
|
||||||
}
|
? {
|
||||||
|
type: isUsingAdaptiveRadius("rectangle")
|
||||||
if (endBinding?.elementId === textElement.id) {
|
? ROUNDNESS.ADAPTIVE_RADIUS
|
||||||
endBinding = { ...endBinding, elementId: container.id };
|
: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
}
|
}
|
||||||
|
: null,
|
||||||
if (startBinding || endBinding) {
|
opacity: 100,
|
||||||
mutateElement(ele, { startBinding, endBinding });
|
locked: false,
|
||||||
}
|
x: textElement.x - BOUND_TEXT_PADDING,
|
||||||
|
y: textElement.y - BOUND_TEXT_PADDING,
|
||||||
|
width: computeContainerDimensionForBoundText(
|
||||||
|
textElement.width,
|
||||||
|
"rectangle",
|
||||||
|
),
|
||||||
|
height: computeContainerDimensionForBoundText(
|
||||||
|
textElement.height,
|
||||||
|
"rectangle",
|
||||||
|
),
|
||||||
|
groupIds: textElement.groupIds,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
mutateElement(textElement, {
|
// update bindings
|
||||||
containerId: container.id,
|
if (textElement.boundElements?.length) {
|
||||||
verticalAlign: VERTICAL_ALIGN.MIDDLE,
|
const linearElementIds = textElement.boundElements
|
||||||
boundElements: null,
|
.filter((ele) => ele.type === "arrow")
|
||||||
});
|
.map((el) => el.id);
|
||||||
redrawTextBoundingBox(textElement, container);
|
const linearElements = updatedElements.filter((ele) =>
|
||||||
|
linearElementIds.includes(ele.id),
|
||||||
|
) as ExcalidrawLinearElement[];
|
||||||
|
linearElements.forEach((ele) => {
|
||||||
|
let startBinding = ele.startBinding;
|
||||||
|
let endBinding = ele.endBinding;
|
||||||
|
|
||||||
return {
|
if (startBinding?.elementId === textElement.id) {
|
||||||
elements: pushContainerBelowText(
|
startBinding = {
|
||||||
[...elements, container],
|
...startBinding,
|
||||||
|
elementId: container.id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endBinding?.elementId === textElement.id) {
|
||||||
|
endBinding = { ...endBinding, elementId: container.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startBinding || endBinding) {
|
||||||
|
mutateElement(ele, { startBinding, endBinding }, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mutateElement(
|
||||||
|
textElement,
|
||||||
|
{
|
||||||
|
containerId: container.id,
|
||||||
|
verticalAlign: VERTICAL_ALIGN.MIDDLE,
|
||||||
|
boundElements: null,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
redrawTextBoundingBox(textElement, container);
|
||||||
|
|
||||||
|
updatedElements = pushContainerBelowText(
|
||||||
|
[...updatedElements, container],
|
||||||
container,
|
container,
|
||||||
textElement,
|
textElement,
|
||||||
),
|
);
|
||||||
appState: {
|
containerIds[container.id] = true;
|
||||||
...appState,
|
}
|
||||||
selectedElementIds: {
|
|
||||||
[container.id]: true,
|
|
||||||
[textElement.id]: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
commitToHistory: true,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
elements: updatedElements,
|
elements: updatedElements,
|
||||||
appState,
|
appState: {
|
||||||
|
...appState,
|
||||||
|
selectedElementIds: containerIds,
|
||||||
|
},
|
||||||
commitToHistory: true,
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user