@grida/svg-editor 1.0.0-alpha.2 → 1.0.0-alpha.21

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,239 @@
1
+ import { c as SvgEditor, p as Gestures, s as SurfaceHandle, w as Camera } from "./editor-CcW4BVth.mjs";
2
+ import cmath from "@grida/cmath";
3
+ import { guide } from "@grida/cmath/_snap";
4
+
5
+ //#region src/util/attention.d.ts
6
+ /** The runtime handle returned by `create_attention_tracker`. */
7
+ interface AttentionTracker {
8
+ /**
9
+ * `true` iff focus is inside the attention scope (the container's
10
+ * subtree or a registered element's subtree) OR the pointer is
11
+ * currently over any element of the scope. See module doc for the
12
+ * rationale.
13
+ *
14
+ * Pure read; no DOM mutation. Cheap enough to call once per keydown.
15
+ */
16
+ is_attended(): boolean;
17
+ /**
18
+ * `true` iff focus is inside the attention scope — the focus arm of
19
+ * {@link is_attended} alone, WITHOUT the pointer-over arm.
20
+ *
21
+ * Exists for the native clipboard gate (`dom.ts`): pointer-over is a
22
+ * sufficient signal to claim a keystroke (worst case: a stolen scroll)
23
+ * but NOT a copy/cut/paste gesture (worst case: destroying what the
24
+ * user believed they copied, or routing a paste meant for a host text
25
+ * field into the document). See docs/wg/feat-svg-editor/clipboard.md
26
+ * §Transport "Gating the native events".
27
+ */
28
+ is_focus_within(): boolean;
29
+ /**
30
+ * Register a host-chrome element into the attention scope. Editor-
31
+ * adjacent chrome — an inspector, a toolbar, a zoom menu; anything that
32
+ * drives `commands.*` — is a DOM *sibling* of the container (the
33
+ * container is exclusively surface-owned), so without registration the
34
+ * tracker cannot tell it apart from unrelated page surface: clicking
35
+ * its buttons moves focus out of the container, and hovering it fires
36
+ * the container's `pointerleave`, blacking out the whole keymap.
37
+ * Registered elements count for both arms — focus-within and
38
+ * pointer-over. Idempotent; re-adding a registered element is a no-op.
39
+ */
40
+ add(element: Element): void;
41
+ /**
42
+ * Unregister an element added via {@link add}. Also clears any
43
+ * still-latched pointer-over contribution from it (the element may be
44
+ * unmounted mid-hover — e.g. a popover closing under the cursor).
45
+ * Unknown elements are a no-op. The container itself cannot be
46
+ * removed; it is the scope's fixed root, not a registered extra.
47
+ */
48
+ remove(element: Element): void;
49
+ /** Detach the internal pointer-tracking listeners (container and every
50
+ * registered element). */
51
+ dispose(): void;
52
+ }
53
+ //#endregion
54
+ //#region src/core/snap/options.d.ts
55
+ type SnapOptions = {
56
+ /** When false, snap behavior and snap-guide rendering are both off. */enabled: boolean;
57
+ /** Snap threshold in HUD canvas pixels (container CSS px in svg-editor;
58
+ * whatever space the consumer feeds in). Constant across zoom because
59
+ * the input rects are already in screen-equivalent units. */
60
+ threshold_px: number;
61
+ };
62
+ declare const DEFAULT_SNAP_OPTIONS: SnapOptions;
63
+ //#endregion
64
+ //#region src/dom.d.ts
65
+ /**
66
+ * Wire a web-font settle source to the editor's geometry channel.
67
+ *
68
+ * The DOM surface re-serializes the `<svg>` on every editor tick, but a
69
+ * `<text>` / `<tspan>` bbox can change with NO attribute write: a web font
70
+ * finishing load AFTER its `font-family` / `font-size` was already written.
71
+ * The IR never sees that reflow, so nothing bumps `geometry_version` and
72
+ * every bounds-keyed consumer (snap, HUD chrome, size meter) stays stuck at
73
+ * the fallback-face metrics until the next real edit.
74
+ *
75
+ * Listens for `loadingdone` on `source` (a `FontFaceSet`, or any injected
76
+ * `EventTarget` in tests) and calls `bump` once per settle. COARSE on
77
+ * purpose: one bump clears the WHOLE bounds cache, not just text nodes —
78
+ * consistent with the package's pessimistic-invalidation stance, and far
79
+ * cheaper than scoping the bump to the (possibly many) reflowed runs.
80
+ *
81
+ * Also bumps once when `source.ready` resolves (when present): fonts that
82
+ * settled before attach — a cache hit, or `font-display` resolving the same
83
+ * tick the surface mounts — never re-fire `loadingdone`, so a document
84
+ * mounted post-settle still needs one bump to re-read at the real metrics.
85
+ *
86
+ * Returns a teardown that removes the listener and neutralizes the pending
87
+ * `ready` bump (leak guard) — call it on surface detach.
88
+ *
89
+ * Factored out of the surface so it can be unit-tested with a fake
90
+ * `EventTarget` in the node-only test env (jsdom's `FontFaceSet` is
91
+ * incomplete); never a real font / network.
92
+ */
93
+ declare function install_font_load_geometry_bump(source: EventTarget | null, bump: () => void): () => void;
94
+ type DomSurfaceOptions = {
95
+ /** Mount the SVG inside this container. */container: HTMLElement;
96
+ /**
97
+ * Install the default gesture set (wheel-pan/zoom, space-drag, middle-mouse,
98
+ * keyboard zoom). Default `true`. Pass `false` to start blank and bind à la
99
+ * carte via `handle.gestures.bind(...)`.
100
+ */
101
+ gestures?: boolean;
102
+ /**
103
+ * Wire native ClipboardEvent transport — `copy` / `cut` / `paste`
104
+ * listeners on the owner document, gated by the clipboard attention
105
+ * discipline. Default `true`. Pass `false` to route ALL clipboard
106
+ * traffic through the `ClipboardProvider` seam instead (the
107
+ * configuration under which a host's paste-time screening governs
108
+ * every path) — see docs/wg/feat-svg-editor/clipboard.md §Transport
109
+ * "Host control over the native path". Focus management (the container
110
+ * focusing on pointerdown) stays either way — it is a general canvas
111
+ * mitigation, not a clipboard feature.
112
+ */
113
+ clipboard?: boolean;
114
+ /**
115
+ * Auto-fit the document into the viewport on initial attach. Default
116
+ * `false`. Mirrors Excalidraw's `initialData.scrollToContent`.
117
+ * Subsequent `editor.load()` calls do NOT re-fit — call
118
+ * `handle.camera.fit("<root>")` yourself if you want that behavior.
119
+ */
120
+ fit?: boolean;
121
+ /**
122
+ * Initial camera transform. Default `cmath.transform.identity`. Ignored
123
+ * when `fit: true`.
124
+ */
125
+ initial_camera?: cmath.Transform;
126
+ /**
127
+ * Font-load settle source — the `EventTarget` whose `loadingdone` event
128
+ * signals "web fonts finished loading, text may have reflowed." Defaults
129
+ * to `container.ownerDocument.fonts` (the live `FontFaceSet`). The
130
+ * surface installs a `loadingdone` listener that advances the editor's
131
+ * geometry channel so text bounds re-read at the settled glyph metrics
132
+ * (see ../docs/geometry.md §Limitations "Text bbox depends on font").
133
+ *
134
+ * Injectable as a DOM seam: jsdom's `FontFaceSet` is incomplete, so
135
+ * tests pass a plain `EventTarget` stub and `dispatchEvent(new Event(
136
+ * "loadingdone"))` to simulate a settle without a real font / network.
137
+ */
138
+ font_load_source?: EventTarget;
139
+ };
140
+ /**
141
+ * Host-extendable attention scope — public via `handle.attention`.
142
+ *
143
+ * The document-level keymap (undo / redo / delete / tool keys) is gated on
144
+ * attention: focus inside the scope, or pointer over it. The scope starts
145
+ * as the container alone, which makes editor-adjacent host chrome — an
146
+ * inspector, a toolbar, a zoom menu; anything that drives `commands.*` —
147
+ * indistinguishable from unrelated page surface (chrome must be a DOM
148
+ * *sibling* of the container, never a child). Registering a chrome element
149
+ * keeps the full keymap live while the user works in it, with
150
+ * text-input focus still excluded by the keymap's own guard. The native
151
+ * clipboard gate (deliberately stricter: focus-only, never pointer-over)
152
+ * honors the registered set's focus arm the same way.
153
+ *
154
+ * `add` is idempotent; `remove` of an unregistered element is a no-op.
155
+ * Registrations live for the surface's lifetime — `detach()` drops them
156
+ * with the tracker. Hosts with mounting/unmounting chrome (popovers,
157
+ * panels) pair `add` on mount with `remove` on unmount.
158
+ */
159
+ type AttentionScope = Pick<AttentionTracker, "add" | "remove">;
160
+ /**
161
+ * Surface handle for the DOM surface. Extends the editor's core
162
+ * `SurfaceHandle` with the viewport-scoped concerns: pan/zoom (`camera`),
163
+ * pointer/wheel/keyboard gesture bindings (`gestures`), and the
164
+ * host-extendable attention scope (`attention`).
165
+ *
166
+ * Camera, gestures, and attention are **surface-scoped**: detaching the
167
+ * surface drops all three. They never appear on the headless `SvgEditor`.
168
+ */
169
+ type DomSurfaceHandle = SurfaceHandle & {
170
+ camera: Camera;
171
+ gestures: Gestures;
172
+ attention: AttentionScope;
173
+ };
174
+ /**
175
+ * Attach a DOM surface to a headless editor. Returns a `DomSurfaceHandle`
176
+ * whose `detach()` is the inverse — DOM cleared, listeners removed,
177
+ * gestures uninstalled.
178
+ *
179
+ * Usage is one-shot per container: the surface owns the container's children
180
+ * for its lifetime, and `detach()` restores it to empty.
181
+ */
182
+ declare function attach_dom_surface(editor: SvgEditor, options: DomSurfaceOptions): DomSurfaceHandle;
183
+ /**
184
+ * Affine projection of a point through a 2×3 CTM, then offset by a
185
+ * container origin (in page CSS-px). Mirrors how `line_endpoints_in_container`
186
+ * and `shape_of` (transformed branch) bridge from local SVG coords to the
187
+ * HUD's container-CSS-px space (HUD keeps its own transform at identity;
188
+ * the SVG carries the camera as a CSS transform, which getScreenCTM
189
+ * folds in).
190
+ *
191
+ * Exported for headless test coverage — pure function, no DOM types.
192
+ */
193
+ declare function project_point_through_ctm(px: number, py: number, ctm: {
194
+ a: number;
195
+ b: number;
196
+ c: number;
197
+ d: number;
198
+ e: number;
199
+ f: number;
200
+ }, container_offset: readonly [number, number]): [number, number];
201
+ /**
202
+ * Inverse of the CTM's linear part applied to a delta vector. Drops
203
+ * translation. Used to convert a HUD-reported container-space drag delta
204
+ * back to the path's local coord space for `PathModel.translateVertices`.
205
+ *
206
+ * Throws on a degenerate (det = 0) matrix — the caller is expected to
207
+ * have a non-singular CTM for any visible element.
208
+ */
209
+ declare function project_delta_inverse_ctm(dx: number, dy: number, ctm: {
210
+ a: number;
211
+ b: number;
212
+ c: number;
213
+ d: number;
214
+ }): [number, number];
215
+ /**
216
+ * Inverse-project a doc-space rect through a CTM + container offset back
217
+ * into the element's local frame. The output is the AABB of the four
218
+ * inverse-projected corners — when the CTM has a rotation component the
219
+ * AABB is an approximation, but it matches what the user visually
220
+ * expects from a screen-aligned marquee drag.
221
+ *
222
+ * Returns `null` when the CTM's linear part is singular (degenerate
223
+ * camera) — the caller should skip any test that needs the local rect.
224
+ */
225
+ declare function inverse_project_rect(rect: {
226
+ x: number;
227
+ y: number;
228
+ width: number;
229
+ height: number;
230
+ }, ctm: {
231
+ a: number;
232
+ b: number;
233
+ c: number;
234
+ d: number;
235
+ e: number;
236
+ f: number;
237
+ }, offset: readonly [number, number]): cmath.Rectangle | null;
238
+ //#endregion
239
+ export { install_font_load_geometry_bump as a, project_point_through_ctm as c, attach_dom_surface as i, DEFAULT_SNAP_OPTIONS as l, DomSurfaceHandle as n, inverse_project_rect as o, DomSurfaceOptions as r, project_delta_inverse_ctm as s, AttentionScope as t, SnapOptions as u };
package/dist/dom.d.mts CHANGED
@@ -1,16 +1,3 @@
1
- import { a as SurfaceHandle, o as SvgEditor } from "./editor-BryibVvr.mjs";
2
-
3
- //#region src/dom.d.ts
4
- type DomSurfaceOptions = {
5
- /** Mount the SVG inside this container. */container: HTMLElement;
6
- };
7
- /**
8
- * Attach a DOM surface to a headless editor. Returns a `SurfaceHandle` whose
9
- * `detach()` is the inverse — DOM cleared, listeners removed.
10
- *
11
- * Usage is one-shot per container: the surface owns the container's children
12
- * for its lifetime, and `detach()` restores it to empty.
13
- */
14
- declare function attach_dom_surface(editor: SvgEditor, options: DomSurfaceOptions): SurfaceHandle;
15
- //#endregion
16
- export { DomSurfaceOptions, attach_dom_surface };
1
+ import { C as BoundsResolver, E as CameraOptions, T as CameraConstraints, d as GestureContext, f as GestureId, g as MemoizedGeometryProvider, h as GeometrySignals, i as DomComputedResolver, m as GeometryProvider, p as Gestures, r as DomComputedPaint, u as GestureBinding, w as Camera } from "./editor-CcW4BVth.mjs";
2
+ import { a as install_font_load_geometry_bump, c as project_point_through_ctm, i as attach_dom_surface, l as DEFAULT_SNAP_OPTIONS, n as DomSurfaceHandle, o as inverse_project_rect, r as DomSurfaceOptions, s as project_delta_inverse_ctm, t as AttentionScope, u as SnapOptions } from "./dom-Dw2SPHgc.mjs";
3
+ export { AttentionScope, type BoundsResolver, Camera, type CameraConstraints, type CameraOptions, DEFAULT_SNAP_OPTIONS, type DomComputedPaint, type DomComputedResolver, DomSurfaceHandle, DomSurfaceOptions, type GeometryProvider, type GeometrySignals, type GestureBinding, type GestureContext, type GestureId, Gestures, MemoizedGeometryProvider, type SnapOptions, attach_dom_surface, install_font_load_geometry_bump, inverse_project_rect, project_delta_inverse_ctm, project_point_through_ctm };
package/dist/dom.d.ts CHANGED
@@ -1,16 +1,3 @@
1
- import { a as SurfaceHandle, o as SvgEditor } from "./editor-klT8wu-x.js";
2
-
3
- //#region src/dom.d.ts
4
- type DomSurfaceOptions = {
5
- /** Mount the SVG inside this container. */container: HTMLElement;
6
- };
7
- /**
8
- * Attach a DOM surface to a headless editor. Returns a `SurfaceHandle` whose
9
- * `detach()` is the inverse — DOM cleared, listeners removed.
10
- *
11
- * Usage is one-shot per container: the surface owns the container's children
12
- * for its lifetime, and `detach()` restores it to empty.
13
- */
14
- declare function attach_dom_surface(editor: SvgEditor, options: DomSurfaceOptions): SurfaceHandle;
15
- //#endregion
16
- export { DomSurfaceOptions, attach_dom_surface };
1
+ import { C as BoundsResolver, E as CameraOptions, T as CameraConstraints, d as GestureContext, f as GestureId, g as MemoizedGeometryProvider, h as GeometrySignals, i as DomComputedResolver, m as GeometryProvider, p as Gestures, r as DomComputedPaint, u as GestureBinding, w as Camera } from "./editor-CxqRhhzP.js";
2
+ import { a as install_font_load_geometry_bump, c as project_point_through_ctm, i as attach_dom_surface, l as DEFAULT_SNAP_OPTIONS, n as DomSurfaceHandle, o as inverse_project_rect, r as DomSurfaceOptions, s as project_delta_inverse_ctm, t as AttentionScope, u as SnapOptions } from "./dom-CQkWJNrK.js";
3
+ export { AttentionScope, type BoundsResolver, Camera, type CameraConstraints, type CameraOptions, DEFAULT_SNAP_OPTIONS, type DomComputedPaint, type DomComputedResolver, DomSurfaceHandle, DomSurfaceOptions, type GeometryProvider, type GeometrySignals, type GestureBinding, type GestureContext, type GestureId, Gestures, MemoizedGeometryProvider, type SnapOptions, attach_dom_surface, install_font_load_geometry_bump, inverse_project_rect, project_delta_inverse_ctm, project_point_through_ctm };
package/dist/dom.js CHANGED
@@ -1,3 +1,11 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dom = require("./dom-CfP_ZURh.js");
2
+ const require_dom = require("./dom-CuK0LFUY.js");
3
+ exports.Camera = require_dom.Camera;
4
+ exports.DEFAULT_SNAP_OPTIONS = require_dom.DEFAULT_SNAP_OPTIONS;
5
+ exports.Gestures = require_dom.Gestures;
6
+ exports.MemoizedGeometryProvider = require_dom.MemoizedGeometryProvider;
3
7
  exports.attach_dom_surface = require_dom.attach_dom_surface;
8
+ exports.install_font_load_geometry_bump = require_dom.install_font_load_geometry_bump;
9
+ exports.inverse_project_rect = require_dom.inverse_project_rect;
10
+ exports.project_delta_inverse_ctm = require_dom.project_delta_inverse_ctm;
11
+ exports.project_point_through_ctm = require_dom.project_point_through_ctm;
package/dist/dom.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as attach_dom_surface } from "./dom-kA8NDuVh.mjs";
2
- export { attach_dom_surface };
1
+ import { a as project_point_through_ctm, c as MemoizedGeometryProvider, i as project_delta_inverse_ctm, l as Camera, n as install_font_load_geometry_bump, o as Gestures, r as inverse_project_rect, s as DEFAULT_SNAP_OPTIONS, t as attach_dom_surface } from "./dom-DHaTIObb.mjs";
2
+ export { Camera, DEFAULT_SNAP_OPTIONS, Gestures, MemoizedGeometryProvider, attach_dom_surface, install_font_load_geometry_bump, inverse_project_rect, project_delta_inverse_ctm, project_point_through_ctm };