diff --git a/packages/common/src/points.ts b/packages/common/src/points.ts index 9d48857db..e8f988203 100644 --- a/packages/common/src/points.ts +++ b/packages/common/src/points.ts @@ -4,6 +4,8 @@ import { type LocalPoint, } from "@excalidraw/math"; +import type { NullableGridSize } from "@excalidraw/excalidraw/types"; + export const getSizeFromPoints = ( points: readonly (GlobalPoint | LocalPoint)[], ) => { @@ -61,3 +63,18 @@ export const rescalePoints = ( return nextPoints; }; + +// TODO: Rounding this point causes some shake when free drawing +export const getGridPoint = ( + x: number, + y: number, + gridSize: NullableGridSize, +): [number, number] => { + if (gridSize) { + return [ + Math.round(x / gridSize) * gridSize, + Math.round(y / gridSize) * gridSize, + ]; + } + return [x, y]; +}; diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts index 177dc26b6..292b026fe 100644 --- a/packages/common/src/utils.ts +++ b/packages/common/src/utils.ts @@ -1206,59 +1206,3 @@ export const escapeDoubleQuotes = (str: string) => { export const castArray = (value: T | T[]): T[] => Array.isArray(value) ? value : [value]; - -// TODO_SEP: perhaps could be refactored away - -// TODO: Rounding this point causes some shake when free drawing -export const getGridPoint = ( - x: number, - y: number, - gridSize: NullableGridSize, -): [number, number] => { - if (gridSize) { - return [ - Math.round(x / gridSize) * gridSize, - Math.round(y / gridSize) * gridSize, - ]; - } - return [x, y]; -}; - -export const elementsAreInSameGroup = ( - elements: readonly ExcalidrawElement[], -) => { - const allGroups = elements.flatMap((element) => element.groupIds); - const groupCount = new Map(); - let maxGroup = 0; - - for (const group of allGroups) { - groupCount.set(group, (groupCount.get(group) ?? 0) + 1); - if (groupCount.get(group)! > maxGroup) { - maxGroup = groupCount.get(group)!; - } - } - - return maxGroup === elements.length; -}; - -export const isInGroup = (element: NonDeletedExcalidrawElement) => { - return element.groupIds.length > 0; -}; - -export const getNewGroupIdsForDuplication = ( - groupIds: ExcalidrawElement["groupIds"], - editingGroupId: AppState["editingGroupId"], - mapper: (groupId: GroupId) => GroupId, -) => { - const copy = [...groupIds]; - const positionOfEditingGroupId = editingGroupId - ? groupIds.indexOf(editingGroupId) - : -1; - const endIndex = - positionOfEditingGroupId > -1 ? positionOfEditingGroupId : groupIds.length; - for (let index = 0; index < endIndex; index++) { - copy[index] = mapper(copy[index]); - } - - return copy; -}; diff --git a/packages/element/src/fractionalIndex.ts b/packages/element/src/fractionalIndex.ts index 081368266..c2d7b93ab 100644 --- a/packages/element/src/fractionalIndex.ts +++ b/packages/element/src/fractionalIndex.ts @@ -12,7 +12,9 @@ import type { OrderedExcalidrawElement, } from "@excalidraw/element/types"; -import { InvalidFractionalIndexError } from "../../excalidraw/errors"; +export class InvalidFractionalIndexError extends Error { + public code = "ELEMENT_HAS_INVALID_INDEX" as const; +} /** * Envisioned relation between array order and fractional indices: diff --git a/packages/element/src/frame.ts b/packages/element/src/frame.ts index 93db14823..de138f6a8 100644 --- a/packages/element/src/frame.ts +++ b/packages/element/src/frame.ts @@ -5,11 +5,6 @@ import { elementsOverlappingBBox, } from "@excalidraw/utils"; -import { - getElementsWithinSelection, - getSelectedElements, -} from "@excalidraw/excalidraw/scene"; - import { getElementAbsoluteCoords, isTextElement } from "@excalidraw/element"; import type { @@ -31,6 +26,7 @@ import type { import type { ReadonlySetLike } from "@excalidraw/common/utility-types"; +import { getElementsWithinSelection, getSelectedElements } from "./selection"; import { getElementsInGroup, selectGroupsFromGivenElements } from "./groups"; import { getElementLineSegments, getCommonBounds } from "./bounds"; diff --git a/packages/element/src/groups.ts b/packages/element/src/groups.ts index ffa8dfcfd..ce95f1e29 100644 --- a/packages/element/src/groups.ts +++ b/packages/element/src/groups.ts @@ -1,8 +1,5 @@ import { getBoundTextElement } from "@excalidraw/element/textElement"; -import { getSelectedElements } from "@excalidraw/excalidraw/scene"; -import { makeNextSelectedElementIds } from "@excalidraw/excalidraw/scene/selection"; - import type { GroupId, ExcalidrawElement, @@ -19,6 +16,8 @@ import type { } from "@excalidraw/excalidraw/types"; import type { Mutable } from "@excalidraw/common/utility-types"; +import { makeNextSelectedElementIds, getSelectedElements } from "./selection"; + export const selectGroup = ( groupId: GroupId, appState: InteractiveCanvasAppState, diff --git a/packages/element/src/resizeElements.ts b/packages/element/src/resizeElements.ts index 24d851c4c..3ff405603 100644 --- a/packages/element/src/resizeElements.ts +++ b/packages/element/src/resizeElements.ts @@ -11,7 +11,6 @@ import { import { MIN_FONT_SIZE, SHIFT_LOCKING_ANGLE, - isInGroup, rescalePoints, getFontString, } from "@excalidraw/common"; @@ -59,6 +58,8 @@ import { isTextElement, } from "./typeChecks"; +import { isInGroup } from "./groups"; + import type { BoundingBox } from "./bounds"; import type { MaybeTransformHandleType, diff --git a/packages/excalidraw/scene/selection.ts b/packages/element/src/selection.ts similarity index 94% rename from packages/excalidraw/scene/selection.ts rename to packages/element/src/selection.ts index 48fd5eff1..c582c32e8 100644 --- a/packages/excalidraw/scene/selection.ts +++ b/packages/element/src/selection.ts @@ -1,17 +1,3 @@ -import { - getElementAbsoluteCoords, - getElementBounds, -} from "@excalidraw/element/bounds"; -import { isElementInViewport } from "@excalidraw/element/sizeHelpers"; -import { - isBoundToContainer, - isFrameLikeElement, -} from "@excalidraw/element/typeChecks"; -import { - elementOverlapsWithFrame, - getContainingFrame, - getFrameChildren, -} from "@excalidraw/element/frame"; import { isShallowEqual } from "@excalidraw/common"; import type { @@ -21,7 +7,19 @@ import type { NonDeletedExcalidrawElement, } from "@excalidraw/element/types"; -import type { AppState, InteractiveCanvasAppState } from "../types"; +import type { + AppState, + InteractiveCanvasAppState, +} from "@excalidraw/excalidraw/types"; + +import { getElementAbsoluteCoords, getElementBounds } from "./bounds"; +import { isElementInViewport } from "./sizeHelpers"; +import { isBoundToContainer, isFrameLikeElement } from "./typeChecks"; +import { + elementOverlapsWithFrame, + getContainingFrame, + getFrameChildren, +} from "./frame"; /** * Frames and their containing elements are not to be selected at the same time. diff --git a/packages/element/src/showSelectedShapeActions.ts b/packages/element/src/showSelectedShapeActions.ts index 32e9d4c76..efcf83894 100644 --- a/packages/element/src/showSelectedShapeActions.ts +++ b/packages/element/src/showSelectedShapeActions.ts @@ -1,7 +1,7 @@ -import { getSelectedElements } from "@excalidraw/excalidraw/scene"; - import type { UIAppState } from "@excalidraw/excalidraw/types"; +import { getSelectedElements } from "./selection"; + import type { NonDeletedExcalidrawElement } from "./types"; export const showSelectedShapeActions = ( diff --git a/packages/excalidraw/scene/selection.test.ts b/packages/element/tests/selection.test.ts similarity index 95% rename from packages/excalidraw/scene/selection.test.ts rename to packages/element/tests/selection.test.ts index 644d2129f..fbcdb2693 100644 --- a/packages/excalidraw/scene/selection.test.ts +++ b/packages/element/tests/selection.test.ts @@ -1,4 +1,4 @@ -import { makeNextSelectedElementIds } from "./selection"; +import { makeNextSelectedElementIds } from "../src/selection"; describe("makeNextSelectedElementIds", () => { const _makeNextSelectedElementIds = ( diff --git a/packages/excalidraw/actions/actionDuplicateSelection.tsx b/packages/excalidraw/actions/actionDuplicateSelection.tsx index 7aedef1fb..3584ff7d6 100644 --- a/packages/excalidraw/actions/actionDuplicateSelection.tsx +++ b/packages/excalidraw/actions/actionDuplicateSelection.tsx @@ -39,6 +39,11 @@ import { getElementsInGroup, } from "@excalidraw/element/groups"; +import { + excludeElementsInFramesFromSelection, + getSelectedElements, +} from "@excalidraw/element/selection"; + import type { ExcalidrawElement } from "@excalidraw/element/types"; import { ToolButton } from "../components/ToolButton"; @@ -46,10 +51,6 @@ import { DuplicateIcon } from "../components/icons"; import { t } from "../i18n"; import { isSomeElementSelected } from "../scene"; -import { - excludeElementsInFramesFromSelection, - getSelectedElements, -} from "../scene/selection"; import { CaptureUpdateAction } from "../store"; import { register } from "./register"; diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 1ce4d678d..16fb4ba06 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -289,6 +289,11 @@ import { syncMovedIndices, } from "@excalidraw/element/fractionalIndex"; +import { + excludeElementsInFramesFromSelection, + makeNextSelectedElementIds, +} from "@excalidraw/element/selection"; + import type { LocalPoint, Radians } from "@excalidraw/math"; import type { @@ -420,10 +425,6 @@ import { import { Fonts } from "../fonts"; import { getLineHeight } from "../fonts/FontMetadata"; -import { - excludeElementsInFramesFromSelection, - makeNextSelectedElementIds, -} from "../scene/selection"; import { editorJotaiStore } from "../editor-jotai"; import { ImageSceneDataError } from "../errors"; import { diff --git a/packages/excalidraw/components/Stats/MultiAngle.tsx b/packages/excalidraw/components/Stats/MultiAngle.tsx index e90167cd8..3cabd19c0 100644 --- a/packages/excalidraw/components/Stats/MultiAngle.tsx +++ b/packages/excalidraw/components/Stats/MultiAngle.tsx @@ -1,5 +1,3 @@ -import { isInGroup } from "@excalidraw/common"; - import { degreesToRadians, radiansToDegrees } from "@excalidraw/math"; import { mutateElement } from "@excalidraw/element/mutateElement"; @@ -7,6 +5,8 @@ import { mutateElement } from "@excalidraw/element/mutateElement"; import { getBoundTextElement } from "@excalidraw/element/textElement"; import { isArrowElement } from "@excalidraw/element/typeChecks"; +import { isInGroup } from "@excalidraw/element/groups"; + import type { Degrees } from "@excalidraw/math"; import type { ExcalidrawElement } from "@excalidraw/element/types"; diff --git a/packages/excalidraw/components/Stats/MultiFontSize.tsx b/packages/excalidraw/components/Stats/MultiFontSize.tsx index e5a541fb7..0ad90bb2f 100644 --- a/packages/excalidraw/components/Stats/MultiFontSize.tsx +++ b/packages/excalidraw/components/Stats/MultiFontSize.tsx @@ -1,10 +1,10 @@ -import { isInGroup } from "@excalidraw/common"; - import { isTextElement, redrawTextBoundingBox } from "@excalidraw/element"; import { mutateElement } from "@excalidraw/element/mutateElement"; import { getBoundTextElement } from "@excalidraw/element/textElement"; import { hasBoundTextElement } from "@excalidraw/element/typeChecks"; +import { isInGroup } from "@excalidraw/element/groups"; + import type { ExcalidrawElement, ExcalidrawTextElement, diff --git a/packages/excalidraw/components/Stats/stats.test.tsx b/packages/excalidraw/components/Stats/stats.test.tsx index 76446a5cf..722b16469 100644 --- a/packages/excalidraw/components/Stats/stats.test.tsx +++ b/packages/excalidraw/components/Stats/stats.test.tsx @@ -5,7 +5,9 @@ import { vi } from "vitest"; import { getCommonBounds, isTextElement } from "@excalidraw/element"; -import { setDateTimeForTests, isInGroup, reseed } from "@excalidraw/common"; +import { setDateTimeForTests, reseed } from "@excalidraw/common"; + +import { isInGroup } from "@excalidraw/element/groups"; import type { Degrees } from "@excalidraw/math"; diff --git a/packages/excalidraw/components/Stats/utils.ts b/packages/excalidraw/components/Stats/utils.ts index d7e050ac7..dbb47a234 100644 --- a/packages/excalidraw/components/Stats/utils.ts +++ b/packages/excalidraw/components/Stats/utils.ts @@ -1,4 +1,3 @@ -import { isInGroup } from "@excalidraw/common"; import { pointFrom, pointRotateRads } from "@excalidraw/math"; import { @@ -16,6 +15,7 @@ import { import { getSelectedGroupIds, getElementsInGroup, + isInGroup, } from "@excalidraw/element/groups"; import type { Radians } from "@excalidraw/math"; diff --git a/packages/excalidraw/errors.ts b/packages/excalidraw/errors.ts index d6091b0e9..20fe694cd 100644 --- a/packages/excalidraw/errors.ts +++ b/packages/excalidraw/errors.ts @@ -33,10 +33,6 @@ export class ImageSceneDataError extends Error { } } -export class InvalidFractionalIndexError extends Error { - public code = "ELEMENT_HAS_INVALID_INDEX" as const; -} - type WorkerErrorCodes = "WORKER_URL_NOT_DEFINED" | "WORKER_IN_THE_MAIN_CHUNK"; export class WorkerUrlNotDefinedError extends Error { diff --git a/packages/excalidraw/scene/Scene.ts b/packages/excalidraw/scene/Scene.ts index dc35ecf7d..32a403757 100644 --- a/packages/excalidraw/scene/Scene.ts +++ b/packages/excalidraw/scene/Scene.ts @@ -17,6 +17,8 @@ import { validateFractionalIndices, } from "@excalidraw/element/fractionalIndex"; +import { getSelectedElements } from "@excalidraw/element/selection"; + import type { LinearElementEditor } from "@excalidraw/element/linearElementEditor"; import type { ExcalidrawElement, @@ -32,8 +34,6 @@ import type { import type { Assert, SameType } from "@excalidraw/common/utility-types"; -import { getSelectedElements } from "./selection"; - import type { AppState } from "../types"; type ElementIdKey = InstanceType["elementId"]; diff --git a/packages/excalidraw/scene/index.ts b/packages/excalidraw/scene/index.ts index 3819d3ab4..6f39a7fe2 100644 --- a/packages/excalidraw/scene/index.ts +++ b/packages/excalidraw/scene/index.ts @@ -4,7 +4,7 @@ export { getCommonAttributeOfSelectedElements, getSelectedElements, getTargetElements, -} from "./selection"; +} from "@excalidraw/element/selection"; export { calculateScrollCenter } from "./scroll"; export { hasBackground, diff --git a/packages/excalidraw/snapping.ts b/packages/excalidraw/snapping.ts index 042be5bbf..6ea23bd87 100644 --- a/packages/excalidraw/snapping.ts +++ b/packages/excalidraw/snapping.ts @@ -20,6 +20,11 @@ import { import { getMaximumGroups } from "@excalidraw/element/groups"; +import { + getSelectedElements, + getVisibleAndNonSelectedElements, +} from "@excalidraw/element/selection"; + import type { InclusiveRange } from "@excalidraw/math"; import type { Bounds } from "@excalidraw/element/bounds"; @@ -30,11 +35,6 @@ import type { NonDeletedExcalidrawElement, } from "@excalidraw/element/types"; -import { - getSelectedElements, - getVisibleAndNonSelectedElements, -} from "./scene/selection"; - import type { AppClassProperties, AppState,