@flighthq/interaction 0.2.0 → 0.2.1-next.410.a23f189

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.
Files changed (74) hide show
  1. package/dist/cursorBackend.d.ts +12 -0
  2. package/dist/cursorBackend.d.ts.map +1 -0
  3. package/dist/cursorBackend.js +17 -0
  4. package/dist/cursorBackend.js.map +1 -0
  5. package/dist/displayHitTests.d.ts +10 -11
  6. package/dist/displayHitTests.d.ts.map +1 -1
  7. package/dist/displayHitTests.js +12 -14
  8. package/dist/displayHitTests.js.map +1 -1
  9. package/dist/enableInteractionGuards.d.ts +23 -0
  10. package/dist/enableInteractionGuards.d.ts.map +1 -0
  11. package/dist/enableInteractionGuards.js +75 -0
  12. package/dist/enableInteractionGuards.js.map +1 -0
  13. package/dist/focusManager.d.ts +46 -0
  14. package/dist/focusManager.d.ts.map +1 -0
  15. package/dist/focusManager.js +243 -0
  16. package/dist/focusManager.js.map +1 -0
  17. package/dist/hitTests.d.ts +45 -24
  18. package/dist/hitTests.d.ts.map +1 -1
  19. package/dist/hitTests.js +164 -47
  20. package/dist/hitTests.js.map +1 -1
  21. package/dist/index.d.ts +9 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +9 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/interactionManager.d.ts +10 -2
  26. package/dist/interactionManager.d.ts.map +1 -1
  27. package/dist/interactionManager.js +58 -6
  28. package/dist/interactionManager.js.map +1 -1
  29. package/dist/interactionSpatialIndex.d.ts +17 -0
  30. package/dist/interactionSpatialIndex.d.ts.map +1 -0
  31. package/dist/interactionSpatialIndex.js +77 -0
  32. package/dist/interactionSpatialIndex.js.map +1 -0
  33. package/dist/nodeInteractionState.d.ts +39 -0
  34. package/dist/nodeInteractionState.d.ts.map +1 -0
  35. package/dist/nodeInteractionState.js +72 -0
  36. package/dist/nodeInteractionState.js.map +1 -0
  37. package/dist/registerBitmapHitTest.d.ts +11 -0
  38. package/dist/registerBitmapHitTest.d.ts.map +1 -0
  39. package/dist/registerBitmapHitTest.js +55 -0
  40. package/dist/registerBitmapHitTest.js.map +1 -0
  41. package/dist/registerDefaultHitTests.d.ts +2 -0
  42. package/dist/registerDefaultHitTests.d.ts.map +1 -0
  43. package/dist/registerDefaultHitTests.js +20 -0
  44. package/dist/registerDefaultHitTests.js.map +1 -0
  45. package/dist/registerShapeHitTest.d.ts +10 -0
  46. package/dist/registerShapeHitTest.d.ts.map +1 -0
  47. package/dist/registerShapeHitTest.js +32 -0
  48. package/dist/registerShapeHitTest.js.map +1 -0
  49. package/dist/registerTextHitTest.d.ts +12 -0
  50. package/dist/registerTextHitTest.d.ts.map +1 -0
  51. package/dist/registerTextHitTest.js +32 -0
  52. package/dist/registerTextHitTest.js.map +1 -0
  53. package/dist/spriteHitTests.d.ts +3 -3
  54. package/dist/spriteHitTests.d.ts.map +1 -1
  55. package/dist/spriteHitTests.js +5 -5
  56. package/dist/spriteHitTests.js.map +1 -1
  57. package/package.json +13 -7
  58. package/src/cursorBackend.test.ts +24 -0
  59. package/src/displayHitTests.test.ts +39 -47
  60. package/src/enableInteractionGuards.test.ts +102 -0
  61. package/src/focusManager.test.ts +307 -0
  62. package/src/hitTests.test.ts +235 -98
  63. package/src/interactionManager.test.ts +59 -8
  64. package/src/interactionSpatialIndex.test.ts +103 -0
  65. package/src/nodeInteractionState.test.ts +141 -0
  66. package/src/registerBitmapHitTest.test.ts +22 -0
  67. package/src/{registerDefaultHitTestPoints.test.ts → registerDefaultHitTests.test.ts} +10 -7
  68. package/src/registerShapeHitTest.test.ts +27 -0
  69. package/src/registerTextHitTest.test.ts +54 -0
  70. package/src/spriteHitTests.test.ts +15 -15
  71. package/dist/registerDefaultHitTestPoints.d.ts +0 -2
  72. package/dist/registerDefaultHitTestPoints.d.ts.map +0 -1
  73. package/dist/registerDefaultHitTestPoints.js +0 -21
  74. package/dist/registerDefaultHitTestPoints.js.map +0 -1
