@grida/hud 0.1.0 → 0.2.1

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,241 @@
1
+ import { f as HUDSemanticGroup, r as HUDPaint } from "./types-3wwFisZs.mjs";
2
+ import cmath from "@grida/cmath";
3
+
4
+ //#region primitives/cursor.d.ts
5
+ /** 8 cardinal/diagonal resize directions. */
6
+ type ResizeDirection = "n" | "ne" | "e" | "se" | "s" | "sw" | "w" | "nw";
7
+ /** 4 corner positions for rotation handles. */
8
+ type RotationCorner = "nw" | "ne" | "se" | "sw";
9
+ /**
10
+ * Logical cursor icon names.
11
+ *
12
+ * `baseAngle` (radians) tilts the rendered arrow by an additional
13
+ * amount on top of the variant's canonical orientation; the
14
+ * orchestrator sets it when a gesture rotates a selection so the
15
+ * cursor tracks live rotation.
16
+ */
17
+ type CursorIcon = "default" | "pointer" | "move" | "crosshair" | "grab" | "grabbing" | "text" | {
18
+ kind: "resize";
19
+ direction: ResizeDirection;
20
+ baseAngle?: number;
21
+ } | {
22
+ kind: "rotate";
23
+ corner: RotationCorner;
24
+ baseAngle?: number;
25
+ };
26
+ /**
27
+ * Angle quantization bucket — 0.5° in radians. Two rotated cursors
28
+ * compare equal when their `baseAngle`s round to the same bucket.
29
+ *
30
+ * 0.5° is below human perception for cursor orientation, so the
31
+ * quantization is visually free.
32
+ */
33
+ declare const CURSOR_ANGLE_BUCKET_RAD: number;
34
+ /** Quantize an angle (radians) to its `CURSOR_ANGLE_BUCKET_RAD` bucket. */
35
+ declare function angleBucket(rad: number | undefined): number;
36
+ /**
37
+ * Pluggable cursor renderer — maps a logical `CursorIcon` to a CSS
38
+ * `cursor:` value. Bedrock ships {@link cursorToCss} as the default;
39
+ * hosts compose their own to substitute SVG data-URLs or platform
40
+ * extensions.
41
+ */
42
+ type CursorRenderer = (icon: CursorIcon) => string;
43
+ /**
44
+ * Default mapping from `CursorIcon` to CSS `cursor` value.
45
+ */
46
+ declare function cursorToCss(c: CursorIcon): string;
47
+ /**
48
+ * Cursor equality with `baseAngle` bucketing.
49
+ *
50
+ * Lets a hot path (a rotate-in-progress gesture's per-frame setCursor)
51
+ * emit `cursorChanged` only on visible motion (≥ one bucket of
52
+ * rotation).
53
+ */
54
+ declare function cursorEquals(a: CursorIcon, b: CursorIcon): boolean;
55
+ //#endregion
56
+ //#region primitives/overlay.d.ts
57
+ /**
58
+ * Minimum hit-target size in screen-px.
59
+ *
60
+ * Visual knobs are typically 8px; the hit region is 16px so the user
61
+ * does not need pixel-perfect aim (Fitts'). Bedrock constant — value
62
+ * mirrors the legacy `event/overlay.ts` constant during the additive
63
+ * migration.
64
+ */
65
+ declare const MIN_HIT_SIZE = 16;
66
+ /**
67
+ * Below this selection size (in screen-px on either axis), chrome is
68
+ * suppressed — both the visual handles AND the hit regions. The
69
+ * consumer enforces this when computing per-frame `HUDObject`s.
70
+ */
71
+ declare const MIN_CHROME_VISIBLE_SIZE = 12;
72
+ /**
73
+ * The hit region of a `HUDObject`. Always screen-space; the variants
74
+ * differ on how the region is anchored.
75
+ *
76
+ * **Variants** (closed taxonomy — no host extension):
77
+ *
78
+ * - `screen_rect_at_doc` — fixed screen-pixel rect, anchored to a
79
+ * doc-space point. The hit region tracks the document under camera
80
+ * changes; dimensions stay constant in CSS px. Used by handles.
81
+ *
82
+ * - `screen_aabb` — pre-projected screen-space AABB. Used for
83
+ * overlays whose layout is already screen-space (edge strips).
84
+ *
85
+ * - `screen_obb` — oriented bounding box. `rect` is axis-aligned in
86
+ * a shadow space; `inverse_transform` maps screen → shadow. Lets
87
+ * rotated chrome stay exact without AABB inflation.
88
+ *
89
+ * - `screen_circle_at_doc` — fixed screen-pixel circle, anchored to a
90
+ * doc-space point. Used by vector-handle dots and parametric-handle
91
+ * knobs where a square hit region would feel wrong at the corners.
92
+ *
93
+ * - `screen_polygon` — pre-projected screen-space polygon. Used by
94
+ * curved zones (variable-width controls, lasso previews) where AABB
95
+ * plus a `customHitTest` callback would otherwise leak host code
96
+ * into bedrock.
97
+ */
98
+ type HitShape = {
99
+ readonly kind: "screen_rect_at_doc";
100
+ readonly anchor_doc: cmath.Vector2; /** Screen-space size in CSS px. */
101
+ readonly width: number;
102
+ readonly height: number; /** Which point of the rect sits on the anchor. Default: "center". */
103
+ readonly placement?: "center" | "tl" | "tr" | "bl" | "br";
104
+ } | {
105
+ readonly kind: "screen_aabb";
106
+ readonly rect: cmath.Rectangle;
107
+ } | {
108
+ readonly kind: "screen_obb"; /** Axis-aligned rect in shadow space. */
109
+ readonly rect: cmath.Rectangle; /** screen → shadow. Applied to the pointer before AABB containment. */
110
+ readonly inverse_transform: cmath.Transform;
111
+ } | {
112
+ readonly kind: "screen_circle_at_doc";
113
+ readonly anchor_doc: cmath.Vector2; /** Radius in screen CSS px. */
114
+ readonly radius: number;
115
+ } | {
116
+ readonly kind: "screen_polygon"; /** Pre-projected screen-space polygon vertices. */
117
+ readonly points: ReadonlyArray<readonly [number, number]>;
118
+ };
119
+ /**
120
+ * The visual representation of a `HUDObject`. Maps directly onto the
121
+ * primitive layer's `HUDDraw` entries; the consumer (or the deferred
122
+ * orchestrator) fans these into one merged `HUDDraw` per frame.
123
+ *
124
+ * Closed taxonomy — same set as the legacy `OverlayElement.render`
125
+ * union (`screen_rect`, `doc_rect`, `doc_line`, `doc_polyline`). No
126
+ * new variants in bedrock; new render kinds land here only with ≥2
127
+ * internal consumers shaped (sdk-design promotion bar).
128
+ */
129
+ type RenderShape = {
130
+ readonly kind: "screen_rect";
131
+ readonly anchor_doc: cmath.Vector2;
132
+ readonly width: number;
133
+ readonly height: number;
134
+ readonly placement?: "center" | "tl" | "tr" | "bl" | "br";
135
+ readonly fill?: boolean;
136
+ readonly stroke?: boolean;
137
+ readonly fillColor?: string;
138
+ readonly strokeColor?: string;
139
+ readonly angle?: number;
140
+ readonly shape?: "rect" | "circle";
141
+ } | {
142
+ readonly kind: "doc_rect";
143
+ readonly x: number;
144
+ readonly y: number;
145
+ readonly width: number;
146
+ readonly height: number;
147
+ readonly stroke?: boolean;
148
+ readonly fill?: boolean;
149
+ readonly fillOpacity?: number;
150
+ readonly dashed?: boolean;
151
+ } | {
152
+ readonly kind: "doc_line";
153
+ readonly x1: number;
154
+ readonly y1: number;
155
+ readonly x2: number;
156
+ readonly y2: number;
157
+ readonly dashed?: boolean;
158
+ readonly strokeWidth?: number;
159
+ readonly color?: string;
160
+ } | {
161
+ readonly kind: "doc_polyline";
162
+ readonly points: ReadonlyArray<readonly [number, number]>;
163
+ readonly stroke?: boolean;
164
+ readonly fill?: boolean;
165
+ readonly fillOpacity?: number;
166
+ readonly strokeOpacity?: number;
167
+ readonly strokeWidth?: number;
168
+ readonly dashed?: boolean;
169
+ readonly color?: string;
170
+ readonly fillPaint?: HUDPaint;
171
+ };
172
+ /**
173
+ * Fields common to every `HUDObject` variant.
174
+ */
175
+ interface HUDObjectCommon {
176
+ /** Optional debug label. Stable semantic identifier, e.g.
177
+ * `"resize_handle:nw"`, `"my-class:knob"`. */
178
+ readonly label?: string;
179
+ /** Semantic group, used by the consumer for visibility filtering. */
180
+ readonly group?: HUDSemanticGroup;
181
+ /** Lower wins on overlap. The consumer assigns the integer; bedrock
182
+ * treats it opaquely (sort key only). */
183
+ readonly priority: number;
184
+ }
185
+ /**
186
+ * Paint-only object: visual chrome that is never hit-tested.
187
+ * `render` is required; `hit`, `intent`, `cursor` are forbidden.
188
+ */
189
+ interface HUDObjectPaintOnly extends HUDObjectCommon {
190
+ readonly render: RenderShape;
191
+ readonly hit?: never;
192
+ readonly intent?: never;
193
+ readonly cursor?: never;
194
+ }
195
+ /**
196
+ * Interactive object: hit-testable; may also paint, carry an intent,
197
+ * and a cursor. `hit` is required; the rest are optional.
198
+ *
199
+ * Sub-states (none enforced; documented for readers):
200
+ * - `intent` absent → silent / hover-only.
201
+ * - `intent` present → fully interactive.
202
+ * - `render` absent → silent affordance (invisible hit padding around
203
+ * a pre-painted target).
204
+ */
205
+ interface HUDObjectInteractive<I = unknown> extends HUDObjectCommon {
206
+ readonly hit: HitShape;
207
+ readonly render?: RenderShape;
208
+ readonly intent?: I;
209
+ readonly cursor?: CursorIcon;
210
+ /**
211
+ * Optional refinement applied AFTER `hit` containment passes. Return
212
+ * `false` to reject the hit even though the shape contained the point.
213
+ *
214
+ * The point passed is the same screen-space point handed to
215
+ * `HitRegistry.queryPoint`. Used by curve-shaped affordances (a path
216
+ * segment's hit region is the bezier's bbox; the refinement asks "are
217
+ * you actually near the curve in screen-px?") — the one real case that
218
+ * an AABB/circle/polygon cannot express on its own.
219
+ *
220
+ * This is a deliberate, narrow escape hatch, restored after the
221
+ * vector-path consumer proved an AABB-only hit model drops the
222
+ * curve-near refinement. It is NOT a general "host runs arbitrary code
223
+ * in the hit loop" door: it only *narrows* a shape that already
224
+ * matched; it cannot widen one.
225
+ */
226
+ readonly refine?: (p: cmath.Vector2) => boolean;
227
+ }
228
+ /**
229
+ * The canonical bedrock primitive — the value type a consumer
230
+ * constructs to participate in HUD.
231
+ *
232
+ * Generic over the opaque intent type `I` the consumer supplies; both
233
+ * bedrock and `HitRegistry<I>` propagate `I` unchanged.
234
+ *
235
+ * The discriminated union enforces the (`render` ∨ `hit`) invariant
236
+ * at compile time: an object with neither field is not assignable to
237
+ * either variant.
238
+ */
239
+ type HUDObject<I = unknown> = HUDObjectPaintOnly | HUDObjectInteractive<I>;
240
+ //#endregion
241
+ export { MIN_CHROME_VISIBLE_SIZE as a, CURSOR_ANGLE_BUCKET_RAD as c, ResizeDirection as d, RotationCorner as f, cursorToCss as h, HitShape as i, CursorIcon as l, cursorEquals as m, HUDObjectInteractive as n, MIN_HIT_SIZE as o, angleBucket as p, HUDObjectPaintOnly as r, RenderShape as s, HUDObject as t, CursorRenderer as u };
@@ -0,0 +1,47 @@
1
+ import { a as HUDPaintStripes, c as HUDRect, d as HUDSemantic, f as HUDSemanticGroup, i as HUDPaintSolid, l as HUDRule, n as HUDLine, o as HUDPoint, r as HUDPaint, s as HUDPolyline, t as HUDDraw, u as HUDScreenRect } from "../types-3wwFisZs.mjs";
2
+ import { a as MIN_CHROME_VISIBLE_SIZE, c as CURSOR_ANGLE_BUCKET_RAD, d as ResizeDirection, f as RotationCorner, h as cursorToCss, i as HitShape, l as CursorIcon, m as cursorEquals, n as HUDObjectInteractive, o as MIN_HIT_SIZE, p as angleBucket, r as HUDObjectPaintOnly, s as RenderShape, t as HUDObject, u as CursorRenderer } from "../overlay-dsG32baA.mjs";
3
+ import cmath from "@grida/cmath";
4
+
5
+ //#region primitives/painter.d.ts
6
+ /**
7
+ * Per-frame viewport state handed to `beginFrame`.
8
+ */
9
+ interface PainterViewport {
10
+ /** Width in CSS pixels. */
11
+ readonly w: number;
12
+ /** Height in CSS pixels. */
13
+ readonly h: number;
14
+ /** Device-pixel ratio. */
15
+ readonly dpr: number;
16
+ }
17
+ /**
18
+ * Backend-agnostic chrome painter.
19
+ *
20
+ * Bedrock contract — exactly four methods. Concrete implementations
21
+ * (`primitives/painter-canvas2d.ts` ships canvas2d) may add private
22
+ * helpers, but the public interface is frozen at this shape.
23
+ *
24
+ * Frame lifecycle:
25
+ *
26
+ * 1. `beginFrame(viewport)` — clear or prepare the backing surface.
27
+ * 2. `setTransform(t)` — set the camera (doc → screen affine). May
28
+ * be called multiple times within a frame.
29
+ * 3. `draw(d)` — submit a `HUDDraw` payload. May be called multiple
30
+ * times within a frame; payloads accumulate.
31
+ * 4. `endFrame()` — commit. The backing surface displays the frame.
32
+ *
33
+ * Implementations MAY no-op `endFrame` (canvas2d does); SVG/DOM
34
+ * backends use it to flush DOM mutations in a single batch.
35
+ */
36
+ interface Painter {
37
+ /** Start a new frame. Implementations clear / reset state here. */
38
+ beginFrame(viewport: PainterViewport): void;
39
+ /** Set the camera (doc → screen). */
40
+ setTransform(t: cmath.Transform): void;
41
+ /** Paint a `HUDDraw` payload. Calls accumulate within a frame. */
42
+ draw(d: HUDDraw): void;
43
+ /** Commit the frame. Implementations flush their backing surface. */
44
+ endFrame(): void;
45
+ }
46
+ //#endregion
47
+ export { CURSOR_ANGLE_BUCKET_RAD, type CursorIcon, type CursorRenderer, type HUDDraw, type HUDLine, type HUDObject, type HUDObjectInteractive, type HUDObjectPaintOnly, type HUDPaint, type HUDPaintSolid, type HUDPaintStripes, type HUDPoint, type HUDPolyline, type HUDRect, type HUDRule, type HUDScreenRect, type HUDSemantic, type HUDSemanticGroup, type HitShape, MIN_CHROME_VISIBLE_SIZE, MIN_HIT_SIZE, type Painter, type PainterViewport, type RenderShape, type ResizeDirection, type RotationCorner, angleBucket, cursorEquals, cursorToCss };
@@ -0,0 +1,47 @@
1
+ import { a as HUDPaintStripes, c as HUDRect, d as HUDSemantic, f as HUDSemanticGroup, i as HUDPaintSolid, l as HUDRule, n as HUDLine, o as HUDPoint, r as HUDPaint, s as HUDPolyline, t as HUDDraw, u as HUDScreenRect } from "../types-3wwFisZs.js";
2
+ import { a as MIN_CHROME_VISIBLE_SIZE, c as CURSOR_ANGLE_BUCKET_RAD, d as ResizeDirection, f as RotationCorner, h as cursorToCss, i as HitShape, l as CursorIcon, m as cursorEquals, n as HUDObjectInteractive, o as MIN_HIT_SIZE, p as angleBucket, r as HUDObjectPaintOnly, s as RenderShape, t as HUDObject, u as CursorRenderer } from "../overlay-CVV4s3IL.js";
3
+ import cmath from "@grida/cmath";
4
+
5
+ //#region primitives/painter.d.ts
6
+ /**
7
+ * Per-frame viewport state handed to `beginFrame`.
8
+ */
9
+ interface PainterViewport {
10
+ /** Width in CSS pixels. */
11
+ readonly w: number;
12
+ /** Height in CSS pixels. */
13
+ readonly h: number;
14
+ /** Device-pixel ratio. */
15
+ readonly dpr: number;
16
+ }
17
+ /**
18
+ * Backend-agnostic chrome painter.
19
+ *
20
+ * Bedrock contract — exactly four methods. Concrete implementations
21
+ * (`primitives/painter-canvas2d.ts` ships canvas2d) may add private
22
+ * helpers, but the public interface is frozen at this shape.
23
+ *
24
+ * Frame lifecycle:
25
+ *
26
+ * 1. `beginFrame(viewport)` — clear or prepare the backing surface.
27
+ * 2. `setTransform(t)` — set the camera (doc → screen affine). May
28
+ * be called multiple times within a frame.
29
+ * 3. `draw(d)` — submit a `HUDDraw` payload. May be called multiple
30
+ * times within a frame; payloads accumulate.
31
+ * 4. `endFrame()` — commit. The backing surface displays the frame.
32
+ *
33
+ * Implementations MAY no-op `endFrame` (canvas2d does); SVG/DOM
34
+ * backends use it to flush DOM mutations in a single batch.
35
+ */
36
+ interface Painter {
37
+ /** Start a new frame. Implementations clear / reset state here. */
38
+ beginFrame(viewport: PainterViewport): void;
39
+ /** Set the camera (doc → screen). */
40
+ setTransform(t: cmath.Transform): void;
41
+ /** Paint a `HUDDraw` payload. Calls accumulate within a frame. */
42
+ draw(d: HUDDraw): void;
43
+ /** Commit the frame. Implementations flush their backing surface. */
44
+ endFrame(): void;
45
+ }
46
+ //#endregion
47
+ export { CURSOR_ANGLE_BUCKET_RAD, type CursorIcon, type CursorRenderer, type HUDDraw, type HUDLine, type HUDObject, type HUDObjectInteractive, type HUDObjectPaintOnly, type HUDPaint, type HUDPaintSolid, type HUDPaintStripes, type HUDPoint, type HUDPolyline, type HUDRect, type HUDRule, type HUDScreenRect, type HUDSemantic, type HUDSemanticGroup, type HitShape, MIN_CHROME_VISIBLE_SIZE, MIN_HIT_SIZE, type Painter, type PainterViewport, type RenderShape, type ResizeDirection, type RotationCorner, angleBucket, cursorEquals, cursorToCss };
@@ -0,0 +1,71 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region primitives/overlay.ts
3
+ /**
4
+ * Minimum hit-target size in screen-px.
5
+ *
6
+ * Visual knobs are typically 8px; the hit region is 16px so the user
7
+ * does not need pixel-perfect aim (Fitts'). Bedrock constant — value
8
+ * mirrors the legacy `event/overlay.ts` constant during the additive
9
+ * migration.
10
+ */
11
+ const MIN_HIT_SIZE = 16;
12
+ /**
13
+ * Below this selection size (in screen-px on either axis), chrome is
14
+ * suppressed — both the visual handles AND the hit regions. The
15
+ * consumer enforces this when computing per-frame `HUDObject`s.
16
+ */
17
+ const MIN_CHROME_VISIBLE_SIZE = 12;
18
+ //#endregion
19
+ //#region primitives/cursor.ts
20
+ /**
21
+ * Angle quantization bucket — 0.5° in radians. Two rotated cursors
22
+ * compare equal when their `baseAngle`s round to the same bucket.
23
+ *
24
+ * 0.5° is below human perception for cursor orientation, so the
25
+ * quantization is visually free.
26
+ */
27
+ const CURSOR_ANGLE_BUCKET_RAD = Math.PI / 360;
28
+ /** Quantize an angle (radians) to its `CURSOR_ANGLE_BUCKET_RAD` bucket. */
29
+ function angleBucket(rad) {
30
+ if (rad === void 0 || rad === 0) return 0;
31
+ return Math.round(rad / CURSOR_ANGLE_BUCKET_RAD);
32
+ }
33
+ /**
34
+ * Default mapping from `CursorIcon` to CSS `cursor` value.
35
+ */
36
+ function cursorToCss(c) {
37
+ if (typeof c === "string") switch (c) {
38
+ case "default": return "default";
39
+ case "pointer": return "pointer";
40
+ case "move": return "move";
41
+ case "crosshair": return "crosshair";
42
+ case "grab": return "grab";
43
+ case "grabbing": return "grabbing";
44
+ case "text": return "text";
45
+ }
46
+ if (c.kind === "resize") return `${c.direction}-resize`;
47
+ return "crosshair";
48
+ }
49
+ /**
50
+ * Cursor equality with `baseAngle` bucketing.
51
+ *
52
+ * Lets a hot path (a rotate-in-progress gesture's per-frame setCursor)
53
+ * emit `cursorChanged` only on visible motion (≥ one bucket of
54
+ * rotation).
55
+ */
56
+ function cursorEquals(a, b) {
57
+ if (typeof a === "string" && typeof b === "string") return a === b;
58
+ if (typeof a !== "string" && typeof b !== "string") {
59
+ if (a.kind === "resize" && b.kind === "resize") return a.direction === b.direction && angleBucket(a.baseAngle) === angleBucket(b.baseAngle);
60
+ if (a.kind === "rotate" && b.kind === "rotate") return a.corner === b.corner && angleBucket(a.baseAngle) === angleBucket(b.baseAngle);
61
+ return false;
62
+ }
63
+ return false;
64
+ }
65
+ //#endregion
66
+ exports.CURSOR_ANGLE_BUCKET_RAD = CURSOR_ANGLE_BUCKET_RAD;
67
+ exports.MIN_CHROME_VISIBLE_SIZE = MIN_CHROME_VISIBLE_SIZE;
68
+ exports.MIN_HIT_SIZE = MIN_HIT_SIZE;
69
+ exports.angleBucket = angleBucket;
70
+ exports.cursorEquals = cursorEquals;
71
+ exports.cursorToCss = cursorToCss;
@@ -0,0 +1,65 @@
1
+ //#region primitives/overlay.ts
2
+ /**
3
+ * Minimum hit-target size in screen-px.
4
+ *
5
+ * Visual knobs are typically 8px; the hit region is 16px so the user
6
+ * does not need pixel-perfect aim (Fitts'). Bedrock constant — value
7
+ * mirrors the legacy `event/overlay.ts` constant during the additive
8
+ * migration.
9
+ */
10
+ const MIN_HIT_SIZE = 16;
11
+ /**
12
+ * Below this selection size (in screen-px on either axis), chrome is
13
+ * suppressed — both the visual handles AND the hit regions. The
14
+ * consumer enforces this when computing per-frame `HUDObject`s.
15
+ */
16
+ const MIN_CHROME_VISIBLE_SIZE = 12;
17
+ //#endregion
18
+ //#region primitives/cursor.ts
19
+ /**
20
+ * Angle quantization bucket — 0.5° in radians. Two rotated cursors
21
+ * compare equal when their `baseAngle`s round to the same bucket.
22
+ *
23
+ * 0.5° is below human perception for cursor orientation, so the
24
+ * quantization is visually free.
25
+ */
26
+ const CURSOR_ANGLE_BUCKET_RAD = Math.PI / 360;
27
+ /** Quantize an angle (radians) to its `CURSOR_ANGLE_BUCKET_RAD` bucket. */
28
+ function angleBucket(rad) {
29
+ if (rad === void 0 || rad === 0) return 0;
30
+ return Math.round(rad / CURSOR_ANGLE_BUCKET_RAD);
31
+ }
32
+ /**
33
+ * Default mapping from `CursorIcon` to CSS `cursor` value.
34
+ */
35
+ function cursorToCss(c) {
36
+ if (typeof c === "string") switch (c) {
37
+ case "default": return "default";
38
+ case "pointer": return "pointer";
39
+ case "move": return "move";
40
+ case "crosshair": return "crosshair";
41
+ case "grab": return "grab";
42
+ case "grabbing": return "grabbing";
43
+ case "text": return "text";
44
+ }
45
+ if (c.kind === "resize") return `${c.direction}-resize`;
46
+ return "crosshair";
47
+ }
48
+ /**
49
+ * Cursor equality with `baseAngle` bucketing.
50
+ *
51
+ * Lets a hot path (a rotate-in-progress gesture's per-frame setCursor)
52
+ * emit `cursorChanged` only on visible motion (≥ one bucket of
53
+ * rotation).
54
+ */
55
+ function cursorEquals(a, b) {
56
+ if (typeof a === "string" && typeof b === "string") return a === b;
57
+ if (typeof a !== "string" && typeof b !== "string") {
58
+ if (a.kind === "resize" && b.kind === "resize") return a.direction === b.direction && angleBucket(a.baseAngle) === angleBucket(b.baseAngle);
59
+ if (a.kind === "rotate" && b.kind === "rotate") return a.corner === b.corner && angleBucket(a.baseAngle) === angleBucket(b.baseAngle);
60
+ return false;
61
+ }
62
+ return false;
63
+ }
64
+ //#endregion
65
+ export { CURSOR_ANGLE_BUCKET_RAD, MIN_CHROME_VISIBLE_SIZE, MIN_HIT_SIZE, angleBucket, cursorEquals, cursorToCss };
package/dist/react.d.mts CHANGED
@@ -1,6 +1,7 @@
1
- import { O as HUDDraw, o as Surface, s as SurfaceOptions } from "./index-CBqCh-ZM.mjs";
2
- import { Measurement } from "@grida/cmath/_measurement";
1
+ import { t as HUDDraw } from "./types-3wwFisZs.mjs";
2
+ import { n as SurfaceOptions, t as Surface } from "./index-Cmbe2X5b.mjs";
3
3
  import cmath from "@grida/cmath";
