@grida/hud 0.1.0 → 0.2.0
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/README.md +185 -19
- package/dist/cursor-BFGUuD2M.d.mts +64 -0
- package/dist/cursor-BieMVb71.mjs +57 -0
- package/dist/cursor-CIYvFshz.d.ts +64 -0
- package/dist/cursor-DsP9qtN2.js +80 -0
- package/dist/cursors/index.d.mts +98 -0
- package/dist/cursors/index.d.ts +98 -0
- package/dist/cursors/index.js +188 -0
- package/dist/cursors/index.mjs +185 -0
- package/dist/{index-CBqCh-ZM.d.mts → index-Cp0X4SV7.d.ts} +385 -172
- package/dist/{index-DRBeSiI2.d.ts → index-DhGdcuQz.d.mts} +385 -172
- package/dist/index.d.mts +106 -2
- package/dist/index.d.ts +106 -2
- package/dist/index.js +13 -1
- package/dist/index.mjs +3 -2
- package/dist/react.d.mts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +8 -3
- package/dist/react.mjs +8 -3
- package/dist/{surface-hUEeEVdL.mjs → surface-BvMmXoEl.mjs} +910 -247
- package/dist/{surface-CNlBaEXn.js → surface-ofSNTJ8H.js} +965 -248
- package/package.json +8 -2
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as RotationCorner, n as CursorRenderer, r as ResizeDirection, t as CursorIcon } from "./cursor-CIYvFshz.js";
|
|
2
2
|
import cmath from "@grida/cmath";
|
|
3
3
|
import { guide } from "@grida/cmath/_snap";
|
|
4
|
+
import { Measurement } from "@grida/cmath/_measurement";
|
|
4
5
|
|
|
5
6
|
//#region primitives/types.d.ts
|
|
7
|
+
type HUDSemanticGroup = string;
|
|
8
|
+
interface HUDSemantic {
|
|
9
|
+
/** Semantic owner of this primitive, used for group-level visibility policy. */
|
|
10
|
+
group?: HUDSemanticGroup;
|
|
11
|
+
}
|
|
6
12
|
/**
|
|
7
13
|
* A line segment in document space, extending `cmath.ui.Line` with
|
|
8
14
|
* an optional `dashed` style.
|
|
9
15
|
*/
|
|
10
|
-
interface HUDLine extends cmath.ui.Line {
|
|
16
|
+
interface HUDLine extends cmath.ui.Line, HUDSemantic {
|
|
11
17
|
dashed?: boolean;
|
|
12
18
|
/** Stroke width in screen-space CSS px. Defaults to the canvas default. */
|
|
13
19
|
strokeWidth?: number;
|
|
@@ -16,6 +22,13 @@ interface HUDLine extends cmath.ui.Line {
|
|
|
16
22
|
* back to the canvas's current color when absent.
|
|
17
23
|
*/
|
|
18
24
|
color?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Label rotation in radians (CCW) around the label pill's screen-space
|
|
27
|
+
* center. Defaults to `0`. Used to make the size meter pill rotate with
|
|
28
|
+
* a `SelectionShape.transformed` parent. Only affects the pill +
|
|
29
|
+
* text; the underlying line stroke is unaffected.
|
|
30
|
+
*/
|
|
31
|
+
labelAngle?: number;
|
|
19
32
|
}
|
|
20
33
|
/**
|
|
21
34
|
* A full-viewport axis-aligned line (infinite extent) at a given offset.
|
|
@@ -26,16 +39,37 @@ interface HUDLine extends cmath.ui.Line {
|
|
|
26
39
|
*
|
|
27
40
|
* Offset is in document space; the renderer projects it to screen.
|
|
28
41
|
*/
|
|
29
|
-
interface HUDRule {
|
|
42
|
+
interface HUDRule extends HUDSemantic {
|
|
30
43
|
axis: "x" | "y";
|
|
31
44
|
offset: number;
|
|
45
|
+
/**
|
|
46
|
+
* Override the canvas color for this rule's stroke. Falls back to
|
|
47
|
+
* the canvas's current color when absent.
|
|
48
|
+
*/
|
|
49
|
+
color?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A single document-space point rendered as a small crosshair "X" on
|
|
53
|
+
* the canvas. The size of the crosshair is fixed in CSS pixels; the
|
|
54
|
+
* anchor (x, y) is in document space.
|
|
55
|
+
*
|
|
56
|
+
* Stroke uses the canvas color by default. Per-point override is opt-in.
|
|
57
|
+
*/
|
|
58
|
+
interface HUDPoint extends HUDSemantic {
|
|
59
|
+
x: number;
|
|
60
|
+
y: number;
|
|
61
|
+
/**
|
|
62
|
+
* Override the canvas color for this point's crosshair stroke.
|
|
63
|
+
* Falls back to the canvas's current color when absent.
|
|
64
|
+
*/
|
|
65
|
+
color?: string;
|
|
32
66
|
}
|
|
33
67
|
/**
|
|
34
68
|
* A rectangle in document space.
|
|
35
69
|
*
|
|
36
70
|
* Stroke uses the canvas color by default. Fill is opt-in.
|
|
37
71
|
*/
|
|
38
|
-
interface HUDRect {
|
|
72
|
+
interface HUDRect extends HUDSemantic {
|
|
39
73
|
x: number;
|
|
40
74
|
y: number;
|
|
41
75
|
width: number;
|
|
@@ -61,7 +95,7 @@ interface HUDRect {
|
|
|
61
95
|
*
|
|
62
96
|
* Stroke uses the canvas color by default. Fill is opt-in.
|
|
63
97
|
*/
|
|
64
|
-
interface HUDPolyline {
|
|
98
|
+
interface HUDPolyline extends HUDSemantic {
|
|
65
99
|
points: cmath.Vector2[];
|
|
66
100
|
/** Whether to stroke the path (default: true). */
|
|
67
101
|
stroke?: boolean;
|
|
@@ -87,7 +121,7 @@ interface HUDPolyline {
|
|
|
87
121
|
*
|
|
88
122
|
* Default anchor is `"center"` (the doc-space point becomes the rect's center).
|
|
89
123
|
*/
|
|
90
|
-
interface HUDScreenRect {
|
|
124
|
+
interface HUDScreenRect extends HUDSemantic {
|
|
91
125
|
/** Document-space anchor point. */
|
|
92
126
|
x: number;
|
|
93
127
|
y: number;
|
|
@@ -102,6 +136,14 @@ interface HUDScreenRect {
|
|
|
102
136
|
fillColor?: string;
|
|
103
137
|
/** Override the canvas color for stroke. */
|
|
104
138
|
strokeColor?: string;
|
|
139
|
+
/**
|
|
140
|
+
* Rotation in radians (CCW) around the rect's screen-space center.
|
|
141
|
+
* Defaults to `0`. Used to make handle knobs / size badges rotate
|
|
142
|
+
* together with a `SelectionShape.transformed` parent. Hit-testing is
|
|
143
|
+
* unaffected — render and hit live on independent shapes per the
|
|
144
|
+
* package's render/hit-test split (see README).
|
|
145
|
+
*/
|
|
146
|
+
angle?: number;
|
|
105
147
|
}
|
|
106
148
|
/**
|
|
107
149
|
* A complete set of draw commands for one frame.
|
|
@@ -113,13 +155,43 @@ interface HUDScreenRect {
|
|
|
113
155
|
interface HUDDraw {
|
|
114
156
|
lines?: HUDLine[];
|
|
115
157
|
rules?: HUDRule[];
|
|
116
|
-
points?:
|
|
158
|
+
points?: HUDPoint[];
|
|
117
159
|
rects?: HUDRect[];
|
|
118
160
|
polylines?: HUDPolyline[];
|
|
119
161
|
/** Screen-space-sized rects anchored to document-space points (handles). */
|
|
120
162
|
screenRects?: HUDScreenRect[];
|
|
121
163
|
}
|
|
122
164
|
//#endregion
|
|
165
|
+
//#region primitives/pixel-grid.d.ts
|
|
166
|
+
declare const DEFAULT_PIXEL_GRID_COLOR = "rgba(150, 150, 150, 0.15)";
|
|
167
|
+
declare const DEFAULT_PIXEL_GRID_STEPS: [number, number];
|
|
168
|
+
interface PixelGridConfig {
|
|
169
|
+
enabled: boolean;
|
|
170
|
+
/** Minimum `transform[0][0]` (uniform scale) at which the grid renders. */
|
|
171
|
+
zoomThreshold: number;
|
|
172
|
+
/**
|
|
173
|
+
* Optional camera transform used to space the grid. Hosts that drive the
|
|
174
|
+
* HUD canvas's own `setTransform` can omit this — the pixel grid falls
|
|
175
|
+
* back to the canvas's chrome transform. Hosts that keep the HUD at
|
|
176
|
+
* identity (e.g. `@grida/svg-editor`, which applies the camera as a CSS
|
|
177
|
+
* transform on the `<svg>` element) must supply this explicitly and
|
|
178
|
+
* update it on every camera change via `setPixelGridTransform`.
|
|
179
|
+
*/
|
|
180
|
+
transform?: cmath.Transform;
|
|
181
|
+
color?: string;
|
|
182
|
+
steps?: [number, number];
|
|
183
|
+
}
|
|
184
|
+
interface DrawPixelGridParams {
|
|
185
|
+
ctx: CanvasRenderingContext2D;
|
|
186
|
+
transform: cmath.Transform;
|
|
187
|
+
width: number;
|
|
188
|
+
height: number;
|
|
189
|
+
dpr: number;
|
|
190
|
+
color?: string;
|
|
191
|
+
steps?: [number, number];
|
|
192
|
+
}
|
|
193
|
+
declare function drawPixelGrid(p: DrawPixelGridParams): void;
|
|
194
|
+
//#endregion
|
|
123
195
|
//#region primitives/canvas.d.ts
|
|
124
196
|
interface HUDCanvasOptions {
|
|
125
197
|
color?: string;
|
|
@@ -143,10 +215,22 @@ declare class HUDCanvas {
|
|
|
143
215
|
private color;
|
|
144
216
|
private width;
|
|
145
217
|
private height;
|
|
218
|
+
private pixelGrid;
|
|
146
219
|
constructor(canvas: HTMLCanvasElement, options?: HUDCanvasOptions);
|
|
147
220
|
setColor(color?: string): void;
|
|
148
221
|
setSize(w: number, h: number): void;
|
|
149
222
|
setTransform(transform: cmath.Transform): void;
|
|
223
|
+
/**
|
|
224
|
+
* Configure the back-most pixel-grid layer. Pass `null` to disable.
|
|
225
|
+
* Drawn before any HUD primitive, gated by `zoomThreshold`. See
|
|
226
|
+
* `PixelGridConfig.transform` for the two-transform contract.
|
|
227
|
+
*/
|
|
228
|
+
setPixelGrid(config: PixelGridConfig | null): void;
|
|
229
|
+
/**
|
|
230
|
+
* Update only the pixel grid's transform, without replacing the rest of
|
|
231
|
+
* the config. Cheap to call per camera tick.
|
|
232
|
+
*/
|
|
233
|
+
setPixelGridTransform(transform: cmath.Transform): void;
|
|
150
234
|
/**
|
|
151
235
|
* Clear the canvas and draw all primitives in `commands`.
|
|
152
236
|
* Pass `undefined` to clear without drawing (e.g. when no overlay is active).
|
|
@@ -172,16 +256,29 @@ declare class HUDCanvas {
|
|
|
172
256
|
private drawScreenRects;
|
|
173
257
|
}
|
|
174
258
|
//#endregion
|
|
259
|
+
//#region primitives/draw.d.ts
|
|
260
|
+
interface HUDGroupFilter {
|
|
261
|
+
hidden?: Iterable<HUDSemanticGroup>;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Filter a draw command list by semantic group.
|
|
265
|
+
*
|
|
266
|
+
* Ungrouped primitives are always kept. The function is intentionally shallow:
|
|
267
|
+
* primitives are immutable command objects on the hot draw path, so preserving
|
|
268
|
+
* object identity keeps this as a visibility pass rather than a rewrite.
|
|
269
|
+
*/
|
|
270
|
+
declare function filterHUDDrawByGroup(draw: HUDDraw | undefined, filter: HUDGroupFilter): HUDDraw | undefined;
|
|
271
|
+
//#endregion
|
|
175
272
|
//#region primitives/snap-guide.d.ts
|
|
176
273
|
/**
|
|
177
274
|
* Convert a `guide.SnapGuide` (the output of `guide.plot()`) into a
|
|
178
275
|
* generic {@link HUDDraw} command list.
|
|
179
276
|
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
277
|
+
* `color`, when supplied, is applied as the per-item stroke override
|
|
278
|
+
* for every emitted line, rule, and point. When absent, the HUD
|
|
279
|
+
* canvas's current color is used.
|
|
183
280
|
*/
|
|
184
|
-
declare function snapGuideToHUDDraw(sg: guide.SnapGuide | undefined): HUDDraw | undefined;
|
|
281
|
+
declare function snapGuideToHUDDraw(sg: guide.SnapGuide | undefined, color?: string): HUDDraw | undefined;
|
|
185
282
|
//#endregion
|
|
186
283
|
//#region primitives/measurement-guide.d.ts
|
|
187
284
|
/**
|
|
@@ -281,19 +378,57 @@ interface SurfaceResponse {
|
|
|
281
378
|
hoverChanged: boolean;
|
|
282
379
|
}
|
|
283
380
|
//#endregion
|
|
284
|
-
//#region event/
|
|
285
|
-
/**
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
381
|
+
//#region event/shape.d.ts
|
|
382
|
+
/**
|
|
383
|
+
* Selection shape — what the chrome wraps.
|
|
384
|
+
*
|
|
385
|
+
* Hosts return a `SelectionShape` from `shapeOf(id)` so the HUD can lay out
|
|
386
|
+
* the right kind of chrome:
|
|
387
|
+
*
|
|
388
|
+
* - **`rect`** — standard bounding box. Renders selection outline + 4 corner
|
|
389
|
+
* knobs, with virtual edge / rotation hit regions.
|
|
390
|
+
* - **`transformed`** — an axis-aligned local bbox PLUS a 2×3 affine matrix
|
|
391
|
+
* mapping local-frame points into doc-space. Covers rotation, skew,
|
|
392
|
+
* non-uniform scale, and mirror with one code path. `local.width × local.height`
|
|
393
|
+
* are the artwork's true dims (read by the size badge and by `applyResize`
|
|
394
|
+
* in local space). Identity matrix here is byte-equivalent to
|
|
395
|
+
* `{ kind: "rect", rect: local }`.
|
|
396
|
+
* - **`line`** — two-endpoint primitive (e.g. SVG `<line>`). Renders the
|
|
397
|
+
* line segment + 2 endpoint knobs. No edge / rotation regions.
|
|
398
|
+
* - **`unresolved`** — internal-only. Used inside `SelectionGroup` when the
|
|
399
|
+
* host gave a flat `NodeId[]` to `setSelection` — the chrome builder
|
|
400
|
+
* resolves the real shape by calling `shapeOf(id)` at frame build time.
|
|
401
|
+
* Hosts never emit this; treating it as host-facing would be a bug.
|
|
402
|
+
*
|
|
403
|
+
* Future kinds (e.g. `polyline`, `ellipse_oriented`) can be added without
|
|
404
|
+
* breaking the existing kinds — the chrome builder branches on `kind`.
|
|
405
|
+
*/
|
|
406
|
+
type SelectionShape = {
|
|
407
|
+
kind: "rect";
|
|
408
|
+
rect: Rect;
|
|
293
409
|
} | {
|
|
294
|
-
kind: "
|
|
295
|
-
|
|
410
|
+
kind: "transformed"; /** Local-frame AABB; width/height are artwork's true dims. */
|
|
411
|
+
local: Rect; /** 2×3 affine mapping local-frame points → doc-space. */
|
|
412
|
+
matrix: cmath.Transform;
|
|
413
|
+
} | {
|
|
414
|
+
kind: "line";
|
|
415
|
+
p1: cmath.Vector2;
|
|
416
|
+
p2: cmath.Vector2;
|
|
417
|
+
} | {
|
|
418
|
+
kind: "unresolved";
|
|
419
|
+
id: string;
|
|
296
420
|
};
|
|
421
|
+
/**
|
|
422
|
+
* A logical selection group. The HUD renders one chrome instance per group.
|
|
423
|
+
*
|
|
424
|
+
* The host pre-computes `shape` (typically the union of member bounds for
|
|
425
|
+
* multi-node groups). Member `ids` are the gesture target — they all
|
|
426
|
+
* translate/resize together as a unit.
|
|
427
|
+
*/
|
|
428
|
+
interface SelectionGroup {
|
|
429
|
+
ids: readonly NodeId[];
|
|
430
|
+
shape: SelectionShape;
|
|
431
|
+
}
|
|
297
432
|
//#endregion
|
|
298
433
|
//#region event/gesture.d.ts
|
|
299
434
|
/**
|
|
@@ -333,10 +468,15 @@ type SurfaceGesture = {
|
|
|
333
468
|
} | {
|
|
334
469
|
kind: "resize"; /** Member ids of the group being resized (1 or more). */
|
|
335
470
|
ids: NodeId[]; /** Which handle the user grabbed. */
|
|
336
|
-
direction: ResizeDirection;
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
471
|
+
direction: ResizeDirection;
|
|
472
|
+
/**
|
|
473
|
+
* Selection shape at gesture start. For `kind: "rect"` this is the
|
|
474
|
+
* doc-space bbox; for `kind: "transformed"` it carries the local-frame
|
|
475
|
+
* AABB + matrix so resize math runs in the rotated/skewed local frame.
|
|
476
|
+
*/
|
|
477
|
+
initial_shape: SelectionShape; /** Anchor (pointer-down) in document-space. */
|
|
478
|
+
anchor_doc: cmath.Vector2; /** Current shape during the gesture. Same kind as `initial_shape`. */
|
|
479
|
+
current_shape: SelectionShape;
|
|
340
480
|
} | {
|
|
341
481
|
kind: "rotate";
|
|
342
482
|
ids: NodeId[];
|
|
@@ -344,6 +484,14 @@ type SurfaceGesture = {
|
|
|
344
484
|
center_doc: cmath.Vector2; /** Angle at gesture start (radians). */
|
|
345
485
|
anchor_angle: number; /** Current angle (radians). */
|
|
346
486
|
current_angle: number;
|
|
487
|
+
/**
|
|
488
|
+
* Selection's screen-space rotation at gesture start (radians).
|
|
489
|
+
* Composed with `current_angle - anchor_angle` each frame to set
|
|
490
|
+
* the rotate-cursor's `baseAngle` — so cursors on already-rotated
|
|
491
|
+
* selections continue tilting correctly mid-gesture instead of
|
|
492
|
+
* snapping back to 0 + delta.
|
|
493
|
+
*/
|
|
494
|
+
initial_cursor_angle: number;
|
|
347
495
|
} | {
|
|
348
496
|
kind: "endpoint";
|
|
349
497
|
id: NodeId;
|
|
@@ -384,8 +532,20 @@ type Intent = {
|
|
|
384
532
|
} | {
|
|
385
533
|
kind: "resize"; /** Member ids of the group being resized (1 or more). */
|
|
386
534
|
ids: NodeId[];
|
|
387
|
-
anchor: ResizeDirection;
|
|
535
|
+
anchor: ResizeDirection;
|
|
536
|
+
/**
|
|
537
|
+
* Target rect in document-space. For `transformed` selections this
|
|
538
|
+
* is the AABB of the new shape — preserved so axis-aligned hosts
|
|
539
|
+
* that ignore `shape` keep working unchanged.
|
|
540
|
+
*/
|
|
388
541
|
rect: Rect;
|
|
542
|
+
/**
|
|
543
|
+
* Full target shape. Present whenever the gesture produced one
|
|
544
|
+
* (which is always, post-Commit 2 of the affine-first plan).
|
|
545
|
+
* Hosts that handle rotated/sheared selections consume this
|
|
546
|
+
* directly; legacy hosts can read `rect` and ignore `shape`.
|
|
547
|
+
*/
|
|
548
|
+
shape?: SelectionShape;
|
|
389
549
|
phase: IntentPhase;
|
|
390
550
|
} | {
|
|
391
551
|
kind: "rotate"; /** Member ids of the group being rotated (typically 1). */
|
|
@@ -424,48 +584,6 @@ type IntentHandler = (intent: Intent) => void;
|
|
|
424
584
|
*/
|
|
425
585
|
type Transform = cmath.Transform;
|
|
426
586
|
//#endregion
|
|
427
|
-
//#region event/shape.d.ts
|
|
428
|
-
/**
|
|
429
|
-
* Selection shape — what the chrome wraps.
|
|
430
|
-
*
|
|
431
|
-
* Hosts return a `SelectionShape` from `shapeOf(id)` so the HUD can lay out
|
|
432
|
-
* the right kind of chrome:
|
|
433
|
-
*
|
|
434
|
-
* - **`rect`** — standard bounding box. Renders selection outline + 4 corner
|
|
435
|
-
* knobs, with virtual edge / rotation hit regions.
|
|
436
|
-
* - **`line`** — two-endpoint primitive (e.g. SVG `<line>`). Renders the
|
|
437
|
-
* line segment + 2 endpoint knobs. No edge / rotation regions.
|
|
438
|
-
* - **`unresolved`** — internal-only. Used inside `SelectionGroup` when the
|
|
439
|
-
* host gave a flat `NodeId[]` to `setSelection` — the chrome builder
|
|
440
|
-
* resolves the real shape by calling `shapeOf(id)` at frame build time.
|
|
441
|
-
* Hosts never emit this; treating it as host-facing would be a bug.
|
|
442
|
-
*
|
|
443
|
-
* Future kinds (e.g. `polyline`, `ellipse_oriented`) can be added without
|
|
444
|
-
* breaking the existing kinds — the chrome builder branches on `kind`.
|
|
445
|
-
*/
|
|
446
|
-
type SelectionShape = {
|
|
447
|
-
kind: "rect";
|
|
448
|
-
rect: Rect;
|
|
449
|
-
} | {
|
|
450
|
-
kind: "line";
|
|
451
|
-
p1: cmath.Vector2;
|
|
452
|
-
p2: cmath.Vector2;
|
|
453
|
-
} | {
|
|
454
|
-
kind: "unresolved";
|
|
455
|
-
id: string;
|
|
456
|
-
};
|
|
457
|
-
/**
|
|
458
|
-
* A logical selection group. The HUD renders one chrome instance per group.
|
|
459
|
-
*
|
|
460
|
-
* The host pre-computes `shape` (typically the union of member bounds for
|
|
461
|
-
* multi-node groups). Member `ids` are the gesture target — they all
|
|
462
|
-
* translate/resize together as a unit.
|
|
463
|
-
*/
|
|
464
|
-
interface SelectionGroup {
|
|
465
|
-
ids: readonly NodeId[];
|
|
466
|
-
shape: SelectionShape;
|
|
467
|
-
}
|
|
468
|
-
//#endregion
|
|
469
587
|
//#region surface/style.d.ts
|
|
470
588
|
/**
|
|
471
589
|
* HUD style — colors, sizes, and offsets for the surface-owned chrome.
|
|
@@ -491,92 +609,6 @@ interface HUDStyle {
|
|
|
491
609
|
showRotationHandles: boolean;
|
|
492
610
|
}
|
|
493
611
|
//#endregion
|
|
494
|
-
//#region surface/surface.d.ts
|
|
495
|
-
interface SurfaceOptions {
|
|
496
|
-
/**
|
|
497
|
-
* Content pick. Given a doc-space point, return the topmost node id under
|
|
498
|
-
* the pointer, or `null`. Host wraps its scene query however it wants
|
|
499
|
-
* (e.g. `elementFromPoint` + `data-id` for SVG-DOM hosts).
|
|
500
|
-
*/
|
|
501
|
-
pick: (point_doc: [number, number]) => NodeId | null;
|
|
502
|
-
/**
|
|
503
|
-
* Selection shape for a node — what the chrome should wrap. Most nodes
|
|
504
|
-
* return `{ kind: "rect", rect }`; vector lines return
|
|
505
|
-
* `{ kind: "line", p1, p2 }`.
|
|
506
|
-
*/
|
|
507
|
-
shapeOf: (id: NodeId) => SelectionShape | null;
|
|
508
|
-
/** Surface emits intents the host commits. */
|
|
509
|
-
onIntent: IntentHandler;
|
|
510
|
-
/** Initial style (partial; merged with defaults). */
|
|
511
|
-
style?: Partial<HUDStyle>;
|
|
512
|
-
/** Initial readonly flag. Default `false`. */
|
|
513
|
-
readonly?: boolean;
|
|
514
|
-
/** Optional HUDCanvas color override. */
|
|
515
|
-
color?: string;
|
|
516
|
-
}
|
|
517
|
-
/**
|
|
518
|
-
* Top-level wired surface.
|
|
519
|
-
*
|
|
520
|
-
* Owns an internal `HUDCanvas`, a `SurfaceState` (gesture/hover/...) and
|
|
521
|
-
* the host providers. On every `dispatch`, the state machine runs;
|
|
522
|
-
* `draw` composes surface chrome + host-fed extras into a single canvas
|
|
523
|
-
* paint.
|
|
524
|
-
*/
|
|
525
|
-
declare class Surface {
|
|
526
|
-
private hudCanvas;
|
|
527
|
-
private state;
|
|
528
|
-
private style;
|
|
529
|
-
private opts;
|
|
530
|
-
private width;
|
|
531
|
-
private height;
|
|
532
|
-
constructor(canvas: HTMLCanvasElement, options: SurfaceOptions);
|
|
533
|
-
setSize(w: number, h: number): void;
|
|
534
|
-
setTransform(t: Transform): void;
|
|
535
|
-
/**
|
|
536
|
-
* Push a new selection from the host.
|
|
537
|
-
*
|
|
538
|
-
* Accepts either:
|
|
539
|
-
* - `NodeId[]` — each id becomes its own single-member group, shape
|
|
540
|
-
* resolved via `shapeOf(id)` by the chrome builder.
|
|
541
|
-
* - `SelectionGroup[]` — pre-computed groups with their union shape.
|
|
542
|
-
*
|
|
543
|
-
* See `SurfaceState.setSelection` for details.
|
|
544
|
-
*/
|
|
545
|
-
setSelection(input: readonly NodeId[] | readonly SelectionGroup[]): void;
|
|
546
|
-
setStyle(partial: Partial<HUDStyle>): void;
|
|
547
|
-
setReadonly(v: boolean): void;
|
|
548
|
-
/**
|
|
549
|
-
* Set or clear a host-driven hover override.
|
|
550
|
-
*
|
|
551
|
-
* The surface tracks two hover sources:
|
|
552
|
-
* - **Pointer pick** — what scene content is under the cursor (updated
|
|
553
|
-
* automatically on `pointer_move`).
|
|
554
|
-
* - **Host override** — what the host wants to show as hovered, e.g.
|
|
555
|
-
* from a layers panel row mouseenter.
|
|
556
|
-
*
|
|
557
|
-
* The override (when non-null) wins. `hover()` returns the effective
|
|
558
|
-
* value; chrome renders the effective value. Pass `null` to clear and
|
|
559
|
-
* fall back to pointer pick.
|
|
560
|
-
*
|
|
561
|
-
* Returns the same response shape as `dispatch` so the host can react
|
|
562
|
-
* to whether anything actually changed.
|
|
563
|
-
*/
|
|
564
|
-
setHoverOverride(id: NodeId | null): SurfaceResponse;
|
|
565
|
-
dispose(): void;
|
|
566
|
-
dispatch(event: SurfaceEvent): SurfaceResponse;
|
|
567
|
-
draw(extra?: HUDDraw): void;
|
|
568
|
-
/** Convenience: clear the canvas (e.g. when the host stops the surface). */
|
|
569
|
-
clear(): void;
|
|
570
|
-
gesture(): SurfaceGesture;
|
|
571
|
-
/**
|
|
572
|
-
* The effective hover: host override (when set) wins over pointer pick.
|
|
573
|
-
* Use this for chrome decisions and host-side reads.
|
|
574
|
-
*/
|
|
575
|
-
hover(): NodeId | null;
|
|
576
|
-
cursor(): CursorIcon;
|
|
577
|
-
modifiers(): Modifiers;
|
|
578
|
-
}
|
|
579
|
-
//#endregion
|
|
580
612
|
//#region event/hit-regions.d.ts
|
|
581
613
|
/**
|
|
582
614
|
* Action a UI hit-region triggers when clicked.
|
|
@@ -588,9 +620,12 @@ declare class Surface {
|
|
|
588
620
|
*
|
|
589
621
|
* - `select_node` — user clicked on a node-representative UI region.
|
|
590
622
|
* - `resize_handle` — one of 8 resize regions (4 corner knobs + 4 virtual
|
|
591
|
-
* edges). Carries the group's member ids and the group's initial
|
|
623
|
+
* edges). Carries the group's member ids and the group's initial
|
|
624
|
+
* `SelectionShape` — `rect` for axis-aligned groups, `transformed` for
|
|
625
|
+
* rotated/sheared groups (so resize math runs in the local frame).
|
|
592
626
|
* - `rotate_handle` — one of 4 virtual rotation regions outside the group's
|
|
593
|
-
* corners. Carries the group's initial
|
|
627
|
+
* corners. Carries the group's initial `SelectionShape` for center math
|
|
628
|
+
* (pivot = center of `shapeBounds(initial_shape)`).
|
|
594
629
|
* - `endpoint_handle` — endpoint of a line-shape selection. Carries the
|
|
595
630
|
* line's current p1/p2 so dragging is relative to a stable snapshot.
|
|
596
631
|
* - `translate_handle` — body region covering a selection group's bbox.
|
|
@@ -606,22 +641,12 @@ type OverlayAction = {
|
|
|
606
641
|
kind: "resize_handle";
|
|
607
642
|
direction: ResizeDirection;
|
|
608
643
|
ids: readonly NodeId[];
|
|
609
|
-
|
|
610
|
-
x: number;
|
|
611
|
-
y: number;
|
|
612
|
-
width: number;
|
|
613
|
-
height: number;
|
|
614
|
-
};
|
|
644
|
+
initial_shape: SelectionShape;
|
|
615
645
|
} | {
|
|
616
646
|
kind: "rotate_handle";
|
|
617
647
|
corner: RotationCorner;
|
|
618
648
|
ids: readonly NodeId[];
|
|
619
|
-
|
|
620
|
-
x: number;
|
|
621
|
-
y: number;
|
|
622
|
-
width: number;
|
|
623
|
-
height: number;
|
|
624
|
-
};
|
|
649
|
+
initial_shape: SelectionShape;
|
|
625
650
|
} | {
|
|
626
651
|
kind: "endpoint_handle";
|
|
627
652
|
endpoint: "p1" | "p2";
|
|
@@ -673,6 +698,23 @@ type HitShape =
|
|
|
673
698
|
| {
|
|
674
699
|
kind: "screen_aabb";
|
|
675
700
|
rect: Rect;
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Oriented bounding-box hit shape — an axis-aligned `rect` in a *shadow*
|
|
704
|
+
* coordinate space, plus the affine that maps a screen-space pointer
|
|
705
|
+
* INTO that space. The hit-test pipeline applies `inverse_transform` to
|
|
706
|
+
* the pointer and then tests against `rect` with normal AABB containment.
|
|
707
|
+
*
|
|
708
|
+
* Used by transformed-chrome zones: the 9-slice runs in an axis-aligned
|
|
709
|
+
* shadow rect centered at the chrome's screen center, and a rotation
|
|
710
|
+
* (typically around the same center) maps shadow → screen. Storing the
|
|
711
|
+
* inverse here lets hit-test stay exact at any rotation/skew without
|
|
712
|
+
* inflating to an AABB-of-rotated-corners.
|
|
713
|
+
*/
|
|
714
|
+
| {
|
|
715
|
+
kind: "screen_obb";
|
|
716
|
+
rect: Rect; /** screen → shadow. Applied to the pointer before AABB containment. */
|
|
717
|
+
inverse_transform: cmath.Transform;
|
|
676
718
|
};
|
|
677
719
|
/**
|
|
678
720
|
* Visual representation for one overlay element. Maps directly to the
|
|
@@ -691,6 +733,12 @@ type RenderShape = /** Screen-space sized rect at doc anchor — e.g. resize kno
|
|
|
691
733
|
stroke?: boolean;
|
|
692
734
|
fillColor?: string;
|
|
693
735
|
strokeColor?: string;
|
|
736
|
+
/**
|
|
737
|
+
* Rotation around the rect's screen-space center, in radians (CCW).
|
|
738
|
+
* Defaults to 0. Used for knobs/badges rendered for a transformed
|
|
739
|
+
* selection so they rotate with the parent.
|
|
740
|
+
*/
|
|
741
|
+
angle?: number;
|
|
694
742
|
} /** Doc-space rect — e.g. selection outline, marquee. */ | {
|
|
695
743
|
kind: "doc_rect";
|
|
696
744
|
x: number;
|
|
@@ -721,14 +769,179 @@ type RenderShape = /** Screen-space sized rect at doc anchor — e.g. resize kno
|
|
|
721
769
|
* `render` — they exist only as hit regions.
|
|
722
770
|
* - **Padded elements** have `hit` larger than the corresponding `render`
|
|
723
771
|
* shape (e.g. 16px hit AABB around an 8px visual knob).
|
|
724
|
-
*
|
|
725
|
-
*
|
|
772
|
+
*
|
|
773
|
+
* TODO(rotation): when the first base-rotated overlay lands (e.g. an
|
|
774
|
+
* in-canvas rotation pip), add an `orientation: "screen" | "base"` field.
|
|
775
|
+
* Existing call sites default to `"screen"` and don't change.
|
|
726
776
|
*/
|
|
727
777
|
interface OverlayElement {
|
|
778
|
+
/** Stable semantic identifier. Format: `"<kind>[:<param>]"`. Examples:
|
|
779
|
+
* `"translate"`, `"resize_handle:nw"`, `"resize_edge:n"`,
|
|
780
|
+
* `"rotate:ne"`, `"endpoint:p1"`. Used by tests and debug tooling. */
|
|
781
|
+
label: string;
|
|
782
|
+
/** Semantic owner for group-level visibility policy. */
|
|
783
|
+
group?: HUDSemanticGroup;
|
|
728
784
|
action: OverlayAction;
|
|
729
785
|
hit: HitShape;
|
|
730
786
|
render?: RenderShape;
|
|
787
|
+
/** Lower wins. See `HUDHitPriority` in `selection-controls.ts`. */
|
|
788
|
+
priority: number;
|
|
731
789
|
cursor?: CursorIcon;
|
|
732
790
|
}
|
|
733
791
|
//#endregion
|
|
734
|
-
|
|
792
|
+
//#region surface/chrome.d.ts
|
|
793
|
+
interface SurfaceChromeGroups {
|
|
794
|
+
hover?: HUDSemanticGroup;
|
|
795
|
+
selection?: HUDSemanticGroup;
|
|
796
|
+
selectionControls?: HUDSemanticGroup;
|
|
797
|
+
marquee?: HUDSemanticGroup;
|
|
798
|
+
transformPreview?: HUDSemanticGroup;
|
|
799
|
+
}
|
|
800
|
+
//#endregion
|
|
801
|
+
//#region surface/surface.d.ts
|
|
802
|
+
interface SurfaceVisibilityContext {
|
|
803
|
+
gesture: SurfaceGesture;
|
|
804
|
+
}
|
|
805
|
+
interface SurfaceVisibility {
|
|
806
|
+
hidden?: Iterable<HUDSemanticGroup>;
|
|
807
|
+
}
|
|
808
|
+
type SurfaceVisibilityPolicy = (context: SurfaceVisibilityContext) => SurfaceVisibility | undefined;
|
|
809
|
+
interface SurfaceOptions {
|
|
810
|
+
/**
|
|
811
|
+
* Content pick. Given a doc-space point, return the topmost node id under
|
|
812
|
+
* the pointer, or `null`. Host wraps its scene query however it wants
|
|
813
|
+
* (e.g. `elementFromPoint` + `data-id` for SVG-DOM hosts).
|
|
814
|
+
*/
|
|
815
|
+
pick: (point_doc: [number, number]) => NodeId | null;
|
|
816
|
+
/**
|
|
817
|
+
* Selection shape for a node — what the chrome should wrap. Most nodes
|
|
818
|
+
* return `{ kind: "rect", rect }`; vector lines return
|
|
819
|
+
* `{ kind: "line", p1, p2 }`.
|
|
820
|
+
*/
|
|
821
|
+
shapeOf: (id: NodeId) => SelectionShape | null;
|
|
822
|
+
/** Surface emits intents the host commits. */
|
|
823
|
+
onIntent: IntentHandler;
|
|
824
|
+
/** Initial style (partial; merged with defaults). */
|
|
825
|
+
style?: Partial<HUDStyle>;
|
|
826
|
+
/** Initial readonly flag. Default `false`. */
|
|
827
|
+
readonly?: boolean;
|
|
828
|
+
/** Optional HUDCanvas color override. */
|
|
829
|
+
color?: string;
|
|
830
|
+
/**
|
|
831
|
+
* Optional pixel-grid configuration. Drawn back-most in the HUD canvas
|
|
832
|
+
* when `enabled` and the current zoom exceeds `zoomThreshold`. Hosts can
|
|
833
|
+
* also call `surface.setPixelGrid(...)` later.
|
|
834
|
+
*/
|
|
835
|
+
pixelGrid?: PixelGridConfig | null;
|
|
836
|
+
/**
|
|
837
|
+
* Optional semantic groups for surface-owned chrome. The HUD package does
|
|
838
|
+
* not define a group vocabulary; hosts pass the strings they want to use.
|
|
839
|
+
*/
|
|
840
|
+
groups?: SurfaceChromeGroups;
|
|
841
|
+
/**
|
|
842
|
+
* Host-owned visibility policy. Called per frame with the current surface
|
|
843
|
+
* gesture; returned groups are filtered from surface chrome and host extras.
|
|
844
|
+
*/
|
|
845
|
+
visibility?: SurfaceVisibilityPolicy;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Top-level wired surface.
|
|
849
|
+
*
|
|
850
|
+
* Owns an internal `HUDCanvas`, a `SurfaceState` (gesture/hover/...) and
|
|
851
|
+
* the host providers. On every `dispatch`, the state machine runs;
|
|
852
|
+
* `draw` composes surface chrome + host-fed extras into a single canvas
|
|
853
|
+
* paint.
|
|
854
|
+
*/
|
|
855
|
+
declare class Surface {
|
|
856
|
+
private hudCanvas;
|
|
857
|
+
private state;
|
|
858
|
+
private style;
|
|
859
|
+
private opts;
|
|
860
|
+
private colorOverride;
|
|
861
|
+
private width;
|
|
862
|
+
private height;
|
|
863
|
+
private cursor_renderer;
|
|
864
|
+
constructor(canvas: HTMLCanvasElement, options: SurfaceOptions);
|
|
865
|
+
/** Configure / disable the back-most pixel-grid layer. */
|
|
866
|
+
setPixelGrid(config: PixelGridConfig | null): void;
|
|
867
|
+
/**
|
|
868
|
+
* Update just the pixel grid's transform. Cheap to call per camera tick.
|
|
869
|
+
* No-op when no pixel-grid config is set.
|
|
870
|
+
*/
|
|
871
|
+
setPixelGridTransform(transform: Transform): void;
|
|
872
|
+
setSize(w: number, h: number): void;
|
|
873
|
+
setTransform(t: Transform): void;
|
|
874
|
+
/**
|
|
875
|
+
* Push a new selection from the host.
|
|
876
|
+
*
|
|
877
|
+
* Accepts either:
|
|
878
|
+
* - `NodeId[]` — each id becomes its own single-member group, shape
|
|
879
|
+
* resolved via `shapeOf(id)` by the chrome builder.
|
|
880
|
+
* - `SelectionGroup[]` — pre-computed groups with their union shape.
|
|
881
|
+
*
|
|
882
|
+
* See `SurfaceState.setSelection` for details.
|
|
883
|
+
*/
|
|
884
|
+
setSelection(input: readonly NodeId[] | readonly SelectionGroup[]): void;
|
|
885
|
+
setStyle(partial: Partial<HUDStyle>): void;
|
|
886
|
+
/**
|
|
887
|
+
* Set or clear the host color override. `null` clears the override and
|
|
888
|
+
* lets `style.chromeColor` win on the next paint.
|
|
889
|
+
*/
|
|
890
|
+
setColor(color: string | null): void;
|
|
891
|
+
setReadonly(v: boolean): void;
|
|
892
|
+
/**
|
|
893
|
+
* Set or clear a host-driven hover override.
|
|
894
|
+
*
|
|
895
|
+
* The surface tracks two hover sources:
|
|
896
|
+
* - **Pointer pick** — what scene content is under the cursor (updated
|
|
897
|
+
* automatically on `pointer_move`).
|
|
898
|
+
* - **Host override** — what the host wants to show as hovered, e.g.
|
|
899
|
+
* from a layers panel row mouseenter.
|
|
900
|
+
*
|
|
901
|
+
* The override (when non-null) wins. `hover()` returns the effective
|
|
902
|
+
* value; chrome renders the effective value. Pass `null` to clear and
|
|
903
|
+
* fall back to pointer pick.
|
|
904
|
+
*
|
|
905
|
+
* Returns the same response shape as `dispatch` so the host can react
|
|
906
|
+
* to whether anything actually changed.
|
|
907
|
+
*/
|
|
908
|
+
setHoverOverride(id: NodeId | null): SurfaceResponse;
|
|
909
|
+
dispose(): void;
|
|
910
|
+
dispatch(event: SurfaceEvent): SurfaceResponse;
|
|
911
|
+
draw(extra?: HUDDraw): void;
|
|
912
|
+
/** Convenience: clear the canvas (e.g. when the host stops the surface). */
|
|
913
|
+
clear(): void;
|
|
914
|
+
gesture(): SurfaceGesture;
|
|
915
|
+
/**
|
|
916
|
+
* The effective hover: host override (when set) wins over pointer pick.
|
|
917
|
+
* Use this for chrome decisions and host-side reads.
|
|
918
|
+
*/
|
|
919
|
+
hover(): NodeId | null;
|
|
920
|
+
cursor(): CursorIcon;
|
|
921
|
+
/**
|
|
922
|
+
* Resolve the current cursor to a CSS `cursor:` value. Runs the
|
|
923
|
+
* installed renderer (or the built-in `cursorToCss` if none installed).
|
|
924
|
+
*
|
|
925
|
+
* Host wires it like:
|
|
926
|
+
*
|
|
927
|
+
* const r = surface.dispatch(event);
|
|
928
|
+
* if (r.cursorChanged) el.style.cursor = surface.cursorCss();
|
|
929
|
+
*
|
|
930
|
+
* Saves the host from re-importing `cursorToCss` after every dispatch
|
|
931
|
+
* and gives one place to change behavior when a renderer is swapped in.
|
|
932
|
+
*/
|
|
933
|
+
cursorCss(): string;
|
|
934
|
+
/**
|
|
935
|
+
* Install (or clear) a custom cursor renderer.
|
|
936
|
+
*
|
|
937
|
+
* `null` restores the built-in `cursorToCss` behavior (native CSS
|
|
938
|
+
* keywords for every variant). Pass `cursors.defaultRenderer()` from
|
|
939
|
+
* `@grida/hud/cursors` for the bundled SVG cursor set.
|
|
940
|
+
*
|
|
941
|
+
* Re-callable mid-session; the next `cursorCss()` reads the new value.
|
|
942
|
+
*/
|
|
943
|
+
setCursorRenderer(fn: CursorRenderer | null): void;
|
|
944
|
+
modifiers(): Modifiers;
|
|
945
|
+
}
|
|
946
|
+
//#endregion
|
|
947
|
+
export { HUDCanvas as A, HUDRect as B, SurfaceEvent as C, measurementToHUDDraw as D, marqueeToHUDDraw as E, PixelGridConfig as F, HUDScreenRect as H, drawPixelGrid as I, HUDDraw as L, DEFAULT_PIXEL_GRID_COLOR as M, DEFAULT_PIXEL_GRID_STEPS as N, snapGuideToHUDDraw as O, DrawPixelGridParams as P, HUDLine as R, PointerButton as S, lassoToHUDDraw as T, HUDSemantic as U, HUDRule as V, HUDSemanticGroup as W, SurfaceGesture as _, SurfaceVisibilityPolicy as a, Modifiers as b, MIN_CHROME_VISIBLE_SIZE as c, RenderShape as d, HUDStyle as f, Rect as g, SelectMode as h, SurfaceVisibilityContext as i, HUDCanvasOptions as j, filterHUDDrawByGroup as k, MIN_HIT_SIZE as l, IntentPhase as m, SurfaceOptions as n, SurfaceChromeGroups as o, Intent as p, SurfaceVisibility as r, HitShape as s, Surface as t, OverlayElement as u, SelectionGroup as v, SurfaceResponse as w, NO_MODS as x, SelectionShape as y, HUDPolyline as z };
|