@tldraw/editor
Version:
tldraw infinite canvas SDK (editor).
8 lines (7 loc) • 6.08 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../../src/lib/editor/overlays/OverlayUtil.ts"],
"sourcesContent": ["import { TLCursorType } from '@tldraw/tlschema'\nimport { Geometry2d } from '../../primitives/geometry/Geometry2d'\nimport type { Editor } from '../Editor'\nimport { TLPointerEventInfo } from '../types/event-types'\n\n/** @public */\nexport interface TLOverlay<Props = Record<string, unknown>> {\n\t/**\n\t * Globally unique id for this overlay instance across all overlay utils.\n\t * Hit-test and hover lookup key on `id` alone, so utils must namespace their\n\t * ids (e.g. `'selection_fg:top_left'`, `'handle:<shapeId>:<handleId>'`) to\n\t * avoid colliding with overlays from other utils.\n\t */\n\tid: string\n\t/** The overlay util type that owns this instance */\n\ttype: string\n\t/** Arbitrary props for the overlay (handle id, corner name, etc.) */\n\tprops: Props\n}\n\n/** @public */\nexport interface TLOverlayUtilConstructor<U extends OverlayUtil = OverlayUtil> {\n\tnew (editor: Editor): U\n\ttype: string\n\tconfigure<T extends TLOverlayUtilConstructor<any>>(\n\t\tthis: T,\n\t\toptions: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never\n\t): T\n}\n\n/** @public */\nexport type TLAnyOverlayUtilConstructor = TLOverlayUtilConstructor<any>\n\n/**\n * Base class for overlay utilities. Overlays are ephemeral UI elements rendered\n * on top of the canvas (selection handles, rotation corners, shape handles, etc.).\n *\n * Each OverlayUtil defines a type of overlay and knows how to:\n * - Determine when its overlays should be active (predicate)\n * - Produce overlay instances from current editor state\n * - Provide hit-test geometry for interactive overlays\n * - Provide cursor style on hover\n * - Render into a canvas 2D context\n *\n * @public\n */\nexport abstract class OverlayUtil<T extends TLOverlay = TLOverlay> {\n\tconstructor(public editor: Editor) {}\n\tstatic type: string\n\n\t/**\n\t * Options for this overlay util. Override this to provide customization options.\n\t * Use {@link OverlayUtil.configure} to customize existing overlay utils.\n\t *\n\t * `zIndex` controls paint and hit-test order across utils \u2014 higher numbers\n\t * paint on top and are hit-tested first. Ties resolve by registration order.\n\t * Defaults to `0`; built-in utils use larger integers (100, 200, \u2026) with\n\t * gaps so custom utils can slot between.\n\t *\n\t * @public\n\t */\n\toptions: { zIndex?: number } = {}\n\n\t/**\n\t * Create a new overlay util class with the given options merged in.\n\t *\n\t * @example\n\t * ```ts\n\t * const MyBrush = BrushOverlayUtil.configure({ fill: 'rgba(0,0,255,0.1)' })\n\t * ```\n\t *\n\t * @public\n\t */\n\tstatic configure<T extends TLOverlayUtilConstructor<any>>(\n\t\tthis: T,\n\t\toptions: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never\n\t): T {\n\t\t// @ts-expect-error -- typescript has no idea what's going on here but it's fine\n\t\treturn class extends this {\n\t\t\t// @ts-expect-error\n\t\t\toptions = { ...this.options, ...options }\n\t\t}\n\t}\n\n\t/**\n\t * Whether this overlay util's overlays should currently be active.\n\t * Checked reactively to determine which overlays exist at any given time.\n\t */\n\tabstract isActive(): boolean\n\n\t/**\n\t * Returns the overlay instances that currently exist.\n\t * Called only when `isActive()` returns true.\n\t */\n\tabstract getOverlays(): T[]\n\n\t/**\n\t * Returns hit-test geometry for an overlay instance, in page coordinates.\n\t * Return null for non-interactive overlays (e.g. snap indicators, scribbles).\n\t */\n\tgetGeometry(_overlay: T): Geometry2d | null {\n\t\treturn null\n\t}\n\n\t/**\n\t * Returns the cursor type to show when hovering this overlay.\n\t */\n\tgetCursor(_overlay: T): TLCursorType | undefined {\n\t\treturn undefined\n\t}\n\n\t/**\n\t * Called when the user points down on this overlay, before the default\n\t * routing runs. Acts as an interrupt: define it to take over the event.\n\t *\n\t * Return `false` to continue with the default behavior (e.g. the\n\t * built-in rotate/resize handle transitions or shape-handle dispatch).\n\t * Return `true` \u2014 or nothing at all \u2014 to skip the default. In other\n\t * words, once you override this method you own the event unless you\n\t * explicitly opt back in by returning `false`.\n\t */\n\tonPointerDown?(overlay: T, info: TLPointerEventInfo): boolean | void\n\n\t/**\n\t * Render all active overlays into the canvas context.\n\t * The context is already transformed to page space (camera transform applied).\n\t * Called reactively when overlays or editor state changes.\n\t */\n\trender(_ctx: CanvasRenderingContext2D, _overlays: T[]): void {}\n\n\t/**\n\t * Optional: render all active overlays into the minimap canvas.\n\t * The context is already transformed to page space (minimap camera applied),\n\t * so overlays can use the same page-space coordinates as in {@link OverlayUtil.render}.\n\t *\n\t * `zoom` is the minimap's screen-pixels-per-page-unit, analogous to\n\t * `editor.getCamera().z`; use `1 / zoom` for one-minimap-pixel line widths.\n\t *\n\t * Most overlays should leave this blank \u2014 only overlays that are meaningful\n\t * at minimap scale (e.g. brushes, collaborator cursors) should opt in.\n\t */\n\trenderMinimap(_ctx: CanvasRenderingContext2D, _overlays: T[], _zoom: number): void {}\n}\n"],
"mappings": "AA8CO,MAAe,YAA6C;AAAA,EAClE,YAAmB,QAAgB;AAAhB;AAAA,EAAiB;AAAA,EAAjB;AAAA,EACnB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaP,UAA+B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYhC,OAAO,UAEN,SACI;AAEJ,WAAO,cAAc,KAAK;AAAA;AAAA,MAEzB,UAAU,EAAE,GAAG,KAAK,SAAS,GAAG,QAAQ;AAAA,IACzC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,YAAY,UAAgC;AAC3C,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,UAAuC;AAChD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,OAAO,MAAgC,WAAsB;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAa9D,cAAc,MAAgC,WAAgB,OAAqB;AAAA,EAAC;AACrF;",
"names": []
}