Documentation Index
Fetch the complete documentation index at: https://mintlify.com/pocket-stack/pocketjs/llms.txt
Use this file to discover all available pages before exploring further.
@pocketjs/framework/input exposes the low-level input surface: the PSP button bitmask constants, programmatic focus control, and the imperative scope and grid stacks that back the FocusScope and FocusGrid components. In application code, prefer the FocusScope and FocusGrid components from @pocketjs/framework/components — they manage push/pop automatically via the reactive owner. Reach for these imperative functions when building custom focus abstractions, animation-driven transitions, or test utilities.
The focus model operates over a JS mirror of the native tree. Default traversal follows document order (DFS). pushFocusScope restricts traversal to a subtree; pushFocusGrid gives a subtree explicit row/column d-pad semantics. The stacks are independent — a grid inside a scope works correctly. Every focus change calls ops.setFocus so the Rust core applies the focus: style variant with zero further JS.
BTN
The PSP button bitmask. Values are identical on every host — web and Bun hosts remap keyboard keys to these same bits, so code written against BTN works unchanged on all targets.
| Constant | Value | Button |
|---|---|---|
BTN.SELECT | 0x0001 | Select |
BTN.START | 0x0008 | Start |
BTN.UP | 0x0010 | D-pad Up |
BTN.RIGHT | 0x0020 | D-pad Right |
BTN.DOWN | 0x0040 | D-pad Down |
BTN.LEFT | 0x0080 | D-pad Left |
BTN.LTRIGGER | 0x0100 | L Trigger (left shoulder) |
BTN.RTRIGGER | 0x0200 | R Trigger (right shoulder) |
BTN.TRIANGLE | 0x1000 | Triangle |
BTN.CIRCLE | 0x2000 | Circle (Confirm / onPress action) |
BTN.CROSS | 0x4000 | Cross (Back) |
BTN.SQUARE | 0x8000 | Square |
onPress handler. The runtime handles CIRCLE automatically during focus navigation — you do not need to call focusNode or getFocused to intercept it. Use onButtonPress(BTN.CIRCLE, …) only for unconditional CIRCLE bindings outside the focus system.
focusNode
Programmatically focuses a node, or clears focus when called with null. Immediately calls ops.setFocus on the native core so the focus: style variant is applied synchronously.
The node to focus. Must be within the active focus scope (if any). Pass
null to clear focus entirely.focusNode(null) does not trigger the scope’s restoreFocus path — it is an explicit imperative clear. Use it sparingly; prefer letting the d-pad navigation and autoFocus handle focus automatically.
getFocused
Returns the currently focused NodeMirror, or null if no node is focused.
onFrame or button handler when you need to inspect focus without subscribing to changes.
pushFocusScope
Temporarily restricts d-pad traversal and CIRCLE press to the subtree rooted at node. Pushes an entry onto an internal scope stack; the returned disposer pops it and optionally restores the previously focused node.
The subtree root. All focusable nodes inside this subtree become reachable; nodes outside become unreachable while the scope is active.
Auto-focus and restore-focus behavior. See
FocusScopeOptions below.() => void — a disposer. Call it when the scope should be released. Calling more than once is safe.
Scopes are stacked — pushing a second scope while one is active restricts to the newer scope’s subtree. Popping the outer scope re-enters the inner one. This matches the Modal nesting contract.
FocusScopeOptions
| Field | Type | Default | Description |
|---|---|---|---|
autoFocus | boolean | true | Focus the first focusable descendant when the scope is pushed. Set to false to preserve current focus. |
restoreFocus | boolean | true | When the scope is disposed, restore focus to the node that was focused before the scope was pushed, if that node is still within the new active scope. |
pushFocusGrid
Gives the subtree rooted at node explicit row/column d-pad traversal semantics. Without a grid, UP/DOWN navigates forward/backward in document order; with a grid, UP/DOWN moves between rows and LEFT/RIGHT moves between columns.
The subtree root. Focusable nodes inside are addressed as a
columns-wide grid in document order.Grid column count and wrap behavior.
columns is required.() => void — a disposer that removes the grid registration from the stack. Calling more than once is safe.
Grid registrations are also stacked. The innermost grid that contains the currently focused node wins. A grid inside a scope works correctly — the grid narrows traversal within the scope’s already-narrowed subtree.
FocusGridOptions
| Field | Type | Default | Description |
|---|---|---|---|
columns | number | — | Number of columns. Required. Clamped to a minimum of 1. Drives traversal only — visible column count is determined by tile widths and container width. |
wrap | boolean | false | When true, pressing RIGHT at the last column of a row jumps to the first column of that row, and pressing LEFT at the first column jumps to the last. Same wrap applies vertically: pressing DOWN on the last row jumps to the same column of the first row. |
Focus model details
Understanding the focus model helps when building custom navigation patterns:- Default traversal order is document order over the mirror tree (DFS), derived lazily on each navigation press. It is always correct after
<For>reorders because it re-walks the live tree. - Active scope is the top of the
focusScopeStack, or the input root when the stack is empty. Navigation is confined to focusable nodes within the active scope’s subtree. - Active grid is the innermost
focusGridStackentry whose node contains the focused node and is within the active scope. Grid traversal overrides linear traversal when an active grid exists. - Focus loss on removal: when the focused node’s subtree is detached, focus moves to the next sibling subtree → previous sibling subtree → nearest focusable ancestor →
null. This repair happens before the mirror unlink so the transition is seamless. - CIRCLE: fires
onPresson the focused node, bubbling to the nearest ancestor that has a handler. The runtime handles this automatically — noonButtonPress(BTN.CIRCLE, …)is needed for standardFocusable/onPresspatterns.
Usage examples
Programmatic focus on mount:<FocusGrid columns={3}> from @pocketjs/framework/components — it wraps this pattern with reactive cleanup automatically.