4
+ import { Measurement } from "@grida/cmath/_measurement";
4
5
  import * as React from "react";
5
6
  import { SnapResult } from "@grida/cmath/_snap";
6
7
 
package/dist/react.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { O as HUDDraw, o as Surface, s as SurfaceOptions } from "./index-DRBeSiI2.js";
1
+ import { t as HUDDraw } from "./types-3wwFisZs.js";
2
+ import { n as SurfaceOptions, t as Surface } from "./index-BrfEdWbQ.js";
2
3
  import cmath from "@grida/cmath";
3
4
  import { SnapResult } from "@grida/cmath/_snap";
4
5
  import { Measurement } from "@grida/cmath/_measurement";
package/dist/react.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_surface = require("./surface-CNlBaEXn.js");
3
+ const require_surface = require("./surface-BHQVvRFC.js");
4
4
  let react = require("react");
5
5
  react = require_surface.__toESM(react);
6
6
  let _grida_cmath__snap = require("@grida/cmath/_snap");
@@ -33,7 +33,10 @@ function useHUDSurface(canvasRef, options) {
33
33
  onIntent: (i) => onIntentRef.current(i),
34
34
  style: options.style,
35
35
  readonly: options.readonly,
36
- color: options.color
36
+ color: options.color,
37
+ pixelGrid: options.pixelGrid,
38
+ groups: options.groups,
39
+ visibility: options.visibility
37
40
  });
