tldraw 4.3.0 → 4.4.0-canary.29afdff6bb04
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.js +1 -1
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +1 -8
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
- package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +8 -1
- package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js +14 -1
- package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js.map +3 -3
- package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js +15 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js.map +3 -3
- package/dist-cjs/lib/ui/components/DefaultDebugPanel.js +1 -1
- package/dist-cjs/lib/ui/components/DefaultDebugPanel.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +1 -8
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +9 -1
- package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs +14 -1
- package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs.map +3 -3
- package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs +16 -2
- package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs.map +3 -3
- package/dist-esm/lib/ui/components/DefaultDebugPanel.mjs +1 -1
- package/dist-esm/lib/ui/components/DefaultDebugPanel.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +3 -3
- package/src/lib/shapes/frame/FrameShapeUtil.tsx +1 -7
- package/src/lib/tools/EraserTool/childStates/Erasing.ts +14 -1
- package/src/lib/tools/SelectTool/childStates/Brushing.ts +22 -3
- package/src/lib/tools/SelectTool/childStates/ScribbleBrushing.ts +25 -4
- package/src/lib/ui/components/DefaultDebugPanel.tsx +1 -1
- package/src/lib/ui/version.ts +3 -3
- package/src/test/notVisibleShapes.test.ts +698 -0
package/dist-cjs/index.js
CHANGED
|
@@ -592,7 +592,7 @@ var import_buildFromV1Document = require("./lib/utils/tldr/buildFromV1Document")
|
|
|
592
592
|
var import_file = require("./lib/utils/tldr/file");
|
|
593
593
|
(0, import_editor.registerTldrawLibraryVersion)(
|
|
594
594
|
"tldraw",
|
|
595
|
-
"4.
|
|
595
|
+
"4.4.0-canary.29afdff6bb04",
|
|
596
596
|
"cjs"
|
|
597
597
|
);
|
|
598
598
|
//# sourceMappingURL=index.js.map
|
|
@@ -255,14 +255,7 @@ class FrameShapeUtil extends import_editor.BaseBoxShapeUtil {
|
|
|
255
255
|
] });
|
|
256
256
|
}
|
|
257
257
|
indicator(shape) {
|
|
258
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
259
|
-
"rect",
|
|
260
|
-
{
|
|
261
|
-
width: (0, import_editor.toDomPrecision)(shape.props.w),
|
|
262
|
-
height: (0, import_editor.toDomPrecision)(shape.props.h),
|
|
263
|
-
className: `tl-frame-indicator`
|
|
264
|
-
}
|
|
265
|
-
);
|
|
258
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { width: (0, import_editor.toDomPrecision)(shape.props.w), height: (0, import_editor.toDomPrecision)(shape.props.h) });
|
|
266
259
|
}
|
|
267
260
|
providesBackgroundForChildren() {
|
|
268
261
|
return true;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/frame/FrameShapeUtil.tsx"],
|
|
4
|
-
"sourcesContent": ["import {\n\tBaseBoxShapeUtil,\n\tDefaultColorStyle,\n\tGeometry2d,\n\tGroup2d,\n\tRectangle2d,\n\tSVGContainer,\n\tSvgExportContext,\n\tTLClickEventInfo,\n\tTLDragShapesOutInfo,\n\tTLDragShapesOverInfo,\n\tTLEditStartInfo,\n\tTLFrameShape,\n\tTLFrameShapeProps,\n\tTLResizeInfo,\n\tTLShape,\n\tTLShapePartial,\n\tTLShapeUtilConstructor,\n\tclamp,\n\tcompact,\n\tframeShapeMigrations,\n\tframeShapeProps,\n\tgetColorValue,\n\tgetDefaultColorTheme,\n\tlerp,\n\tresizeBox,\n\ttoDomPrecision,\n\tuseValue,\n} from '@tldraw/editor'\nimport classNames from 'classnames'\nimport { fitFrameToContent, getFrameChildrenBounds } from '../../utils/frames/frames'\nimport {\n\tTLCreateTextJsxFromSpansOpts,\n\tcreateTextJsxFromSpans,\n} from '../shared/createTextJsxFromSpans'\nimport { useDefaultColorTheme } from '../shared/useDefaultColorTheme'\nimport { FrameHeading } from './components/FrameHeading'\nimport {\n\tgetFrameHeadingOpts,\n\tgetFrameHeadingSide,\n\tgetFrameHeadingSize,\n\tgetFrameHeadingTranslation,\n} from './frameHelpers'\n\n// Some of these values are repeated in CSS and need to match\nconst FRAME_HEADING_EXTRA_WIDTH = 12\nconst FRAME_HEADING_MIN_WIDTH = 32\nconst FRAME_HEADING_NOCOLORS_OFFSET_X = -7\nconst FRAME_HEADING_OFFSET_Y = 4\n\n/** @public */\nexport interface FrameShapeOptions {\n\t/**\n\t * When true, the frame will display colors for the shape's headings and background.\n\t */\n\tshowColors: boolean\n\t/**\n\t * When true, the frame will resize its children when the frame itself is resized.\n\t */\n\tresizeChildren: boolean\n}\n\nexport function defaultEmptyAs(str: string, dflt: string) {\n\tif (str.match(/^\\s*$/)) {\n\t\treturn dflt\n\t}\n\treturn str\n}\n\n/** @public */\nexport class FrameShapeUtil extends BaseBoxShapeUtil<TLFrameShape> {\n\tstatic override type = 'frame' as const\n\tstatic override props = frameShapeProps\n\tstatic override migrations = frameShapeMigrations\n\n\toverride options: FrameShapeOptions = {\n\t\tshowColors: false,\n\t\tresizeChildren: false,\n\t}\n\n\t// evil crimes :)\n\t// By default, showColors is off. Because they use style props, which are picked up\n\t// automatically, we don't have DefaultColorStyle in the props in the schema by default.\n\t// Instead, when someone calls .configure to turn the option on, we manually add in the color\n\t// style here so it plays nicely with the other editor APIs.\n\tstatic override configure<T extends TLShapeUtilConstructor<any, any>>(\n\t\tthis: T,\n\t\toptions: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never\n\t): T {\n\t\tconst withOptions = super.configure.call(this, options) as T\n\t\tif ((options as any).showColors) {\n\t\t\t;(withOptions as any).props = { ...withOptions.props, color: DefaultColorStyle }\n\t\t}\n\t\treturn withOptions\n\t}\n\n\toverride canEdit(shape: TLFrameShape, info: TLEditStartInfo) {\n\t\treturn info.type === 'click-header' || info.type === 'unknown'\n\t}\n\n\toverride canResize() {\n\t\treturn true\n\t}\n\n\toverride canResizeChildren() {\n\t\treturn this.options.resizeChildren\n\t}\n\n\toverride isExportBoundsContainer(): boolean {\n\t\treturn true\n\t}\n\n\toverride getDefaultProps(): TLFrameShape['props'] {\n\t\treturn { w: 160 * 2, h: 90 * 2, name: '', color: 'black' }\n\t}\n\n\toverride getAriaDescriptor(shape: TLFrameShape) {\n\t\treturn shape.props.name\n\t}\n\n\toverride getGeometry(shape: TLFrameShape): Geometry2d {\n\t\tconst { editor } = this\n\n\t\tconst z = editor.getEfficientZoomLevel()\n\n\t\t// Which dimension measures the top edge after rotation?\n\t\tconst labelSide = getFrameHeadingSide(editor, shape)\n\t\tconst isVertical = labelSide % 2 === 1\n\t\tconst rotatedTopEdgeWidth = isVertical ? shape.props.h : shape.props.w\n\n\t\t// Get the size of the heading (max width equal to the rotatedTopEdgeWidth)\n\t\tconst opts = getFrameHeadingOpts(rotatedTopEdgeWidth, false)\n\t\tconst headingSize = getFrameHeadingSize(editor, shape, opts)\n\n\t\t// If NOT showing frame colors, we need to offset the label\n\t\t// to the left so that the title is in line with the shape edge\n\t\t// and add that extra width to the right side of the label\n\t\tconst isShowingFrameColors = this.options.showColors\n\n\t\t// Scale everything into **screen space**\n\t\tconst extraWidth = FRAME_HEADING_EXTRA_WIDTH / z\n\t\tconst minWidth = FRAME_HEADING_MIN_WIDTH / z\n\t\tconst maxWidth = rotatedTopEdgeWidth + (isShowingFrameColors ? 1 : extraWidth)\n\n\t\tconst labelWidth = headingSize.w / z\n\t\tconst labelHeight = headingSize.h / z\n\n\t\tconst clampedLabelWidth = clamp(labelWidth + extraWidth, minWidth, maxWidth)\n\n\t\tconst offsetX = (isShowingFrameColors ? -1 : FRAME_HEADING_NOCOLORS_OFFSET_X) / z\n\t\tconst offsetY = FRAME_HEADING_OFFSET_Y / z\n\n\t\t// In page space\n\t\tconst width = isVertical ? labelHeight : clampedLabelWidth\n\t\tconst height = isVertical ? clampedLabelWidth : labelHeight\n\n\t\t// Calculate label position based on side. The position needs to always appear\n\t\t// at the top left of the shape, regardless of rotation. The label must be\n\t\t// between a minimum and maximum. The minimum is arbitrary; the maximum is the\n\t\t// width of the edge of the frame where the label will be shown.\n\n\t\tlet x: number, y: number\n\n\t\tswitch (labelSide) {\n\t\t\tcase 0: {\n\t\t\t\t// top\n\t\t\t\tx = offsetX\n\t\t\t\ty = -(labelHeight + offsetY)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 1: {\n\t\t\t\t// right\n\t\t\t\tx = -(labelHeight + offsetY)\n\t\t\t\ty = shape.props.h - (offsetX + clampedLabelWidth)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 2: {\n\t\t\t\t// bottom\n\t\t\t\tx = shape.props.w - (offsetX + clampedLabelWidth)\n\t\t\t\ty = shape.props.h + offsetY\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 3: {\n\t\t\t\t// left\n\t\t\t\tx = shape.props.w + offsetY\n\t\t\t\ty = offsetX\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\treturn new Group2d({\n\t\t\tchildren: [\n\t\t\t\tnew Rectangle2d({\n\t\t\t\t\twidth: shape.props.w,\n\t\t\t\t\theight: shape.props.h,\n\t\t\t\t\tisFilled: false,\n\t\t\t\t}),\n\t\t\t\tnew Rectangle2d({\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\tisFilled: true,\n\t\t\t\t\tisLabel: true,\n\t\t\t\t\texcludeFromShapeBounds: true,\n\t\t\t\t}),\n\t\t\t],\n\t\t})\n\t}\n\n\toverride getText(shape: TLFrameShape): string | undefined {\n\t\treturn shape.props.name\n\t}\n\n\toverride component(shape: TLFrameShape) {\n\t\t// eslint-disable-next-line react-hooks/rules-of-hooks\n\t\tconst theme = useDefaultColorTheme()\n\n\t\t// eslint-disable-next-line react-hooks/rules-of-hooks\n\t\tconst isCreating = useValue(\n\t\t\t'is creating this shape',\n\t\t\t() => {\n\t\t\t\tconst resizingState = this.editor.getStateDescendant('select.resizing')\n\t\t\t\tif (!resizingState) return false\n\t\t\t\tif (!resizingState.getIsActive()) return false\n\t\t\t\tconst info = (resizingState as typeof resizingState & { info: { isCreating: boolean } })\n\t\t\t\t\t?.info\n\t\t\t\tif (!info) return false\n\t\t\t\treturn info.isCreating && this.editor.getOnlySelectedShapeId() === shape.id\n\t\t\t},\n\t\t\t[shape.id]\n\t\t)\n\n\t\tconst showFrameColors = this.options.showColors\n\t\tconst colorToUse = showFrameColors ? shape.props.color : 'black'\n\t\tconst frameFill = getColorValue(theme, colorToUse, 'frameFill')\n\t\tconst frameStroke = getColorValue(theme, colorToUse, 'frameStroke')\n\t\tconst frameHeadingStroke = showFrameColors\n\t\t\t? getColorValue(theme, colorToUse, 'frameHeadingStroke')\n\t\t\t: theme.background\n\t\tconst frameHeadingFill = showFrameColors\n\t\t\t? getColorValue(theme, colorToUse, 'frameHeadingFill')\n\t\t\t: theme.background\n\t\tconst frameHeadingText = getColorValue(theme, colorToUse, 'frameText')\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<SVGContainer>\n\t\t\t\t\t<rect\n\t\t\t\t\t\tclassName={classNames('tl-frame__body', { 'tl-frame__creating': isCreating })}\n\t\t\t\t\t\tfill={frameFill}\n\t\t\t\t\t\tstroke={frameStroke}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\twidth: `calc(${shape.props.w}px + 1px / var(--tl-zoom))`,\n\t\t\t\t\t\t\theight: `calc(${shape.props.h}px + 1px / var(--tl-zoom))`,\n\t\t\t\t\t\t\ttransform: `translate(calc(-0.5px / var(--tl-zoom)), calc(-0.5px / var(--tl-zoom)))`,\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</SVGContainer>\n\t\t\t\t{isCreating ? null : (\n\t\t\t\t\t<FrameHeading\n\t\t\t\t\t\tid={shape.id}\n\t\t\t\t\t\tname={shape.props.name}\n\t\t\t\t\t\tfill={frameHeadingFill}\n\t\t\t\t\t\tstroke={frameHeadingStroke}\n\t\t\t\t\t\tcolor={frameHeadingText}\n\t\t\t\t\t\twidth={shape.props.w}\n\t\t\t\t\t\theight={shape.props.h}\n\t\t\t\t\t\toffsetX={showFrameColors ? -1 : -7}\n\t\t\t\t\t\tshowColors={this.options.showColors}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride toSvg(shape: TLFrameShape, ctx: SvgExportContext) {\n\t\tconst theme = getDefaultColorTheme({ isDarkMode: ctx.isDarkMode })\n\n\t\t// rotate right 45 deg\n\t\tconst labelSide = getFrameHeadingSide(this.editor, shape)\n\t\tconst isVertical = labelSide % 2 === 1\n\t\tconst rotatedTopEdgeWidth = isVertical ? shape.props.h : shape.props.w\n\t\tconst labelTranslate = getFrameHeadingTranslation(shape, labelSide, true)\n\n\t\t// Truncate with ellipsis\n\t\tconst opts: TLCreateTextJsxFromSpansOpts = getFrameHeadingOpts(rotatedTopEdgeWidth - 12, true)\n\n\t\tconst frameTitle = defaultEmptyAs(shape.props.name, 'Frame') + String.fromCharCode(8203)\n\t\tconst labelBounds = getFrameHeadingSize(this.editor, shape, opts)\n\t\tconst spans = this.editor.textMeasure.measureTextSpans(frameTitle, opts)\n\t\tconst text = createTextJsxFromSpans(this.editor, spans, opts)\n\n\t\tconst showFrameColors = this.options.showColors\n\t\tconst colorToUse = showFrameColors ? shape.props.color : 'black'\n\t\tconst frameFill = getColorValue(theme, colorToUse, 'frameFill')\n\t\tconst frameStroke = getColorValue(theme, colorToUse, 'frameStroke')\n\t\tconst frameHeadingStroke = showFrameColors\n\t\t\t? getColorValue(theme, colorToUse, 'frameHeadingStroke')\n\t\t\t: theme.background\n\t\tconst frameHeadingFill = showFrameColors\n\t\t\t? getColorValue(theme, colorToUse, 'frameHeadingFill')\n\t\t\t: theme.background\n\t\tconst frameHeadingText = getColorValue(theme, colorToUse, 'frameText')\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<rect\n\t\t\t\t\twidth={shape.props.w}\n\t\t\t\t\theight={shape.props.h}\n\t\t\t\t\tfill={frameFill}\n\t\t\t\t\tstroke={frameStroke}\n\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\tx={0}\n\t\t\t\t\trx={0}\n\t\t\t\t\try={0}\n\t\t\t\t/>\n\t\t\t\t<g fill={frameHeadingText} transform={labelTranslate}>\n\t\t\t\t\t<rect\n\t\t\t\t\t\tx={labelBounds.x - (showFrameColors ? 0 : 6)}\n\t\t\t\t\t\ty={labelBounds.y - 6}\n\t\t\t\t\t\twidth={Math.min(rotatedTopEdgeWidth, labelBounds.width + 12)}\n\t\t\t\t\t\theight={labelBounds.height}\n\t\t\t\t\t\tfill={frameHeadingFill}\n\t\t\t\t\t\tstroke={frameHeadingStroke}\n\t\t\t\t\t\trx={4}\n\t\t\t\t\t\try={4}\n\t\t\t\t\t/>\n\t\t\t\t\t<g transform={`translate(${showFrameColors ? 8 : 0}, 4)`}>{text}</g>\n\t\t\t\t</g>\n\t\t\t</>\n\t\t)\n\t}\n\n\tindicator(shape: TLFrameShape) {\n\t\treturn (\n\t\t\t<rect\n\t\t\t\twidth={toDomPrecision(shape.props.w)}\n\t\t\t\theight={toDomPrecision(shape.props.h)}\n\t\t\t\tclassName={`tl-frame-indicator`}\n\t\t\t/>\n\t\t)\n\t}\n\n\toverride providesBackgroundForChildren(): boolean {\n\t\treturn true\n\t}\n\n\toverride getClipPath(shape: TLFrameShape) {\n\t\treturn this.editor.getShapeGeometry(shape.id).vertices\n\t}\n\n\toverride canReceiveNewChildrenOfType(shape: TLShape) {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride onResize(shape: any, info: TLResizeInfo<any>) {\n\t\treturn resizeBox(shape, info)\n\t}\n\n\toverride getInterpolatedProps(\n\t\tstartShape: TLFrameShape,\n\t\tendShape: TLFrameShape,\n\t\tt: number\n\t): TLFrameShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\tw: lerp(startShape.props.w, endShape.props.w, t),\n\t\t\th: lerp(startShape.props.h, endShape.props.h, t),\n\t\t}\n\t}\n\n\toverride onDoubleClickEdge(shape: TLFrameShape, info: TLClickEventInfo) {\n\t\tif (info.target !== 'selection') return\n\t\tconst { handle } = info\n\n\t\t// If handle is missing, we can't determine which edge was clicked\n\t\tif (!handle) return\n\n\t\tconst isHorizontalEdge = handle === 'left' || handle === 'right'\n\t\tconst isVerticalEdge = handle === 'top' || handle === 'bottom'\n\n\t\tconst childIds = this.editor.getSortedChildIdsForParent(shape.id)\n\t\tconst children = compact(childIds.map((id) => this.editor.getShape(id)))\n\t\tif (!children.length) return\n\n\t\tconst { dx, dy, w, h } = getFrameChildrenBounds(children, this.editor, { padding: 10 })\n\n\t\tthis.editor.run(() => {\n\t\t\tconst changes: TLShapePartial[] = childIds.map((childId) => {\n\t\t\t\tconst childShape = this.editor.getShape(childId)!\n\t\t\t\treturn {\n\t\t\t\t\tid: childShape.id,\n\t\t\t\t\ttype: childShape.type,\n\t\t\t\t\tx: isHorizontalEdge ? childShape.x + dx : childShape.x,\n\t\t\t\t\ty: isVerticalEdge ? childShape.y + dy : childShape.y,\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tthis.editor.updateShapes(changes)\n\t\t})\n\n\t\treturn {\n\t\t\tid: shape.id,\n\t\t\ttype: shape.type,\n\t\t\tprops: {\n\t\t\t\tw: isHorizontalEdge ? w : shape.props.w,\n\t\t\t\th: isVerticalEdge ? h : shape.props.h,\n\t\t\t},\n\t\t}\n\t}\n\n\toverride onDoubleClickCorner(shape: TLFrameShape) {\n\t\tfitFrameToContent(this.editor, shape.id, { padding: 10 })\n\t\treturn {\n\t\t\tid: shape.id,\n\t\t\ttype: shape.type,\n\t\t}\n\t}\n\n\toverride onDragShapesIn(\n\t\tshape: TLFrameShape,\n\t\tdraggingShapes: TLShape[],\n\t\t{ initialParentIds, initialIndices }: TLDragShapesOverInfo\n\t) {\n\t\tconst { editor } = this\n\n\t\tif (draggingShapes.every((s) => s.parentId === shape.id)) return\n\n\t\t// Check to see whether any of the shapes can have their old index restored\n\t\tlet canRestoreOriginalIndices = false\n\t\tconst previousChildren = draggingShapes.filter((s) => shape.id === initialParentIds.get(s.id))\n\n\t\tif (previousChildren.length > 0) {\n\t\t\tconst currentChildren = compact(\n\t\t\t\teditor.getSortedChildIdsForParent(shape).map((id) => editor.getShape(id))\n\t\t\t)\n\t\t\tif (previousChildren.every((s) => !currentChildren.find((c) => c.index === s.index))) {\n\t\t\t\tcanRestoreOriginalIndices = true\n\t\t\t}\n\t\t}\n\n\t\t// I can't imagine this happening, but if any of the children are the ancestor of the frame, quit here\n\t\tif (draggingShapes.some((s) => editor.hasAncestor(shape, s.id))) return\n\n\t\t// Reparent the shapes to the new parent\n\t\teditor.reparentShapes(draggingShapes, shape.id)\n\n\t\t// If we can restore the original indices, then do so\n\t\tif (canRestoreOriginalIndices) {\n\t\t\tfor (const shape of previousChildren) {\n\t\t\t\teditor.updateShape({\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tindex: initialIndices.get(shape.id),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\toverride onDragShapesOut(\n\t\tshape: TLFrameShape,\n\t\tdraggingShapes: TLShape[],\n\t\tinfo: TLDragShapesOutInfo\n\t): void {\n\t\tconst { editor } = this\n\t\t// When a user drags shapes out of a frame, and if we're not dragging into a new shape, then reparent\n\t\t// the dragging shapes (that are current children of the frame) onto the current page instead\n\t\tif (!info.nextDraggingOverShapeId) {\n\t\t\teditor.reparentShapes(\n\t\t\t\tdraggingShapes.filter(\n\t\t\t\t\t(s) => s.parentId === shape.id && this.canReceiveNewChildrenOfType(s)\n\t\t\t\t),\n\t\t\t\teditor.getCurrentPageId()\n\t\t\t)\n\t\t}\n\t}\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import {\n\tBaseBoxShapeUtil,\n\tDefaultColorStyle,\n\tGeometry2d,\n\tGroup2d,\n\tRectangle2d,\n\tSVGContainer,\n\tSvgExportContext,\n\tTLClickEventInfo,\n\tTLDragShapesOutInfo,\n\tTLDragShapesOverInfo,\n\tTLEditStartInfo,\n\tTLFrameShape,\n\tTLFrameShapeProps,\n\tTLResizeInfo,\n\tTLShape,\n\tTLShapePartial,\n\tTLShapeUtilConstructor,\n\tclamp,\n\tcompact,\n\tframeShapeMigrations,\n\tframeShapeProps,\n\tgetColorValue,\n\tgetDefaultColorTheme,\n\tlerp,\n\tresizeBox,\n\ttoDomPrecision,\n\tuseValue,\n} from '@tldraw/editor'\nimport classNames from 'classnames'\nimport { fitFrameToContent, getFrameChildrenBounds } from '../../utils/frames/frames'\nimport {\n\tTLCreateTextJsxFromSpansOpts,\n\tcreateTextJsxFromSpans,\n} from '../shared/createTextJsxFromSpans'\nimport { useDefaultColorTheme } from '../shared/useDefaultColorTheme'\nimport { FrameHeading } from './components/FrameHeading'\nimport {\n\tgetFrameHeadingOpts,\n\tgetFrameHeadingSide,\n\tgetFrameHeadingSize,\n\tgetFrameHeadingTranslation,\n} from './frameHelpers'\n\n// Some of these values are repeated in CSS and need to match\nconst FRAME_HEADING_EXTRA_WIDTH = 12\nconst FRAME_HEADING_MIN_WIDTH = 32\nconst FRAME_HEADING_NOCOLORS_OFFSET_X = -7\nconst FRAME_HEADING_OFFSET_Y = 4\n\n/** @public */\nexport interface FrameShapeOptions {\n\t/**\n\t * When true, the frame will display colors for the shape's headings and background.\n\t */\n\tshowColors: boolean\n\t/**\n\t * When true, the frame will resize its children when the frame itself is resized.\n\t */\n\tresizeChildren: boolean\n}\n\nexport function defaultEmptyAs(str: string, dflt: string) {\n\tif (str.match(/^\\s*$/)) {\n\t\treturn dflt\n\t}\n\treturn str\n}\n\n/** @public */\nexport class FrameShapeUtil extends BaseBoxShapeUtil<TLFrameShape> {\n\tstatic override type = 'frame' as const\n\tstatic override props = frameShapeProps\n\tstatic override migrations = frameShapeMigrations\n\n\toverride options: FrameShapeOptions = {\n\t\tshowColors: false,\n\t\tresizeChildren: false,\n\t}\n\n\t// evil crimes :)\n\t// By default, showColors is off. Because they use style props, which are picked up\n\t// automatically, we don't have DefaultColorStyle in the props in the schema by default.\n\t// Instead, when someone calls .configure to turn the option on, we manually add in the color\n\t// style here so it plays nicely with the other editor APIs.\n\tstatic override configure<T extends TLShapeUtilConstructor<any, any>>(\n\t\tthis: T,\n\t\toptions: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never\n\t): T {\n\t\tconst withOptions = super.configure.call(this, options) as T\n\t\tif ((options as any).showColors) {\n\t\t\t;(withOptions as any).props = { ...withOptions.props, color: DefaultColorStyle }\n\t\t}\n\t\treturn withOptions\n\t}\n\n\toverride canEdit(shape: TLFrameShape, info: TLEditStartInfo) {\n\t\treturn info.type === 'click-header' || info.type === 'unknown'\n\t}\n\n\toverride canResize() {\n\t\treturn true\n\t}\n\n\toverride canResizeChildren() {\n\t\treturn this.options.resizeChildren\n\t}\n\n\toverride isExportBoundsContainer(): boolean {\n\t\treturn true\n\t}\n\n\toverride getDefaultProps(): TLFrameShape['props'] {\n\t\treturn { w: 160 * 2, h: 90 * 2, name: '', color: 'black' }\n\t}\n\n\toverride getAriaDescriptor(shape: TLFrameShape) {\n\t\treturn shape.props.name\n\t}\n\n\toverride getGeometry(shape: TLFrameShape): Geometry2d {\n\t\tconst { editor } = this\n\n\t\tconst z = editor.getEfficientZoomLevel()\n\n\t\t// Which dimension measures the top edge after rotation?\n\t\tconst labelSide = getFrameHeadingSide(editor, shape)\n\t\tconst isVertical = labelSide % 2 === 1\n\t\tconst rotatedTopEdgeWidth = isVertical ? shape.props.h : shape.props.w\n\n\t\t// Get the size of the heading (max width equal to the rotatedTopEdgeWidth)\n\t\tconst opts = getFrameHeadingOpts(rotatedTopEdgeWidth, false)\n\t\tconst headingSize = getFrameHeadingSize(editor, shape, opts)\n\n\t\t// If NOT showing frame colors, we need to offset the label\n\t\t// to the left so that the title is in line with the shape edge\n\t\t// and add that extra width to the right side of the label\n\t\tconst isShowingFrameColors = this.options.showColors\n\n\t\t// Scale everything into **screen space**\n\t\tconst extraWidth = FRAME_HEADING_EXTRA_WIDTH / z\n\t\tconst minWidth = FRAME_HEADING_MIN_WIDTH / z\n\t\tconst maxWidth = rotatedTopEdgeWidth + (isShowingFrameColors ? 1 : extraWidth)\n\n\t\tconst labelWidth = headingSize.w / z\n\t\tconst labelHeight = headingSize.h / z\n\n\t\tconst clampedLabelWidth = clamp(labelWidth + extraWidth, minWidth, maxWidth)\n\n\t\tconst offsetX = (isShowingFrameColors ? -1 : FRAME_HEADING_NOCOLORS_OFFSET_X) / z\n\t\tconst offsetY = FRAME_HEADING_OFFSET_Y / z\n\n\t\t// In page space\n\t\tconst width = isVertical ? labelHeight : clampedLabelWidth\n\t\tconst height = isVertical ? clampedLabelWidth : labelHeight\n\n\t\t// Calculate label position based on side. The position needs to always appear\n\t\t// at the top left of the shape, regardless of rotation. The label must be\n\t\t// between a minimum and maximum. The minimum is arbitrary; the maximum is the\n\t\t// width of the edge of the frame where the label will be shown.\n\n\t\tlet x: number, y: number\n\n\t\tswitch (labelSide) {\n\t\t\tcase 0: {\n\t\t\t\t// top\n\t\t\t\tx = offsetX\n\t\t\t\ty = -(labelHeight + offsetY)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 1: {\n\t\t\t\t// right\n\t\t\t\tx = -(labelHeight + offsetY)\n\t\t\t\ty = shape.props.h - (offsetX + clampedLabelWidth)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 2: {\n\t\t\t\t// bottom\n\t\t\t\tx = shape.props.w - (offsetX + clampedLabelWidth)\n\t\t\t\ty = shape.props.h + offsetY\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 3: {\n\t\t\t\t// left\n\t\t\t\tx = shape.props.w + offsetY\n\t\t\t\ty = offsetX\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\treturn new Group2d({\n\t\t\tchildren: [\n\t\t\t\tnew Rectangle2d({\n\t\t\t\t\twidth: shape.props.w,\n\t\t\t\t\theight: shape.props.h,\n\t\t\t\t\tisFilled: false,\n\t\t\t\t}),\n\t\t\t\tnew Rectangle2d({\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\tisFilled: true,\n\t\t\t\t\tisLabel: true,\n\t\t\t\t\texcludeFromShapeBounds: true,\n\t\t\t\t}),\n\t\t\t],\n\t\t})\n\t}\n\n\toverride getText(shape: TLFrameShape): string | undefined {\n\t\treturn shape.props.name\n\t}\n\n\toverride component(shape: TLFrameShape) {\n\t\t// eslint-disable-next-line react-hooks/rules-of-hooks\n\t\tconst theme = useDefaultColorTheme()\n\n\t\t// eslint-disable-next-line react-hooks/rules-of-hooks\n\t\tconst isCreating = useValue(\n\t\t\t'is creating this shape',\n\t\t\t() => {\n\t\t\t\tconst resizingState = this.editor.getStateDescendant('select.resizing')\n\t\t\t\tif (!resizingState) return false\n\t\t\t\tif (!resizingState.getIsActive()) return false\n\t\t\t\tconst info = (resizingState as typeof resizingState & { info: { isCreating: boolean } })\n\t\t\t\t\t?.info\n\t\t\t\tif (!info) return false\n\t\t\t\treturn info.isCreating && this.editor.getOnlySelectedShapeId() === shape.id\n\t\t\t},\n\t\t\t[shape.id]\n\t\t)\n\n\t\tconst showFrameColors = this.options.showColors\n\t\tconst colorToUse = showFrameColors ? shape.props.color : 'black'\n\t\tconst frameFill = getColorValue(theme, colorToUse, 'frameFill')\n\t\tconst frameStroke = getColorValue(theme, colorToUse, 'frameStroke')\n\t\tconst frameHeadingStroke = showFrameColors\n\t\t\t? getColorValue(theme, colorToUse, 'frameHeadingStroke')\n\t\t\t: theme.background\n\t\tconst frameHeadingFill = showFrameColors\n\t\t\t? getColorValue(theme, colorToUse, 'frameHeadingFill')\n\t\t\t: theme.background\n\t\tconst frameHeadingText = getColorValue(theme, colorToUse, 'frameText')\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<SVGContainer>\n\t\t\t\t\t<rect\n\t\t\t\t\t\tclassName={classNames('tl-frame__body', { 'tl-frame__creating': isCreating })}\n\t\t\t\t\t\tfill={frameFill}\n\t\t\t\t\t\tstroke={frameStroke}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\twidth: `calc(${shape.props.w}px + 1px / var(--tl-zoom))`,\n\t\t\t\t\t\t\theight: `calc(${shape.props.h}px + 1px / var(--tl-zoom))`,\n\t\t\t\t\t\t\ttransform: `translate(calc(-0.5px / var(--tl-zoom)), calc(-0.5px / var(--tl-zoom)))`,\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</SVGContainer>\n\t\t\t\t{isCreating ? null : (\n\t\t\t\t\t<FrameHeading\n\t\t\t\t\t\tid={shape.id}\n\t\t\t\t\t\tname={shape.props.name}\n\t\t\t\t\t\tfill={frameHeadingFill}\n\t\t\t\t\t\tstroke={frameHeadingStroke}\n\t\t\t\t\t\tcolor={frameHeadingText}\n\t\t\t\t\t\twidth={shape.props.w}\n\t\t\t\t\t\theight={shape.props.h}\n\t\t\t\t\t\toffsetX={showFrameColors ? -1 : -7}\n\t\t\t\t\t\tshowColors={this.options.showColors}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride toSvg(shape: TLFrameShape, ctx: SvgExportContext) {\n\t\tconst theme = getDefaultColorTheme({ isDarkMode: ctx.isDarkMode })\n\n\t\t// rotate right 45 deg\n\t\tconst labelSide = getFrameHeadingSide(this.editor, shape)\n\t\tconst isVertical = labelSide % 2 === 1\n\t\tconst rotatedTopEdgeWidth = isVertical ? shape.props.h : shape.props.w\n\t\tconst labelTranslate = getFrameHeadingTranslation(shape, labelSide, true)\n\n\t\t// Truncate with ellipsis\n\t\tconst opts: TLCreateTextJsxFromSpansOpts = getFrameHeadingOpts(rotatedTopEdgeWidth - 12, true)\n\n\t\tconst frameTitle = defaultEmptyAs(shape.props.name, 'Frame') + String.fromCharCode(8203)\n\t\tconst labelBounds = getFrameHeadingSize(this.editor, shape, opts)\n\t\tconst spans = this.editor.textMeasure.measureTextSpans(frameTitle, opts)\n\t\tconst text = createTextJsxFromSpans(this.editor, spans, opts)\n\n\t\tconst showFrameColors = this.options.showColors\n\t\tconst colorToUse = showFrameColors ? shape.props.color : 'black'\n\t\tconst frameFill = getColorValue(theme, colorToUse, 'frameFill')\n\t\tconst frameStroke = getColorValue(theme, colorToUse, 'frameStroke')\n\t\tconst frameHeadingStroke = showFrameColors\n\t\t\t? getColorValue(theme, colorToUse, 'frameHeadingStroke')\n\t\t\t: theme.background\n\t\tconst frameHeadingFill = showFrameColors\n\t\t\t? getColorValue(theme, colorToUse, 'frameHeadingFill')\n\t\t\t: theme.background\n\t\tconst frameHeadingText = getColorValue(theme, colorToUse, 'frameText')\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<rect\n\t\t\t\t\twidth={shape.props.w}\n\t\t\t\t\theight={shape.props.h}\n\t\t\t\t\tfill={frameFill}\n\t\t\t\t\tstroke={frameStroke}\n\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\tx={0}\n\t\t\t\t\trx={0}\n\t\t\t\t\try={0}\n\t\t\t\t/>\n\t\t\t\t<g fill={frameHeadingText} transform={labelTranslate}>\n\t\t\t\t\t<rect\n\t\t\t\t\t\tx={labelBounds.x - (showFrameColors ? 0 : 6)}\n\t\t\t\t\t\ty={labelBounds.y - 6}\n\t\t\t\t\t\twidth={Math.min(rotatedTopEdgeWidth, labelBounds.width + 12)}\n\t\t\t\t\t\theight={labelBounds.height}\n\t\t\t\t\t\tfill={frameHeadingFill}\n\t\t\t\t\t\tstroke={frameHeadingStroke}\n\t\t\t\t\t\trx={4}\n\t\t\t\t\t\try={4}\n\t\t\t\t\t/>\n\t\t\t\t\t<g transform={`translate(${showFrameColors ? 8 : 0}, 4)`}>{text}</g>\n\t\t\t\t</g>\n\t\t\t</>\n\t\t)\n\t}\n\n\tindicator(shape: TLFrameShape) {\n\t\treturn <rect width={toDomPrecision(shape.props.w)} height={toDomPrecision(shape.props.h)} />\n\t}\n\n\toverride providesBackgroundForChildren(): boolean {\n\t\treturn true\n\t}\n\n\toverride getClipPath(shape: TLFrameShape) {\n\t\treturn this.editor.getShapeGeometry(shape.id).vertices\n\t}\n\n\toverride canReceiveNewChildrenOfType(shape: TLShape) {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride onResize(shape: any, info: TLResizeInfo<any>) {\n\t\treturn resizeBox(shape, info)\n\t}\n\n\toverride getInterpolatedProps(\n\t\tstartShape: TLFrameShape,\n\t\tendShape: TLFrameShape,\n\t\tt: number\n\t): TLFrameShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\tw: lerp(startShape.props.w, endShape.props.w, t),\n\t\t\th: lerp(startShape.props.h, endShape.props.h, t),\n\t\t}\n\t}\n\n\toverride onDoubleClickEdge(shape: TLFrameShape, info: TLClickEventInfo) {\n\t\tif (info.target !== 'selection') return\n\t\tconst { handle } = info\n\n\t\t// If handle is missing, we can't determine which edge was clicked\n\t\tif (!handle) return\n\n\t\tconst isHorizontalEdge = handle === 'left' || handle === 'right'\n\t\tconst isVerticalEdge = handle === 'top' || handle === 'bottom'\n\n\t\tconst childIds = this.editor.getSortedChildIdsForParent(shape.id)\n\t\tconst children = compact(childIds.map((id) => this.editor.getShape(id)))\n\t\tif (!children.length) return\n\n\t\tconst { dx, dy, w, h } = getFrameChildrenBounds(children, this.editor, { padding: 10 })\n\n\t\tthis.editor.run(() => {\n\t\t\tconst changes: TLShapePartial[] = childIds.map((childId) => {\n\t\t\t\tconst childShape = this.editor.getShape(childId)!\n\t\t\t\treturn {\n\t\t\t\t\tid: childShape.id,\n\t\t\t\t\ttype: childShape.type,\n\t\t\t\t\tx: isHorizontalEdge ? childShape.x + dx : childShape.x,\n\t\t\t\t\ty: isVerticalEdge ? childShape.y + dy : childShape.y,\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tthis.editor.updateShapes(changes)\n\t\t})\n\n\t\treturn {\n\t\t\tid: shape.id,\n\t\t\ttype: shape.type,\n\t\t\tprops: {\n\t\t\t\tw: isHorizontalEdge ? w : shape.props.w,\n\t\t\t\th: isVerticalEdge ? h : shape.props.h,\n\t\t\t},\n\t\t}\n\t}\n\n\toverride onDoubleClickCorner(shape: TLFrameShape) {\n\t\tfitFrameToContent(this.editor, shape.id, { padding: 10 })\n\t\treturn {\n\t\t\tid: shape.id,\n\t\t\ttype: shape.type,\n\t\t}\n\t}\n\n\toverride onDragShapesIn(\n\t\tshape: TLFrameShape,\n\t\tdraggingShapes: TLShape[],\n\t\t{ initialParentIds, initialIndices }: TLDragShapesOverInfo\n\t) {\n\t\tconst { editor } = this\n\n\t\tif (draggingShapes.every((s) => s.parentId === shape.id)) return\n\n\t\t// Check to see whether any of the shapes can have their old index restored\n\t\tlet canRestoreOriginalIndices = false\n\t\tconst previousChildren = draggingShapes.filter((s) => shape.id === initialParentIds.get(s.id))\n\n\t\tif (previousChildren.length > 0) {\n\t\t\tconst currentChildren = compact(\n\t\t\t\teditor.getSortedChildIdsForParent(shape).map((id) => editor.getShape(id))\n\t\t\t)\n\t\t\tif (previousChildren.every((s) => !currentChildren.find((c) => c.index === s.index))) {\n\t\t\t\tcanRestoreOriginalIndices = true\n\t\t\t}\n\t\t}\n\n\t\t// I can't imagine this happening, but if any of the children are the ancestor of the frame, quit here\n\t\tif (draggingShapes.some((s) => editor.hasAncestor(shape, s.id))) return\n\n\t\t// Reparent the shapes to the new parent\n\t\teditor.reparentShapes(draggingShapes, shape.id)\n\n\t\t// If we can restore the original indices, then do so\n\t\tif (canRestoreOriginalIndices) {\n\t\t\tfor (const shape of previousChildren) {\n\t\t\t\teditor.updateShape({\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tindex: initialIndices.get(shape.id),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\toverride onDragShapesOut(\n\t\tshape: TLFrameShape,\n\t\tdraggingShapes: TLShape[],\n\t\tinfo: TLDragShapesOutInfo\n\t): void {\n\t\tconst { editor } = this\n\t\t// When a user drags shapes out of a frame, and if we're not dragging into a new shape, then reparent\n\t\t// the dragging shapes (that are current children of the frame) onto the current page instead\n\t\tif (!info.nextDraggingOverShapeId) {\n\t\t\teditor.reparentShapes(\n\t\t\t\tdraggingShapes.filter(\n\t\t\t\t\t(s) => s.parentId === shape.id && this.canReceiveNewChildrenOfType(s)\n\t\t\t\t),\n\t\t\t\teditor.getCurrentPageId()\n\t\t\t)\n\t\t}\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["classNames", "shape"]
|
|
7
7
|
}
|
|
@@ -88,12 +88,19 @@ class Erasing extends import_editor.StateNode {
|
|
|
88
88
|
const { editor, excludedShapeIds } = this;
|
|
89
89
|
const erasingShapeIds = editor.getErasingShapeIds();
|
|
90
90
|
const zoomLevel = editor.getZoomLevel();
|
|
91
|
-
const currentPageShapes = editor.getCurrentPageRenderingShapesSorted();
|
|
92
91
|
const currentPagePoint = editor.inputs.getCurrentPagePoint();
|
|
93
92
|
const previousPagePoint = editor.inputs.getPreviousPagePoint();
|
|
94
93
|
this.pushPointToScribble();
|
|
95
94
|
const erasing = new Set(erasingShapeIds);
|
|
96
95
|
const minDist = this.editor.options.hitTestMargin / zoomLevel;
|
|
96
|
+
const lineBounds = import_editor.Box.FromPoints([previousPagePoint, currentPagePoint]).expandBy(minDist);
|
|
97
|
+
const candidateIds = editor.getShapeIdsInsideBounds(lineBounds);
|
|
98
|
+
if (candidateIds.size === 0) {
|
|
99
|
+
editor.setErasingShapes(Array.from(erasing));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const allShapes = editor.getCurrentPageRenderingShapesSorted();
|
|
103
|
+
const currentPageShapes = allShapes.filter((shape) => candidateIds.has(shape.id));
|
|
97
104
|
for (const shape of currentPageShapes) {
|
|
98
105
|
if (editor.isShapeOfType(shape, "group")) continue;
|
|
99
106
|
const pageMask = editor.getShapeMask(shape.id);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/tools/EraserTool/childStates/Erasing.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tStateNode,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tisAccelKey,\n\tpointInPolygon,\n} from '@tldraw/editor'\n\nexport class Erasing extends StateNode {\n\tstatic override id = 'erasing'\n\n\tprivate info = {} as TLPointerEventInfo\n\tprivate scribbleId = 'id'\n\tprivate markId = ''\n\tprivate excludedShapeIds = new Set<TLShapeId>()\n\n\t_isHoldingAccelKey = false\n\t_firstErasingShapeId: TLShapeId | null = null\n\t_erasingShapeIds: TLShapeId[] = []\n\n\toverride onEnter(info: TLPointerEventInfo) {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t\tthis._firstErasingShapeId = this.editor.getErasingShapeIds()[0] // the first one should be the first one we hit... is it?\n\t\tthis._erasingShapeIds = this.editor.getErasingShapeIds()\n\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('erase scribble begin')\n\t\tthis.info = info\n\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\t\tthis.excludedShapeIds = new Set(\n\t\t\tthis.editor\n\t\t\t\t.getCurrentPageShapes()\n\t\t\t\t.filter((shape) => {\n\t\t\t\t\t//If the shape is locked, we shouldn't erase it\n\t\t\t\t\tif (this.editor.isShapeOrAncestorLocked(shape)) return true\n\t\t\t\t\t//If the shape is a group or frame, check we're inside it when we start erasing\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.editor.isShapeOfType(shape, 'group') ||\n\t\t\t\t\t\tthis.editor.isShapeOfType(shape, 'frame')\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst pointInShapeShape = this.editor.getPointInShapeSpace(shape, originPagePoint)\n\t\t\t\t\t\tconst geometry = this.editor.getShapeGeometry(shape)\n\t\t\t\t\t\treturn geometry.bounds.containsPoint(pointInShapeShape)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false\n\t\t\t\t})\n\t\t\t\t.map((shape) => shape.id)\n\t\t)\n\n\t\tconst scribble = this.editor.scribbles.addScribble({\n\t\t\tcolor: 'muted-1',\n\t\t\tsize: 12,\n\t\t})\n\t\tthis.scribbleId = scribble.id\n\n\t\tthis.update()\n\t}\n\n\tprivate pushPointToScribble() {\n\t\tconst { x, y } = this.editor.inputs.getCurrentPagePoint()\n\t\tthis.editor.scribbles.addPoint(this.scribbleId, x, y)\n\t}\n\n\toverride onExit() {\n\t\tthis.editor.setErasingShapes([])\n\t\tthis.editor.scribbles.stop(this.scribbleId)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.update()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onKeyUp() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t\tthis.update()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t\tthis.update()\n\t}\n\n\tupdate() {\n\t\tconst { editor, excludedShapeIds } = this\n\t\tconst erasingShapeIds = editor.getErasingShapeIds()\n\t\tconst zoomLevel = editor.getZoomLevel()\n\t\tconst
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import {\n\tBox,\n\tStateNode,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tisAccelKey,\n\tpointInPolygon,\n} from '@tldraw/editor'\n\nexport class Erasing extends StateNode {\n\tstatic override id = 'erasing'\n\n\tprivate info = {} as TLPointerEventInfo\n\tprivate scribbleId = 'id'\n\tprivate markId = ''\n\tprivate excludedShapeIds = new Set<TLShapeId>()\n\n\t_isHoldingAccelKey = false\n\t_firstErasingShapeId: TLShapeId | null = null\n\t_erasingShapeIds: TLShapeId[] = []\n\n\toverride onEnter(info: TLPointerEventInfo) {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t\tthis._firstErasingShapeId = this.editor.getErasingShapeIds()[0] // the first one should be the first one we hit... is it?\n\t\tthis._erasingShapeIds = this.editor.getErasingShapeIds()\n\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('erase scribble begin')\n\t\tthis.info = info\n\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\t\tthis.excludedShapeIds = new Set(\n\t\t\tthis.editor\n\t\t\t\t.getCurrentPageShapes()\n\t\t\t\t.filter((shape) => {\n\t\t\t\t\t//If the shape is locked, we shouldn't erase it\n\t\t\t\t\tif (this.editor.isShapeOrAncestorLocked(shape)) return true\n\t\t\t\t\t//If the shape is a group or frame, check we're inside it when we start erasing\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.editor.isShapeOfType(shape, 'group') ||\n\t\t\t\t\t\tthis.editor.isShapeOfType(shape, 'frame')\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst pointInShapeShape = this.editor.getPointInShapeSpace(shape, originPagePoint)\n\t\t\t\t\t\tconst geometry = this.editor.getShapeGeometry(shape)\n\t\t\t\t\t\treturn geometry.bounds.containsPoint(pointInShapeShape)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false\n\t\t\t\t})\n\t\t\t\t.map((shape) => shape.id)\n\t\t)\n\n\t\tconst scribble = this.editor.scribbles.addScribble({\n\t\t\tcolor: 'muted-1',\n\t\t\tsize: 12,\n\t\t})\n\t\tthis.scribbleId = scribble.id\n\n\t\tthis.update()\n\t}\n\n\tprivate pushPointToScribble() {\n\t\tconst { x, y } = this.editor.inputs.getCurrentPagePoint()\n\t\tthis.editor.scribbles.addPoint(this.scribbleId, x, y)\n\t}\n\n\toverride onExit() {\n\t\tthis.editor.setErasingShapes([])\n\t\tthis.editor.scribbles.stop(this.scribbleId)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.update()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onKeyUp() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t\tthis.update()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t\tthis.update()\n\t}\n\n\tupdate() {\n\t\tconst { editor, excludedShapeIds } = this\n\t\tconst erasingShapeIds = editor.getErasingShapeIds()\n\t\tconst zoomLevel = editor.getZoomLevel()\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\t\tconst previousPagePoint = editor.inputs.getPreviousPagePoint()\n\n\t\tthis.pushPointToScribble()\n\n\t\t// Otherwise, erasing shapes are all the shapes that were hit before plus any new shapes that are hit\n\t\tconst erasing = new Set<TLShapeId>(erasingShapeIds)\n\t\tconst minDist = this.editor.options.hitTestMargin / zoomLevel\n\n\t\t// Create bounds around line segment with margin\n\t\tconst lineBounds = Box.FromPoints([previousPagePoint, currentPagePoint]).expandBy(minDist)\n\t\tconst candidateIds = editor.getShapeIdsInsideBounds(lineBounds)\n\n\t\t// Early return if no candidates - avoid expensive getCurrentPageRenderingShapesSorted()\n\t\tif (candidateIds.size === 0) {\n\t\t\teditor.setErasingShapes(Array.from(erasing))\n\t\t\treturn\n\t\t}\n\n\t\tconst allShapes = editor.getCurrentPageRenderingShapesSorted()\n\t\tconst currentPageShapes = allShapes.filter((shape) => candidateIds.has(shape.id))\n\n\t\tfor (const shape of currentPageShapes) {\n\t\t\tif (editor.isShapeOfType(shape, 'group')) continue\n\n\t\t\t// Avoid testing masked shapes, unless the pointer is inside the mask\n\t\t\tconst pageMask = editor.getShapeMask(shape.id)\n\t\t\tif (pageMask && !pointInPolygon(currentPagePoint, pageMask)) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Hit test the shape using a line segment\n\t\t\tconst geometry = editor.getShapeGeometry(shape)\n\t\t\tconst pageTransform = editor.getShapePageTransform(shape)\n\t\t\tif (!geometry || !pageTransform) continue\n\t\t\tconst pt = pageTransform.clone().invert()\n\t\t\tconst A = pt.applyToPoint(previousPagePoint)\n\t\t\tconst B = pt.applyToPoint(currentPagePoint)\n\n\t\t\t// If the line segment is entirely above / below / left / right of the shape's bounding box, skip the hit test\n\t\t\tconst { bounds } = geometry\n\t\t\tif (\n\t\t\t\tbounds.minX - minDist > Math.max(A.x, B.x) ||\n\t\t\t\tbounds.minY - minDist > Math.max(A.y, B.y) ||\n\t\t\t\tbounds.maxX + minDist < Math.min(A.x, B.x) ||\n\t\t\t\tbounds.maxY + minDist < Math.min(A.y, B.y)\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (geometry.hitTestLineSegment(A, B, minDist)) {\n\t\t\t\terasing.add(editor.getOutermostSelectableShape(shape).id)\n\t\t\t}\n\n\t\t\tthis._erasingShapeIds = [...erasing]\n\t\t}\n\n\t\t// If the user is holding the meta / ctrl key, we should only erase the first shape we hit\n\t\tif (this._isHoldingAccelKey && this._firstErasingShapeId) {\n\t\t\tconst erasingShapeId = this._firstErasingShapeId\n\t\t\tif (erasingShapeId && this.editor.getShape(erasingShapeId)) {\n\t\t\t\teditor.setErasingShapes([erasingShapeId])\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\t// Remove the hit shapes, except if they're in the list of excluded shapes\n\t\t// (these excluded shapes will be any frames or groups the pointer was inside of\n\t\t// when the user started erasing)\n\t\tthis.editor.setErasingShapes(this._erasingShapeIds.filter((id) => !excludedShapeIds.has(id)))\n\t}\n\n\tcomplete() {\n\t\tconst { editor } = this\n\t\teditor.deleteShapes(editor.getCurrentPageState().erasingShapeIds)\n\t\tthis.parent.transition('idle')\n\t\tthis._erasingShapeIds = []\n\t\tthis._firstErasingShapeId = null\n\t}\n\n\tcancel() {\n\t\tconst { editor } = this\n\t\teditor.bailToMark(this.markId)\n\t\tthis.parent.transition('idle', this.info)\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -106,8 +106,21 @@ class Brushing extends import_editor.StateNode {
|
|
|
106
106
|
const { corners } = brush;
|
|
107
107
|
let A, B, shape, pageBounds, pageTransform, localCorners;
|
|
108
108
|
const brushBoxIsInsideViewport = editor.getViewportPageBounds().contains(brush);
|
|
109
|
-
const shapesToHitTest = brushBoxIsInsideViewport && !this.viewportDidChange ? editor.getCurrentPageRenderingShapesSorted() : editor.getCurrentPageShapesSorted();
|
|
110
109
|
const currentPageId = editor.getCurrentPageId();
|
|
110
|
+
const candidateIds = editor.getShapeIdsInsideBounds(brush);
|
|
111
|
+
if (candidateIds.size === 0) {
|
|
112
|
+
const currentBrush2 = editor.getInstanceState().brush;
|
|
113
|
+
if (!currentBrush2 || !brush.equals(currentBrush2)) {
|
|
114
|
+
editor.updateInstanceState({ brush: { ...brush.toJson() } });
|
|
115
|
+
}
|
|
116
|
+
const current2 = editor.getSelectedShapeIds();
|
|
117
|
+
if (current2.length !== results.size || current2.some((id) => !results.has(id))) {
|
|
118
|
+
editor.setSelectedShapes(Array.from(results));
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const allShapes = brushBoxIsInsideViewport && !this.viewportDidChange ? editor.getCurrentPageRenderingShapesSorted() : editor.getCurrentPageShapesSorted();
|
|
123
|
+
const shapesToHitTest = allShapes.filter((shape2) => candidateIds.has(shape2.id));
|
|
111
124
|
testAllShapes: for (let i = 0, n = shapesToHitTest.length; i < n; i++) {
|
|
112
125
|
shape = shapesToHitTest[i];
|
|
113
126
|
if (excludedShapeIds.has(shape.id) || results.has(shape.id)) continue testAllShapes;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/tools/SelectTool/childStates/Brushing.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tBox,\n\tMat,\n\tStateNode,\n\tTLCancelEventInfo,\n\tTLKeyboardEventInfo,\n\tTLPageId,\n\tTLPointerEventInfo,\n\tTLShape,\n\tTLShapeId,\n\tTLTickEventInfo,\n\tVec,\n\tpointInPolygon,\n\tpolygonsIntersect,\n\treact,\n} from '@tldraw/editor'\n\nexport class Brushing extends StateNode {\n\tstatic override id = 'brushing'\n\n\tinfo = {} as TLPointerEventInfo & { target: 'canvas' }\n\n\tinitialSelectedShapeIds: TLShapeId[] = []\n\texcludedShapeIds = new Set<TLShapeId>()\n\tisWrapMode = false\n\n\tviewportDidChange = false\n\tcleanupViewportChangeReactor() {\n\t\tvoid null\n\t} // cleanup function for the viewport reactor\n\n\toverride onEnter(info: TLPointerEventInfo & { target: 'canvas' }) {\n\t\tconst { editor } = this\n\t\tconst altKey = editor.inputs.getAltKey()\n\n\t\tthis.isWrapMode = editor.user.getIsWrapMode()\n\n\t\tthis.viewportDidChange = false\n\n\t\tlet isInitialCheck = true\n\n\t\tthis.cleanupViewportChangeReactor = react('viewport change while brushing', () => {\n\t\t\teditor.getViewportPageBounds() // capture the viewport change\n\t\t\tif (!isInitialCheck && !this.viewportDidChange) {\n\t\t\t\tthis.viewportDidChange = true\n\t\t\t}\n\t\t})\n\n\t\tif (altKey) {\n\t\t\tthis.parent.transition('scribble_brushing', info)\n\t\t\treturn\n\t\t}\n\n\t\tthis.excludedShapeIds = new Set(\n\t\t\teditor\n\t\t\t\t.getCurrentPageShapes()\n\t\t\t\t.filter(\n\t\t\t\t\t(shape) => editor.isShapeOfType(shape, 'group') || editor.isShapeOrAncestorLocked(shape)\n\t\t\t\t)\n\t\t\t\t.map((shape) => shape.id)\n\t\t)\n\n\t\tthis.info = info\n\t\tthis.initialSelectedShapeIds = editor.getSelectedShapeIds().slice()\n\t\tthis.hitTestShapes()\n\t\tisInitialCheck = false\n\t}\n\n\toverride onExit() {\n\t\tthis.initialSelectedShapeIds = []\n\t\tthis.editor.updateInstanceState({ brush: null })\n\n\t\tthis.cleanupViewportChangeReactor()\n\t}\n\n\toverride onTick({ elapsed }: TLTickEventInfo) {\n\t\tconst { editor } = this\n\t\teditor.edgeScrollManager.updateEdgeScrolling(elapsed)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.hitTestShapes()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel(info: TLCancelEventInfo) {\n\t\tthis.editor.setSelectedShapes(this.initialSelectedShapeIds)\n\t\tthis.parent.transition('idle', info)\n\t}\n\n\toverride onKeyDown(info: TLKeyboardEventInfo) {\n\t\tif (this.editor.inputs.getAltKey()) {\n\t\t\tthis.parent.transition('scribble_brushing', info)\n\t\t} else {\n\t\t\tthis.hitTestShapes()\n\t\t}\n\t}\n\n\toverride onKeyUp() {\n\t\tthis.hitTestShapes()\n\t}\n\n\tprivate complete() {\n\t\tthis.hitTestShapes()\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate hitTestShapes() {\n\t\tconst { editor, excludedShapeIds, isWrapMode } = this\n\t\tconst originPagePoint = editor.inputs.getOriginPagePoint()\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\t\tconst shiftKey = editor.inputs.getShiftKey()\n\t\tconst ctrlKey = editor.inputs.getCtrlKey()\n\n\t\t// We'll be collecting shape ids of selected shapes; if we're holding shift key, we start from our initial shapes\n\t\tconst results = new Set(shiftKey ? this.initialSelectedShapeIds : [])\n\n\t\t// In wrap mode, we need to completely enclose a shape to select it\n\t\tconst isWrapping = isWrapMode ? !ctrlKey : ctrlKey\n\n\t\t// Set the brush to contain the current and origin points\n\t\tconst brush = Box.FromPoints([originPagePoint, currentPagePoint])\n\n\t\t// We'll be testing the corners of the brush against the shapes\n\t\tconst { corners } = brush\n\n\t\tlet A: Vec,\n\t\t\tB: Vec,\n\t\t\tshape: TLShape,\n\t\t\tpageBounds: Box | undefined,\n\t\t\tpageTransform: Mat | undefined,\n\t\t\tlocalCorners: Vec[]\n\n\t\t// Some notes on optimization. We could easily cache all of the shape positions at\n\t\t// the start of the interaction and then do very fast checks against them, but that\n\t\t// would mean changes introduced by other collaborators wouldn't be reflected\u2014a user\n\t\t// could select a shape by selecting where it _used_ to be.\n\n\t\t// We still want to avoid hit tests as much as possible, however, so we test only the\n\t\t// shapes that are on screen UNLESS: the user has scrolled their viewpor; or the user\n\t\t// is dragging outside of the screen (e.g. in a window). In those cases, we need to\n\t\t// test all shapes.\n\n\t\t// On a page with ~5000 shapes, on-screen hit tests are about 2x faster than\n\t\t// testing all shapes.\n\n\t\tconst brushBoxIsInsideViewport = editor.getViewportPageBounds().contains(brush)\n\t\tconst
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAeO;AAEA,MAAM,iBAAiB,wBAAU;AAAA,EACvC,OAAgB,KAAK;AAAA,EAErB,OAAO,CAAC;AAAA,EAER,0BAAuC,CAAC;AAAA,EACxC,mBAAmB,oBAAI,IAAe;AAAA,EACtC,aAAa;AAAA,EAEb,oBAAoB;AAAA,EACpB,+BAA+B;AAAA,EAE/B;AAAA;AAAA,EAES,QAAQ,MAAiD;AACjE,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,SAAS,OAAO,OAAO,UAAU;AAEvC,SAAK,aAAa,OAAO,KAAK,cAAc;AAE5C,SAAK,oBAAoB;AAEzB,QAAI,iBAAiB;AAErB,SAAK,mCAA+B,qBAAM,kCAAkC,MAAM;AACjF,aAAO,sBAAsB;AAC7B,UAAI,CAAC,kBAAkB,CAAC,KAAK,mBAAmB;AAC/C,aAAK,oBAAoB;AAAA,MAC1B;AAAA,IACD,CAAC;AAED,QAAI,QAAQ;AACX,WAAK,OAAO,WAAW,qBAAqB,IAAI;AAChD;AAAA,IACD;AAEA,SAAK,mBAAmB,IAAI;AAAA,MAC3B,OACE,qBAAqB,EACrB;AAAA,QACA,CAAC,UAAU,OAAO,cAAc,OAAO,OAAO,KAAK,OAAO,wBAAwB,KAAK;AAAA,MACxF,EACC,IAAI,CAAC,UAAU,MAAM,EAAE;AAAA,IAC1B;AAEA,SAAK,OAAO;AACZ,SAAK,0BAA0B,OAAO,oBAAoB,EAAE,MAAM;AAClE,SAAK,cAAc;AACnB,qBAAiB;AAAA,EAClB;AAAA,EAES,SAAS;AACjB,SAAK,0BAA0B,CAAC;AAChC,SAAK,OAAO,oBAAoB,EAAE,OAAO,KAAK,CAAC;AAE/C,SAAK,6BAA6B;AAAA,EACnC;AAAA,EAES,OAAO,EAAE,QAAQ,GAAoB;AAC7C,UAAM,EAAE,OAAO,IAAI;AACnB,WAAO,kBAAkB,oBAAoB,OAAO;AAAA,EACrD;AAAA,EAES,gBAAgB;AACxB,SAAK,cAAc;AAAA,EACpB;AAAA,EAES,cAAc;AACtB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,aAAa;AACrB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,SAAS,MAAyB;AAC1C,SAAK,OAAO,kBAAkB,KAAK,uBAAuB;AAC1D,SAAK,OAAO,WAAW,QAAQ,IAAI;AAAA,EACpC;AAAA,EAES,UAAU,MAA2B;AAC7C,QAAI,KAAK,OAAO,OAAO,UAAU,GAAG;AACnC,WAAK,OAAO,WAAW,qBAAqB,IAAI;AAAA,IACjD,OAAO;AACN,WAAK,cAAc;AAAA,IACpB;AAAA,EACD;AAAA,EAES,UAAU;AAClB,SAAK,cAAc;AAAA,EACpB;AAAA,EAEQ,WAAW;AAClB,SAAK,cAAc;AACnB,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEQ,gBAAgB;AACvB,UAAM,EAAE,QAAQ,kBAAkB,WAAW,IAAI;AACjD,UAAM,kBAAkB,OAAO,OAAO,mBAAmB;AACzD,UAAM,mBAAmB,OAAO,OAAO,oBAAoB;AAC3D,UAAM,WAAW,OAAO,OAAO,YAAY;AAC3C,UAAM,UAAU,OAAO,OAAO,WAAW;AAGzC,UAAM,UAAU,IAAI,IAAI,WAAW,KAAK,0BAA0B,CAAC,CAAC;AAGpE,UAAM,aAAa,aAAa,CAAC,UAAU;AAG3C,UAAM,QAAQ,kBAAI,WAAW,CAAC,iBAAiB,gBAAgB,CAAC;AAGhE,UAAM,EAAE,QAAQ,IAAI;AAEpB,QAAI,GACH,GACA,OACA,YACA,eACA;AAeD,UAAM,2BAA2B,OAAO,sBAAsB,EAAE,SAAS,KAAK;AAC9E,UAAM,
|
|
6
|
-
"names": ["i"]
|
|
4
|
+
"sourcesContent": ["import {\n\tBox,\n\tMat,\n\tStateNode,\n\tTLCancelEventInfo,\n\tTLKeyboardEventInfo,\n\tTLPageId,\n\tTLPointerEventInfo,\n\tTLShape,\n\tTLShapeId,\n\tTLTickEventInfo,\n\tVec,\n\tpointInPolygon,\n\tpolygonsIntersect,\n\treact,\n} from '@tldraw/editor'\n\nexport class Brushing extends StateNode {\n\tstatic override id = 'brushing'\n\n\tinfo = {} as TLPointerEventInfo & { target: 'canvas' }\n\n\tinitialSelectedShapeIds: TLShapeId[] = []\n\texcludedShapeIds = new Set<TLShapeId>()\n\tisWrapMode = false\n\n\tviewportDidChange = false\n\tcleanupViewportChangeReactor() {\n\t\tvoid null\n\t} // cleanup function for the viewport reactor\n\n\toverride onEnter(info: TLPointerEventInfo & { target: 'canvas' }) {\n\t\tconst { editor } = this\n\t\tconst altKey = editor.inputs.getAltKey()\n\n\t\tthis.isWrapMode = editor.user.getIsWrapMode()\n\n\t\tthis.viewportDidChange = false\n\n\t\tlet isInitialCheck = true\n\n\t\tthis.cleanupViewportChangeReactor = react('viewport change while brushing', () => {\n\t\t\teditor.getViewportPageBounds() // capture the viewport change\n\t\t\tif (!isInitialCheck && !this.viewportDidChange) {\n\t\t\t\tthis.viewportDidChange = true\n\t\t\t}\n\t\t})\n\n\t\tif (altKey) {\n\t\t\tthis.parent.transition('scribble_brushing', info)\n\t\t\treturn\n\t\t}\n\n\t\tthis.excludedShapeIds = new Set(\n\t\t\teditor\n\t\t\t\t.getCurrentPageShapes()\n\t\t\t\t.filter(\n\t\t\t\t\t(shape) => editor.isShapeOfType(shape, 'group') || editor.isShapeOrAncestorLocked(shape)\n\t\t\t\t)\n\t\t\t\t.map((shape) => shape.id)\n\t\t)\n\n\t\tthis.info = info\n\t\tthis.initialSelectedShapeIds = editor.getSelectedShapeIds().slice()\n\t\tthis.hitTestShapes()\n\t\tisInitialCheck = false\n\t}\n\n\toverride onExit() {\n\t\tthis.initialSelectedShapeIds = []\n\t\tthis.editor.updateInstanceState({ brush: null })\n\n\t\tthis.cleanupViewportChangeReactor()\n\t}\n\n\toverride onTick({ elapsed }: TLTickEventInfo) {\n\t\tconst { editor } = this\n\t\teditor.edgeScrollManager.updateEdgeScrolling(elapsed)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.hitTestShapes()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel(info: TLCancelEventInfo) {\n\t\tthis.editor.setSelectedShapes(this.initialSelectedShapeIds)\n\t\tthis.parent.transition('idle', info)\n\t}\n\n\toverride onKeyDown(info: TLKeyboardEventInfo) {\n\t\tif (this.editor.inputs.getAltKey()) {\n\t\t\tthis.parent.transition('scribble_brushing', info)\n\t\t} else {\n\t\t\tthis.hitTestShapes()\n\t\t}\n\t}\n\n\toverride onKeyUp() {\n\t\tthis.hitTestShapes()\n\t}\n\n\tprivate complete() {\n\t\tthis.hitTestShapes()\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate hitTestShapes() {\n\t\tconst { editor, excludedShapeIds, isWrapMode } = this\n\t\tconst originPagePoint = editor.inputs.getOriginPagePoint()\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\t\tconst shiftKey = editor.inputs.getShiftKey()\n\t\tconst ctrlKey = editor.inputs.getCtrlKey()\n\n\t\t// We'll be collecting shape ids of selected shapes; if we're holding shift key, we start from our initial shapes\n\t\tconst results = new Set(shiftKey ? this.initialSelectedShapeIds : [])\n\n\t\t// In wrap mode, we need to completely enclose a shape to select it\n\t\tconst isWrapping = isWrapMode ? !ctrlKey : ctrlKey\n\n\t\t// Set the brush to contain the current and origin points\n\t\tconst brush = Box.FromPoints([originPagePoint, currentPagePoint])\n\n\t\t// We'll be testing the corners of the brush against the shapes\n\t\tconst { corners } = brush\n\n\t\tlet A: Vec,\n\t\t\tB: Vec,\n\t\t\tshape: TLShape,\n\t\t\tpageBounds: Box | undefined,\n\t\t\tpageTransform: Mat | undefined,\n\t\t\tlocalCorners: Vec[]\n\n\t\t// Some notes on optimization. We could easily cache all of the shape positions at\n\t\t// the start of the interaction and then do very fast checks against them, but that\n\t\t// would mean changes introduced by other collaborators wouldn't be reflected\u2014a user\n\t\t// could select a shape by selecting where it _used_ to be.\n\n\t\t// We still want to avoid hit tests as much as possible, however, so we test only the\n\t\t// shapes that are on screen UNLESS: the user has scrolled their viewpor; or the user\n\t\t// is dragging outside of the screen (e.g. in a window). In those cases, we need to\n\t\t// test all shapes.\n\n\t\t// On a page with ~5000 shapes, on-screen hit tests are about 2x faster than\n\t\t// testing all shapes.\n\n\t\tconst brushBoxIsInsideViewport = editor.getViewportPageBounds().contains(brush)\n\t\tconst currentPageId = editor.getCurrentPageId()\n\n\t\t// Use spatial index to filter candidates\n\t\tconst candidateIds = editor.getShapeIdsInsideBounds(brush)\n\n\t\t// Early return if no candidates - avoid expensive getCurrentPageShapesSorted()\n\t\t// But still update brush visual and selection\n\t\tif (candidateIds.size === 0) {\n\t\t\tconst currentBrush = editor.getInstanceState().brush\n\t\t\tif (!currentBrush || !brush.equals(currentBrush)) {\n\t\t\t\teditor.updateInstanceState({ brush: { ...brush.toJson() } })\n\t\t\t}\n\n\t\t\tconst current = editor.getSelectedShapeIds()\n\t\t\tif (current.length !== results.size || current.some((id) => !results.has(id))) {\n\t\t\t\teditor.setSelectedShapes(Array.from(results))\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst allShapes =\n\t\t\tbrushBoxIsInsideViewport && !this.viewportDidChange\n\t\t\t\t? editor.getCurrentPageRenderingShapesSorted()\n\t\t\t\t: editor.getCurrentPageShapesSorted()\n\t\tconst shapesToHitTest = allShapes.filter((shape) => candidateIds.has(shape.id))\n\n\t\ttestAllShapes: for (let i = 0, n = shapesToHitTest.length; i < n; i++) {\n\t\t\tshape = shapesToHitTest[i]\n\t\t\tif (excludedShapeIds.has(shape.id) || results.has(shape.id)) continue testAllShapes\n\n\t\t\tpageBounds = editor.getShapePageBounds(shape)\n\t\t\tif (!pageBounds) continue testAllShapes\n\n\t\t\t// If the brush fully wraps a shape, it's almost certainly a hit\n\t\t\tif (brush.contains(pageBounds)) {\n\t\t\t\tthis.handleHit(shape, currentPagePoint, currentPageId, results, corners)\n\t\t\t\tcontinue testAllShapes\n\t\t\t}\n\n\t\t\t// If we're in wrap mode and the brush did not fully encloses the shape, it's a miss\n\t\t\t// We also skip frames unless we've completely selected the frame.\n\t\t\tif (isWrapping || editor.isShapeOfType(shape, 'frame')) {\n\t\t\t\tcontinue testAllShapes\n\t\t\t}\n\n\t\t\t// If the brush collides the page bounds, then do hit tests against\n\t\t\t// each of the brush's four sides.\n\t\t\tif (brush.collides(pageBounds)) {\n\t\t\t\t// Shapes expect to hit test line segments in their own coordinate system,\n\t\t\t\t// so we first need to get the brush corners in the shape's local space.\n\t\t\t\tpageTransform = editor.getShapePageTransform(shape)\n\t\t\t\tif (!pageTransform) continue testAllShapes\n\t\t\t\tlocalCorners = pageTransform.clone().invert().applyToPoints(corners)\n\t\t\t\t// See if any of the edges intersect the shape's geometry\n\t\t\t\tconst geometry = editor.getShapeGeometry(shape)\n\t\t\t\thitTestBrushEdges: for (let i = 0; i < 4; i++) {\n\t\t\t\t\tA = localCorners[i]\n\t\t\t\t\tB = localCorners[(i + 1) % 4]\n\t\t\t\t\tif (geometry.hitTestLineSegment(A, B, 0)) {\n\t\t\t\t\t\tthis.handleHit(shape, currentPagePoint, currentPageId, results, corners)\n\t\t\t\t\t\tbreak hitTestBrushEdges\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst currentBrush = editor.getInstanceState().brush\n\t\tif (!currentBrush || !brush.equals(currentBrush)) {\n\t\t\teditor.updateInstanceState({ brush: { ...brush.toJson() } })\n\t\t}\n\n\t\tconst current = editor.getSelectedShapeIds()\n\t\tif (current.length !== results.size || current.some((id) => !results.has(id))) {\n\t\t\teditor.setSelectedShapes(Array.from(results))\n\t\t}\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.editor.updateInstanceState({ brush: null })\n\t}\n\n\tprivate handleHit(\n\t\tshape: TLShape,\n\t\tcurrentPagePoint: Vec,\n\t\tcurrentPageId: TLPageId,\n\t\tresults: Set<TLShapeId>,\n\t\tcorners: Vec[]\n\t) {\n\t\tif (shape.parentId === currentPageId) {\n\t\t\tresults.add(shape.id)\n\t\t\treturn\n\t\t}\n\n\t\t// Find the outermost selectable shape, check to see if it has a\n\t\t// page mask; and if so, check to see if the brush intersects it\n\t\tconst selectedShape = this.editor.getOutermostSelectableShape(shape)\n\t\tconst pageMask = this.editor.getShapeMask(selectedShape.id)\n\t\tif (\n\t\t\tpageMask &&\n\t\t\t!polygonsIntersect(pageMask, corners) &&\n\t\t\t!pointInPolygon(currentPagePoint, pageMask)\n\t\t) {\n\t\t\treturn\n\t\t}\n\t\tresults.add(selectedShape.id)\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["currentBrush", "current", "shape", "i"]
|
|
7
7
|
}
|
|
@@ -76,7 +76,6 @@ class ScribbleBrushing extends import_editor.StateNode {
|
|
|
76
76
|
}
|
|
77
77
|
updateScribbleSelection(addPoint) {
|
|
78
78
|
const { editor } = this;
|
|
79
|
-
const currentPageShapes = this.editor.getCurrentPageRenderingShapesSorted();
|
|
80
79
|
const shiftKey = this.editor.inputs.getShiftKey();
|
|
81
80
|
const originPagePoint = this.editor.inputs.getOriginPagePoint();
|
|
82
81
|
const previousPagePoint = this.editor.inputs.getPreviousPagePoint();
|
|
@@ -85,9 +84,23 @@ class ScribbleBrushing extends import_editor.StateNode {
|
|
|
85
84
|
if (addPoint) {
|
|
86
85
|
this.pushPointToScribble();
|
|
87
86
|
}
|
|
87
|
+
const minDist = 0;
|
|
88
|
+
const lineBounds = import_editor.Box.FromPoints([previousPagePoint, currentPagePoint]).expandBy(minDist);
|
|
89
|
+
const candidateIds = editor.getShapeIdsInsideBounds(lineBounds);
|
|
90
|
+
if (candidateIds.size === 0) {
|
|
91
|
+
const current2 = editor.getSelectedShapeIds();
|
|
92
|
+
const next2 = new Set(
|
|
93
|
+
shiftKey ? [...newlySelectedShapeIds, ...initialSelectedShapeIds] : [...newlySelectedShapeIds]
|
|
94
|
+
);
|
|
95
|
+
if (current2.length !== next2.size || current2.some((id) => !next2.has(id))) {
|
|
96
|
+
this.editor.setSelectedShapes(Array.from(next2));
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const allShapes = this.editor.getCurrentPageRenderingShapesSorted();
|
|
101
|
+
const currentPageShapes = allShapes.filter((shape2) => candidateIds.has(shape2.id));
|
|
88
102
|
const shapes = currentPageShapes;
|
|
89
103
|
let shape, geometry, A, B;
|
|
90
|
-
const minDist = 0;
|
|
91
104
|
for (let i = 0, n = shapes.length; i < n; i++) {
|
|
92
105
|
shape = shapes[i];
|
|
93
106
|
if (editor.isShapeOfType(shape, "group") || newlySelectedShapeIds.has(shape.id) || editor.isShapeOrAncestorLocked(shape)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/tools/SelectTool/childStates/ScribbleBrushing.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tGeometry2d,\n\tStateNode,\n\tTLShape,\n\tTLShapeId,\n\tVec,\n\tintersectLineSegmentPolygon,\n\tpointInPolygon,\n} from '@tldraw/editor'\n\nexport class ScribbleBrushing extends StateNode {\n\tstatic override id = 'scribble_brushing'\n\n\thits = new Set<TLShapeId>()\n\n\tsize = 0\n\n\tscribbleId = 'id'\n\n\tinitialSelectedShapeIds = new Set<TLShapeId>()\n\tnewlySelectedShapeIds = new Set<TLShapeId>()\n\n\toverride onEnter() {\n\t\tthis.initialSelectedShapeIds = new Set<TLShapeId>(\n\t\t\tthis.editor.inputs.getShiftKey() ? this.editor.getSelectedShapeIds() : []\n\t\t)\n\t\tthis.newlySelectedShapeIds = new Set<TLShapeId>()\n\t\tthis.size = 0\n\t\tthis.hits.clear()\n\n\t\tconst scribbleItem = this.editor.scribbles.addScribble({\n\t\t\tcolor: 'selection-stroke',\n\t\t\topacity: 0.32,\n\t\t\tsize: 12,\n\t\t})\n\n\t\tthis.scribbleId = scribbleItem.id\n\n\t\tthis.updateScribbleSelection(true)\n\n\t\tthis.editor.updateInstanceState({ brush: null })\n\t}\n\n\toverride onExit() {\n\t\tthis.editor.scribbles.stop(this.scribbleId)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.updateScribbleSelection(true)\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis.updateScribbleSelection(false)\n\t}\n\n\toverride onKeyUp() {\n\t\tif (!this.editor.inputs.getAltKey()) {\n\t\t\tthis.parent.transition('brushing')\n\t\t} else {\n\t\t\tthis.updateScribbleSelection(false)\n\t\t}\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\tprivate pushPointToScribble() {\n\t\tconst { x, y } = this.editor.inputs.getCurrentPagePoint()\n\t\tthis.editor.scribbles.addPoint(this.scribbleId, x, y)\n\t}\n\n\tprivate updateScribbleSelection(addPoint: boolean) {\n\t\tconst { editor } = this\n\t\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import {\n\tBox,\n\tGeometry2d,\n\tStateNode,\n\tTLShape,\n\tTLShapeId,\n\tVec,\n\tintersectLineSegmentPolygon,\n\tpointInPolygon,\n} from '@tldraw/editor'\n\nexport class ScribbleBrushing extends StateNode {\n\tstatic override id = 'scribble_brushing'\n\n\thits = new Set<TLShapeId>()\n\n\tsize = 0\n\n\tscribbleId = 'id'\n\n\tinitialSelectedShapeIds = new Set<TLShapeId>()\n\tnewlySelectedShapeIds = new Set<TLShapeId>()\n\n\toverride onEnter() {\n\t\tthis.initialSelectedShapeIds = new Set<TLShapeId>(\n\t\t\tthis.editor.inputs.getShiftKey() ? this.editor.getSelectedShapeIds() : []\n\t\t)\n\t\tthis.newlySelectedShapeIds = new Set<TLShapeId>()\n\t\tthis.size = 0\n\t\tthis.hits.clear()\n\n\t\tconst scribbleItem = this.editor.scribbles.addScribble({\n\t\t\tcolor: 'selection-stroke',\n\t\t\topacity: 0.32,\n\t\t\tsize: 12,\n\t\t})\n\n\t\tthis.scribbleId = scribbleItem.id\n\n\t\tthis.updateScribbleSelection(true)\n\n\t\tthis.editor.updateInstanceState({ brush: null })\n\t}\n\n\toverride onExit() {\n\t\tthis.editor.scribbles.stop(this.scribbleId)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.updateScribbleSelection(true)\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis.updateScribbleSelection(false)\n\t}\n\n\toverride onKeyUp() {\n\t\tif (!this.editor.inputs.getAltKey()) {\n\t\t\tthis.parent.transition('brushing')\n\t\t} else {\n\t\t\tthis.updateScribbleSelection(false)\n\t\t}\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\tprivate pushPointToScribble() {\n\t\tconst { x, y } = this.editor.inputs.getCurrentPagePoint()\n\t\tthis.editor.scribbles.addPoint(this.scribbleId, x, y)\n\t}\n\n\tprivate updateScribbleSelection(addPoint: boolean) {\n\t\tconst { editor } = this\n\t\tconst shiftKey = this.editor.inputs.getShiftKey()\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\t\tconst previousPagePoint = this.editor.inputs.getPreviousPagePoint()\n\t\tconst currentPagePoint = this.editor.inputs.getCurrentPagePoint()\n\n\t\tconst { newlySelectedShapeIds, initialSelectedShapeIds } = this\n\n\t\tif (addPoint) {\n\t\t\tthis.pushPointToScribble()\n\t\t}\n\n\t\tconst minDist = 0 // this.editor.options.hitTestMargin / zoomLevel\n\n\t\t// Create bounds around line segment with margin\n\t\tconst lineBounds = Box.FromPoints([previousPagePoint, currentPagePoint]).expandBy(minDist)\n\t\tconst candidateIds = editor.getShapeIdsInsideBounds(lineBounds)\n\n\t\t// Early return if no candidates - avoid expensive getCurrentPageRenderingShapesSorted()\n\t\t// But still update selection based on current state\n\t\tif (candidateIds.size === 0) {\n\t\t\tconst current = editor.getSelectedShapeIds()\n\t\t\tconst next = new Set<TLShapeId>(\n\t\t\t\tshiftKey\n\t\t\t\t\t? [...newlySelectedShapeIds, ...initialSelectedShapeIds]\n\t\t\t\t\t: [...newlySelectedShapeIds]\n\t\t\t)\n\t\t\tif (current.length !== next.size || current.some((id) => !next.has(id))) {\n\t\t\t\tthis.editor.setSelectedShapes(Array.from(next))\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst allShapes = this.editor.getCurrentPageRenderingShapesSorted()\n\t\tconst currentPageShapes = allShapes.filter((shape) => candidateIds.has(shape.id))\n\n\t\tconst shapes = currentPageShapes\n\t\tlet shape: TLShape, geometry: Geometry2d, A: Vec, B: Vec\n\n\t\tfor (let i = 0, n = shapes.length; i < n; i++) {\n\t\t\tshape = shapes[i]\n\n\t\t\t// If the shape is a group or is already selected or locked, don't select it\n\t\t\tif (\n\t\t\t\teditor.isShapeOfType(shape, 'group') ||\n\t\t\t\tnewlySelectedShapeIds.has(shape.id) ||\n\t\t\t\teditor.isShapeOrAncestorLocked(shape)\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tgeometry = editor.getShapeGeometry(shape)\n\n\t\t\t// If the scribble started inside of the frame, don't select it\n\t\t\tif (\n\t\t\t\teditor.isShapeOfType(shape, 'frame') &&\n\t\t\t\tgeometry.bounds.containsPoint(editor.getPointInShapeSpace(shape, originPagePoint))\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Hit test the shape using a line segment\n\t\t\tconst pageTransform = editor.getShapePageTransform(shape)\n\t\t\tif (!geometry || !pageTransform) continue\n\t\t\tconst pt = pageTransform.clone().invert()\n\t\t\tA = pt.applyToPoint(previousPagePoint)\n\t\t\tB = pt.applyToPoint(currentPagePoint)\n\n\t\t\t// If the line segment is entirely above / below / left / right of the shape's bounding box, skip the hit test\n\t\t\tconst { bounds } = geometry\n\t\t\tif (\n\t\t\t\tbounds.minX - minDist > Math.max(A.x, B.x) ||\n\t\t\t\tbounds.minY - minDist > Math.max(A.y, B.y) ||\n\t\t\t\tbounds.maxX + minDist < Math.min(A.x, B.x) ||\n\t\t\t\tbounds.maxY + minDist < Math.min(A.y, B.y)\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (geometry.hitTestLineSegment(A, B, minDist)) {\n\t\t\t\tconst outermostShape = this.editor.getOutermostSelectableShape(shape)\n\t\t\t\tconst pageMask = this.editor.getShapeMask(outermostShape.id)\n\t\t\t\tif (pageMask) {\n\t\t\t\t\tconst intersection = intersectLineSegmentPolygon(\n\t\t\t\t\t\tpreviousPagePoint,\n\t\t\t\t\t\tcurrentPagePoint,\n\t\t\t\t\t\tpageMask\n\t\t\t\t\t)\n\t\t\t\t\tif (intersection !== null) {\n\t\t\t\t\t\tconst isInMask = pointInPolygon(currentPagePoint, pageMask)\n\t\t\t\t\t\tif (!isInMask) continue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnewlySelectedShapeIds.add(outermostShape.id)\n\t\t\t}\n\t\t}\n\n\t\tconst current = editor.getSelectedShapeIds()\n\t\tconst next = new Set<TLShapeId>(\n\t\t\tshiftKey ? [...newlySelectedShapeIds, ...initialSelectedShapeIds] : [...newlySelectedShapeIds]\n\t\t)\n\t\tif (current.length !== next.size || current.some((id) => !next.has(id))) {\n\t\t\tthis.editor.setSelectedShapes(Array.from(next))\n\t\t}\n\t}\n\n\tprivate complete() {\n\t\tthis.updateScribbleSelection(true)\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate cancel() {\n\t\tthis.editor.setSelectedShapes([...this.initialSelectedShapeIds])\n\t\tthis.parent.transition('idle')\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["current", "next", "shape"]
|
|
7
7
|
}
|
|
@@ -67,7 +67,7 @@ function FPS() {
|
|
|
67
67
|
if (fps < slowFps && !isSlow || fps >= slowFps && isSlow) {
|
|
68
68
|
isSlow = !isSlow;
|
|
69
69
|
}
|
|
70
|
-
fpsRef.current.innerHTML = `FPS ${fps.toString()}`;
|
|
70
|
+
fpsRef.current.innerHTML = `FPS ${fps.toString()} (max: ${maxKnownFps})`;
|
|
71
71
|
fpsRef.current.className = `tlui-debug-panel__fps` + (isSlow ? ` tlui-debug-panel__fps__slow` : ``);
|
|
72
72
|
currentTickLength -= TICK_LENGTH;
|
|
73
73
|
framesInCurrentTick = 0;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/ui/components/DefaultDebugPanel.tsx"],
|
|
4
|
-
"sourcesContent": ["import { debugFlags, track, useEditor, usePassThroughWheelEvents, useValue } from '@tldraw/editor'\nimport { memo, useEffect, useRef } from 'react'\nimport { useTldrawUiComponents } from '../context/components'\n\n/** @internal */\nexport const DefaultDebugPanel = memo(function DefaultDebugPanel() {\n\tconst { DebugMenu } = useTldrawUiComponents()\n\n\tconst ref = useRef<HTMLDivElement>(null)\n\tusePassThroughWheelEvents(ref)\n\n\treturn (\n\t\t<footer ref={ref} className=\"tlui-debug-panel\">\n\t\t\t<CurrentState />\n\t\t\t<FPS />\n\t\t\t{DebugMenu && <DebugMenu />}\n\t\t</footer>\n\t)\n})\n\nconst CurrentState = track(function CurrentState() {\n\tconst editor = useEditor()\n\tconst path = editor.getPath()\n\treturn <div className=\"tlui-debug-panel__current-state\">{`${path}`}</div>\n})\n\nfunction FPS() {\n\tconst editor = useEditor()\n\tconst showFps = useValue('show_fps', () => debugFlags.showFps.get(), [debugFlags])\n\n\tconst fpsRef = useRef<HTMLDivElement>(null)\n\n\tuseEffect(() => {\n\t\tif (!showFps) return\n\n\t\tconst TICK_LENGTH = 250\n\t\tlet maxKnownFps = 0\n\t\tlet raf = -1\n\n\t\tlet start = performance.now()\n\t\tlet currentTickLength = 0\n\t\tlet framesInCurrentTick = 0\n\t\tlet isSlow = false\n\n\t\t// A \"tick\" is the amount of time between renders. Even though\n\t\t// we'll loop on every frame, we will only paint when the time\n\t\t// since the last paint is greater than the tick length.\n\n\t\t// When we paint, we'll calculate the FPS based on the number\n\t\t// of frames that we've seen since the last time we rendered,\n\t\t// and the actual time since the last render.\n\t\tfunction loop() {\n\t\t\t// Count the frame\n\t\t\tframesInCurrentTick++\n\n\t\t\t// Check if we should render\n\t\t\tcurrentTickLength = performance.now() - start\n\n\t\t\tif (currentTickLength > TICK_LENGTH) {\n\t\t\t\t// Calculate the FPS and paint it\n\t\t\t\tconst fps = Math.round(\n\t\t\t\t\tframesInCurrentTick * (TICK_LENGTH / currentTickLength) * (1000 / TICK_LENGTH)\n\t\t\t\t)\n\n\t\t\t\tif (fps > maxKnownFps) {\n\t\t\t\t\tmaxKnownFps = fps\n\t\t\t\t}\n\n\t\t\t\tconst slowFps = maxKnownFps * 0.75\n\t\t\t\tif ((fps < slowFps && !isSlow) || (fps >= slowFps && isSlow)) {\n\t\t\t\t\tisSlow = !isSlow\n\t\t\t\t}\n\n\t\t\t\tfpsRef.current!.innerHTML = `FPS ${fps.toString()}`\n\t\t\t\tfpsRef.current!.className =\n\t\t\t\t\t`tlui-debug-panel__fps` + (isSlow ? ` tlui-debug-panel__fps__slow` : ``)\n\n\t\t\t\t// Reset the values\n\t\t\t\tcurrentTickLength -= TICK_LENGTH\n\t\t\t\tframesInCurrentTick = 0\n\t\t\t\tstart = performance.now()\n\t\t\t}\n\n\t\t\traf = editor.timers.requestAnimationFrame(loop)\n\t\t}\n\n\t\tloop()\n\n\t\treturn () => {\n\t\t\tcancelAnimationFrame(raf)\n\t\t}\n\t}, [showFps, editor])\n\n\tif (!showFps) return null\n\n\treturn <div ref={fpsRef} />\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAYE;AAZF,oBAAkF;AAClF,mBAAwC;AACxC,wBAAsC;AAG/B,MAAM,wBAAoB,mBAAK,SAASA,qBAAoB;AAClE,QAAM,EAAE,UAAU,QAAI,yCAAsB;AAE5C,QAAM,UAAM,qBAAuB,IAAI;AACvC,+CAA0B,GAAG;AAE7B,SACC,6CAAC,YAAO,KAAU,WAAU,oBAC3B;AAAA,gDAAC,gBAAa;AAAA,IACd,4CAAC,OAAI;AAAA,IACJ,aAAa,4CAAC,aAAU;AAAA,KAC1B;AAEF,CAAC;AAED,MAAM,mBAAe,qBAAM,SAASC,gBAAe;AAClD,QAAM,aAAS,yBAAU;AACzB,QAAM,OAAO,OAAO,QAAQ;AAC5B,SAAO,4CAAC,SAAI,WAAU,mCAAmC,aAAG,IAAI,IAAG;AACpE,CAAC;AAED,SAAS,MAAM;AACd,QAAM,aAAS,yBAAU;AACzB,QAAM,cAAU,wBAAS,YAAY,MAAM,yBAAW,QAAQ,IAAI,GAAG,CAAC,wBAAU,CAAC;AAEjF,QAAM,aAAS,qBAAuB,IAAI;AAE1C,8BAAU,MAAM;AACf,QAAI,CAAC,QAAS;AAEd,UAAM,cAAc;AACpB,QAAI,cAAc;AAClB,QAAI,MAAM;AAEV,QAAI,QAAQ,YAAY,IAAI;AAC5B,QAAI,oBAAoB;AACxB,QAAI,sBAAsB;AAC1B,QAAI,SAAS;AASb,aAAS,OAAO;AAEf;AAGA,0BAAoB,YAAY,IAAI,IAAI;AAExC,UAAI,oBAAoB,aAAa;AAEpC,cAAM,MAAM,KAAK;AAAA,UAChB,uBAAuB,cAAc,sBAAsB,MAAO;AAAA,QACnE;AAEA,YAAI,MAAM,aAAa;AACtB,wBAAc;AAAA,QACf;AAEA,cAAM,UAAU,cAAc;AAC9B,YAAK,MAAM,WAAW,CAAC,UAAY,OAAO,WAAW,QAAS;AAC7D,mBAAS,CAAC;AAAA,QACX;AAEA,eAAO,QAAS,YAAY,OAAO,IAAI,SAAS,CAAC;
|
|
4
|
+
"sourcesContent": ["import { debugFlags, track, useEditor, usePassThroughWheelEvents, useValue } from '@tldraw/editor'\nimport { memo, useEffect, useRef } from 'react'\nimport { useTldrawUiComponents } from '../context/components'\n\n/** @internal */\nexport const DefaultDebugPanel = memo(function DefaultDebugPanel() {\n\tconst { DebugMenu } = useTldrawUiComponents()\n\n\tconst ref = useRef<HTMLDivElement>(null)\n\tusePassThroughWheelEvents(ref)\n\n\treturn (\n\t\t<footer ref={ref} className=\"tlui-debug-panel\">\n\t\t\t<CurrentState />\n\t\t\t<FPS />\n\t\t\t{DebugMenu && <DebugMenu />}\n\t\t</footer>\n\t)\n})\n\nconst CurrentState = track(function CurrentState() {\n\tconst editor = useEditor()\n\tconst path = editor.getPath()\n\treturn <div className=\"tlui-debug-panel__current-state\">{`${path}`}</div>\n})\n\nfunction FPS() {\n\tconst editor = useEditor()\n\tconst showFps = useValue('show_fps', () => debugFlags.showFps.get(), [debugFlags])\n\n\tconst fpsRef = useRef<HTMLDivElement>(null)\n\n\tuseEffect(() => {\n\t\tif (!showFps) return\n\n\t\tconst TICK_LENGTH = 250\n\t\tlet maxKnownFps = 0\n\t\tlet raf = -1\n\n\t\tlet start = performance.now()\n\t\tlet currentTickLength = 0\n\t\tlet framesInCurrentTick = 0\n\t\tlet isSlow = false\n\n\t\t// A \"tick\" is the amount of time between renders. Even though\n\t\t// we'll loop on every frame, we will only paint when the time\n\t\t// since the last paint is greater than the tick length.\n\n\t\t// When we paint, we'll calculate the FPS based on the number\n\t\t// of frames that we've seen since the last time we rendered,\n\t\t// and the actual time since the last render.\n\t\tfunction loop() {\n\t\t\t// Count the frame\n\t\t\tframesInCurrentTick++\n\n\t\t\t// Check if we should render\n\t\t\tcurrentTickLength = performance.now() - start\n\n\t\t\tif (currentTickLength > TICK_LENGTH) {\n\t\t\t\t// Calculate the FPS and paint it\n\t\t\t\tconst fps = Math.round(\n\t\t\t\t\tframesInCurrentTick * (TICK_LENGTH / currentTickLength) * (1000 / TICK_LENGTH)\n\t\t\t\t)\n\n\t\t\t\tif (fps > maxKnownFps) {\n\t\t\t\t\tmaxKnownFps = fps\n\t\t\t\t}\n\n\t\t\t\tconst slowFps = maxKnownFps * 0.75\n\t\t\t\tif ((fps < slowFps && !isSlow) || (fps >= slowFps && isSlow)) {\n\t\t\t\t\tisSlow = !isSlow\n\t\t\t\t}\n\n\t\t\t\tfpsRef.current!.innerHTML = `FPS ${fps.toString()} (max: ${maxKnownFps})`\n\t\t\t\tfpsRef.current!.className =\n\t\t\t\t\t`tlui-debug-panel__fps` + (isSlow ? ` tlui-debug-panel__fps__slow` : ``)\n\n\t\t\t\t// Reset the values\n\t\t\t\tcurrentTickLength -= TICK_LENGTH\n\t\t\t\tframesInCurrentTick = 0\n\t\t\t\tstart = performance.now()\n\t\t\t}\n\n\t\t\traf = editor.timers.requestAnimationFrame(loop)\n\t\t}\n\n\t\tloop()\n\n\t\treturn () => {\n\t\t\tcancelAnimationFrame(raf)\n\t\t}\n\t}, [showFps, editor])\n\n\tif (!showFps) return null\n\n\treturn <div ref={fpsRef} />\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAYE;AAZF,oBAAkF;AAClF,mBAAwC;AACxC,wBAAsC;AAG/B,MAAM,wBAAoB,mBAAK,SAASA,qBAAoB;AAClE,QAAM,EAAE,UAAU,QAAI,yCAAsB;AAE5C,QAAM,UAAM,qBAAuB,IAAI;AACvC,+CAA0B,GAAG;AAE7B,SACC,6CAAC,YAAO,KAAU,WAAU,oBAC3B;AAAA,gDAAC,gBAAa;AAAA,IACd,4CAAC,OAAI;AAAA,IACJ,aAAa,4CAAC,aAAU;AAAA,KAC1B;AAEF,CAAC;AAED,MAAM,mBAAe,qBAAM,SAASC,gBAAe;AAClD,QAAM,aAAS,yBAAU;AACzB,QAAM,OAAO,OAAO,QAAQ;AAC5B,SAAO,4CAAC,SAAI,WAAU,mCAAmC,aAAG,IAAI,IAAG;AACpE,CAAC;AAED,SAAS,MAAM;AACd,QAAM,aAAS,yBAAU;AACzB,QAAM,cAAU,wBAAS,YAAY,MAAM,yBAAW,QAAQ,IAAI,GAAG,CAAC,wBAAU,CAAC;AAEjF,QAAM,aAAS,qBAAuB,IAAI;AAE1C,8BAAU,MAAM;AACf,QAAI,CAAC,QAAS;AAEd,UAAM,cAAc;AACpB,QAAI,cAAc;AAClB,QAAI,MAAM;AAEV,QAAI,QAAQ,YAAY,IAAI;AAC5B,QAAI,oBAAoB;AACxB,QAAI,sBAAsB;AAC1B,QAAI,SAAS;AASb,aAAS,OAAO;AAEf;AAGA,0BAAoB,YAAY,IAAI,IAAI;AAExC,UAAI,oBAAoB,aAAa;AAEpC,cAAM,MAAM,KAAK;AAAA,UAChB,uBAAuB,cAAc,sBAAsB,MAAO;AAAA,QACnE;AAEA,YAAI,MAAM,aAAa;AACtB,wBAAc;AAAA,QACf;AAEA,cAAM,UAAU,cAAc;AAC9B,YAAK,MAAM,WAAW,CAAC,UAAY,OAAO,WAAW,QAAS;AAC7D,mBAAS,CAAC;AAAA,QACX;AAEA,eAAO,QAAS,YAAY,OAAO,IAAI,SAAS,CAAC,UAAU,WAAW;AACtE,eAAO,QAAS,YACf,2BAA2B,SAAS,iCAAiC;AAGtE,6BAAqB;AACrB,8BAAsB;AACtB,gBAAQ,YAAY,IAAI;AAAA,MACzB;AAEA,YAAM,OAAO,OAAO,sBAAsB,IAAI;AAAA,IAC/C;AAEA,SAAK;AAEL,WAAO,MAAM;AACZ,2BAAqB,GAAG;AAAA,IACzB;AAAA,EACD,GAAG,CAAC,SAAS,MAAM,CAAC;AAEpB,MAAI,CAAC,QAAS,QAAO;AAErB,SAAO,4CAAC,SAAI,KAAK,QAAQ;AAC1B;",
|
|
6
6
|
"names": ["DefaultDebugPanel", "CurrentState"]
|
|
7
7
|
}
|
|
@@ -22,10 +22,10 @@ __export(version_exports, {
|
|
|
22
22
|
version: () => version
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(version_exports);
|
|
25
|
-
const version = "4.
|
|
25
|
+
const version = "4.4.0-canary.29afdff6bb04";
|
|
26
26
|
const publishDates = {
|
|
27
27
|
major: "2025-09-18T14:39:22.803Z",
|
|
28
|
-
minor: "2026-01-
|
|
29
|
-
patch: "2026-01-
|
|
28
|
+
minor: "2026-01-21T13:27:27.357Z",
|
|
29
|
+
patch: "2026-01-21T13:27:27.357Z"
|
|
30
30
|
};
|
|
31
31
|
//# sourceMappingURL=version.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/ui/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.
|
|
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.4.0-canary.29afdff6bb04'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2026-01-21T13:27:27.357Z',\n\tpatch: '2026-01-21T13:27:27.357Z',\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/index.mjs
CHANGED
|
@@ -244,14 +244,7 @@ class FrameShapeUtil extends BaseBoxShapeUtil {
|
|
|
244
244
|
] });
|
|
245
245
|
}
|
|
246
246
|
indicator(shape) {
|
|
247
|
-
return /* @__PURE__ */ jsx(
|
|
248
|
-
"rect",
|
|
249
|
-
{
|
|
250
|
-
width: toDomPrecision(shape.props.w),
|
|
251
|
-
height: toDomPrecision(shape.props.h),
|
|
252
|
-
className: `tl-frame-indicator`
|
|
253
|
-
}
|
|
254
|
-
);
|
|
247
|
+
return /* @__PURE__ */ jsx("rect", { width: toDomPrecision(shape.props.w), height: toDomPrecision(shape.props.h) });
|
|
255
248
|
}
|
|
256
249
|
providesBackgroundForChildren() {
|
|
257
250
|
return true;
|