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

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.
@@ -0,0 +1,61 @@
1
+ import { c as SvgEditor } from "./editor-BH03X8cX.mjs";
2
+ import { n as DomSurfaceOptions, t as DomSurfaceHandle } from "./dom-DgB4f-TE.mjs";
3
+
4
+ //#region src/presets/keynote.d.ts
5
+ declare namespace keynote_d_exports {
6
+ export { KeynoteAttachOptions, KeynoteSurfaceHandle, attach };
7
+ }
8
+ type KeynoteAttachOptions = {
9
+ /** Container to mount the SVG into. */container: HTMLElement;
10
+ /**
11
+ * Screen-pixel breathing room between the slide and the viewport edge.
12
+ * Used for both initial fit and the cover-constraint clamp. Default 80.
13
+ */
14
+ padding?: number;
15
+ /**
16
+ * Screen-pixel scroll slack past the slide edge when zoomed in past fit.
17
+ * Forwarded to the cover constraint's `pan_overshoot`. Default 0 — strict
18
+ * cover behavior (no panning past the slide edge). Applies only when an
19
+ * axis is scrollable; a fitted axis stays locked at center.
20
+ */
21
+ pan_overshoot?: number;
22
+ /**
23
+ * Forward additional surface options (e.g. `gestures: false`). `container`,
24
+ * `fit`, and `initial_camera` are owned by the preset.
25
+ */
26
+ surface?: Omit<DomSurfaceOptions, "container" | "fit" | "initial_camera">;
27
+ };
28
+ /**
29
+ * Surface handle returned by `keynote.attach`. Extends `DomSurfaceHandle`
30
+ * with `set_padding` so hosts can vary the slide breathing room at runtime
31
+ * (e.g. on a "present mode" toggle that wants margin: 0 vs the default 80).
32
+ */
33
+ type KeynoteSurfaceHandle = DomSurfaceHandle & {
34
+ /**
35
+ * Update the slide padding and re-fit. Mutates the live constraint AND
36
+ * the captured padding used by load-triggered refits.
37
+ */
38
+ set_padding(p: number): void;
39
+ /**
40
+ * Update the scroll-past slack at runtime. Mutates the live constraint;
41
+ * `reenforce()` pulls a previously over-panned transform back into the
42
+ * new range when the value is decreased.
43
+ */
44
+ set_pan_overshoot(o: number): void;
45
+ };
46
+ /**
47
+ * Attach a keynote-shaped DOM surface:
48
+ * - Mounts via `attach_dom_surface` with `fit: true` (slide is visible on
49
+ * first frame).
50
+ * - Installs a `'cover'` camera constraint bound to the document root, so
51
+ * the user can't zoom out past the slide or pan past its edges.
52
+ * - Subscribes to `editor.state.load_version` so every `editor.load(svg)`
53
+ * re-fits the camera to the new document.
54
+ *
55
+ * Returns a `KeynoteSurfaceHandle` — same shape as `DomSurfaceHandle` plus
56
+ * `set_padding` for present-mode toggles. The returned `detach()`
57
+ * additionally tears down the load subscription.
58
+ */
59
+ declare function attach(editor: SvgEditor, opts: KeynoteAttachOptions): KeynoteSurfaceHandle;
60
+ //#endregion
61
+ export { type KeynoteAttachOptions, type KeynoteSurfaceHandle, keynote_d_exports as keynote };
@@ -0,0 +1,61 @@
1
+ import { c as SvgEditor } from "./editor-Bd4-VCEJ.js";
2
+ import { n as DomSurfaceOptions, t as DomSurfaceHandle } from "./dom-DCX-a8Kr.js";
3
+
4
+ //#region \0rolldown/runtime.js
5
+ declare namespace keynote_d_exports {
6
+ export { KeynoteAttachOptions, KeynoteSurfaceHandle, attach };
7
+ }
8
+ type KeynoteAttachOptions = {
9
+ /** Container to mount the SVG into. */container: HTMLElement;
10
+ /**
11
+ * Screen-pixel breathing room between the slide and the viewport edge.
12
+ * Used for both initial fit and the cover-constraint clamp. Default 80.
13
+ */
14
+ padding?: number;
15
+ /**
16
+ * Screen-pixel scroll slack past the slide edge when zoomed in past fit.
17
+ * Forwarded to the cover constraint's `pan_overshoot`. Default 0 — strict
18
+ * cover behavior (no panning past the slide edge). Applies only when an
19
+ * axis is scrollable; a fitted axis stays locked at center.
20
+ */
21
+ pan_overshoot?: number;
22
+ /**
23
+ * Forward additional surface options (e.g. `gestures: false`). `container`,
24
+ * `fit`, and `initial_camera` are owned by the preset.
25
+ */
26
+ surface?: Omit<DomSurfaceOptions, "container" | "fit" | "initial_camera">;
27
+ };
28
+ /**
29
+ * Surface handle returned by `keynote.attach`. Extends `DomSurfaceHandle`
30
+ * with `set_padding` so hosts can vary the slide breathing room at runtime
31
+ * (e.g. on a "present mode" toggle that wants margin: 0 vs the default 80).
32
+ */
33
+ type KeynoteSurfaceHandle = DomSurfaceHandle & {
34
+ /**
35
+ * Update the slide padding and re-fit. Mutates the live constraint AND
36
+ * the captured padding used by load-triggered refits.
37
+ */
38
+ set_padding(p: number): void;
39
+ /**
40
+ * Update the scroll-past slack at runtime. Mutates the live constraint;
41
+ * `reenforce()` pulls a previously over-panned transform back into the
42
+ * new range when the value is decreased.
43
+ */
44
+ set_pan_overshoot(o: number): void;
45
+ };
46
+ /**
47
+ * Attach a keynote-shaped DOM surface:
48
+ * - Mounts via `attach_dom_surface` with `fit: true` (slide is visible on
49
+ * first frame).
50
+ * - Installs a `'cover'` camera constraint bound to the document root, so
51
+ * the user can't zoom out past the slide or pan past its edges.
52
+ * - Subscribes to `editor.state.load_version` so every `editor.load(svg)`
53
+ * re-fits the camera to the new document.
54
+ *
55
+ * Returns a `KeynoteSurfaceHandle` — same shape as `DomSurfaceHandle` plus
56
+ * `set_padding` for present-mode toggles. The returned `detach()`
57
+ * additionally tears down the load subscription.
58
+ */
59
+ declare function attach(editor: SvgEditor, opts: KeynoteAttachOptions): KeynoteSurfaceHandle;
60
+ //#endregion
61
+ export { type KeynoteAttachOptions, type KeynoteSurfaceHandle, keynote_d_exports as keynote };
@@ -0,0 +1,61 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_insertions = require("./insertions-BJ-6o6o5.js");
3
+ const require_dom = require("./dom-Cvm9Towu.js");
4
+ //#region src/presets/keynote.ts
5
+ var keynote_exports = /* @__PURE__ */ require_insertions.__exportAll({ attach: () => attach });
6
+ /**
7
+ * Attach a keynote-shaped DOM surface:
8
+ * - Mounts via `attach_dom_surface` with `fit: true` (slide is visible on
9
+ * first frame).
10
+ * - Installs a `'cover'` camera constraint bound to the document root, so
11
+ * the user can't zoom out past the slide or pan past its edges.
12
+ * - Subscribes to `editor.state.load_version` so every `editor.load(svg)`
13
+ * re-fits the camera to the new document.
14
+ *
15
+ * Returns a `KeynoteSurfaceHandle` — same shape as `DomSurfaceHandle` plus
16
+ * `set_padding` for present-mode toggles. The returned `detach()`
17
+ * additionally tears down the load subscription.
18
+ */
19
+ function attach(editor, opts) {
20
+ const inner = require_dom.attach_dom_surface(editor, {
21
+ ...opts.surface,
22
+ container: opts.container,
23
+ fit: true
24
+ });
25
+ let padding = opts.padding ?? 80;
26
+ let pan_overshoot = opts.pan_overshoot ?? 0;
27
+ const apply = () => {
28
+ inner.camera.constraints = {
29
+ type: "cover",
30
+ bounds: "<root>",
31
+ padding,
32
+ pan_overshoot
33
+ };
34
+ };
35
+ apply();
36
+ const unsub_load = editor.subscribe_with_selector((s) => s.load_version, () => inner.camera.fit("<root>", { margin: inner.camera.constraints?.padding ?? 0 }));
37
+ return {
38
+ camera: inner.camera,
39
+ gestures: inner.gestures,
40
+ set_padding(p) {
41
+ padding = p;
42
+ apply();
43
+ inner.camera.fit("<root>", { margin: p });
44
+ },
45
+ set_pan_overshoot(o) {
46
+ pan_overshoot = o;
47
+ apply();
48
+ },
49
+ detach: () => {
50
+ unsub_load();
51
+ inner.detach();
52
+ }
53
+ };
54
+ }
55
+ //#endregion
56
+ Object.defineProperty(exports, "keynote", {
57
+ enumerable: true,
58
+ get: function() {
59
+ return keynote_exports;
60
+ }
61
+ });
@@ -0,0 +1,55 @@
1
+ import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
2
+ import { t as attach_dom_surface } from "./dom-BlMk07oX.mjs";
3
+ //#region src/presets/keynote.ts
4
+ var keynote_exports = /* @__PURE__ */ __exportAll({ attach: () => attach });
5
+ /**
6
+ * Attach a keynote-shaped DOM surface:
7
+ * - Mounts via `attach_dom_surface` with `fit: true` (slide is visible on
8
+ * first frame).
9
+ * - Installs a `'cover'` camera constraint bound to the document root, so
10
+ * the user can't zoom out past the slide or pan past its edges.
11
+ * - Subscribes to `editor.state.load_version` so every `editor.load(svg)`
12
+ * re-fits the camera to the new document.
13
+ *
14
+ * Returns a `KeynoteSurfaceHandle` — same shape as `DomSurfaceHandle` plus
15
+ * `set_padding` for present-mode toggles. The returned `detach()`
16
+ * additionally tears down the load subscription.
17
+ */
18
+ function attach(editor, opts) {
19
+ const inner = attach_dom_surface(editor, {
20
+ ...opts.surface,
21
+ container: opts.container,
22
+ fit: true
23
+ });
24
+ let padding = opts.padding ?? 80;
25
+ let pan_overshoot = opts.pan_overshoot ?? 0;
26
+ const apply = () => {
27
+ inner.camera.constraints = {
28
+ type: "cover",
29
+ bounds: "<root>",
30
+ padding,
31
+ pan_overshoot
32
+ };
33
+ };
34
+ apply();
35
+ const unsub_load = editor.subscribe_with_selector((s) => s.load_version, () => inner.camera.fit("<root>", { margin: inner.camera.constraints?.padding ?? 0 }));
36
+ return {
37
+ camera: inner.camera,
38
+ gestures: inner.gestures,
39
+ set_padding(p) {
40
+ padding = p;
41
+ apply();
42
+ inner.camera.fit("<root>", { margin: p });
43
+ },
44
+ set_pan_overshoot(o) {
45
+ pan_overshoot = o;
46
+ apply();
47
+ },
48
+ detach: () => {
49
+ unsub_load();
50
+ inner.detach();
51
+ }
52
+ };
53
+ }
54
+ //#endregion
55
+ export { keynote_exports as keynote };
package/dist/react.d.mts CHANGED
@@ -1,20 +1,37 @@
1
- import { d as EditorState, f as EditorStyle, k as Providers, o as SvgEditor, t as Commands } from "./editor-JY7AQrR1.mjs";
1
+ import { B as PaintPreviewSession, E as EditorStyle, G as Providers, H as PreviewSession, I as Mode, L as NodeId, T as EditorState, X as Tool, c as SvgEditor, t as Commands } from "./editor-BH03X8cX.mjs";
2
+ import { t as DomSurfaceHandle } from "./dom-DgB4f-TE.mjs";
3
+ import cmath from "@grida/cmath";
2
4
  import { ReactNode } from "react";
