diff --git a/apps/examples/src/16-custom-styles/CardShape.tsx b/apps/examples/src/16-custom-styles/CardShape.tsx index 584fe6157..1e32fdab3 100644 --- a/apps/examples/src/16-custom-styles/CardShape.tsx +++ b/apps/examples/src/16-custom-styles/CardShape.tsx @@ -48,8 +48,8 @@ export class CardShapeUtil extends BaseBoxShapeUtil { } } - // Render method — the React component that will be rendered for the shape - render(shape: CardShape) { + // The React component that will be rendered for the shape; can return any HTML elements here + component(shape: CardShape) { const bounds = this.bounds(shape) return ( @@ -71,7 +71,7 @@ export class CardShapeUtil extends BaseBoxShapeUtil { ) } - // Indicator — used when hovering over a shape or when it's selected; must return only SVG elements here + // The indicator shown when hovering over a shape or when it's selected; must return only SVG elements here indicator(shape: CardShape) { return } diff --git a/apps/examples/src/3-custom-config/CardShape.tsx b/apps/examples/src/3-custom-config/CardShape.tsx index 26068222e..3703abf17 100644 --- a/apps/examples/src/3-custom-config/CardShape.tsx +++ b/apps/examples/src/3-custom-config/CardShape.tsx @@ -31,8 +31,8 @@ export class CardShapeUtil extends BaseBoxShapeUtil { } } - // Render method — the React component that will be rendered for the shape - render(shape: CardShape) { + // The React component that will be rendered for the shape; can return any HTML elements here + component(shape: CardShape) { const bounds = this.bounds(shape) return ( diff --git a/apps/examples/src/8-error-boundary/ErrorShape.ts b/apps/examples/src/8-error-boundary/ErrorShape.ts index 29700f37d..56498f99e 100644 --- a/apps/examples/src/8-error-boundary/ErrorShape.ts +++ b/apps/examples/src/8-error-boundary/ErrorShape.ts @@ -9,7 +9,7 @@ export class ErrorShapeUtil extends BaseBoxShapeUtil { defaultProps() { return { message: 'Error!', w: 100, h: 100 } } - render(shape: ErrorShape) { + component(shape: ErrorShape) { throw new Error(shape.props.message) } indicator() { diff --git a/packages/editor/api-report.md b/packages/editor/api-report.md index 42a0adae1..2562ea677 100644 --- a/packages/editor/api-report.md +++ b/packages/editor/api-report.md @@ -109,6 +109,8 @@ export class ArrowShapeUtil extends ShapeUtil { // (undocumented) canSnap: () => boolean; // (undocumented) + component(shape: TLArrowShape): JSX.Element | null; + // (undocumented) defaultProps(): TLArrowShape['props']; // (undocumented) getArrowInfo(shape: TLArrowShape): ArrowInfo | undefined; @@ -155,8 +157,6 @@ export class ArrowShapeUtil extends ShapeUtil { // (undocumented) onTranslateStart: TLOnTranslateStartHandler; // (undocumented) - render(shape: TLArrowShape): JSX.Element | null; - // (undocumented) snapPoints(_shape: TLArrowShape): Vec2d[]; // (undocumented) toSvg(shape: TLArrowShape, font: string, colors: TLExportColors): SVGGElement; @@ -203,6 +203,8 @@ export class BookmarkShapeUtil extends BaseBoxShapeUtil { // (undocumented) canResize: () => boolean; // (undocumented) + component(shape: TLBookmarkShape): JSX.Element; + // (undocumented) defaultProps(): TLBookmarkShape['props']; // (undocumented) hideSelectionBoundsBg: () => boolean; @@ -215,8 +217,6 @@ export class BookmarkShapeUtil extends BaseBoxShapeUtil { // (undocumented) onBeforeUpdate?: TLOnBeforeUpdateHandler; // (undocumented) - render(shape: TLBookmarkShape): JSX.Element; - // (undocumented) static type: "bookmark"; } @@ -312,6 +312,8 @@ export const DrawShape: TLShapeInfo; // @public (undocumented) export class DrawShapeUtil extends ShapeUtil { + // (undocumented) + component(shape: TLDrawShape): JSX.Element; // (undocumented) defaultProps(): TLDrawShape['props']; // (undocumented) @@ -341,8 +343,6 @@ export class DrawShapeUtil extends ShapeUtil { // (undocumented) onResize: TLOnResizeHandler; // (undocumented) - render(shape: TLDrawShape): JSX.Element; - // (undocumented) toSvg(shape: TLDrawShape, _font: string | undefined, colors: TLExportColors): SVGGElement; // (undocumented) static type: "draw"; @@ -727,6 +727,8 @@ export class EmbedShapeUtil extends BaseBoxShapeUtil { // (undocumented) canUnmount: TLShapeUtilFlag; // (undocumented) + component(shape: TLEmbedShape): JSX.Element; + // (undocumented) defaultProps(): TLEmbedShape['props']; // (undocumented) hideSelectionBoundsBg: TLShapeUtilFlag; @@ -739,8 +741,6 @@ export class EmbedShapeUtil extends BaseBoxShapeUtil { // (undocumented) onResize: TLOnResizeHandler; // (undocumented) - render(shape: TLEmbedShape): JSX.Element; - // (undocumented) static type: "embed"; } @@ -792,6 +792,8 @@ export class FrameShapeUtil extends BaseBoxShapeUtil { // (undocumented) canReceiveNewChildrenOfType: (shape: TLShape, _type: TLShape['type']) => boolean; // (undocumented) + component(shape: TLFrameShape): JSX.Element; + // (undocumented) defaultProps(): TLFrameShape['props']; // (undocumented) indicator(shape: TLFrameShape): JSX.Element; @@ -806,8 +808,6 @@ export class FrameShapeUtil extends BaseBoxShapeUtil { // (undocumented) providesBackgroundForChildren(): boolean; // (undocumented) - render(shape: TLFrameShape): JSX.Element; - // (undocumented) toSvg(shape: TLFrameShape, font: string, colors: TLExportColors): Promise | SVGElement; // (undocumented) static type: "frame"; @@ -821,6 +821,8 @@ export class GeoShapeUtil extends BaseBoxShapeUtil { // (undocumented) canEdit: () => boolean; // (undocumented) + component(shape: TLGeoShape): JSX.Element; + // (undocumented) defaultProps(): TLGeoShape['props']; // (undocumented) getBounds(shape: TLGeoShape): Box2d; @@ -927,8 +929,6 @@ export class GeoShapeUtil extends BaseBoxShapeUtil { // (undocumented) onResize: TLOnResizeHandler; // (undocumented) - render(shape: TLGeoShape): JSX.Element; - // (undocumented) toSvg(shape: TLGeoShape, font: string, colors: TLExportColors): SVGElement; // (undocumented) static type: "geo"; @@ -1041,6 +1041,8 @@ export class GroupShapeUtil extends ShapeUtil { // (undocumented) canBind: () => boolean; // (undocumented) + component(shape: TLGroupShape): JSX.Element | null; + // (undocumented) defaultProps(): TLGroupShape['props']; // (undocumented) getBounds(shape: TLGroupShape): Box2d; @@ -1057,8 +1059,6 @@ export class GroupShapeUtil extends ShapeUtil { // (undocumented) onChildrenChange: TLOnChildrenChangeHandler; // (undocumented) - render(shape: TLGroupShape): JSX.Element | null; - // (undocumented) static type: "group"; // (undocumented) type: "group"; @@ -1083,6 +1083,8 @@ export const HighlightShape: TLShapeInfo; // @public (undocumented) export class HighlightShapeUtil extends ShapeUtil { + // (undocumented) + component(shape: TLHighlightShape): JSX.Element; // (undocumented) defaultProps(): TLHighlightShape['props']; // (undocumented) @@ -1110,8 +1112,6 @@ export class HighlightShapeUtil extends ShapeUtil { // (undocumented) onResize: TLOnResizeHandler; // (undocumented) - render(shape: TLHighlightShape): JSX.Element; - // (undocumented) renderBackground(shape: TLHighlightShape): JSX.Element; // (undocumented) toBackgroundSvg(shape: TLHighlightShape, font: string | undefined, colors: TLExportColors): SVGPathElement; @@ -1135,6 +1135,8 @@ export class ImageShapeUtil extends BaseBoxShapeUtil { // (undocumented) canCrop: () => boolean; // (undocumented) + component(shape: TLImageShape): JSX.Element; + // (undocumented) defaultProps(): TLImageShape['props']; // (undocumented) indicator(shape: TLImageShape): JSX.Element | null; @@ -1145,8 +1147,6 @@ export class ImageShapeUtil extends BaseBoxShapeUtil { // (undocumented) onDoubleClickEdge: TLOnDoubleClickHandler; // (undocumented) - render(shape: TLImageShape): JSX.Element; - // (undocumented) toSvg(shape: TLImageShape): Promise; // (undocumented) static type: "image"; @@ -1181,6 +1181,8 @@ export const LineShape: TLShapeInfo; // @public (undocumented) export class LineShapeUtil extends ShapeUtil { + // (undocumented) + component(shape: TLLineShape): JSX.Element | undefined; // (undocumented) defaultProps(): TLLineShape['props']; // (undocumented) @@ -1214,8 +1216,6 @@ export class LineShapeUtil extends ShapeUtil { // (undocumented) onResize: TLOnResizeHandler; // (undocumented) - render(shape: TLLineShape): JSX.Element | undefined; - // (undocumented) toSvg(shape: TLLineShape, _font: string, colors: TLExportColors): SVGGElement; // (undocumented) static type: "line"; @@ -1650,6 +1650,8 @@ export class NoteShapeUtil extends ShapeUtil { // (undocumented) canEdit: () => boolean; // (undocumented) + component(shape: TLNoteShape): JSX.Element; + // (undocumented) defaultProps(): TLNoteShape['props']; // (undocumented) getBounds(shape: TLNoteShape): Box2d; @@ -1716,8 +1718,6 @@ export class NoteShapeUtil extends ShapeUtil { // (undocumented) onEditEnd: TLOnEditEndHandler; // (undocumented) - render(shape: TLNoteShape): JSX.Element; - // (undocumented) toSvg(shape: TLNoteShape, font: string, colors: TLExportColors): SVGGElement; // (undocumented) static type: "note"; @@ -1833,6 +1833,7 @@ export abstract class ShapeUtil { canSnap: TLShapeUtilFlag; canUnmount: TLShapeUtilFlag; center(shape: Shape): Vec2d; + abstract component(shape: Shape): any; abstract defaultProps(): Shape['props']; // (undocumented) editor: Editor; @@ -1889,7 +1890,6 @@ export abstract class ShapeUtil { outlineSegments(shape: Shape): Vec2d[][]; // @internal providesBackgroundForChildren(shape: Shape): boolean; - abstract render(shape: Shape): any; // @internal renderBackground?(shape: Shape): any; // (undocumented) @@ -2020,6 +2020,8 @@ export class TextShapeUtil extends ShapeUtil { // (undocumented) canEdit: () => boolean; // (undocumented) + component(shape: TLTextShape): JSX.Element; + // (undocumented) defaultProps(): TLTextShape['props']; // (undocumented) getBounds(shape: TLTextShape): Box2d; @@ -2103,8 +2105,6 @@ export class TextShapeUtil extends ShapeUtil { // (undocumented) onResize: TLOnResizeHandler; // (undocumented) - render(shape: TLTextShape): JSX.Element; - // (undocumented) toSvg(shape: TLTextShape, font: string | undefined, colors: TLExportColors): SVGGElement; // (undocumented) static type: "text"; @@ -2763,14 +2763,14 @@ export class VideoShapeUtil extends BaseBoxShapeUtil { // (undocumented) canEdit: () => boolean; // (undocumented) + component(shape: TLVideoShape): JSX.Element; + // (undocumented) defaultProps(): TLVideoShape['props']; // (undocumented) indicator(shape: TLVideoShape): JSX.Element; // (undocumented) isAspectRatioLocked: () => boolean; // (undocumented) - render(shape: TLVideoShape): JSX.Element; - // (undocumented) toSvg(shape: TLVideoShape): SVGGElement; // (undocumented) static type: "video"; diff --git a/packages/editor/src/lib/components/Shape.tsx b/packages/editor/src/lib/components/Shape.tsx index 28c13bc80..e370644d5 100644 --- a/packages/editor/src/lib/components/Shape.tsx +++ b/packages/editor/src/lib/components/Shape.tsx @@ -155,7 +155,7 @@ export const Shape = track(function Shape({ const InnerShape = React.memo( function InnerShape({ shape, util }: { shape: T; util: ShapeUtil }) { - return useStateTracking('InnerShape:' + util.type, () => util.render(shape)) + return useStateTracking('InnerShape:' + util.type, () => util.component(shape)) }, (prev, next) => prev.shape.props === next.shape.props ) diff --git a/packages/editor/src/lib/editor/shapes/ShapeUtil.ts b/packages/editor/src/lib/editor/shapes/ShapeUtil.ts index ab2e86e90..c6585c20f 100644 --- a/packages/editor/src/lib/editor/shapes/ShapeUtil.ts +++ b/packages/editor/src/lib/editor/shapes/ShapeUtil.ts @@ -183,7 +183,7 @@ export abstract class ShapeUtil { * @param shape - The shape. * @public */ - abstract render(shape: Shape): any + abstract component(shape: Shape): any /** * Get JSX describing the shape's indicator (as an SVG element). diff --git a/packages/editor/src/lib/editor/shapes/arrow/ArrowShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/arrow/ArrowShapeUtil.tsx index cab7b1bcf..c45c3eafa 100644 --- a/packages/editor/src/lib/editor/shapes/arrow/ArrowShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/arrow/ArrowShapeUtil.tsx @@ -559,7 +559,7 @@ export class ArrowShapeUtil extends ShapeUtil { return false } - render(shape: TLArrowShape) { + component(shape: TLArrowShape) { // Not a class component, but eslint can't tell that :( const onlySelectedShape = this.editor.onlySelectedShape const shouldDisplayHandles = diff --git a/packages/editor/src/lib/editor/shapes/bookmark/BookmarkShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/bookmark/BookmarkShapeUtil.tsx index 96a19824d..e5231e86b 100644 --- a/packages/editor/src/lib/editor/shapes/bookmark/BookmarkShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/bookmark/BookmarkShapeUtil.tsx @@ -32,7 +32,7 @@ export class BookmarkShapeUtil extends BaseBoxShapeUtil { } } - override render(shape: TLBookmarkShape) { + override component(shape: TLBookmarkShape) { const asset = ( shape.props.assetId ? this.editor.getAssetById(shape.props.assetId) : null ) as TLBookmarkAsset diff --git a/packages/editor/src/lib/editor/shapes/draw/DrawShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/draw/DrawShapeUtil.tsx index 18b0167a6..74dfd3bfe 100644 --- a/packages/editor/src/lib/editor/shapes/draw/DrawShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/draw/DrawShapeUtil.tsx @@ -117,7 +117,7 @@ export class DrawShapeUtil extends ShapeUtil { return false } - render(shape: TLDrawShape) { + component(shape: TLDrawShape) { const forceSolid = useForceSolid() const strokeWidth = STROKE_SIZES[shape.props.size] const allPointsFromSegments = getPointsFromSegments(shape.props.segments) diff --git a/packages/editor/src/lib/editor/shapes/embed/EmbedShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/embed/EmbedShapeUtil.tsx index eb5c30a11..d34eaaa4a 100644 --- a/packages/editor/src/lib/editor/shapes/embed/EmbedShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/embed/EmbedShapeUtil.tsx @@ -72,7 +72,7 @@ export class EmbedShapeUtil extends BaseBoxShapeUtil { return resizeBox(shape, info, { minWidth, minHeight }) } - override render(shape: TLEmbedShape) { + override component(shape: TLEmbedShape) { const { w, h, url } = shape.props const isEditing = useIsEditing(shape.id) const embedInfo = useMemo(() => getEmbedInfoUnsafely(url), [url]) diff --git a/packages/editor/src/lib/editor/shapes/frame/FrameShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/frame/FrameShapeUtil.tsx index bdb3926f4..e7c92a725 100644 --- a/packages/editor/src/lib/editor/shapes/frame/FrameShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/frame/FrameShapeUtil.tsx @@ -22,7 +22,7 @@ export class FrameShapeUtil extends BaseBoxShapeUtil { return { w: 160 * 2, h: 90 * 2, name: '' } } - override render(shape: TLFrameShape) { + override component(shape: TLFrameShape) { const bounds = this.bounds(shape) return ( diff --git a/packages/editor/src/lib/editor/shapes/geo/GeoShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/geo/GeoShapeUtil.tsx index cf0bde48c..0fcfb3c66 100644 --- a/packages/editor/src/lib/editor/shapes/geo/GeoShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/geo/GeoShapeUtil.tsx @@ -335,7 +335,7 @@ export class GeoShapeUtil extends BaseBoxShapeUtil { } } - render(shape: TLGeoShape) { + component(shape: TLGeoShape) { const { id, type, props } = shape const forceSolid = useForceSolid() diff --git a/packages/editor/src/lib/editor/shapes/group/GroupShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/group/GroupShapeUtil.tsx index dd05161dd..9e874feea 100644 --- a/packages/editor/src/lib/editor/shapes/group/GroupShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/group/GroupShapeUtil.tsx @@ -43,7 +43,7 @@ export class GroupShapeUtil extends ShapeUtil { return this.bounds(shape).corners } - render(shape: TLGroupShape) { + component(shape: TLGroupShape) { // Not a class component, but eslint can't tell that :( const { erasingIdsSet, diff --git a/packages/editor/src/lib/editor/shapes/highlight/HighlightShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/highlight/HighlightShapeUtil.tsx index a9bc658f8..3df53ee48 100644 --- a/packages/editor/src/lib/editor/shapes/highlight/HighlightShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/highlight/HighlightShapeUtil.tsx @@ -92,7 +92,7 @@ export class HighlightShapeUtil extends ShapeUtil { return false } - render(shape: TLHighlightShape) { + component(shape: TLHighlightShape) { return ( { } } - render(shape: TLImageShape) { + component(shape: TLImageShape) { const containerStyle = getContainerStyle(shape) const isCropping = useIsCropping(shape.id) const prefersReducedMotion = usePrefersReducedMotion() diff --git a/packages/editor/src/lib/editor/shapes/line/LineShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/line/LineShapeUtil.tsx index 50a608cf6..5b45df524 100644 --- a/packages/editor/src/lib/editor/shapes/line/LineShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/line/LineShapeUtil.tsx @@ -181,7 +181,7 @@ export class LineShapeUtil extends ShapeUtil { return intersectLineSegmentPolyline(A, B, this.outline(shape)) !== null } - render(shape: TLLineShape) { + component(shape: TLLineShape) { const forceSolid = useForceSolid() const spline = getSplineForLineShape(shape) const strokeWidth = STROKE_SIZES[shape.props.size] diff --git a/packages/editor/src/lib/editor/shapes/note/NoteShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/note/NoteShapeUtil.tsx index 5c2d4918c..c1765a1f6 100644 --- a/packages/editor/src/lib/editor/shapes/note/NoteShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/note/NoteShapeUtil.tsx @@ -49,7 +49,7 @@ export class NoteShapeUtil extends ShapeUtil { return new Vec2d(NOTE_SIZE / 2, this.getHeight(_shape) / 2) } - render(shape: TLNoteShape) { + component(shape: TLNoteShape) { const { id, type, diff --git a/packages/editor/src/lib/editor/shapes/text/TextShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/text/TextShapeUtil.tsx index c498d5f97..55751e94e 100644 --- a/packages/editor/src/lib/editor/shapes/text/TextShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/text/TextShapeUtil.tsx @@ -78,7 +78,7 @@ export class TextShapeUtil extends ShapeUtil { return new Vec2d(bounds.width / 2, bounds.height / 2) } - render(shape: TLTextShape) { + component(shape: TLTextShape) { const { id, type, diff --git a/packages/editor/src/lib/editor/shapes/video/VideoShapeUtil.tsx b/packages/editor/src/lib/editor/shapes/video/VideoShapeUtil.tsx index c1c5b787a..f41f034f9 100644 --- a/packages/editor/src/lib/editor/shapes/video/VideoShapeUtil.tsx +++ b/packages/editor/src/lib/editor/shapes/video/VideoShapeUtil.tsx @@ -27,7 +27,7 @@ export class VideoShapeUtil extends BaseBoxShapeUtil { } } - render(shape: TLVideoShape) { + component(shape: TLVideoShape) { return } diff --git a/packages/editor/src/lib/test/Editor.test.tsx b/packages/editor/src/lib/test/Editor.test.tsx index 94d22cd23..270d8fc45 100644 --- a/packages/editor/src/lib/test/Editor.test.tsx +++ b/packages/editor/src/lib/test/Editor.test.tsx @@ -458,7 +458,7 @@ describe('getShapeUtil', () => { defaultProps() { throw new Error('Method not implemented.') } - render() { + component() { throw new Error('Method not implemented.') } indicator() { @@ -478,7 +478,7 @@ describe('getShapeUtil', () => { defaultProps() { throw new Error('Method not implemented.') } - render() { + component() { throw new Error('Method not implemented.') } indicator() { diff --git a/packages/editor/src/lib/test/TldrawEditor.test.tsx b/packages/editor/src/lib/test/TldrawEditor.test.tsx index 5e7cf4b4b..1c7eed32e 100644 --- a/packages/editor/src/lib/test/TldrawEditor.test.tsx +++ b/packages/editor/src/lib/test/TldrawEditor.test.tsx @@ -282,7 +282,7 @@ describe('Custom shapes', () => { } } - render(shape: CardShape) { + component(shape: CardShape) { const bounds = this.bounds(shape) return ( diff --git a/packages/editor/src/lib/test/tools/translating.test.ts b/packages/editor/src/lib/test/tools/translating.test.ts index 10db21b0d..e62a2108d 100644 --- a/packages/editor/src/lib/test/tools/translating.test.ts +++ b/packages/editor/src/lib/test/tools/translating.test.ts @@ -28,7 +28,7 @@ class __TopLeftSnapOnlyShapeUtil extends ShapeUtil<__TopLeftSnapOnlyShape> { Vec2d.From({ x: shape.x, y: shape.y + shape.props.height }), ] } - render() { + component() { throw new Error('Method not implemented.') } indicator() {