@@ -1,10 +1,30 @@
1
- import type { DisplayObject, HitTestFunction, Kind, Node } from '@flighthq/types';
1
+ import type { DisplayObject, HitTestFunction, HitTestPreciseFunction, HitTestResult, Kind, Node, NodeAny } from '@flighthq/types';
2
2
  /**
3
- * Walks the scene graph depth-first in reverse child order (front-to-back) and
4
- * returns the first node that registers a hit at the given world-space
5
- * coordinates, or null if nothing was hit.
3
+ * Fills `out` with the sub-index and local coordinates of a hit at world-space (x, y) on a node you
4
+ * already have (usually the result of a `*Precise` query, or a dispatch target). `out.subIndex` is the
5
+ * sub-element under the point (text char, tile, quad) from the node kind's registered exact provider, or
6
+ * -1 when the kind has no provider. This is the "resolve detail on a known node" call — it does no walk.
6
7
  **/
7
- export declare function findGraphHitTarget<Traits extends object>(source: Node<Traits>, x: number, y: number, shapeFlag?: boolean): Node<Traits> | null;
8
+ export declare function describeGraphHit(node: NodeAny, x: number, y: number, out: HitTestResult): void;
9
+ /**
10
+ * Coarse pick: front-to-back (reverse child order), the first node whose bounding geometry contains
11
+ * world-space (x, y), or null. Eligibility is opt-in (`hitTestEnabled`, default off); a node with a
12
+ * `hitArea` is an atomic unit that consumes the hit and hides its children. Cheap — the bbox path.
13
+ **/
14
+ export declare function findGraphHitTarget<Traits extends object>(source: Node<Traits>, x: number, y: number): Node<Traits> | null;
15
+ /**
16
+ * Precise pick: like `findGraphHitTarget`, but each node is tested by its registered exact geometry
17
+ * (fill/alpha/glyph), **falling back to bounds per kind** where no exact provider is registered — so
18
+ * the answer is the most precise available. Pays for the exact math; use on click/select, not per move.
19
+ **/
20
+ export declare function findGraphHitTargetPrecise<Traits extends object>(source: Node<Traits>, x: number, y: number): Node<Traits> | null;
21
+ /**
22
+ * Coarse stack: every node whose bounding geometry contains (x, y), front-to-back into `out` (cleared
23
+ * first). The "what is under this point" query — overlapping targets, multi-pick.
24
+ **/
25
+ export declare function findGraphHitTargets<Traits extends object>(source: Node<Traits>, x: number, y: number, out?: Node<Traits>[]): Node<Traits>[];
26
+ /** Precise stack: `findGraphHitTargets` using exact geometry per kind (bounds fallback where none). */
27
+ export declare function findGraphHitTargetsPrecise<Traits extends object>(source: Node<Traits>, x: number, y: number, out?: Node<Traits>[]): Node<Traits>[];
8
28
  /**
9
29
  * Evaluates the world bounding box of one node to see if it overlaps or
10
30
  * intersects the world bounding box of another.
@@ -15,24 +35,25 @@ export declare function hitTestDisplayObjects(source: DisplayObject, other: Disp
15
35
  * after inverting through the node's world transform.
16
36
  **/
17
37
  export declare function hitTestGraphLocalBounds<Traits extends object>(source: Node<Traits>, x: number, y: number): boolean;