3
5
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
6
 
5
7
  //#region src/react.d.ts
6
8
  type SvgEditorProviderProps = {
7
- svg: string;
9
+ /**
10
+ * Initial document for the editor. Read **once** on first render —
11
+ * subsequent changes to this prop are silently ignored. For live updates
12
+ * (file open, page switch, reset to a snapshot), pull the editor from
13
+ * context with `useSvgEditor()` and call `editor.load(...)` imperatively.
14
+ *
15
+ * This is the same shape Lexical (`initialConfig.editorState`), Slate
16
+ * (`initialValue`), and TipTap (`content` option) settled on for the
17
+ * same reason: a reactive document prop creates a feedback loop with the
18
+ * editor's own emissions. The editor instance is the source of truth
19
+ * for the document during a session; React state is not.
20
+ */
21
+ initialSvg: string;
8
22
  providers?: Providers;
9
23
  style?: Partial<EditorStyle>;
10
24
  children: ReactNode;
11
25
  };
12
26
  /**
13
27
  * Owns the headless editor and exposes it via context. The editor is created
14
- * once on first render; subsequent prop changes to `svg` call `editor.load()`.
28
+ * once on first render with `initialSvg`; subsequent changes to that prop are
29
+ * silently ignored. To replace the document at runtime, call
30
+ * `useSvgEditor().load(...)` imperatively, or remount the provider with a
31
+ * different `key`.
15
32
  */
