Prefer arrow functions and callbacks (#1210)
This commit is contained in:
@ -12,9 +12,9 @@ import { rescalePoints } from "../points";
|
||||
|
||||
// If the element is created from right to left, the width is going to be negative
|
||||
// This set of functions retrieves the absolute position of the 4 points.
|
||||
export function getElementAbsoluteCoords(
|
||||
export const getElementAbsoluteCoords = (
|
||||
element: ExcalidrawElement,
|
||||
): [number, number, number, number] {
|
||||
): [number, number, number, number] => {
|
||||
if (isLinearElement(element)) {
|
||||
return getLinearElementAbsoluteCoords(element);
|
||||
}
|
||||
@ -24,9 +24,9 @@ export function getElementAbsoluteCoords(
|
||||
element.x + element.width,
|
||||
element.y + element.height,
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
export function getDiamondPoints(element: ExcalidrawElement) {
|
||||
export const getDiamondPoints = (element: ExcalidrawElement) => {
|
||||
// Here we add +1 to avoid these numbers to be 0
|
||||
// otherwise rough.js will throw an error complaining about it
|
||||
const topX = Math.floor(element.width / 2) + 1;
|
||||
@ -39,16 +39,16 @@ export function getDiamondPoints(element: ExcalidrawElement) {
|
||||
const leftY = rightY;
|
||||
|
||||
return [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY];
|
||||
}
|
||||
};
|
||||
|
||||
export function getCurvePathOps(shape: Drawable): Op[] {
|
||||
export const getCurvePathOps = (shape: Drawable): Op[] => {
|
||||
for (const set of shape.sets) {
|
||||
if (set.type === "path") {
|
||||
return set.ops;
|
||||
}
|
||||
}
|
||||
return shape.sets[0].ops;
|
||||
}
|
||||
};
|
||||
|
||||
const getMinMaxXYFromCurvePathOps = (
|
||||
ops: Op[],
|
||||
@ -150,10 +150,10 @@ const getLinearElementAbsoluteCoords = (
|
||||
];
|
||||
};
|
||||
|
||||
export function getArrowPoints(
|
||||
export const getArrowPoints = (
|
||||
element: ExcalidrawLinearElement,
|
||||
shape: Drawable[],
|
||||
) {
|
||||
) => {
|
||||
const ops = getCurvePathOps(shape[0]);
|
||||
|
||||
const data = ops[ops.length - 1].data;
|
||||
@ -212,7 +212,7 @@ export function getArrowPoints(
|
||||
const [x4, y4] = rotate(xs, ys, x2, y2, (angle * Math.PI) / 180);
|
||||
|
||||
return [x2, y2, x3, y3, x4, y4];
|
||||
}
|
||||
};
|
||||
|
||||
const getLinearElementRotatedBounds = (
|
||||
element: ExcalidrawLinearElement,
|
||||
|
@ -19,10 +19,10 @@ import { AppState } from "../types";
|
||||
import { getShapeForElement } from "../renderer/renderElement";
|
||||
import { isLinearElement } from "./typeChecks";
|
||||
|
||||
function isElementDraggableFromInside(
|
||||
const isElementDraggableFromInside = (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
appState: AppState,
|
||||
): boolean {
|
||||
): boolean => {
|
||||
const dragFromInside =
|
||||
element.backgroundColor !== "transparent" ||
|
||||
appState.selectedElementIds[element.id];
|
||||
@ -30,15 +30,15 @@ function isElementDraggableFromInside(
|
||||
return dragFromInside && isPathALoop(element.points);
|
||||
}
|
||||
return dragFromInside;
|
||||
}
|
||||
};
|
||||
|
||||
export function hitTest(
|
||||
export const hitTest = (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
appState: AppState,
|
||||
x: number,
|
||||
y: number,
|
||||
zoom: number,
|
||||
): boolean {
|
||||
): boolean => {
|
||||
// For shapes that are composed of lines, we only enable point-selection when the distance
|
||||
// of the click is less than x pixels of any of the lines that the shape is composed of
|
||||
const lineThreshold = 10 / zoom;
|
||||
@ -210,7 +210,7 @@ export function hitTest(
|
||||
return false;
|
||||
}
|
||||
throw new Error(`Unimplemented type ${element.type}`);
|
||||
}
|
||||
};
|
||||
|
||||
const pointInBezierEquation = (
|
||||
p0: Point,
|
||||
|
@ -21,7 +21,7 @@ export const OMIT_SIDES_FOR_MULTIPLE_ELEMENTS = {
|
||||
rotation: true,
|
||||
};
|
||||
|
||||
function generateHandler(
|
||||
const generateHandler = (
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
@ -29,18 +29,18 @@ function generateHandler(
|
||||
cx: number,
|
||||
cy: number,
|
||||
angle: number,
|
||||
): [number, number, number, number] {
|
||||
): [number, number, number, number] => {
|
||||
const [xx, yy] = rotate(x + width / 2, y + height / 2, cx, cy, angle);
|
||||
return [xx - width / 2, yy - height / 2, width, height];
|
||||
}
|
||||
};
|
||||
|
||||
export function handlerRectanglesFromCoords(
|
||||
export const handlerRectanglesFromCoords = (
|
||||
[x1, y1, x2, y2]: [number, number, number, number],
|
||||
angle: number,
|
||||
zoom: number,
|
||||
pointerType: PointerType = "mouse",
|
||||
omitSides: { [T in Sides]?: boolean } = {},
|
||||
): Partial<{ [T in Sides]: [number, number, number, number] }> {
|
||||
): Partial<{ [T in Sides]: [number, number, number, number] }> => {
|
||||
const size = handleSizes[pointerType];
|
||||
const handlerWidth = size / zoom;
|
||||
const handlerHeight = size / zoom;
|
||||
@ -173,13 +173,13 @@ export function handlerRectanglesFromCoords(
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
};
|
||||
|
||||
export function handlerRectangles(
|
||||
export const handlerRectangles = (
|
||||
element: ExcalidrawElement,
|
||||
zoom: number,
|
||||
pointerType: PointerType = "mouse",
|
||||
) {
|
||||
) => {
|
||||
const handlers = handlerRectanglesFromCoords(
|
||||
getElementAbsoluteCoords(element),
|
||||
element.angle,
|
||||
@ -234,4 +234,4 @@ export function handlerRectangles(
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
};
|
||||
|
@ -49,35 +49,30 @@ export {
|
||||
} from "./sizeHelpers";
|
||||
export { showSelectedShapeActions } from "./showSelectedShapeActions";
|
||||
|
||||
export function getSyncableElements(elements: readonly ExcalidrawElement[]) {
|
||||
// There are places in Excalidraw where synthetic invisibly small elements are added and removed.
|
||||
export const getSyncableElements = (
|
||||
elements: readonly ExcalidrawElement[], // There are places in Excalidraw where synthetic invisibly small elements are added and removed.
|
||||
) =>
|
||||
// It's probably best to keep those local otherwise there might be a race condition that
|
||||
// gets the app into an invalid state. I've never seen it happen but I'm worried about it :)
|
||||
return elements.filter((el) => el.isDeleted || !isInvisiblySmallElement(el));
|
||||
}
|
||||
elements.filter((el) => el.isDeleted || !isInvisiblySmallElement(el));
|
||||
|
||||
export function getElementMap(elements: readonly ExcalidrawElement[]) {
|
||||
return elements.reduce(
|
||||
export const getElementMap = (elements: readonly ExcalidrawElement[]) =>
|
||||
elements.reduce(
|
||||
(acc: { [key: string]: ExcalidrawElement }, element: ExcalidrawElement) => {
|
||||
acc[element.id] = element;
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
export function getDrawingVersion(elements: readonly ExcalidrawElement[]) {
|
||||
return elements.reduce((acc, el) => acc + el.version, 0);
|
||||
}
|
||||
export const getDrawingVersion = (elements: readonly ExcalidrawElement[]) =>
|
||||
elements.reduce((acc, el) => acc + el.version, 0);
|
||||
|
||||
export function getNonDeletedElements(elements: readonly ExcalidrawElement[]) {
|
||||
return elements.filter(
|
||||
export const getNonDeletedElements = (elements: readonly ExcalidrawElement[]) =>
|
||||
elements.filter(
|
||||
(element) => !element.isDeleted,
|
||||
) as readonly NonDeletedExcalidrawElement[];
|
||||
}
|
||||
|
||||
export function isNonDeletedElement<T extends ExcalidrawElement>(
|
||||
export const isNonDeletedElement = <T extends ExcalidrawElement>(
|
||||
element: T,
|
||||
): element is NonDeleted<T> {
|
||||
return !element.isDeleted;
|
||||
}
|
||||
): element is NonDeleted<T> => !element.isDeleted;
|
||||
|
@ -13,10 +13,10 @@ type ElementUpdate<TElement extends ExcalidrawElement> = Omit<
|
||||
// The version is used to compare updates when more than one user is working in
|
||||
// the same drawing. Note: this will trigger the component to update. Make sure you
|
||||
// are calling it either from a React event handler or within unstable_batchedUpdates().
|
||||
export function mutateElement<TElement extends Mutable<ExcalidrawElement>>(
|
||||
export const mutateElement = <TElement extends Mutable<ExcalidrawElement>>(
|
||||
element: TElement,
|
||||
updates: ElementUpdate<TElement>,
|
||||
) {
|
||||
) => {
|
||||
// casting to any because can't use `in` operator
|
||||
// (see https://github.com/microsoft/TypeScript/issues/21732)
|
||||
const { points } = updates as any;
|
||||
@ -45,16 +45,14 @@ export function mutateElement<TElement extends Mutable<ExcalidrawElement>>(
|
||||
element.versionNonce = randomInteger();
|
||||
|
||||
globalSceneState.informMutation();
|
||||
}
|
||||
};
|
||||
|
||||
export function newElementWith<TElement extends ExcalidrawElement>(
|
||||
export const newElementWith = <TElement extends ExcalidrawElement>(
|
||||
element: TElement,
|
||||
updates: ElementUpdate<TElement>,
|
||||
): TElement {
|
||||
return {
|
||||
...element,
|
||||
version: element.version + 1,
|
||||
versionNonce: randomInteger(),
|
||||
...updates,
|
||||
};
|
||||
}
|
||||
): TElement => ({
|
||||
...element,
|
||||
version: element.version + 1,
|
||||
versionNonce: randomInteger(),
|
||||
...updates,
|
||||
});
|
||||
|
@ -5,12 +5,12 @@ import {
|
||||
} from "./newElement";
|
||||
import { mutateElement } from "./mutateElement";
|
||||
|
||||
function isPrimitive(val: any) {
|
||||
const isPrimitive = (val: any) => {
|
||||
const type = typeof val;
|
||||
return val == null || (type !== "object" && type !== "function");
|
||||
}
|
||||
};
|
||||
|
||||
function assertCloneObjects(source: any, clone: any) {
|
||||
const assertCloneObjects = (source: any, clone: any) => {
|
||||
for (const key in clone) {
|
||||
if (clone.hasOwnProperty(key) && !isPrimitive(clone[key])) {
|
||||
expect(clone[key]).not.toBe(source[key]);
|
||||
@ -19,7 +19,7 @@ function assertCloneObjects(source: any, clone: any) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
it("clones arrow element", () => {
|
||||
const element = newLinearElement({
|
||||
|
@ -25,7 +25,7 @@ type ElementConstructorOpts = {
|
||||
angle?: ExcalidrawGenericElement["angle"];
|
||||
};
|
||||
|
||||
function _newElementBase<T extends ExcalidrawElement>(
|
||||
const _newElementBase = <T extends ExcalidrawElement>(
|
||||
type: T["type"],
|
||||
{
|
||||
x,
|
||||
@ -42,44 +42,41 @@ function _newElementBase<T extends ExcalidrawElement>(
|
||||
angle = 0,
|
||||
...rest
|
||||
}: ElementConstructorOpts & Partial<ExcalidrawGenericElement>,
|
||||
) {
|
||||
return {
|
||||
id: rest.id || randomId(),
|
||||
type,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
angle,
|
||||
strokeColor,
|
||||
backgroundColor,
|
||||
fillStyle,
|
||||
strokeWidth,
|
||||
strokeStyle,
|
||||
roughness,
|
||||
opacity,
|
||||
seed: rest.seed ?? randomInteger(),
|
||||
version: rest.version || 1,
|
||||
versionNonce: rest.versionNonce ?? 0,
|
||||
isDeleted: false as false,
|
||||
};
|
||||
}
|
||||
) => ({
|
||||
id: rest.id || randomId(),
|
||||
type,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
angle,
|
||||
strokeColor,
|
||||
backgroundColor,
|
||||
fillStyle,
|
||||
strokeWidth,
|
||||
strokeStyle,
|
||||
roughness,
|
||||
opacity,
|
||||
seed: rest.seed ?? randomInteger(),
|
||||
version: rest.version || 1,
|
||||
versionNonce: rest.versionNonce ?? 0,
|
||||
isDeleted: false as false,
|
||||
});
|
||||
|
||||
export function newElement(
|
||||
export const newElement = (
|
||||
opts: {
|
||||
type: ExcalidrawGenericElement["type"];
|
||||
} & ElementConstructorOpts,
|
||||
): NonDeleted<ExcalidrawGenericElement> {
|
||||
return _newElementBase<ExcalidrawGenericElement>(opts.type, opts);
|
||||
}
|
||||
): NonDeleted<ExcalidrawGenericElement> =>
|
||||
_newElementBase<ExcalidrawGenericElement>(opts.type, opts);
|
||||
|
||||
export function newTextElement(
|
||||
export const newTextElement = (
|
||||
opts: {
|
||||
text: string;
|
||||
font: string;
|
||||
textAlign: TextAlign;
|
||||
} & ElementConstructorOpts,
|
||||
): NonDeleted<ExcalidrawTextElement> {
|
||||
): NonDeleted<ExcalidrawTextElement> => {
|
||||
const metrics = measureText(opts.text, opts.font);
|
||||
const textElement = newElementWith(
|
||||
{
|
||||
@ -98,26 +95,26 @@ export function newTextElement(
|
||||
);
|
||||
|
||||
return textElement;
|
||||
}
|
||||
};
|
||||
|
||||
export function newLinearElement(
|
||||
export const newLinearElement = (
|
||||
opts: {
|
||||
type: ExcalidrawLinearElement["type"];
|
||||
lastCommittedPoint?: ExcalidrawLinearElement["lastCommittedPoint"];
|
||||
} & ElementConstructorOpts,
|
||||
): NonDeleted<ExcalidrawLinearElement> {
|
||||
): NonDeleted<ExcalidrawLinearElement> => {
|
||||
return {
|
||||
..._newElementBase<ExcalidrawLinearElement>(opts.type, opts),
|
||||
points: [],
|
||||
lastCommittedPoint: opts.lastCommittedPoint || null,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Simplified deep clone for the purpose of cloning ExcalidrawElement only
|
||||
// (doesn't clone Date, RegExp, Map, Set, Typed arrays etc.)
|
||||
//
|
||||
// Adapted from https://github.com/lukeed/klona
|
||||
function _duplicateElement(val: any, depth: number = 0) {
|
||||
const _duplicateElement = (val: any, depth: number = 0) => {
|
||||
if (val == null || typeof val !== "object") {
|
||||
return val;
|
||||
}
|
||||
@ -149,12 +146,12 @@ function _duplicateElement(val: any, depth: number = 0) {
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
export function duplicateElement<TElement extends Mutable<ExcalidrawElement>>(
|
||||
export const duplicateElement = <TElement extends Mutable<ExcalidrawElement>>(
|
||||
element: TElement,
|
||||
overrides?: Partial<TElement>,
|
||||
): TElement {
|
||||
): TElement => {
|
||||
let copy: TElement = _duplicateElement(element);
|
||||
copy.id = randomId();
|
||||
copy.seed = randomInteger();
|
||||
@ -162,4 +159,4 @@ export function duplicateElement<TElement extends Mutable<ExcalidrawElement>>(
|
||||
copy = Object.assign(copy, overrides);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
};
|
||||
|
@ -13,27 +13,24 @@ import { AppState } from "../types";
|
||||
|
||||
type HandlerRectanglesRet = keyof ReturnType<typeof handlerRectangles>;
|
||||
|
||||
function isInHandlerRect(
|
||||
const isInHandlerRect = (
|
||||
handler: [number, number, number, number],
|
||||
x: number,
|
||||
y: number,
|
||||
) {
|
||||
return (
|
||||
x >= handler[0] &&
|
||||
x <= handler[0] + handler[2] &&
|
||||
y >= handler[1] &&
|
||||
y <= handler[1] + handler[3]
|
||||
);
|
||||
}
|
||||
) =>
|
||||
x >= handler[0] &&
|
||||
x <= handler[0] + handler[2] &&
|
||||
y >= handler[1] &&
|
||||
y <= handler[1] + handler[3];
|
||||
|
||||
export function resizeTest(
|
||||
export const resizeTest = (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
appState: AppState,
|
||||
x: number,
|
||||
y: number,
|
||||
zoom: number,
|
||||
pointerType: PointerType,
|
||||
): HandlerRectanglesRet | false {
|
||||
): HandlerRectanglesRet | false => {
|
||||
if (!appState.selectedElementIds[element.id]) {
|
||||
return false;
|
||||
}
|
||||
@ -66,30 +63,29 @@ export function resizeTest(
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export function getElementWithResizeHandler(
|
||||
export const getElementWithResizeHandler = (
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
appState: AppState,
|
||||
{ x, y }: { x: number; y: number },
|
||||
zoom: number,
|
||||
pointerType: PointerType,
|
||||
) {
|
||||
return elements.reduce((result, element) => {
|
||||
) =>
|
||||
elements.reduce((result, element) => {
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
const resizeHandle = resizeTest(element, appState, x, y, zoom, pointerType);
|
||||
return resizeHandle ? { element, resizeHandle } : null;
|
||||
}, null as { element: NonDeletedExcalidrawElement; resizeHandle: ReturnType<typeof resizeTest> } | null);
|
||||
}
|
||||
|
||||
export function getResizeHandlerFromCoords(
|
||||
export const getResizeHandlerFromCoords = (
|
||||
[x1, y1, x2, y2]: readonly [number, number, number, number],
|
||||
{ x, y }: { x: number; y: number },
|
||||
zoom: number,
|
||||
pointerType: PointerType,
|
||||
) {
|
||||
) => {
|
||||
const handlers = handlerRectanglesFromCoords(
|
||||
[x1, y1, x2, y2],
|
||||
0,
|
||||
@ -103,7 +99,7 @@ export function getResizeHandlerFromCoords(
|
||||
return handler && isInHandlerRect(handler, x, y);
|
||||
});
|
||||
return (found || false) as HandlerRectanglesRet;
|
||||
}
|
||||
};
|
||||
|
||||
const RESIZE_CURSORS = ["ns", "nesw", "ew", "nwse"];
|
||||
const rotateResizeCursor = (cursor: string, angle: number) => {
|
||||
@ -118,10 +114,10 @@ const rotateResizeCursor = (cursor: string, angle: number) => {
|
||||
/*
|
||||
* Returns bi-directional cursor for the element being resized
|
||||
*/
|
||||
export function getCursorForResizingElement(resizingElement: {
|
||||
export const getCursorForResizingElement = (resizingElement: {
|
||||
element?: ExcalidrawElement;
|
||||
resizeHandle: ReturnType<typeof resizeTest>;
|
||||
}): string {
|
||||
}): string => {
|
||||
const { element, resizeHandle } = resizingElement;
|
||||
const shouldSwapCursors =
|
||||
element && Math.sign(element.height) * Math.sign(element.width) === -1;
|
||||
@ -161,12 +157,12 @@ export function getCursorForResizingElement(resizingElement: {
|
||||
}
|
||||
|
||||
return cursor ? `${cursor}-resize` : "";
|
||||
}
|
||||
};
|
||||
|
||||
export function normalizeResizeHandle(
|
||||
export const normalizeResizeHandle = (
|
||||
element: ExcalidrawElement,
|
||||
resizeHandle: HandlerRectanglesRet,
|
||||
): HandlerRectanglesRet {
|
||||
): HandlerRectanglesRet => {
|
||||
if (element.width >= 0 && element.height >= 0) {
|
||||
return resizeHandle;
|
||||
}
|
||||
@ -215,4 +211,4 @@ export function normalizeResizeHandle(
|
||||
}
|
||||
|
||||
return resizeHandle;
|
||||
}
|
||||
};
|
||||
|
@ -3,21 +3,23 @@ import { mutateElement } from "./mutateElement";
|
||||
import { isLinearElement } from "./typeChecks";
|
||||
import { SHIFT_LOCKING_ANGLE } from "../constants";
|
||||
|
||||
export function isInvisiblySmallElement(element: ExcalidrawElement): boolean {
|
||||
export const isInvisiblySmallElement = (
|
||||
element: ExcalidrawElement,
|
||||
): boolean => {
|
||||
if (isLinearElement(element)) {
|
||||
return element.points.length < 2;
|
||||
}
|
||||
return element.width === 0 && element.height === 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a perfect shape or diagonal/horizontal/vertical line
|
||||
*/
|
||||
export function getPerfectElementSize(
|
||||
export const getPerfectElementSize = (
|
||||
elementType: string,
|
||||
width: number,
|
||||
height: number,
|
||||
): { width: number; height: number } {
|
||||
): { width: number; height: number } => {
|
||||
const absWidth = Math.abs(width);
|
||||
const absHeight = Math.abs(height);
|
||||
|
||||
@ -42,13 +44,13 @@ export function getPerfectElementSize(
|
||||
height = absWidth * Math.sign(height);
|
||||
}
|
||||
return { width, height };
|
||||
}
|
||||
};
|
||||
|
||||
export function resizePerfectLineForNWHandler(
|
||||
export const resizePerfectLineForNWHandler = (
|
||||
element: ExcalidrawElement,
|
||||
x: number,
|
||||
y: number,
|
||||
) {
|
||||
) => {
|
||||
const anchorX = element.x + element.width;
|
||||
const anchorY = element.y + element.height;
|
||||
const distanceToAnchorX = x - anchorX;
|
||||
@ -77,14 +79,14 @@ export function resizePerfectLineForNWHandler(
|
||||
height: nextHeight,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {boolean} whether element was normalized
|
||||
*/
|
||||
export function normalizeDimensions(
|
||||
export const normalizeDimensions = (
|
||||
element: ExcalidrawElement | null,
|
||||
): element is ExcalidrawElement {
|
||||
): element is ExcalidrawElement => {
|
||||
if (!element || (element.width >= 0 && element.height >= 0)) {
|
||||
return false;
|
||||
}
|
||||
@ -106,4 +108,4 @@ export function normalizeDimensions(
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ import { globalSceneState } from "../scene";
|
||||
import { isTextElement } from "./typeChecks";
|
||||
import { CLASSES } from "../constants";
|
||||
|
||||
function trimText(text: string) {
|
||||
const trimText = (text: string) => {
|
||||
// whitespace only → trim all because we'd end up inserting invisible element
|
||||
if (!text.trim()) {
|
||||
return "";
|
||||
@ -13,7 +13,7 @@ function trimText(text: string) {
|
||||
// box calculation (there's also a bug in FF which inserts trailing newline
|
||||
// for multiline texts)
|
||||
return text.replace(/^\n+|\n+$/g, "");
|
||||
}
|
||||
};
|
||||
|
||||
type TextWysiwygParams = {
|
||||
id: string;
|
||||
@ -31,7 +31,7 @@ type TextWysiwygParams = {
|
||||
onCancel: () => void;
|
||||
};
|
||||
|
||||
export function textWysiwyg({
|
||||
export const textWysiwyg = ({
|
||||
id,
|
||||
initText,
|
||||
x,
|
||||
@ -45,7 +45,7 @@ export function textWysiwyg({
|
||||
textAlign,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}: TextWysiwygParams) {
|
||||
}: TextWysiwygParams) => {
|
||||
const editable = document.createElement("div");
|
||||
try {
|
||||
editable.contentEditable = "plaintext-only";
|
||||
@ -126,20 +126,20 @@ export function textWysiwyg({
|
||||
}
|
||||
};
|
||||
|
||||
function stopEvent(event: Event) {
|
||||
const stopEvent = (event: Event) => {
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
function handleSubmit() {
|
||||
const handleSubmit = () => {
|
||||
if (editable.innerText) {
|
||||
onSubmit(trimText(editable.innerText));
|
||||
} else {
|
||||
onCancel();
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
function cleanup() {
|
||||
const cleanup = () => {
|
||||
if (isDestroyed) {
|
||||
return;
|
||||
}
|
||||
@ -158,7 +158,7 @@ export function textWysiwyg({
|
||||
unbindUpdate();
|
||||
|
||||
document.body.removeChild(editable);
|
||||
}
|
||||
};
|
||||
|
||||
const rebindBlur = () => {
|
||||
window.removeEventListener("pointerup", rebindBlur);
|
||||
@ -210,4 +210,4 @@ export function textWysiwyg({
|
||||
document.body.appendChild(editable);
|
||||
editable.focus();
|
||||
selectNode(editable);
|
||||
}
|
||||
};
|
||||
|
@ -4,24 +4,24 @@ import {
|
||||
ExcalidrawLinearElement,
|
||||
} from "./types";
|
||||
|
||||
export function isTextElement(
|
||||
export const isTextElement = (
|
||||
element: ExcalidrawElement | null,
|
||||
): element is ExcalidrawTextElement {
|
||||
): element is ExcalidrawTextElement => {
|
||||
return element != null && element.type === "text";
|
||||
}
|
||||
};
|
||||
|
||||
export function isLinearElement(
|
||||
export const isLinearElement = (
|
||||
element?: ExcalidrawElement | null,
|
||||
): element is ExcalidrawLinearElement {
|
||||
): element is ExcalidrawLinearElement => {
|
||||
return (
|
||||
element != null &&
|
||||
(element.type === "arrow" ||
|
||||
element.type === "line" ||
|
||||
element.type === "draw")
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export function isExcalidrawElement(element: any): boolean {
|
||||
export const isExcalidrawElement = (element: any): boolean => {
|
||||
return (
|
||||
element?.type === "text" ||
|
||||
element?.type === "diamond" ||
|
||||
@ -31,4 +31,4 @@ export function isExcalidrawElement(element: any): boolean {
|
||||
element?.type === "draw" ||
|
||||
element?.type === "line"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user