diff --git a/apps/examples/src/examples/exploded/ExplodedExample.tsx b/apps/examples/src/examples/exploded/ExplodedExample.tsx index f38ed1b13..f53dce67c 100644 --- a/apps/examples/src/examples/exploded/ExplodedExample.tsx +++ b/apps/examples/src/examples/exploded/ExplodedExample.tsx @@ -3,7 +3,6 @@ import { DefaultContextMenuContent, TldrawEditor, TldrawHandles, - TldrawHoveredShapeIndicator, TldrawScribble, TldrawSelectionBackground, TldrawSelectionForeground, @@ -23,7 +22,6 @@ const defaultComponents = { SelectionForeground: TldrawSelectionForeground, SelectionBackground: TldrawSelectionBackground, Handles: TldrawHandles, - HoveredShapeIndicator: TldrawHoveredShapeIndicator, } //[2] diff --git a/packages/editor/api-report.md b/packages/editor/api-report.md index e2ca21d9d..7f6ed4c04 100644 --- a/packages/editor/api-report.md +++ b/packages/editor/api-report.md @@ -118,7 +118,7 @@ export class Arc2d extends Geometry2d { // (undocumented) getVertices(): Vec[]; // (undocumented) - hitTestLineSegment(A: Vec, B: Vec, _zoom: number): boolean; + hitTestLineSegment(A: Vec, B: Vec): boolean; // (undocumented) length: number; // (undocumented) @@ -332,7 +332,7 @@ export class Circle2d extends Geometry2d { // (undocumented) getVertices(): Vec[]; // (undocumented) - hitTestLineSegment(A: Vec, B: Vec, _zoom: number): boolean; + hitTestLineSegment(A: Vec, B: Vec, distance?: number): boolean; // (undocumented) nearestPoint(point: Vec): Vec; // (undocumented) @@ -414,7 +414,7 @@ export class CubicSpline2d extends Geometry2d { // (undocumented) getVertices(): Vec[]; // (undocumented) - hitTestLineSegment(A: Vec, B: Vec, zoom: number): boolean; + hitTestLineSegment(A: Vec, B: Vec): boolean; // (undocumented) get length(): number; // (undocumented) @@ -471,9 +471,6 @@ export function DefaultHandle({ handle, isCoarse, className, zoom }: TLHandlePro // @public (undocumented) export const DefaultHandles: ({ children }: TLHandlesProps) => JSX_2.Element; -// @public (undocumented) -export function DefaultHoveredShapeIndicator({ shapeId }: TLHoveredShapeIndicatorProps): JSX_2.Element | null; - // @public (undocumented) export function DefaultScribble({ scribble, zoom, color, opacity, className }: TLScribbleProps): JSX_2.Element | null; @@ -552,7 +549,7 @@ export class Edge2d extends Geometry2d { // (undocumented) getVertices(): Vec[]; // (undocumented) - hitTestLineSegment(A: Vec, B: Vec, _zoom: number): boolean; + hitTestLineSegment(A: Vec, B: Vec, distance?: number): boolean; // (undocumented) get length(): number; // (undocumented) @@ -968,7 +965,7 @@ export class Ellipse2d extends Geometry2d { // (undocumented) h: number; // (undocumented) - hitTestLineSegment(A: Vec, B: Vec, zoom: number): boolean; + hitTestLineSegment(A: Vec, B: Vec): boolean; // (undocumented) nearestPoint(A: Vec): Vec; // (undocumented) @@ -1458,7 +1455,7 @@ export class Polyline2d extends Geometry2d { // (undocumented) getVertices(): Vec[]; // (undocumented) - hitTestLineSegment(A: Vec, B: Vec, zoom: number): boolean; + hitTestLineSegment(A: Vec, B: Vec, distance?: number): boolean; // (undocumented) get length(): number; // (undocumented) @@ -2302,11 +2299,6 @@ export type TLHistoryMark = { onRedo: boolean; }; -// @public (undocumented) -export type TLHoveredShapeIndicatorProps = { - shapeId: TLShapeId; -}; - // @public (undocumented) export type TLInterruptEvent = (info: TLInterruptEventInfo) => void; @@ -2539,6 +2531,7 @@ export type TLShapeIndicatorProps = { color?: string | undefined; opacity?: number; className?: string; + hidden?: boolean; }; // @public (undocumented) @@ -2726,7 +2719,6 @@ export function useEditorComponents(): Partial<{ Spinner: ComponentType | null; SelectionForeground: ComponentType | null; SelectionBackground: ComponentType | null; - HoveredShapeIndicator: ComponentType | null; OnTheCanvas: ComponentType | null; InFrontOfTheCanvas: ComponentType | null; LoadingScreen: ComponentType | null; @@ -2850,6 +2842,8 @@ export class Vec { // (undocumented) static DistanceToLineThroughPoint(A: VecLike, u: VecLike, P: VecLike): number; // (undocumented) + static DistMin(A: VecLike, B: VecLike, n: number): boolean; + // (undocumented) static Div(A: VecLike, t: number): Vec; // (undocumented) div(t: number): this; diff --git a/packages/editor/api/api.json b/packages/editor/api/api.json index 6945f077c..0c14fb4e0 100644 --- a/packages/editor/api/api.json +++ b/packages/editor/api/api.json @@ -605,14 +605,6 @@ "text": "Vec", "canonicalReference": "@tldraw/editor!Vec:class" }, - { - "kind": "Content", - "text": ", _zoom: " - }, - { - "kind": "Content", - "text": "number" - }, { "kind": "Content", "text": "): " @@ -628,8 +620,8 @@ ], "isStatic": false, "returnTypeTokenRange": { - "startIndex": 7, - "endIndex": 8 + "startIndex": 5, + "endIndex": 6 }, "releaseTag": "Public", "isProtected": false, @@ -650,14 +642,6 @@ "endIndex": 4 }, "isOptional": false - }, - { - "parameterName": "_zoom", - "parameterTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - }, - "isOptional": false } ], "isOptional": false, @@ -4438,7 +4422,7 @@ }, { "kind": "Content", - "text": ", _zoom: " + "text": ", distance?: " }, { "kind": "Content", @@ -4483,12 +4467,12 @@ "isOptional": false }, { - "parameterName": "_zoom", + "parameterName": "distance", "parameterTypeTokenRange": { "startIndex": 5, "endIndex": 6 }, - "isOptional": false + "isOptional": true } ], "isOptional": false, @@ -5746,14 +5730,6 @@ "text": "Vec", "canonicalReference": "@tldraw/editor!Vec:class" }, - { - "kind": "Content", - "text": ", zoom: " - }, - { - "kind": "Content", - "text": "number" - }, { "kind": "Content", "text": "): " @@ -5769,8 +5745,8 @@ ], "isStatic": false, "returnTypeTokenRange": { - "startIndex": 7, - "endIndex": 8 + "startIndex": 5, + "endIndex": 6 }, "releaseTag": "Public", "isProtected": false, @@ -5791,14 +5767,6 @@ "endIndex": 4 }, "isOptional": false - }, - { - "parameterName": "zoom", - "parameterTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - }, - "isOptional": false } ], "isOptional": false, @@ -6449,61 +6417,6 @@ ], "name": "DefaultHandles" }, - { - "kind": "Function", - "canonicalReference": "@tldraw/editor!DefaultHoveredShapeIndicator:function(1)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function DefaultHoveredShapeIndicator({ shapeId }: " - }, - { - "kind": "Reference", - "text": "TLHoveredShapeIndicatorProps", - "canonicalReference": "@tldraw/editor!TLHoveredShapeIndicatorProps:type" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "import(\"react/jsx-runtime\")." - }, - { - "kind": "Reference", - "text": "JSX.Element", - "canonicalReference": "@types/react!JSX.Element:interface" - }, - { - "kind": "Content", - "text": " | null" - }, - { - "kind": "Content", - "text": ";" - } - ], - "fileUrlPath": "packages/editor/src/lib/components/default-components/DefaultHoveredShapeIndicator.tsx", - "returnTypeTokenRange": { - "startIndex": 3, - "endIndex": 6 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "{ shapeId }", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isOptional": false - } - ], - "name": "DefaultHoveredShapeIndicator" - }, { "kind": "Function", "canonicalReference": "@tldraw/editor!DefaultScribble:function(1)", @@ -7134,7 +7047,7 @@ }, { "kind": "Content", - "text": ", _zoom: " + "text": ", distance?: " }, { "kind": "Content", @@ -7179,12 +7092,12 @@ "isOptional": false }, { - "parameterName": "_zoom", + "parameterName": "distance", "parameterTypeTokenRange": { "startIndex": 5, "endIndex": 6 }, - "isOptional": false + "isOptional": true } ], "isOptional": false, @@ -20311,14 +20224,6 @@ "text": "Vec", "canonicalReference": "@tldraw/editor!Vec:class" }, - { - "kind": "Content", - "text": ", zoom: " - }, - { - "kind": "Content", - "text": "number" - }, { "kind": "Content", "text": "): " @@ -20334,8 +20239,8 @@ ], "isStatic": false, "returnTypeTokenRange": { - "startIndex": 7, - "endIndex": 8 + "startIndex": 5, + "endIndex": 6 }, "releaseTag": "Public", "isProtected": false, @@ -20356,14 +20261,6 @@ "endIndex": 4 }, "isOptional": false - }, - { - "parameterName": "zoom", - "parameterTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - }, - "isOptional": false } ], "isOptional": false, @@ -28466,7 +28363,7 @@ }, { "kind": "Content", - "text": ", zoom: " + "text": ", distance?: " }, { "kind": "Content", @@ -28511,12 +28408,12 @@ "isOptional": false }, { - "parameterName": "zoom", + "parameterName": "distance", "parameterTypeTokenRange": { "startIndex": 5, "endIndex": 6 }, - "isOptional": false + "isOptional": true } ], "isOptional": false, @@ -39669,41 +39566,6 @@ "endIndex": 2 } }, - { - "kind": "TypeAlias", - "canonicalReference": "@tldraw/editor!TLHoveredShapeIndicatorProps:type", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export type TLHoveredShapeIndicatorProps = " - }, - { - "kind": "Content", - "text": "{\n shapeId: " - }, - { - "kind": "Reference", - "text": "TLShapeId", - "canonicalReference": "@tldraw/tlschema!TLShapeId:type" - }, - { - "kind": "Content", - "text": ";\n}" - }, - { - "kind": "Content", - "text": ";" - } - ], - "fileUrlPath": "packages/editor/src/lib/components/default-components/DefaultHoveredShapeIndicator.tsx", - "releaseTag": "Public", - "name": "TLHoveredShapeIndicatorProps", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 4 - } - }, { "kind": "TypeAlias", "canonicalReference": "@tldraw/editor!TLInterruptEvent:type", @@ -41940,7 +41802,7 @@ }, { "kind": "Content", - "text": ";\n color?: string | undefined;\n opacity?: number;\n className?: string;\n}" + "text": ";\n color?: string | undefined;\n opacity?: number;\n className?: string;\n hidden?: boolean;\n}" }, { "kind": "Content", @@ -43835,24 +43697,6 @@ "text": "TLSelectionBackgroundProps", "canonicalReference": "@tldraw/editor!TLSelectionBackgroundProps:type" }, - { - "kind": "Content", - "text": "> | null;\n HoveredShapeIndicator: " - }, - { - "kind": "Reference", - "text": "ComponentType", - "canonicalReference": "@types/react!React.ComponentType:type" - }, - { - "kind": "Content", - "text": "<" - }, - { - "kind": "Reference", - "text": "TLHoveredShapeIndicatorProps", - "canonicalReference": "@tldraw/editor!TLHoveredShapeIndicatorProps:type" - }, { "kind": "Content", "text": "> | null;\n OnTheCanvas: " @@ -43906,7 +43750,7 @@ "fileUrlPath": "packages/editor/src/lib/hooks/useEditorComponents.tsx", "returnTypeTokenRange": { "startIndex": 1, - "endIndex": 90 + "endIndex": 86 }, "releaseTag": "Public", "overloadIndex": 1, @@ -46051,6 +45895,88 @@ "isAbstract": false, "name": "DistanceToLineThroughPoint" }, + { + "kind": "Method", + "canonicalReference": "@tldraw/editor!Vec.DistMin:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "static DistMin(A: " + }, + { + "kind": "Reference", + "text": "VecLike", + "canonicalReference": "@tldraw/editor!VecLike:type" + }, + { + "kind": "Content", + "text": ", B: " + }, + { + "kind": "Reference", + "text": "VecLike", + "canonicalReference": "@tldraw/editor!VecLike:type" + }, + { + "kind": "Content", + "text": ", n: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": true, + "returnTypeTokenRange": { + "startIndex": 7, + "endIndex": 8 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "A", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "B", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + }, + { + "parameterName": "n", + "parameterTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "DistMin" + }, { "kind": "Method", "canonicalReference": "@tldraw/editor!Vec#div:member(1)", diff --git a/packages/editor/editor.css b/packages/editor/editor.css index 03bbb64f4..b2a0e6add 100644 --- a/packages/editor/editor.css +++ b/packages/editor/editor.css @@ -465,7 +465,7 @@ input, transform-origin: top left; fill: none; stroke-width: calc(1.5px * var(--tl-scale)); - contain: size; + contain: size layout; } /* ------------------ SelectionBox ------------------ */ diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 51b62ba6c..b639db49a 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -62,10 +62,6 @@ export { DefaultHandles, type TLHandlesProps, } from './lib/components/default-components/DefaultHandles' -export { - DefaultHoveredShapeIndicator, - type TLHoveredShapeIndicatorProps, -} from './lib/components/default-components/DefaultHoveredShapeIndicator' export { DefaultScribble, type TLScribbleProps, diff --git a/packages/editor/src/lib/components/default-components/DefaultCanvas.tsx b/packages/editor/src/lib/components/default-components/DefaultCanvas.tsx index a752edb54..05f9d54d1 100644 --- a/packages/editor/src/lib/components/default-components/DefaultCanvas.tsx +++ b/packages/editor/src/lib/components/default-components/DefaultCanvas.tsx @@ -151,8 +151,7 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) { - - + @@ -431,16 +430,17 @@ function ShapesToDisplay() { ) } -function SelectedIdIndicators() { +function ShapeIndicators() { const editor = useEditor() - const selectedShapeIds = useValue('selectedShapeIds', () => editor.getSelectedShapeIds(), [ - editor, - ]) - const shouldDisplay = useValue( + const renderingShapes = useValue('rendering shapes', () => editor.getRenderingShapes(), [editor]) + const rPreviousSelectedShapeIds = useRef>(new Set()) + const idsToDisplay = useValue( 'should display selected ids', () => { - // todo: move to tldraw selected ids wrapper - return ( + // todo: move to tldraw selected ids wrappe + const prev = rPreviousSelectedShapeIds.current + const next = new Set() + if ( editor.isInAny( 'select.idle', 'select.brushing', @@ -449,52 +449,51 @@ function SelectedIdIndicators() { 'select.pointing_shape', 'select.pointing_selection', 'select.pointing_handle' - ) && !editor.getInstanceState().isChangingStyle - ) + ) && + !editor.getInstanceState().isChangingStyle + ) { + const selected = editor.getSelectedShapeIds() + for (const id of selected) { + next.add(id) + } + if (editor.isInAny('select.idle', 'select.editing_shape')) { + const instanceState = editor.getInstanceState() + if (instanceState.isHoveringCanvas && !instanceState.isCoarsePointer) { + const hovered = editor.getHoveredShapeId() + if (hovered) next.add(hovered) + } + } + } + + if (prev.size !== next.size) { + rPreviousSelectedShapeIds.current = next + return next + } + + for (const id of next) { + if (!prev.has(id)) { + rPreviousSelectedShapeIds.current = next + return next + } + } + + return prev }, [editor] ) const { ShapeIndicator } = useEditorComponents() - if (!ShapeIndicator) return null - if (!shouldDisplay) return null return ( <> - {selectedShapeIds.map((id) => ( - + {renderingShapes.map(({ id }) => ( +