import { createContext, useContext } from "@solidrt/core" import type { PointerFeed } from "@solidrt/core" import type { SpriteGroup, SpriteLayer as LayerHandle } from "../layer.ts" import type { ViewHandle } from "../views.ts" export let LayerContext = createContext() export let GroupContext = createContext(null) // The nearest view: the 's own, or the enclosing 's; // null under a leafless layer (output={false}) until a // provides one. Null-default on purpose, like GroupContext. export let ViewportContext = createContext(null) // The nearest view's pointer feed (its owner's `pointer` prop), null when // none was handed in. export let PointerContext = createContext(null) // The nearest view's size in view pixels as a signal (view.size(), // reactive); null where ViewportContext is. export let ViewportSizeContext = createContext<(() => { width: number; height: number }) | null>(null) type LayerCtx = { layer: LayerHandle parent: SpriteGroup | null readonly viewport: ViewHandle pointer: PointerFeed | null /** The nearest view's size in view pixels, reactive - `viewport.size()` * as a signal: a fill view's follows its leaf, a fixed one's its props. * What a HUD or a view-space effect sizes from without polling; the * same throw as `viewport` where there is no view. */ readonly viewportSize: () => { width: number; height: number } } /** * The enclosing layer, parent group, view and pointer feed - the * imperative escape hatch inside a component subtree (throws outside a * ``), the same shape as @solidrt/3d's useScene. `parent` is * the enclosing ``'s handle (null at the layer root); pass it on * to addSprite/addGroup so imperative sprites mount where the JSX sits. * `viewport` is the nearest view: the ``'s own, or inside a * `` that view - what a `` drives, and where a custom * `output` leaf takes its `handlers`. Reading it under a * `` throws: such a layer shows only through * its `` children, so controls and leaves go inside one. * `pointer` is that view's feed (the owner's `pointer` prop), or null. */ export function useSpriteLayer(): LayerCtx { let layer = useContext(LayerContext) let parent = useContext(GroupContext) let viewport = useContext(ViewportContext) let pointer = useContext(PointerContext) let viewportSize = useContext(ViewportSizeContext) let noView = () => new Error("useSpriteLayer: no view here - a shows only through its children; put camera controls and leaves inside one") return { layer, parent, pointer, get viewport() { if (viewport === null) throw noView() return viewport }, get viewportSize() { if (viewportSize === null) throw noView() return viewportSize }, } }