38
+ /** Coarse any-hit query: whether the node or any descendant is hit at (x, y). Traversal order is irrelevant to the boolean. */
39
+ export declare function hitTestGraphPoint<Traits extends object>(source: Node<Traits>, x: number, y: number): boolean;
40
+ /** Precise any-hit query: `hitTestGraphPoint` using exact geometry per kind (bounds fallback where none). */
41
+ export declare function hitTestGraphPointPrecise<Traits extends object>(source: Node<Traits>, x: number, y: number): boolean;
18
42
  /**
19
- * Evaluates the node to see if it or any of its descendants register a hit at
20
- * the given world-space coordinates.
21
- *
22
- * Traverses self first, then children in natural (back-to-front) order — the opposite of
23
- * `findGraphHitTarget` which tests children in reverse order (front-to-back) to find the
24
- * deepest topmost hit. This function answers "does anything hit?" rather than "which specific
25
- * node is hit?", so traversal order does not affect the boolean result.
26
- *
27
- * Hit behavior for a given node kind must be registered via `registerHitTest`.
28
- * Unregistered kinds are skipped for self-hit but children are still tested.
29
- *
30
- * @param shapeFlag Passed to the registered hit function; interpretation is kind-specific.
31
- **/
32
- export declare function hitTestGraphPoint<Traits extends object>(source: Node<Traits>, x: number, y: number, shapeFlag?: boolean): boolean;
33
- /**
34
- * Registers an interaction handler for nodes of the given kind.
35
- * Call this once at startup to opt a node kind into interaction handling.
36
- **/
37
- export declare function registerHitTestPoint(kind: Kind, fn: HitTestFunction): void;
43
+ * Tests one node's own hit region at world-space (x, y): its `hitArea` if set, else its kind geometry
44
+ * (coarse bounds, or the exact provider when `precise`). No eligibility check and no recursion — for
45
+ * callers (e.g. the broadphase) that already hold an eligible, atomic candidate.
46
+ **/
47
+ export declare function hitTestNodeRegion(source: NodeAny, x: number, y: number, precise?: boolean): boolean;
48
+ /**
49
+ * Registers a node kind's coarse (bounding) hit function the bbox path used by the non-`Precise`
50
+ * queries. Open registry: register only the kinds you need, or `registerDefaultHitTests()` for the bank.
51
+ **/
52
+ export declare function registerHitTest(kind: Kind, fn: HitTestFunction): void;
53
+ /**
54
+ * Registers a node kind's exact (precise) hit provider used by the `*Precise` queries and by
55
+ * `describeGraphHit`. The provider returns -1 (miss), 0 (hit, no sub-element), or a sub-index (>0).
56
+ * Opt-in per kind so the exact geometry and its dependencies tree-shake unless registered.
57
+ **/
58
+ export declare function registerHitTestPrecise(kind: Kind, fn: HitTestPreciseFunction): void;
38
59
  //# sourceMappingURL=hitTests.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hitTests.d.ts","sourceRoot":"","sources":["../src/hitTests.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,IAAI,EAAE,IAAI,EAAW,MAAM,iBAAiB,CAAC;AAE3F;;;;IAII;AACJ,wBAAgB,kBAAkB,CAAC,MAAM,SAAS,MAAM,EACtD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EACpB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,SAAS,GAAE,OAAe,GACzB,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAerB;AAED;;;IAGI;AACJ,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAK1F;AAED;;;IAGI;AACJ,wBAAgB,uBAAuB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAYlH;AAED;;;;;;;;;;;;;IAaI;AACJ,wBAAgB,iBAAiB,CAAC,MAAM,SAAS,MAAM,EACrD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EACpB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,SAAS,GAAE,OAAe,GACzB,OAAO,CAcT;AAED;;;IAGI;AACJ,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,eAAe,GAAG,IAAI,CAE1E"}
