@tldraw/editor 4.3.0-canary.fd6b7f2a8adc → 4.3.0-next.2b3bfbba757b
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 +35 -55
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/editor/Editor.js +12 -1
- 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/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 +35 -55
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/editor/Editor.mjs +12 -1
- 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/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 +59 -82
- package/src/lib/editor/bindings/BindingUtil.ts +9 -15
- package/src/lib/editor/derivations/bindingsIndex.ts +2 -2
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +4 -14
- 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 +8 -5
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +3 -1
- package/src/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.ts +1 -2
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +3 -3
- package/src/lib/exports/getSvgJsx.test.ts +19 -10
- package/src/lib/exports/getSvgJsx.tsx +5 -2
- 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(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": "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<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": "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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-
|
|
1
|
+
const version = "4.3.0-next.2b3bfbba757b";
|
|
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-25T08:43:48.918Z",
|
|
5
|
+
patch: "2025-11-25T08:43:48.918Z"
|
|
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-
|
|
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.2b3bfbba757b'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-11-25T08:43:48.918Z',\n\tpatch: '2025-11-25T08:43:48.918Z',\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-
|
|
4
|
+
"version": "4.3.0-next.2b3bfbba757b",
|
|
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": "
|
|
51
|
-
"@tiptap/pm": "
|
|
52
|
-
"@tiptap/react": "
|
|
53
|
-
"@tldraw/state": "4.3.0-
|
|
54
|
-
"@tldraw/state-react": "4.3.0-
|
|
55
|
-
"@tldraw/store": "4.3.0-
|
|
56
|
-
"@tldraw/tlschema": "4.3.0-
|
|
57
|
-
"@tldraw/utils": "4.3.0-
|
|
58
|
-
"@tldraw/validate": "4.3.0-
|
|
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.2b3bfbba757b",
|
|
54
|
+
"@tldraw/state-react": "4.3.0-next.2b3bfbba757b",
|
|
55
|
+
"@tldraw/store": "4.3.0-next.2b3bfbba757b",
|
|
56
|
+
"@tldraw/tlschema": "4.3.0-next.2b3bfbba757b",
|
|
57
|
+
"@tldraw/utils": "4.3.0-next.2b3bfbba757b",
|
|
58
|
+
"@tldraw/validate": "4.3.0-next.2b3bfbba757b",
|
|
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
|
+
TLBaseShape,
|
|
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
|
-
|
|
16
|
+
type ICustomShape = TLBaseShape<
|
|
17
|
+
'my-custom-shape',
|
|
18
|
+
{
|
|
19
|
+
w: number
|
|
20
|
+
h: number
|
|
21
|
+
text: string | undefined
|
|
22
|
+
isFilled: boolean
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
type ICustomShape = TLShape<typeof MY_CUSTOM_SHAPE_TYPE>
|
|
24
|
+
>
|
|
25
25
|
|
|
26
26
|
class CustomShape extends ShapeUtil<ICustomShape> {
|
|
27
|
-
static override type =
|
|
27
|
+
static override type = 'my-custom-shape' as const
|
|
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,6 +21,7 @@ import {
|
|
|
21
21
|
PageRecordType,
|
|
22
22
|
StyleProp,
|
|
23
23
|
StylePropValue,
|
|
24
|
+
TLArrowShape,
|
|
24
25
|
TLAsset,
|
|
25
26
|
TLAssetId,
|
|
26
27
|
TLAssetPartial,
|
|
@@ -29,12 +30,12 @@ import {
|
|
|
29
30
|
TLBindingId,
|
|
30
31
|
TLBindingUpdate,
|
|
31
32
|
TLCamera,
|
|
32
|
-
TLCreateShapePartial,
|
|
33
33
|
TLCursor,
|
|
34
34
|
TLCursorType,
|
|
35
35
|
TLDOCUMENT_ID,
|
|
36
36
|
TLDocument,
|
|
37
37
|
TLFrameShape,
|
|
38
|
+
TLGeoShape,
|
|
38
39
|
TLGroupShape,
|
|
39
40
|
TLHandle,
|
|
40
41
|
TLINSTANCE_ID,
|
|
@@ -42,6 +43,7 @@ import {
|
|
|
42
43
|
TLInstance,
|
|
43
44
|
TLInstancePageState,
|
|
44
45
|
TLInstancePresence,
|
|
46
|
+
TLNoteShape,
|
|
45
47
|
TLPOINTER_ID,
|
|
46
48
|
TLPage,
|
|
47
49
|
TLPageId,
|
|
@@ -52,6 +54,8 @@ import {
|
|
|
52
54
|
TLShapePartial,
|
|
53
55
|
TLStore,
|
|
54
56
|
TLStoreSnapshot,
|
|
57
|
+
TLUnknownBinding,
|
|
58
|
+
TLUnknownShape,
|
|
55
59
|
TLVideoAsset,
|
|
56
60
|
createBindingId,
|
|
57
61
|
createShapeId,
|
|
@@ -443,7 +447,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
443
447
|
let deletedBindings = new Map<TLBindingId, BindingOnDeleteOptions<any>>()
|
|
444
448
|
const deletedShapeIds = new Set<TLShapeId>()
|
|
445
449
|
const invalidParents = new Set<TLShapeId>()
|
|
446
|
-
let invalidBindingTypes = new Set<
|
|
450
|
+
let invalidBindingTypes = new Set<string>()
|
|
447
451
|
this.disposables.add(
|
|
448
452
|
this.sideEffects.registerOperationCompleteHandler(() => {
|
|
449
453
|
// this needs to be cleared here because further effects may delete more shapes
|
|
@@ -706,7 +710,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
706
710
|
if (filtered.length > 0) {
|
|
707
711
|
const commonGroupAncestor = this.findCommonAncestor(
|
|
708
712
|
compact(filtered.map((id) => this.getShape(id))),
|
|
709
|
-
(shape) => this.isShapeOfType(shape, 'group')
|
|
713
|
+
(shape) => this.isShapeOfType<TLGroupShape>(shape, 'group')
|
|
710
714
|
)
|
|
711
715
|
|
|
712
716
|
if (commonGroupAncestor) {
|
|
@@ -978,7 +982,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
978
982
|
*
|
|
979
983
|
* @public
|
|
980
984
|
*/
|
|
981
|
-
shapeUtils: { readonly [K in string]?: ShapeUtil<
|
|
985
|
+
shapeUtils: { readonly [K in string]?: ShapeUtil<TLUnknownShape> }
|
|
982
986
|
|
|
983
987
|
styleProps: { [key: string]: Map<StyleProp<any>, string> }
|
|
984
988
|
|
|
@@ -997,8 +1001,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
997
1001
|
*
|
|
998
1002
|
* @public
|
|
999
1003
|
*/
|
|
1000
|
-
getShapeUtil<
|
|
1001
|
-
getShapeUtil<S extends
|
|
1004
|
+
getShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): ShapeUtil<S>
|
|
1005
|
+
getShapeUtil<S extends TLUnknownShape>(type: S['type']): ShapeUtil<S>
|
|
1002
1006
|
getShapeUtil<T extends ShapeUtil>(type: T extends ShapeUtil<infer R> ? R['type'] : string): T
|
|
1003
1007
|
getShapeUtil(arg: string | { type: string }) {
|
|
1004
1008
|
const type = typeof arg === 'string' ? arg : arg.type
|
|
@@ -1012,8 +1016,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1012
1016
|
*
|
|
1013
1017
|
* @param shape - A shape, shape partial, or shape type.
|
|
1014
1018
|
*/
|
|
1015
|
-
hasShapeUtil(shape:
|
|
1016
|
-
hasShapeUtil(type:
|
|
1019
|
+
hasShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): boolean
|
|
1020
|
+
hasShapeUtil<S extends TLUnknownShape>(type: S['type']): boolean
|
|
1017
1021
|
hasShapeUtil<T extends ShapeUtil>(
|
|
1018
1022
|
type: T extends ShapeUtil<infer R> ? R['type'] : string
|
|
1019
1023
|
): boolean
|
|
@@ -1028,7 +1032,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1028
1032
|
*
|
|
1029
1033
|
* @public
|
|
1030
1034
|
*/
|
|
1031
|
-
bindingUtils: { readonly [K in string]?: BindingUtil<
|
|
1035
|
+
bindingUtils: { readonly [K in string]?: BindingUtil<TLUnknownBinding> }
|
|
1032
1036
|
|
|
1033
1037
|
/**
|
|
1034
1038
|
* Get a binding util from a binding itself.
|
|
@@ -1045,8 +1049,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1045
1049
|
*
|
|
1046
1050
|
* @public
|
|
1047
1051
|
*/
|
|
1048
|
-
getBindingUtil<
|
|
1049
|
-
getBindingUtil<S extends
|
|
1052
|
+
getBindingUtil<S extends TLUnknownBinding>(binding: S | { type: S['type'] }): BindingUtil<S>
|
|
1053
|
+
getBindingUtil<S extends TLUnknownBinding>(type: S['type']): BindingUtil<S>
|
|
1050
1054
|
getBindingUtil<T extends BindingUtil>(
|
|
1051
1055
|
type: T extends BindingUtil<infer R> ? R['type'] : string
|
|
1052
1056
|
): T
|
|
@@ -2216,7 +2220,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2216
2220
|
throw Error(`Editor.setFocusedGroup: Shape with id ${id} does not exist`)
|
|
2217
2221
|
}
|
|
2218
2222
|
|
|
2219
|
-
if (!this.isShapeOfType(shape, 'group')) {
|
|
2223
|
+
if (!this.isShapeOfType<TLGroupShape>(shape, 'group')) {
|
|
2220
2224
|
throw Error(
|
|
2221
2225
|
`Editor.setFocusedGroup: Cannot set focused group to shape of type ${shape.type}`
|
|
2222
2226
|
)
|
|
@@ -2244,7 +2248,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2244
2248
|
if (focusedGroup) {
|
|
2245
2249
|
// If we have a focused layer, look for an ancestor of the focused shape that is a group
|
|
2246
2250
|
const match = this.findShapeAncestor(focusedGroup, (shape) =>
|
|
2247
|
-
this.isShapeOfType(shape, 'group')
|
|
2251
|
+
this.isShapeOfType<TLGroupShape>(shape, 'group')
|
|
2248
2252
|
)
|
|
2249
2253
|
// If we have an ancestor that can become a focused layer, set it as the focused layer
|
|
2250
2254
|
this.setFocusedGroup(match?.id ?? null)
|
|
@@ -5123,10 +5127,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5123
5127
|
|
|
5124
5128
|
// Check labels first
|
|
5125
5129
|
if (
|
|
5126
|
-
this.isShapeOfType(shape, 'frame') ||
|
|
5127
|
-
((this.isShapeOfType(shape, 'note') ||
|
|
5128
|
-
this.isShapeOfType(shape, 'arrow') ||
|
|
5129
|
-
(this.isShapeOfType(shape, 'geo') && shape.props.fill === 'none')) &&
|
|
5130
|
+
this.isShapeOfType<TLFrameShape>(shape, 'frame') ||
|
|
5131
|
+
((this.isShapeOfType<TLNoteShape>(shape, 'note') ||
|
|
5132
|
+
this.isShapeOfType<TLArrowShape>(shape, 'arrow') ||
|
|
5133
|
+
(this.isShapeOfType<TLGeoShape>(shape, 'geo') && shape.props.fill === 'none')) &&
|
|
5130
5134
|
this.getShapeUtil(shape).getText(shape)?.trim())
|
|
5131
5135
|
) {
|
|
5132
5136
|
for (const childGeometry of (geometry as Group2d).children) {
|
|
@@ -5136,7 +5140,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5136
5140
|
}
|
|
5137
5141
|
}
|
|
5138
5142
|
|
|
5139
|
-
if (this.isShapeOfType(shape, 'frame')) {
|
|
5143
|
+
if (this.isShapeOfType<TLFrameShape>(shape, 'frame')) {
|
|
5140
5144
|
// On the rare case that we've hit a frame (not its label), test again hitInside to be forced true;
|
|
5141
5145
|
// this prevents clicks from passing through the body of a frame to shapes behind it.
|
|
5142
5146
|
|
|
@@ -5417,7 +5421,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5417
5421
|
*
|
|
5418
5422
|
* @example
|
|
5419
5423
|
* ```ts
|
|
5420
|
-
* const isArrowShape = isShapeOfType(someShape, 'arrow')
|
|
5424
|
+
* const isArrowShape = isShapeOfType<TLArrowShape>(someShape, 'arrow')
|
|
5421
5425
|
* ```
|
|
5422
5426
|
*
|
|
5423
5427
|
* @param util - the TLShapeUtil constructor to test against
|
|
@@ -5425,16 +5429,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5425
5429
|
*
|
|
5426
5430
|
* @public
|
|
5427
5431
|
*/
|
|
5428
|
-
isShapeOfType<
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5432
|
+
isShapeOfType<T extends TLUnknownShape>(shape: TLUnknownShape, type: T['type']): shape is T
|
|
5433
|
+
isShapeOfType<T extends TLUnknownShape>(
|
|
5434
|
+
shapeId: TLUnknownShape['id'],
|
|
5435
|
+
type: T['type']
|
|
5436
|
+
): shapeId is T['id']
|
|
5437
|
+
isShapeOfType<T extends TLUnknownShape>(
|
|
5438
|
+
arg: TLUnknownShape | TLUnknownShape['id'],
|
|
5434
5439
|
type: T['type']
|
|
5435
|
-
)
|
|
5436
|
-
isShapeOfType<T extends TLShape = TLShape>(shapeId: TLShapeId, type: T['type']): boolean
|
|
5437
|
-
isShapeOfType(arg: TLShape | TLShapeId, type: TLShape['type']) {
|
|
5440
|
+
) {
|
|
5438
5441
|
const shape = typeof arg === 'string' ? this.getShape(arg) : arg
|
|
5439
5442
|
if (!shape) return false
|
|
5440
5443
|
return shape.type === type
|
|
@@ -5830,7 +5833,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5830
5833
|
|
|
5831
5834
|
while (node) {
|
|
5832
5835
|
if (
|
|
5833
|
-
this.isShapeOfType(node, 'group') &&
|
|
5836
|
+
this.isShapeOfType<TLGroupShape>(node, 'group') &&
|
|
5834
5837
|
focusedGroup?.id !== node.id &&
|
|
5835
5838
|
!this.hasAncestor(focusedGroup, node.id) &&
|
|
5836
5839
|
(filter?.(node) ?? true)
|
|
@@ -5872,15 +5875,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5872
5875
|
* Get all bindings of a certain type _from_ a particular shape. These are the bindings whose
|
|
5873
5876
|
* `fromId` matched the shape's ID.
|
|
5874
5877
|
*/
|
|
5875
|
-
getBindingsFromShape<
|
|
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>(
|
|
5878
|
+
getBindingsFromShape<Binding extends TLUnknownBinding = TLBinding>(
|
|
5884
5879
|
shape: TLShape | TLShapeId,
|
|
5885
5880
|
type: Binding['type']
|
|
5886
5881
|
): Binding[] {
|
|
@@ -5894,15 +5889,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5894
5889
|
* Get all bindings of a certain type _to_ a particular shape. These are the bindings whose
|
|
5895
5890
|
* `toId` matches the shape's ID.
|
|
5896
5891
|
*/
|
|
5897
|
-
getBindingsToShape<
|
|
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>(
|
|
5892
|
+
getBindingsToShape<Binding extends TLUnknownBinding = TLBinding>(
|
|
5906
5893
|
shape: TLShape | TLShapeId,
|
|
5907
5894
|
type: Binding['type']
|
|
5908
5895
|
): Binding[] {
|
|
@@ -5916,15 +5903,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5916
5903
|
* Get all bindings involving a particular shape. This includes bindings where the shape is the
|
|
5917
5904
|
* `fromId` or `toId`. If a type is provided, only bindings of that type are returned.
|
|
5918
5905
|
*/
|
|
5919
|
-
getBindingsInvolvingShape<
|
|
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>(
|
|
5906
|
+
getBindingsInvolvingShape<Binding extends TLUnknownBinding = TLBinding>(
|
|
5928
5907
|
shape: TLShape | TLShapeId,
|
|
5929
5908
|
type?: Binding['type']
|
|
5930
5909
|
): Binding[] {
|
|
@@ -5946,7 +5925,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5946
5925
|
if (!fromShape || !toShape) continue
|
|
5947
5926
|
if (!this.canBindShapes({ fromShape, toShape, binding: partial })) continue
|
|
5948
5927
|
|
|
5949
|
-
const util = this.getBindingUtil(partial.type)
|
|
5928
|
+
const util = this.getBindingUtil<TLUnknownBinding>(partial.type)
|
|
5950
5929
|
const defaultProps = util.getDefaultProps()
|
|
5951
5930
|
const binding = this.store.schema.types.binding.create({
|
|
5952
5931
|
...partial,
|
|
@@ -6051,7 +6030,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6051
6030
|
const toShapeType = typeof toShape === 'string' ? toShape : toShape.type
|
|
6052
6031
|
const bindingType = typeof binding === 'string' ? binding : binding.type
|
|
6053
6032
|
|
|
6054
|
-
const canBindOpts = { fromShapeType, toShapeType, bindingType }
|
|
6033
|
+
const canBindOpts = { fromShapeType, toShapeType, bindingType }
|
|
6055
6034
|
|
|
6056
6035
|
if (fromShapeType === toShapeType) {
|
|
6057
6036
|
return this.getShapeUtil(fromShapeType).canBind(canBindOpts)
|
|
@@ -6592,7 +6571,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6592
6571
|
const shapesToFlipFirstPass = compact(ids.map((id) => this.getShape(id)))
|
|
6593
6572
|
|
|
6594
6573
|
for (const shape of shapesToFlipFirstPass) {
|
|
6595
|
-
if (this.isShapeOfType(shape, 'group')) {
|
|
6574
|
+
if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
|
|
6596
6575
|
const childrenOfGroups = compact(
|
|
6597
6576
|
this.getSortedChildIdsForParent(shape.id).map((id) => this.getShape(id))
|
|
6598
6577
|
)
|
|
@@ -7713,7 +7692,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7713
7692
|
*
|
|
7714
7693
|
* @public
|
|
7715
7694
|
*/
|
|
7716
|
-
canCreateShape
|
|
7695
|
+
canCreateShape<T extends TLUnknownShape>(
|
|
7696
|
+
shape: OptionalKeys<TLShapePartial<T>, 'id'> | T['id']
|
|
7697
|
+
): boolean {
|
|
7717
7698
|
return this.canCreateShapes([shape])
|
|
7718
7699
|
}
|
|
7719
7700
|
|
|
@@ -7724,8 +7705,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7724
7705
|
*
|
|
7725
7706
|
* @public
|
|
7726
7707
|
*/
|
|
7727
|
-
canCreateShapes(
|
|
7728
|
-
shapes: (
|
|
7708
|
+
canCreateShapes<T extends TLUnknownShape>(
|
|
7709
|
+
shapes: (T['id'] | OptionalKeys<TLShapePartial<T>, 'id'>)[]
|
|
7729
7710
|
): boolean {
|
|
7730
7711
|
return shapes.length + this.getCurrentPageShapeIds().size <= this.options.maxShapesPerPage
|
|
7731
7712
|
}
|
|
@@ -7743,7 +7724,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7743
7724
|
*
|
|
7744
7725
|
* @public
|
|
7745
7726
|
*/
|
|
7746
|
-
createShape<
|
|
7727
|
+
createShape<T extends TLUnknownShape>(shape: OptionalKeys<TLShapePartial<T>, 'id'>): this {
|
|
7747
7728
|
this.createShapes([shape])
|
|
7748
7729
|
return this
|
|
7749
7730
|
}
|
|
@@ -7761,7 +7742,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7761
7742
|
*
|
|
7762
7743
|
* @public
|
|
7763
7744
|
*/
|
|
7764
|
-
createShapes<
|
|
7745
|
+
createShapes<T extends TLUnknownShape>(shapes: OptionalKeys<TLShapePartial<T>, 'id'>[]): this {
|
|
7765
7746
|
if (!Array.isArray(shapes)) {
|
|
7766
7747
|
throw Error('Editor.createShapes: must provide an array of shapes or shape partials')
|
|
7767
7748
|
}
|
|
@@ -8142,7 +8123,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8142
8123
|
const highestIndex = shapesWithRootParent[shapesWithRootParent.length - 1]?.index
|
|
8143
8124
|
|
|
8144
8125
|
this.run(() => {
|
|
8145
|
-
this.createShapes([
|
|
8126
|
+
this.createShapes<TLGroupShape>([
|
|
8146
8127
|
{
|
|
8147
8128
|
id: groupId,
|
|
8148
8129
|
type: 'group',
|
|
@@ -8212,7 +8193,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8212
8193
|
const groups: TLGroupShape[] = []
|
|
8213
8194
|
|
|
8214
8195
|
shapesToUngroup.forEach((shape) => {
|
|
8215
|
-
if (this.isShapeOfType(shape, 'group')) {
|
|
8196
|
+
if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
|
|
8216
8197
|
groups.push(shape)
|
|
8217
8198
|
} else {
|
|
8218
8199
|
idsToSelect.add(shape.id)
|
|
@@ -8258,7 +8239,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8258
8239
|
*
|
|
8259
8240
|
* @public
|
|
8260
8241
|
*/
|
|
8261
|
-
updateShape<T extends
|
|
8242
|
+
updateShape<T extends TLUnknownShape>(partial: TLShapePartial<T> | null | undefined) {
|
|
8262
8243
|
this.updateShapes([partial])
|
|
8263
8244
|
return this
|
|
8264
8245
|
}
|
|
@@ -8275,7 +8256,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8275
8256
|
*
|
|
8276
8257
|
* @public
|
|
8277
8258
|
*/
|
|
8278
|
-
updateShapes<T extends
|
|
8259
|
+
updateShapes<T extends TLUnknownShape>(partials: (TLShapePartial<T> | null | undefined)[]) {
|
|
8279
8260
|
const compactedPartials: TLShapePartial<T>[] = Array(partials.length)
|
|
8280
8261
|
|
|
8281
8262
|
for (let i = 0, n = partials.length; i < n; i++) {
|
|
@@ -8427,7 +8408,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8427
8408
|
* @internal
|
|
8428
8409
|
*/
|
|
8429
8410
|
private _extractSharedStyles(shape: TLShape, sharedStyleMap: SharedStyleMap) {
|
|
8430
|
-
if (this.isShapeOfType(shape, 'group')) {
|
|
8411
|
+
if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
|
|
8431
8412
|
// For groups, ignore the styles of the group shape and instead include the styles of the
|
|
8432
8413
|
// group's children. These are the shapes that would have their styles changed if the
|
|
8433
8414
|
// user called `setStyle` on the current selection.
|
|
@@ -8547,7 +8528,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8547
8528
|
// For groups, ignore the opacity of the group shape and instead include
|
|
8548
8529
|
// the opacity of the group's children. These are the shapes that would have
|
|
8549
8530
|
// their opacity changed if the user called `setOpacity` on the current selection.
|
|
8550
|
-
if (this.isShapeOfType(shape, 'group')) {
|
|
8531
|
+
if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
|
|
8551
8532
|
for (const childId of this.getSortedChildIdsForParent(shape.id)) {
|
|
8552
8533
|
addShape(childId)
|
|
8553
8534
|
}
|
|
@@ -8608,7 +8589,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8608
8589
|
// We can have many deep levels of grouped shape
|
|
8609
8590
|
// Making a recursive function to look through all the levels
|
|
8610
8591
|
const addShapeById = (shape: TLShape) => {
|
|
8611
|
-
if (this.isShapeOfType(shape, 'group')) {
|
|
8592
|
+
if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
|
|
8612
8593
|
const childIds = this.getSortedChildIdsForParent(shape)
|
|
8613
8594
|
for (const childId of childIds) {
|
|
8614
8595
|
addShapeById(this.getShape(childId)!)
|
|
@@ -8692,7 +8673,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8692
8673
|
// We can have many deep levels of grouped shape
|
|
8693
8674
|
// Making a recursive function to look through all the levels
|
|
8694
8675
|
const addShapeById = (shape: TLShape) => {
|
|
8695
|
-
if (this.isShapeOfType(shape, 'group')) {
|
|
8676
|
+
if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
|
|
8696
8677
|
const childIds = this.getSortedChildIdsForParent(shape.id)
|
|
8697
8678
|
for (const childId of childIds) {
|
|
8698
8679
|
addShapeById(this.getShape(childId)!)
|
|
@@ -9117,7 +9098,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9117
9098
|
for (const shape of this.getSelectedShapes()) {
|
|
9118
9099
|
if (lowestDepth === 0) break
|
|
9119
9100
|
|
|
9120
|
-
const isFrame = this.isShapeOfType(shape, 'frame')
|
|
9101
|
+
const isFrame = this.isShapeOfType<TLFrameShape>(shape, 'frame')
|
|
9121
9102
|
const ancestors = this.getShapeAncestors(shape)
|
|
9122
9103
|
if (isFrame) ancestors.push(shape)
|
|
9123
9104
|
|
|
@@ -9156,8 +9137,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9156
9137
|
if (rootShapeIds.length === 1) {
|
|
9157
9138
|
const rootShape = shapes.find((s) => s.id === rootShapeIds[0])!
|
|
9158
9139
|
if (
|
|
9159
|
-
this.isShapeOfType(parent, 'frame') &&
|
|
9160
|
-
this.isShapeOfType(rootShape, 'frame') &&
|
|
9140
|
+
this.isShapeOfType<TLFrameShape>(parent, 'frame') &&
|
|
9141
|
+
this.isShapeOfType<TLFrameShape>(rootShape, 'frame') &&
|
|
9161
9142
|
rootShape.props.w === parent?.props.w &&
|
|
9162
9143
|
rootShape.props.h === parent?.props.h
|
|
9163
9144
|
) {
|
|
@@ -9332,11 +9313,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9332
9313
|
const onlyRoot = rootShapes[0] as TLFrameShape
|
|
9333
9314
|
// If the old bounds are in the viewport...
|
|
9334
9315
|
// todo: replace frame references with shapes that can accept children
|
|
9335
|
-
if (this.isShapeOfType(onlyRoot, 'frame')) {
|
|
9316
|
+
if (this.isShapeOfType<TLFrameShape>(onlyRoot, 'frame')) {
|
|
9336
9317
|
while (
|
|
9337
9318
|
this.getShapesAtPoint(point).some(
|
|
9338
9319
|
(shape) =>
|
|
9339
|
-
this.isShapeOfType(shape, 'frame') &&
|
|
9320
|
+
this.isShapeOfType<TLFrameShape>(shape, 'frame') &&
|
|
9340
9321
|
shape.props.w === onlyRoot.props.w &&
|
|
9341
9322
|
shape.props.h === onlyRoot.props.h
|
|
9342
9323
|
)
|
|
@@ -10251,7 +10232,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10251
10232
|
}
|
|
10252
10233
|
}
|
|
10253
10234
|
|
|
10254
|
-
this.emit('event', info)
|
|
10255
10235
|
this.root.handleEvent(info)
|
|
10256
10236
|
return
|
|
10257
10237
|
}
|
|
@@ -10750,10 +10730,7 @@ function alertMaxShapes(editor: Editor, pageId = editor.getCurrentPageId()) {
|
|
|
10750
10730
|
|
|
10751
10731
|
function applyPartialToRecordWithProps<
|
|
10752
10732
|
T extends UnknownRecord & { type: string; props: object; meta: object },
|
|
10753
|
-
>(
|
|
10754
|
-
prev: T,
|
|
10755
|
-
partial?: T extends T ? Omit<Partial<T>, 'props'> & { props?: Partial<T['props']> } : never
|
|
10756
|
-
): T {
|
|
10733
|
+
>(prev: T, partial?: Partial<T> & { props?: Partial<T['props']> }): T {
|
|
10757
10734
|
if (!partial) return prev
|
|
10758
10735
|
let next = null as null | T
|
|
10759
10736
|
const entries = Object.entries(partial)
|