@flighthq/interaction 0.5.1-next.658.9cb44d7 → 0.5.1-next.693.478551c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/interaction`. The `@
13
13
  This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
14
14
 
15
15
  - [Flight project](https://github.com/flighthq/flight)
16
- - [Source for @flighthq/interaction@0.5.1-next.658.9cb44d7](https://github.com/flighthq/flight/tree/9cb44d76b981adad2503d5e62207be99adb35c55/packages/interaction)
17
- - [License](https://github.com/flighthq/flight/blob/9cb44d76b981adad2503d5e62207be99adb35c55/LICENSE.md)
16
+ - [Source for @flighthq/interaction@0.5.1-next.693.478551c](https://github.com/flighthq/flight/tree/478551cf7887f05c42c11f75e59034c715c8495f/packages/interaction)
17
+ - [License](https://github.com/flighthq/flight/blob/478551cf7887f05c42c11f75e59034c715c8495f/LICENSE.md)
@@ -6,6 +6,7 @@ export * from './hitTests';
6
6
  export * from './interactionManager';
7
7
  export * from './interactionSpatialIndex';
8
8
  export * from './nodeInteractionState';
9
+ export * from './nodeInteractiveStateBinding';
9
10
  export * from './registerSpriteHitTest';
10
11
  export * from './registerShapeHitTest';
11
12
  export * from './registerTextHitTest';
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,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
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,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,+BAA+B,CAAC;AAC9C,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/contract.js CHANGED
@@ -6,6 +6,7 @@ export * from './hitTests';
6
6
  export * from './interactionManager';
7
7
  export * from './interactionSpatialIndex';
8
8
  export * from './nodeInteractionState';
9
+ export * from './nodeInteractiveStateBinding';
9
10
  export * from './registerSpriteHitTest';
10
11
  export * from './registerShapeHitTest';
11
12
  export * from './registerTextHitTest';
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,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
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,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,+BAA+B,CAAC;AAC9C,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.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { captureInteractionPointer, clearFocus, connectFocusNavigation, connectInputToInteraction, connectInteractionSignal, containsNode2D, createFocusManager, createInteractionManager, createNodeInteractionState, describeGraphHit, disableInteractionGuards, disconnectInteractionSignal, dispatchInteractionContextMenu, dispatchInteractionKeyDown, dispatchInteractionKeyUp, dispatchInteractionPointerCancel, dispatchInteractionPointerDown, dispatchInteractionPointerMove, dispatchInteractionPointerUp, dispatchInteractionWheel, enableInteractionGuards, enableInteractionSignals, enableNodeInteractionState, explainInteractionHitEligibility, findGraphHitTarget, findGraphHitTargetPrecise, findGraphHitTargets, findGraphHitTargetsPrecise, findSpatialInteractionTarget, focusNextNode, focusNodeInDirection, focusPreviousNode, getFocusOrder, getFocusedNode, getInteractionSignals, getNode2DOverlapRectangle, getNodeCursor, getNodeHitArea, getNodeInteractionState, getNodeTabIndex, hitTestAreaQuery, hitTestAreaQueryCircle, hitTestGraphLocalBounds, hitTestGraphPoint, hitTestGraphPointPrecise, hitTestNode2Ds, hitTestNode2DsShape, hitTestNodeRegion, isNodeFocusable, isNodeFocused, isNodeHitTestEnabled, refreshInteractionSpatialIndex, registerSpriteHitTest, registerDefaultHitTests, registerHitTest, registerHitTestPrecise, registerShapeHitTest, registerTextHitTest, releaseInteractionPointer, setFocusedNode, setInteractionConnectGuard, setNodeCursor, setNodeFocusable, setNodeHitArea, setNodeHitTestEnabled, setNodeTabIndex, } from './contract';
1
+ export { applyNodeInteractiveStates, captureInteractionPointer, clearFocus, connectFocusNavigation, connectInputToInteraction, connectInteractionDispatchLayer, connectInteractionSignal, containsNode2D, createFocusManager, createInteractionManager, createNodeInteractionState, createNodeInteractiveStateBinding, describeGraphHit, disableInteractionGuards, disconnectInteractionSignal, dispatchInteractionContextMenu, dispatchInteractionKeyDown, dispatchInteractionKeyUp, dispatchInteractionPointerCancel, dispatchInteractionPointerDown, dispatchInteractionPointerMove, dispatchInteractionPointerUp, dispatchInteractionWheel, disposeNodeInteractiveStateBinding, enableInteractionGuards, enableInteractionSignals, enableNodeInteractionState, explainInteractionHitEligibility, explainNodeInteractiveStateBinding, findGraphHitTarget, findGraphHitTargetPrecise, findGraphHitTargets, findGraphHitTargetsPrecise, findSpatialInteractionTarget, focusNextNode, focusNodeInDirection, focusPreviousNode, getFocusOrder, getFocusedNode, getInteractionSignals, getNode2DOverlapRectangle, getNodeCursor, getNodeHitArea, getNodeInteractionState, getNodeTabIndex, hitTestAreaQuery, hitTestAreaQueryCircle, hitTestGraphLocalBounds, hitTestGraphPoint, hitTestGraphPointPrecise, hitTestNode2Ds, hitTestNode2DsShape, hitTestNodeRegion, invalidateInteractionCursor, isNodeFocusable, isNodeFocused, isNodeHitTestEnabled, isNodePointerDoubleClickEnabled, refreshInteractionSpatialIndex, registerSpriteHitTest, registerDefaultHitTests, registerHitTest, registerHitTestPrecise, registerShapeHitTest, registerTextHitTest, releaseInteractionPointer, setFocusedNode, setInteractionConnectGuard, setNodeCursor, setNodeFocusable, setNodeHitArea, setNodeHitTestEnabled, setNodePointerDoubleClickEnabled, setNodeTabIndex, } from './contract';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,sBAAsB,EACtB,yBAAyB,EACzB,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC1B,gBAAgB,EAChB,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,EAC9B,0BAA0B,EAC1B,wBAAwB,EACxB,gCAAgC,EAChC,8BAA8B,EAC9B,8BAA8B,EAC9B,4BAA4B,EAC5B,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,gCAAgC,EAChC,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,4BAA4B,EAC5B,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,8BAA8B,EAC9B,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,yBAAyB,EACzB,cAAc,EACd,0BAA0B,EAC1B,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,eAAe,GAChB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,UAAU,EACV,sBAAsB,EACtB,yBAAyB,EACzB,+BAA+B,EAC/B,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC1B,iCAAiC,EACjC,gBAAgB,EAChB,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,EAC9B,0BAA0B,EAC1B,wBAAwB,EACxB,gCAAgC,EAChC,8BAA8B,EAC9B,8BAA8B,EAC9B,4BAA4B,EAC5B,wBAAwB,EACxB,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,gCAAgC,EAChC,kCAAkC,EAClC,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,4BAA4B,EAC5B,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,+BAA+B,EAC/B,8BAA8B,EAC9B,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,yBAAyB,EACzB,cAAc,EACd,0BAA0B,EAC1B,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,gCAAgC,EAChC,eAAe,GAChB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { captureInteractionPointer, clearFocus, connectFocusNavigation, connectInputToInteraction, connectInteractionSignal, containsNode2D, createFocusManager, createInteractionManager, createNodeInteractionState, describeGraphHit, disableInteractionGuards, disconnectInteractionSignal, dispatchInteractionContextMenu, dispatchInteractionKeyDown, dispatchInteractionKeyUp, dispatchInteractionPointerCancel, dispatchInteractionPointerDown, dispatchInteractionPointerMove, dispatchInteractionPointerUp, dispatchInteractionWheel, enableInteractionGuards, enableInteractionSignals, enableNodeInteractionState, explainInteractionHitEligibility, findGraphHitTarget, findGraphHitTargetPrecise, findGraphHitTargets, findGraphHitTargetsPrecise, findSpatialInteractionTarget, focusNextNode, focusNodeInDirection, focusPreviousNode, getFocusOrder, getFocusedNode, getInteractionSignals, getNode2DOverlapRectangle, getNodeCursor, getNodeHitArea, getNodeInteractionState, getNodeTabIndex, hitTestAreaQuery, hitTestAreaQueryCircle, hitTestGraphLocalBounds, hitTestGraphPoint, hitTestGraphPointPrecise, hitTestNode2Ds, hitTestNode2DsShape, hitTestNodeRegion, isNodeFocusable, isNodeFocused, isNodeHitTestEnabled, refreshInteractionSpatialIndex, registerSpriteHitTest, registerDefaultHitTests, registerHitTest, registerHitTestPrecise, registerShapeHitTest, registerTextHitTest, releaseInteractionPointer, setFocusedNode, setInteractionConnectGuard, setNodeCursor, setNodeFocusable, setNodeHitArea, setNodeHitTestEnabled, setNodeTabIndex, } from './contract';
1
+ export { applyNodeInteractiveStates, captureInteractionPointer, clearFocus, connectFocusNavigation, connectInputToInteraction, connectInteractionDispatchLayer, connectInteractionSignal, containsNode2D, createFocusManager, createInteractionManager, createNodeInteractionState, createNodeInteractiveStateBinding, describeGraphHit, disableInteractionGuards, disconnectInteractionSignal, dispatchInteractionContextMenu, dispatchInteractionKeyDown, dispatchInteractionKeyUp, dispatchInteractionPointerCancel, dispatchInteractionPointerDown, dispatchInteractionPointerMove, dispatchInteractionPointerUp, dispatchInteractionWheel, disposeNodeInteractiveStateBinding, enableInteractionGuards, enableInteractionSignals, enableNodeInteractionState, explainInteractionHitEligibility, explainNodeInteractiveStateBinding, findGraphHitTarget, findGraphHitTargetPrecise, findGraphHitTargets, findGraphHitTargetsPrecise, findSpatialInteractionTarget, focusNextNode, focusNodeInDirection, focusPreviousNode, getFocusOrder, getFocusedNode, getInteractionSignals, getNode2DOverlapRectangle, getNodeCursor, getNodeHitArea, getNodeInteractionState, getNodeTabIndex, hitTestAreaQuery, hitTestAreaQueryCircle, hitTestGraphLocalBounds, hitTestGraphPoint, hitTestGraphPointPrecise, hitTestNode2Ds, hitTestNode2DsShape, hitTestNodeRegion, invalidateInteractionCursor, isNodeFocusable, isNodeFocused, isNodeHitTestEnabled, isNodePointerDoubleClickEnabled, refreshInteractionSpatialIndex, registerSpriteHitTest, registerDefaultHitTests, registerHitTest, registerHitTestPrecise, registerShapeHitTest, registerTextHitTest, releaseInteractionPointer, setFocusedNode, setInteractionConnectGuard, setNodeCursor, setNodeFocusable, setNodeHitArea, setNodeHitTestEnabled, setNodePointerDoubleClickEnabled, setNodeTabIndex, } from './contract';
2
2
  //# 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,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,sBAAsB,EACtB,yBAAyB,EACzB,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC1B,gBAAgB,EAChB,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,EAC9B,0BAA0B,EAC1B,wBAAwB,EACxB,gCAAgC,EAChC,8BAA8B,EAC9B,8BAA8B,EAC9B,4BAA4B,EAC5B,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,gCAAgC,EAChC,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,4BAA4B,EAC5B,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,8BAA8B,EAC9B,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,yBAAyB,EACzB,cAAc,EACd,0BAA0B,EAC1B,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,eAAe,GAChB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,UAAU,EACV,sBAAsB,EACtB,yBAAyB,EACzB,+BAA+B,EAC/B,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC1B,iCAAiC,EACjC,gBAAgB,EAChB,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,EAC9B,0BAA0B,EAC1B,wBAAwB,EACxB,gCAAgC,EAChC,8BAA8B,EAC9B,8BAA8B,EAC9B,4BAA4B,EAC5B,wBAAwB,EACxB,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,gCAAgC,EAChC,kCAAkC,EAClC,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,4BAA4B,EAC5B,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,+BAA+B,EAC/B,8BAA8B,EAC9B,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,yBAAyB,EACzB,cAAc,EACd,0BAA0B,EAC1B,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,gCAAgC,EAChC,eAAe,GAChB,MAAM,YAAY,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { FocusEventData, InteractionConnectGuard, InteractionInputSource, InteractionManager, InteractionManagerOptions, InteractionPointerOptions, InteractionSignalName, InteractionSignals, KeyboardEventData, NodeAny, PointerEventData, SignalConnectOptions } from '@flighthq/types/contract';
1
+ import type { FocusEventData, InteractionConnectGuard, InteractionDispatchLayer, InteractionDispatchLayerOptions, InteractionInputSource, InteractionManager, InteractionManagerOptions, InteractionPointerOptions, InteractionSignalName, InteractionSignals, KeyboardEventData, NodeAny, PointerEventData, SignalConnectOptions } from '@flighthq/types/contract';
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
@@ -16,6 +16,12 @@ export declare function captureInteractionPointer<N extends NodeAny>(manager: In
16
16
  * point, since that offset moves with scroll and layout.
17
17
  */
18
18
  export declare function connectInputToInteraction<N extends NodeAny>(input: InteractionInputSource, manager: InteractionManager<N>, coordScale?: number): () => void;
19
+ /**
20
+ * Adds a priority-ordered layer before Flight signal dispatch and returns an idempotent disconnect.
21
+ * Equal priorities retain connection order. Each dispatch snapshots the current list: additions wait
22
+ * for the next dispatch, while a layer removed during the walk still receives the current one.
23
+ */
24
+ export declare function connectInteractionDispatchLayer<N extends NodeAny>(manager: InteractionManager<N>, layer: InteractionDispatchLayer<N>, options?: Readonly<InteractionDispatchLayerOptions>): () => void;
19
25
  export declare function connectInteractionSignal<N extends NodeAny, Name extends InteractionSignalName>(manager: InteractionManager<N>, target: N, name: Name, slot: InteractionSignalSlot<Name>, options?: Readonly<SignalConnectOptions>): void;
20
26
  export declare function createInteractionManager<N extends NodeAny>(root: N, options?: Readonly<InteractionManagerOptions>): InteractionManager<N>;
21
27
  export declare function createInteractionSignals(): InteractionSignals;
@@ -30,6 +36,8 @@ export declare function dispatchInteractionPointerUp<N extends NodeAny>(manager:
30
36
  export declare function dispatchInteractionWheel<N extends NodeAny>(manager: InteractionManager<N>, x: number, y: number, deltaX?: number, deltaY?: number, options?: Readonly<InteractionPointerOptions>): void;
31
37
  export declare function enableInteractionSignals<N extends NodeAny>(source: N): InteractionSignals;
32
38
  export declare function getInteractionSignals<N extends NodeAny>(source: N): InteractionSignals | null;
39
+ /** Re-resolves and immediately applies the cursor for the manager's current rollover target. */
40
+ export declare function invalidateInteractionCursor<N extends NodeAny>(manager: InteractionManager<N>): void;
33
41
  export declare function releaseInteractionPointer<N extends NodeAny>(manager: InteractionManager<N>, pointerId: number): void;
34
42
  /**
35
43
  * Installs the connect-time guard hook consulted by `connectInteractionSignal`; `null` uninstalls it.
@@ -1 +1 @@
1
- {"version":3,"file":"interactionManager.d.ts","sourceRoot":"","sources":["../src/interactionManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,cAAc,EAGd,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,yBAAyB,EACzB,yBAAyB,EAEzB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,OAAO,EAEP,gBAAgB,EAEhB,oBAAoB,EAErB,MAAM,0BAA0B,CAAC;AAMlC,wBAAgB,yBAAyB,CAAC,CAAC,SAAS,OAAO,EACzD,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,CAAC,GACR,IAAI,CAEN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,SAAS,OAAO,EACzD,KAAK,EAAE,sBAAsB,EAC7B,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,UAAU,GAAE,MAAU,GACrB,MAAM,IAAI,CAkCZ;AAED,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,SAAS,qBAAqB,EAC5F,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,qBAAqB,CAAC,IAAI,CAAC,EACjC,OAAO,CAAC,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GACvC,IAAI,CA2BN;AAED,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,OAAO,EACxD,IAAI,EAAE,CAAC,EACP,OAAO,GAAE,QAAQ,CAAC,yBAAyB,CAAM,GAChD,kBAAkB,CAAC,CAAC,CAAC,CAcvB;AAED,wBAAgB,wBAAwB,IAAI,kBAAkB,CAoB7D;AAED,wBAAgB,2BAA2B,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,SAAS,qBAAqB,EAC/F,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,qBAAqB,CAAC,IAAI,CAAC,GAChC,IAAI,CAWN;AAED,wBAAgB,8BAA8B,CAAC,CAAC,SAAS,OAAO,EAC9D,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,GAAE,MAAU,EAClB,OAAO,CAAC,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAC5C,IAAI,CAEN;AAED,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,OAAO,EAC1D,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,MAAU,EACnB,SAAS,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,GAC/C,IAAI,CAEN;AAED,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,OAAO,EACxD,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,MAAU,EACnB,SAAS,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,GAC/C,IAAI,CAEN;AAED,wBAAgB,gCAAgC,CAAC,CAAC,SAAS,OAAO,EAChE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,OAAO,CAAC,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAC5C,IAAI,CAmBN;AAED,wBAAgB,8BAA8B,CAAC,CAAC,SAAS,OAAO,EAC9D,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,GAAE,MAAU,EAClB,OAAO,CAAC,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAC5C,IAAI,CAWN;AAED,wBAAgB,8BAA8B,CAAC,CAAC,SAAS,OAAO,EAC9D,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,GAAE,MAAU,EAClB,OAAO,CAAC,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAC5C,IAAI,CAuBN;AAED,wBAAgB,4BAA4B,CAAC,CAAC,SAAS,OAAO,EAC5D,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,GAAE,MAAU,EAClB,IAAI,GAAE,MAAmB,EACzB,OAAO,CAAC,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAC5C,IAAI,CA6BN;AAED,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,OAAO,EACxD,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,GAAE,MAAU,EAClB,MAAM,GAAE,MAAU,EAClB,OAAO,CAAC,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAC5C,IAAI,CAEN;AAED,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,kBAAkB,CAGzF;AAED,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,kBAAkB,GAAG,IAAI,CAE7F;AAED,wBAAgB,yBAAyB,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAEpH;AAED;;;;IAII;AACJ,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,GAAG,IAAI,CAEtF;AA+VD,KAAK,kBAAkB,GAAG,WAAW,GAAG,SAAS,CAAC;AAClD,KAAK,eAAe,GAAG,WAAW,GAAG,YAAY,CAAC;AAGlD,KAAK,wBAAwB,CAAC,IAAI,SAAS,qBAAqB,IAAI,IAAI,SAAS,kBAAkB,GAC/F,QAAQ,CAAC,iBAAiB,CAAC,GAC3B,IAAI,SAAS,eAAe,GAC1B,QAAQ,CAAC,cAAc,CAAC,GACxB,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AACjC,KAAK,qBAAqB,CAAC,IAAI,SAAS,qBAAqB,IAAI,CAAC,KAAK,EAAE,wBAAwB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC"}
1
+ {"version":3,"file":"interactionManager.d.ts","sourceRoot":"","sources":["../src/interactionManager.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ import { getNodeParent, getNodeRuntime, getNodeWorldMatrix } from '@flighthq/nod
3
3
  import { connectSignal, createSignal, disconnectSignal, emitSignal, isSlotConnected } from '@flighthq/signals/contract';
4
4
  import { findGraphHitTarget, findGraphHitTargetPrecise } from './hitTests';
5
5
  import { findSpatialInteractionTarget } from './interactionSpatialIndex';
6
- import { getNodeCursor } from './nodeInteractionState';
6
+ import { getNodeCursor, getNodeInteractionState } from './nodeInteractionState';
7
7
  export function captureInteractionPointer(manager, pointerId, target) {
8
8
  manager.pointerCaptures.set(pointerId, target);
9
9
  }
@@ -29,7 +29,7 @@ export function connectInputToInteraction(input, manager, coordScale = 1) {
29
29
  const onPointerCancel = (data) => dispatchInteractionPointerCancel(manager, sx(data.x), sx(data.y), data);
30
30
  const onPointerDown = (data) => dispatchInteractionPointerDown(manager, sx(data.x), sx(data.y), data.button, data);
31
31
  const onPointerMove = (data) => dispatchInteractionPointerMove(manager, sx(data.x), sx(data.y), data.button, data);
32
- const onPointerUp = (data) => dispatchInteractionPointerUp(manager, sx(data.x), sx(data.y), data.button, Date.now(), data);
32
+ const onPointerUp = (data) => dispatchInteractionPointerUp(manager, sx(data.x), sx(data.y), data.button, data.timeStamp, data);
33
33
  const onWheel = (data) => dispatchInteractionWheel(manager, sx(data.x), sx(data.y), data.deltaX, data.deltaY, data);
34
34
  connectSignal(input.onKeyDown, onKeyDown);
35
35
  connectSignal(input.onKeyUp, onKeyUp);
@@ -46,6 +46,35 @@ export function connectInputToInteraction(input, manager, coordScale = 1) {
46
46
  disconnectSignal(input.onPointerMove, onPointerMove);
47
47
  disconnectSignal(input.onPointerUp, onPointerUp);
48
48
  disconnectSignal(input.onWheel, onWheel);
49
+ resetInteractionClickStates(manager);
50
+ };
51
+ }
52
+ /**
53
+ * Adds a priority-ordered layer before Flight signal dispatch and returns an idempotent disconnect.
54
+ * Equal priorities retain connection order. Each dispatch snapshots the current list: additions wait
55
+ * for the next dispatch, while a layer removed during the walk still receives the current one.
56
+ */
57
+ export function connectInteractionDispatchLayer(manager, layer, options = {}) {
58
+ const entry = { layer, priority: options.priority ?? 0 };
59
+ const layers = (manager.dispatchLayers ??= []);
60
+ let index = 0;
61
+ while (index < layers.length && entry.priority <= layers[index].priority)
62
+ index++;
63
+ layers.splice(index, 0, entry);
64
+ let connected = true;
65
+ return () => {
66
+ if (!connected)
67
+ return;
68
+ connected = false;
69
+ const current = manager.dispatchLayers;
70
+ if (current === null)
71
+ return;
72
+ const currentIndex = current.indexOf(entry);
73
+ if (currentIndex === -1)
74
+ return;
75
+ current.splice(currentIndex, 1);
76
+ if (current.length === 0)
77
+ manager.dispatchLayers = null;
49
78
  };
50
79
  }
51
80
  export function connectInteractionSignal(manager, target, name, slot, options) {
@@ -75,7 +104,10 @@ export function connectInteractionSignal(manager, target, name, slot, options) {
75
104
  export function createInteractionManager(root, options = {}) {
76
105
  return {
77
106
  cursorBackend: options.cursorBackend ?? null,
78
- doubleClickDelay: 500,
107
+ cursorTarget: null,
108
+ dispatchLayers: null,
109
+ doubleClickDelay: options.doubleClickDelay ?? 500,
110
+ doubleClickDistance: options.doubleClickDistance ?? 4,
79
111
  enabled: options.enabled ?? true,
80
112
  pointerCaptures: new Map(),
81
113
  pointerStates: new Map(),
@@ -97,6 +129,7 @@ export function createInteractionSignals() {
97
129
  onKeyDown: createSignal(),
98
130
  onKeyUp: createSignal(),
99
131
  onPointerCancel: createSignal(),
132
+ onPointerDoubleClick: createSignal(),
100
133
  onPointerDown: createSignal(),
101
134
  onPointerMove: createSignal(),
102
135
  onPointerOut: createSignal(),
@@ -130,10 +163,13 @@ export function dispatchInteractionKeyUp(manager, key, keyCode = 0, modifiers) {
130
163
  dispatchKeyboardSignal(manager, 'onKeyUp', key, keyCode, modifiers);
131
164
  }
132
165
  export function dispatchInteractionPointerCancel(manager, x, y, options) {
166
+ const pointerId = options?.pointerId ?? 0;
167
+ const existingState = manager.pointerStates.get(pointerId);
168
+ if (existingState !== undefined)
169
+ resetInteractionClickState(existingState);
133
170
  if (!isPointerSignalNeeded(manager, cancelSignalNames))
134
171
  return;
135
- const pointerId = options?.pointerId ?? 0;
136
- const state = getInteractionPointerState(manager, pointerId);
172
+ const state = existingState ?? getInteractionPointerState(manager, pointerId);
137
173
  const captured = manager.pointerCaptures.get(pointerId) ?? null;
138
174
  const oldTarget = state.pointerOverTarget;
139
175
  const target = captured ?? state.pointerDownTarget ?? oldTarget;
@@ -142,7 +178,10 @@ export function dispatchInteractionPointerCancel(manager, x, y, options) {
142
178
  manager.pointerCaptures.delete(pointerId);
143
179
  setPointerData(target, null, x, y, -1, 0, 0, options);
144
180
  if (target !== null) {
145
- emitInteractionSignal(target, manager.root, 'onPointerCancel', _pointerData);
181
+ if (manager.dispatchLayers === null ||
182
+ dispatchInteractionLayers(manager, target, 'onPointerCancel', _pointerData)) {
183
+ emitInteractionSignal(target, manager.root, 'onPointerCancel', _pointerData);
184
+ }
146
185
  }
147
186
  if (oldTarget !== null) {
148
187
  dispatchPointerRolloverChange(manager, oldTarget, null);
@@ -154,11 +193,14 @@ export function dispatchInteractionPointerDown(manager, x, y, button = 0, option
154
193
  const pointerId = options?.pointerId ?? 0;
155
194
  const state = getInteractionPointerState(manager, pointerId);
156
195
  const target = findInteractionTarget(manager, x, y, pointerId);
196
+ resetPointerDoubleClickIfInvalid(manager, state, target, x, y, button, options?.timeStamp);
157
197
  if (target === null)
158
198
  return;
159
199
  state.pointerDownTarget = target;
160
200
  setPointerData(target, null, x, y, button, 0, 0, options);
161
- emitInteractionSignal(target, manager.root, 'onPointerDown', _pointerData);
201
+ if (manager.dispatchLayers === null || dispatchInteractionLayers(manager, target, 'onPointerDown', _pointerData)) {
202
+ emitInteractionSignal(target, manager.root, 'onPointerDown', _pointerData);
203
+ }
162
204
  }
163
205
  export function dispatchInteractionPointerMove(manager, x, y, button = 0, options) {
164
206
  // Run the move body when a rollover subscriber needs it OR a cursor backend is active — a scene that
@@ -170,6 +212,7 @@ export function dispatchInteractionPointerMove(manager, x, y, button = 0, option
170
212
  const state = getInteractionPointerState(manager, pointerId);
171
213
  const oldTarget = state.pointerOverTarget;
172
214
  const target = findInteractionTarget(manager, x, y, pointerId);
215
+ resetPointerDoubleClickIfInvalid(manager, state, target, x, y, button, options?.timeStamp);
173
216
  if (target === null && oldTarget === null)
174
217
  return;
175
218
  state.pointerOverTarget = target;
@@ -178,37 +221,54 @@ export function dispatchInteractionPointerMove(manager, x, y, button = 0, option
178
221
  dispatchPointerRolloverChange(manager, oldTarget, target);
179
222
  }
180
223
  if (target !== null) {
181
- emitInteractionSignal(target, manager.root, 'onPointerMove', _pointerData);
224
+ if (manager.dispatchLayers === null || dispatchInteractionLayers(manager, target, 'onPointerMove', _pointerData)) {
225
+ emitInteractionSignal(target, manager.root, 'onPointerMove', _pointerData);
226
+ }
182
227
  }
183
228
  }
184
- export function dispatchInteractionPointerUp(manager, x, y, button = 0, time = Date.now(), options) {
229
+ export function dispatchInteractionPointerUp(manager, x, y, button = 0, time, options) {
185
230
  if (!isPointerSignalNeeded(manager, upSignalNames))
186
231
  return;
232
+ const clickTime = time ?? options?.timeStamp ?? 0;
187
233
  const pointerId = options?.pointerId ?? 0;
188
234
  const state = getInteractionPointerState(manager, pointerId);
189
235
  const downTarget = state.pointerDownTarget;
190
236
  const target = findInteractionTarget(manager, x, y, pointerId);
237
+ resetPointerDoubleClickIfInvalid(manager, state, target, x, y, button, clickTime);
191
238
  state.pointerDownTarget = null;
192
239
  setPointerData(target ?? downTarget, null, x, y, button, 0, 0, options);
193
240
  if (target !== null) {
194
- emitInteractionSignal(target, manager.root, 'onPointerUp', _pointerData);
241
+ if (manager.dispatchLayers === null || dispatchInteractionLayers(manager, target, 'onPointerUp', _pointerData)) {
242
+ emitInteractionSignal(target, manager.root, 'onPointerUp', _pointerData);
243
+ }
195
244
  }
196
245
  if (downTarget === null)
197
246
  return;
198
247
  if (target === downTarget) {
199
- emitInteractionSignal(target, manager.root, 'onClick', _pointerData);
200
- if (state.lastClickTarget === target && time - state.lastClickTime <= manager.doubleClickDelay) {
201
- emitInteractionSignal(target, manager.root, 'onDoubleClick', _pointerData);
248
+ if (manager.dispatchLayers === null || dispatchInteractionLayers(manager, target, 'onClick', _pointerData)) {
249
+ emitInteractionSignal(target, manager.root, 'onClick', _pointerData);
250
+ }
251
+ const legacyElapsed = clickTime - state.lastClickTime;
252
+ if (state.lastClickTarget === target && legacyElapsed >= 0 && legacyElapsed <= manager.doubleClickDelay) {
253
+ if (manager.dispatchLayers === null ||
254
+ dispatchInteractionLayers(manager, target, 'onDoubleClick', _pointerData)) {
255
+ emitInteractionSignal(target, manager.root, 'onDoubleClick', _pointerData);
256
+ }
202
257
  state.lastClickTarget = null;
203
258
  state.lastClickTime = -Infinity;
204
259
  }
205
260
  else {
206
261
  state.lastClickTarget = target;
207
- state.lastClickTime = time;
262
+ state.lastClickTime = clickTime;
208
263
  }
264
+ dispatchPointerDoubleClick(manager, state, target, x, y, button, clickTime);
209
265
  }
210
266
  else {
211
- emitInteractionSignal(downTarget, manager.root, 'onReleaseOutside', _pointerData);
267
+ resetInteractionClickState(state);
268
+ if (manager.dispatchLayers === null ||
269
+ dispatchInteractionLayers(manager, downTarget, 'onReleaseOutside', _pointerData)) {
270
+ emitInteractionSignal(downTarget, manager.root, 'onReleaseOutside', _pointerData);
271
+ }
212
272
  }
213
273
  }
214
274
  export function dispatchInteractionWheel(manager, x, y, deltaX = 0, deltaY = 0, options) {
@@ -221,8 +281,15 @@ export function enableInteractionSignals(source) {
221
281
  export function getInteractionSignals(source) {
222
282
  return getNodeRuntime(source).interactionSignals;
223
283
  }
284
+ /** Re-resolves and immediately applies the cursor for the manager's current rollover target. */
285
+ export function invalidateInteractionCursor(manager) {
286
+ applyInteractionCursor(manager, manager.cursorTarget);
287
+ }
224
288
  export function releaseInteractionPointer(manager, pointerId) {
225
289
  manager.pointerCaptures.delete(pointerId);
290
+ const state = manager.pointerStates.get(pointerId);
291
+ if (state !== undefined)
292
+ resetInteractionClickState(state);
226
293
  }
227
294
  /**
228
295
  * Installs the connect-time guard hook consulted by `connectInteractionSignal`; `null` uninstalls it.
@@ -233,33 +300,47 @@ export function setInteractionConnectGuard(guard) {
233
300
  interactionConnectGuard = guard;
234
301
  }
235
302
  function dispatchKeyboardSignal(manager, name, key, keyCode, modifiers) {
236
- if (!manager.enabled || !hasInteractionSignalSubscriber(manager, name))
303
+ if (!manager.enabled || (manager.dispatchLayers === null && !hasInteractionSignalSubscriber(manager, name)))
237
304
  return;
238
305
  setKeyboardData(key, keyCode, modifiers);
239
- emitInteractionSignal(manager.root, manager.root, name, _keyboardData);
306
+ if (manager.dispatchLayers === null || dispatchInteractionLayers(manager, manager.root, name, _keyboardData)) {
307
+ emitInteractionSignal(manager.root, manager.root, name, _keyboardData);
308
+ }
240
309
  }
241
310
  function dispatchPointerRolloverChange(manager, oldTarget, target) {
242
311
  if (oldTarget !== null) {
243
- emitInteractionSignal(oldTarget, manager.root, 'onPointerOut', _pointerData);
312
+ if (manager.dispatchLayers === null ||
313
+ dispatchInteractionLayers(manager, oldTarget, 'onPointerOut', _pointerData)) {
314
+ emitInteractionSignal(oldTarget, manager.root, 'onPointerOut', _pointerData);
315
+ }
244
316
  }
245
317
  const oldChain = oldTarget !== null ? getInteractionChain(oldTarget, manager.root) : [];
246
318
  const newChain = target !== null ? getInteractionChain(target, manager.root) : [];
247
319
  for (const node of oldChain) {
248
320
  if (newChain.indexOf(node) === -1) {
249
321
  setInteractionSignalCurrentTarget(_pointerData, node, node);
250
- emitInteractionSignalDirect(node, 'onPointerRollOut', _pointerData);
322
+ if (manager.dispatchLayers === null ||
323
+ dispatchInteractionLayers(manager, node, 'onPointerRollOut', _pointerData)) {
324
+ emitInteractionSignalDirect(node, 'onPointerRollOut', _pointerData);
325
+ }
251
326
  }
252
327
  }
253
328
  for (let i = newChain.length - 1; i >= 0; i--) {
254
329
  const node = newChain[i];
255
330
  if (oldChain.indexOf(node) === -1) {
256
331
  setInteractionSignalCurrentTarget(_pointerData, node, node);
257
- emitInteractionSignalDirect(node, 'onPointerRollOver', _pointerData);
332
+ if (manager.dispatchLayers === null ||
333
+ dispatchInteractionLayers(manager, node, 'onPointerRollOver', _pointerData)) {
334
+ emitInteractionSignalDirect(node, 'onPointerRollOver', _pointerData);
335
+ }
258
336
  }
259
337
  }
260
338
  if (target !== null) {
261
- emitInteractionSignal(target, manager.root, 'onPointerOver', _pointerData);
339
+ if (manager.dispatchLayers === null || dispatchInteractionLayers(manager, target, 'onPointerOver', _pointerData)) {
340
+ emitInteractionSignal(target, manager.root, 'onPointerOver', _pointerData);
341
+ }
262
342
  }
343
+ manager.cursorTarget = target;
263
344
  applyInteractionCursor(manager, target);
264
345
  }
265
346
  /**
@@ -295,7 +376,9 @@ function dispatchPointerSignalAt(manager, name, x, y, button, deltaX = 0, deltaY
295
376
  if (target === null)
296
377
  return;
297
378
  setPointerData(target, null, x, y, button, deltaX, deltaY, options);
298
- emitInteractionSignal(target, manager.root, name, _pointerData);
379
+ if (manager.dispatchLayers === null || dispatchInteractionLayers(manager, target, name, _pointerData)) {
380
+ emitInteractionSignal(target, manager.root, name, _pointerData);
381
+ }
299
382
  }
300
383
  function emitInteractionSignal(target, root, name, data) {
301
384
  let current = target;
@@ -314,6 +397,17 @@ function emitInteractionSignalDirect(target, name, data) {
314
397
  if (signal !== null)
315
398
  emitSignal(signal, data);
316
399
  }
400
+ function dispatchInteractionLayers(manager, target, name, data) {
401
+ const layers = manager.dispatchLayers;
402
+ if (layers === null)
403
+ return true;
404
+ const snapshot = layers.slice();
405
+ for (let i = 0; i < snapshot.length; i++) {
406
+ if (!snapshot[i].layer(target, name, data))
407
+ return false;
408
+ }
409
+ return true;
410
+ }
317
411
  function decrementInteractionSignalSubscriberCount(manager, name) {
318
412
  const count = manager.signalSubscriberCounts.get(name) ?? 0;
319
413
  if (count <= 1) {
@@ -334,12 +428,82 @@ function findInteractionTarget(manager, x, y, pointerId) {
334
428
  const root = manager.root;
335
429
  return (manager.precise ? findGraphHitTargetPrecise(root, x, y) : findGraphHitTarget(root, x, y));
336
430
  }
431
+ function dispatchPointerDoubleClick(manager, state, target, x, y, button, time) {
432
+ const interactionState = getNodeInteractionState(target);
433
+ if (interactionState?.pointerDoubleClickEnabled !== true) {
434
+ resetPointerDoubleClickState(state);
435
+ return;
436
+ }
437
+ if (isPointerDoubleClickCandidateValid(manager, state, target, x, y, button, time)) {
438
+ resetPointerDoubleClickState(state);
439
+ if (manager.dispatchLayers === null ||
440
+ dispatchInteractionLayers(manager, target, 'onPointerDoubleClick', _pointerData)) {
441
+ emitInteractionSignal(target, manager.root, 'onPointerDoubleClick', _pointerData);
442
+ }
443
+ return;
444
+ }
445
+ state.lastPointerClickButton = button;
446
+ state.lastPointerClickInteractionState = interactionState;
447
+ state.lastPointerClickTarget = target;
448
+ state.lastPointerClickTime = time;
449
+ state.lastPointerClickX = x;
450
+ state.lastPointerClickY = y;
451
+ }
452
+ function isPointerDoubleClickCandidateValid(manager, state, target, x, y, button, time) {
453
+ if (target === null || state.lastPointerClickTarget !== target || state.lastPointerClickButton !== button) {
454
+ return false;
455
+ }
456
+ const interactionState = getNodeInteractionState(target);
457
+ if (interactionState?.pointerDoubleClickEnabled !== true ||
458
+ interactionState !== state.lastPointerClickInteractionState) {
459
+ return false;
460
+ }
461
+ const dx = x - state.lastPointerClickX;
462
+ const dy = y - state.lastPointerClickY;
463
+ if (dx * dx + dy * dy > manager.doubleClickDistance * manager.doubleClickDistance)
464
+ return false;
465
+ if (time !== undefined) {
466
+ const elapsed = time - state.lastPointerClickTime;
467
+ if (elapsed < 0 || elapsed > manager.doubleClickDelay)
468
+ return false;
469
+ }
470
+ return true;
471
+ }
472
+ function resetInteractionClickState(state) {
473
+ state.lastClickTarget = null;
474
+ state.lastClickTime = -Infinity;
475
+ resetPointerDoubleClickState(state);
476
+ }
477
+ function resetInteractionClickStates(manager) {
478
+ for (const state of manager.pointerStates.values())
479
+ resetInteractionClickState(state);
480
+ }
481
+ function resetPointerDoubleClickIfInvalid(manager, state, target, x, y, button, time) {
482
+ if (state.lastPointerClickTarget !== null &&
483
+ !isPointerDoubleClickCandidateValid(manager, state, target, x, y, button, time)) {
484
+ resetPointerDoubleClickState(state);
485
+ }
486
+ }
487
+ function resetPointerDoubleClickState(state) {
488
+ state.lastPointerClickButton = -1;
489
+ state.lastPointerClickInteractionState = null;
490
+ state.lastPointerClickTarget = null;
491
+ state.lastPointerClickTime = -Infinity;
492
+ state.lastPointerClickX = 0;
493
+ state.lastPointerClickY = 0;
494
+ }
337
495
  function getInteractionPointerState(manager, pointerId) {
338
496
  let state = manager.pointerStates.get(pointerId);
339
497
  if (state === undefined) {
340
498
  state = {
341
499
  lastClickTarget: null,
342
500
  lastClickTime: -Infinity,
501
+ lastPointerClickButton: -1,
502
+ lastPointerClickInteractionState: null,
503
+ lastPointerClickTarget: null,
504
+ lastPointerClickTime: -Infinity,
505
+ lastPointerClickX: 0,
506
+ lastPointerClickY: 0,
343
507
  pointerDownTarget: null,
344
508
  pointerOverTarget: null,
345
509
  };
@@ -395,8 +559,12 @@ function isInteractionSignalCancelled(source, name) {
395
559
  return getInteractionSignal(source, name)?.data?.cancelled === true;
396
560
  }
397
561
  function isPointerSignalNeeded(manager, names) {
398
- if (!manager.enabled)
562
+ if (!manager.enabled) {
563
+ resetInteractionClickStates(manager);
399
564
  return false;
565
+ }
566
+ if (manager.dispatchLayers !== null)
567
+ return true;
400
568
  for (const name of names) {
401
569
  if (hasInteractionSignalSubscriber(manager, name))
402
570
  return true;
@@ -481,15 +649,23 @@ function isTransform2DNode(source) {
481
649
  }
482
650
  let interactionConnectGuard = null;
483
651
  const cancelSignalNames = ['onPointerCancel', 'onPointerOut', 'onPointerRollOut'];
484
- const downSignalNames = ['onClick', 'onDoubleClick', 'onPointerCancel', 'onPointerDown', 'onReleaseOutside'];
652
+ const downSignalNames = [
653
+ 'onClick',
654
+ 'onDoubleClick',
655
+ 'onPointerCancel',
656
+ 'onPointerDoubleClick',
657
+ 'onPointerDown',
658
+ 'onReleaseOutside',
659
+ ];
485
660
  const moveSignalNames = [
661
+ 'onPointerDoubleClick',
486
662
  'onPointerMove',
487
663
  'onPointerOut',
488
664
  'onPointerOver',
489
665
  'onPointerRollOut',
490
666
  'onPointerRollOver',
491
667
  ];
492
- const upSignalNames = ['onClick', 'onDoubleClick', 'onPointerUp', 'onReleaseOutside'];
668
+ const upSignalNames = ['onClick', 'onDoubleClick', 'onPointerDoubleClick', 'onPointerUp', 'onReleaseOutside'];
493
669
  const _keyboardData = {
494
670
  altKey: false,
495
671
  ctrlKey: false,