@tldraw/editor 4.3.0-next.2b3bfbba757b → 4.3.0-next.2d181ae353a2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +55 -35
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/editor/Editor.js +1 -12
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/BaseBoxShapeUtil.js.map +1 -1
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/globals/menus.js +1 -1
- package/dist-cjs/lib/globals/menus.js.map +2 -2
- package/dist-cjs/lib/utils/reparenting.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +55 -35
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/editor/Editor.mjs +1 -12
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/BaseBoxShapeUtil.mjs.map +1 -1
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/globals/menus.mjs +1 -1
- package/dist-esm/lib/globals/menus.mjs.map +2 -2
- package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +10 -10
- package/src/lib/editor/Editor.test.ts +10 -10
- package/src/lib/editor/Editor.ts +82 -59
- package/src/lib/editor/bindings/BindingUtil.ts +15 -9
- package/src/lib/editor/derivations/bindingsIndex.ts +2 -2
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +14 -4
- package/src/lib/editor/managers/SnapManager/SnapManager.ts +3 -3
- package/src/lib/editor/shapes/BaseBoxShapeUtil.tsx +2 -2
- package/src/lib/editor/shapes/ShapeUtil.ts +5 -8
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -3
- package/src/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.ts +2 -1
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +3 -3
- package/src/lib/exports/getSvgJsx.test.ts +10 -19
- package/src/lib/exports/getSvgJsx.tsx +2 -5
- package/src/lib/globals/menus.ts +1 -1
- package/src/lib/utils/reparenting.ts +5 -5
- package/src/version.ts +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/reparenting.ts"],
|
|
4
|
-
"sourcesContent": ["import { EMPTY_ARRAY } from '@tldraw/state'\nimport { TLGroupShape, TLParentId, TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { IndexKey, compact, getIndexAbove, getIndexBetween } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\nimport { intersectPolygonPolygon } from '../primitives/intersect'\n\n/**\n * Reparents shapes that are no longer contained within their parent shapes.\n * todo: rename me to something more descriptive, like `reparentOccludedShapes` or `reparentAutoDroppedShapes`\n *\n * @param editor - The editor instance.\n * @param shapeIds - The IDs of the shapes to reparent.\n * @param opts - Optional options, including a callback to filter out certain parents, such as when removing a frame.\n *\n * @public\n */\nexport function kickoutOccludedShapes(\n\teditor: Editor,\n\tshapeIds: TLShapeId[],\n\topts?: { filter?(parent: TLShape): boolean }\n) {\n\tconst parentsToCheck = new Set<TLShape>()\n\n\tfor (const id of shapeIds) {\n\t\tconst shape = editor.getShape(id)\n\n\t\tif (!shape) continue\n\t\tparentsToCheck.add(shape)\n\n\t\tconst parent = editor.getShape(shape.parentId)\n\t\tif (!parent) continue\n\t\tparentsToCheck.add(parent)\n\t}\n\n\t// Check all of the parents and gather up parents who have lost children\n\tconst parentsToLostChildren = new Map<TLShape, TLShapeId[]>()\n\n\tfor (const parent of parentsToCheck) {\n\t\tconst childIds = editor.getSortedChildIdsForParent(parent)\n\t\tif (opts?.filter && !opts.filter(parent)) {\n\t\t\t// If the shape is filtered out, we kick out all of its children\n\t\t\tparentsToLostChildren.set(parent, childIds)\n\t\t} else {\n\t\t\tconst overlappingChildren = getOverlappingShapes(editor, parent.id, childIds)\n\t\t\tif (overlappingChildren.length < childIds.length) {\n\t\t\t\tparentsToLostChildren.set(\n\t\t\t\t\tparent,\n\t\t\t\t\tchildIds.filter((id) => !overlappingChildren.includes(id))\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Get all of the shapes on the current page, sorted by their index\n\tconst sortedShapeIds = editor.getCurrentPageShapesSorted().map((s) => s.id)\n\n\tconst parentsToNewChildren: Record<\n\t\tTLParentId,\n\t\t{ parentId: TLParentId; shapeIds: TLShapeId[]; index?: IndexKey }\n\t> = {}\n\n\tfor (const [prevParent, lostChildrenIds] of parentsToLostChildren) {\n\t\tconst lostChildren = compact(lostChildrenIds.map((id) => editor.getShape(id)))\n\n\t\t// Don't fall \"up\" into frames in front of the shape\n\t\t// if (pageShapes.indexOf(shape) < frameSortPosition) continue shapeCheck\n\n\t\t// Otherwise, we have no next dropping shape under the cursor, so go find\n\t\t// all the frames on the page where the moving shapes will fall into\n\t\tconst { reparenting, remainingShapesToReparent } = getDroppedShapesToNewParents(\n\t\t\teditor,\n\t\t\tlostChildren,\n\t\t\t(shape, maybeNewParent) => {\n\t\t\t\t// If we're filtering out a potential parent, don't reparent shapes to the filtered out shape\n\t\t\t\tif (opts?.filter && !opts.filter(maybeNewParent)) return false\n\t\t\t\treturn (\n\t\t\t\t\tmaybeNewParent.id !== prevParent.id &&\n\t\t\t\t\tsortedShapeIds.indexOf(maybeNewParent.id) < sortedShapeIds.indexOf(shape.id)\n\t\t\t\t)\n\t\t\t}\n\t\t)\n\n\t\treparenting.forEach((childrenToReparent, newParentId) => {\n\t\t\tif (childrenToReparent.length === 0) return\n\t\t\tif (!parentsToNewChildren[newParentId]) {\n\t\t\t\tparentsToNewChildren[newParentId] = {\n\t\t\t\t\tparentId: newParentId,\n\t\t\t\t\tshapeIds: [],\n\t\t\t\t}\n\t\t\t}\n\t\t\tparentsToNewChildren[newParentId].shapeIds.push(...childrenToReparent.map((s) => s.id))\n\t\t})\n\n\t\t// Reparent the rest to the page (or containing group)\n\t\tif (remainingShapesToReparent.size > 0) {\n\t\t\t// The remaining shapes are going to be reparented to the old parent's containing group, if there was one, or else to the page\n\t\t\tconst newParentId =\n\t\t\t\teditor.findShapeAncestor(prevParent, (s) => editor.isShapeOfType<TLGroupShape>(s, 'group'))\n\t\t\t\t\t?.id ?? editor.getCurrentPageId()\n\n\t\t\tremainingShapesToReparent.forEach((shape) => {\n\t\t\t\tif (!parentsToNewChildren[newParentId]) {\n\t\t\t\t\tlet insertIndexKey: IndexKey | undefined\n\n\t\t\t\t\tconst oldParentSiblingIds = editor.getSortedChildIdsForParent(newParentId)\n\t\t\t\t\tconst oldParentIndex = oldParentSiblingIds.indexOf(prevParent.id)\n\t\t\t\t\tif (oldParentIndex > -1) {\n\t\t\t\t\t\t// If the old parent is a direct child of the new parent, then we'll add them above the old parent but below the next sibling.\n\t\t\t\t\t\tconst siblingsIndexAbove = oldParentSiblingIds[oldParentIndex + 1]\n\t\t\t\t\t\tconst indexKeyAbove = siblingsIndexAbove\n\t\t\t\t\t\t\t? editor.getShape(siblingsIndexAbove)!.index\n\t\t\t\t\t\t\t: getIndexAbove(prevParent.index)\n\t\t\t\t\t\tinsertIndexKey = getIndexBetween(prevParent.index, indexKeyAbove)\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If the old parent is not a direct child of the new parent, then we'll add them to the \"top\" of the new parent's children.\n\t\t\t\t\t\t// This is done automatically if we leave the index undefined, so let's do that.\n\t\t\t\t\t}\n\n\t\t\t\t\tparentsToNewChildren[newParentId] = {\n\t\t\t\t\t\tparentId: newParentId,\n\t\t\t\t\t\tshapeIds: [],\n\t\t\t\t\t\tindex: insertIndexKey,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tparentsToNewChildren[newParentId].shapeIds.push(shape.id)\n\t\t\t})\n\t\t}\n\t}\n\n\teditor.run(() => {\n\t\tObject.values(parentsToNewChildren).forEach(({ parentId, shapeIds, index }) => {\n\t\t\tif (shapeIds.length === 0) return\n\t\t\t// Before we reparent, sort the new shape ids by their place in the original absolute order on the page\n\t\t\tshapeIds.sort((a, b) => (sortedShapeIds.indexOf(a) < sortedShapeIds.indexOf(b) ? -1 : 1))\n\t\t\teditor.reparentShapes(shapeIds, parentId, index)\n\t\t})\n\t})\n}\n\n/**\n * Get the shapes that overlap with a given shape.\n *\n * @param editor - The editor instance.\n * @param shape - The shapes or shape IDs to check against.\n * @param otherShapes - The shapes or shape IDs to check for overlap.\n * @returns An array of shapes or shape IDs that overlap with the given shape.\n */\nfunction getOverlappingShapes<T extends TLShape[] | TLShapeId[]>(\n\teditor: Editor,\n\tshape: T[number],\n\totherShapes: T\n) {\n\tif (otherShapes.length === 0) {\n\t\treturn EMPTY_ARRAY\n\t}\n\n\tconst parentPageBounds = editor.getShapePageBounds(shape)\n\tif (!parentPageBounds) return EMPTY_ARRAY\n\n\tconst parentGeometry = editor.getShapeGeometry(shape)\n\tconst parentPageTransform = editor.getShapePageTransform(shape)\n\tconst parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)\n\n\tconst _shape = editor.getShape(shape)\n\tif (!_shape) return EMPTY_ARRAY\n\n\tconst pageTransform = editor.getShapePageTransform(shape)\n\tconst clipPath = editor.getShapeUtil(_shape.type).getClipPath?.(_shape)\n\n\tconst parentPageMaskVertices = clipPath ? pageTransform.applyToPoints(clipPath) : undefined\n\tconst parentPagePolygon = parentPageMaskVertices\n\t\t? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)\n\t\t: parentPageCorners\n\n\tif (!parentPagePolygon) return EMPTY_ARRAY\n\n\treturn otherShapes.filter((childId) => {\n\t\tconst shapePageBounds = editor.getShapePageBounds(childId)\n\t\tif (!shapePageBounds || !parentPageBounds.includes(shapePageBounds)) return false\n\n\t\tconst parentPolygonInShapeShape = editor\n\t\t\t.getShapePageTransform(childId)\n\t\t\t.clone()\n\t\t\t.invert()\n\t\t\t.applyToPoints(parentPagePolygon)\n\n\t\tconst geometry = editor.getShapeGeometry(childId)\n\n\t\treturn geometry.overlapsPolygon(parentPolygonInShapeShape)\n\t})\n}\n\n/**\n * Get the shapes that will be reparented to new parents when the shapes are dropped.\n *\n * @param editor - The editor instance.\n * @param shapes - The shapes to check.\n * @param cb - A callback to filter out certain shapes.\n * @returns An object with the shapes that will be reparented to new parents and the shapes that will be reparented to the page or their ancestral group.\n *\n * @public\n */\nexport function getDroppedShapesToNewParents(\n\teditor: Editor,\n\tshapes: Set<TLShape> | TLShape[],\n\tcb?: (shape: TLShape, parent: TLShape) => boolean\n) {\n\tconst shapesToActuallyCheck = new Set<TLShape>(shapes)\n\tconst movingGroups = new Set<TLGroupShape>()\n\n\tfor (const shape of shapes) {\n\t\tconst parent = editor.getShapeParent(shape)\n\t\tif (parent && editor.isShapeOfType<TLGroupShape>(parent, 'group')) {\n\t\t\tif (!movingGroups.has(parent)) {\n\t\t\t\tmovingGroups.add(parent)\n\t\t\t}\n\t\t}\n\t}\n\n\t// If all of a group's children are moving, then move the group instead\n\tfor (const movingGroup of movingGroups) {\n\t\tconst children = compact(\n\t\t\teditor.getSortedChildIdsForParent(movingGroup).map((id) => editor.getShape(id))\n\t\t)\n\t\tfor (const child of children) {\n\t\t\tshapesToActuallyCheck.delete(child)\n\t\t}\n\t\tshapesToActuallyCheck.add(movingGroup)\n\t}\n\n\t// this could be cached and passed in\n\tconst shapeGroupIds = new Map<TLShapeId, TLShapeId | undefined>()\n\n\tconst reparenting = new Map<TLShapeId, TLShape[]>()\n\n\tconst remainingShapesToReparent = new Set(shapesToActuallyCheck)\n\n\tconst potentialParentShapes = editor\n\t\t.getCurrentPageShapesSorted()\n\t\t// filter out any shapes that aren't frames or that are included among the provided shapes\n\t\t.filter(\n\t\t\t(s) =>\n\t\t\t\teditor.getShapeUtil(s).canReceiveNewChildrenOfType?.(s, s.type) &&\n\t\t\t\t!remainingShapesToReparent.has(s)\n\t\t)\n\n\tparentCheck: for (let i = potentialParentShapes.length - 1; i >= 0; i--) {\n\t\tconst parentShape = potentialParentShapes[i]\n\t\tconst parentShapeContainingGroupId = editor.findShapeAncestor(parentShape, (s) =>\n\t\t\teditor.isShapeOfType<TLGroupShape>(s, 'group')\n\t\t)?.id\n\n\t\tconst parentGeometry = editor.getShapeGeometry(parentShape)\n\t\tconst parentPageTransform = editor.getShapePageTransform(parentShape)\n\t\tconst parentPageMaskVertices = editor.getShapeMask(parentShape)\n\t\tconst parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)\n\t\tconst parentPagePolygon = parentPageMaskVertices\n\t\t\t? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)\n\t\t\t: parentPageCorners\n\n\t\tif (!parentPagePolygon) continue parentCheck\n\n\t\tconst childrenToReparent = []\n\n\t\t// For each of the dropping shapes...\n\t\tshapeCheck: for (const shape of remainingShapesToReparent) {\n\t\t\t// Don't reparent a frame to itself\n\t\t\tif (parentShape.id === shape.id) continue shapeCheck\n\n\t\t\t// Use the callback to filter out certain shapes\n\t\t\tif (cb && !cb(shape, parentShape)) continue shapeCheck\n\n\t\t\tif (!shapeGroupIds.has(shape.id)) {\n\t\t\t\tshapeGroupIds.set(\n\t\t\t\t\tshape.id,\n\t\t\t\t\teditor.findShapeAncestor(shape, (s) => editor.isShapeOfType<TLGroupShape>(s, 'group'))?.id\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst shapeGroupId = shapeGroupIds.get(shape.id)\n\n\t\t\t// Are the shape and the parent part of different groups?\n\t\t\tif (shapeGroupId !== parentShapeContainingGroupId) continue shapeCheck\n\n\t\t\t// Is the shape is actually the ancestor of the parent?\n\t\t\tif (editor.findShapeAncestor(parentShape, (s) => shape.id === s.id)) continue shapeCheck\n\n\t\t\t// Convert the parent polygon to the shape's space\n\t\t\tconst parentPolygonInShapeSpace = editor\n\t\t\t\t.getShapePageTransform(shape)\n\t\t\t\t.clone()\n\t\t\t\t.invert()\n\t\t\t\t.applyToPoints(parentPagePolygon)\n\n\t\t\t// If the shape overlaps the parent polygon, reparent it to that parent\n\t\t\tif (editor.getShapeGeometry(shape).overlapsPolygon(parentPolygonInShapeSpace)) {\n\t\t\t\t// Use the util to check if the shape can be reparented to the parent\n\t\t\t\tif (\n\t\t\t\t\t!editor.getShapeUtil(parentShape).canReceiveNewChildrenOfType?.(parentShape, shape.type)\n\t\t\t\t)\n\t\t\t\t\tcontinue shapeCheck\n\n\t\t\t\tif (shape.parentId !== parentShape.id) {\n\t\t\t\t\tchildrenToReparent.push(shape)\n\t\t\t\t}\n\t\t\t\tremainingShapesToReparent.delete(shape)\n\t\t\t\tcontinue shapeCheck\n\t\t\t}\n\t\t}\n\n\t\tif (childrenToReparent.length) {\n\t\t\treparenting.set(parentShape.id, childrenToReparent)\n\t\t}\n\t}\n\n\treturn {\n\t\t// these are the shapes that will be reparented to new parents\n\t\treparenting,\n\t\t// these are the shapes that will be reparented to the page or their ancestral group\n\t\tremainingShapesToReparent,\n\t}\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,mBAAmB;AAE5B,SAAmB,SAAS,eAAe,uBAAuB;AAElE,SAAS,+BAA+B;AAYjC,SAAS,sBACf,QACA,UACA,MACC;AACD,QAAM,iBAAiB,oBAAI,IAAa;AAExC,aAAW,MAAM,UAAU;AAC1B,UAAM,QAAQ,OAAO,SAAS,EAAE;AAEhC,QAAI,CAAC,MAAO;AACZ,mBAAe,IAAI,KAAK;AAExB,UAAM,SAAS,OAAO,SAAS,MAAM,QAAQ;AAC7C,QAAI,CAAC,OAAQ;AACb,mBAAe,IAAI,MAAM;AAAA,EAC1B;AAGA,QAAM,wBAAwB,oBAAI,IAA0B;AAE5D,aAAW,UAAU,gBAAgB;AACpC,UAAM,WAAW,OAAO,2BAA2B,MAAM;AACzD,QAAI,MAAM,UAAU,CAAC,KAAK,OAAO,MAAM,GAAG;AAEzC,4BAAsB,IAAI,QAAQ,QAAQ;AAAA,IAC3C,OAAO;AACN,YAAM,sBAAsB,qBAAqB,QAAQ,OAAO,IAAI,QAAQ;AAC5E,UAAI,oBAAoB,SAAS,SAAS,QAAQ;AACjD,8BAAsB;AAAA,UACrB;AAAA,UACA,SAAS,OAAO,CAAC,OAAO,CAAC,oBAAoB,SAAS,EAAE,CAAC;AAAA,QAC1D;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAGA,QAAM,iBAAiB,OAAO,2BAA2B,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AAE1E,QAAM,uBAGF,CAAC;AAEL,aAAW,CAAC,YAAY,eAAe,KAAK,uBAAuB;AAClE,UAAM,eAAe,QAAQ,gBAAgB,IAAI,CAAC,OAAO,OAAO,SAAS,EAAE,CAAC,CAAC;AAO7E,UAAM,EAAE,aAAa,0BAA0B,IAAI;AAAA,MAClD;AAAA,MACA;AAAA,MACA,CAAC,OAAO,mBAAmB;AAE1B,YAAI,MAAM,UAAU,CAAC,KAAK,OAAO,cAAc,EAAG,QAAO;AACzD,eACC,eAAe,OAAO,WAAW,MACjC,eAAe,QAAQ,eAAe,EAAE,IAAI,eAAe,QAAQ,MAAM,EAAE;AAAA,MAE7E;AAAA,IACD;AAEA,gBAAY,QAAQ,CAAC,oBAAoB,gBAAgB;AACxD,UAAI,mBAAmB,WAAW,EAAG;AACrC,UAAI,CAAC,qBAAqB,WAAW,GAAG;AACvC,6BAAqB,WAAW,IAAI;AAAA,UACnC,UAAU;AAAA,UACV,UAAU,CAAC;AAAA,QACZ;AAAA,MACD;AACA,2BAAqB,WAAW,EAAE,SAAS,KAAK,GAAG,mBAAmB,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAAA,IACvF,CAAC;AAGD,QAAI,0BAA0B,OAAO,GAAG;AAEvC,YAAM,cACL,OAAO,kBAAkB,YAAY,CAAC,MAAM,OAAO,
|
|
4
|
+
"sourcesContent": ["import { EMPTY_ARRAY } from '@tldraw/state'\nimport { TLGroupShape, TLParentId, TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { IndexKey, compact, getIndexAbove, getIndexBetween } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\nimport { intersectPolygonPolygon } from '../primitives/intersect'\n\n/**\n * Reparents shapes that are no longer contained within their parent shapes.\n * todo: rename me to something more descriptive, like `reparentOccludedShapes` or `reparentAutoDroppedShapes`\n *\n * @param editor - The editor instance.\n * @param shapeIds - The IDs of the shapes to reparent.\n * @param opts - Optional options, including a callback to filter out certain parents, such as when removing a frame.\n *\n * @public\n */\nexport function kickoutOccludedShapes(\n\teditor: Editor,\n\tshapeIds: TLShapeId[],\n\topts?: { filter?(parent: TLShape): boolean }\n) {\n\tconst parentsToCheck = new Set<TLShape>()\n\n\tfor (const id of shapeIds) {\n\t\tconst shape = editor.getShape(id)\n\n\t\tif (!shape) continue\n\t\tparentsToCheck.add(shape)\n\n\t\tconst parent = editor.getShape(shape.parentId)\n\t\tif (!parent) continue\n\t\tparentsToCheck.add(parent)\n\t}\n\n\t// Check all of the parents and gather up parents who have lost children\n\tconst parentsToLostChildren = new Map<TLShape, TLShapeId[]>()\n\n\tfor (const parent of parentsToCheck) {\n\t\tconst childIds = editor.getSortedChildIdsForParent(parent)\n\t\tif (opts?.filter && !opts.filter(parent)) {\n\t\t\t// If the shape is filtered out, we kick out all of its children\n\t\t\tparentsToLostChildren.set(parent, childIds)\n\t\t} else {\n\t\t\tconst overlappingChildren = getOverlappingShapes(editor, parent.id, childIds)\n\t\t\tif (overlappingChildren.length < childIds.length) {\n\t\t\t\tparentsToLostChildren.set(\n\t\t\t\t\tparent,\n\t\t\t\t\tchildIds.filter((id) => !overlappingChildren.includes(id))\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Get all of the shapes on the current page, sorted by their index\n\tconst sortedShapeIds = editor.getCurrentPageShapesSorted().map((s) => s.id)\n\n\tconst parentsToNewChildren: Record<\n\t\tTLParentId,\n\t\t{ parentId: TLParentId; shapeIds: TLShapeId[]; index?: IndexKey }\n\t> = {}\n\n\tfor (const [prevParent, lostChildrenIds] of parentsToLostChildren) {\n\t\tconst lostChildren = compact(lostChildrenIds.map((id) => editor.getShape(id)))\n\n\t\t// Don't fall \"up\" into frames in front of the shape\n\t\t// if (pageShapes.indexOf(shape) < frameSortPosition) continue shapeCheck\n\n\t\t// Otherwise, we have no next dropping shape under the cursor, so go find\n\t\t// all the frames on the page where the moving shapes will fall into\n\t\tconst { reparenting, remainingShapesToReparent } = getDroppedShapesToNewParents(\n\t\t\teditor,\n\t\t\tlostChildren,\n\t\t\t(shape, maybeNewParent) => {\n\t\t\t\t// If we're filtering out a potential parent, don't reparent shapes to the filtered out shape\n\t\t\t\tif (opts?.filter && !opts.filter(maybeNewParent)) return false\n\t\t\t\treturn (\n\t\t\t\t\tmaybeNewParent.id !== prevParent.id &&\n\t\t\t\t\tsortedShapeIds.indexOf(maybeNewParent.id) < sortedShapeIds.indexOf(shape.id)\n\t\t\t\t)\n\t\t\t}\n\t\t)\n\n\t\treparenting.forEach((childrenToReparent, newParentId) => {\n\t\t\tif (childrenToReparent.length === 0) return\n\t\t\tif (!parentsToNewChildren[newParentId]) {\n\t\t\t\tparentsToNewChildren[newParentId] = {\n\t\t\t\t\tparentId: newParentId,\n\t\t\t\t\tshapeIds: [],\n\t\t\t\t}\n\t\t\t}\n\t\t\tparentsToNewChildren[newParentId].shapeIds.push(...childrenToReparent.map((s) => s.id))\n\t\t})\n\n\t\t// Reparent the rest to the page (or containing group)\n\t\tif (remainingShapesToReparent.size > 0) {\n\t\t\t// The remaining shapes are going to be reparented to the old parent's containing group, if there was one, or else to the page\n\t\t\tconst newParentId =\n\t\t\t\teditor.findShapeAncestor(prevParent, (s) => editor.isShapeOfType(s, 'group'))?.id ??\n\t\t\t\teditor.getCurrentPageId()\n\n\t\t\tremainingShapesToReparent.forEach((shape) => {\n\t\t\t\tif (!parentsToNewChildren[newParentId]) {\n\t\t\t\t\tlet insertIndexKey: IndexKey | undefined\n\n\t\t\t\t\tconst oldParentSiblingIds = editor.getSortedChildIdsForParent(newParentId)\n\t\t\t\t\tconst oldParentIndex = oldParentSiblingIds.indexOf(prevParent.id)\n\t\t\t\t\tif (oldParentIndex > -1) {\n\t\t\t\t\t\t// If the old parent is a direct child of the new parent, then we'll add them above the old parent but below the next sibling.\n\t\t\t\t\t\tconst siblingsIndexAbove = oldParentSiblingIds[oldParentIndex + 1]\n\t\t\t\t\t\tconst indexKeyAbove = siblingsIndexAbove\n\t\t\t\t\t\t\t? editor.getShape(siblingsIndexAbove)!.index\n\t\t\t\t\t\t\t: getIndexAbove(prevParent.index)\n\t\t\t\t\t\tinsertIndexKey = getIndexBetween(prevParent.index, indexKeyAbove)\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If the old parent is not a direct child of the new parent, then we'll add them to the \"top\" of the new parent's children.\n\t\t\t\t\t\t// This is done automatically if we leave the index undefined, so let's do that.\n\t\t\t\t\t}\n\n\t\t\t\t\tparentsToNewChildren[newParentId] = {\n\t\t\t\t\t\tparentId: newParentId,\n\t\t\t\t\t\tshapeIds: [],\n\t\t\t\t\t\tindex: insertIndexKey,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tparentsToNewChildren[newParentId].shapeIds.push(shape.id)\n\t\t\t})\n\t\t}\n\t}\n\n\teditor.run(() => {\n\t\tObject.values(parentsToNewChildren).forEach(({ parentId, shapeIds, index }) => {\n\t\t\tif (shapeIds.length === 0) return\n\t\t\t// Before we reparent, sort the new shape ids by their place in the original absolute order on the page\n\t\t\tshapeIds.sort((a, b) => (sortedShapeIds.indexOf(a) < sortedShapeIds.indexOf(b) ? -1 : 1))\n\t\t\teditor.reparentShapes(shapeIds, parentId, index)\n\t\t})\n\t})\n}\n\n/**\n * Get the shapes that overlap with a given shape.\n *\n * @param editor - The editor instance.\n * @param shape - The shapes or shape IDs to check against.\n * @param otherShapes - The shapes or shape IDs to check for overlap.\n * @returns An array of shapes or shape IDs that overlap with the given shape.\n */\nfunction getOverlappingShapes<T extends TLShape[] | TLShapeId[]>(\n\teditor: Editor,\n\tshape: T[number],\n\totherShapes: T\n) {\n\tif (otherShapes.length === 0) {\n\t\treturn EMPTY_ARRAY\n\t}\n\n\tconst parentPageBounds = editor.getShapePageBounds(shape)\n\tif (!parentPageBounds) return EMPTY_ARRAY\n\n\tconst parentGeometry = editor.getShapeGeometry(shape)\n\tconst parentPageTransform = editor.getShapePageTransform(shape)\n\tconst parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)\n\n\tconst _shape = editor.getShape(shape)\n\tif (!_shape) return EMPTY_ARRAY\n\n\tconst pageTransform = editor.getShapePageTransform(shape)\n\tconst clipPath = editor.getShapeUtil(_shape.type).getClipPath?.(_shape)\n\n\tconst parentPageMaskVertices = clipPath ? pageTransform.applyToPoints(clipPath) : undefined\n\tconst parentPagePolygon = parentPageMaskVertices\n\t\t? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)\n\t\t: parentPageCorners\n\n\tif (!parentPagePolygon) return EMPTY_ARRAY\n\n\treturn otherShapes.filter((childId) => {\n\t\tconst shapePageBounds = editor.getShapePageBounds(childId)\n\t\tif (!shapePageBounds || !parentPageBounds.includes(shapePageBounds)) return false\n\n\t\tconst parentPolygonInShapeShape = editor\n\t\t\t.getShapePageTransform(childId)\n\t\t\t.clone()\n\t\t\t.invert()\n\t\t\t.applyToPoints(parentPagePolygon)\n\n\t\tconst geometry = editor.getShapeGeometry(childId)\n\n\t\treturn geometry.overlapsPolygon(parentPolygonInShapeShape)\n\t})\n}\n\n/**\n * Get the shapes that will be reparented to new parents when the shapes are dropped.\n *\n * @param editor - The editor instance.\n * @param shapes - The shapes to check.\n * @param cb - A callback to filter out certain shapes.\n * @returns An object with the shapes that will be reparented to new parents and the shapes that will be reparented to the page or their ancestral group.\n *\n * @public\n */\nexport function getDroppedShapesToNewParents(\n\teditor: Editor,\n\tshapes: Set<TLShape> | TLShape[],\n\tcb?: (shape: TLShape, parent: TLShape) => boolean\n) {\n\tconst shapesToActuallyCheck = new Set<TLShape>(shapes)\n\tconst movingGroups = new Set<TLGroupShape>()\n\n\tfor (const shape of shapes) {\n\t\tconst parent = editor.getShapeParent(shape)\n\t\tif (parent && editor.isShapeOfType(parent, 'group')) {\n\t\t\tif (!movingGroups.has(parent)) {\n\t\t\t\tmovingGroups.add(parent)\n\t\t\t}\n\t\t}\n\t}\n\n\t// If all of a group's children are moving, then move the group instead\n\tfor (const movingGroup of movingGroups) {\n\t\tconst children = compact(\n\t\t\teditor.getSortedChildIdsForParent(movingGroup).map((id) => editor.getShape(id))\n\t\t)\n\t\tfor (const child of children) {\n\t\t\tshapesToActuallyCheck.delete(child)\n\t\t}\n\t\tshapesToActuallyCheck.add(movingGroup)\n\t}\n\n\t// this could be cached and passed in\n\tconst shapeGroupIds = new Map<TLShapeId, TLShapeId | undefined>()\n\n\tconst reparenting = new Map<TLShapeId, TLShape[]>()\n\n\tconst remainingShapesToReparent = new Set(shapesToActuallyCheck)\n\n\tconst potentialParentShapes = editor\n\t\t.getCurrentPageShapesSorted()\n\t\t// filter out any shapes that aren't frames or that are included among the provided shapes\n\t\t.filter(\n\t\t\t(s) =>\n\t\t\t\teditor.getShapeUtil(s).canReceiveNewChildrenOfType?.(s, s.type) &&\n\t\t\t\t!remainingShapesToReparent.has(s)\n\t\t)\n\n\tparentCheck: for (let i = potentialParentShapes.length - 1; i >= 0; i--) {\n\t\tconst parentShape = potentialParentShapes[i]\n\t\tconst parentShapeContainingGroupId = editor.findShapeAncestor(parentShape, (s) =>\n\t\t\teditor.isShapeOfType(s, 'group')\n\t\t)?.id\n\n\t\tconst parentGeometry = editor.getShapeGeometry(parentShape)\n\t\tconst parentPageTransform = editor.getShapePageTransform(parentShape)\n\t\tconst parentPageMaskVertices = editor.getShapeMask(parentShape)\n\t\tconst parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)\n\t\tconst parentPagePolygon = parentPageMaskVertices\n\t\t\t? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)\n\t\t\t: parentPageCorners\n\n\t\tif (!parentPagePolygon) continue parentCheck\n\n\t\tconst childrenToReparent = []\n\n\t\t// For each of the dropping shapes...\n\t\tshapeCheck: for (const shape of remainingShapesToReparent) {\n\t\t\t// Don't reparent a frame to itself\n\t\t\tif (parentShape.id === shape.id) continue shapeCheck\n\n\t\t\t// Use the callback to filter out certain shapes\n\t\t\tif (cb && !cb(shape, parentShape)) continue shapeCheck\n\n\t\t\tif (!shapeGroupIds.has(shape.id)) {\n\t\t\t\tshapeGroupIds.set(\n\t\t\t\t\tshape.id,\n\t\t\t\t\teditor.findShapeAncestor(shape, (s) => editor.isShapeOfType(s, 'group'))?.id\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst shapeGroupId = shapeGroupIds.get(shape.id)\n\n\t\t\t// Are the shape and the parent part of different groups?\n\t\t\tif (shapeGroupId !== parentShapeContainingGroupId) continue shapeCheck\n\n\t\t\t// Is the shape is actually the ancestor of the parent?\n\t\t\tif (editor.findShapeAncestor(parentShape, (s) => shape.id === s.id)) continue shapeCheck\n\n\t\t\t// Convert the parent polygon to the shape's space\n\t\t\tconst parentPolygonInShapeSpace = editor\n\t\t\t\t.getShapePageTransform(shape)\n\t\t\t\t.clone()\n\t\t\t\t.invert()\n\t\t\t\t.applyToPoints(parentPagePolygon)\n\n\t\t\t// If the shape overlaps the parent polygon, reparent it to that parent\n\t\t\tif (editor.getShapeGeometry(shape).overlapsPolygon(parentPolygonInShapeSpace)) {\n\t\t\t\t// Use the util to check if the shape can be reparented to the parent\n\t\t\t\tif (\n\t\t\t\t\t!editor.getShapeUtil(parentShape).canReceiveNewChildrenOfType?.(parentShape, shape.type)\n\t\t\t\t)\n\t\t\t\t\tcontinue shapeCheck\n\n\t\t\t\tif (shape.parentId !== parentShape.id) {\n\t\t\t\t\tchildrenToReparent.push(shape)\n\t\t\t\t}\n\t\t\t\tremainingShapesToReparent.delete(shape)\n\t\t\t\tcontinue shapeCheck\n\t\t\t}\n\t\t}\n\n\t\tif (childrenToReparent.length) {\n\t\t\treparenting.set(parentShape.id, childrenToReparent)\n\t\t}\n\t}\n\n\treturn {\n\t\t// these are the shapes that will be reparented to new parents\n\t\treparenting,\n\t\t// these are the shapes that will be reparented to the page or their ancestral group\n\t\tremainingShapesToReparent,\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["shapeIds"]
|
|
7
7
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "4.3.0-next.
|
|
1
|
+
const version = "4.3.0-next.2d181ae353a2";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2025-09-18T14:39:22.803Z",
|
|
4
|
-
minor: "2025-11-
|
|
5
|
-
patch: "2025-11-
|
|
4
|
+
minor: "2025-11-28T15:57:11.960Z",
|
|
5
|
+
patch: "2025-11-28T15:57:11.960Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
package/dist-esm/version.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '4.3.0-next.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '4.3.0-next.2d181ae353a2'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-11-28T15:57:11.960Z',\n\tpatch: '2025-11-28T15:57:11.960Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "tldraw infinite canvas SDK (editor).",
|
|
4
|
-
"version": "4.3.0-next.
|
|
4
|
+
"version": "4.3.0-next.2d181ae353a2",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -47,15 +47,15 @@
|
|
|
47
47
|
"context": "yarn run -T tsx ../../internal/scripts/context.ts"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@tiptap/core": "3.6.2",
|
|
51
|
-
"@tiptap/pm": "3.6.2",
|
|
52
|
-
"@tiptap/react": "3.6.2",
|
|
53
|
-
"@tldraw/state": "4.3.0-next.
|
|
54
|
-
"@tldraw/state-react": "4.3.0-next.
|
|
55
|
-
"@tldraw/store": "4.3.0-next.
|
|
56
|
-
"@tldraw/tlschema": "4.3.0-next.
|
|
57
|
-
"@tldraw/utils": "4.3.0-next.
|
|
58
|
-
"@tldraw/validate": "4.3.0-next.
|
|
50
|
+
"@tiptap/core": "^3.6.2",
|
|
51
|
+
"@tiptap/pm": "^3.6.2",
|
|
52
|
+
"@tiptap/react": "^3.6.2",
|
|
53
|
+
"@tldraw/state": "4.3.0-next.2d181ae353a2",
|
|
54
|
+
"@tldraw/state-react": "4.3.0-next.2d181ae353a2",
|
|
55
|
+
"@tldraw/store": "4.3.0-next.2d181ae353a2",
|
|
56
|
+
"@tldraw/tlschema": "4.3.0-next.2d181ae353a2",
|
|
57
|
+
"@tldraw/utils": "4.3.0-next.2d181ae353a2",
|
|
58
|
+
"@tldraw/validate": "4.3.0-next.2d181ae353a2",
|
|
59
59
|
"@types/core-js": "^2.5.8",
|
|
60
60
|
"@use-gesture/react": "^10.3.1",
|
|
61
61
|
"classnames": "^2.5.1",
|
|
@@ -6,25 +6,25 @@ import {
|
|
|
6
6
|
Rectangle2d,
|
|
7
7
|
ShapeUtil,
|
|
8
8
|
T,
|
|
9
|
-
|
|
9
|
+
TLShape,
|
|
10
10
|
createShapeId,
|
|
11
11
|
createTLStore,
|
|
12
12
|
} from '../..'
|
|
13
13
|
import { Editor } from './Editor'
|
|
14
14
|
import { StateNode } from './tools/StateNode'
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
h: number
|
|
21
|
-
text: string | undefined
|
|
22
|
-
isFilled: boolean
|
|
16
|
+
const MY_CUSTOM_SHAPE_TYPE = 'my-custom-shape'
|
|
17
|
+
|
|
18
|
+
declare module '@tldraw/tlschema' {
|
|
19
|
+
export interface TLGlobalShapePropsMap {
|
|
20
|
+
[MY_CUSTOM_SHAPE_TYPE]: { w: number; h: number; text: string | undefined; isFilled: boolean }
|
|
23
21
|
}
|
|
24
|
-
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type ICustomShape = TLShape<typeof MY_CUSTOM_SHAPE_TYPE>
|
|
25
25
|
|
|
26
26
|
class CustomShape extends ShapeUtil<ICustomShape> {
|
|
27
|
-
static override type =
|
|
27
|
+
static override type = MY_CUSTOM_SHAPE_TYPE
|
|
28
28
|
static override props: RecordProps<ICustomShape> = {
|
|
29
29
|
w: T.number,
|
|
30
30
|
h: T.number,
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
PageRecordType,
|
|
22
22
|
StyleProp,
|
|
23
23
|
StylePropValue,
|
|
24
|
-
TLArrowShape,
|
|
25
24
|
TLAsset,
|
|
26
25
|
TLAssetId,
|
|
27
26
|
TLAssetPartial,
|
|
@@ -30,12 +29,12 @@ import {
|
|
|
30
29
|
TLBindingId,
|
|
31
30
|
TLBindingUpdate,
|
|
32
31
|
TLCamera,
|
|
32
|
+
TLCreateShapePartial,
|
|
33
33
|
TLCursor,
|
|
34
34
|
TLCursorType,
|
|
35
35
|
TLDOCUMENT_ID,
|
|
36
36
|
TLDocument,
|
|
37
37
|
TLFrameShape,
|
|
38
|
-
TLGeoShape,
|
|
39
38
|
TLGroupShape,
|
|
40
39
|
TLHandle,
|
|
41
40
|
TLINSTANCE_ID,
|
|
@@ -43,7 +42,6 @@ import {
|
|
|
43
42
|
TLInstance,
|
|
44
43
|
TLInstancePageState,
|
|
45
44
|
TLInstancePresence,
|
|
46
|
-
TLNoteShape,
|
|
47
45
|
TLPOINTER_ID,
|
|
48
46
|
TLPage,
|
|
49
47
|
TLPageId,
|
|
@@ -54,8 +52,6 @@ import {
|
|
|
54
52
|
TLShapePartial,
|
|
55
53
|
TLStore,
|
|
56
54
|
TLStoreSnapshot,
|
|
57
|
-
TLUnknownBinding,
|
|
58
|
-
TLUnknownShape,
|
|
59
55
|
TLVideoAsset,
|
|
60
56
|
createBindingId,
|
|
61
57
|
createShapeId,
|
|
@@ -447,7 +443,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
447
443
|
let deletedBindings = new Map<TLBindingId, BindingOnDeleteOptions<any>>()
|
|
448
444
|
const deletedShapeIds = new Set<TLShapeId>()
|
|
449
445
|
const invalidParents = new Set<TLShapeId>()
|
|
450
|
-
let invalidBindingTypes = new Set<
|
|
446
|
+
let invalidBindingTypes = new Set<TLBinding['type']>()
|
|
451
447
|
this.disposables.add(
|
|
452
448
|
this.sideEffects.registerOperationCompleteHandler(() => {
|
|
453
449
|
// this needs to be cleared here because further effects may delete more shapes
|
|
@@ -710,7 +706,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
710
706
|
if (filtered.length > 0) {
|
|
711
707
|
const commonGroupAncestor = this.findCommonAncestor(
|
|
712
708
|
compact(filtered.map((id) => this.getShape(id))),
|
|
713
|
-
(shape) => this.isShapeOfType
|
|
709
|
+
(shape) => this.isShapeOfType(shape, 'group')
|
|
714
710
|
)
|
|
715
711
|
|
|
716
712
|
if (commonGroupAncestor) {
|
|
@@ -982,7 +978,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
982
978
|
*
|
|
983
979
|
* @public
|
|
984
980
|
*/
|
|
985
|
-
shapeUtils: { readonly [K in string]?: ShapeUtil<
|
|
981
|
+
shapeUtils: { readonly [K in string]?: ShapeUtil<TLShape> }
|
|
986
982
|
|
|
987
983
|
styleProps: { [key: string]: Map<StyleProp<any>, string> }
|
|
988
984
|
|
|
@@ -1001,8 +997,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1001
997
|
*
|
|
1002
998
|
* @public
|
|
1003
999
|
*/
|
|
1004
|
-
getShapeUtil<
|
|
1005
|
-
getShapeUtil<S extends
|
|
1000
|
+
getShapeUtil<K extends TLShape['type']>(type: K): ShapeUtil<Extract<TLShape, { type: K }>>
|
|
1001
|
+
getShapeUtil<S extends TLShape>(shape: S | TLShapePartial<S> | S['type']): ShapeUtil<S>
|
|
1006
1002
|
getShapeUtil<T extends ShapeUtil>(type: T extends ShapeUtil<infer R> ? R['type'] : string): T
|
|
1007
1003
|
getShapeUtil(arg: string | { type: string }) {
|
|
1008
1004
|
const type = typeof arg === 'string' ? arg : arg.type
|
|
@@ -1016,8 +1012,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1016
1012
|
*
|
|
1017
1013
|
* @param shape - A shape, shape partial, or shape type.
|
|
1018
1014
|
*/
|
|
1019
|
-
hasShapeUtil
|
|
1020
|
-
hasShapeUtil
|
|
1015
|
+
hasShapeUtil(shape: TLShape | TLShapePartial<TLShape>): boolean
|
|
1016
|
+
hasShapeUtil(type: TLShape['type']): boolean
|
|
1021
1017
|
hasShapeUtil<T extends ShapeUtil>(
|
|
1022
1018
|
type: T extends ShapeUtil<infer R> ? R['type'] : string
|
|
1023
1019
|
): boolean
|
|
@@ -1032,7 +1028,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1032
1028
|
*
|
|
1033
1029
|
* @public
|
|
1034
1030
|
*/
|
|
1035
|
-
bindingUtils: { readonly [K in string]?: BindingUtil<
|
|
1031
|
+
bindingUtils: { readonly [K in string]?: BindingUtil<TLBinding> }
|
|
1036
1032
|
|
|
1037
1033
|
/**
|
|
1038
1034
|
* Get a binding util from a binding itself.
|
|
@@ -1049,8 +1045,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1049
1045
|
*
|
|
1050
1046
|
* @public
|
|
1051
1047
|
*/
|
|
1052
|
-
getBindingUtil<
|
|
1053
|
-
getBindingUtil<S extends
|
|
1048
|
+
getBindingUtil<K extends TLBinding['type']>(type: K): BindingUtil<Extract<TLBinding, { type: K }>>
|
|
1049
|
+
getBindingUtil<S extends TLBinding>(binding: S | { type: S['type'] }): BindingUtil<S>
|
|
1054
1050
|
getBindingUtil<T extends BindingUtil>(
|
|
1055
1051
|
type: T extends BindingUtil<infer R> ? R['type'] : string
|
|
1056
1052
|
): T
|
|
@@ -2220,7 +2216,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2220
2216
|
throw Error(`Editor.setFocusedGroup: Shape with id ${id} does not exist`)
|
|
2221
2217
|
}
|
|
2222
2218
|
|
|
2223
|
-
if (!this.isShapeOfType
|
|
2219
|
+
if (!this.isShapeOfType(shape, 'group')) {
|
|
2224
2220
|
throw Error(
|
|
2225
2221
|
`Editor.setFocusedGroup: Cannot set focused group to shape of type ${shape.type}`
|
|
2226
2222
|
)
|
|
@@ -2248,7 +2244,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2248
2244
|
if (focusedGroup) {
|
|
2249
2245
|
// If we have a focused layer, look for an ancestor of the focused shape that is a group
|
|
2250
2246
|
const match = this.findShapeAncestor(focusedGroup, (shape) =>
|
|
2251
|
-
this.isShapeOfType
|
|
2247
|
+
this.isShapeOfType(shape, 'group')
|
|
2252
2248
|
)
|
|
2253
2249
|
// If we have an ancestor that can become a focused layer, set it as the focused layer
|
|
2254
2250
|
this.setFocusedGroup(match?.id ?? null)
|
|
@@ -5127,10 +5123,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5127
5123
|
|
|
5128
5124
|
// Check labels first
|
|
5129
5125
|
if (
|
|
5130
|
-
this.isShapeOfType
|
|
5131
|
-
((this.isShapeOfType
|
|
5132
|
-
this.isShapeOfType
|
|
5133
|
-
(this.isShapeOfType
|
|
5126
|
+
this.isShapeOfType(shape, 'frame') ||
|
|
5127
|
+
((this.isShapeOfType(shape, 'note') ||
|
|
5128
|
+
this.isShapeOfType(shape, 'arrow') ||
|
|
5129
|
+
(this.isShapeOfType(shape, 'geo') && shape.props.fill === 'none')) &&
|
|
5134
5130
|
this.getShapeUtil(shape).getText(shape)?.trim())
|
|
5135
5131
|
) {
|
|
5136
5132
|
for (const childGeometry of (geometry as Group2d).children) {
|
|
@@ -5140,7 +5136,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5140
5136
|
}
|
|
5141
5137
|
}
|
|
5142
5138
|
|
|
5143
|
-
if (this.isShapeOfType
|
|
5139
|
+
if (this.isShapeOfType(shape, 'frame')) {
|
|
5144
5140
|
// On the rare case that we've hit a frame (not its label), test again hitInside to be forced true;
|
|
5145
5141
|
// this prevents clicks from passing through the body of a frame to shapes behind it.
|
|
5146
5142
|
|
|
@@ -5421,7 +5417,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5421
5417
|
*
|
|
5422
5418
|
* @example
|
|
5423
5419
|
* ```ts
|
|
5424
|
-
* const isArrowShape = isShapeOfType
|
|
5420
|
+
* const isArrowShape = isShapeOfType(someShape, 'arrow')
|
|
5425
5421
|
* ```
|
|
5426
5422
|
*
|
|
5427
5423
|
* @param util - the TLShapeUtil constructor to test against
|
|
@@ -5429,15 +5425,16 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5429
5425
|
*
|
|
5430
5426
|
* @public
|
|
5431
5427
|
*/
|
|
5432
|
-
isShapeOfType<
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
arg: TLUnknownShape | TLUnknownShape['id'],
|
|
5428
|
+
isShapeOfType<K extends TLShape['type']>(
|
|
5429
|
+
shape: TLShape,
|
|
5430
|
+
type: K
|
|
5431
|
+
): shape is Extract<TLShape, { type: K }>
|
|
5432
|
+
isShapeOfType<T extends TLShape>(
|
|
5433
|
+
shape: TLShape,
|
|
5439
5434
|
type: T['type']
|
|
5440
|
-
) {
|
|
5435
|
+
): shape is Extract<TLShape, { type: T['type'] }>
|
|
5436
|
+
isShapeOfType<T extends TLShape = TLShape>(shapeId: TLShapeId, type: T['type']): boolean
|
|
5437
|
+
isShapeOfType(arg: TLShape | TLShapeId, type: TLShape['type']) {
|
|
5441
5438
|
const shape = typeof arg === 'string' ? this.getShape(arg) : arg
|
|
5442
5439
|
if (!shape) return false
|
|
5443
5440
|
return shape.type === type
|
|
@@ -5833,7 +5830,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5833
5830
|
|
|
5834
5831
|
while (node) {
|
|
5835
5832
|
if (
|
|
5836
|
-
this.isShapeOfType
|
|
5833
|
+
this.isShapeOfType(node, 'group') &&
|
|
5837
5834
|
focusedGroup?.id !== node.id &&
|
|
5838
5835
|
!this.hasAncestor(focusedGroup, node.id) &&
|
|
5839
5836
|
(filter?.(node) ?? true)
|
|
@@ -5875,7 +5872,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5875
5872
|
* Get all bindings of a certain type _from_ a particular shape. These are the bindings whose
|
|
5876
5873
|
* `fromId` matched the shape's ID.
|
|
5877
5874
|
*/
|
|
5878
|
-
getBindingsFromShape<
|
|
5875
|
+
getBindingsFromShape<K extends TLBinding['type']>(
|
|
5876
|
+
shape: TLShape | TLShapeId,
|
|
5877
|
+
type: K
|
|
5878
|
+
): Extract<TLBinding, { type: K }>[]
|
|
5879
|
+
getBindingsFromShape<Binding extends TLBinding = TLBinding>(
|
|
5880
|
+
shape: TLShape | TLShapeId,
|
|
5881
|
+
type: Binding['type']
|
|
5882
|
+
): Binding[]
|
|
5883
|
+
getBindingsFromShape<Binding extends TLBinding = TLBinding>(
|
|
5879
5884
|
shape: TLShape | TLShapeId,
|
|
5880
5885
|
type: Binding['type']
|
|
5881
5886
|
): Binding[] {
|
|
@@ -5889,7 +5894,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5889
5894
|
* Get all bindings of a certain type _to_ a particular shape. These are the bindings whose
|
|
5890
5895
|
* `toId` matches the shape's ID.
|
|
5891
5896
|
*/
|
|
5892
|
-
getBindingsToShape<
|
|
5897
|
+
getBindingsToShape<K extends TLBinding['type']>(
|
|
5898
|
+
shape: TLShape | TLShapeId,
|
|
5899
|
+
type: K
|
|
5900
|
+
): Extract<TLBinding, { type: K }>[]
|
|
5901
|
+
getBindingsToShape<Binding extends TLBinding = TLBinding>(
|
|
5902
|
+
shape: TLShape | TLShapeId,
|
|
5903
|
+
type: Binding['type']
|
|
5904
|
+
): Binding[]
|
|
5905
|
+
getBindingsToShape<Binding extends TLBinding = TLBinding>(
|
|
5893
5906
|
shape: TLShape | TLShapeId,
|
|
5894
5907
|
type: Binding['type']
|
|
5895
5908
|
): Binding[] {
|
|
@@ -5903,7 +5916,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5903
5916
|
* Get all bindings involving a particular shape. This includes bindings where the shape is the
|
|
5904
5917
|
* `fromId` or `toId`. If a type is provided, only bindings of that type are returned.
|
|
5905
5918
|
*/
|
|
5906
|
-
getBindingsInvolvingShape<
|
|
5919
|
+
getBindingsInvolvingShape<K extends TLBinding['type']>(
|
|
5920
|
+
shape: TLShape | TLShapeId,
|
|
5921
|
+
type: K
|
|
5922
|
+
): Extract<TLBinding, { type: K }>[]
|
|
5923
|
+
getBindingsInvolvingShape<Binding extends TLBinding = TLBinding>(
|
|
5924
|
+
shape: TLShape | TLShapeId,
|
|
5925
|
+
type?: Binding['type']
|
|
5926
|
+
): Binding[]
|
|
5927
|
+
getBindingsInvolvingShape<Binding extends TLBinding = TLBinding>(
|
|
5907
5928
|
shape: TLShape | TLShapeId,
|
|
5908
5929
|
type?: Binding['type']
|
|
5909
5930
|
): Binding[] {
|
|
@@ -5925,7 +5946,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5925
5946
|
if (!fromShape || !toShape) continue
|
|
5926
5947
|
if (!this.canBindShapes({ fromShape, toShape, binding: partial })) continue
|
|
5927
5948
|
|
|
5928
|
-
const util = this.getBindingUtil
|
|
5949
|
+
const util = this.getBindingUtil(partial.type)
|
|
5929
5950
|
const defaultProps = util.getDefaultProps()
|
|
5930
5951
|
const binding = this.store.schema.types.binding.create({
|
|
5931
5952
|
...partial,
|
|
@@ -6030,7 +6051,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6030
6051
|
const toShapeType = typeof toShape === 'string' ? toShape : toShape.type
|
|
6031
6052
|
const bindingType = typeof binding === 'string' ? binding : binding.type
|
|
6032
6053
|
|
|
6033
|
-
const canBindOpts = { fromShapeType, toShapeType, bindingType }
|
|
6054
|
+
const canBindOpts = { fromShapeType, toShapeType, bindingType } as const
|
|
6034
6055
|
|
|
6035
6056
|
if (fromShapeType === toShapeType) {
|
|
6036
6057
|
return this.getShapeUtil(fromShapeType).canBind(canBindOpts)
|
|
@@ -6571,7 +6592,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6571
6592
|
const shapesToFlipFirstPass = compact(ids.map((id) => this.getShape(id)))
|
|
6572
6593
|
|
|
6573
6594
|
for (const shape of shapesToFlipFirstPass) {
|
|
6574
|
-
if (this.isShapeOfType
|
|
6595
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
6575
6596
|
const childrenOfGroups = compact(
|
|
6576
6597
|
this.getSortedChildIdsForParent(shape.id).map((id) => this.getShape(id))
|
|
6577
6598
|
)
|
|
@@ -7692,9 +7713,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7692
7713
|
*
|
|
7693
7714
|
* @public
|
|
7694
7715
|
*/
|
|
7695
|
-
canCreateShape<
|
|
7696
|
-
shape: OptionalKeys<TLShapePartial<T>, 'id'> | T['id']
|
|
7697
|
-
): boolean {
|
|
7716
|
+
canCreateShape(shape: OptionalKeys<TLShapePartial<TLShape>, 'id'> | TLShape['id']): boolean {
|
|
7698
7717
|
return this.canCreateShapes([shape])
|
|
7699
7718
|
}
|
|
7700
7719
|
|
|
@@ -7705,8 +7724,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7705
7724
|
*
|
|
7706
7725
|
* @public
|
|
7707
7726
|
*/
|
|
7708
|
-
canCreateShapes
|
|
7709
|
-
shapes: (
|
|
7727
|
+
canCreateShapes(
|
|
7728
|
+
shapes: (TLShape['id'] | OptionalKeys<TLShapePartial<TLShape>, 'id'>)[]
|
|
7710
7729
|
): boolean {
|
|
7711
7730
|
return shapes.length + this.getCurrentPageShapeIds().size <= this.options.maxShapesPerPage
|
|
7712
7731
|
}
|
|
@@ -7724,7 +7743,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7724
7743
|
*
|
|
7725
7744
|
* @public
|
|
7726
7745
|
*/
|
|
7727
|
-
createShape<
|
|
7746
|
+
createShape<TShape extends TLShape>(shape: TLCreateShapePartial<TShape>): this {
|
|
7728
7747
|
this.createShapes([shape])
|
|
7729
7748
|
return this
|
|
7730
7749
|
}
|
|
@@ -7742,7 +7761,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7742
7761
|
*
|
|
7743
7762
|
* @public
|
|
7744
7763
|
*/
|
|
7745
|
-
createShapes<
|
|
7764
|
+
createShapes<TShape extends TLShape = TLShape>(shapes: TLCreateShapePartial<TShape>[]): this {
|
|
7746
7765
|
if (!Array.isArray(shapes)) {
|
|
7747
7766
|
throw Error('Editor.createShapes: must provide an array of shapes or shape partials')
|
|
7748
7767
|
}
|
|
@@ -8123,7 +8142,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8123
8142
|
const highestIndex = shapesWithRootParent[shapesWithRootParent.length - 1]?.index
|
|
8124
8143
|
|
|
8125
8144
|
this.run(() => {
|
|
8126
|
-
this.createShapes
|
|
8145
|
+
this.createShapes([
|
|
8127
8146
|
{
|
|
8128
8147
|
id: groupId,
|
|
8129
8148
|
type: 'group',
|
|
@@ -8193,7 +8212,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8193
8212
|
const groups: TLGroupShape[] = []
|
|
8194
8213
|
|
|
8195
8214
|
shapesToUngroup.forEach((shape) => {
|
|
8196
|
-
if (this.isShapeOfType
|
|
8215
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8197
8216
|
groups.push(shape)
|
|
8198
8217
|
} else {
|
|
8199
8218
|
idsToSelect.add(shape.id)
|
|
@@ -8239,7 +8258,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8239
8258
|
*
|
|
8240
8259
|
* @public
|
|
8241
8260
|
*/
|
|
8242
|
-
updateShape<T extends
|
|
8261
|
+
updateShape<T extends TLShape = TLShape>(partial: TLShapePartial<T> | null | undefined) {
|
|
8243
8262
|
this.updateShapes([partial])
|
|
8244
8263
|
return this
|
|
8245
8264
|
}
|
|
@@ -8256,7 +8275,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8256
8275
|
*
|
|
8257
8276
|
* @public
|
|
8258
8277
|
*/
|
|
8259
|
-
updateShapes<T extends
|
|
8278
|
+
updateShapes<T extends TLShape>(partials: (TLShapePartial<T> | null | undefined)[]) {
|
|
8260
8279
|
const compactedPartials: TLShapePartial<T>[] = Array(partials.length)
|
|
8261
8280
|
|
|
8262
8281
|
for (let i = 0, n = partials.length; i < n; i++) {
|
|
@@ -8408,7 +8427,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8408
8427
|
* @internal
|
|
8409
8428
|
*/
|
|
8410
8429
|
private _extractSharedStyles(shape: TLShape, sharedStyleMap: SharedStyleMap) {
|
|
8411
|
-
if (this.isShapeOfType
|
|
8430
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8412
8431
|
// For groups, ignore the styles of the group shape and instead include the styles of the
|
|
8413
8432
|
// group's children. These are the shapes that would have their styles changed if the
|
|
8414
8433
|
// user called `setStyle` on the current selection.
|
|
@@ -8528,7 +8547,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8528
8547
|
// For groups, ignore the opacity of the group shape and instead include
|
|
8529
8548
|
// the opacity of the group's children. These are the shapes that would have
|
|
8530
8549
|
// their opacity changed if the user called `setOpacity` on the current selection.
|
|
8531
|
-
if (this.isShapeOfType
|
|
8550
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8532
8551
|
for (const childId of this.getSortedChildIdsForParent(shape.id)) {
|
|
8533
8552
|
addShape(childId)
|
|
8534
8553
|
}
|
|
@@ -8589,7 +8608,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8589
8608
|
// We can have many deep levels of grouped shape
|
|
8590
8609
|
// Making a recursive function to look through all the levels
|
|
8591
8610
|
const addShapeById = (shape: TLShape) => {
|
|
8592
|
-
if (this.isShapeOfType
|
|
8611
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8593
8612
|
const childIds = this.getSortedChildIdsForParent(shape)
|
|
8594
8613
|
for (const childId of childIds) {
|
|
8595
8614
|
addShapeById(this.getShape(childId)!)
|
|
@@ -8673,7 +8692,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8673
8692
|
// We can have many deep levels of grouped shape
|
|
8674
8693
|
// Making a recursive function to look through all the levels
|
|
8675
8694
|
const addShapeById = (shape: TLShape) => {
|
|
8676
|
-
if (this.isShapeOfType
|
|
8695
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8677
8696
|
const childIds = this.getSortedChildIdsForParent(shape.id)
|
|
8678
8697
|
for (const childId of childIds) {
|
|
8679
8698
|
addShapeById(this.getShape(childId)!)
|
|
@@ -9098,7 +9117,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9098
9117
|
for (const shape of this.getSelectedShapes()) {
|
|
9099
9118
|
if (lowestDepth === 0) break
|
|
9100
9119
|
|
|
9101
|
-
const isFrame = this.isShapeOfType
|
|
9120
|
+
const isFrame = this.isShapeOfType(shape, 'frame')
|
|
9102
9121
|
const ancestors = this.getShapeAncestors(shape)
|
|
9103
9122
|
if (isFrame) ancestors.push(shape)
|
|
9104
9123
|
|
|
@@ -9137,8 +9156,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9137
9156
|
if (rootShapeIds.length === 1) {
|
|
9138
9157
|
const rootShape = shapes.find((s) => s.id === rootShapeIds[0])!
|
|
9139
9158
|
if (
|
|
9140
|
-
this.isShapeOfType
|
|
9141
|
-
this.isShapeOfType
|
|
9159
|
+
this.isShapeOfType(parent, 'frame') &&
|
|
9160
|
+
this.isShapeOfType(rootShape, 'frame') &&
|
|
9142
9161
|
rootShape.props.w === parent?.props.w &&
|
|
9143
9162
|
rootShape.props.h === parent?.props.h
|
|
9144
9163
|
) {
|
|
@@ -9313,11 +9332,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9313
9332
|
const onlyRoot = rootShapes[0] as TLFrameShape
|
|
9314
9333
|
// If the old bounds are in the viewport...
|
|
9315
9334
|
// todo: replace frame references with shapes that can accept children
|
|
9316
|
-
if (this.isShapeOfType
|
|
9335
|
+
if (this.isShapeOfType(onlyRoot, 'frame')) {
|
|
9317
9336
|
while (
|
|
9318
9337
|
this.getShapesAtPoint(point).some(
|
|
9319
9338
|
(shape) =>
|
|
9320
|
-
this.isShapeOfType
|
|
9339
|
+
this.isShapeOfType(shape, 'frame') &&
|
|
9321
9340
|
shape.props.w === onlyRoot.props.w &&
|
|
9322
9341
|
shape.props.h === onlyRoot.props.h
|
|
9323
9342
|
)
|
|
@@ -10232,6 +10251,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10232
10251
|
}
|
|
10233
10252
|
}
|
|
10234
10253
|
|
|
10254
|
+
this.emit('event', info)
|
|
10235
10255
|
this.root.handleEvent(info)
|
|
10236
10256
|
return
|
|
10237
10257
|
}
|
|
@@ -10730,7 +10750,10 @@ function alertMaxShapes(editor: Editor, pageId = editor.getCurrentPageId()) {
|
|
|
10730
10750
|
|
|
10731
10751
|
function applyPartialToRecordWithProps<
|
|
10732
10752
|
T extends UnknownRecord & { type: string; props: object; meta: object },
|
|
10733
|
-
>(
|
|
10753
|
+
>(
|
|
10754
|
+
prev: T,
|
|
10755
|
+
partial?: T extends T ? Omit<Partial<T>, 'props'> & { props?: Partial<T['props']> } : never
|
|
10756
|
+
): T {
|
|
10734
10757
|
if (!partial) return prev
|
|
10735
10758
|
let next = null as null | T
|
|
10736
10759
|
const entries = Object.entries(partial)
|