@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.
- package/dist/cursorBackend.d.ts +12 -0
- package/dist/cursorBackend.d.ts.map +1 -0
- package/dist/cursorBackend.js +17 -0
- package/dist/cursorBackend.js.map +1 -0
- package/dist/displayHitTests.d.ts +10 -11
- package/dist/displayHitTests.d.ts.map +1 -1
- package/dist/displayHitTests.js +12 -14
- package/dist/displayHitTests.js.map +1 -1
- package/dist/enableInteractionGuards.d.ts +23 -0
- package/dist/enableInteractionGuards.d.ts.map +1 -0
- package/dist/enableInteractionGuards.js +75 -0
- package/dist/enableInteractionGuards.js.map +1 -0
- package/dist/focusManager.d.ts +46 -0
- package/dist/focusManager.d.ts.map +1 -0
- package/dist/focusManager.js +243 -0
- package/dist/focusManager.js.map +1 -0
- package/dist/hitTests.d.ts +45 -24
- package/dist/hitTests.d.ts.map +1 -1
- package/dist/hitTests.js +164 -47
- package/dist/hitTests.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/interactionManager.d.ts +10 -2
- package/dist/interactionManager.d.ts.map +1 -1
- package/dist/interactionManager.js +58 -6
- package/dist/interactionManager.js.map +1 -1
- package/dist/interactionSpatialIndex.d.ts +17 -0
- package/dist/interactionSpatialIndex.d.ts.map +1 -0
- package/dist/interactionSpatialIndex.js +77 -0
- package/dist/interactionSpatialIndex.js.map +1 -0
- package/dist/nodeInteractionState.d.ts +39 -0
- package/dist/nodeInteractionState.d.ts.map +1 -0
- package/dist/nodeInteractionState.js +72 -0
- package/dist/nodeInteractionState.js.map +1 -0
- package/dist/registerBitmapHitTest.d.ts +11 -0
- package/dist/registerBitmapHitTest.d.ts.map +1 -0
- package/dist/registerBitmapHitTest.js +55 -0
- package/dist/registerBitmapHitTest.js.map +1 -0
- package/dist/registerDefaultHitTests.d.ts +2 -0
- package/dist/registerDefaultHitTests.d.ts.map +1 -0
- package/dist/registerDefaultHitTests.js +20 -0
- package/dist/registerDefaultHitTests.js.map +1 -0
- package/dist/registerShapeHitTest.d.ts +10 -0
- package/dist/registerShapeHitTest.d.ts.map +1 -0
- package/dist/registerShapeHitTest.js +32 -0
- package/dist/registerShapeHitTest.js.map +1 -0
- package/dist/registerTextHitTest.d.ts +12 -0
- package/dist/registerTextHitTest.d.ts.map +1 -0
- package/dist/registerTextHitTest.js +32 -0
- package/dist/registerTextHitTest.js.map +1 -0
- package/dist/spriteHitTests.d.ts +3 -3
- package/dist/spriteHitTests.d.ts.map +1 -1
- package/dist/spriteHitTests.js +5 -5
- package/dist/spriteHitTests.js.map +1 -1
- package/package.json +13 -7
- package/src/cursorBackend.test.ts +24 -0
- package/src/displayHitTests.test.ts +39 -47
- package/src/enableInteractionGuards.test.ts +102 -0
- package/src/focusManager.test.ts +307 -0
- package/src/hitTests.test.ts +235 -98
- package/src/interactionManager.test.ts +59 -8
- package/src/interactionSpatialIndex.test.ts +103 -0
- package/src/nodeInteractionState.test.ts +141 -0
- package/src/registerBitmapHitTest.test.ts +22 -0
- package/src/{registerDefaultHitTestPoints.test.ts → registerDefaultHitTests.test.ts} +10 -7
- package/src/registerShapeHitTest.test.ts +27 -0
- package/src/registerTextHitTest.test.ts +54 -0
- package/src/spriteHitTests.test.ts +15 -15
- package/dist/registerDefaultHitTestPoints.d.ts +0 -2
- package/dist/registerDefaultHitTestPoints.d.ts.map +0 -1
- package/dist/registerDefaultHitTestPoints.js +0 -21
- package/dist/registerDefaultHitTestPoints.js.map +0 -1
package/dist/hitTests.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
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
|
-
*
|
|
20
|
-
* the
|
|
21
|
-
*
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* node
|
|
26
|
-
*
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
package/dist/hitTests.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hitTests.d.ts","sourceRoot":"","sources":["../src/hitTests.ts"],"names":[],"mappings":"
|
|
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,
|
|
2
|
+
import { getNodeLocalBoundsRectangle, getNodeParent, getNodeRuntime, getNodeWorldBoundsRectangle, getNodeWorldMatrix, } from '@flighthq/node';
|
|
3
|
+
import { containsPathPoint } from '@flighthq/path';
|
|
4
|
+
import { getNodeInteractionState } from './nodeInteractionState';
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return
|
|
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(
|
|
40
|
-
return containsRectanglePointXY(getNodeLocalBoundsRectangle(source),
|
|
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
|
-
*
|
|
44
|
-
* the
|
|
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
|
|
57
|
-
|
|
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
|
|
60
|
-
|
|
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(
|
|
135
|
+
const children = getNodeRuntime(node).children;
|
|
63
136
|
if (children !== null) {
|
|
64
137
|
for (const child of children) {
|
|
65
|
-
if (
|
|
138
|
+
if (anyHit(child, x, y, precise))
|
|
66
139
|
return true;
|
|
67
140
|
}
|
|
68
141
|
}
|
|
69
142
|
return false;
|
|
70
143
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
79
|
-
const
|
|
194
|
+
const hitTestScratchPoint = { x: 0, y: 0 };
|
|
195
|
+
const hitTestRegistry = new Map();
|
|
196
|
+
const hitTestExactRegistry = new Map();
|
|
80
197
|
//# sourceMappingURL=hitTests.js.map
|
package/dist/hitTests.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hitTests.js","sourceRoot":"","sources":["../src/hitTests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,oBAAoB,CAAC;AAClH,OAAO,EACL,2BAA2B,EAC3B,aAAa,EACb,cAAc,EACd,2BAA2B,EAC3B,
|
|
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 './
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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 './
|
|
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,
|
|
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
|
|
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":"AAGA,OAAO,KAAK,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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 '
|
|
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 = [
|