/** * Screen/State management types for ECSpresso ECS framework */ import type ECSpresso from './ecspresso'; /** * Definition for a screen including its state, lifecycle hooks, and requirements */ export interface ScreenDefinition = Record, State extends Record = Config, World = ECSpresso> { /** * Function to create initial state from config */ readonly initialState: (config: Config) => State; /** * Lifecycle hook called when entering this screen */ readonly onEnter?: (ctx: { config: Config; ecs: World; }) => void | Promise; /** * Lifecycle hook called when exiting this screen */ readonly onExit?: (ecs: World) => void | Promise; /** * Lifecycle hook called when this stacked screen becomes current again * after an overlay is popped. */ readonly onResume?: (ctx: { config: Config; state: State; ecs: World; }) => void | Promise; /** * Asset keys that must be loaded before entering this screen */ readonly requiredAssets?: ReadonlyArray; /** * Asset groups that must be loaded before entering this screen */ readonly requiredAssetGroups?: ReadonlyArray; } /** * Entry in the screen stack for overlay support */ export interface ScreenStackEntry>, K extends keyof Screens = keyof Screens> { readonly name: K; readonly config: Screens[K] extends ScreenDefinition ? Readonly : never; state: Screens[K] extends ScreenDefinition ? S : never; } /** * Helper to extract config type from a screen definition */ export type ScreenConfig> = S extends ScreenDefinition ? C : never; /** * Helper to extract state type from a screen definition */ export type ScreenState> = S extends ScreenDefinition ? St : never; /** * Resource interface for accessing screen state in systems * Exposed as $screen resource */ export interface ScreenResource>> { /** * Current active screen name, or null if no screen */ readonly current: keyof Screens | null; /** * Immutable config of the current screen */ readonly config: Readonly> | null; /** * Mutable state of the current screen */ state: ScreenState | null; /** * The screen stack (read-only view) */ readonly stack: ReadonlyArray>; /** * Whether the current screen is an overlay (has screens beneath it) */ readonly isOverlay: boolean; /** * Current depth of the screen stack */ readonly stackDepth: number; /** * Check if a specific screen is currently active (either current or in stack) */ isActive(screenName: keyof Screens): boolean; /** * Check if a specific screen is the current screen */ isCurrent(screenName: keyof Screens): boolean; } /** * Events emitted by the screen system. * @typeParam S - Screen name type (defaults to `string` for backward compatibility) */ export interface ScreenEvents { screenEnter: { screen: S; config: unknown; }; screenExit: { screen: S; }; screenPush: { screen: S; config: unknown; }; screenPop: { screen: S; }; screenResume: { screen: S; config: unknown; state: unknown; }; } /** * Configuration for screen definitions during builder setup */ export interface ScreenConfigurator>, W = unknown> { /** * Add a screen definition */ add, State extends Record>(name: K, definition: ScreenDefinition): ScreenConfigurator>, W>; } /** * Callback shape for extracted screen configurator helpers. */ export type ScreenConfiguratorFn>> = (screens: ScreenConfigurator<{}, World>) => ScreenConfigurator; /** * Type-safe screen state getter result */ export type CurrentScreenState>, CurrentScreen extends keyof Screens> = Screens[CurrentScreen] extends ScreenDefinition ? S : never; /** * Type-safe screen config getter result */ export type CurrentScreenConfig>, CurrentScreen extends keyof Screens> = Screens[CurrentScreen] extends ScreenDefinition ? Readonly : never;