aboutsummaryrefslogtreecommitdiffstats
path: root/packages/excalidraw/components/Stats/MultiFontSize.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/excalidraw/components/Stats/MultiFontSize.tsx')
-rw-r--r--packages/excalidraw/components/Stats/MultiFontSize.tsx164
1 files changed, 164 insertions, 0 deletions
diff --git a/packages/excalidraw/components/Stats/MultiFontSize.tsx b/packages/excalidraw/components/Stats/MultiFontSize.tsx
new file mode 100644
index 0000000..419bbbc
--- /dev/null
+++ b/packages/excalidraw/components/Stats/MultiFontSize.tsx
@@ -0,0 +1,164 @@
+import { isTextElement, redrawTextBoundingBox } from "../../element";
+import { mutateElement } from "../../element/mutateElement";
+import { hasBoundTextElement } from "../../element/typeChecks";
+import type {
+ ExcalidrawElement,
+ ExcalidrawTextElement,
+ NonDeletedSceneElementsMap,
+} from "../../element/types";
+import { isInGroup } from "../../groups";
+import type Scene from "../../scene/Scene";
+import { fontSizeIcon } from "../icons";
+import StatsDragInput from "./DragInput";
+import type { DragInputCallbackType } from "./DragInput";
+import { getStepSizedValue } from "./utils";
+import type { AppState } from "../../types";
+import { getBoundTextElement } from "../../element/textElement";
+
+interface MultiFontSizeProps {
+ elements: readonly ExcalidrawElement[];
+ scene: Scene;
+ elementsMap: NonDeletedSceneElementsMap;
+ appState: AppState;
+ property: "fontSize";
+}
+
+const MIN_FONT_SIZE = 4;
+const STEP_SIZE = 4;
+
+const getApplicableTextElements = (
+ elements: readonly (ExcalidrawElement | undefined)[],
+ elementsMap: NonDeletedSceneElementsMap,
+) =>
+ elements.reduce(
+ (acc: ExcalidrawTextElement[], el) => {
+ if (!el || isInGroup(el)) {
+ return acc;
+ }
+ if (isTextElement(el)) {
+ acc.push(el);
+ return acc;
+ }
+ if (hasBoundTextElement(el)) {
+ const boundTextElement = getBoundTextElement(el, elementsMap);
+ if (boundTextElement) {
+ acc.push(boundTextElement);
+ return acc;
+ }
+ }
+
+ return acc;
+ },
+
+ [],
+ );
+
+const handleFontSizeChange: DragInputCallbackType<
+ MultiFontSizeProps["property"],
+ ExcalidrawTextElement
+> = ({
+ accumulatedChange,
+ originalElements,
+ shouldChangeByStepSize,
+ nextValue,
+ scene,
+}) => {
+ const elementsMap = scene.getNonDeletedElementsMap();
+ const latestTextElements = originalElements.map((el) =>
+ elementsMap.get(el.id),
+ ) as ExcalidrawTextElement[];
+
+ let nextFontSize;
+
+ if (nextValue) {
+ nextFontSize = Math.max(Math.round(nextValue), MIN_FONT_SIZE);
+
+ for (const textElement of latestTextElements) {
+ mutateElement(
+ textElement,
+ {
+ fontSize: nextFontSize,
+ },
+ false,
+ );
+
+ redrawTextBoundingBox(
+ textElement,
+ scene.getContainerElement(textElement),
+ elementsMap,
+ false,
+ );
+ }
+
+ scene.triggerUpdate();
+ } else {
+ const originalTextElements = originalElements as ExcalidrawTextElement[];
+
+ for (let i = 0; i < latestTextElements.length; i++) {
+ const latestElement = latestTextElements[i];
+ const originalElement = originalTextElements[i];
+
+ const originalFontSize = Math.round(originalElement.fontSize);
+ const changeInFontSize = Math.round(accumulatedChange);
+ let nextFontSize = Math.max(
+ originalFontSize + changeInFontSize,
+ MIN_FONT_SIZE,
+ );
+ if (shouldChangeByStepSize) {
+ nextFontSize = getStepSizedValue(nextFontSize, STEP_SIZE);
+ }
+ mutateElement(
+ latestElement,
+ {
+ fontSize: nextFontSize,
+ },
+ false,
+ );
+
+ redrawTextBoundingBox(
+ latestElement,
+ scene.getContainerElement(latestElement),
+ elementsMap,
+ false,
+ );
+ }
+
+ scene.triggerUpdate();
+ }
+};
+
+const MultiFontSize = ({
+ elements,
+ scene,
+ appState,
+ property,
+ elementsMap,
+}: MultiFontSizeProps) => {
+ const latestTextElements = getApplicableTextElements(elements, elementsMap);
+
+ if (!latestTextElements.length) {
+ return null;
+ }
+
+ const fontSizes = latestTextElements.map(
+ (textEl) => Math.round(textEl.fontSize * 10) / 10,
+ );
+ const value = new Set(fontSizes).size === 1 ? fontSizes[0] : "Mixed";
+ const editable = fontSizes.length > 0;
+
+ return (
+ <StatsDragInput
+ label="F"
+ icon={fontSizeIcon}
+ elements={latestTextElements}
+ dragInputCallback={handleFontSizeChange}
+ value={value}
+ editable={editable}
+ scene={scene}
+ property={property}
+ appState={appState}
+ />
+ );
+};
+
+export default MultiFontSize;