lint & format

This commit is contained in:
dwelle
2026-01-24 22:28:19 +01:00
parent be9981bda5
commit 29ba7fe96d
181 changed files with 3968 additions and 2654 deletions
+20 -20
View File
@@ -1,10 +1,21 @@
{
"name": "@excalidraw/element",
"version": "0.18.0",
"description": "Excalidraw elements-related logic",
"keywords": [
"excalidraw",
"excalidraw-utils"
],
"bugs": "https://github.com/excalidraw/excalidraw/issues",
"license": "MIT",
"repository": "https://github.com/excalidraw/excalidraw",
"files": [
"dist/*"
],
"type": "module",
"types": "./dist/types/element/src/index.d.ts",
"main": "./dist/prod/index.js",
"module": "./dist/prod/index.js",
"types": "./dist/types/element/src/index.d.ts",
"exports": {
".": {
"types": "./dist/types/element/src/index.d.ts",
@@ -25,18 +36,17 @@
"default": "./dist/prod/visualdebug.js"
}
},
"files": [
"dist/*"
],
"description": "Excalidraw elements-related logic",
"publishConfig": {
"access": "public"
},
"license": "MIT",
"keywords": [
"excalidraw",
"excalidraw-utils"
],
"scripts": {
"gen:types": "rimraf types && tsc",
"build:esm": "rimraf dist && node ../../scripts/buildBase.js && yarn gen:types"
},
"dependencies": {
"@excalidraw/common": "0.18.0",
"@excalidraw/math": "0.18.0"
},
"browserslist": {
"production": [
">0.2%",
@@ -55,15 +65,5 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"bugs": "https://github.com/excalidraw/excalidraw/issues",
"repository": "https://github.com/excalidraw/excalidraw",
"scripts": {
"gen:types": "rimraf types && tsc",
"build:esm": "rimraf dist && node ../../scripts/buildBase.js && yarn gen:types"
},
"dependencies": {
"@excalidraw/common": "0.18.0",
"@excalidraw/math": "0.18.0"
}
}
+1 -1
View File
@@ -90,7 +90,7 @@ const hashSelectionOpts = (
type _ = Assert<
SameType<
Required<HashableKeys>,
Pick<Required<HashableKeys>, typeof keys[number]>
Pick<Required<HashableKeys>, (typeof keys)[number]>
>
>;
+50 -56
View File
@@ -258,7 +258,7 @@ const bindingStrategyForElbowArrowEndpointDragging = (
globalPoint,
elements,
elementsMap,
(element) => maxBindingDistance_simple(zoom),
() => maxBindingDistance_simple(zoom),
);
const current = hit
@@ -391,7 +391,7 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
element: otherElement,
focusPoint: shiftKey
? elementCenterPoint(otherElement, elementsMap)
: origin ?? pointFrom<GlobalPoint>(arrow.x, arrow.y),
: (origin ?? pointFrom<GlobalPoint>(arrow.x, arrow.y)),
};
// We are hovering another element with the end point
@@ -522,41 +522,35 @@ const bindingStrategyForSimpleArrowEndpointDragging_complex = (
}
// The opposite binding is inside the same element
// eslint-disable-next-line no-else-return
else {
current = { element: hit, mode: "inside", focusPoint: point };
return { current, other: isMultiPoint ? { mode: undefined } : other };
}
}
// The opposite binding is on a different element (or nested)
// eslint-disable-next-line no-else-return
else {
// Handle the nested element case
if (isOverlapping && oppositeElement && !otherIsTransparent) {
current = {
element: oppositeElement,
mode: "inside",
focusPoint: point,
};
} else {
current = {
element: hit,
mode: "orbit",
focusPoint: isNested ? point : point,
};
}
current = { element: hit, mode: "inside", focusPoint: point };
return { current, other: isMultiPoint ? { mode: undefined } : other };
}
// The opposite binding is on a different element (or nested)
// eslint-disable-next-line no-else-return
// Handle the nested element case
if (isOverlapping && oppositeElement && !otherIsTransparent) {
current = {
element: oppositeElement,
mode: "inside",
focusPoint: point,
};
} else {
current = {
element: hit,
mode: "orbit",
focusPoint: isNested ? point : point,
};
}
return { current, other: isMultiPoint ? { mode: undefined } : other };
}
// The opposite binding is on a different element or no binding
else {
current = {
element: hit,
mode: "orbit",
focusPoint: point,
};
}
current = {
element: hit,
mode: "orbit",
focusPoint: point,
};
// Must return as only one endpoint is dragged, therefore
// the end binding strategy might accidentally gets overriden
@@ -683,7 +677,7 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
globalPoint,
elements,
elementsMap,
(e) => maxBindingDistance_simple(appState.zoom),
() => maxBindingDistance_simple(appState.zoom),
);
const pointInElement =
hit &&
@@ -726,13 +720,13 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
focusPoint: startDragged
? globalPoint
: // NOTE: Can only affect the start point because new arrows always drag the end point
opts?.newArrow
? appState.selectedLinearElement!.initialState.origin!
: LinearElementEditor.getPointAtIndexGlobalCoordinates(
arrow,
0,
elementsMap,
), // startFixedPoint,
opts?.newArrow
? appState.selectedLinearElement!.initialState.origin!
: LinearElementEditor.getPointAtIndexGlobalCoordinates(
arrow,
0,
elementsMap,
), // startFixedPoint,
},
end: {
mode: "inside",
@@ -810,19 +804,19 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
focusPoint: appState.selectedLinearElement.initialState.altFocusPoint,
}
: opts?.angleLocked && otherBindableElement
? {
mode: "orbit",
element: otherBindableElement,
focusPoint:
projectFixedPointOntoDiagonal(
arrow,
otherEndpoint,
otherBindableElement,
startDragged ? "end" : "start",
elementsMap,
) || otherEndpoint,
}
: { mode: undefined };
? {
mode: "orbit",
element: otherBindableElement,
focusPoint:
projectFixedPointOntoDiagonal(
arrow,
otherEndpoint,
otherBindableElement,
startDragged ? "end" : "start",
elementsMap,
) || otherEndpoint,
}
: { mode: undefined };
return {
start: startDragged ? current : other,
@@ -1944,9 +1938,9 @@ const newBoundElements = (
nextBoundElements.push(
...elementsToAdd.map(
(x) =>
({ id: x.id, type: x.type } as
({ id: x.id, type: x.type }) as
| ExcalidrawArrowElement
| ExcalidrawTextElement),
| ExcalidrawTextElement,
),
);
@@ -2414,7 +2408,7 @@ const SHAPE_CONFIGS: Record<ShapeType, SectorConfig[]> = {
const getSectorBoundaries = (
config: SectorConfig[],
): Array<{ start: number; end: number; side: Side }> => {
return config.map((sector, index) => {
return config.map((sector) => {
const halfWidth = sector.sectorWidth / 2;
let start = sector.centerAngle - halfWidth;
let end = sector.centerAngle + halfWidth;
+7 -10
View File
@@ -974,7 +974,7 @@ export class AppStateDelta implements DeltaContainer<AppState> {
inserted,
"selectedElementIds",
// ts language server has a bit trouble resolving this, so we are giving it a little push
(_) => true as ValueOf<T["selectedElementIds"]>,
() => true as ValueOf<T["selectedElementIds"]>,
);
Delta.diffObjects(
deleted,
@@ -995,9 +995,8 @@ export class AppStateDelta implements DeltaContainer<AppState> {
if (isTestEnv() || isDevEnv()) {
throw e;
}
} finally {
return [deleted, inserted];
}
return [deleted, inserted];
}
private static orderAppStateKeys(partial: Partial<ObservedAppState>) {
@@ -1459,9 +1458,8 @@ export class ElementsDelta implements DeltaContainer<SceneElementsMap> {
if (isTestEnv() || isDevEnv()) {
throw e;
}
} finally {
return [nextElements, flags.containsVisibleDifference];
}
return [nextElements, flags.containsVisibleDifference];
}
public squash(delta: ElementsDelta): this {
@@ -1802,7 +1800,7 @@ export class ElementsDelta implements DeltaContainer<SceneElementsMap> {
// updated delta is affecting the binding only in case it contains changed binding or bindable property
for (const [id] of Array.from(Object.entries(this.updated)).filter(
([_, delta]) =>
([, delta]) =>
Object.keys({ ...delta.deleted, ...delta.inserted }).find((prop) =>
bindingProperties.has(prop as BindingProp | BindableProp),
),
@@ -1908,9 +1906,8 @@ export class ElementsDelta implements DeltaContainer<SceneElementsMap> {
if (isTestEnv() || isDevEnv()) {
throw e;
}
} finally {
return nextElements;
}
return nextElements;
}
private static redrawTextBoundingBoxes(
@@ -2051,9 +2048,9 @@ export class ElementsDelta implements DeltaContainer<SceneElementsMap> {
if (isTestEnv() || isDevEnv()) {
throw e;
}
} finally {
return [deleted, inserted];
}
return [deleted, inserted];
}
private static stripIrrelevantProps(
+38 -36
View File
@@ -255,11 +255,12 @@ const handleSegmentRenormalization = (
);
}
isDevEnv() &&
if (isDevEnv()) {
invariant(
validateElbowPoints(nextPoints),
"Invalid elbow points with fixed segments",
);
}
return normalizeArrowElementUpdate(
nextPoints,
@@ -521,8 +522,8 @@ const handleSegmentMove = (
? segmentLength / 2
: BASE_PADDING
: segmentIsTooShort
? -segmentLength / 2
: -BASE_PADDING;
? -segmentLength / 2
: -BASE_PADDING;
fixedSegments[activelyModifiedSegmentIdx].start = pointFrom<LocalPoint>(
fixedSegments[activelyModifiedSegmentIdx].start[0] +
(startIsHorizontal ? padding : 0),
@@ -547,8 +548,8 @@ const handleSegmentMove = (
? segmentLength / 2
: BASE_PADDING
: segmentIsTooShort
? -segmentLength / 2
: -BASE_PADDING;
? -segmentLength / 2
: -BASE_PADDING;
fixedSegments[activelyModifiedSegmentIdx].end = pointFrom<LocalPoint>(
fixedSegments[activelyModifiedSegmentIdx].end[0] +
(endIsHorizontal ? padding : 0),
@@ -571,7 +572,7 @@ const handleSegmentMove = (
}));
// For start, clone old arrow points
const newPoints: GlobalPoint[] = arrow.points.map((p, i) =>
const newPoints: GlobalPoint[] = arrow.points.map((p) =>
pointFrom<GlobalPoint>(arrow.x + p[0], arrow.y + p[1]),
);
@@ -720,11 +721,11 @@ const handleEndpointDrag = (
i === 0
? pointFrom<GlobalPoint>(arrow.x + p[0], arrow.y + p[1])
: i === updatedPoints.length - 1
? pointFrom<GlobalPoint>(arrow.x + p[0], arrow.y + p[1])
: pointFrom<GlobalPoint>(
arrow.x + arrow.points[i][0],
arrow.y + arrow.points[i][1],
),
? pointFrom<GlobalPoint>(arrow.x + p[0], arrow.y + p[1])
: pointFrom<GlobalPoint>(
arrow.x + arrow.points[i][0],
arrow.y + arrow.points[i][1],
),
);
const nextFixedSegments = fixedSegments.map((segment) => ({
...segment,
@@ -982,8 +983,8 @@ export const updateElbowArrowPoints = (
idx === 0
? updates.points![0]
: idx === arrow.points.length - 1
? updates.points![1]
: p,
? updates.points![1]
: p,
)
: updates.points.slice()
: arrow.points.slice();
@@ -1489,8 +1490,12 @@ const routeElbowArrow = (
node.pos[0],
node.pos[1],
]) as GlobalPoint[];
startDongle && points.unshift(startGlobalPoint);
endDongle && points.push(endGlobalPoint);
if (startDongle) {
points.unshift(startGlobalPoint);
}
if (endDongle) {
points.push(endGlobalPoint);
}
return points;
}
@@ -1680,29 +1685,29 @@ const generateDynamicAABBs = (
? Math.min((startEl[0] + endEl[2]) / 2, a[0] - startLeft)
: (startEl[0] + endEl[2]) / 2
: a[0] > b[0]
? a[0] - startLeft
: common[0] - startLeft,
? a[0] - startLeft
: common[0] - startLeft,
a[1] > b[3]
? a[0] > b[2] || a[2] < b[0]
? Math.min((startEl[1] + endEl[3]) / 2, a[1] - startUp)
: (startEl[1] + endEl[3]) / 2
: a[1] > b[1]
? a[1] - startUp
: common[1] - startUp,
? a[1] - startUp
: common[1] - startUp,
a[2] < b[0]
? a[1] > b[3] || a[3] < b[1]
? Math.max((startEl[2] + endEl[0]) / 2, a[2] + startRight)
: (startEl[2] + endEl[0]) / 2
: a[2] < b[2]
? a[2] + startRight
: common[2] + startRight,
? a[2] + startRight
: common[2] + startRight,
a[3] < b[1]
? a[0] > b[2] || a[2] < b[0]
? Math.max((startEl[3] + endEl[1]) / 2, a[3] + startDown)
: (startEl[3] + endEl[1]) / 2
: a[3] < b[3]
? a[3] + startDown
: common[3] + startDown,
? a[3] + startDown
: common[3] + startDown,
] as Bounds;
const second = [
b[0] > a[2]
@@ -1710,29 +1715,29 @@ const generateDynamicAABBs = (
? Math.min((endEl[0] + startEl[2]) / 2, b[0] - endLeft)
: (endEl[0] + startEl[2]) / 2
: b[0] > a[0]
? b[0] - endLeft
: common[0] - endLeft,
? b[0] - endLeft
: common[0] - endLeft,
b[1] > a[3]
? b[0] > a[2] || b[2] < a[0]
? Math.min((endEl[1] + startEl[3]) / 2, b[1] - endUp)
: (endEl[1] + startEl[3]) / 2
: b[1] > a[1]
? b[1] - endUp
: common[1] - endUp,
? b[1] - endUp
: common[1] - endUp,
b[2] < a[0]
? b[1] > a[3] || b[3] < a[1]
? Math.max((endEl[2] + startEl[0]) / 2, b[2] + endRight)
: (endEl[2] + startEl[0]) / 2
: b[2] < a[2]
? b[2] + endRight
: common[2] + endRight,
? b[2] + endRight
: common[2] + endRight,
b[3] < a[1]
? b[0] > a[2] || b[2] < a[0]
? Math.max((endEl[3] + startEl[1]) / 2, b[3] + endDown)
: (endEl[3] + startEl[1]) / 2
: b[3] < a[3]
? b[3] + endDown
: common[3] + endDown,
? b[3] + endDown
: common[3] + endDown,
] as Bounds;
const c = commonAABB([first, second]);
@@ -2272,11 +2277,8 @@ const getHoveredElement = (
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
zoom?: AppState["zoom"],
) => {
return getHoveredElementForBinding(
origPoint,
elements,
elementsMap,
(element) => maxBindingDistance_simple(zoom),
return getHoveredElementForBinding(origPoint, elements, elementsMap, () =>
maxBindingDistance_simple(zoom),
);
};
+2 -2
View File
@@ -13,7 +13,7 @@ import type { ExcalidrawElement } from "./types";
export const defaultGetElementLinkFromSelection: Exclude<
AppProps["generateLinkForSelection"],
undefined
> = (id, type) => {
> = (id) => {
const url = window.location.href;
try {
@@ -86,7 +86,7 @@ export const isElementLink = (url: string) => {
_url.searchParams.has(ELEMENT_LINK_KEY) &&
_url.host === window.location.host
);
} catch (error) {
} catch {
return false;
}
};
+2 -2
View File
@@ -63,7 +63,7 @@ const parseYouTubeTimestamp = (url: string): number => {
const urlObj = new URL(url.startsWith("http") ? url : `https://${url}`);
timeParam =
urlObj.searchParams.get("t") || urlObj.searchParams.get("start");
} catch (error) {
} catch {
const timeMatch = url.match(/[?&#](?:t|start)=([^&#\s]+)/);
timeParam = timeMatch?.[1];
}
@@ -388,7 +388,7 @@ const matchHostname = (
if (bareDomain === bareAllowedHostname) {
return bareAllowedHostname;
}
} catch (error) {
} catch {
// ignore
}
return null;
+4 -4
View File
@@ -198,8 +198,8 @@ const getOffsets = (
linkedNodes.length === 0
? 0
: (linkedNodes.length + 1) % 2 === 0
? ((linkedNodes.length + 1) / 2) * _HORIZONTAL_OFFSET
: (linkedNodes.length / 2) * _HORIZONTAL_OFFSET * -1;
? ((linkedNodes.length + 1) / 2) * _HORIZONTAL_OFFSET
: (linkedNodes.length / 2) * _HORIZONTAL_OFFSET * -1;
if (direction === "up") {
return {
@@ -222,8 +222,8 @@ const getOffsets = (
linkedNodes.length === 0
? 0
: (linkedNodes.length + 1) % 2 === 0
? ((linkedNodes.length + 1) / 2) * _VERTICAL_OFFSET
: (linkedNodes.length / 2) * _VERTICAL_OFFSET * -1;
? ((linkedNodes.length + 1) / 2) * _VERTICAL_OFFSET
: (linkedNodes.length / 2) * _VERTICAL_OFFSET * -1;
if (direction === "left") {
return {
+1 -1
View File
@@ -187,7 +187,7 @@ export const syncMovedIndices = (
for (const [element, { index }] of elementsUpdates) {
mutateElement(element, elementsMap, { index });
}
} catch (e) {
} catch {
// fallback to default sync
syncInvalidIndices(elements);
}
+1 -1
View File
@@ -797,7 +797,7 @@ export const isElementInFrame = (
for (const gid of _element.groupIds) {
if (opts?.checkedGroups?.has(gid)) {
return opts.checkedGroups.get(gid)!!;
return opts.checkedGroups.get(gid)!;
}
}
+4 -4
View File
@@ -231,8 +231,8 @@ export const getSelectedGroupIds = (
appState: InteractiveCanvasAppState,
): GroupId[] =>
Object.entries(appState.selectedGroupIds)
.filter(([groupId, isSelected]) => isSelected)
.map(([groupId, isSelected]) => groupId);
.filter(([, isSelected]) => isSelected)
.map(([groupId]) => groupId);
// given a list of elements, return the the actual group ids that should be selected
// or used to update the elements
@@ -325,8 +325,8 @@ export const getMaximumGroups = (
elements: ExcalidrawElement[],
elementsMap: ElementsMap,
): ExcalidrawElement[][] => {
const groups: Map<String, ExcalidrawElement[]> = new Map<
String,
const groups: Map<string, ExcalidrawElement[]> = new Map<
string,
ExcalidrawElement[]
>();
elements.forEach((element: ExcalidrawElement) => {
+10 -10
View File
@@ -268,16 +268,16 @@ export const headingForPointFromElement = <Point extends GlobalPoint>(
)
? HEADING_UP
: triangleIncludesPoint<Point>(
[topRight, bottomRight, midPoint] as Triangle<Point>,
p,
)
? HEADING_RIGHT
: triangleIncludesPoint<Point>(
[bottomRight, bottomLeft, midPoint] as Triangle<Point>,
p,
)
? HEADING_DOWN
: HEADING_LEFT;
[topRight, bottomRight, midPoint] as Triangle<Point>,
p,
)
? HEADING_RIGHT
: triangleIncludesPoint<Point>(
[bottomRight, bottomLeft, midPoint] as Triangle<Point>,
p,
)
? HEADING_DOWN
: HEADING_LEFT;
};
export const flipHeading = (h: Heading): Heading =>
+1 -1
View File
@@ -69,7 +69,7 @@ export const updateImageCache = async ({
const image = await imagePromise;
imageCache.set(fileId, { ...data, image });
} catch (error: any) {
} catch {
erroredFiles.set(fileId, true);
}
})(),
+48 -48
View File
@@ -606,10 +606,10 @@ export class LinearElementEditor {
updates?.suggestedBinding?.id !== startBindingElement.id // The end point is not hovering the start bindable + it's binding gap
? startBindingElement
: startIsSelected && // The "other" end (i.e. "start") is dragged
endBindingElement &&
updates?.suggestedBinding?.id !== endBindingElement.id // The start point is not hovering the end bindable + it's binding gap
? endBindingElement
: null;
endBindingElement &&
updates?.suggestedBinding?.id !== endBindingElement.id // The start point is not hovering the end bindable + it's binding gap
? endBindingElement
: null;
const newLinearElementEditor: LinearElementEditor = {
...linearElementEditor,
@@ -721,8 +721,8 @@ export class LinearElementEditor {
)
: selectedPointsIndices
: selectedPointsIndices?.includes(pointerDownState.lastClickedPoint)
? [pointerDownState.lastClickedPoint]
: selectedPointsIndices,
? [pointerDownState.lastClickedPoint]
: selectedPointsIndices,
isDragging: false,
pointerOffset: { x: 0, y: 0 },
customLineAngle: null,
@@ -976,7 +976,7 @@ export class LinearElementEditor {
const appState = app.state;
const elementsMap = scene.getNonDeletedElementsMap();
const ret: ReturnType<typeof LinearElementEditor["handlePointerDown"]> = {
const ret: ReturnType<(typeof LinearElementEditor)["handlePointerDown"]> = {
didAddPoint: false,
hitElement: null,
linearElementEditor: null,
@@ -2130,8 +2130,8 @@ const pointDraggingUpdates = (
suggestedBinding: startIsDragged
? start.element
: endIsDragged
? end.element
: null,
? end.element
: null,
},
};
}
@@ -2222,14 +2222,14 @@ const pointDraggingUpdates = (
updates.startBinding === undefined
? element.startBinding
: updates.startBinding === null
? null
: updates.startBinding,
? null
: updates.startBinding,
endBinding:
updates.endBinding === undefined
? element.endBinding
: updates.endBinding === null
? null
: updates.endBinding,
? null
: updates.endBinding,
};
// We need to use a custom intersector to ensure that if there is a big "jump"
@@ -2261,28 +2261,28 @@ const pointDraggingUpdates = (
// We need to update the non-dragged point too if bound,
// so we look up the old binding to trigger updateBoundPoint
const endBindable = nextArrow.endBinding
? end.element ??
? (end.element ??
(elementsMap.get(
nextArrow.endBinding.elementId,
)! as ExcalidrawBindableElement)
)! as ExcalidrawBindableElement))
: null;
const endLocalPoint = startIsDraggingOverEndElement
? nextArrow.points[nextArrow.points.length - 1]
: endIsDraggingOverStartElement &&
app.state.bindMode !== "inside" &&
getFeatureFlag("COMPLEX_BINDINGS")
? nextArrow.points[0]
: endBindable
? updateBoundPoint(
element,
"endBinding",
nextArrow.endBinding,
endBindable,
elementsMap,
endCustomIntersector,
) || nextArrow.points[nextArrow.points.length - 1]
: nextArrow.points[nextArrow.points.length - 1];
app.state.bindMode !== "inside" &&
getFeatureFlag("COMPLEX_BINDINGS")
? nextArrow.points[0]
: endBindable
? updateBoundPoint(
element,
"endBinding",
nextArrow.endBinding,
endBindable,
elementsMap,
endCustomIntersector,
) || nextArrow.points[nextArrow.points.length - 1]
: nextArrow.points[nextArrow.points.length - 1];
// We need to keep the simulated next arrow up-to-date, because
// updateBoundPoint looks at the opposite point
@@ -2291,29 +2291,29 @@ const pointDraggingUpdates = (
// We need to update the non-dragged point too if bound,
// so we look up the old binding to trigger updateBoundPoint
const startBindable = nextArrow.startBinding
? start.element ??
? (start.element ??
(elementsMap.get(
nextArrow.startBinding.elementId,
)! as ExcalidrawBindableElement)
)! as ExcalidrawBindableElement))
: null;
const startLocalPoint =
endIsDraggingOverStartElement && getFeatureFlag("COMPLEX_BINDINGS")
? nextArrow.points[0]
: startIsDraggingOverEndElement &&
app.state.bindMode !== "inside" &&
getFeatureFlag("COMPLEX_BINDINGS")
? nextArrow.points[nextArrow.points.length - 1]
: startBindable
? updateBoundPoint(
element,
"startBinding",
nextArrow.startBinding,
startBindable,
elementsMap,
startCustomIntersector,
) || nextArrow.points[0]
: nextArrow.points[0];
app.state.bindMode !== "inside" &&
getFeatureFlag("COMPLEX_BINDINGS")
? nextArrow.points[nextArrow.points.length - 1]
: startBindable
? updateBoundPoint(
element,
"startBinding",
nextArrow.startBinding,
startBindable,
elementsMap,
startCustomIntersector,
) || nextArrow.points[0]
: nextArrow.points[0];
const endChanged =
pointDistance(
@@ -2350,11 +2350,11 @@ const pointDraggingUpdates = (
isDragging: true,
}
: idx === element.points.length - 1
? {
point: endLocalPoint,
isDragging: true,
}
: naiveDraggingPoints.get(idx)!,
? {
point: endLocalPoint,
isDragging: true,
}
: naiveDraggingPoints.get(idx)!,
];
}),
),
+2 -2
View File
@@ -230,8 +230,8 @@ const getTextElementPositionOffsets = (
opts.textAlign === "center"
? metrics.width / 2
: opts.textAlign === "right"
? metrics.width
: 0,
? metrics.width
: 0,
y: opts.verticalAlign === "middle" ? metrics.height / 2 : 0,
};
};
+2 -2
View File
@@ -514,8 +514,8 @@ const drawElementOnCanvas = (
element.textAlign === "center"
? element.width / 2
: element.textAlign === "right"
? element.width
: 0;
? element.width
: 0;
const lineHeightPx = getLineHeightInPx(
element.fontSize,
+3 -3
View File
@@ -819,8 +819,8 @@ export const resizeSingleElement = (
nextHeight,
origElement.angle,
handleDirection,
shouldMaintainAspectRatio!!,
shouldResizeFromCenter!!,
shouldMaintainAspectRatio,
shouldResizeFromCenter,
);
if (isLinearElement(origElement) && rescaledPoints.points) {
@@ -1370,7 +1370,7 @@ export const resizeMultipleElements = (
false,
);
const update: typeof elementsAndUpdates[0]["update"] = {
const update: (typeof elementsAndUpdates)[0]["update"] = {
x,
y,
width,
+22 -16
View File
@@ -137,22 +137,28 @@ export const getElementWithTransformHandleType = (
elementsMap: ElementsMap,
editorInterface: EditorInterface,
) => {
return elements.reduce((result, element) => {
if (result) {
return result;
}
const transformHandleType = resizeTest(
element,
elementsMap,
appState,
scenePointerX,
scenePointerY,
zoom,
pointerType,
editorInterface,
);
return transformHandleType ? { element, transformHandleType } : null;
}, null as { element: NonDeletedExcalidrawElement; transformHandleType: MaybeTransformHandleType } | null);
return elements.reduce(
(result, element) => {
if (result) {
return result;
}
const transformHandleType = resizeTest(
element,
elementsMap,
appState,
scenePointerX,
scenePointerY,
zoom,
pointerType,
editorInterface,
);
return transformHandleType ? { element, transformHandleType } : null;
},
null as {
element: NonDeletedExcalidrawElement;
transformHandleType: MaybeTransformHandleType;
} | null,
);
};
export const getTransformHandleTypeFromCoords = <
+4 -4
View File
@@ -223,10 +223,10 @@ export const getTargetElements = (
appState.editingTextElement
? [appState.editingTextElement]
: appState.newElement
? [appState.newElement]
: getSelectedElements(elements, appState, {
includeBoundTextElement: true,
});
? [appState.newElement]
: getSelectedElements(elements, appState, {
includeBoundTextElement: true,
});
/**
* returns prevState's selectedElementids if no change from previous, so as to
+16 -16
View File
@@ -201,8 +201,8 @@ export const generateRoughOptions = (
element.strokeStyle === "dashed"
? getDashArrayDashed(element.strokeWidth)
: element.strokeStyle === "dotted"
? getDashArrayDotted(element.strokeWidth)
: undefined,
? getDashArrayDotted(element.strokeWidth)
: undefined,
// for non-solid strokes, disable multiStroke because it tends to make
// dashes/dots overlay each other
disableMultiStroke: element.strokeStyle !== "solid",
@@ -235,8 +235,8 @@ export const generateRoughOptions = (
options.fill = isTransparent(element.backgroundColor)
? undefined
: isDarkMode
? applyDarkModeFilter(element.backgroundColor)
: element.backgroundColor;
? applyDarkModeFilter(element.backgroundColor)
: element.backgroundColor;
if (element.type === "ellipse") {
options.curveFitting = 1;
}
@@ -250,8 +250,8 @@ export const generateRoughOptions = (
element.backgroundColor === "transparent"
? undefined
: isDarkMode
? applyDarkModeFilter(element.backgroundColor)
: element.backgroundColor;
? applyDarkModeFilter(element.backgroundColor)
: element.backgroundColor;
}
return options;
}
@@ -708,20 +708,20 @@ const _generateElementShape = (
rightX - verticalRadius
} ${rightY - horizontalRadius}
C ${rightX} ${rightY}, ${rightX} ${rightY}, ${
rightX - verticalRadius
} ${rightY + horizontalRadius}
rightX - verticalRadius
} ${rightY + horizontalRadius}
L ${bottomX + verticalRadius} ${bottomY - horizontalRadius}
C ${bottomX} ${bottomY}, ${bottomX} ${bottomY}, ${
bottomX - verticalRadius
} ${bottomY - horizontalRadius}
bottomX - verticalRadius
} ${bottomY - horizontalRadius}
L ${leftX + verticalRadius} ${leftY + horizontalRadius}
C ${leftX} ${leftY}, ${leftX} ${leftY}, ${leftX + verticalRadius} ${
leftY - horizontalRadius
}
leftY - horizontalRadius
}
L ${topX - verticalRadius} ${topY + horizontalRadius}
C ${topX} ${topY}, ${topX} ${topY}, ${topX + verticalRadius} ${
topY + horizontalRadius
}`,
topY + horizontalRadius
}`,
generateRoughOptions(element, true, isDarkMode),
);
} else {
@@ -1057,8 +1057,8 @@ export const getFreedrawOutlinePoints = (
const inputPoints = element.simulatePressure
? element.points
: element.points.length
? element.points.map(([x, y], i) => [x, y, element.pressures[i]])
: [[0, 0, 0.5]];
? element.points.map(([x, y], i) => [x, y, element.pressures[i]])
: [[0, 0, 0.5]];
return getStroke(inputPoints as number[][], {
simulatePressure: element.simulatePressure,
@@ -10,13 +10,13 @@ export const showSelectedShapeActions = (
) =>
Boolean(
!appState.viewModeEnabled &&
appState.openDialog?.name !== "elementLinkSelector" &&
((appState.activeTool.type !== "custom" &&
(appState.editingTextElement ||
(appState.activeTool.type !== "selection" &&
appState.activeTool.type !== "lasso" &&
appState.activeTool.type !== "eraser" &&
appState.activeTool.type !== "hand" &&
appState.activeTool.type !== "laser"))) ||
getSelectedElements(elements, appState).length),
appState.openDialog?.name !== "elementLinkSelector" &&
((appState.activeTool.type !== "custom" &&
(appState.editingTextElement ||
(appState.activeTool.type !== "selection" &&
appState.activeTool.type !== "lasso" &&
appState.activeTool.type !== "eraser" &&
appState.activeTool.type !== "hand" &&
appState.activeTool.type !== "laser"))) ||
getSelectedElements(elements, appState).length),
);
+1 -1
View File
@@ -89,7 +89,7 @@ const CJK = {
* ↑ BREAK BEFORE "「"
* ↑ BREAK AFTER "」"
*/
// eslint-disable-next-line prettier/prettier
// prettier-ignore
OPENING:/([{〈《⦅「「『【〖〔〘〚<〝/u,
CLOSING: /)]}〉》⦆」」』】〗〕〙〛>。.,、〟‥?!:;・〜〞/u,
/**
+89 -92
View File
@@ -73,104 +73,101 @@ export type ValidLinearElement = {
textAlign?: TextAlign;
verticalAlign?: VerticalAlign;
} & MarkOptional<ElementConstructorOpts, "x" | "y">;
end?:
end?: (
| (
| (
| {
type: Exclude<
ExcalidrawBindableElement["type"],
| "image"
| "text"
| "frame"
| "magicframe"
| "embeddable"
| "iframe"
>;
id?: ExcalidrawGenericElement["id"];
}
| {
id: ExcalidrawGenericElement["id"];
type?: Exclude<
ExcalidrawBindableElement["type"],
| "image"
| "text"
| "frame"
| "magicframe"
| "embeddable"
| "iframe"
>;
}
)
| ((
| {
type: "text";
text: string;
}
| {
type?: "text";
id: ExcalidrawTextElement["id"];
text: string;
}
) &
Partial<ExcalidrawTextElement>)
| {
type: Exclude<
ExcalidrawBindableElement["type"],
| "image"
| "text"
| "frame"
| "magicframe"
| "embeddable"
| "iframe"
>;
id?: ExcalidrawGenericElement["id"];
}
| {
id: ExcalidrawGenericElement["id"];
type?: Exclude<
ExcalidrawBindableElement["type"],
| "image"
| "text"
| "frame"
| "magicframe"
| "embeddable"
| "iframe"
>;
}
)
| ((
| {
type: "text";
text: string;
}
| {
type?: "text";
id: ExcalidrawTextElement["id"];
text: string;
}
) &
MarkOptional<ElementConstructorOpts, "x" | "y">;
start?:
Partial<ExcalidrawTextElement>)
) &
MarkOptional<ElementConstructorOpts, "x" | "y">;
start?: (
| (
| (
| {
type: Exclude<
ExcalidrawBindableElement["type"],
| "image"
| "text"
| "frame"
| "magicframe"
| "embeddable"
| "iframe"
>;
id?: ExcalidrawGenericElement["id"];
}
| {
id: ExcalidrawGenericElement["id"];
type?: Exclude<
ExcalidrawBindableElement["type"],
| "image"
| "text"
| "frame"
| "magicframe"
| "embeddable"
| "iframe"
>;
}
)
| ((
| {
type: "text";
text: string;
}
| {
type?: "text";
id: ExcalidrawTextElement["id"];
text: string;
}
) &
Partial<ExcalidrawTextElement>)
| {
type: Exclude<
ExcalidrawBindableElement["type"],
| "image"
| "text"
| "frame"
| "magicframe"
| "embeddable"
| "iframe"
>;
id?: ExcalidrawGenericElement["id"];
}
| {
id: ExcalidrawGenericElement["id"];
type?: Exclude<
ExcalidrawBindableElement["type"],
| "image"
| "text"
| "frame"
| "magicframe"
| "embeddable"
| "iframe"
>;
}
)
| ((
| {
type: "text";
text: string;
}
| {
type?: "text";
id: ExcalidrawTextElement["id"];
text: string;
}
) &
MarkOptional<ElementConstructorOpts, "x" | "y">;
Partial<ExcalidrawTextElement>)
) &
MarkOptional<ElementConstructorOpts, "x" | "y">;
} & Partial<ExcalidrawLinearElement>;
export type ValidContainer =
| {
type: Exclude<ExcalidrawGenericElement["type"], "selection">;
id?: ExcalidrawGenericElement["id"];
label?: {
text: string;
fontSize?: number;
fontFamily?: FontFamilyValues;
textAlign?: TextAlign;
verticalAlign?: VerticalAlign;
} & MarkOptional<ElementConstructorOpts, "x" | "y">;
} & ElementConstructorOpts;
export type ValidContainer = {
type: Exclude<ExcalidrawGenericElement["type"], "selection">;
id?: ExcalidrawGenericElement["id"];
label?: {
text: string;
fontSize?: number;
fontFamily?: FontFamilyValues;
textAlign?: TextAlign;
verticalAlign?: VerticalAlign;
} & MarkOptional<ElementConstructorOpts, "x" | "y">;
} & ElementConstructorOpts;
export type ExcalidrawElementSkeleton =
| Extract<
+2 -2
View File
@@ -312,8 +312,8 @@ export const getTransformHandles = (
const margin = isLinearElement(element)
? DEFAULT_TRANSFORM_HANDLE_SPACING + 8
: isImageElement(element)
? 0
: DEFAULT_TRANSFORM_HANDLE_SPACING;
? 0
: DEFAULT_TRANSFORM_HANDLE_SPACING;
return getTransformHandlesFromCoords(
getElementAbsoluteCoords(element, elementsMap, true),
element.angle,
+12 -13
View File
@@ -18,18 +18,18 @@ import type {
export type ChartType = "bar" | "line";
export type FillStyle = "hachure" | "cross-hatch" | "solid" | "zigzag";
export type FontFamilyKeys = keyof typeof FONT_FAMILY;
export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys];
export type Theme = typeof THEME[keyof typeof THEME];
export type FontFamilyValues = (typeof FONT_FAMILY)[FontFamilyKeys];
export type Theme = (typeof THEME)[keyof typeof THEME];
export type FontString = string & { _brand: "fontString" };
export type GroupId = string;
export type PointerType = "mouse" | "pen" | "touch";
export type StrokeRoundness = "round" | "sharp";
export type RoundnessType = ValueOf<typeof ROUNDNESS>;
export type StrokeStyle = "solid" | "dashed" | "dotted";
export type TextAlign = typeof TEXT_ALIGN[keyof typeof TEXT_ALIGN];
export type TextAlign = (typeof TEXT_ALIGN)[keyof typeof TEXT_ALIGN];
type VerticalAlignKeys = keyof typeof VERTICAL_ALIGN;
export type VerticalAlign = typeof VERTICAL_ALIGN[VerticalAlignKeys];
export type VerticalAlign = (typeof VERTICAL_ALIGN)[VerticalAlignKeys];
export type FractionalIndex = string & { _brand: "franctionalIndex" };
export type BoundElement = Readonly<{
@@ -124,15 +124,14 @@ export type ExcalidrawIframeLikeElement =
| ExcalidrawIframeElement
| ExcalidrawEmbeddableElement;
export type IframeData =
| {
intrinsicSize: { w: number; h: number };
error?: Error;
sandbox?: { allowSameOrigin?: boolean };
} & (
| { type: "video" | "generic"; link: string }
| { type: "document"; srcdoc: (theme: Theme) => string }
);
export type IframeData = {
intrinsicSize: { w: number; h: number };
error?: Error;
sandbox?: { allowSameOrigin?: boolean };
} & (
| { type: "video" | "generic"; link: string }
| { type: "document"; srcdoc: (theme: Theme) => string }
);
export type ImageCrop = {
x: number;
+2 -1
View File
@@ -252,6 +252,7 @@ const addToCurrentFrame = (element: DebugElement) => {
if (window.visualDebug?.data && window.visualDebug.data.length === 0) {
window.visualDebug.data[0] = [];
}
window.visualDebug?.data &&
if (window.visualDebug?.data) {
window.visualDebug.data[window.visualDebug.data.length - 1].push(element);
}
};
+1 -1
View File
@@ -335,7 +335,7 @@ const shiftElementsByOne = (
.map((idx) => elements[idx].id),
);
groupedIndices.forEach((indices, i) => {
groupedIndices.forEach((indices) => {
const leadingIndex = indices[0];
const trailingIndex = indices[indices.length - 1];
const boundaryIndex = direction === "left" ? leadingIndex : trailingIndex;
+1 -1
View File
@@ -37,7 +37,7 @@ const _ce = ({
width: w,
height: h,
angle: a,
} as ExcalidrawElement);
}) as ExcalidrawElement;
describe("getElementAbsoluteCoords", () => {
it("test x1 coordinate", () => {
+1 -1
View File
@@ -24,7 +24,7 @@ describe("Test measureText", () => {
...params,
});
expect(getContainerCoords(element)).toEqual({
x: 44.2893218813452455,
x: 44.289321881345245,
y: 39.64466094067262,
});
});