diff --git a/packages/uikit/src/components/container.ts b/packages/uikit/src/components/container.ts index fe2b2460..dfb0f291 100644 --- a/packages/uikit/src/components/container.ts +++ b/packages/uikit/src/components/container.ts @@ -36,9 +36,9 @@ import { Initializers } from '../utils.js' import { darkPropertyTransformers } from '../dark.js' import { getDefaultPanelMaterialConfig } from '../panel/index.js' import { + computeAnyAncestorsHaveListeners, computedInheritableProperty, - computeOutgoingDefaultProperties, - setupInteractableDecendant, + computeDefaultProperties, setupPointerEvents, UpdateMatrixWorldProperties, } from '../internals.js' @@ -66,7 +66,7 @@ export function createContainer( parentCtx: ParentContext, style: Signal, properties: Signal, - incommingDefaultProperties: Signal, + defaultProperties: Signal, object: Object3DRef, childrenContainer: Object3DRef, ) { @@ -79,7 +79,7 @@ export function createContainer( setupCursorCleanup(hoveredSignal, initializers) //properties - const mergedProperties = computedMergedProperties(style, properties, incommingDefaultProperties, { + const mergedProperties = computedMergedProperties(style, properties, defaultProperties, { ...darkPropertyTransformers, ...createResponsivePropertyTransformers(parentCtx.root.size), ...createHoverPropertyTransformers(hoveredSignal), @@ -136,16 +136,6 @@ export function createContainer( scrollbarWidth, initializers, ) - const interactionPanel = createInteractionPanel( - orderInfo, - parentCtx.root, - parentCtx.clippingRect, - flexState.size, - globalMatrix, - initializers, - ) - setupPointerEvents(mergedProperties, interactionPanel, initializers) - setupInteractableDecendant(mergedProperties, parentCtx.root, interactionPanel, initializers) const scrollHandlers = computedScrollHandlers( scrollPosition, parentCtx.anyAncestorScrollable, @@ -157,6 +147,19 @@ export function createContainer( initializers, ) + const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers) + const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + + const interactionPanel = createInteractionPanel( + orderInfo, + parentCtx.root, + parentCtx.clippingRect, + flexState.size, + globalMatrix, + initializers, + ) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, interactionPanel, initializers, false) + const updateMatrixWorld = computedInheritableProperty(mergedProperties, 'updateMatrixWorld', false) setupMatrixWorldUpdate(updateMatrixWorld, false, object, parentCtx.root, globalMatrix, initializers, false) setupMatrixWorldUpdate(updateMatrixWorld, false, interactionPanel, parentCtx.root, globalMatrix, initializers, true) @@ -165,7 +168,8 @@ export function createContainer( setupClippedListeners(style, properties, isClipped, initializers) return Object.assign(flexState, { - defaultProperties: computeOutgoingDefaultProperties(mergedProperties), + ancestorsHaveListeners, + defaultProperties: computeDefaultProperties(mergedProperties), globalMatrix, isClipped, isVisible, @@ -178,14 +182,7 @@ export function createContainer( root: parentCtx.root, scrollPosition, interactionPanel, - handlers: computedHandlers( - style, - properties, - incommingDefaultProperties, - hoveredSignal, - activeSignal, - scrollHandlers, - ), + handlers, initializers, - }) + }) satisfies ParentContext } diff --git a/packages/uikit/src/components/content.ts b/packages/uikit/src/components/content.ts index 9cd4f00c..8053a49c 100644 --- a/packages/uikit/src/components/content.ts +++ b/packages/uikit/src/components/content.ts @@ -13,13 +13,13 @@ import { Signal, computed, effect, signal, untracked } from '@preact/signals-cor import { VisibilityProperties, WithConditionals, + computeAnyAncestorsHaveListeners, computedGlobalMatrix, computedHandlers, computedIsVisible, computedMergedProperties, createNode, keepAspectRatioPropertyTransformer, - setupInteractableDecendant, setupMatrixWorldUpdate, setupPointerEvents, } from './utils.js' @@ -140,8 +140,10 @@ export function createContent( ) setupMatrixWorldUpdate(true, true, object, parentCtx.root, globalMatrix, initializers, false) - setupPointerEvents(mergedProperties, object, initializers) - setupInteractableDecendant(mergedProperties, parentCtx.root, object, initializers) + + const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal) + const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, object, initializers, true) setupLayoutListeners(style, properties, flexState.size, initializers) setupClippedListeners(style, properties, isClipped, initializers) @@ -163,7 +165,7 @@ export function createContent( initializers, ), interactionPanel, - handlers: computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal), + handlers, initializers, }) } diff --git a/packages/uikit/src/components/custom.ts b/packages/uikit/src/components/custom.ts index 9596f3a1..12c444aa 100644 --- a/packages/uikit/src/components/custom.ts +++ b/packages/uikit/src/components/custom.ts @@ -13,15 +13,14 @@ import { Signal, effect, signal } from '@preact/signals-core' import { VisibilityProperties, WithConditionals, + computeAnyAncestorsHaveListeners, computedGlobalMatrix, computedHandlers, computedIsVisible, computedMergedProperties, createNode, setupMatrixWorldUpdate, - setupInteractableDecendant, setupPointerEvents, - computeOutgoingDefaultProperties, } from './utils.js' import { Initializers } from '../utils.js' import { Listeners, setupLayoutListeners, setupClippedListeners } from '../listeners.js' @@ -147,8 +146,9 @@ export function createCustomContainer( setupMatrixWorldUpdate(true, true, object, parentCtx.root, globalMatrix, initializers, false) - setupPointerEvents(mergedProperties, object, initializers) - setupInteractableDecendant(mergedProperties, parentCtx.root, object, initializers) + const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal) + const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, object, initializers, true) setupLayoutListeners(style, properties, flexState.size, initializers) setupClippedListeners(style, properties, isClipped, initializers) @@ -159,7 +159,7 @@ export function createCustomContainer( isVisible, mergedProperties, root: parentCtx.root, - handlers: computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal), + handlers, initializers, }) } diff --git a/packages/uikit/src/components/icon.ts b/packages/uikit/src/components/icon.ts index eba16b9f..aa3f79cb 100644 --- a/packages/uikit/src/components/icon.ts +++ b/packages/uikit/src/components/icon.ts @@ -1,8 +1,8 @@ import { Signal, effect, signal } from '@preact/signals-core' -import { BufferGeometry, Color, Group, Material, Mesh, MeshBasicMaterial, Plane, ShapeGeometry } from 'three' +import { BufferGeometry, Group, Material, Mesh, MeshBasicMaterial, Plane, ShapeGeometry } from 'three' import { Listeners } from '../index.js' import { Object3DRef, ParentContext } from '../context.js' -import { FlexNode, FlexNodeState, YogaProperties, createFlexNodeState } from '../flex/index.js' +import { FlexNodeState, YogaProperties, createFlexNodeState } from '../flex/index.js' import { ElementType, OrderInfo, ZIndexProperties, computedOrderInfo, setupRenderOrder } from '../order.js' import { PanelProperties, createInstancedPanel } from '../panel/instanced-panel.js' import { WithAllAliases } from '../properties/alias.js' @@ -13,18 +13,17 @@ import { VisibilityProperties, WithConditionals, applyAppearancePropertiesToGroup, - computeOutgoingDefaultProperties, + computeAnyAncestorsHaveListeners, computedGlobalMatrix, computedHandlers, computedIsVisible, computedMergedProperties, createNode, keepAspectRatioPropertyTransformer, - setupInteractableDecendant, setupMatrixWorldUpdate, setupPointerEvents, } from './utils.js' -import { Initializers, Subscriptions, fitNormalizedContentInside } from '../utils.js' +import { Initializers, fitNormalizedContentInside } from '../utils.js' import { makeClippedCast } from '../panel/interaction-panel-mesh.js' import { computedIsClipped, createGlobalClippingPlanes } from '../clipping.js' import { setupLayoutListeners, setupClippedListeners } from '../listeners.js' @@ -36,7 +35,7 @@ import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader.js' import { AppearanceProperties } from './svg.js' import { PanelGroupProperties, computedPanelGroupDependencies, getDefaultPanelMaterialConfig } from '../panel/index.js' import { darkPropertyTransformers } from '../dark.js' -import { computedInheritableProperty, MergedProperties } from '../properties/index.js' +import { MergedProperties } from '../properties/index.js' export type InheritableIconProperties = WithClasses< WithConditionals< @@ -138,8 +137,9 @@ export function createIcon( setupMatrixWorldUpdate(true, true, object, parentCtx.root, globalMatrix, initializers, false) - setupPointerEvents(mergedProperties, object, initializers) - setupInteractableDecendant(mergedProperties, parentCtx.root, object, initializers) + const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal) + const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, object, initializers, false) setupLayoutListeners(style, properties, flexState.size, initializers) setupClippedListeners(style, properties, isClipped, initializers) @@ -151,7 +151,7 @@ export function createIcon( mergedProperties, initializers, iconGroup, - handlers: computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal), + handlers, interactionPanel: createInteractionPanel( orderInfo, parentCtx.root, diff --git a/packages/uikit/src/components/image.ts b/packages/uikit/src/components/image.ts index f0cb9939..226642bc 100644 --- a/packages/uikit/src/components/image.ts +++ b/packages/uikit/src/components/image.ts @@ -41,7 +41,8 @@ import { UpdateMatrixWorldProperties, VisibilityProperties, WithConditionals, - computeOutgoingDefaultProperties, + computeAnyAncestorsHaveListeners, + computeDefaultProperties, computedGlobalMatrix, computedHandlers, computedIsVisible, @@ -49,7 +50,6 @@ import { createNode, keepAspectRatioPropertyTransformer, loadResourceWithParams, - setupInteractableDecendant, setupMatrixWorldUpdate, setupPointerEvents, } from './utils.js' @@ -176,6 +176,17 @@ export function createImage( scrollbarWidth, initializers, ) + const scrollHandlers = computedScrollHandlers( + scrollPosition, + parentCtx.anyAncestorScrollable, + flexState, + object, + scrollbarWidth, + properties, + parentCtx.root, + initializers, + ) + const imageMesh = createImageMesh( mergedProperties, texture, @@ -188,18 +199,9 @@ export function createImage( initializers, ) - setupPointerEvents(mergedProperties, imageMesh, initializers) - setupInteractableDecendant(mergedProperties, parentCtx.root, imageMesh, initializers) - const scrollHandlers = computedScrollHandlers( - scrollPosition, - parentCtx.anyAncestorScrollable, - flexState, - object, - scrollbarWidth, - properties, - parentCtx.root, - initializers, - ) + const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers) + const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, imageMesh, initializers, false) const updateMatrixWorld = computedInheritableProperty(mergedProperties, 'updateMatrixWorld', false) setupMatrixWorldUpdate(updateMatrixWorld, false, object, parentCtx.root, globalMatrix, initializers, false) @@ -209,7 +211,8 @@ export function createImage( setupClippedListeners(style, properties, isClipped, initializers) return Object.assign(flexState, { - defaultProperties: computeOutgoingDefaultProperties(mergedProperties), + ancestorsHaveListeners, + defaultProperties: computeDefaultProperties(mergedProperties), globalMatrix, scrollPosition, isClipped, @@ -217,14 +220,14 @@ export function createImage( mergedProperties, anyAncestorScrollable: computedAnyAncestorScrollable(flexState.scrollable, parentCtx.anyAncestorScrollable), initializers, - handlers: computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers), + handlers, interactionPanel: imageMesh, clippingRect: computedClippingRect(globalMatrix, flexState, parentCtx.root.pixelSize, parentCtx.clippingRect), childrenMatrix, node, orderInfo, root: parentCtx.root, - }) + }) satisfies ParentContext } let imageMaterialConfig: PanelMaterialConfig | undefined diff --git a/packages/uikit/src/components/input.ts b/packages/uikit/src/components/input.ts index ce12b3b7..16c5b7e7 100644 --- a/packages/uikit/src/components/input.ts +++ b/packages/uikit/src/components/input.ts @@ -21,13 +21,12 @@ import { UpdateMatrixWorldProperties, VisibilityProperties, WithConditionals, - computeOutgoingDefaultProperties, + computeAnyAncestorsHaveListeners, computedGlobalMatrix, computedHandlers, computedIsVisible, computedMergedProperties, createNode, - setupInteractableDecendant, setupMatrixWorldUpdate, setupPointerEvents, } from './utils.js' @@ -250,9 +249,6 @@ export function createInput( initializers, ) - setupPointerEvents(mergedProperties, interactionPanel, initializers) - setupInteractableDecendant(mergedProperties, parentCtx.root, interactionPanel, initializers) - const updateMatrixWorld = computedInheritableProperty(mergedProperties, 'updateMatrixWorld', false) setupMatrixWorldUpdate(updateMatrixWorld, false, object, parentCtx.root, globalMatrix, initializers, false) setupMatrixWorldUpdate(updateMatrixWorld, false, interactionPanel, parentCtx.root, globalMatrix, initializers, true) @@ -305,6 +301,18 @@ export function createInput( }) const selectionHandlers = computedSelectionHandlers(type, valueSignal, flexState, instancedTextRef, focus, disabled) + const handlers = computedHandlers( + style, + properties, + defaultProperties, + hoveredSignal, + activeSignal, + selectionHandlers, + 'text', + ) + const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, interactionPanel, initializers, false) + return Object.assign(flexState, { globalMatrix, isClipped, @@ -317,15 +325,7 @@ export function createInput( element, node: nodeSignal, interactionPanel, - handlers: computedHandlers( - style, - properties, - defaultProperties, - hoveredSignal, - activeSignal, - selectionHandlers, - 'text', - ), + handlers, initializers, }) } diff --git a/packages/uikit/src/components/root.ts b/packages/uikit/src/components/root.ts index 4ef54e13..1ddb25f6 100644 --- a/packages/uikit/src/components/root.ts +++ b/packages/uikit/src/components/root.ts @@ -1,5 +1,5 @@ import { Signal, computed, signal } from '@preact/signals-core' -import { Object3DRef, RootContext } from '../context.js' +import { Object3DRef, ParentContext, RootContext } from '../context.js' import { FlexNode, YogaProperties, createFlexNodeState } from '../flex/index.js' import { LayoutListeners, ScrollListeners, setupLayoutListeners } from '../listeners.js' import { PanelProperties, createInstancedPanel } from '../panel/instanced-panel.js' @@ -25,11 +25,11 @@ import { UpdateMatrixWorldProperties, VisibilityProperties, WithConditionals, - computeOutgoingDefaultProperties, + computeAnyAncestorsHaveListeners, + computeDefaultProperties, computedHandlers, computedIsVisible, computedMergedProperties, - setupInteractableDecendant, setupMatrixWorldUpdate, setupPointerEvents, } from './utils.js' @@ -227,10 +227,6 @@ export function createRoot( initializers, ) - const outgoingDefaultProperties = computeOutgoingDefaultProperties(mergedProperties) - setupPointerEvents(mergedProperties, interactionPanel, initializers) - setupInteractableDecendant(mergedProperties, rootCtx, interactionPanel, initializers) - //setup matrix world updates initializers.push(() => { if (childrenContainer.current != null) { @@ -262,8 +258,13 @@ export function createRoot( initializers, ) + const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers) + const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(undefined, handlers) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, rootCtx, interactionPanel, initializers, false) + return Object.assign(flexState, { - defaultProperties: outgoingDefaultProperties, + ancestorsHaveListeners, + defaultProperties: computeDefaultProperties(mergedProperties), globalMatrix, isVisible, scrollPosition, @@ -275,9 +276,9 @@ export function createRoot( orderInfo, initializers, interactionPanel, - handlers: computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers), + handlers, root: rootCtx, - }) + }) satisfies ParentContext } function createDeferredRequestLayoutCalculation( diff --git a/packages/uikit/src/components/svg.ts b/packages/uikit/src/components/svg.ts index f3d5976f..0df3be9e 100644 --- a/packages/uikit/src/components/svg.ts +++ b/packages/uikit/src/components/svg.ts @@ -55,10 +55,10 @@ import { PanelGroupProperties, computedPanelGroupDependencies, getDefaultPanelMa import { KeepAspectRatioProperties } from './image.js' import { computedInheritableProperty, - computeOutgoingDefaultProperties, - setupInteractableDecendant, + computeDefaultProperties, setupMatrixWorldUpdate, setupPointerEvents, + computeAnyAncestorsHaveListeners, } from '../internals.js' export type InheritableSvgProperties = WithClasses< @@ -209,17 +209,17 @@ export function createSvg( initializers, ) - const outgoingDefaultProperties = computeOutgoingDefaultProperties(mergedProperties) - setupPointerEvents(mergedProperties, centerGroup, initializers) - setupPointerEvents(mergedProperties, interactionPanel, initializers) - setupInteractableDecendant(mergedProperties, parentCtx.root, centerGroup, initializers) - setupInteractableDecendant(mergedProperties, parentCtx.root, interactionPanel, initializers) + const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers) + const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(undefined, handlers) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, centerGroup, initializers, false) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, interactionPanel, initializers, false) setupLayoutListeners(style, properties, flexState.size, initializers) setupClippedListeners(style, properties, isClipped, initializers) return Object.assign(flexState, { - defaultProperties: outgoingDefaultProperties, + ancestorsHaveListeners, + defaultProperties: computeDefaultProperties(mergedProperties), globalMatrix, scrollPosition, isClipped, @@ -233,9 +233,9 @@ export function createSvg( root: parentCtx.root, initializers, centerGroup, - handlers: computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers), + handlers, interactionPanel, - }) + }) satisfies ParentContext } function createCenterGroup( diff --git a/packages/uikit/src/components/text.ts b/packages/uikit/src/components/text.ts index 2431c32b..a1a16e1c 100644 --- a/packages/uikit/src/components/text.ts +++ b/packages/uikit/src/components/text.ts @@ -18,7 +18,6 @@ import { computedIsVisible, computedMergedProperties, createNode, - setupInteractableDecendant, setupPointerEvents, setupMatrixWorldUpdate, } from './utils.js' @@ -36,8 +35,8 @@ import { } from '../text/index.js' import { darkPropertyTransformers } from '../dark.js' import { + computeAnyAncestorsHaveListeners, computedInheritableProperty, - computeOutgoingDefaultProperties, UpdateMatrixWorldProperties, } from '../internals.js' @@ -150,8 +149,9 @@ export function createText( initializers, ) - setupPointerEvents(mergedProperties, interactionPanel, initializers) - setupInteractableDecendant(mergedProperties, parentCtx.root, interactionPanel, initializers) + const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal) + const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(undefined, handlers) + setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, interactionPanel, initializers, false) const updateMatrixWorld = computedInheritableProperty(mergedProperties, 'updateMatrixWorld', false) setupMatrixWorldUpdate(updateMatrixWorld, false, object, parentCtx.root, globalMatrix, initializers, false) @@ -166,7 +166,7 @@ export function createText( isVisible, mergedProperties, interactionPanel, - handlers: computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal), + handlers, initializers, }) } diff --git a/packages/uikit/src/components/utils.ts b/packages/uikit/src/components/utils.ts index 512c8c0f..dabc0130 100644 --- a/packages/uikit/src/components/utils.ts +++ b/packages/uikit/src/components/utils.ts @@ -1,4 +1,4 @@ -import { ReadonlySignal, Signal, computed, effect } from '@preact/signals-core' +import { ReadonlySignal, Signal, computed, effect, signal } from '@preact/signals-core' import { BufferGeometry, Color, Material, Matrix4, Mesh, MeshBasicMaterial, Object3D } from 'three' import { WithActive, addActiveHandlers } from '../active.js' import { WithPreferredColorScheme } from '../dark.js' @@ -168,7 +168,16 @@ export function computedHandlers( }) } -export function addHandlers(target: EventHandlers, handlers: EventHandlers | undefined) { +export function computeAnyAncestorsHaveListeners( + parentContext: ParentContext | undefined, + handlers: ReadonlySignal, +) { + return computed( + () => (parentContext?.ancestorsHaveListeners.value ?? false) || Object.keys(handlers.value).length > 0, + ) +} + +export function addHandlers(target: EventHandlers, handlers: EventHandlers | undefined): void { for (const key in handlers) { addHandler(key as keyof EventHandlers, target, handlers[key as keyof EventHandlers]) } @@ -312,7 +321,7 @@ export function setupMatrixWorldUpdate( ) } -export function computeOutgoingDefaultProperties(propertiesSignal: Signal) { +export function computeDefaultProperties(propertiesSignal: Signal) { return { pointerEvents: computedInheritableProperty( propertiesSignal, @@ -346,56 +355,54 @@ export type OutgoingDefaultProperties = { export function setupPointerEvents( propertiesSignal: Signal, - targetRef: Object3D | Object3DRef, - initializers: Initializers, -) { - initializers.push(() => { - const target = targetRef instanceof Object3D ? targetRef : targetRef.current - if (target == null) { - return () => {} - } - const properties = propertiesSignal.value - target.defaultPointerEvents = 'auto' - return effect(() => { - target.pointerEvents = properties.read('pointerEvents', undefined) - target.pointerEventsOrder = properties.read( - 'pointerEventsOrder', - undefined, - ) - target.pointerEventsType = properties.read( - 'pointerEventsType', - undefined, - ) - }) - }) -} - -export function setupInteractableDecendant( - propertiesSignal: Signal, + ancestorsHaveListeners: ReadonlySignal, rootContext: RootContext, targetRef: Object3D | Object3DRef, initializers: Initializers, + canHaveNonUikitChildren: boolean, ) { - initializers.push(() => - effect(() => { - if ( - propertiesSignal.value.read('pointerEvents', undefined) === 'none' - ) { - return - } - const descendants = rootContext.interactableDescendants + initializers.push( + () => { const target = targetRef instanceof Object3D ? targetRef : targetRef.current - if (descendants == null || target == null) { - return + if (target == null) { + return () => {} } - descendants.push(target) - return () => { - const index = descendants.indexOf(target) - if (index === -1) { + const properties = propertiesSignal.value + target.defaultPointerEvents = 'auto' + return effect(() => { + target.ancestorsHaveListeners = ancestorsHaveListeners.value + target.pointerEvents = properties.read('pointerEvents', undefined) + target.pointerEventsOrder = properties.read( + 'pointerEventsOrder', + undefined, + ) + target.pointerEventsType = properties.read( + 'pointerEventsType', + undefined, + ) + }) + }, + () => + effect(() => { + if ( + !canHaveNonUikitChildren && + propertiesSignal.value.read('pointerEvents', undefined) === 'none' + ) { return } - descendants.splice(index, 1) - } - }), + const descendants = rootContext.interactableDescendants + const target = targetRef instanceof Object3D ? targetRef : targetRef.current + if (descendants == null || target == null) { + return + } + descendants.push(target) + return () => { + const index = descendants.indexOf(target) + if (index === -1) { + return + } + descendants.splice(index, 1) + } + }), ) } diff --git a/packages/uikit/src/context.ts b/packages/uikit/src/context.ts index 6276d04c..7bf9bcc3 100644 --- a/packages/uikit/src/context.ts +++ b/packages/uikit/src/context.ts @@ -9,6 +9,7 @@ import { FlexNode } from './flex/index.js' export type ParentContext = Readonly<{ node: Signal anyAncestorScrollable: Signal + ancestorsHaveListeners: Signal clippingRect: Signal childrenMatrix: Signal orderInfo: Signal diff --git a/packages/uikit/src/panel/interaction-panel-mesh.ts b/packages/uikit/src/panel/interaction-panel-mesh.ts index 736c8112..f8d5b106 100644 --- a/packages/uikit/src/panel/interaction-panel-mesh.ts +++ b/packages/uikit/src/panel/interaction-panel-mesh.ts @@ -20,6 +20,7 @@ declare module 'three' { spherecast?(sphere: Sphere, intersects: Array): void intersectChildren?: boolean interactableDescendants?: Array + ancestorsHaveListeners?: boolean defaultPointerEvents?: PointerEventsProperties['pointerEvents'] } }