@grida/svg-editor 1.0.0-alpha.1 → 1.0.0-alpha.3

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/dom.d.mts CHANGED
@@ -1,16 +1,48 @@
1
- import { a as SurfaceHandle, o as SvgEditor } from "./editor-JY7AQrR1.mjs";
1
+ import { a as SurfaceHandle, d as Gestures, g as Camera, o as SvgEditor } from "./editor-DSADZszj.mjs";
2
+ import cmath from "@grida/cmath";
2
3
 
3
4
  //#region src/dom.d.ts
4
5
  type DomSurfaceOptions = {
5
6
  /** Mount the SVG inside this container. */container: HTMLElement;
7
+ /**
8
+ * Install the default gesture set (wheel-pan/zoom, space-drag, middle-mouse,
9
+ * keyboard zoom). Default `true`. Pass `false` to start blank and bind à la
10
+ * carte via `handle.gestures.bind(...)`.
11
+ */
12
+ gestures?: boolean;
13
+ /**
14
+ * Auto-fit the document into the viewport on initial attach. Default
15
+ * `false`. Mirrors Excalidraw's `initialData.scrollToContent`.
16
+ * Subsequent `editor.load()` calls do NOT re-fit — call
17
+ * `handle.camera.fit("<root>")` yourself if you want that behavior.
18
+ */
19
+ fit?: boolean;
20
+ /**
21
+ * Initial camera transform. Default `cmath.transform.identity`. Ignored
22
+ * when `fit: true`.
23
+ */
24
+ initial_camera?: cmath.Transform;
6
25
  };
7
26
  /**
8
- * Attach a DOM surface to a headless editor. Returns a `SurfaceHandle` whose
9
- * `detach()` is the inverse DOM cleared, listeners removed.
27
+ * Surface handle for the DOM surface. Extends the editor's core
28
+ * `SurfaceHandle` with the viewport-scoped concerns: pan/zoom (`camera`)
29
+ * and pointer/wheel/keyboard gesture bindings (`gestures`).
30
+ *
31
+ * Camera + gestures are **surface-scoped**: detaching the surface drops
32
+ * both. They never appear on the headless `SvgEditor`.
33
+ */
34
+ type DomSurfaceHandle = SurfaceHandle & {
35
+ camera: Camera;
36
+ gestures: Gestures;
37
+ };
38
+ /**
39
+ * Attach a DOM surface to a headless editor. Returns a `DomSurfaceHandle`
40
+ * whose `detach()` is the inverse — DOM cleared, listeners removed,
41
+ * gestures uninstalled.
10
42
  *
11
43
  * Usage is one-shot per container: the surface owns the container's children
12
44
  * for its lifetime, and `detach()` restores it to empty.
13
45
  */
14
- declare function attach_dom_surface(editor: SvgEditor, options: DomSurfaceOptions): SurfaceHandle;
46
+ declare function attach_dom_surface(editor: SvgEditor, options: DomSurfaceOptions): DomSurfaceHandle;
15
47
  //#endregion
16
- export { DomSurfaceOptions, attach_dom_surface };
48
+ export { DomSurfaceHandle, DomSurfaceOptions, attach_dom_surface };
package/dist/dom.d.ts CHANGED
@@ -1,16 +1,48 @@
1
- import { a as SurfaceHandle, o as SvgEditor } from "./editor-CTtU2gu4.js";
1
+ import { a as SurfaceHandle, d as Gestures, g as Camera, o as SvgEditor } from "./editor-Da446SPO.js";
2
+ import cmath from "@grida/cmath";
2
3
 
3
4
  //#region src/dom.d.ts
4
5
  type DomSurfaceOptions = {
5
6
  /** Mount the SVG inside this container. */container: HTMLElement;
7
+ /**
8
+ * Install the default gesture set (wheel-pan/zoom, space-drag, middle-mouse,
9
+ * keyboard zoom). Default `true`. Pass `false` to start blank and bind à la
10
+ * carte via `handle.gestures.bind(...)`.
11
+ */
12
+ gestures?: boolean;
13
+ /**
14
+ * Auto-fit the document into the viewport on initial attach. Default
15
+ * `false`. Mirrors Excalidraw's `initialData.scrollToContent`.
16
+ * Subsequent `editor.load()` calls do NOT re-fit — call
17
+ * `handle.camera.fit("<root>")` yourself if you want that behavior.
18
+ */
19
+ fit?: boolean;
20
+ /**
21
+ * Initial camera transform. Default `cmath.transform.identity`. Ignored
22
+ * when `fit: true`.
23
+ */
24
+ initial_camera?: cmath.Transform;
6
25
  };