16
33
  declare function SvgEditorProvider({
17
- svg,
34
+ initialSvg,
18
35
  providers,
19
36
  style,
20
37
  children
@@ -22,17 +39,40 @@ declare function SvgEditorProvider({
22
39
  type SvgEditorCanvasProps = {
23
40
  className?: string;
24
41
  style?: React.CSSProperties;
42
+ /**
43
+ * Install the default gesture set. Default `true`. See
44
+ * `DomSurfaceOptions.gestures`.
45
+ */
46
+ gestures?: boolean;
47
+ /**
48
+ * Auto-fit the document on initial attach. Default `false`. See
49
+ * `DomSurfaceOptions.fit`.
50
+ */
51
+ fit?: boolean; /** Initial camera transform. Default identity. */
52
+ initial_camera?: cmath.Transform;
53
+ /**
54
+ * Receives the `DomSurfaceHandle` once the surface is attached, and
55
+ * `null` on unmount/detach. Use this to thread `handle.camera` /
56
+ * `handle.gestures` into surrounding chrome (toolbars, badges, etc.).
57
+ */
58
+ onAttach?: (handle: DomSurfaceHandle | null) => void;
25
59
  };
26
60
  /**
27
61
  * Renders the editor's SVG into a `div` and wires it to the DOM surface.
28
62
  *
29
- * Internally calls `attach_dom_surface(editor, { container })` on mount and
30
- * `handle.detach()` on unmount. This is the only UI component the package
31
- * ships; everything else (toolbar, property panel, etc.) is consumer-built.
63
+ * Internally calls `attach_dom_surface(editor, { container, ... })` on
64
+ * mount and `handle.detach()` on unmount. Surface-scoped concerns (camera,
65
+ * gestures) are reached via the `onAttach` callback — there is no global
66
+ * context for them, because a host may mount multiple canvases in the
67
+ * same editor session.
32
68
  */
33
69
  declare function SvgEditorCanvas({
34
70
  className,
35
- style
71
+ style,
72
+ gestures,
73
+ fit,
74
+ initial_camera,
75
+ onAttach
36
76
  }: SvgEditorCanvasProps): _$react_jsx_runtime0.JSX.Element;
37
77
  declare function useSvgEditor(): SvgEditor;
38
78
  /**
@@ -45,5 +85,50 @@ declare function useEditorState<T>(selector: (state: EditorState) => T, equals?:
45
85
  * re-renders (commands themselves don't change identity).
46
86
  */
47
87
  declare function useCommands(): Commands;
88
+ /**
89
+ * Subscribe to a slice of `handle.camera` from a `DomSurfaceHandle`. Pass
90
+ * the handle (or null if it isn't attached yet) and a selector that reads
91
+ * what you need from the camera. The returned value updates on every
92
+ * camera mutation — does NOT bump `editor.state.version`.
93
+ *
94
+ * Typical use: zoom badge in a toolbar.
95
+ *
96
+ * ```tsx
97
+ * const zoom = useCameraSnapshot(handle, (c) => c.zoom, 1);
98
+ * return <div>{Math.round(zoom * 100)}%</div>;
99
+ * ```
100
+ *
101
+ * The `fallback` is what's returned when `handle` is `null` (before mount /
102
+ * after detach). It's also the SSR snapshot value — anything that won't
103
+ * mismatch with the first client render.
104
+ */
105
+ declare function useCameraSnapshot<T>(handle: DomSurfaceHandle | null, selector: (camera: DomSurfaceHandle["camera"]) => T, fallback: T): T;
106
+ /** Current selection (frozen, identity-stable across no-op emits). */
107
+ declare function useSelection(): readonly NodeId[];
108
+ /** Active tool. Identity-stable when `set_tool` is a no-op. */
109
+ declare function useTool(): Tool;
110
+ /** Current mode (`"select"` | `"edit-content"`). */
111
+ declare function useMode(): Mode;
112
+ /** Whether the history stack has an undoable entry. */
113
+ declare function useCanUndo(): boolean;
114
+ /** Whether the history stack has a redoable entry. */
115
+ declare function useCanRedo(): boolean;
116
+ /** Hook-owned `PaintPreviewSession`. See block comment above. */
117
+ declare function usePaintPreview(channel: "fill" | "stroke"): PaintPreviewSession;
118
+ /** Hook-owned `PreviewSession` for a CSS/SVG property. See block comment above. */
119
+ declare function usePropertyPreview(name: string): PreviewSession;
120
+ /** Bound `editor.load(svg)`. Stable across renders. */
121
+ declare function useEditorLoad(): (svg: string) => void;
122
+ /** Bound `editor.serialize()`. Stable across renders. */
123
+ declare function useEditorSerialize(): () => string;
124
+ /**
125
+ * Push a hover override into the HUD surface — e.g. when the user hovers
126
+ * a row in a layers panel. The HUD will render the override's outline.
127
+ *
128
+ * Pass `null` to clear and let the pointer pick take over again. On
129
+ * unmount, the hook clears any override it set last so the canvas
130
+ * doesn't stay highlighted on a node that no longer has a panel row.
131
+ */
132
+ declare function useHoverOverride(): (id: NodeId | null) => void;
48
133
  //#endregion
49
- export { SvgEditorCanvas, SvgEditorCanvasProps, SvgEditorProvider, SvgEditorProviderProps, useCommands, useEditorState, useSvgEditor };
134
+ export { SvgEditorCanvas, SvgEditorCanvasProps, SvgEditorProvider, SvgEditorProviderProps, useCameraSnapshot, useCanRedo, useCanUndo, useCommands, useEditorLoad, useEditorSerialize, useEditorState, useHoverOverride, useMode, usePaintPreview, usePropertyPreview, useSelection, useSvgEditor, useTool };
package/dist/react.d.ts CHANGED
@@ -1,20 +1,37 @@
1
- import { d as EditorState, f as EditorStyle, k as Providers, o as SvgEditor, t as Commands } from "./editor-CTtU2gu4.js";
1
+ import { B as PaintPreviewSession, E as EditorStyle, G as Providers, H as PreviewSession, I as Mode, L as NodeId, T as EditorState, X as Tool, c as SvgEditor, t as Commands } from "./editor-Bd4-VCEJ.js";
2
+ import { t as DomSurfaceHandle } from "./dom-DCX-a8Kr.js";
3
+ import cmath from "@grida/cmath";
2
4
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
5
  import { ReactNode } from "react";
4
6
 
5
7
  //#region src/react.d.ts
6
8
  type SvgEditorProviderProps = {
7
- svg: string;
9
+ /**
10
+ * Initial document for the editor. Read **once** on first render —
11
+ * subsequent changes to this prop are silently ignored. For live updates
12
+ * (file open, page switch, reset to a snapshot), pull the editor from
13
+ * context with `useSvgEditor()` and call `editor.load(...)` imperatively.
14
+ *
15
+ * This is the same shape Lexical (`initialConfig.editorState`), Slate
16
+ * (`initialValue`), and TipTap (`content` option) settled on for the
17
+ * same reason: a reactive document prop creates a feedback loop with the
18
+ * editor's own emissions. The editor instance is the source of truth
19
+ * for the document during a session; React state is not.
20
+ */
21
+ initialSvg: string;
8
22
  providers?: Providers;
9
23
  style?: Partial<EditorStyle>;
10
24
  children: ReactNode;
11
25
  };
12
26
  /**
13
27
  * Owns the headless editor and exposes it via context. The editor is created
14
- * once on first render; subsequent prop changes to `svg` call `editor.load()`.
28
+ * once on first render with `initialSvg`; subsequent changes to that prop are
29
+ * silently ignored. To replace the document at runtime, call
30
+ * `useSvgEditor().load(...)` imperatively, or remount the provider with a
31
+ * different `key`.
15
32
  */
16
33
  declare function SvgEditorProvider({
17
- svg,
34
+ initialSvg,
18
35
  providers,
19
36
  style,
20
37
  children
@@ -22,17 +39,40 @@ declare function SvgEditorProvider({
22
39
  type SvgEditorCanvasProps = {
23
40
  className?: string;
24
41
  style?: React.CSSProperties;
42
+ /**
43
+ * Install the default gesture set. Default `true`. See
44
+ * `DomSurfaceOptions.gestures`.
45
+ */
46
+ gestures?: boolean;
47
+ /**
48
+ * Auto-fit the document on initial attach. Default `false`. See
49
+ * `DomSurfaceOptions.fit`.
50
+ */
51
+ fit?: boolean; /** Initial camera transform. Default identity. */
52
+ initial_camera?: cmath.Transform;
53
+ /**
54
+ * Receives the `DomSurfaceHandle` once the surface is attached, and
55
+ * `null` on unmount/detach. Use this to thread `handle.camera` /
56
+ * `handle.gestures` into surrounding chrome (toolbars, badges, etc.).
57
+ */
58
+ onAttach?: (handle: DomSurfaceHandle | null) => void;
25
59
  };
26
60
  /**
27
61
  * Renders the editor's SVG into a `div` and wires it to the DOM surface.
28
62
  *
29
- * Internally calls `attach_dom_surface(editor, { container })` on mount and
30
- * `handle.detach()` on unmount. This is the only UI component the package
31
- * ships; everything else (toolbar, property panel, etc.) is consumer-built.
63
+ * Internally calls `attach_dom_surface(editor, { container, ... })` on
64
+ * mount and `handle.detach()` on unmount. Surface-scoped concerns (camera,
65
+ * gestures) are reached via the `onAttach` callback — there is no global
66
+ * context for them, because a host may mount multiple canvases in the
67
+ * same editor session.
32
68
  */
33
69
  declare function SvgEditorCanvas({
34
70
  className,
35
- style
71
+ style,
72
+ gestures,
73
+ fit,
74
+ initial_camera,
75
+ onAttach
36
76
  }: SvgEditorCanvasProps): _$react_jsx_runtime0.JSX.Element;
37
77
  declare function useSvgEditor(): SvgEditor;
38
78
  /**
@@ -45,5 +85,50 @@ declare function useEditorState<T>(selector: (state: EditorState) => T, equals?:
45
85
  * re-renders (commands themselves don't change identity).
46
86
  */
47
87
  declare function useCommands(): Commands;
88
+ /**
89
+ * Subscribe to a slice of `handle.camera` from a `DomSurfaceHandle`. Pass
90
+ * the handle (or null if it isn't attached yet) and a selector that reads
91
+ * what you need from the camera. The returned value updates on every
92
+ * camera mutation — does NOT bump `editor.state.version`.
93
+ *
94
+ * Typical use: zoom badge in a toolbar.
95
+ *
96
+ * ```tsx
97
+ * const zoom = useCameraSnapshot(handle, (c) => c.zoom, 1);
98
+ * return <div>{Math.round(zoom * 100)}%</div>;
99
+ * ```
100
+ *
101
+ * The `fallback` is what's returned when `handle` is `null` (before mount /
102
+ * after detach). It's also the SSR snapshot value — anything that won't
103
+ * mismatch with the first client render.
104
+ */
105
+ declare function useCameraSnapshot<T>(handle: DomSurfaceHandle | null, selector: (camera: DomSurfaceHandle["camera"]) => T, fallback: T): T;
106
+ /** Current selection (frozen, identity-stable across no-op emits). */
107
+ declare function useSelection(): readonly NodeId[];
108
+ /** Active tool. Identity-stable when `set_tool` is a no-op. */
109
+ declare function useTool(): Tool;
110
+ /** Current mode (`"select"` | `"edit-content"`). */
111
+ declare function useMode(): Mode;
112
+ /** Whether the history stack has an undoable entry. */
113
+ declare function useCanUndo(): boolean;
114
+ /** Whether the history stack has a redoable entry. */
115
+ declare function useCanRedo(): boolean;
116
+ /** Hook-owned `PaintPreviewSession`. See block comment above. */
117
+ declare function usePaintPreview(channel: "fill" | "stroke"): PaintPreviewSession;
118
+ /** Hook-owned `PreviewSession` for a CSS/SVG property. See block comment above. */
119
+ declare function usePropertyPreview(name: string): PreviewSession;
120
+ /** Bound `editor.load(svg)`. Stable across renders. */
121
+ declare function useEditorLoad(): (svg: string) => void;
122
+ /** Bound `editor.serialize()`. Stable across renders. */
123
+ declare function useEditorSerialize(): () => string;
124
+ /**
125
+ * Push a hover override into the HUD surface — e.g. when the user hovers
126
+ * a row in a layers panel. The HUD will render the override's outline.
127
+ *
128
+ * Pass `null` to clear and let the pointer pick take over again. On
129
+ * unmount, the hook clears any override it set last so the canvas
130
+ * doesn't stay highlighted on a node that no longer has a panel row.
131
+ */
132
+ declare function useHoverOverride(): (id: NodeId | null) => void;
48
133
  //#endregion
49
- export { SvgEditorCanvas, SvgEditorCanvasProps, SvgEditorProvider, SvgEditorProviderProps, useCommands, useEditorState, useSvgEditor };
134
+ export { SvgEditorCanvas, SvgEditorCanvasProps, SvgEditorProvider, SvgEditorProviderProps, useCameraSnapshot, useCanRedo, useCanUndo, useCommands, useEditorLoad, useEditorSerialize, useEditorState, useHoverOverride, useMode, usePaintPreview, usePropertyPreview, useSelection, useSvgEditor, useTool };