1
+ {"version":3,"file":"hitTests.d.ts","sourceRoot":"","sources":["../src/hitTests.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,aAAa,EAEb,eAAe,EACf,sBAAsB,EACtB,aAAa,EACb,IAAI,EACJ,IAAI,EACJ,OAAO,EAGR,MAAM,iBAAiB,CAAC;AAIzB;;;;;IAKI;AACJ,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAO9F;AAED;;;;IAII;AACJ,wBAAgB,kBAAkB,CAAC,MAAM,SAAS,MAAM,EACtD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EACpB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAErB;AAED;;;;IAII;AACJ,wBAAgB,yBAAyB,CAAC,MAAM,SAAS,MAAM,EAC7D,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EACpB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAErB;AAED;;;IAGI;AACJ,wBAAgB,mBAAmB,CAAC,MAAM,SAAS,MAAM,EACvD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EACpB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,GAAG,GAAE,IAAI,CAAC,MAAM,CAAC,EAAO,GACvB,IAAI,CAAC,MAAM,CAAC,EAAE,CAIhB;AAED,uGAAuG;AACvG,wBAAgB,0BAA0B,CAAC,MAAM,SAAS,MAAM,EAC9D,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EACpB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,GAAG,GAAE,IAAI,CAAC,MAAM,CAAC,EAAO,GACvB,IAAI,CAAC,MAAM,CAAC,EAAE,CAIhB;AAED;;;IAGI;AACJ,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAK1F;AAED;;;IAGI;AACJ,wBAAgB,uBAAuB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAOlH;AAED,+HAA+H;AAC/H,wBAAgB,iBAAiB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAE5G;AAED,6GAA6G;AAC7G,wBAAgB,wBAAwB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEnH;AAED;;;;IAII;AACJ,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,OAAe,GAAG,OAAO,CAI1G;AAED;;;IAGI;AACJ,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,eAAe,GAAG,IAAI,CAErE;AAED;;;;IAII;AACJ,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,sBAAsB,GAAG,IAAI,CAEnF"}
package/dist/hitTests.js CHANGED
@@ -1,25 +1,51 @@
1
1
  import { containsRectanglePointXY, intersectsRectangle, inverseMatrixTransformPointXY } from '@flighthq/geometry';
2
- import { getNodeLocalBoundsRectangle, getNodeParent, getNodeRuntime, getNodeWorldBoundsRectangle, getNodeWorldTransformMatrix, } from '@flighthq/node';
2
+ import { getNodeLocalBoundsRectangle, getNodeParent, getNodeRuntime, getNodeWorldBoundsRectangle, getNodeWorldMatrix, } from '@flighthq/node';
3
+ import { containsPathPoint } from '@flighthq/path';
4
+ import { getNodeInteractionState } from './nodeInteractionState';
3
5
  /**
4
- * Walks the scene graph depth-first in reverse child order (front-to-back) and
5
- * returns the first node that registers a hit at the given world-space
6
- * coordinates, or null if nothing was hit.
6
+ * Fills `out` with the sub-index and local coordinates of a hit at world-space (x, y) on a node you
7
+ * already have (usually the result of a `*Precise` query, or a dispatch target). `out.subIndex` is the
8
+ * sub-element under the point (text char, tile, quad) from the node kind's registered exact provider, or
9
+ * -1 when the kind has no provider. This is the "resolve detail on a known node" call — it does no walk.
7
10
  **/
8
- export function findGraphHitTarget(source, x, y, shapeFlag = false) {
9
- if (!source.enabled)
10
- return null;
11
- const children = getNodeRuntime(source).children;
12
- if (children !== null) {
13
- for (let i = children.length - 1; i >= 0; i--) {
14
- const hit = findGraphHitTarget(children[i], x, y, shapeFlag);
15
- if (hit !== null)
16
- return hit;
17
- }
18
- }
19
- const hitTestSelf = hitTestPointRegistry.get(source.kind);
20
- if (hitTestSelf?.(source, x, y, shapeFlag))
21
- return source;
22
- return null;
11
+ export function describeGraphHit(node, x, y, out) {
12
+ out.node = node;
13
+ inverseMatrixTransformPointXY(hitTestScratchPoint, getNodeWorldMatrix(node), x, y);
14
+ out.localX = hitTestScratchPoint.x;
15
+ out.localY = hitTestScratchPoint.y;
16
+ const exact = hitTestExactRegistry.get(node.kind);
17
+ out.subIndex = exact ? exact(node, x, y) : -1;
18
+ }
19
+ /**
20
+ * Coarse pick: front-to-back (reverse child order), the first node whose bounding geometry contains
21
+ * world-space (x, y), or null. Eligibility is opt-in (`hitTestEnabled`, default off); a node with a
22
+ * `hitArea` is an atomic unit that consumes the hit and hides its children. Cheap — the bbox path.
23
+ **/
24
+ export function findGraphHitTarget(source, x, y) {
25
+ return findFirstHit(source, x, y, false);
26
+ }
27
+ /**
28
+ * Precise pick: like `findGraphHitTarget`, but each node is tested by its registered exact geometry
29
+ * (fill/alpha/glyph), **falling back to bounds per kind** where no exact provider is registered — so
30
+ * the answer is the most precise available. Pays for the exact math; use on click/select, not per move.
31
+ **/
32
+ export function findGraphHitTargetPrecise(source, x, y) {
33
+ return findFirstHit(source, x, y, true);
34
+ }
35
+ /**
36
+ * Coarse stack: every node whose bounding geometry contains (x, y), front-to-back into `out` (cleared
37
+ * first). The "what is under this point" query — overlapping targets, multi-pick.
38
+ **/
39
+ export function findGraphHitTargets(source, x, y, out = []) {
40
+ out.length = 0;
41
+ collectHits(source, x, y, false, out);
42
+ return out;
43
+ }
44
+ /** Precise stack: `findGraphHitTargets` using exact geometry per kind (bounds fallback where none). */
45
+ export function findGraphHitTargetsPrecise(source, x, y, out = []) {
46
+ out.length = 0;
47
+ collectHits(source, x, y, true, out);
48
+ return out;
23
49
  }
24
50
  /**
25
51
  * Evaluates the world bounding box of one node to see if it overlaps or
@@ -36,45 +62,136 @@ export function hitTestDisplayObjects(source, other) {
36
62
  * after inverting through the node's world transform.
37
63
  **/
38
64
  export function hitTestGraphLocalBounds(source, x, y) {
39
- inverseMatrixTransformPointXY(hitTestLocalBoundsRectanglePoint, getNodeWorldTransformMatrix(source), x, y);
40
- return containsRectanglePointXY(getNodeLocalBoundsRectangle(source), hitTestLocalBoundsRectanglePoint.x, hitTestLocalBoundsRectanglePoint.y);
65
+ inverseMatrixTransformPointXY(hitTestScratchPoint, getNodeWorldMatrix(source), x, y);
66
+ return containsRectanglePointXY(getNodeLocalBoundsRectangle(source), hitTestScratchPoint.x, hitTestScratchPoint.y);
67
+ }
68
+ /** Coarse any-hit query: whether the node or any descendant is hit at (x, y). Traversal order is irrelevant to the boolean. */
69
+ export function hitTestGraphPoint(source, x, y) {
70
+ return anyHit(source, x, y, false);
71
+ }
72
+ /** Precise any-hit query: `hitTestGraphPoint` using exact geometry per kind (bounds fallback where none). */
73
+ export function hitTestGraphPointPrecise(source, x, y) {
74
+ return anyHit(source, x, y, true);
75
+ }
76
+ /**
77
+ * Tests one node's own hit region at world-space (x, y): its `hitArea` if set, else its kind geometry
78
+ * (coarse bounds, or the exact provider when `precise`). No eligibility check and no recursion — for
79
+ * callers (e.g. the broadphase) that already hold an eligible, atomic candidate.
80
+ **/
81
+ export function hitTestNodeRegion(source, x, y, precise = false) {
82
+ const hitArea = getNodeInteractionState(source)?.hitArea ?? null;
83
+ if (hitArea !== null)
84
+ return hitAreaContainsPoint(source, hitArea, x, y);
85
+ return testNodeGeometry(source, x, y, precise);
41
86
  }
42
87
  /**
43
- * Evaluates the node to see if it or any of its descendants register a hit at
44
- * the given world-space coordinates.
45
- *
46
- * Traverses self first, then children in natural (back-to-front) order — the opposite of
47
- * `findGraphHitTarget` which tests children in reverse order (front-to-back) to find the
48
- * deepest topmost hit. This function answers "does anything hit?" rather than "which specific
49
- * node is hit?", so traversal order does not affect the boolean result.
50
- *
51
- * Hit behavior for a given node kind must be registered via `registerHitTest`.
52
- * Unregistered kinds are skipped for self-hit but children are still tested.
53
- *
54
- * @param shapeFlag Passed to the registered hit function; interpretation is kind-specific.
88
+ * Registers a node kind's coarse (bounding) hit function the bbox path used by the non-`Precise`
89
+ * queries. Open registry: register only the kinds you need, or `registerDefaultHitTests()` for the bank.
55
90
  **/
56
- export function hitTestGraphPoint(source, x, y, shapeFlag = false) {
57
- if (!source.enabled)
91
+ export function registerHitTest(kind, fn) {
92
+ hitTestRegistry.set(kind, fn);
93
+ }
94
+ /**
95
+ * Registers a node kind's exact (precise) hit provider — used by the `*Precise` queries and by
96
+ * `describeGraphHit`. The provider returns -1 (miss), 0 (hit, no sub-element), or a sub-index (>0).
97
+ * Opt-in per kind so the exact geometry and its dependencies tree-shake unless registered.
98
+ **/
99
+ export function registerHitTestPrecise(kind, fn) {
100
+ hitTestExactRegistry.set(kind, fn);
101
+ }
102
+ // Front-to-back DFS for the first hit; shared by findGraphHitTarget(Precise).
103
+ function findFirstHit(node, x, y, precise) {
104
+ if (!node.enabled)
105
+ return null;
106
+ const state = getNodeInteractionState(node);
107
+ const enabled = state?.hitTestEnabled === true;
108
+ const hitArea = state?.hitArea ?? null;
109
+ if (enabled && hitArea !== null) {
110
+ return hitAreaContainsPoint(node, hitArea, x, y) ? node : null;
111
+ }
112
+ const children = getNodeRuntime(node).children;
113
+ if (children !== null) {
114
+ for (let i = children.length - 1; i >= 0; i--) {
115
+ const hit = findFirstHit(children[i], x, y, precise);
116
+ if (hit !== null)
117
+ return hit;
118
+ }
119
+ }
120
+ if (enabled && testNodeGeometry(node, x, y, precise))
121
+ return node;
122
+ return null;
123
+ }
124
+ // DFS any-hit; order-independent boolean.
125
+ function anyHit(node, x, y, precise) {
126
+ if (!node.enabled)
58
127
  return false;
59
- const hitTestSelf = hitTestPointRegistry.get(source.kind);
60
- if (hitTestSelf?.(source, x, y, shapeFlag))
128
+ const state = getNodeInteractionState(node);
129
+ const enabled = state?.hitTestEnabled === true;
130
+ const hitArea = state?.hitArea ?? null;
131
+ if (enabled && hitArea !== null)
132
+ return hitAreaContainsPoint(node, hitArea, x, y);
133
+ if (enabled && testNodeGeometry(node, x, y, precise))
61
134
  return true;
62
- const children = getNodeRuntime(source).children;
135
+ const children = getNodeRuntime(node).children;
63
136
  if (children !== null) {
64
137
  for (const child of children) {
65
- if (hitTestGraphPoint(child, x, y, shapeFlag))
138
+ if (anyHit(child, x, y, precise))
66
139
  return true;
67
140
  }
68
141
  }
69
142
  return false;
70
143
  }
71
- /**
72
- * Registers an interaction handler for nodes of the given kind.
73
- * Call this once at startup to opt a node kind into interaction handling.
74
- **/
75
- export function registerHitTestPoint(kind, fn) {
76
- hitTestPointRegistry.set(kind, fn);
144
+ // Front-to-back DFS collecting every hit; shared by findGraphHitTargets(Precise).
145
+ function collectHits(node, x, y, precise, out) {
146
+ if (!node.enabled)
147
+ return;
148
+ const state = getNodeInteractionState(node);
149
+ const enabled = state?.hitTestEnabled === true;
150
+ const hitArea = state?.hitArea ?? null;
151
+ if (enabled && hitArea !== null) {
152
+ if (hitAreaContainsPoint(node, hitArea, x, y))
153
+ out.push(node);
154
+ return;
155
+ }
156
+ const children = getNodeRuntime(node).children;
157
+ if (children !== null) {
158
+ for (let i = children.length - 1; i >= 0; i--)
159
+ collectHits(children[i], x, y, precise, out);
160
+ }
161
+ if (enabled && testNodeGeometry(node, x, y, precise))
162
+ out.push(node);
163
+ }
164
+ // A single node's own-geometry test. Precise uses the kind's exact provider (hit iff >= 0) and falls
165
+ // back to the coarse bounds handler when no exact provider is registered — best-available precision.
166
+ function testNodeGeometry(node, x, y, precise) {
167
+ if (precise) {
168
+ const exact = hitTestExactRegistry.get(node.kind);
169
+ if (exact !== undefined)
170
+ return exact(node, x, y) >= 0;
171
+ }
172
+ const coarse = hitTestRegistry.get(node.kind);
173
+ return coarse ? coarse(node, x, y) : false;
174
+ }
175
+ // Resolves a `hitArea` region against world-space (x, y). Local-space forms (`'bounds'`, `Rectangle`,
176
+ // `Path`) map the point through the owning node's world matrix; a `Node` proxy is tested in the proxy's
177
+ // own world space via its coarse hit function. Union members are discriminated structurally: `'bounds'`
178
+ // is a string, a node carries `kind`, a path carries `commands`, otherwise it is a rectangle.
179
+ function hitAreaContainsPoint(node, hitArea, x, y) {
180
+ if (hitArea === 'bounds')
181
+ return hitTestGraphLocalBounds(node, x, y);
182
+ if ('kind' in hitArea) {
183
+ const proxy = hitArea;
184
+ const proxyHit = hitTestRegistry.get(proxy.kind);
185
+ return proxyHit ? proxyHit(proxy, x, y) : hitTestGraphLocalBounds(proxy, x, y);
186
+ }
187
+ inverseMatrixTransformPointXY(hitTestScratchPoint, getNodeWorldMatrix(node), x, y);
188
+ const lx = hitTestScratchPoint.x;
189
+ const ly = hitTestScratchPoint.y;
190
+ if ('commands' in hitArea)
191
+ return containsPathPoint(hitArea, lx, ly);
192
+ return containsRectanglePointXY(hitArea, lx, ly);
77
193
  }
78
- const hitTestLocalBoundsRectanglePoint = { x: 0, y: 0 };
79
- const hitTestPointRegistry = new Map();
194
+ const hitTestScratchPoint = { x: 0, y: 0 };
195
+ const hitTestRegistry = new Map();
196
+ const hitTestExactRegistry = new Map();
80
197
  //# sourceMappingURL=hitTests.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hitTests.js","sourceRoot":"","sources":["../src/hitTests.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hitTests.js","sourceRoot":"","sources":["../src/hitTests.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,16 @@
1
+ export * from './cursorBackend';
1
2
  export * from './displayHitTests';
3
+ export * from './enableInteractionGuards';
2
4
  export * from './displayObjectOverlap';
5
+ export * from './focusManager';
3
6
  export * from './hitTests';
4
7
  export * from './interactionManager';
5
- export * from './registerDefaultHitTestPoints';
8
+ export * from './interactionSpatialIndex';
9
+ export * from './nodeInteractionState';
10
+ export * from './registerBitmapHitTest';
11
+ export * from './registerShapeHitTest';
12
+ export * from './registerTextHitTest';
13
+ export * from './registerDefaultHitTests';
6
14
  export * from './spatialQuery';
7
15
  export * from './spriteHitTests';
8
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,8 +1,16 @@
1
+ export * from './cursorBackend';
1
2
  export * from './displayHitTests';
3
+ export * from './enableInteractionGuards';
2
4
  export * from './displayObjectOverlap';
5
+ export * from './focusManager';
3
6
  export * from './hitTests';
4
7
  export * from './interactionManager';
5
- export * from './registerDefaultHitTestPoints';
8
+ export * from './interactionSpatialIndex';
9
+ export * from './nodeInteractionState';
10
+ export * from './registerBitmapHitTest';
11
+ export * from './registerShapeHitTest';
12
+ export * from './registerTextHitTest';
13
+ export * from './registerDefaultHitTests';
6
14
  export * from './spatialQuery';
7
15
  export * from './spriteHitTests';
8
16
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { InteractionInputSource, InteractionManager, InteractionManagerOptions, InteractionPointerOptions, InteractionSignalName, InteractionSignals, KeyboardEventData, NodeAny, PointerEventData, SignalConnectOptions } from '@flighthq/types';
1
+ import type { FocusEventData, InteractionInputSource, InteractionManager, InteractionManagerOptions, InteractionPointerOptions, InteractionSignalName, InteractionSignals, KeyboardEventData, NodeAny, PointerEventData, SignalConnectOptions } from '@flighthq/types';
2
2
  export declare function captureInteractionPointer<N extends NodeAny>(manager: InteractionManager<N>, pointerId: number, target: N): void;
3
3
  /**
4
4
  * Wires an input source's pointer/keyboard signals into an interaction manager, forwarding each
@@ -31,8 +31,16 @@ export declare function dispatchInteractionWheel<N extends NodeAny>(manager: Int
31
31
  export declare function enableInteractionSignals<N extends NodeAny>(source: N): InteractionSignals;
32
32
  export declare function getInteractionSignals<N extends NodeAny>(source: N): InteractionSignals | null;
33
33
  export declare function releaseInteractionPointer<N extends NodeAny>(manager: InteractionManager<N>, pointerId: number): void;
34
+ /**
35
+ * Installs the connect-time guard hook consulted by `connectInteractionSignal`; `null` uninstalls it.
36
+ * This is the diagnostics seam — `enableInteractionGuards` (a separately-imported module that depends on
37
+ * `@flighthq/log`) provides the implementation, so the core carries no message or log weight.
38
+ **/
39
+ export declare function setInteractionConnectGuard(guard: InteractionConnectGuard | null): void;
34
40
  type KeyboardSignalName = 'onKeyDown' | 'onKeyUp';
35
- type InteractionSignalPayload<Name extends InteractionSignalName> = Name extends KeyboardSignalName ? Readonly<KeyboardEventData> : Readonly<PointerEventData>;
41
+ type FocusSignalName = 'onFocusIn' | 'onFocusOut';
42
+ export type InteractionConnectGuard = (target: NodeAny, name: InteractionSignalName) => void;
43
+ type InteractionSignalPayload<Name extends InteractionSignalName> = Name extends KeyboardSignalName ? Readonly<KeyboardEventData> : Name extends FocusSignalName ? Readonly<FocusEventData> : Readonly<PointerEventData>;
36
44
  type InteractionSignalSlot<Name extends InteractionSignalName> = (value: InteractionSignalPayload<Name>) => void;
37
45
  export {};
38
46
  //# sourceMappingURL=interactionManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactionManager.d.ts","sourceRoot":"","sources":["../src/interactionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"interactionManager.d.ts","sourceRoot":"","sources":["../src/interactionManager.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
1
  import { inverseMatrixTransformPointXY } from '@flighthq/geometry';
2
- import { getNodeParent, getNodeRuntime, getNodeWorldTransformMatrix } from '@flighthq/node';
2
+ import { getNodeParent, getNodeRuntime, getNodeWorldMatrix } from '@flighthq/node';
3
3
  import { connectSignal, createSignal, disconnectSignal, emitSignal, isSlotConnected } from '@flighthq/signals';
4
- import { findGraphHitTarget } from './hitTests';
4
+ import { findGraphHitTarget, findGraphHitTargetPrecise } from './hitTests';
5
+ import { findSpatialInteractionTarget } from './interactionSpatialIndex';
6
+ import { getNodeCursor } from './nodeInteractionState';
5
7
  export function captureInteractionPointer(manager, pointerId, target) {
6
8
  manager.pointerCaptures.set(pointerId, target);
7
9
  }
@@ -66,14 +68,20 @@ export function connectInteractionSignal(manager, target, name, slot, options) {
66
68
  connectSignal(signal, connectedSlot, options);
67
69
  setTrackedInteractionSignalSlot(manager, target, name, slot, connectedSlot);
68
70
  incrementInteractionSignalSubscriberCount(manager, name);
71
+ // Diagnostics seam: the guard module (separately imported) fills this to catch listeners on nodes
72
+ // with no hit path. Null in production, so no `@flighthq/log` weight on the base bundle.
73
+ interactionConnectGuard?.(target, name);
69
74
  }
70
75
  export function createInteractionManager(root, options = {}) {
71
76
  return {
77
+ cursorBackend: options.cursorBackend ?? null,
72
78
  doubleClickDelay: 500,
73
79
  enabled: options.enabled ?? true,
74
80
  pointerCaptures: new Map(),
75
81
  pointerStates: new Map(),
82
+ precise: options.precise ?? false,
76
83
  root,
84
+ spatialIndex: options.spatialIndex ?? null,
77
85
  signalSubscriberCounts: new Map(),
78
86
  trackedSignalSlots: new Map(),
79
87
  trackedSubscribersOnly: options.trackedSubscribersOnly ?? false,
@@ -84,6 +92,8 @@ export function createInteractionSignals() {
84
92
  onClick: createSignal(),
85
93
  onContextMenu: createSignal(),
86
94
  onDoubleClick: createSignal(),
95
+ onFocusIn: createSignal(),
96
+ onFocusOut: createSignal(),
87
97
  onKeyDown: createSignal(),
88
98
  onKeyUp: createSignal(),
89
99
  onPointerCancel: createSignal(),
@@ -151,8 +161,11 @@ export function dispatchInteractionPointerDown(manager, x, y, button = 0, option
151
161
  emitInteractionSignal(target, manager.root, 'onPointerDown', _pointerData);
152
162
  }
153
163
  export function dispatchInteractionPointerMove(manager, x, y, button = 0, options) {
154
- if (!isPointerSignalNeeded(manager, moveSignalNames))
164
+ // Run the move body when a rollover subscriber needs it OR a cursor backend is active — a scene that
165
+ // only changes the cursor on hover (no move/over/out listeners) must still resolve the rollover.
166
+ if (!isPointerSignalNeeded(manager, moveSignalNames) && !(manager.enabled && manager.cursorBackend !== null)) {
155
167
  return;
168
+ }
156
169
  const pointerId = options?.pointerId ?? 0;
157
170
  const state = getInteractionPointerState(manager, pointerId);
158
171
  const oldTarget = state.pointerOverTarget;
@@ -211,6 +224,14 @@ export function getInteractionSignals(source) {
211
224
  export function releaseInteractionPointer(manager, pointerId) {
212
225
  manager.pointerCaptures.delete(pointerId);
213
226
  }
227
+ /**
228
+ * Installs the connect-time guard hook consulted by `connectInteractionSignal`; `null` uninstalls it.
229
+ * This is the diagnostics seam — `enableInteractionGuards` (a separately-imported module that depends on
230
+ * `@flighthq/log`) provides the implementation, so the core carries no message or log weight.
231
+ **/
232
+ export function setInteractionConnectGuard(guard) {
233
+ interactionConnectGuard = guard;
234
+ }
214
235
  function dispatchKeyboardSignal(manager, name, key, keyCode, modifiers) {
215
236
  if (!manager.enabled || !hasInteractionSignalSubscriber(manager, name))
216
237
  return;
@@ -239,6 +260,33 @@ function dispatchPointerRolloverChange(manager, oldTarget, target) {
239
260
  if (target !== null) {
240
261
  emitInteractionSignal(target, manager.root, 'onPointerOver', _pointerData);
241
262
  }
263
+ applyInteractionCursor(manager, target);
264
+ }
265
+ /**
266
+ * Applies the cursor resolved for the current rollover target through the manager's cursor backend.
267
+ * No-op when no backend is installed. A `null` target (pointer left everything) clears to the default.
268
+ **/
269
+ function applyInteractionCursor(manager, target) {
270
+ const backend = manager.cursorBackend;
271
+ if (backend === null)
272
+ return;
273
+ backend.setCursor(resolveInteractionCursor(target, manager.root));
274
+ }
275
+ /**
276
+ * Resolves the effective rollover cursor: the nearest cursor set on `target` or any of its ancestors
277
+ * up to `root` (innermost wins). Returns `null` when none is set, so the backend clears to its default.
278
+ **/
279
+ function resolveInteractionCursor(target, root) {
280
+ let current = target;
281
+ while (current !== null) {
282
+ const cursor = getNodeCursor(current);
283
+ if (cursor !== null)
284
+ return cursor;
285
+ if (current === root)
286
+ break;
287
+ current = getNodeParent(current);
288
+ }
289
+ return null;
242
290
  }
243
291
  function dispatchPointerSignalAt(manager, name, x, y, button, deltaX = 0, deltaY = 0, options) {
244
292
  if (!isPointerSignalNeeded(manager, [name]))
@@ -281,7 +329,10 @@ function findInteractionTarget(manager, x, y, pointerId) {
281
329
  const captured = manager.pointerCaptures.get(pointerId);
282
330
  if (captured !== undefined)
283
331
  return captured;
284
- return findGraphHitTarget(manager.root, x, y);
332
+ if (manager.spatialIndex !== null)
333
+ return findSpatialInteractionTarget(manager, x, y, manager.precise);
334
+ const root = manager.root;
335
+ return (manager.precise ? findGraphHitTargetPrecise(root, x, y) : findGraphHitTarget(root, x, y));
285
336
  }
286
337
  function getInteractionPointerState(manager, pointerId) {
287
338
  let state = manager.pointerStates.get(pointerId);
@@ -420,14 +471,15 @@ function setPointerDataLocalPosition(data, currentTarget) {
420
471
  data.localY = data.worldY;
421
472
  return;
422
473
  }
423
- inverseMatrixTransformPointXY(_localPoint, getNodeWorldTransformMatrix(currentTarget), data.worldX, data.worldY);
474
+ inverseMatrixTransformPointXY(_localPoint, getNodeWorldMatrix(currentTarget), data.worldX, data.worldY);
424
475
  data.localX = _localPoint.x;
425
476
  data.localY = _localPoint.y;
426
477
  }
427
478
  function isTransform2DNode(source) {
428
479
  const runtime = getNodeRuntime(source);
429
- return 'worldTransform2D' in runtime;
480
+ return 'worldMatrix' in runtime;
430
481
  }
482
+ let interactionConnectGuard = null;
431
483
  const cancelSignalNames = ['onPointerCancel', 'onPointerOut', 'onPointerRollOut'];
432
484
  const downSignalNames = ['onClick', 'onDoubleClick', 'onPointerCancel', 'onPointerDown', 'onReleaseOutside'];
433
485
  const moveSignalNames = [