feat: Bind text to container if double clicked on filled shape or stroke (#6250)
* feat: bind text to container when clicked on filled shape or element stroke * Bind if double clicked on stroke as well * remove * specs * remove * shuffle * fix * back to normal
This commit is contained in:
parent
5acb99777a
commit
b9ba407f96
@ -226,6 +226,7 @@ import {
|
||||
setEraserCursor,
|
||||
updateActiveTool,
|
||||
getShortcutKey,
|
||||
isTransparent,
|
||||
} from "../utils";
|
||||
import {
|
||||
ContextMenu,
|
||||
@ -2762,7 +2763,15 @@ class App extends React.Component<AppProps, AppState> {
|
||||
sceneY,
|
||||
);
|
||||
if (container) {
|
||||
if (isArrowElement(container) || hasBoundTextElement(container)) {
|
||||
if (
|
||||
isArrowElement(container) ||
|
||||
hasBoundTextElement(container) ||
|
||||
!isTransparent(container.backgroundColor) ||
|
||||
isHittingElementNotConsideringBoundingBox(container, this.state, [
|
||||
sceneX,
|
||||
sceneY,
|
||||
])
|
||||
) {
|
||||
const midPoint = getContainerCenter(container, this.state);
|
||||
|
||||
sceneX = midPoint.x;
|
||||
|
@ -463,14 +463,21 @@ describe("textWysiwyg", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should bind text to container when double clicked on center of filled container", async () => {
|
||||
it("should bind text to container when double clicked inside filled container", async () => {
|
||||
const rectangle = API.createElement({
|
||||
type: "rectangle",
|
||||
x: 10,
|
||||
y: 20,
|
||||
width: 90,
|
||||
height: 75,
|
||||
backgroundColor: "red",
|
||||
});
|
||||
h.elements = [rectangle];
|
||||
|
||||
expect(h.elements.length).toBe(1);
|
||||
expect(h.elements[0].id).toBe(rectangle.id);
|
||||
|
||||
mouse.doubleClickAt(
|
||||
rectangle.x + rectangle.width / 2,
|
||||
rectangle.y + rectangle.height / 2,
|
||||
);
|
||||
mouse.doubleClickAt(rectangle.x + 10, rectangle.y + 10);
|
||||
expect(h.elements.length).toBe(2);
|
||||
|
||||
const text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||
@ -504,24 +511,37 @@ describe("textWysiwyg", () => {
|
||||
});
|
||||
h.elements = [rectangle];
|
||||
|
||||
mouse.doubleClickAt(rectangle.x + 10, rectangle.y + 10);
|
||||
expect(h.elements.length).toBe(2);
|
||||
let text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||
expect(text.type).toBe("text");
|
||||
expect(text.containerId).toBe(null);
|
||||
mouse.down();
|
||||
let editor = document.querySelector(
|
||||
".excalidraw-textEditorContainer > textarea",
|
||||
) as HTMLTextAreaElement;
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
editor.blur();
|
||||
|
||||
mouse.doubleClickAt(
|
||||
rectangle.x + rectangle.width / 2,
|
||||
rectangle.y + rectangle.height / 2,
|
||||
);
|
||||
expect(h.elements.length).toBe(2);
|
||||
expect(h.elements.length).toBe(3);
|
||||
|
||||
const text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||
text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||
expect(text.type).toBe("text");
|
||||
expect(text.containerId).toBe(rectangle.id);
|
||||
|
||||
mouse.down();
|
||||
const editor = document.querySelector(
|
||||
editor = document.querySelector(
|
||||
".excalidraw-textEditorContainer > textarea",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
fireEvent.change(editor, { target: { value: "Hello World!" } });
|
||||
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
editor.blur();
|
||||
|
||||
expect(rectangle.boundElements).toStrictEqual([
|
||||
{ id: text.id, type: "text" },
|
||||
]);
|
||||
@ -551,6 +571,43 @@ describe("textWysiwyg", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("should bind text to container when double clicked on container stroke", async () => {
|
||||
const rectangle = API.createElement({
|
||||
type: "rectangle",
|
||||
x: 10,
|
||||
y: 20,
|
||||
width: 90,
|
||||
height: 75,
|
||||
strokeWidth: 4,
|
||||
});
|
||||
h.elements = [rectangle];
|
||||
|
||||
expect(h.elements.length).toBe(1);
|
||||
expect(h.elements[0].id).toBe(rectangle.id);
|
||||
|
||||
mouse.doubleClickAt(rectangle.x + 2, rectangle.y + 2);
|
||||
expect(h.elements.length).toBe(2);
|
||||
|
||||
const text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||
expect(text.type).toBe("text");
|
||||
expect(text.containerId).toBe(rectangle.id);
|
||||
expect(rectangle.boundElements).toStrictEqual([
|
||||
{ id: text.id, type: "text" },
|
||||
]);
|
||||
mouse.down();
|
||||
const editor = document.querySelector(
|
||||
".excalidraw-textEditorContainer > textarea",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
fireEvent.change(editor, { target: { value: "Hello World!" } });
|
||||
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
editor.blur();
|
||||
expect(rectangle.boundElements).toStrictEqual([
|
||||
{ id: text.id, type: "text" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("shouldn't bind to non-text-bindable containers", async () => {
|
||||
const freedraw = API.createElement({
|
||||
type: "freedraw",
|
||||
|
@ -137,7 +137,7 @@ export const isExcalidrawElement = (element: any): boolean => {
|
||||
|
||||
export const hasBoundTextElement = (
|
||||
element: ExcalidrawElement | null,
|
||||
): element is ExcalidrawBindableElement => {
|
||||
): element is MarkNonNullable<ExcalidrawBindableElement, "boundElements"> => {
|
||||
return (
|
||||
isBindableElement(element) &&
|
||||
!!element.boundElements?.some(({ type }) => type === "text")
|
||||
|
Loading…
x
Reference in New Issue
Block a user