
* resize single elements from the side * fix lint * do not resize texts from the sides (for we want to wrap/unwrap) * omit side handles for frames too * upgrade types * enable resizing from the sides for multiple elements as well * fix lint * maintain aspect ratio when elements are not of the same angle * lint * always resize proportionally for multiple elements * increase side resizing padding * code cleanup * adaptive handles * do not resize for linear elements with only two points * prioritize point dragging over edge resizing * lint * allow free resizing for multiple elements at degree 0 * always resize from the sides * reduce hit threshold * make small multiple elements movable * lint * show side handles on touch screen and mobile devices * differentiate touchscreens * keep proportional with text in multi-element resizing * update snapshot * update multi elements resizing logic * lint * reduce side resizing padding * bound texts do not scale in normal cases * lint * test sides for texts * wrap text * do not update text size when changing its alignment * keep text wrapped/unwrapped when editing * change wrapped size to auto size from context menu * fix test * lint * increase min width for wrapped texts * wrap wrapped text in container * unwrap when binding text to container * rename `wrapped` to `autoResize` * fix lint * revert: use `center` align when wrapping text in container * update snaps * fix lint * simplify logic on autoResize * lint and test * snapshots * remove unnecessary code * snapshots * fix: defaults not set correctly * tests for wrapping texts when resized * tests for text wrapping when edited * fix autoResize refactor * include autoResize flag check * refactor * feat: rename action label & change contextmenu position * fix: update version on `autoResize` action * fix infinite loop when editing text in a container * simplify * always maintain `width` if `!autoResize` * maintain `x` if `!autoResize` * maintain `y` pos after fontSize change if `!autoResize` * refactor * when editing, do not wrap text in textWysiwyg * simplify text editor * make test more readable * comment * rename action to match file name * revert function signature change * only update in app --------- Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
122 lines
3.3 KiB
TypeScript
122 lines
3.3 KiB
TypeScript
import type {
|
|
ExcalidrawElement,
|
|
NonDeletedExcalidrawElement,
|
|
NonDeleted,
|
|
} from "./types";
|
|
import { isInvisiblySmallElement } from "./sizeHelpers";
|
|
import { isLinearElementType } from "./typeChecks";
|
|
|
|
export {
|
|
newElement,
|
|
newTextElement,
|
|
refreshTextDimensions,
|
|
newLinearElement,
|
|
newImageElement,
|
|
duplicateElement,
|
|
} from "./newElement";
|
|
export {
|
|
getElementAbsoluteCoords,
|
|
getElementBounds,
|
|
getCommonBounds,
|
|
getDiamondPoints,
|
|
getArrowheadPoints,
|
|
getClosestElementBounds,
|
|
} from "./bounds";
|
|
|
|
export {
|
|
OMIT_SIDES_FOR_MULTIPLE_ELEMENTS,
|
|
getTransformHandlesFromCoords,
|
|
getTransformHandles,
|
|
} from "./transformHandles";
|
|
export {
|
|
resizeTest,
|
|
getCursorForResizingElement,
|
|
getElementWithTransformHandleType,
|
|
getTransformHandleTypeFromCoords,
|
|
} from "./resizeTest";
|
|
export {
|
|
transformElements,
|
|
getResizeOffsetXY,
|
|
getResizeArrowDirection,
|
|
} from "./resizeElements";
|
|
export {
|
|
dragSelectedElements,
|
|
getDragOffsetXY,
|
|
dragNewElement,
|
|
} from "./dragElements";
|
|
export { isTextElement, isExcalidrawElement } from "./typeChecks";
|
|
export { redrawTextBoundingBox } from "./textElement";
|
|
export {
|
|
getPerfectElementSize,
|
|
getLockedLinearCursorAlignSize,
|
|
isInvisiblySmallElement,
|
|
resizePerfectLineForNWHandler,
|
|
getNormalizedDimensions,
|
|
} from "./sizeHelpers";
|
|
export { showSelectedShapeActions } from "./showSelectedShapeActions";
|
|
|
|
/**
|
|
* @deprecated unsafe, use hashElementsVersion instead
|
|
*/
|
|
export const getSceneVersion = (elements: readonly ExcalidrawElement[]) =>
|
|
elements.reduce((acc, el) => acc + el.version, 0);
|
|
|
|
/**
|
|
* Hashes elements' versionNonce (using djb2 algo). Order of elements matters.
|
|
*/
|
|
export const hashElementsVersion = (
|
|
elements: readonly ExcalidrawElement[],
|
|
): number => {
|
|
let hash = 5381;
|
|
for (let i = 0; i < elements.length; i++) {
|
|
hash = (hash << 5) + hash + elements[i].versionNonce;
|
|
}
|
|
return hash >>> 0; // Ensure unsigned 32-bit integer
|
|
};
|
|
|
|
// string hash function (using djb2). Not cryptographically secure, use only
|
|
// for versioning and such.
|
|
export const hashString = (s: string): number => {
|
|
let hash: number = 5381;
|
|
for (let i = 0; i < s.length; i++) {
|
|
const char: number = s.charCodeAt(i);
|
|
hash = (hash << 5) + hash + char;
|
|
}
|
|
return hash >>> 0; // Ensure unsigned 32-bit integer
|
|
};
|
|
|
|
export const getVisibleElements = (elements: readonly ExcalidrawElement[]) =>
|
|
elements.filter(
|
|
(el) => !el.isDeleted && !isInvisiblySmallElement(el),
|
|
) as readonly NonDeletedExcalidrawElement[];
|
|
|
|
export const getNonDeletedElements = <T extends ExcalidrawElement>(
|
|
elements: readonly T[],
|
|
) =>
|
|
elements.filter((element) => !element.isDeleted) as readonly NonDeleted<T>[];
|
|
|
|
export const isNonDeletedElement = <T extends ExcalidrawElement>(
|
|
element: T,
|
|
): element is NonDeleted<T> => !element.isDeleted;
|
|
|
|
const _clearElements = (
|
|
elements: readonly ExcalidrawElement[],
|
|
): ExcalidrawElement[] =>
|
|
getNonDeletedElements(elements).map((element) =>
|
|
isLinearElementType(element.type)
|
|
? { ...element, lastCommittedPoint: null }
|
|
: element,
|
|
);
|
|
|
|
export const clearElementsForDatabase = (
|
|
elements: readonly ExcalidrawElement[],
|
|
) => _clearElements(elements);
|
|
|
|
export const clearElementsForExport = (
|
|
elements: readonly ExcalidrawElement[],
|
|
) => _clearElements(elements);
|
|
|
|
export const clearElementsForLocalStorage = (
|
|
elements: readonly ExcalidrawElement[],
|
|
) => _clearElements(elements);
|