7
26
  /**
8
- * Attach a DOM surface to a headless editor. Returns a `SurfaceHandle` whose
9
- * `detach()` is the inverse DOM cleared, listeners removed.
27
+ * Surface handle for the DOM surface. Extends the editor's core
28
+ * `SurfaceHandle` with the viewport-scoped concerns: pan/zoom (`camera`)
29
+ * and pointer/wheel/keyboard gesture bindings (`gestures`).
30
+ *
31
+ * Camera + gestures are **surface-scoped**: detaching the surface drops
32
+ * both. They never appear on the headless `SvgEditor`.
33
+ */
34
+ type DomSurfaceHandle = SurfaceHandle & {
35
+ camera: Camera;
36
+ gestures: Gestures;
37
+ };
38
+ /**
39
+ * Attach a DOM surface to a headless editor. Returns a `DomSurfaceHandle`
40
+ * whose `detach()` is the inverse — DOM cleared, listeners removed,
41
+ * gestures uninstalled.
10
42
  *
11
43
  * Usage is one-shot per container: the surface owns the container's children
12
44
  * for its lifetime, and `detach()` restores it to empty.
13
45
  */
14
- declare function attach_dom_surface(editor: SvgEditor, options: DomSurfaceOptions): SurfaceHandle;
46
+ declare function attach_dom_surface(editor: SvgEditor, options: DomSurfaceOptions): DomSurfaceHandle;
15
47
  //#endregion
16
- export { DomSurfaceOptions, attach_dom_surface };
48
+ export { DomSurfaceHandle, DomSurfaceOptions, attach_dom_surface };
package/dist/dom.js CHANGED
@@ -1,3 +1,3 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dom = require("./dom-CfP_ZURh.js");
2
+ const require_dom = require("./dom-BlJZWpR_.js");
3
3
  exports.attach_dom_surface = require_dom.attach_dom_surface;
package/dist/dom.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as attach_dom_surface } from "./dom-kA8NDuVh.mjs";
1
+ import { t as attach_dom_surface } from "./dom-D-5D_3o0.mjs";
2
2
  export { attach_dom_surface };
@@ -1,4 +1,4 @@
1
- import { i as apply_translate, n as serialize_paint, o as capture_translate_baseline, t as parse_paint } from "./paint-DuCg6Y-K.mjs";
1
+ import { i as apply_translate, l as is_text_input_focused, n as serialize_paint, o as capture_translate_baseline, t as parse_paint } from "./paint-BTKvRItP.mjs";
2
2
  import { HistoryImpl } from "@grida/history";
3
3
  import { KeyCode, M, chunkKey, eventToChunk, getKeyboardOS, kb, keybindingsToKeyCodes } from "@grida/keybinding";
4
4
  //#region src/commands/registry.ts
@@ -111,15 +111,6 @@ const TEXT_INPUT_SAFE_MODS = new Set([
111
111
  KeyCode.Ctrl,
112
112
  KeyCode.Alt
113
113
  ]);
