chore: release @excalidraw/excalidraw@18.0.0 🎉 (#9127)

This commit is contained in:
Marcel Mraz 2025-02-28 16:49:09 +01:00 committed by GitHub
parent 392118bf26
commit ecef5d12f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
232 changed files with 3412 additions and 2851 deletions

View file

@ -236,8 +236,8 @@ import {
getElementShape,
isPathALoop,
} from "../shapes";
import { getSelectionBoxShape } from "../../utils/geometry/shape";
import { isPointInShape } from "../../utils/collision";
import { getSelectionBoxShape } from "@excalidraw/utils/geometry/shape";
import { isPointInShape } from "@excalidraw/utils/collision";
import type {
AppClassProperties,
AppProps,
@ -412,7 +412,7 @@ import { COLOR_PALETTE } from "../colors";
import { ElementCanvasButton } from "./MagicButton";
import { MagicIcon, copyIcon, fullscreenIcon } from "./icons";
import FollowMode from "./FollowMode/FollowMode";
import { Store, StoreAction } from "../store";
import { Store, CaptureUpdateAction } from "../store";
import { AnimationFrameHandler } from "../animation-frame-handler";
import { AnimatedTrail } from "../animated-trail";
import { LaserTrails } from "../laser-trails";
@ -441,7 +441,7 @@ import {
getLinkDirectionFromKey,
} from "../element/flowchart";
import { searchItemInFocusAtom } from "./SearchMenu";
import type { LocalPoint, Radians } from "../../math";
import type { LocalPoint, Radians } from "@excalidraw/math";
import {
clamp,
pointFrom,
@ -453,7 +453,7 @@ import {
vectorSubtract,
vectorDot,
vectorNormalize,
} from "../../math";
} from "@excalidraw/math";
import { cropElement } from "../element/cropElement";
import { wrapText } from "../element/textWrapping";
import { actionCopyElementLink } from "../actions/actionElementLink";
@ -2097,12 +2097,12 @@ class App extends React.Component<AppProps, AppState> {
if (shouldUpdateStrokeColor) {
this.syncActionResult({
appState: { ...this.state, currentItemStrokeColor: color },
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
} else {
this.syncActionResult({
appState: { ...this.state, currentItemBackgroundColor: color },
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
}
} else {
@ -2116,7 +2116,7 @@ class App extends React.Component<AppProps, AppState> {
}
return el;
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
}
},
@ -2137,9 +2137,9 @@ class App extends React.Component<AppProps, AppState> {
return;
}
if (actionResult.storeAction === StoreAction.UPDATE) {
if (actionResult.captureUpdate === CaptureUpdateAction.NEVER) {
this.store.shouldUpdateSnapshot();
} else if (actionResult.storeAction === StoreAction.CAPTURE) {
} else if (actionResult.captureUpdate === CaptureUpdateAction.IMMEDIATELY) {
this.store.shouldCaptureIncrement();
}
@ -2214,7 +2214,10 @@ class App extends React.Component<AppProps, AppState> {
didUpdate = true;
}
if (!didUpdate && actionResult.storeAction !== StoreAction.NONE) {
if (
!didUpdate &&
actionResult.captureUpdate !== CaptureUpdateAction.EVENTUALLY
) {
this.scene.triggerUpdate();
}
});
@ -2342,7 +2345,7 @@ class App extends React.Component<AppProps, AppState> {
this.resetHistory();
this.syncActionResult({
...scene,
storeAction: StoreAction.UPDATE,
captureUpdate: CaptureUpdateAction.NEVER,
});
// clear the shape and image cache so that any images in initialData
@ -2822,7 +2825,7 @@ class App extends React.Component<AppProps, AppState> {
this.state.editingLinearElement &&
!this.state.selectedElementIds[this.state.editingLinearElement.elementId]
) {
// defer so that the storeAction flag isn't reset via current update
// defer so that the shouldCaptureIncrement flag isn't reset via current update
setTimeout(() => {
// execute only if the condition still holds when the deferred callback
// executes (it can be scheduled multiple times depending on how
@ -3883,12 +3886,25 @@ class App extends React.Component<AppProps, AppState> {
elements?: SceneData["elements"];
appState?: Pick<AppState, K> | null;
collaborators?: SceneData["collaborators"];
/** @default StoreAction.NONE */
storeAction?: SceneData["storeAction"];
/**
* Controls which updates should be captured by the `Store`. Captured updates are emmitted and listened to by other components, such as `History` for undo / redo purposes.
*
* - `CaptureUpdateAction.IMMEDIATELY`: Updates are immediately undoable. Use for most local updates.
* - `CaptureUpdateAction.NEVER`: Updates never make it to undo/redo stack. Use for remote updates or scene initialization.
* - `CaptureUpdateAction.EVENTUALLY`: Updates will be eventually be captured as part of a future increment.
*
* Check [API docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/excalidraw-api#captureUpdate) for more details.
*
* @default CaptureUpdateAction.EVENTUALLY
*/
captureUpdate?: SceneData["captureUpdate"];
}) => {
const nextElements = syncInvalidIndices(sceneData.elements ?? []);
if (sceneData.storeAction && sceneData.storeAction !== StoreAction.NONE) {
if (
sceneData.captureUpdate &&
sceneData.captureUpdate !== CaptureUpdateAction.EVENTUALLY
) {
const prevCommittedAppState = this.store.snapshot.appState;
const prevCommittedElements = this.store.snapshot.elements;
@ -3905,12 +3921,12 @@ class App extends React.Component<AppProps, AppState> {
// WARN: store action always performs deep clone of changed elements, for ephemeral remote updates (i.e. remote dragging, resizing, drawing) we might consider doing something smarter
// do NOT schedule store actions (execute after re-render), as it might cause unexpected concurrency issues if not handled well
if (sceneData.storeAction === StoreAction.CAPTURE) {
if (sceneData.captureUpdate === CaptureUpdateAction.IMMEDIATELY) {
this.store.captureIncrement(
nextCommittedElements,
nextCommittedAppState,
);
} else if (sceneData.storeAction === StoreAction.UPDATE) {
} else if (sceneData.captureUpdate === CaptureUpdateAction.NEVER) {
this.store.updateSnapshot(
nextCommittedElements,
nextCommittedAppState,
@ -4590,7 +4606,9 @@ class App extends React.Component<AppProps, AppState> {
if (!event.altKey) {
if (this.flowChartNavigator.isExploring) {
this.flowChartNavigator.clear();
this.syncActionResult({ storeAction: StoreAction.CAPTURE });
this.syncActionResult({
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
}
}
@ -4637,7 +4655,9 @@ class App extends React.Component<AppProps, AppState> {
}
this.flowChartCreator.clear();
this.syncActionResult({ storeAction: StoreAction.CAPTURE });
this.syncActionResult({
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
}
}
});
@ -6376,10 +6396,10 @@ class App extends React.Component<AppProps, AppState> {
this.state,
),
},
storeAction:
captureUpdate:
this.state.openDialog?.name === "elementLinkSelector"
? StoreAction.NONE
: StoreAction.UPDATE,
? CaptureUpdateAction.EVENTUALLY
: CaptureUpdateAction.NEVER,
});
return;
}
@ -9042,7 +9062,7 @@ class App extends React.Component<AppProps, AppState> {
appState: {
newElement: null,
},
storeAction: StoreAction.UPDATE,
captureUpdate: CaptureUpdateAction.NEVER,
});
return;
@ -9212,7 +9232,7 @@ class App extends React.Component<AppProps, AppState> {
elements: this.scene
.getElementsIncludingDeleted()
.filter((el) => el.id !== resizingElement.id),
storeAction: StoreAction.UPDATE,
captureUpdate: CaptureUpdateAction.NEVER,
});
}
@ -10183,7 +10203,7 @@ class App extends React.Component<AppProps, AppState> {
isLoading: false,
},
replaceFiles: true,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
return;
} catch (error: any) {
@ -10312,7 +10332,7 @@ class App extends React.Component<AppProps, AppState> {
isLoading: false,
},
replaceFiles: true,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
} else if (ret.type === MIME_TYPES.excalidrawlib) {
await this.library

View file

@ -23,7 +23,7 @@ import { nativeFileSystemSupported } from "../data/filesystem";
import type { NonDeletedExcalidrawElement } from "../element/types";
import { t } from "../i18n";
import { isSomeElementSelected } from "../scene";
import { exportToCanvas } from "../../utils/export";
import { exportToCanvas } from "@excalidraw/utils/export";
import { copyIcon, downloadIcon, helpIcon } from "./icons";
import { Dialog } from "./Dialog";

View file

@ -1,12 +1,7 @@
import clsx from "clsx";
import React from "react";
import type { ActionManager } from "../actions/manager";
import {
CLASSES,
DEFAULT_SIDEBAR,
LIBRARY_SIDEBAR_WIDTH,
TOOL_TYPE,
} from "../constants";
import { CLASSES, DEFAULT_SIDEBAR, TOOL_TYPE } from "../constants";
import { showSelectedShapeActions } from "../element";
import type { NonDeletedExcalidrawElement } from "../element/types";
import type { Language } from "../i18n";
@ -531,7 +526,7 @@ const LayerUI = ({
appState.openSidebar &&
isSidebarDocked &&
device.editor.canFitSidebar
? { width: `calc(100% - ${LIBRARY_SIDEBAR_WIDTH}px)` }
? { width: `calc(100% - var(--right-sidebar-width)px)` }
: {}
}
>

View file

@ -7,7 +7,7 @@ import { t } from "../i18n";
import Trans from "./Trans";
import type { LibraryItems, LibraryItem, UIAppState } from "../types";
import { exportToCanvas, exportToSvg } from "../../utils/export";
import { exportToCanvas, exportToSvg } from "@excalidraw/utils/export";
import {
EDITOR_LS_KEYS,
EXPORT_DATA_TYPES,

View file

@ -3,7 +3,7 @@ import { collapseDownIcon, upIcon, searchIcon } from "./icons";
import { TextField } from "./TextField";
import { Button } from "./Button";
import { useApp, useExcalidrawSetAppState } from "./App";
import { debounce } from "lodash";
import debounce from "lodash.debounce";
import type { AppClassProperties } from "../types";
import { isTextElement, newTextElement } from "../element";
import type { ExcalidrawTextElement } from "../element/types";
@ -18,7 +18,7 @@ import { CLASSES, EVENT } from "../constants";
import { useStable } from "../hooks/useStable";
import "./SearchMenu.scss";
import { round } from "../../math";
import { round } from "@excalidraw/math";
import { measureText } from "../element/textMeasurements";
const searchQueryAtom = atom<string>("");

View file

@ -30,7 +30,7 @@
overflow: hidden;
border-radius: 0;
width: calc(#{$right-sidebar-width} - var(--space-factor) * 2);
width: calc(var(--right-sidebar-width) - var(--space-factor) * 2);
border-left: 1px solid var(--sidebar-border-color);

View file

@ -136,6 +136,9 @@ export const SidebarInner = forwardRef(
<Island
{...rest}
className={clsx("sidebar", { "sidebar--docked": docked }, className)}
style={{
"--right-sidebar-width": "302px",
}}
ref={islandRef}
>
<SidebarPropsContext.Provider value={headerPropsRef.current}>

View file

@ -8,8 +8,8 @@ import type { DragInputCallbackType } from "./DragInput";
import { getStepSizedValue, isPropertyEditable, updateBindings } from "./utils";
import type Scene from "../../scene/Scene";
import type { AppState } from "../../types";
import type { Degrees } from "../../../math";
import { degreesToRadians, radiansToDegrees } from "../../../math";
import type { Degrees } from "@excalidraw/math";
import { degreesToRadians, radiansToDegrees } from "@excalidraw/math";
interface AngleProps {
element: ExcalidrawElement;

View file

@ -12,7 +12,7 @@ import {
getUncroppedWidthAndHeight,
} from "../../element/cropElement";
import { mutateElement } from "../../element/mutateElement";
import { clamp, round } from "../../../math";
import { clamp, round } from "@excalidraw/math";
interface DimensionDragInputProps {
property: "width" | "height";

View file

@ -8,7 +8,7 @@ import { useApp } from "../App";
import { InlineIcon } from "../InlineIcon";
import type { StatsInputProperty } from "./utils";
import { SMALLEST_DELTA } from "./utils";
import { StoreAction } from "../../store";
import { CaptureUpdateAction } from "../../store";
import type Scene from "../../scene/Scene";
import "./DragInput.scss";
@ -132,7 +132,9 @@ const StatsDragInput = <
originalAppState: appState,
setInputValue: (value) => setInputValue(String(value)),
});
app.syncActionResult({ storeAction: StoreAction.CAPTURE });
app.syncActionResult({
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
}
};
@ -276,7 +278,9 @@ const StatsDragInput = <
false,
);
app.syncActionResult({ storeAction: StoreAction.CAPTURE });
app.syncActionResult({
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
lastPointer = null;
accumulatedChange = 0;

View file

@ -9,8 +9,8 @@ import DragInput from "./DragInput";
import type { DragInputCallbackType } from "./DragInput";
import { getStepSizedValue, isPropertyEditable } from "./utils";
import type { AppState } from "../../types";
import type { Degrees } from "../../../math";
import { degreesToRadians, radiansToDegrees } from "../../../math";
import type { Degrees } from "@excalidraw/math";
import { degreesToRadians, radiansToDegrees } from "@excalidraw/math";
interface MultiAngleProps {
elements: readonly ExcalidrawElement[];

View file

@ -23,7 +23,7 @@ import { getAtomicUnits, getStepSizedValue, isPropertyEditable } from "./utils";
import { getElementsInAtomicUnit } from "./utils";
import type { AtomicUnit } from "./utils";
import { MIN_WIDTH_OR_HEIGHT } from "../../constants";
import { pointFrom, type GlobalPoint } from "../../../math";
import { pointFrom, type GlobalPoint } from "@excalidraw/math";
interface MultiDimensionProps {
property: "width" | "height";

View file

@ -13,7 +13,7 @@ import { useMemo } from "react";
import { getElementsInAtomicUnit, moveElement } from "./utils";
import type { AtomicUnit } from "./utils";
import type { AppState } from "../../types";
import { pointFrom, pointRotateRads } from "../../../math";
import { pointFrom, pointRotateRads } from "@excalidraw/math";
interface MultiPositionProps {
property: "x" | "y";

View file

@ -4,7 +4,7 @@ import type { DragInputCallbackType } from "./DragInput";
import { getStepSizedValue, moveElement } from "./utils";
import type Scene from "../../scene/Scene";
import type { AppState } from "../../types";
import { clamp, pointFrom, pointRotateRads, round } from "../../../math";
import { clamp, pointFrom, pointRotateRads, round } from "@excalidraw/math";
import { isImageElement } from "../../element/typeChecks";
import {
getFlipAdjustedCropPosition,

View file

@ -9,7 +9,7 @@ import type {
} from "../../types";
import { CloseIcon } from "../icons";
import { Island } from "../Island";
import { throttle } from "lodash";
import throttle from "lodash.throttle";
import Dimension from "./Dimension";
import Angle from "./Angle";
import FontSize from "./FontSize";
@ -30,7 +30,7 @@ import clsx from "clsx";
import "./Stats.scss";
import { isGridModeEnabled } from "../../snapping";
import { getUncroppedWidthAndHeight } from "../../element/cropElement";
import { round } from "../../../math";
import { round } from "@excalidraw/math";
import { frameAndChildrenSelectedTogether } from "../../frame";
interface StatsProps {

View file

@ -24,8 +24,8 @@ import { getCommonBounds, isTextElement } from "../../element";
import { API } from "../../tests/helpers/api";
import { actionGroup } from "../../actions";
import { isInGroup } from "../../groups";
import type { Degrees } from "../../../math";
import { degreesToRadians, pointFrom, pointRotateRads } from "../../../math";
import type { Degrees } from "@excalidraw/math";
import { degreesToRadians, pointFrom, pointRotateRads } from "@excalidraw/math";
const { h } = window;
const mouse = new Pointer("mouse");

View file

@ -1,5 +1,5 @@
import type { Radians } from "../../../math";
import { pointFrom, pointRotateRads } from "../../../math";
import type { Radians } from "@excalidraw/math";
import { pointFrom, pointRotateRads } from "@excalidraw/math";
import {
bindOrUnbindLinearElements,
updateBoundElements,

View file

@ -29,7 +29,7 @@ import { atom, useAtom } from "../../editor-jotai";
import { trackEvent } from "../../analytics";
import { InlineIcon } from "../InlineIcon";
import { TTDDialogSubmitShortcut } from "./TTDDialogSubmitShortcut";
import { isFiniteNumber } from "../../../math";
import { isFiniteNumber } from "@excalidraw/math";
const MIN_PROMPT_LENGTH = 3;
const MAX_PROMPT_LENGTH = 1000;

View file

@ -34,7 +34,7 @@ import { trackEvent } from "../../analytics";
import { useAppProps, useDevice, useExcalidrawAppState } from "../App";
import { isEmbeddableElement } from "../../element/typeChecks";
import { getLinkHandleFromCoords } from "./helpers";
import { pointFrom, type GlobalPoint } from "../../../math";
import { pointFrom, type GlobalPoint } from "@excalidraw/math";
import { isElementLink } from "../../element/elementLink";
import "./Hyperlink.scss";

View file

@ -1,5 +1,5 @@
import type { GlobalPoint, Radians } from "../../../math";
import { pointFrom, pointRotateRads } from "../../../math";
import type { GlobalPoint, Radians } from "@excalidraw/math";
import { pointFrom, pointRotateRads } from "@excalidraw/math";
import { MIME_TYPES } from "../../constants";
import type { Bounds } from "../../element/bounds";
import { getElementAbsoluteCoords } from "../../element/bounds";