@rive-app/canvas-lite
Version:
A lite version of Rive's canvas based web api.
83 lines (82 loc) • 4.36 kB
TypeScript
import * as rc from "../rive_advanced.mjs";
export interface KeyboardInteractionsParams {
canvas: HTMLCanvasElement;
stateMachine: rc.StateMachineInstance;
/**
* Whether this canvas has focus nodes that should participate in tab traversal.
* When true, Tab/Shift+Tab will be intercepted and routed to the Rive focus manager.
* focusNext() returning false means no more traversable nodes — tab is released to the page.
*/
hasFocusNodes: boolean;
}
/**
* Tracks the relationship between the canvas's DOM focus and Rive's internal focus for the
* current focus session.
*
* NotFocused — the canvas is not the active DOM element, or Rive entered and then released focus
* internally this session. Either way the next Tab should move on to the next page
* element, so Tab events are ignored.
* EntryPending — the canvas has DOM focus but Rive holds no active focus node yet, and the next Tab should enter
* the focus tree. This is the resting state for pointer-driven focus (a click on the
* canvas), or an edge case for keyboard focus where initial focus action did not land on a focus node.
* RiveFocused — a Rive node currently holds focus. Tab/Shift+Tab are routed to the Rive focus
* manager and trapped inside the canvas until Rive notifies focus has ended.
*
* When keyboard focus lands on the canvas, onCanvasFocus reads the direction focus came from and
* moves into the focus tree immediately, going straight to RiveFocused. EntryPending is only set via pointer focus (or keyboard focus
* where focusNext()/focusPrevious() return false but respects tabindex).
*/
export declare enum FocusSessionState {
NotFocused = "notFocused",
EntryPending = "entryPending",
RiveFocused = "riveFocused"
}
/**
* Manages keyboard and DOM focus interactions for a Rive canvas.
*
* Tracks the canvas focus session state (focusSessionState) and routes
* Tab/Shift+Tab to the Rive state machine's focus manager. Exposes shared
* state as properties so the Rive render loop can read them directly.
*/
export declare class KeyboardInteractions {
focusSessionState: FocusSessionState;
private canvas;
private mainSm;
private hasFocusNodes;
constructor({ canvas, stateMachine, hasFocusNodes }: KeyboardInteractionsParams);
/**
* Set the FocusSessionState. Useful for invoking a Rive "blur" without actually blurring from the <canvas>. This
* helps put the DOM focus state on the canvas rather than the <body>, so the user doesn't lose the spot in page navigation
*
* @param state FocusSessionState enum
*/
setFocusSessionState(state: FocusSessionState): void;
/**
* Called by pollFocusState on the Rive instance when it observes hasFocus=true. Rive acquired
* focus internally (e.g. via a listener action or state transition) without a DOM focus event,
* so mark the session RiveFocused.
*/
notifyRiveFocused(): void;
/**
* Handles the canvas gaining browser focus. The behavior differs based on how focus was gained -
*
* Pointer-driven focus: the canvas now has focus but Rive holds nothing yet, so we move to EntryPending — this lets the
* next Tab enter the focus tree even when the focus is pointer-driven
*
* Keyboard-driven focus: we enter the Rive focus tree immediately once canvas gains focus.
* The direction is inferred from where focus came from: an element before the canvas in DOM order
* means a forward Tab (focusNext), one after means a Shift+Tab (focusPrevious). :focus-visible
* gates this so a click doesn't yank Rive focus to the first node on the focus event itself.
*/
onCanvasFocus: (event: FocusEvent) => void;
onCanvasBlur: (_event: FocusEvent) => void;
onKeyDown: (event: KeyboardEvent) => void;
/**
* Whether the canvas currently matches :focus-visible — the browser's heuristic for keyboard-
* (vs pointer-) driven focus. For older browser versions that don't support this selector, return false
* so that we don't incorrectly assume pointer vs keyboard focus. Next tab would enter the focus tree in those edge cases.
*/
private isKeyboardDrivenFocus;
private cameFromBeforeCanvas;
cleanup(): void;
}