38
41
  setSurface(s);
39
42
  return () => {
@@ -45,10 +48,12 @@ function useHUDSurface(canvasRef, options) {
45
48
  if (!surface) return;
46
49
  if (options.style) surface.setStyle(options.style);
47
50
  if (options.readonly !== void 0) surface.setReadonly(options.readonly);
51
+ surface.setColor(options.color ?? null);
48
52
  }, [
49
53
  surface,
50
54
  options.style,
51
- options.readonly
55
+ options.readonly,
56
+ options.color
52
57
  ]);
53
58
  return surface;
54
59
  }
package/dist/react.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { a as lassoToHUDDraw, c as snapGuideToHUDDraw, l as HUDCanvas, o as marqueeToHUDDraw, s as measurementToHUDDraw, t as Surface } from "./surface-hUEeEVdL.mjs";
2
+ import { D as marqueeToHUDDraw, E as lassoToHUDDraw, O as measurementToHUDDraw, j as HUDCanvas, k as snapGuideToHUDDraw, t as Surface } from "./surface-NHSzUR8r.mjs";
3
3
  import * as React from "react";
4
4
  import { guide } from "@grida/cmath/_snap";
5
5
  import { jsx } from "react/jsx-runtime";
@@ -31,7 +31,10 @@ function useHUDSurface(canvasRef, options) {
31
31
  onIntent: (i) => onIntentRef.current(i),
32
32
  style: options.style,
33
33
  readonly: options.readonly,
34
- color: options.color
34
+ color: options.color,
35
+ pixelGrid: options.pixelGrid,
36
+ groups: options.groups,
37
+ visibility: options.visibility
35
38
  });
36
39
  setSurface(s);
37
40
  return () => {
@@ -43,10 +46,12 @@ function useHUDSurface(canvasRef, options) {
43
46
  if (!surface) return;
44
47
  if (options.style) surface.setStyle(options.style);
45
48
  if (options.readonly !== void 0) surface.setReadonly(options.readonly);
49
+ surface.setColor(options.color ?? null);
46
50
  }, [
47
51
  surface,
48
52
  options.style,
49
- options.readonly
53
+ options.readonly,
54
+ options.color
50
55
  ]);
51
56
  return surface;
52
57
  }