diff --git a/packages/common/src/constants.ts b/packages/common/src/constants.ts index c8f4f7c4da..c7b309379d 100644 --- a/packages/common/src/constants.ts +++ b/packages/common/src/constants.ts @@ -458,7 +458,10 @@ export const DEFAULT_ELEMENT_PROPS: { roughness: ROUGHNESS.artist, opacity: 100, locked: false, - containerBehavior: "growing", + containerBehavior: { + textFlow: "growing", + margin: BOUND_TEXT_PADDING, + }, }; export const LIBRARY_SIDEBAR_TAB = "library"; diff --git a/packages/element/src/newElement.ts b/packages/element/src/newElement.ts index 180c0772e7..5d49c47cdc 100644 --- a/packages/element/src/newElement.ts +++ b/packages/element/src/newElement.ts @@ -10,6 +10,7 @@ import { getFontString, getUpdatedTimestamp, getLineHeight, + BOUND_TEXT_PADDING, } from "@excalidraw/common"; import type { Radians } from "@excalidraw/math"; @@ -169,7 +170,10 @@ export const newElement = ( opts.type as ExcalidrawFlowchartNodeElement["type"], opts, ), - containerBehavior: opts.containerBehavior ?? "growing", + containerBehavior: { + textFlow: opts.containerBehavior?.textFlow ?? "growing", + margin: opts.containerBehavior?.margin ?? BOUND_TEXT_PADDING, + }, } as NonDeleted; } return _newElementBase( diff --git a/packages/element/src/types.ts b/packages/element/src/types.ts index f5b5bff5c6..7ac9dca1c0 100644 --- a/packages/element/src/types.ts +++ b/packages/element/src/types.ts @@ -27,7 +27,10 @@ export type StrokeRoundness = "round" | "sharp"; export type RoundnessType = ValueOf; export type StrokeStyle = "solid" | "dashed" | "dotted"; export type TextAlign = typeof TEXT_ALIGN[keyof typeof TEXT_ALIGN]; -export type ContainerBehavior = "growing" | "stickyNote"; +export type ContainerBehavior = { + textFlow: "growing" | "fixed"; + margin?: number; +}; type VerticalAlignKeys = keyof typeof VERTICAL_ALIGN; export type VerticalAlign = typeof VERTICAL_ALIGN[VerticalAlignKeys]; @@ -88,7 +91,7 @@ export type ExcalidrawSelectionElement = _ExcalidrawElementBase & { }; type _ExcalidrawStickyNoteContainer = _ExcalidrawElementBase & { - containerBehavior: "stickyNote"; + containerBehavior: ContainerBehavior; }; export type ExcalidrawRectangleElement = _ExcalidrawStickyNoteContainer & { diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index 4a72da6158..e428a60646 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -21,6 +21,7 @@ import { getLineHeight, isTransparent, reduceToCommonValue, + BOUND_TEXT_PADDING, } from "@excalidraw/common"; import { @@ -1559,14 +1560,24 @@ export const actionChangeContainerBehavior = register({ const nextElements = elements.map((el) => containerIdsToUpdate.has(el.id) ? newElementWith(el, { - containerBehavior: value, + containerBehavior: { + textFlow: value, + margin: el.containerBehavior?.margin ?? BOUND_TEXT_PADDING, + }, }) : el, ); return { elements: nextElements, - appState: { ...appState, currentItemContainerBehavior: value }, + appState: { + ...appState, + currentItemContainerBehavior: { + textFlow: value, + margin: + appState.currentItemContainerBehavior?.margin ?? BOUND_TEXT_PADDING, + }, + }, captureUpdate: CaptureUpdateAction.IMMEDIATELY, }; }, @@ -1611,7 +1622,7 @@ export const actionChangeContainerBehavior = register({ const value = reduceToCommonValue( targetContainers, - (el) => el.containerBehavior ?? "growing", + (el) => el.containerBehavior?.textFlow ?? "growing", ) ?? // mixed selection -> show null so nothing appears selected null; @@ -1631,8 +1642,8 @@ export const actionChangeContainerBehavior = register({ icon: growingContainerIcon, }, { - value: "stickyNote", - text: t("labels.container_sticky"), + value: "fixed", + text: t("labels.container_fixed"), icon: stickyNoteIcon, }, ]} @@ -1640,7 +1651,7 @@ export const actionChangeContainerBehavior = register({ value ?? (targetContainers.length ? null - : appState.currentItemContainerBehavior ?? "growing") + : appState.currentItemContainerBehavior?.textFlow ?? "growing") } onChange={(val) => updateData(val)} /> diff --git a/packages/excalidraw/charts.ts b/packages/excalidraw/charts.ts index 4329c231c8..4c7143cee5 100644 --- a/packages/excalidraw/charts.ts +++ b/packages/excalidraw/charts.ts @@ -9,6 +9,7 @@ import { VERTICAL_ALIGN, randomId, isDevEnv, + BOUND_TEXT_PADDING, } from "@excalidraw/common"; import { @@ -334,7 +335,10 @@ const chartBaseElements = ( strokeColor: COLOR_PALETTE.black, fillStyle: "solid", opacity: 6, - containerBehavior: "growing", + containerBehavior: { + textFlow: "growing", + margin: BOUND_TEXT_PADDING, + }, }) : null; @@ -367,7 +371,10 @@ const chartTypeBar = ( y: y - barHeight - BAR_GAP, width: BAR_WIDTH, height: barHeight, - containerBehavior: "growing", + containerBehavior: { + textFlow: "growing", + margin: BOUND_TEXT_PADDING, + }, }); }); @@ -434,7 +441,10 @@ const chartTypeLine = ( y: y + cy - BAR_GAP * 2, width: BAR_GAP, height: BAR_GAP, - containerBehavior: "growing", + containerBehavior: { + textFlow: "growing", + margin: BOUND_TEXT_PADDING, + }, }); }); diff --git a/packages/excalidraw/data/restore.ts b/packages/excalidraw/data/restore.ts index 57b6f27ca1..271175fa13 100644 --- a/packages/excalidraw/data/restore.ts +++ b/packages/excalidraw/data/restore.ts @@ -17,6 +17,7 @@ import { getSizeFromPoints, normalizeLink, getLineHeight, + BOUND_TEXT_PADDING, } from "@excalidraw/common"; import { getNonDeletedElements, @@ -238,9 +239,10 @@ const restoreElementWithProperties = < locked: element.locked ?? false, ...(isFlowchartType(nextType) ? { - containerBehavior: - element.containerBehavior ?? - DEFAULT_ELEMENT_PROPS.containerBehavior, + containerBehavior: { + textFlow: element.containerBehavior?.textFlow ?? "growing", + margin: element.containerBehavior?.margin ?? BOUND_TEXT_PADDING, + }, } : {}), }; diff --git a/packages/excalidraw/locales/en.json b/packages/excalidraw/locales/en.json index 54dbd6c8bd..0a01cd6ce8 100644 --- a/packages/excalidraw/locales/en.json +++ b/packages/excalidraw/locales/en.json @@ -32,7 +32,7 @@ "strokeStyle_dotted": "Dotted", "sloppiness": "Sloppiness", "container": "Container", - "container_sticky": "Sticky note", + "container_fixed": "Sticky note", "container_growing": "Fit to text", "opacity": "Opacity", "textAlign": "Text align", diff --git a/packages/excalidraw/tests/fixtures/elementFixture.ts b/packages/excalidraw/tests/fixtures/elementFixture.ts index 2e335b60c8..633a34e6ba 100644 --- a/packages/excalidraw/tests/fixtures/elementFixture.ts +++ b/packages/excalidraw/tests/fixtures/elementFixture.ts @@ -1,4 +1,4 @@ -import { DEFAULT_FONT_FAMILY } from "@excalidraw/common"; +import { BOUND_TEXT_PADDING, DEFAULT_FONT_FAMILY } from "@excalidraw/common"; import type { Radians } from "@excalidraw/math"; @@ -34,7 +34,7 @@ const elementBase: Omit = { export const rectangleFixture: ExcalidrawElement = { ...elementBase, - containerBehavior: "growing", + containerBehavior: { textFlow: "growing", margin: BOUND_TEXT_PADDING }, type: "rectangle", } as unknown as ExcalidrawElement; export const embeddableFixture: ExcalidrawElement = { @@ -43,17 +43,17 @@ export const embeddableFixture: ExcalidrawElement = { }; export const ellipseFixture: ExcalidrawElement = { ...elementBase, - containerBehavior: "growing", + containerBehavior: { textFlow: "growing", margin: BOUND_TEXT_PADDING }, type: "ellipse", } as unknown as ExcalidrawElement; export const diamondFixture: ExcalidrawElement = { ...elementBase, - containerBehavior: "growing", + containerBehavior: { textFlow: "growing", margin: BOUND_TEXT_PADDING }, type: "diamond", } as unknown as ExcalidrawElement; export const rectangleWithLinkFixture: ExcalidrawElement = { ...elementBase, - containerBehavior: "growing", + containerBehavior: { textFlow: "growing", margin: BOUND_TEXT_PADDING }, type: "rectangle", link: "excalidraw.com", } as unknown as ExcalidrawElement; diff --git a/packages/excalidraw/tests/helpers/api.ts b/packages/excalidraw/tests/helpers/api.ts index f839661f4e..dc5bda6fb8 100644 --- a/packages/excalidraw/tests/helpers/api.ts +++ b/packages/excalidraw/tests/helpers/api.ts @@ -4,7 +4,7 @@ import util from "util"; import { pointFrom, type LocalPoint, type Radians } from "@excalidraw/math"; -import { DEFAULT_VERTICAL_ALIGN, ROUNDNESS, assertNever } from "@excalidraw/common"; +import { BOUND_TEXT_PADDING, DEFAULT_VERTICAL_ALIGN, ROUNDNESS, assertNever } from "@excalidraw/common"; import { newArrowElement, @@ -286,7 +286,10 @@ export class API { element = newElement({ type: type as "rectangle" | "diamond" | "ellipse", ...base, - containerBehavior: rest.containerBehavior ?? "growing", + containerBehavior: { + textFlow: rest.containerBehavior?.textFlow ?? "growing", + margin: rest.containerBehavior?.margin ?? BOUND_TEXT_PADDING, + }, }); break; case "embeddable": diff --git a/packages/excalidraw/wysiwyg/textWysiwyg.tsx b/packages/excalidraw/wysiwyg/textWysiwyg.tsx index 838e9bb526..1c1f4176e5 100644 --- a/packages/excalidraw/wysiwyg/textWysiwyg.tsx +++ b/packages/excalidraw/wysiwyg/textWysiwyg.tsx @@ -160,7 +160,7 @@ export const textWysiwyg = ({ let maxHeight = updatedTextElement.height; if (container && updatedTextElement.containerId) { - if ((container as any).containerBehavior === "stickyNote") { + if ((container as any).containerBehavior?.textFlow === "fixed") { if (stickyNoteInitialFontSize == null) { stickyNoteInitialFontSize = updatedTextElement.fontSize; } @@ -244,7 +244,7 @@ export const textWysiwyg = ({ ); // autogrow / autoshrink only for non-sticky behaviors - if ((container as any).containerBehavior !== "stickyNote") { + if ((container as any).containerBehavior?.textFlow !== "fixed") { // autogrow container height if text exceeds if (!isArrowElement(container) && height > maxHeight) { const targetContainerHeight =