@dreamboard-games/sdk 0.5.0-alpha.11 → 0.5.0-alpha.13
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 +68 -1
- package/dist/{chunk-2IGXAYW4.js → chunk-W5G6VMMQ.js} +18 -15
- package/dist/chunk-W5G6VMMQ.js.map +1 -0
- package/dist/{chunk-D3F3GCMF.js → chunk-YUEMDRIH.js} +14 -4
- package/dist/chunk-YUEMDRIH.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +100 -3
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +22 -6
- package/dist/react.js +282 -33
- package/dist/react.js.map +1 -1
- package/dist/{model-BeslAXVA.d.ts → shortcuts-Chlx8o7p.d.ts} +93 -8
- package/dist/testing.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-2IGXAYW4.js.map +0 -1
- package/dist/chunk-D3F3GCMF.js.map +0 -1
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/gesture.tsx","../src/react/create-game-hook.tsx"],"sourcesContent":["import { createStore } from \"@tanstack/store\";\nimport { useSelector } from \"@tanstack/react-store\";\nimport {\n createContext,\n useContext,\n type CSSProperties,\n type DragEvent,\n type MouseEvent,\n type PointerEvent,\n} from \"react\";\nimport {\n createGestureRecognizer,\n magneticDropPoint,\n type GestureRecognizer,\n} from \"../headless/gesture.js\";\nimport { isSameDropTarget } from \"../headless/drop-targets.js\";\nimport type { Point } from \"../headless/features/pointer-session.js\";\nimport type {\n RuntimeDropTarget,\n RuntimeTargetOptions,\n} from \"../headless/targets.js\";\n\n/** The runtime surface of `dragFeature` that a gesture needs. */\nexport interface GestureDrag {\n readonly active: { readonly target: RuntimeDropTarget | null } | null;\n getCanDrag(cardId: string, options?: RuntimeTargetOptions): boolean;\n getDropTargets(): readonly RuntimeDropTarget[];\n begin(cardId: string, options?: RuntimeTargetOptions): boolean;\n setDropTarget(target: RuntimeDropTarget | null): void;\n drop(): void;\n cancel(): void;\n}\nexport interface GestureGame {\n readonly drag?: GestureDrag;\n readonly request: unknown;\n readonly snapshot: unknown;\n subscribe(listener: () => void): () => void;\n}\n\nexport interface GestureState {\n readonly drag: {\n readonly cardId: string;\n /** Pointer offset inside the card where it was picked up. */\n readonly grab: Point;\n readonly size: { readonly width: number; readonly height: number };\n /** Dropped and submitted; waiting for the authoritative frame. */\n readonly settling: boolean;\n } | null;\n readonly inspect: {\n readonly cardId: string;\n readonly via: \"hold\" | \"hover\";\n } | null;\n}\n\nexport interface CardGestureProps {\n onPointerDown(event: PointerEvent<Element>): void;\n onPointerEnter(event: PointerEvent<Element>): void;\n onPointerLeave(event: PointerEvent<Element>): void;\n onFocus(): void;\n onBlur(): void;\n onContextMenu(event: MouseEvent<Element>): void;\n onDragStart(event: DragEvent<Element>): void;\n readonly style: CSSProperties;\n readonly \"data-dragging\"?: true;\n readonly \"data-inspecting\"?: \"hold\" | \"hover\";\n}\n\nconst CARD_STYLE: CSSProperties = Object.freeze({\n // Sideways movement stays native scrolling; everything else reaches the recognizer.\n touchAction: \"pan-x\",\n userSelect: \"none\",\n WebkitUserSelect: \"none\",\n WebkitTouchCallout: \"none\",\n});\nconst INSPECTION_STYLE: CSSProperties = Object.freeze({\n ...CARD_STYLE,\n // Inspection-only cards should not block their table's native scrolling.\n touchAction: \"manipulation\",\n});\nconst px = (value: number) => `${value}px`;\n\n/** A resolved board destination, or the interaction an area runs. */\nexport type DropAreaInput =\n | RuntimeDropTarget\n | { readonly interaction: string; readonly input?: string }\n | null;\n\nexport function resolveDropArea(\n drag: GestureDrag | undefined,\n binding: DropAreaInput,\n): RuntimeDropTarget | null {\n if (!drag || !binding) return null;\n if (\"interactionKey\" in binding) return binding;\n const matches = drag\n .getDropTargets()\n .filter(\n (target) =>\n target.kind === \"interaction\" &&\n target.interactionKey === binding.interaction &&\n (!binding.input || target.cardInputKey === binding.input),\n );\n // Two card inputs on one interaction need an explicit `input`.\n return matches.length === 1 ? matches[0] : null;\n}\n/** Targets are rebuilt with every drag update; compare what they route. */\nexport const sameDropTarget = (\n left: RuntimeDropTarget | null,\n right: RuntimeDropTarget | null,\n) => left === right || (!!left && !!right && isSameDropTarget(left, right));\nlet sessions = 0;\n\nexport type GestureSession = ReturnType<typeof createGestureSession>;\n\n/**\n * One press at a time for a provider: tap, hold, drag or browse, plus mouse\n * hover intent. The session outlives the pressed element, so a hand may move\n * the card into an overlay mid-drag. Drop areas are found with the browser's\n * own hit testing, so transformed and SVG areas need no geometry.\n */\nexport function createGestureSession(game: GestureGame) {\n const id = `g${++sessions}`;\n const store = createStore<GestureState>({ drag: null, inspect: null });\n const areas = new Map<string, () => DropAreaInput>();\n const followers = new Set<(point: Point) => void>();\n let press: {\n readonly recognizer: GestureRecognizer;\n readonly pointerType: string;\n readonly detach: () => void;\n dragging: boolean;\n area: string | null;\n target: RuntimeDropTarget | null;\n } | null = null;\n let hover: string | null = null;\n let focused: string | null = null;\n let alt = false;\n let pointer: Point = { x: 0, y: 0 };\n let swallowing = false;\n let guardingClicks = false;\n let disposed = false;\n\n const set = (patch: Partial<GestureState>) =>\n store.setState((previous) => ({ ...previous, ...patch }));\n\n let snapshot = game.snapshot;\n const unsubscribe = game.subscribe(() => {\n if (snapshot !== game.snapshot) {\n snapshot = game.snapshot;\n press?.recognizer.cancel();\n // Surviving DOM cards do not receive another enter/focus event.\n alt = false;\n set({ inspect: null });\n }\n // New frames, seats and sources cancel the semantic drag; end the press with it.\n if (press?.dragging && !game.drag?.active) press.recognizer.cancel();\n const drag = store.get().drag;\n if (drag?.settling && game.request === null) set({ drag: null });\n });\n\n function hitArea(at: Point): string | null {\n for (const element of document.elementsFromPoint(at.x, at.y)) {\n if (element.closest(\"[data-drag-overlay]\")) continue;\n const area = element.closest(\"[data-drop-area]\");\n if (area) return area.getAttribute(\"data-drop-area\");\n }\n return null;\n }\n function retarget(at: Point): Point {\n if (!press?.dragging) return at;\n let area = hitArea(at);\n const read = area === null ? undefined : areas.get(area);\n let target = read ? resolveDropArea(game.drag, read()) : null;\n let point = at;\n // Direct hits win; outside a target retain its edge before looking for a new one.\n if (!target) {\n const candidates = [...areas].sort(([left], [right]) =>\n left === press?.area ? -1 : right === press?.area ? 1 : 0,\n );\n let distance = Infinity;\n for (const [id, binding] of candidates) {\n const resolved = resolveDropArea(game.drag, binding());\n if (\n !resolved ||\n !game.drag\n ?.getDropTargets()\n .some((item) => sameDropTarget(item, resolved))\n )\n continue;\n const element = document.querySelector(\n `[data-drop-area=\"${CSS.escape(id)}\"]`,\n );\n if (!(element instanceof HTMLElement)) continue;\n const snapped = magneticDropPoint(\n at,\n element.getBoundingClientRect(),\n id === press.area,\n press.pointerType === \"touch\",\n );\n if (!snapped) continue;\n const nextDistance = Math.hypot(at.x - snapped.x, at.y - snapped.y);\n if (nextDistance >= distance) continue;\n area = id;\n target = resolved;\n point = snapped;\n distance = nextDistance;\n if (id === press.area) break;\n }\n }\n if (area !== press.area || !sameDropTarget(target, press.target)) {\n press.area = area;\n press.target = target;\n game.drag?.setDropTarget(target);\n }\n return point;\n }\n // Keyboard clicks (detail 0) and clicks from a new press are never swallowed.\n function swallow(event: globalThis.MouseEvent) {\n if (!swallowing || event.detail === 0) return;\n swallowing = false;\n event.stopPropagation();\n event.preventDefault();\n }\n function newPress() {\n swallowing = false;\n }\n /** A non-tap stays suppressed until its click or a new press, even after cancellation. */\n function swallowNextClick() {\n swallowing = true;\n if (guardingClicks) return;\n guardingClicks = true;\n addEventListener(\"click\", swallow, true);\n addEventListener(\"pointerdown\", newPress, true);\n }\n function clearHover() {\n hover = null;\n }\n function inspectWithAlt() {\n const cardId = hover ?? focused;\n set({ inspect: alt && cardId && !press ? { cardId, via: \"hover\" } : null });\n }\n const key = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n press?.recognizer.cancel();\n alt = false;\n set({ inspect: null });\n } else if (event.key === \"Alt\") {\n alt = event.type === \"keydown\";\n inspectWithAlt();\n }\n };\n const loseFocus = () => {\n alt = false;\n clearHover();\n focused = null;\n set({ inspect: null });\n };\n addEventListener(\"keydown\", key);\n addEventListener(\"keyup\", key);\n addEventListener(\"blur\", loseFocus);\n function release() {\n press?.detach();\n press = null;\n }\n\n function start(\n event: globalThis.PointerEvent,\n cardId: string,\n element: Element,\n options: false | RuntimeTargetOptions,\n ) {\n if (disposed || press || event.button !== 0) return;\n const recognizer = createGestureRecognizer(event, {\n hold() {\n set({ inspect: { cardId, via: \"hold\" } });\n },\n dragStart(origin) {\n if (options === false || !game.drag?.begin(cardId, options))\n return false;\n const box = element.getBoundingClientRect();\n clearHover();\n press!.dragging = true;\n set({\n drag: {\n cardId,\n grab: { x: origin.x - box.left, y: origin.y - box.top },\n size: { width: box.width, height: box.height },\n settling: false,\n },\n inspect: null,\n });\n return true;\n },\n dragMove(at) {\n pointer = retarget(at);\n for (const follow of followers) follow(pointer);\n },\n end(kind, at) {\n const dragging = press!.dragging;\n if (dragging) retarget(at);\n release();\n if (kind !== \"tap\") swallowNextClick();\n if (kind === \"hold\") set({ inspect: null });\n if (!dragging) return;\n const before = game.request;\n game.drag?.drop();\n // A submitted move keeps its overlay until the authoritative frame.\n const drag = store.get().drag;\n if (drag && game.request !== null && game.request !== before)\n set({ drag: { ...drag, settling: true } });\n else set({ drag: null });\n },\n cancel(kind) {\n const dragging = press!.dragging;\n release();\n // Cancellation does not turn a non-tap into a selection on release.\n if (kind !== \"tap\") swallowNextClick();\n if (kind === \"hold\") set({ inspect: null });\n if (dragging) {\n game.drag?.cancel();\n set({ drag: null });\n }\n },\n });\n const move = (next: globalThis.PointerEvent) => recognizer.move(next);\n const up = (next: globalThis.PointerEvent) => recognizer.up(next);\n const cancel = (next: globalThis.PointerEvent) => recognizer.cancel(next);\n const blur = () => recognizer.cancel();\n addEventListener(\"pointermove\", move);\n addEventListener(\"pointerup\", up);\n addEventListener(\"pointercancel\", cancel);\n addEventListener(\"blur\", blur);\n if (event.pointerType === \"mouse\") {\n // A mouse keeps reporting outside the card; touch is captured implicitly.\n try {\n element.setPointerCapture(event.pointerId);\n } catch {\n // The pointer may already be gone.\n }\n }\n press = {\n recognizer,\n pointerType: event.pointerType,\n dragging: false,\n area: null,\n target: null,\n detach() {\n removeEventListener(\"pointermove\", move);\n removeEventListener(\"pointerup\", up);\n removeEventListener(\"pointercancel\", cancel);\n removeEventListener(\"blur\", blur);\n },\n };\n }\n\n function cardProps(\n cardId: string,\n options: false | RuntimeTargetOptions,\n flags: { dragging: boolean; inspecting: \"hold\" | \"hover\" | null },\n ): CardGestureProps {\n return {\n onPointerDown: (event) =>\n start(event.nativeEvent, cardId, event.currentTarget, options),\n onPointerEnter(event) {\n if (event.pointerType !== \"mouse\" || press?.dragging) return;\n clearHover();\n hover = cardId;\n alt = event.altKey;\n inspectWithAlt();\n },\n onPointerLeave() {\n if (hover === cardId) clearHover();\n inspectWithAlt();\n },\n onFocus() {\n focused = cardId;\n inspectWithAlt();\n },\n onBlur() {\n if (focused === cardId) focused = null;\n inspectWithAlt();\n },\n onContextMenu(event) {\n // A long press must inspect the card, not open the browser's menu.\n if ((press && press.pointerType !== \"mouse\") || swallowing)\n event.preventDefault();\n },\n onDragStart: (event) => event.preventDefault(),\n style: options === false ? INSPECTION_STYLE : CARD_STYLE,\n \"data-dragging\": flags.dragging || undefined,\n \"data-inspecting\": flags.inspecting ?? undefined,\n };\n }\n\n /** Positions the dragged card's overlay without rendering on each move. */\n function overlayRef(element: HTMLElement | null) {\n const drag = store.get().drag;\n if (!element || !drag) return;\n element.setAttribute(\"data-drag-overlay\", \"\");\n Object.assign(element.style, {\n position: \"fixed\",\n margin: \"0\",\n pointerEvents: \"none\",\n width: px(drag.size.width),\n height: px(drag.size.height),\n });\n const follow = (at: Point) => {\n element.style.left = px(at.x - drag.grab.x);\n element.style.top = px(at.y - drag.grab.y);\n };\n follow(pointer);\n followers.add(follow);\n return () => {\n followers.delete(follow);\n };\n }\n\n return {\n id,\n store,\n cardProps,\n overlayRef,\n /** `read` returns the area's current binding; targets resolve when hit. */\n registerArea(area: string, read: () => DropAreaInput) {\n areas.set(area, read);\n return () => {\n areas.delete(area);\n };\n },\n dispose() {\n disposed = true;\n press?.recognizer.cancel();\n clearHover();\n removeEventListener(\"keydown\", key);\n removeEventListener(\"keyup\", key);\n removeEventListener(\"blur\", loseFocus);\n unsubscribe();\n followers.clear();\n if (!guardingClicks) return;\n removeEventListener(\"click\", swallow, true);\n removeEventListener(\"pointerdown\", newPress, true);\n },\n };\n}\n\nexport const GestureContext = createContext<GestureSession | null>(null);\n\nexport function useGestureSession(): GestureSession {\n const session = useContext(GestureContext);\n if (!session) throw new Error(\"Gesture hooks require their GameProvider.\");\n return session;\n}\n\nexport function useGestureState<Value>(\n session: GestureSession,\n select: (state: GestureState) => Value,\n): Value {\n return useSelector(session.store, select);\n}\n","import {\n createGestureSession,\n resolveDropArea,\n sameDropTarget,\n GestureContext,\n useGestureSession,\n useGestureState,\n type CardGestureProps,\n type DropAreaInput,\n type GestureGame,\n type GestureSession,\n} from \"./gesture.js\";\nimport type { SeatCardId } from \"../headless/model.js\";\nimport type {\n DropTarget,\n RuntimeTargetOptions,\n TargetOptions,\n} from \"../headless/targets.js\";\nimport {\n createContext,\n useContext,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { useSelector } from \"@tanstack/react-store\";\nimport { createGameInstance } from \"../headless/instance.js\";\nimport type {\n CoreInstance,\n FeatureContext,\n Features,\n GameInstance,\n GameSnapshot,\n GameSource,\n InstanceOptions,\n} from \"../headless/model.js\";\n\nexport interface SelectionOptions<Value> {\n readonly compare?: (previous: Value, next: Value) => boolean;\n}\n\n/** Inspection stays enabled when this control does not support dragging. */\nexport interface CardGestureOptions<Game> {\n readonly drag: false | TargetOptions<Game>;\n}\n\n/** An area that runs this interaction with whichever card is dropped on it. */\nexport type DropAreaBinding<G> = Exclude<\n TargetOptions<G>,\n { readonly interaction?: undefined }\n>;\n\nexport interface CardGesture {\n /** Spread on the card's own control, after the card's selection props. */\n readonly props: CardGestureProps;\n readonly canDrag: boolean;\n readonly isDragging: boolean;\n /** Held on touch, or rested on with a mouse. */\n readonly inspecting: \"hold\" | \"hover\" | null;\n}\n\nexport interface DropArea {\n readonly props: {\n readonly \"data-drop-area\": string;\n readonly \"data-drop-target\"?: \"true\";\n readonly \"data-drop-over\"?: true;\n };\n readonly isEligible: boolean;\n readonly isOver: boolean;\n}\n\nexport interface DragOverlay<G> {\n readonly cardId: SeatCardId<G>;\n /** Dropped and submitted; the authoritative frame has not arrived yet. */\n readonly settling: boolean;\n /** Attach to a fixed-position copy of the card; it follows the pointer. */\n readonly ref: (element: HTMLElement | null) => (() => void) | undefined;\n}\n\n/** Bind erased game types and features; each provider owns its source lifetime. */\nexport function createGameHook<Game, Source extends GameSource = GameSource>() {\n return function <const Enabled extends Features = Record<never, never>>(\n defaults: Omit<InstanceOptions<Game, Source>, \"source\"> & {\n features?: (\n core: CoreInstance<Game>,\n context: FeatureContext<Game>,\n ) => Enabled;\n },\n ) {\n type Instance = GameInstance<Game, Enabled, Source>;\n type Snapshot = GameSnapshot<Game, Enabled>;\n type ProviderProps = Partial<\n Omit<InstanceOptions<Game, Source>, \"source\">\n > & {\n source: Source;\n children?: ReactNode;\n };\n const Context = createContext<Instance | null>(null);\n\n /** Owns the source. Do not share it between independently mounted providers. */\n function GameProvider({ children, ...overrides }: ProviderProps) {\n const [owned, setOwned] = useState<{\n instance: Instance;\n session: GestureSession;\n } | null>(null);\n const lifetime = useRef<{\n instance: Instance;\n session: GestureSession;\n generation: number;\n } | null>(null);\n const options = {\n ...defaults,\n ...overrides,\n };\n useLayoutEffect(() => {\n let current = lifetime.current;\n if (!current) {\n const instance = createGameInstance<Game>()(options);\n current = {\n instance,\n session: createGestureSession(instance),\n generation: 0,\n };\n lifetime.current = current;\n setOwned({ instance, session: current.session });\n }\n const owned = current;\n ++owned.generation;\n return () => {\n const generation = ++owned.generation;\n queueMicrotask(() => {\n if (owned.generation !== generation) return;\n owned.session.dispose();\n owned.instance.dispose();\n if (lifetime.current === owned) lifetime.current = null;\n });\n };\n // Construction belongs to this committed provider lifetime. Current\n // options are installed separately without recreating features.\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Construct once per committed provider lifetime; the next effect updates options.\n }, []);\n useLayoutEffect(() => {\n lifetime.current?.instance.setOptions(options);\n });\n return owned ? (\n <Context.Provider value={owned.instance}>\n <GestureContext.Provider value={owned.session}>\n {children}\n </GestureContext.Provider>\n </Context.Provider>\n ) : null;\n }\n\n function useInstance(): Instance {\n const instance = useContext(Context);\n if (!instance) throw new Error(\"useGame requires its GameProvider.\");\n return instance;\n }\n\n function useGame(): Instance;\n function useGame<Value>(\n selector: (snapshot: Snapshot) => Value,\n options?: SelectionOptions<Value>,\n ): Value;\n function useGame<Value>(\n selector?: (snapshot: Snapshot) => Value,\n options?: SelectionOptions<Value>,\n ): Instance | Value {\n const instance = useInstance();\n const selected = useSelector(\n instance.store,\n (snapshot): { value: Value } | { snapshot: Snapshot } =>\n selector ? { value: selector(snapshot) } : { snapshot },\n {\n compare: (previous, next) =>\n \"value\" in previous && \"value\" in next\n ? (options?.compare ?? Object.is)(previous.value, next.value)\n : \"snapshot\" in previous &&\n \"snapshot\" in next &&\n Object.is(previous.snapshot, next.snapshot),\n },\n );\n return \"value\" in selected ? selected.value : instance;\n }\n\n function Subscribe<Value>({\n selector,\n compare,\n children,\n }: {\n selector: (snapshot: Snapshot) => Value;\n compare?: SelectionOptions<Value>[\"compare\"];\n children: (value: Value) => ReactNode;\n }) {\n return children(useGame(selector, { compare }));\n }\n\n // Game-binding boundary: typed ids and routes cross into the erased session.\n const dragOf = (snapshot: Snapshot) =>\n (snapshot as Pick<GestureGame, \"drag\">).drag;\n\n /** Tap, hold, drag and browse on one card; hover intent with a mouse. */\n function useCardGesture(\n cardId: SeatCardId<Game>,\n options: CardGestureOptions<Game>,\n ): CardGesture {\n const session = useGestureSession();\n const routes = options.drag as false | RuntimeTargetOptions;\n const canDrag = useGame(\n (snapshot) =>\n routes !== false &&\n (dragOf(snapshot)?.getCanDrag(cardId, routes) ?? false),\n );\n const dragging = useGestureState(\n session,\n (state) => state.drag?.cardId === cardId,\n );\n const inspecting = useGestureState(session, (state) =>\n state.inspect?.cardId === cardId ? state.inspect.via : null,\n );\n return {\n props: session.cardProps(cardId, routes, { dragging, inspecting }),\n canDrag,\n isDragging: dragging,\n inspecting,\n };\n }\n\n /**\n * Marks an element where a dragged card can land: a board destination,\n * or an area that runs an interaction with the dropped card.\n */\n function useDropArea(\n binding: DropTarget<Game> | DropAreaBinding<Game> | null,\n ): DropArea {\n const session = useGestureSession();\n const id = `${session.id}${useId()}`;\n const erased = binding as DropAreaInput;\n const target = useGame(\n (snapshot) => resolveDropArea(dragOf(snapshot), erased),\n { compare: sameDropTarget },\n );\n const isOver = useGame((snapshot) => {\n const active = dragOf(snapshot)?.active?.target;\n return !!target && sameDropTarget(active ?? null, target);\n });\n const latest = useRef(erased);\n useLayoutEffect(() => {\n latest.current = erased;\n });\n useLayoutEffect(\n () => session.registerArea(id, () => latest.current),\n [session, id],\n );\n return {\n props: {\n \"data-drop-area\": id,\n \"data-drop-target\": target ? \"true\" : undefined,\n \"data-drop-over\": isOver || undefined,\n },\n isEligible: target !== null,\n isOver,\n };\n }\n\n /** The card being dragged, and a ref that keeps its copy under the pointer. */\n function useDragOverlay(): DragOverlay<Game> | null {\n const session = useGestureSession();\n const drag = useGestureState(session, (state) => state.drag);\n return drag\n ? {\n cardId: drag.cardId as SeatCardId<Game>,\n settling: drag.settling,\n ref: session.overlayRef,\n }\n : null;\n }\n\n return {\n GameProvider,\n useGame,\n Subscribe,\n useCardGesture,\n useDropArea,\n useDragOverlay,\n };\n };\n}\n"],"mappings":"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","names":["id","createContext","useContext","useSelector","createContext","owned","useContext","useSelector"]}
|
|
1
|
+
{"version":3,"sources":["../src/react/create-game-hook.tsx","../src/react/shortcuts.ts","../src/react/gesture.tsx"],"sourcesContent":["import { createStore } from \"@tanstack/store\";\nimport { inputValueKey } from \"../shared/input-domain.js\";\nimport { useShortcutsAdapter } from \"./shortcuts.js\";\nimport type {\n ShortcutOptions,\n ShortcutTarget,\n ShortcutHint,\n ShortcutsController,\n RuntimeShortcutTarget,\n} from \"../headless/features/shortcuts.js\";\nimport {\n createGestureSession,\n resolveDropArea,\n sameDropTarget,\n GestureContext,\n useGestureSession,\n useGestureState,\n type CardGestureProps,\n type DropAreaInput,\n type GestureGame,\n type GestureSession,\n} from \"./gesture.js\";\nimport type { SeatCardId } from \"../headless/model.js\";\nimport type {\n DropTarget,\n RuntimeTargetOptions,\n TargetOptions,\n} from \"../headless/targets.js\";\nimport {\n createContext,\n useContext,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { useSelector } from \"@tanstack/react-store\";\nimport { createGameInstance } from \"../headless/instance.js\";\nimport type {\n CoreInstance,\n FeatureContext,\n Features,\n GameInstance,\n GameSnapshot,\n GameSource,\n InstanceOptions,\n} from \"../headless/model.js\";\n\nexport interface SelectionOptions<Value> {\n readonly compare?: (previous: Value, next: Value) => boolean;\n}\n\n/** Inspection stays enabled when this control does not support dragging. */\nexport interface CardGestureOptions<Game> {\n readonly drag: false | TargetOptions<Game>;\n}\n\n/** An area that runs this interaction with whichever card is dropped on it. */\nexport type DropAreaBinding<G> = Exclude<\n TargetOptions<G>,\n { readonly interaction?: undefined }\n>;\n\nexport interface CardGesture {\n /** Spread on the card's own control, after the card's selection props. */\n readonly props: CardGestureProps;\n readonly canDrag: boolean;\n readonly isDragging: boolean;\n readonly isActive: boolean;\n /** Held on touch, or rested on with a mouse. */\n readonly inspecting: \"hold\" | \"hover\" | null;\n}\n\nexport interface DropArea {\n readonly props: {\n readonly \"data-drop-area\": string;\n readonly \"data-drop-target\"?: \"true\";\n readonly \"data-drop-over\"?: true;\n };\n readonly isEligible: boolean;\n readonly isOver: boolean;\n}\n\nexport interface DragOverlay<G> {\n readonly cardId: SeatCardId<G>;\n /** Dropped and submitted; the authoritative frame has not arrived yet. */\n readonly settling: boolean;\n /** Attach to a fixed-position copy of the card; it follows the pointer. */\n readonly ref: (element: HTMLElement | null) => (() => void) | undefined;\n}\n\n/** Bind erased game types and features; each provider owns its source lifetime. */\nexport function createGameHook<Game, Source extends GameSource = GameSource>() {\n return function <const Enabled extends Features = Record<never, never>>(\n defaults: Omit<InstanceOptions<Game, Source>, \"source\"> & {\n features?: (\n core: CoreInstance<Game>,\n context: FeatureContext<Game>,\n ) => Enabled;\n },\n ) {\n type Instance = GameInstance<Game, Enabled, Source>;\n type Snapshot = GameSnapshot<Game, Enabled>;\n type ProviderProps = Partial<\n Omit<InstanceOptions<Game, Source>, \"source\">\n > & {\n source: Source;\n children?: ReactNode;\n };\n const Context = createContext<Instance | null>(null);\n\n /** Owns the source. Do not share it between independently mounted providers. */\n function GameProvider({ children, ...overrides }: ProviderProps) {\n const [owned, setOwned] = useState<{\n instance: Instance;\n session: GestureSession;\n } | null>(null);\n const lifetime = useRef<{\n instance: Instance;\n session: GestureSession;\n generation: number;\n } | null>(null);\n const options = {\n ...defaults,\n ...overrides,\n };\n useLayoutEffect(() => {\n let current = lifetime.current;\n if (!current) {\n const instance = createGameInstance<Game>()(options);\n current = {\n instance,\n session: createGestureSession(instance),\n generation: 0,\n };\n lifetime.current = current;\n setOwned({ instance, session: current.session });\n }\n const owned = current;\n ++owned.generation;\n return () => {\n const generation = ++owned.generation;\n queueMicrotask(() => {\n if (owned.generation !== generation) return;\n owned.session.dispose();\n owned.instance.dispose();\n if (lifetime.current === owned) lifetime.current = null;\n });\n };\n // Construction belongs to this committed provider lifetime. Current\n // options are installed separately without recreating features.\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Construct once per committed provider lifetime; the next effect updates options.\n }, []);\n useLayoutEffect(() => {\n lifetime.current?.instance.setOptions(options);\n });\n return owned ? (\n <Context.Provider value={owned.instance}>\n <GestureContext.Provider value={owned.session}>\n {children}\n </GestureContext.Provider>\n </Context.Provider>\n ) : null;\n }\n\n function useInstance(): Instance {\n const instance = useContext(Context);\n if (!instance) throw new Error(\"useGame requires its GameProvider.\");\n return instance;\n }\n\n function useGame(): Instance;\n function useGame<Value>(\n selector: (snapshot: Snapshot) => Value,\n options?: SelectionOptions<Value>,\n ): Value;\n function useGame<Value>(\n selector?: (snapshot: Snapshot) => Value,\n options?: SelectionOptions<Value>,\n ): Instance | Value {\n const instance = useInstance();\n const selected = useSelector(\n instance.store,\n (snapshot): { value: Value } | { snapshot: Snapshot } =>\n selector ? { value: selector(snapshot) } : { snapshot },\n {\n compare: (previous, next) =>\n \"value\" in previous && \"value\" in next\n ? (options?.compare ?? Object.is)(previous.value, next.value)\n : \"snapshot\" in previous &&\n \"snapshot\" in next &&\n Object.is(previous.snapshot, next.snapshot),\n },\n );\n return \"value\" in selected ? selected.value : instance;\n }\n\n function Subscribe<Value>({\n selector,\n compare,\n children,\n }: {\n selector: (snapshot: Snapshot) => Value;\n compare?: SelectionOptions<Value>[\"compare\"];\n children: (value: Value) => ReactNode;\n }) {\n return children(useGame(selector, { compare }));\n }\n\n // Game-binding boundary: typed ids and routes cross into the erased session.\n const dragOf = (snapshot: Snapshot) =>\n (snapshot as Pick<GestureGame, \"drag\">).drag;\n\n /** Tap, hold, drag and browse on one card; hover intent with a mouse. */\n function useCardGesture(\n cardId: SeatCardId<Game>,\n options: CardGestureOptions<Game>,\n ): CardGesture {\n const session = useGestureSession();\n const routes = options.drag as false | RuntimeTargetOptions;\n const canDrag = useGame(\n (snapshot) =>\n routes !== false &&\n (dragOf(snapshot)?.getCanDrag(cardId, routes) ?? false),\n );\n const dragging = useGestureState(\n session,\n (state) => state.drag?.cardId === cardId,\n );\n const inspecting = useGestureState(session, (state) =>\n state.inspect?.cardId === cardId ? state.inspect.via : null,\n );\n const isActive = useGestureState(\n session,\n (state) =>\n state.activeTarget?.kind === \"card\" &&\n state.activeTarget.value === cardId,\n );\n return {\n props: session.cardProps(cardId, routes, { dragging, inspecting }),\n canDrag,\n isDragging: dragging,\n isActive,\n inspecting,\n };\n }\n\n /**\n * Marks an element where a dragged card can land: a board destination,\n * or an area that runs an interaction with the dropped card.\n */\n function useDropArea(\n binding: DropTarget<Game> | DropAreaBinding<Game> | null,\n ): DropArea {\n const session = useGestureSession();\n const id = `${session.id}${useId()}`;\n const erased = binding as DropAreaInput;\n const target = useGame(\n (snapshot) => resolveDropArea(dragOf(snapshot), erased),\n { compare: sameDropTarget },\n );\n const isOver = useGame((snapshot) => {\n const active = dragOf(snapshot)?.active?.target;\n return !!target && sameDropTarget(active ?? null, target);\n });\n const latest = useRef(erased);\n useLayoutEffect(() => {\n latest.current = erased;\n });\n useLayoutEffect(\n () => session.registerArea(id, () => latest.current),\n [session, id],\n );\n return {\n props: {\n \"data-drop-area\": id,\n \"data-drop-target\": target ? \"true\" : undefined,\n \"data-drop-over\": isOver || undefined,\n },\n isEligible: target !== null,\n isOver,\n };\n }\n\n const shortcutsOf = (snapshot: Snapshot) =>\n (\n snapshot as Snapshot & {\n readonly shortcuts?: ShortcutsController<Game>;\n }\n ).shortcuts;\n const noShortcutsConfiguration = createStore<ShortcutOptions<Game> | null>(\n null,\n );\n const sameHints = (\n left: readonly ShortcutHint<Game>[],\n right: readonly ShortcutHint<Game>[],\n ) =>\n left.length === right.length &&\n left.every((hint, index) => {\n const next = right[index];\n return (\n hint.label === next.label &&\n hint.interaction === next.interaction &&\n hint.keys.length === next.keys.length &&\n hint.keys.every((key, at) => key === next.keys[at])\n );\n });\n /** Current eligible hints; configuration and projected domains each notify their own readers. */\n function useShortcutHints(\n target: ShortcutTarget<Game> | null,\n ): readonly ShortcutHint<Game>[] {\n const controller = shortcutsOf(useInstance());\n useGame((snapshot) => shortcutsOf(snapshot)?.getHints(target) ?? [], {\n compare: sameHints,\n });\n return useSelector(\n controller?.configuration ?? noShortcutsConfiguration,\n () => controller?.getHints(target) ?? [],\n { compare: sameHints },\n );\n }\n\n /** Installs the authored keyboard bindings for this mounted application. */\n function useGameShortcuts(options: ShortcutOptions<Game>): {\n readonly target: ShortcutTarget<Game> | null;\n readonly hints: readonly ShortcutHint<Game>[];\n } {\n const instance = useInstance();\n const session = useGestureSession();\n // Feature-composition boundary: this binding and its installed root feature share Game.\n const controller = shortcutsOf(instance);\n if (!controller)\n throw new Error(\n \"useGameShortcuts requires shortcutsFeature in the game binding.\",\n );\n useShortcutsAdapter(instance, controller, session, options, (result) => {\n if (result instanceof Error) instance.getOptions().onError?.(result);\n else if (!result.accepted)\n instance\n .getOptions()\n .onError?.(\n new Error(result.message ?? result.errorCode, { cause: result }),\n );\n });\n const target = useGestureState(\n session,\n (state) => state.activeTarget,\n ) as ShortcutTarget<Game> | null;\n const hints = useShortcutHints(target);\n return { target, hints };\n }\n\n /** Shares the canonical pointer and keyboard focus with a zone, tile or board control. */\n function useShortcutTarget(target: ShortcutTarget<Game>) {\n const session = useGestureSession();\n const id = `${session.id}${useId()}`;\n const latest = useRef<RuntimeShortcutTarget>(target);\n const targetKey = inputValueKey(target);\n useLayoutEffect(() => {\n latest.current = target;\n });\n useLayoutEffect(\n () => session.registerTarget(id, () => latest.current),\n [session, id, targetKey],\n );\n return { props: session.targetProps(id) };\n }\n\n /** The card being dragged, and a ref that keeps its copy under the pointer. */\n function useDragOverlay(): DragOverlay<Game> | null {\n const session = useGestureSession();\n const drag = useGestureState(session, (state) => state.drag);\n return drag\n ? {\n cardId: drag.cardId as SeatCardId<Game>,\n settling: drag.settling,\n ref: session.overlayRef,\n }\n : null;\n }\n\n /** Presentation focus shared by the fan, inspection and pointer activation. */\n function useActiveCard(): SeatCardId<Game> | null {\n const session = useGestureSession();\n return useGestureState(\n session,\n (state) =>\n (state.activeTarget?.kind === \"card\"\n ? state.activeTarget.value\n : null) as SeatCardId<Game> | null,\n );\n }\n\n return {\n GameProvider,\n useGame,\n Subscribe,\n useCardGesture,\n useActiveCard,\n useGameShortcuts,\n useShortcutTarget,\n useShortcutHints,\n useDropArea,\n useDragOverlay,\n };\n };\n}\n","import { useLayoutEffect, useRef } from \"react\";\nimport type {\n ShortcutOptions,\n ShortcutTarget,\n ShortcutsController,\n RuntimeShortcutTarget,\n} from \"../headless/features/shortcuts.js\";\nimport type { CoreInstance, SubmitResult } from \"../headless/model.js\";\n\n/** Browser adapter input; the gesture session owns the single active target. */\nexport interface ShortcutSession {\n getActiveTarget(): RuntimeShortcutTarget | null;\n}\nfunction canHandle(event: KeyboardEvent) {\n const target = event.target;\n return (\n !event.defaultPrevented &&\n !event.repeat &&\n !event.isComposing &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.shiftKey &&\n !(\n target instanceof Element &&\n target.closest(\n \"input, textarea, select, [contenteditable]:not([contenteditable='false']), [role='textbox']\",\n )\n ) &&\n !Array.from(\n document.querySelectorAll(\n \"[aria-modal='true'], dialog[open], [role='dialog'], [role='menu'], [role='listbox']\",\n ),\n ).some(\n (surface) =>\n !surface.closest(\"[aria-hidden='true']\") &&\n surface.checkVisibility({\n visibilityProperty: true,\n opacityProperty: true,\n }),\n )\n );\n}\n/** Installs only for a committed child beneath the bound GameProvider. */\nexport function useShortcutsAdapter<G>(\n game: CoreInstance<G>,\n controller: ShortcutsController<G>,\n session: ShortcutSession,\n options: ShortcutOptions<G>,\n onResult: (result: SubmitResult | Error) => void,\n) {\n const latest = useRef({ options, onResult });\n const registration = useRef<ReturnType<\n ShortcutsController<G>[\"register\"]\n > | null>(null);\n useLayoutEffect(() => {\n latest.current = { options, onResult };\n });\n useLayoutEffect(() => {\n let mounted = true;\n const owned = controller.register(latest.current.options);\n registration.current = owned;\n function keydown(event: KeyboardEvent) {\n if (!canHandle(event)) return;\n // Bound game identity boundary; session targets originate from its own controls.\n const source = game.getOptions().source;\n const seat = game.snapshot?.me;\n const active = () =>\n mounted &&\n game.getOptions().source === source &&\n game.snapshot?.me === seat;\n const pending = controller.handle(\n event.key,\n session.getActiveTarget() as ShortcutTarget<G> | null,\n );\n if (!pending) return;\n event.preventDefault();\n void pending.then(\n (result) => {\n if (active()) latest.current.onResult(result);\n },\n (cause: unknown) => {\n if (active())\n latest.current.onResult(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n },\n );\n }\n window.addEventListener(\"keydown\", keydown);\n return () => {\n mounted = false;\n window.removeEventListener(\"keydown\", keydown);\n registration.current = null;\n owned.dispose();\n };\n }, [game, controller, session]);\n useLayoutEffect(() => {\n registration.current?.update(options);\n });\n}\n","import type { RuntimeShortcutTarget } from \"../headless/features/shortcuts.js\";\nimport type { CoreInstance, InstanceOptions } from \"../headless/model.js\";\nimport { inputValueKey } from \"../shared/input-domain.js\";\nimport { createStore } from \"@tanstack/store\";\nimport { useSelector } from \"@tanstack/react-store\";\nimport {\n createContext,\n useContext,\n type CSSProperties,\n type DragEvent,\n type FocusEvent,\n type MouseEvent,\n type PointerEvent,\n} from \"react\";\nimport {\n createGestureRecognizer,\n magneticDropPoint,\n type GestureRecognizer,\n} from \"../headless/gesture.js\";\nimport { isSameDropTarget } from \"../headless/drop-targets.js\";\nimport type { Point } from \"../headless/features/pointer-session.js\";\nimport type {\n RuntimeDropTarget,\n RuntimeTargetOptions,\n} from \"../headless/targets.js\";\n\n/** The runtime surface of `dragFeature` that a gesture needs. */\nexport interface GestureDrag {\n readonly active: { readonly target: RuntimeDropTarget | null } | null;\n getCanDrag(cardId: string, options?: RuntimeTargetOptions): boolean;\n getDropTargets(): readonly RuntimeDropTarget[];\n begin(cardId: string, options?: RuntimeTargetOptions): boolean;\n setDropTarget(target: RuntimeDropTarget | null): void;\n drop(): void;\n cancel(): void;\n}\nexport interface GestureGame extends Pick<\n CoreInstance<unknown>,\n \"snapshot\" | \"subscribe\"\n> {\n readonly drag?: GestureDrag;\n readonly request: unknown;\n getOptions(): Pick<InstanceOptions<unknown>, \"source\">;\n}\n\nexport interface GestureState {\n readonly activeTarget: RuntimeShortcutTarget | null;\n readonly drag: {\n readonly cardId: string;\n /** Pointer offset inside the card where it was picked up. */\n readonly grab: Point;\n readonly size: { readonly width: number; readonly height: number };\n /** Dropped and submitted; waiting for the authoritative frame. */\n readonly settling: boolean;\n } | null;\n readonly inspect: {\n readonly cardId: string;\n readonly via: \"hold\" | \"hover\";\n } | null;\n}\n\nexport interface CardGestureProps {\n onPointerDown(event: PointerEvent<Element>): void;\n onFocus(event: FocusEvent<Element>): void;\n onBlur(): void;\n onContextMenu(event: MouseEvent<Element>): void;\n onDragStart(event: DragEvent<Element>): void;\n readonly style: CSSProperties;\n readonly \"data-dragging\"?: true;\n readonly \"data-inspecting\"?: \"hold\" | \"hover\";\n readonly \"data-card-gesture\": string;\n readonly \"data-gesture-session\": string;\n}\n\nconst CARD_STYLE: CSSProperties = Object.freeze({\n // Sideways movement stays native scrolling; everything else reaches the recognizer.\n touchAction: \"pan-x\",\n userSelect: \"none\",\n WebkitUserSelect: \"none\",\n WebkitTouchCallout: \"none\",\n});\nconst INSPECTION_STYLE: CSSProperties = Object.freeze({\n ...CARD_STYLE,\n // Inspection-only cards should not block their table's native scrolling.\n touchAction: \"manipulation\",\n});\nconst px = (value: number) => `${value}px`;\n\n/** A resolved board destination, or the interaction an area runs. */\nexport type DropAreaInput =\n | RuntimeDropTarget\n | { readonly interaction: string; readonly input?: string }\n | null;\n\nexport function resolveDropArea(\n drag: GestureDrag | undefined,\n binding: DropAreaInput,\n): RuntimeDropTarget | null {\n if (!drag || !binding) return null;\n if (\"interactionKey\" in binding) return binding;\n const matches = drag\n .getDropTargets()\n .filter(\n (target) =>\n target.kind === \"interaction\" &&\n target.interactionKey === binding.interaction &&\n (!binding.input || target.cardInputKey === binding.input),\n );\n // Two card inputs on one interaction need an explicit `input`.\n return matches.length === 1 ? matches[0] : null;\n}\n/** Targets are rebuilt with every drag update; compare what they route. */\nexport const sameDropTarget = (\n left: RuntimeDropTarget | null,\n right: RuntimeDropTarget | null,\n) => left === right || (!!left && !!right && isSameDropTarget(left, right));\nlet sessions = 0;\n\nexport type GestureSession = ReturnType<typeof createGestureSession>;\n\n/**\n * One press at a time for a provider: tap, hold, drag or browse, plus mouse\n * hover intent. The session outlives the pressed element, so a hand may move\n * the card into an overlay mid-drag. Drop areas are found with the browser's\n * own hit testing, so transformed and SVG areas need no geometry.\n */\nexport function createGestureSession(game: GestureGame) {\n const id = `g${++sessions}`;\n const store = createStore<GestureState>({\n activeTarget: null,\n drag: null,\n inspect: null,\n });\n const targets = new Map<string, () => RuntimeShortcutTarget>();\n const sameTarget = (\n left: RuntimeShortcutTarget | null,\n right: RuntimeShortcutTarget | null,\n ) => inputValueKey(left) === inputValueKey(right);\n const areas = new Map<string, () => DropAreaInput>();\n const followers = new Set<(point: Point) => void>();\n let press: {\n readonly recognizer: GestureRecognizer;\n readonly pointerType: string;\n readonly detach: () => void;\n dragging: boolean;\n area: string | null;\n target: RuntimeDropTarget | null;\n } | null = null;\n let hover: RuntimeShortcutTarget | null = null;\n let hoverPoint: Point | null = null;\n let focused: RuntimeShortcutTarget | null = null;\n let alt = false;\n let pointer: Point = { x: 0, y: 0 };\n let swallowing = false;\n let guardingClicks = false;\n let disposed = false;\n\n const set = (patch: Partial<GestureState>) =>\n store.setState((previous) => ({ ...previous, ...patch }));\n\n let snapshot = game.snapshot;\n let source = game.getOptions().source;\n function admitted(target: RuntimeShortcutTarget | null) {\n if (!target || !game.snapshot) return null;\n const zones = game.snapshot.frame.zones;\n if (target.kind === \"zone\")\n return zones[target.zoneId]?.[target.hostId] ? target : null;\n if (target.kind === \"card\")\n return Object.entries(snapshot?.frame.zones ?? {}).some(\n ([zoneId, hosts]) =>\n Object.entries(hosts).some(\n ([hostId, zone]) =>\n zone.cardIds.includes(target.value) &&\n zones[zoneId]?.[hostId]?.cardIds.includes(target.value),\n ),\n )\n ? target\n : null;\n // Board controls own their mounted identity; each shortcut still checks\n // the current projected input domain before submitting.\n return [...targets.values()].some((read) => sameTarget(read(), target))\n ? target\n : null;\n }\n const unsubscribe = game.subscribe(() => {\n const nextSource = game.getOptions().source;\n const changedLifetime =\n source !== nextSource || snapshot?.me !== game.snapshot?.me;\n if (changedLifetime || snapshot !== game.snapshot) {\n const nextHover = changedLifetime ? null : admitted(hover);\n const nextFocused = changedLifetime ? null : admitted(focused);\n source = nextSource;\n snapshot = game.snapshot;\n press?.recognizer.cancel();\n alt = false;\n // A parked pointer or keyboard focus survives an admitted same-seat\n // frame, so separate key presses can keep acting on the same control.\n hover = nextHover;\n focused = nextFocused;\n if (changedLifetime) hoverPoint = null;\n set({ activeTarget: hover ?? focused, inspect: null });\n }\n // New frames, seats and sources cancel the semantic drag; end the press with it.\n if (press?.dragging && !game.drag?.active) press.recognizer.cancel();\n const drag = store.get().drag;\n if (drag?.settling && game.request === null) set({ drag: null });\n });\n\n function hitArea(at: Point): string | null {\n for (const element of document.elementsFromPoint(at.x, at.y)) {\n if (element.closest(\"[data-drag-overlay]\")) continue;\n const area = element.closest(\"[data-drop-area]\");\n if (area) return area.getAttribute(\"data-drop-area\");\n }\n return null;\n }\n function retarget(at: Point): Point {\n if (!press?.dragging) return at;\n let area = hitArea(at);\n const read = area === null ? undefined : areas.get(area);\n let target = read ? resolveDropArea(game.drag, read()) : null;\n let point = at;\n // Direct hits win; outside a target retain its edge before looking for a new one.\n if (!target) {\n const candidates = [...areas].sort(([left], [right]) =>\n left === press?.area ? -1 : right === press?.area ? 1 : 0,\n );\n let distance = Infinity;\n for (const [id, binding] of candidates) {\n const resolved = resolveDropArea(game.drag, binding());\n if (\n !resolved ||\n !game.drag\n ?.getDropTargets()\n .some((item) => sameDropTarget(item, resolved))\n )\n continue;\n const element = document.querySelector(\n `[data-drop-area=\"${CSS.escape(id)}\"]`,\n );\n if (!(element instanceof HTMLElement)) continue;\n const snapped = magneticDropPoint(\n at,\n element.getBoundingClientRect(),\n id === press.area,\n press.pointerType === \"touch\",\n );\n if (!snapped) continue;\n const nextDistance = Math.hypot(at.x - snapped.x, at.y - snapped.y);\n if (nextDistance >= distance) continue;\n area = id;\n target = resolved;\n point = snapped;\n distance = nextDistance;\n if (id === press.area) break;\n }\n }\n if (area !== press.area || !sameDropTarget(target, press.target)) {\n press.area = area;\n press.target = target;\n game.drag?.setDropTarget(target);\n }\n return point;\n }\n // Keyboard clicks (detail 0) and clicks from a new press are never swallowed.\n function swallow(event: globalThis.MouseEvent) {\n if (!swallowing || event.detail === 0) return;\n swallowing = false;\n event.stopPropagation();\n event.preventDefault();\n }\n function newPress() {\n swallowing = false;\n }\n /** A non-tap stays suppressed until its click or a new press, even after cancellation. */\n function swallowNextClick() {\n swallowing = true;\n if (guardingClicks) return;\n guardingClicks = true;\n addEventListener(\"click\", swallow, true);\n addEventListener(\"pointerdown\", newPress, true);\n }\n function clearHover() {\n hover = null;\n }\n function inspectWithAlt() {\n const target = hover ?? focused;\n const cardId = target?.kind === \"card\" ? target.value : null;\n set({\n activeTarget: target,\n inspect: alt && cardId && !press ? { cardId, via: \"hover\" } : null,\n });\n }\n function hoverAt(at: Point) {\n hoverPoint = at;\n const wasFocused = focused !== null;\n focused = null;\n const hit = document\n .elementFromPoint(at.x, at.y)\n ?.closest(\"[data-card-gesture], [data-shortcut-target]\");\n const control =\n hit?.getAttribute(\"data-gesture-session\") === id ? hit : null;\n const targetId = control?.getAttribute(\"data-shortcut-target\");\n const cardId = control?.getAttribute(\"data-card-gesture\");\n const next: RuntimeShortcutTarget | null = targetId\n ? (targets.get(targetId)?.() ?? null)\n : cardId\n ? { kind: \"card\", value: cardId }\n : null;\n if (sameTarget(hover, next) && !wasFocused) return;\n hover = next;\n inspectWithAlt();\n }\n // CSS transforms generate enter/leave events under a parked mouse. Only\n // physical movement changes its target; down uses the actual pressed control.\n const browse = (event: globalThis.PointerEvent) => {\n if (event.pointerType !== \"mouse\" || press) return;\n if (hoverPoint?.x === event.clientX && hoverPoint.y === event.clientY)\n return;\n alt = event.altKey;\n hoverAt({ x: event.clientX, y: event.clientY });\n };\n const key = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n press?.recognizer.cancel();\n alt = false;\n set({ inspect: null });\n } else if (event.key === \"Alt\") {\n alt = event.type === \"keydown\";\n inspectWithAlt();\n }\n };\n const loseFocus = () => {\n alt = false;\n clearHover();\n hoverPoint = null;\n focused = null;\n set({ activeTarget: null, inspect: null });\n };\n addEventListener(\"keydown\", key);\n addEventListener(\"keyup\", key);\n addEventListener(\"blur\", loseFocus);\n const leaveWindow = (event: globalThis.PointerEvent) => {\n if (event.pointerType !== \"mouse\" || event.relatedTarget !== null) return;\n clearHover();\n hoverPoint = null;\n focused = null;\n alt = false;\n inspectWithAlt();\n };\n addEventListener(\"pointermove\", browse);\n addEventListener(\"pointerout\", leaveWindow);\n function release() {\n press?.detach();\n press = null;\n }\n\n function start(\n event: globalThis.PointerEvent,\n cardId: string,\n element: Element,\n options: false | RuntimeTargetOptions,\n ) {\n if (disposed || press || event.button !== 0) return;\n const recognizer = createGestureRecognizer(event, {\n hold() {\n set({ inspect: { cardId, via: \"hold\" } });\n },\n dragStart(origin) {\n if (options === false || !game.drag?.begin(cardId, options))\n return false;\n const box = element.getBoundingClientRect();\n clearHover();\n focused = null;\n press!.dragging = true;\n set({\n drag: {\n cardId,\n grab: { x: origin.x - box.left, y: origin.y - box.top },\n size: { width: box.width, height: box.height },\n settling: false,\n },\n inspect: null,\n activeTarget: null,\n });\n return true;\n },\n dragMove(at) {\n pointer = retarget(at);\n for (const follow of followers) follow(pointer);\n },\n end(kind, at) {\n const dragging = press!.dragging;\n const pointerType = press!.pointerType;\n if (dragging) retarget(at);\n release();\n if (kind !== \"tap\") swallowNextClick();\n if (kind === \"hold\") set({ inspect: null });\n if (!dragging) {\n // A rejected drag or inspection-only mouse press may browse to a\n // different face. Its final physical point becomes the canonical target.\n if (kind === \"browse\" && pointerType === \"mouse\") hoverAt(at);\n return;\n }\n const before = game.request;\n game.drag?.drop();\n // A submitted move keeps its overlay until the authoritative frame.\n const drag = store.get().drag;\n if (drag && game.request !== null && game.request !== before)\n set({ drag: { ...drag, settling: true } });\n else set({ drag: null });\n },\n cancel(kind) {\n const dragging = press!.dragging;\n release();\n // Cancellation does not turn a non-tap into a selection on release.\n if (kind !== \"tap\") swallowNextClick();\n if (kind === \"hold\") set({ inspect: null });\n if (dragging) {\n game.drag?.cancel();\n set({ drag: null });\n }\n },\n });\n const move = (next: globalThis.PointerEvent) => recognizer.move(next);\n const up = (next: globalThis.PointerEvent) => recognizer.up(next);\n const cancel = (next: globalThis.PointerEvent) => recognizer.cancel(next);\n const blur = () => recognizer.cancel();\n addEventListener(\"pointermove\", move);\n addEventListener(\"pointerup\", up);\n addEventListener(\"pointercancel\", cancel);\n addEventListener(\"blur\", blur);\n if (event.pointerType === \"mouse\") {\n // A mouse keeps reporting outside the card; touch is captured implicitly.\n try {\n element.setPointerCapture(event.pointerId);\n } catch {\n // The pointer may already be gone.\n }\n }\n press = {\n recognizer,\n pointerType: event.pointerType,\n dragging: false,\n area: null,\n target: null,\n detach() {\n removeEventListener(\"pointermove\", move);\n removeEventListener(\"pointerup\", up);\n removeEventListener(\"pointercancel\", cancel);\n removeEventListener(\"blur\", blur);\n },\n };\n }\n\n function cardProps(\n cardId: string,\n options: false | RuntimeTargetOptions,\n flags: { dragging: boolean; inspecting: \"hold\" | \"hover\" | null },\n ): CardGestureProps {\n return {\n onPointerDown(event) {\n if (event.pointerType === \"mouse\") {\n hover = { kind: \"card\", value: cardId };\n alt = event.altKey;\n inspectWithAlt();\n }\n start(event.nativeEvent, cardId, event.currentTarget, options);\n },\n onFocus(event) {\n focused = event.currentTarget.matches(\":focus-visible\")\n ? { kind: \"card\", value: cardId }\n : null;\n if (focused) hover = null;\n inspectWithAlt();\n },\n onBlur() {\n if (focused?.kind === \"card\" && focused.value === cardId)\n focused = null;\n inspectWithAlt();\n },\n onContextMenu(event) {\n // A long press must inspect the card, not open the browser's menu.\n if ((press && press.pointerType !== \"mouse\") || swallowing)\n event.preventDefault();\n },\n onDragStart: (event) => event.preventDefault(),\n style: options === false ? INSPECTION_STYLE : CARD_STYLE,\n \"data-dragging\": flags.dragging || undefined,\n \"data-inspecting\": flags.inspecting ?? undefined,\n \"data-card-gesture\": cardId,\n \"data-gesture-session\": id,\n };\n }\n\n /** Positions the dragged card's overlay without rendering on each move. */\n function overlayRef(element: HTMLElement | null) {\n const drag = store.get().drag;\n if (!element || !drag) return;\n element.setAttribute(\"data-drag-overlay\", \"\");\n Object.assign(element.style, {\n position: \"fixed\",\n margin: \"0\",\n pointerEvents: \"none\",\n width: px(drag.size.width),\n height: px(drag.size.height),\n });\n const follow = (at: Point) => {\n element.style.left = px(at.x - drag.grab.x);\n element.style.top = px(at.y - drag.grab.y);\n };\n follow(pointer);\n followers.add(follow);\n return () => {\n followers.delete(follow);\n };\n }\n\n return {\n id,\n store,\n cardProps,\n getActiveCardId() {\n const target = store.get().activeTarget;\n return target?.kind === \"card\" ? target.value : null;\n },\n getActiveTarget: () => store.get().activeTarget,\n registerTarget(targetId: string, read: () => RuntimeShortcutTarget) {\n const target = read();\n targets.set(targetId, read);\n return () => {\n targets.delete(targetId);\n if (sameTarget(hover, target)) hover = null;\n if (sameTarget(focused, target)) focused = null;\n inspectWithAlt();\n };\n },\n targetProps(targetId: string) {\n return {\n \"data-shortcut-target\": targetId,\n \"data-gesture-session\": id,\n onPointerDown(event: PointerEvent<Element>) {\n if (event.pointerType !== \"mouse\") return;\n hover = targets.get(targetId)?.() ?? null;\n alt = event.altKey;\n inspectWithAlt();\n },\n onFocus(event: FocusEvent<Element>) {\n focused = event.currentTarget.matches(\":focus-visible\")\n ? (targets.get(targetId)?.() ?? null)\n : null;\n if (focused) hover = null;\n inspectWithAlt();\n },\n onBlur() {\n const target = targets.get(targetId)?.() ?? null;\n if (sameTarget(focused, target)) focused = null;\n inspectWithAlt();\n },\n };\n },\n overlayRef,\n /** `read` returns the area's current binding; targets resolve when hit. */\n registerArea(area: string, read: () => DropAreaInput) {\n areas.set(area, read);\n return () => {\n areas.delete(area);\n };\n },\n dispose() {\n disposed = true;\n press?.recognizer.cancel();\n clearHover();\n removeEventListener(\"keydown\", key);\n removeEventListener(\"keyup\", key);\n removeEventListener(\"blur\", loseFocus);\n removeEventListener(\"pointermove\", browse);\n removeEventListener(\"pointerout\", leaveWindow);\n unsubscribe();\n followers.clear();\n targets.clear();\n if (!guardingClicks) return;\n removeEventListener(\"click\", swallow, true);\n removeEventListener(\"pointerdown\", newPress, true);\n },\n };\n}\n\nexport const GestureContext = createContext<GestureSession | null>(null);\n\nexport function useGestureSession(): GestureSession {\n const session = useContext(GestureContext);\n if (!session) throw new Error(\"Gesture hooks require their GameProvider.\");\n return session;\n}\n\nexport function useGestureState<Value>(\n session: GestureSession,\n select: (state: GestureState) => Value,\n): Value {\n return useSelector(session.store, select);\n}\n"],"mappings":"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","names":["createStore","id","createContext","useContext","useLayoutEffect","useRef","useSelector","createContext","useRef","useLayoutEffect","owned","useContext","useSelector","createStore"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { j as BoardSpaceTarget, bf as TopologyDefinitions, h as BoardIdOfTable, b9 as TileSpaceId, aX as SeatSpaceRef, a_ as SpaceIdOfTable, bc as TiledBoardIdOfTable, bd as TiledEdgeIdOfTable, be as TiledVertexIdOfTable, k as BoardStateOfTable, aY as SeatTileRef, aV as SeatBoardTopology, U as InputDomain, aN as RuntimeJson, aq as PhaseNamesOfDefinition, a4 as InteractionIdOfDefinitionPhase, s as ClientParamsOfInteractionOfDefinition, T as InputCollectorOfDefinition, a5 as InteractionInputDescriptor, bo as ViewOfDefinition, aw as ProjectedTile, ay as ReadonlyRuntimeData, l as BoardTopologyOf, P as HiddenCardId, bi as ViewCard, bj as ViewCardOfTable, I as GameEvent } from './extract-DgzrJ5el.js';
|
|
2
|
-
import { z } from 'zod';
|
|
3
1
|
import { Store } from '@tanstack/store';
|
|
4
|
-
import {
|
|
2
|
+
import { j as BoardSpaceTarget, bf as TopologyDefinitions, h as BoardIdOfTable, b9 as TileSpaceId, aX as SeatSpaceRef, a_ as SpaceIdOfTable, bc as TiledBoardIdOfTable, bd as TiledEdgeIdOfTable, be as TiledVertexIdOfTable, k as BoardStateOfTable, aY as SeatTileRef, aV as SeatBoardTopology, aN as RuntimeJson, a5 as InteractionInputDescriptor, U as InputDomain, aq as PhaseNamesOfDefinition, a4 as InteractionIdOfDefinitionPhase, s as ClientParamsOfInteractionOfDefinition, T as InputCollectorOfDefinition, bo as ViewOfDefinition, aw as ProjectedTile, ay as ReadonlyRuntimeData, l as BoardTopologyOf, P as HiddenCardId, bi as ViewCard, bj as ViewCardOfTable, I as GameEvent } from './extract-DgzrJ5el.js';
|
|
3
|
+
import { g as SourceSnapshot, h as SourceState, i as SubmitResult, G as GameSource, I as InteractionDescriptor } from './types-Xg_RxV1n.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
5
|
|
|
6
6
|
type RuntimeBoardTarget = {
|
|
7
7
|
readonly valueKind: "board-id";
|
|
@@ -109,6 +109,7 @@ type DropTarget<G> = BoardDropTarget<G> | InteractionDropTarget<G>;
|
|
|
109
109
|
declare const runtimeFeatures: unique symbol;
|
|
110
110
|
interface RuntimeInput {
|
|
111
111
|
readonly key: string;
|
|
112
|
+
readonly kind: InteractionInputDescriptor["kind"];
|
|
112
113
|
getDomain(): InputDomain;
|
|
113
114
|
getIsEligible(value: RuntimeJson): boolean;
|
|
114
115
|
getIsSelected(value: RuntimeJson): boolean;
|
|
@@ -116,16 +117,25 @@ interface RuntimeInput {
|
|
|
116
117
|
}
|
|
117
118
|
interface RuntimeInteraction {
|
|
118
119
|
readonly key: string;
|
|
119
|
-
getIsAvailable(): boolean;
|
|
120
|
+
getIsAvailable(params?: Readonly<Record<string, RuntimeJson>>): boolean;
|
|
121
|
+
getIsReady(params?: Readonly<Record<string, RuntimeJson>>): boolean;
|
|
122
|
+
getStatus(): "open" | "submitting" | "submitted";
|
|
123
|
+
submit(params?: Readonly<Record<string, RuntimeJson>>): Promise<SubmitResult>;
|
|
120
124
|
getInputs(): readonly RuntimeInput[];
|
|
121
125
|
}
|
|
122
126
|
interface RuntimeFeatureSnapshot {
|
|
123
127
|
readonly view: unknown;
|
|
124
128
|
readonly snapshot: SourceSnapshot | null;
|
|
125
129
|
readonly connection: SourceState["connection"];
|
|
130
|
+
readonly request: SourceState["request"];
|
|
126
131
|
readonly interactions: {
|
|
127
132
|
list(): readonly RuntimeInteraction[];
|
|
128
133
|
};
|
|
134
|
+
readonly zones: {
|
|
135
|
+
find(id: string, hostId: string): {
|
|
136
|
+
readonly count: number;
|
|
137
|
+
} | undefined;
|
|
138
|
+
};
|
|
129
139
|
readonly cards: {
|
|
130
140
|
find(id: string): {
|
|
131
141
|
getInteractions(): readonly RuntimeInteraction[];
|
|
@@ -471,14 +481,14 @@ interface InteractionBase<G, K extends InteractionKey<G>> {
|
|
|
471
481
|
readonly kind: "inputs" | "steps";
|
|
472
482
|
readonly game: CoreInstance<G>;
|
|
473
483
|
getAvailability(): InteractionDescriptor["availability"];
|
|
474
|
-
getIsAvailable(): boolean;
|
|
484
|
+
getIsAvailable(params?: InteractionParams<G, K>): boolean;
|
|
475
485
|
getUnavailableReason(): string | null;
|
|
476
486
|
getStep(): InteractionDescriptor["step"] | null;
|
|
477
487
|
getStepIndex(): number | null;
|
|
478
|
-
getIsReady(): boolean;
|
|
488
|
+
getIsReady(params?: InteractionParams<G, K>): boolean;
|
|
479
489
|
getMissingInputs(): readonly InputKey<G, K>[];
|
|
480
490
|
getStatus(): "open" | "submitting" | "submitted";
|
|
481
|
-
submit(): Promise<SubmitResult>;
|
|
491
|
+
submit(params?: InteractionParams<G, K>): Promise<SubmitResult>;
|
|
482
492
|
cancel(): Promise<SubmitResult>;
|
|
483
493
|
reset(): void;
|
|
484
494
|
activate(): void;
|
|
@@ -645,4 +655,79 @@ type GameInstance<G, F extends Features = Record<never, never>, S extends GameSo
|
|
|
645
655
|
explore(...args: A): R;
|
|
646
656
|
} : Record<never, never>);
|
|
647
657
|
|
|
648
|
-
|
|
658
|
+
/** A zone control carries the actual admitted attachment, including its host. */
|
|
659
|
+
type ShortcutZoneTarget<G> = {
|
|
660
|
+
[Z in IdOf<G, "zoneId">]: {
|
|
661
|
+
readonly kind: "zone";
|
|
662
|
+
readonly zoneId: Z;
|
|
663
|
+
readonly hostId: ZoneHostId<G, Z>;
|
|
664
|
+
};
|
|
665
|
+
}[IdOf<G, "zoneId">];
|
|
666
|
+
type ShortcutTarget<G> = SelectionTarget<G> | ShortcutZoneTarget<G>;
|
|
667
|
+
type TargetKind = SelectionTarget<unknown>["kind"];
|
|
668
|
+
type CollectorKind<Kind extends TargetKind> = Kind extends "space" ? "board-space" : Kind extends "edge" ? "board-edge" : Kind extends "vertex" ? "board-vertex" : Kind;
|
|
669
|
+
type TargetFor<G, K extends InteractionKey<G>, N extends InputKey<G, K>, Kind extends TargetKind> = Extract<SelectionTarget<G>, {
|
|
670
|
+
readonly kind: Kind;
|
|
671
|
+
}> & {
|
|
672
|
+
readonly value: InputTarget<G, K, N>;
|
|
673
|
+
};
|
|
674
|
+
type Binding<G, K extends InteractionKey<G>, Target, Filter> = Filter & {
|
|
675
|
+
/** Exact browser event.key values; modifiers and held repeats are ignored. */
|
|
676
|
+
readonly keys: readonly string[];
|
|
677
|
+
readonly label: string;
|
|
678
|
+
readonly interaction: K;
|
|
679
|
+
readonly inputs: (context: {
|
|
680
|
+
readonly key: string;
|
|
681
|
+
readonly target: Target;
|
|
682
|
+
}) => InteractionParams<G, K>;
|
|
683
|
+
};
|
|
684
|
+
type SelectionBinding<G, K extends InteractionKey<G>> = {
|
|
685
|
+
[N in InputKey<G, K>]: {
|
|
686
|
+
[Kind in TargetKind]: [
|
|
687
|
+
Extract<InputKind<G, K, N>, CollectorKind<Kind>>
|
|
688
|
+
] extends [never] ? never : Binding<G, K, TargetFor<G, K, N, Kind>, {
|
|
689
|
+
readonly target: Kind;
|
|
690
|
+
readonly input: N;
|
|
691
|
+
}>;
|
|
692
|
+
}[TargetKind];
|
|
693
|
+
}[InputKey<G, K>];
|
|
694
|
+
/** Correlated by interaction, input kind, and the selected target's value. */
|
|
695
|
+
type ShortcutBinding<G> = {
|
|
696
|
+
[K in InteractionKey<G>]: SelectionBinding<G, K> | {
|
|
697
|
+
[Z in IdOf<G, "zoneId">]: Binding<G, K, Extract<ShortcutZoneTarget<G>, {
|
|
698
|
+
readonly zoneId: Z;
|
|
699
|
+
}>, {
|
|
700
|
+
readonly target: "zone";
|
|
701
|
+
readonly zoneId: Z;
|
|
702
|
+
}>;
|
|
703
|
+
}[IdOf<G, "zoneId">];
|
|
704
|
+
}[InteractionKey<G>];
|
|
705
|
+
interface ShortcutOptions<G> {
|
|
706
|
+
readonly bindings: readonly ShortcutBinding<G>[];
|
|
707
|
+
}
|
|
708
|
+
interface ShortcutHint<G = unknown> {
|
|
709
|
+
readonly keys: readonly string[];
|
|
710
|
+
readonly label: string;
|
|
711
|
+
readonly interaction: InteractionKey<G>;
|
|
712
|
+
}
|
|
713
|
+
interface ShortcutsController<G> {
|
|
714
|
+
/** UI binding configuration has its own subscription, independent of reducer frames. */
|
|
715
|
+
readonly configuration: Pick<Store<ShortcutOptions<G> | null>, "get" | "subscribe">;
|
|
716
|
+
/** Registers one mounted adapter. Cleanup removes both behavior and hints. */
|
|
717
|
+
register(options: ShortcutOptions<G>): {
|
|
718
|
+
update(options: ShortcutOptions<G>): void;
|
|
719
|
+
dispose(): void;
|
|
720
|
+
};
|
|
721
|
+
/** null means unhandled; a handled key submits exactly once. */
|
|
722
|
+
handle(key: string, target: ShortcutTarget<G> | null): Promise<SubmitResult> | null;
|
|
723
|
+
getHints(target: ShortcutTarget<G> | null): readonly ShortcutHint<G>[];
|
|
724
|
+
}
|
|
725
|
+
/** Headless and opt-in: no names, bindings or browser listeners are installed by default. */
|
|
726
|
+
declare function shortcutsFeature<G>(_game: CoreInstance<G>, context: FeatureContext<G>): {
|
|
727
|
+
root: {
|
|
728
|
+
shortcuts: ShortcutsController<G>;
|
|
729
|
+
};
|
|
730
|
+
dispose(): void;
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
export { type RuntimeSelectionTarget as $, type ActionProps as A, type Board as B, type Card as C, type Drafts as D, type InstanceOptions as E, type Feature as F, type GameInstance as G, type Hook as H, type IdOf as I, type Interaction as J, type InteractionBase as K, type InteractionDropTarget as L, type InteractionKey as M, type InteractionParams as N, type LocalState as O, type NativeEvent as P, type Phase as Q, type PhaseName as R, type PlacedTileDataOf as S, type Player as T, type ReadModel as U, type ReadonlyData as V, type RuntimeBoard as W, type RuntimeBoardDropTarget as X, type RuntimeBoardTarget as Y, type RuntimeDropTarget as Z, type RuntimeInteractionDropTarget as _, type AnyInput as a, type RuntimeTargetOptions as a0, type SeatCardId as a1, type SelectionTarget as a2, type ShortcutBinding as a3, type ShortcutHint as a4, type ShortcutOptions as a5, type ShortcutTarget as a6, type ShortcutZoneTarget as a7, type ShortcutsController as a8, type TableOfGame as a9, type TargetOptions as aa, type Tile as ab, type TileDataOf as ac, type Turn as ad, type ViewOf as ae, type Zone as af, type ZoneBase as ag, type ZoneHostId as ah, shortcutsFeature as ai, type AnyInteraction as b, type BoardBase as c, type BoardCollection as d, type BoardDataOf as e, type BoardDropTarget as f, type BoardSpace as g, type BoardSpaceCollection as h, type BoardSpaceData as i, type BoardSpaceId as j, type BoardTarget as k, type CardBase as l, type CardDataOf as m, type CoreInstance as n, type DropTarget as o, type FeatureContext as p, type Features as q, type GameSnapshot as r, type Input as s, type InputBase as t, type InputControl as u, type InputDomainOf as v, type InputKey as w, type InputKind as x, type InputTarget as y, type InputTargetOption as z };
|
package/dist/testing.js
CHANGED
package/package.json
CHANGED