114
- function is_text_input_focused() {
115
- if (typeof document === "undefined") return false;
116
- const el = document.activeElement;
117
- if (!el) return false;
118
- const tag = el.tagName;
119
- if (tag === "INPUT" || tag === "TEXTAREA") return true;
120
- if (el.isContentEditable) return true;
121
- return false;
122
- }
123
114
  var Keymap = class {
124
115
  constructor(commands, platformGetter = getKeyboardOS) {
125
116
  this.commands = commands;
@@ -1797,6 +1788,8 @@ function createSvgEditor(opts) {
1797
1788
  providers,
1798
1789
  _internal: {
1799
1790
  doc,
1791
+ history: { preview: (label) => history.preview(label) },
1792
+ emit,
1800
1793
  set_content_edit_driver(fn) {
1801
1794
  content_edit_driver = fn;
1802
1795
  },
@@ -1,112 +1,7 @@
1
+ import * as _$_grida_history0 from "@grida/history";
1
2
  import { Keybinding, Platform } from "@grida/keybinding";
3
+ import cmath from "@grida/cmath";
2
4
 
3
- //#region src/commands/registry.d.ts
4
- /**
5
- * Command registry.
6
- *
7
- * A passive id-keyed registry of handlers. Built so that:
8
- *
9
- * - keybindings (in `src/keymap`) can address commands by stable id;
10
- * - new commands can be added in ONE place (`src/commands/defaults.ts`)
11
- * without growing the public surface of the editor;
12
- * - "one key, many meanings" can be expressed via chain semantics: a
13
- * handler returns `true` if it consumed, `false`/`void` otherwise,
14
- * and the dispatcher tries the next candidate in the chain.
15
- *
16
- * Handlers are plain closures — they capture whatever editor reference
17
- * they need. The registry itself stays unaware of the editor's type,
18
- * which avoids a circular type dependency between editor and registry.
19
- */
20
- /** Stable, dotted id for a command, e.g. `"history.undo"`. */
21
- type CommandId = string;
22
- /**
23
- * A command handler.
24
- *
25
- * Return `true` if the handler consumed the invocation. Return `false`
26
- * or `undefined` to signal "did not apply" — the dispatcher will try
27
- * the next candidate registered for the same key.
28
- *
29
- * Handlers are closures: they capture their editor reference. No
30
- * editor parameter is passed — keep handlers self-contained.
31
- */
32
- type CommandHandler = (args?: unknown) => boolean | void;
33
- declare class CommandRegistry {
34
- private readonly map;
35
- /**
36
- * Register a command. Returns an unregister function. Re-registering
37
- * the same id replaces the previous handler (last writer wins).
38
- */
39
- register(id: CommandId, handler: CommandHandler): () => void;
40
- /**
41
- * Invoke a command by id. Returns `true` if the handler consumed,
42
- * `false` otherwise (including unknown ids and handlers that returned
43
- * `false`/`undefined`).
44
- */
45
- invoke(id: CommandId, args?: unknown): boolean;
46
- has(id: CommandId): boolean;
47
- /** All registered ids, for debugging / introspection. */
48
- ids(): readonly CommandId[];
49
- }
50
- //#endregion
51
- //#region src/keymap/keymap.d.ts
52
- type KeymapBinding = {
53
- /** Declarative key combination. Build with `kb()` / `c()` / `seq()`. */keybinding: Keybinding; /** Command id to invoke on match. */
54
- command: CommandId; /** Forwarded as the `args` parameter to the command handler. */
55
- args?: unknown; /** Higher priorities run first in the chain. Default 0. */
56
- priority?: number;
57
- /**
58
- * Reserved for V2; not honored by the V1 dispatcher. When added, this
59
- * will be evaluated before the handler runs; if false, the binding is
60
- * skipped without invoking the handler.
61
- */
62
- when?: (ctx: unknown) => boolean;
63
- };
64
- declare class Keymap {
65
- private readonly commands;
66
- private readonly platformGetter;
67
- /**
68
- * Bindings bucketed by canonical chunk-key hash, computed per
69
- * `@grida/keybinding`'s `chunkKey`. Each list is the chain for that
70
- * key, sorted in dispatch order (priority desc, then registration
71
- * order).
72
- */
73
- private readonly buckets;
74
- /** Insert order, so ties on priority are deterministic. */
75
- private seq;
76
- constructor(commands: CommandRegistry, platformGetter?: () => Platform);
77
- /**
78
- * Bind a key combination to a command. Returns an unbind function.
79
- * The same `Keybinding` can be bound to multiple commands — they will
80
- * all be tried in chain order on dispatch.
81
- */
82
- bind(binding: KeymapBinding): () => void;
83
- /**
84
- * Remove bindings matching the spec. If both filters are passed, only
85
- * bindings that match BOTH are removed.
86
- */
87
- unbind(spec: {
88
- keybinding?: Keybinding;
89
- command?: CommandId;
90
- }): void;
91
- /** All registered bindings, for introspection. Order is not guaranteed. */
92
- bindings(): readonly KeymapBinding[];
93
- /**
94
- * Match the event against bound chunks, then run candidates in chain
95
- * order. Returns `true` and calls `preventDefault()` on the first
96
- * handler that consumes; returns `false` if nothing matched or all
97
- * matches fell through.
98
- */
99
- dispatch(event: KeyboardEvent): boolean;
100
- /**
101
- * Compute the set of canonical hashes a `Keybinding` lights up. A
102
- * binding with aliases (multiple sequences) contributes one hash per
103
- * single-chunk alias; multi-chunk sequences (chords) are skipped in
104
- * V1.
105
- */
106
- private chunkKeysFor;
107
- private has_safe_mod;
108
- }
109
- //#endregion
110
5
  //#region src/types.d.ts
111
6
  /**
112
7
  * Stable identifier for a node in the editor's document model.
@@ -277,6 +172,206 @@ type PaintPreviewSession = {
277
172
  discard(): void;
278
173
  };
279
174
  //#endregion
175
+ //#region src/core/camera.d.ts
176
+ /**
177
+ * Returns world-space bounds for the given target, or `null` when
178
+ * unresolvable (e.g. empty selection, unknown node id). Implemented by the
179
+ * surface — the camera itself has no view into the document.
180
+ *
181
+ * Only string targets are passed to the resolver — `Rect` targets are
182
+ * handled by the camera as identity (the rect IS its own bounds).
183
+ */
184
+ type BoundsResolver = (target: "<root>" | "<selection>" | NodeId) => Rect | null;
185
+ type CameraOptions = {
186
+ resolve_bounds: BoundsResolver;
187
+ initial?: cmath.Transform;
188
+ };
189
+ /**
190
+ * Surface-scoped pan/zoom state.
191
+ *
192
+ * The public shape leads with the peer convention (`center` / `zoom` /
193
+ * `bounds`) and keeps the matrix as an advanced read. Methods mirror
194
+ * Figma/Penpot where they overlap.
195
+ */
196
+ declare class Camera {
197
+ private _transform;
198
+ private viewport_w;
199
+ private viewport_h;
200
+ private listeners;
201
+ private resolve_bounds;
202
+ constructor(opts: CameraOptions);
203
+ /** Underlying 2D affine. World→screen. */
204
+ get transform(): cmath.Transform;
205
+ /** Uniform scale factor. 1 = 100 %. */
206
+ get zoom(): number;
207
+ /** World-space point currently at viewport center. */
208
+ get center(): Vec2;
209
+ /** World-space rectangle visible in the viewport. */
210
+ get bounds(): Rect;
211
+ /** Translate the camera by a screen-space delta. */
212
+ pan(delta_screen: Vec2): void;
213
+ /**
214
+ * Multiply zoom by `factor` keeping `origin_screen` fixed in world space.
215
+ * Used by wheel-zoom-at-cursor and pinch-zoom.
216
+ */
217
+ zoom_at(factor: number, origin_screen: Vec2): void;
218
+ /** Pan so `c` lands at the viewport center. Zoom unchanged. */
219
+ set_center(c: Vec2): void;
220
+ /** Set zoom directly; pivot defaults to viewport center. */
221
+ set_zoom(z: number, pivot_screen?: Vec2): void;
222
+ /**
223
+ * Replace the entire transform.
224
+ *
225
+ * Idempotent: when the new transform is element-wise equal to the current
226
+ * one, this is a no-op (no notification fires). This is the seam that
227
+ * makes external constraint loops (e.g. "subscribe → compute clamped →
228
+ * set_transform") terminate: the clamp re-emits the same transform on
229
+ * the second pass, set_transform short-circuits, no recursion.
230
+ */
231
+ set_transform(t: cmath.Transform): void;
232
+ /** Viewport size in screen pixels. Read by host code computing constraints. */
233
+ get viewport_size(): {
234
+ width: number;
235
+ height: number;
236
+ };
237
+ /**
238
+ * Fit a target into the viewport.
239
+ *
240
+ * - `"<root>"` — the document root's content bounds (host-resolved).
241
+ * - `"<selection>"` — current editor.state.selection's union bounds.
242
+ * - `NodeId` — that node's content bounds.
243
+ * - `Rect` — an explicit world-space rectangle.
244
+ *
245
+ * No-ops if the target resolves to `null` (e.g. empty selection) or if
246
+ * the viewport size is 0 (no container).
247
+ */
248
+ fit(target: "<root>" | "<selection>" | NodeId | Rect, opts?: {
249
+ margin?: number;
250
+ }): void;
251
+ /** Snap back to identity. */
252
+ reset(): void;
253
+ /**
254
+ * Subscribe to camera changes. Fires on every mutation. Cheap channel —
255
+ * does NOT bump `editor.state.version`. Same pattern as
256
+ * `editor.subscribe_surface_hover`.
257
+ */
258
+ subscribe(cb: () => void): Unsubscribe;
259
+ /** @internal Surface drives this on container resize. */
260
+ _set_viewport_size(w: number, h: number): void;
261
+ /** Convert a screen-space point to world-space. */
262
+ screen_to_world(p: Vec2): Vec2;
263
+ /** Convert a world-space point to screen-space. */
264
+ world_to_screen(p: Vec2): Vec2;
265
+ private notify;
266
+ }
267
+ //#endregion
268
+ //#region src/commands/registry.d.ts
269
+ /**
270
+ * Command registry.
271
+ *
272
+ * A passive id-keyed registry of handlers. Built so that:
273
+ *
274
+ * - keybindings (in `src/keymap`) can address commands by stable id;
275
+ * - new commands can be added in ONE place (`src/commands/defaults.ts`)
276
+ * without growing the public surface of the editor;
277
+ * - "one key, many meanings" can be expressed via chain semantics: a
278
+ * handler returns `true` if it consumed, `false`/`void` otherwise,
279
+ * and the dispatcher tries the next candidate in the chain.
280
+ *
281
+ * Handlers are plain closures — they capture whatever editor reference
282
+ * they need. The registry itself stays unaware of the editor's type,
283
+ * which avoids a circular type dependency between editor and registry.
284
+ */
285
+ /** Stable, dotted id for a command, e.g. `"history.undo"`. */
286
+ type CommandId = string;
287
+ /**
288
+ * A command handler.
289
+ *
290
+ * Return `true` if the handler consumed the invocation. Return `false`
291
+ * or `undefined` to signal "did not apply" — the dispatcher will try
292
+ * the next candidate registered for the same key.
293
+ *
294
+ * Handlers are closures: they capture their editor reference. No
295
+ * editor parameter is passed — keep handlers self-contained.
296
+ */
297
+ type CommandHandler = (args?: unknown) => boolean | void;
298
+ declare class CommandRegistry {
299
+ private readonly map;
300
+ /**
301
+ * Register a command. Returns an unregister function. Re-registering
302
+ * the same id replaces the previous handler (last writer wins).
303
+ */
304
+ register(id: CommandId, handler: CommandHandler): () => void;
305
+ /**
306
+ * Invoke a command by id. Returns `true` if the handler consumed,
307
+ * `false` otherwise (including unknown ids and handlers that returned
308
+ * `false`/`undefined`).
309
+ */
310
+ invoke(id: CommandId, args?: unknown): boolean;
311
+ has(id: CommandId): boolean;
312
+ /** All registered ids, for debugging / introspection. */
313
+ ids(): readonly CommandId[];
314
+ }
315
+ //#endregion
316
+ //#region src/keymap/keymap.d.ts
317
+ type KeymapBinding = {
318
+ /** Declarative key combination. Build with `kb()` / `c()` / `seq()`. */keybinding: Keybinding; /** Command id to invoke on match. */
319
+ command: CommandId; /** Forwarded as the `args` parameter to the command handler. */
320
+ args?: unknown; /** Higher priorities run first in the chain. Default 0. */
321
+ priority?: number;
322
+ /**
323
+ * Reserved for V2; not honored by the V1 dispatcher. When added, this
324
+ * will be evaluated before the handler runs; if false, the binding is
325
+ * skipped without invoking the handler.
326
+ */
327
+ when?: (ctx: unknown) => boolean;
328
+ };
329
+ declare class Keymap {
330
+ private readonly commands;
331
+ private readonly platformGetter;
332
+ /**
333
+ * Bindings bucketed by canonical chunk-key hash, computed per
334
+ * `@grida/keybinding`'s `chunkKey`. Each list is the chain for that
335
+ * key, sorted in dispatch order (priority desc, then registration
336
+ * order).
337
+ */
338
+ private readonly buckets;
339
+ /** Insert order, so ties on priority are deterministic. */
340
+ private seq;
341
+ constructor(commands: CommandRegistry, platformGetter?: () => Platform);
342
+ /**
343
+ * Bind a key combination to a command. Returns an unbind function.
344
+ * The same `Keybinding` can be bound to multiple commands — they will
345
+ * all be tried in chain order on dispatch.
346
+ */
347
+ bind(binding: KeymapBinding): () => void;
348
+ /**
349
+ * Remove bindings matching the spec. If both filters are passed, only
350
+ * bindings that match BOTH are removed.
351
+ */
352
+ unbind(spec: {
353
+ keybinding?: Keybinding;
354
+ command?: CommandId;
355
+ }): void;
356
+ /** All registered bindings, for introspection. Order is not guaranteed. */
357
+ bindings(): readonly KeymapBinding[];
358
+ /**
359
+ * Match the event against bound chunks, then run candidates in chain
360
+ * order. Returns `true` and calls `preventDefault()` on the first
361
+ * handler that consumes; returns `false` if nothing matched or all
362
+ * matches fell through.
363
+ */
364
+ dispatch(event: KeyboardEvent): boolean;
365
+ /**
366
+ * Compute the set of canonical hashes a `Keybinding` lights up. A
367
+ * binding with aliases (multiple sequences) contributes one hash per
368
+ * single-chunk alias; multi-chunk sequences (chords) are skipped in
369
+ * V1.
370
+ */
371
+ private chunkKeysFor;
372
+ private has_safe_mod;
373
+ }
374
+ //#endregion
280
375
  //#region src/core/parser.d.ts
281
376
  type AttrToken = {
282
377
  /** Verbatim source name including any prefix, e.g. "xlink:href". */raw_name: string; /** Prefix or null. */
@@ -438,6 +533,62 @@ type Defs = {
438
533
  //#region src/core/properties.d.ts
439
534
  declare function read_property(doc: SvgDocument, id: NodeId, property: string): PropertyValue;
440
535
  //#endregion
536
+ //#region src/gestures/gestures.d.ts
537
+ /** Stable identifier for a gesture binding. Used by `unbind({ id })`. */
538
+ type GestureId = string;
539
+ /**
540
+ * Context passed to every installer. Exposes the seams a gesture needs:
541
+ * the container element to listen on, the camera to mutate, and the
542
+ * editor for keymap dispatch / state reads.
543
+ *
544
+ * Surface authors construct this once at attach; bindings receive it on
545
+ * every `install(...)` call.
546
+ */
547
+ type GestureContext = {
548
+ /** Container element listeners attach to. */container: HTMLElement; /** SVG element being framed by the camera. Useful for hit-testing. */
549
+ svg_root: () => SVGSVGElement | null; /** HUD canvas overlay; sits on top of the SVG. */
550
+ hud_canvas: HTMLCanvasElement; /** Camera the binding mutates. */
551
+ camera: Camera; /** Editor for keymap dispatch / state reads. */
552
+ editor: SvgEditor; /** Handle for advanced bindings (e.g. wanting `camera.fit("<selection>")`). */
553
+ handle: SurfaceHandle;
554
+ };
555
+ type GestureBinding = {
556
+ /** Stable id used by `unbind` / `bindings()`. */id: GestureId;
557
+ /**
558
+ * Wire DOM listeners (or any side-effect) needed for this gesture.
559
+ * Returns the uninstaller — called on `unbind` or surface detach.
560
+ */
561
+ install(ctx: GestureContext): () => void;
562
+ };
563
+ /**
564
+ * Sibling to `Keymap`. Owns a list of installed gesture bindings; each
565
+ * binding's `install(ctx)` is called eagerly when bound and uninstalled
566
+ * on `unbind` or surface detach.
567
+ */
568
+ declare class Gestures {
569
+ private readonly ctx;
570
+ private entries;
571
+ constructor(ctx: GestureContext);
572
+ /**
573
+ * Install a gesture binding. Returns an unbind function.
574
+ * Re-binding the same `id` does NOT replace — both will be active.
575
+ * Use `unbind({ id })` first if you want a clean swap.
576
+ */
577
+ bind(binding: GestureBinding): () => void;
578
+ /**
579
+ * Remove bindings matching the spec. With `{ id }`, all bindings with
580
+ * that id are uninstalled. With no spec, this is a no-op (use
581
+ * `dispose()` to nuke everything).
582
+ */
583
+ unbind(spec: {
584
+ id?: GestureId;
585
+ }): void;
586
+ /** All currently installed bindings. Order is registration order. */
587
+ bindings(): readonly GestureBinding[];
588
+ /** @internal Uninstall every binding. Surface calls on detach. */
589
+ _dispose(): void;
590
+ }
591
+ //#endregion
441
592
  //#region src/core/editor.d.ts
442
593
  /** Resolved paint from the DOM-attached cascade. `resolved_paint` mirrors the
443
594
  * shape of `PaintValue.computed` so consumers can treat it uniformly with
@@ -594,6 +745,10 @@ declare function createSvgEditor(opts: CreateSvgEditorOptions): {
594
745
  providers: Providers;
595
746
  _internal: {
596
747
  doc: SvgDocument;
748
+ history: {
749
+ preview: (label: string) => _$_grida_history0.Preview;
750
+ };
751
+ emit: () => void;
597
752
  set_content_edit_driver(fn: ((target: NodeId) => boolean) | null): void;
598
753
  /** Fires the driver immediately with the current override so the
599
754
  * surface can sync state on attach. */
@@ -604,4 +759,4 @@ declare function createSvgEditor(opts: CreateSvgEditorOptions): {
604
759
  keymap: Keymap;
605
760
  };
606
761
  //#endregion
607
- export { RadialGradientDefinition as A, PaintFallback as C, PropertyValue as D, PreviewSession as E, KeymapBinding as F, CommandHandler as I, CommandId as L, ReorderDirection as M, Unsubscribe as N, Provenance as O, Vec2 as P, Paint as S, PaintValue as T, GradientStop as _, SurfaceHandle as a, Mode as b, ClipboardProvider as c, EditorState as d, EditorStyle as f, GradientEntry as g, GradientDefinition as h, DomComputedResolver as i, Rect as j, Providers as k, Color as l, FontResolver as m, CreateSvgEditorOptions as n, SvgEditor as o, FileIOProvider as p, DomComputedPaint as r, createSvgEditor as s, Commands as t, DEFAULT_STYLE as u, InvalidComputedValue as v, PaintPreviewSession as w, NodeId as x, LinearGradientDefinition as y };
762
+ export { Mode as A, RadialGradientDefinition as B, FileIOProvider as C, GradientStop as D, GradientEntry as E, PaintValue as F, ReorderDirection as H, PreviewSession as I, PropertyValue as L, Paint as M, PaintFallback as N, InvalidComputedValue as O, PaintPreviewSession as P, Provenance as R, EditorStyle as S, GradientDefinition as T, Unsubscribe as U, Rect as V, Vec2 as W, CameraOptions as _, SurfaceHandle as a, DEFAULT_STYLE as b, GestureBinding as c, Gestures as d, KeymapBinding as f, Camera as g, BoundsResolver as h, DomComputedResolver as i, NodeId as j, LinearGradientDefinition as k, GestureContext as l, CommandId as m, CreateSvgEditorOptions as n, SvgEditor as o, CommandHandler as p, DomComputedPaint as r, createSvgEditor as s, Commands as t, GestureId as u, ClipboardProvider as v, FontResolver as w, EditorState as x, Color as y, Providers as z };