fix: copy bound text style when copying element having bound text (#5305)

* fix: copy bound text style when copying element having bound text

* fix

* fix tests
This commit is contained in:
Aakansha Doshi 2022-06-14 19:42:49 +05:30 committed by GitHub
parent 6196fba286
commit 84b47a2ed5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 21 deletions

View File

@ -48,7 +48,7 @@ describe("actionStyles", () => {
Keyboard.withModifierKeys({ ctrl: true, alt: true }, () => { Keyboard.withModifierKeys({ ctrl: true, alt: true }, () => {
Keyboard.codeDown(CODES.C); Keyboard.codeDown(CODES.C);
}); });
const secondRect = JSON.parse(copiedStyles); const secondRect = JSON.parse(copiedStyles)[0];
expect(secondRect.id).toBe(h.elements[1].id); expect(secondRect.id).toBe(h.elements[1].id);
mouse.reset(); mouse.reset();

View File

@ -12,7 +12,9 @@ import {
DEFAULT_FONT_FAMILY, DEFAULT_FONT_FAMILY,
DEFAULT_TEXT_ALIGN, DEFAULT_TEXT_ALIGN,
} from "../constants"; } from "../constants";
import { getContainerElement } from "../element/textElement"; import { getBoundTextElement } from "../element/textElement";
import { hasBoundTextElement } from "../element/typeChecks";
import { getSelectedElements } from "../scene";
// `copiedStyles` is exported only for tests. // `copiedStyles` is exported only for tests.
export let copiedStyles: string = "{}"; export let copiedStyles: string = "{}";
@ -21,9 +23,15 @@ export const actionCopyStyles = register({
name: "copyStyles", name: "copyStyles",
trackEvent: { category: "element" }, trackEvent: { category: "element" },
perform: (elements, appState) => { perform: (elements, appState) => {
const elementsCopied = [];
const element = elements.find((el) => appState.selectedElementIds[el.id]); const element = elements.find((el) => appState.selectedElementIds[el.id]);
elementsCopied.push(element);
if (element && hasBoundTextElement(element)) {
const boundTextElement = getBoundTextElement(element);
elementsCopied.push(boundTextElement);
}
if (element) { if (element) {
copiedStyles = JSON.stringify(element); copiedStyles = JSON.stringify(elementsCopied);
} }
return { return {
appState: { appState: {
@ -42,37 +50,59 @@ export const actionPasteStyles = register({
name: "pasteStyles", name: "pasteStyles",
trackEvent: { category: "element" }, trackEvent: { category: "element" },
perform: (elements, appState) => { perform: (elements, appState) => {
const pastedElement = JSON.parse(copiedStyles); const elementsCopied = JSON.parse(copiedStyles);
const pastedElement = elementsCopied[0];
const boundTextElement = elementsCopied[1];
if (!isExcalidrawElement(pastedElement)) { if (!isExcalidrawElement(pastedElement)) {
return { elements, commitToHistory: false }; return { elements, commitToHistory: false };
} }
const selectedElements = getSelectedElements(elements, appState, true);
const selectedElementIds = selectedElements.map((element) => element.id);
return { return {
elements: elements.map((element) => { elements: elements.map((element) => {
if (appState.selectedElementIds[element.id]) { if (selectedElementIds.includes(element.id)) {
let elementStylesToCopyFrom = pastedElement;
if (isTextElement(element) && element.containerId) {
elementStylesToCopyFrom = boundTextElement;
}
if (!elementStylesToCopyFrom) {
return element;
}
let newElement = newElementWith(element, { let newElement = newElementWith(element, {
backgroundColor: pastedElement?.backgroundColor, backgroundColor: elementStylesToCopyFrom?.backgroundColor,
strokeWidth: pastedElement?.strokeWidth, strokeWidth: elementStylesToCopyFrom?.strokeWidth,
strokeColor: pastedElement?.strokeColor, strokeColor: elementStylesToCopyFrom?.strokeColor,
strokeStyle: pastedElement?.strokeStyle, strokeStyle: elementStylesToCopyFrom?.strokeStyle,
fillStyle: pastedElement?.fillStyle, fillStyle: elementStylesToCopyFrom?.fillStyle,
opacity: pastedElement?.opacity, opacity: elementStylesToCopyFrom?.opacity,
roughness: pastedElement?.roughness, roughness: elementStylesToCopyFrom?.roughness,
}); });
if (isTextElement(newElement)) { if (isTextElement(newElement)) {
newElement = newElementWith(newElement, { newElement = newElementWith(newElement, {
fontSize: pastedElement?.fontSize || DEFAULT_FONT_SIZE, fontSize: elementStylesToCopyFrom?.fontSize || DEFAULT_FONT_SIZE,
fontFamily: pastedElement?.fontFamily || DEFAULT_FONT_FAMILY, fontFamily:
textAlign: pastedElement?.textAlign || DEFAULT_TEXT_ALIGN, elementStylesToCopyFrom?.fontFamily || DEFAULT_FONT_FAMILY,
textAlign:
elementStylesToCopyFrom?.textAlign || DEFAULT_TEXT_ALIGN,
}); });
let container = null;
redrawTextBoundingBox(newElement, getContainerElement(newElement)); if (newElement.containerId) {
container =
selectedElements.find(
(element) =>
isTextElement(newElement) &&
element.id === newElement.containerId,
) || null;
}
redrawTextBoundingBox(newElement, container);
} }
if (newElement.type === "arrow") { if (newElement.type === "arrow") {
newElement = newElementWith(newElement, { newElement = newElementWith(newElement, {
startArrowhead: pastedElement.startArrowhead, startArrowhead: elementStylesToCopyFrom.startArrowhead,
endArrowhead: pastedElement.endArrowhead, endArrowhead: elementStylesToCopyFrom.endArrowhead,
}); });
} }

View File

@ -289,7 +289,7 @@ describe("contextMenu element", () => {
expect(copiedStyles).toBe("{}"); expect(copiedStyles).toBe("{}");
fireEvent.click(queryByText(contextMenu as HTMLElement, "Copy styles")!); fireEvent.click(queryByText(contextMenu as HTMLElement, "Copy styles")!);
expect(copiedStyles).not.toBe("{}"); expect(copiedStyles).not.toBe("{}");
const element = JSON.parse(copiedStyles); const element = JSON.parse(copiedStyles)[0];
expect(element).toEqual(API.getSelectedElement()); expect(element).toEqual(API.getSelectedElement());
}); });
@ -329,7 +329,7 @@ describe("contextMenu element", () => {
}); });
let contextMenu = UI.queryContextMenu(); let contextMenu = UI.queryContextMenu();
fireEvent.click(queryByText(contextMenu as HTMLElement, "Copy styles")!); fireEvent.click(queryByText(contextMenu as HTMLElement, "Copy styles")!);
const secondRect = JSON.parse(copiedStyles); const secondRect = JSON.parse(copiedStyles)[0];
expect(secondRect.id).toBe(h.elements[1].id); expect(secondRect.id).toBe(h.elements[1].id);
mouse.reset(); mouse.reset();