import * as react_jsx_runtime from 'react/jsx-runtime'; import { ReactNode } from 'react'; import './useInput-D8eE1Kzb.js'; /** * Terminal capability detection — platform-aware feature flags. * * Detects Windows Terminal, ConPTY, VS Code terminal, WSL, Git Bash, * and falls back gracefully for each capability. */ interface TerminalCapabilities { /** Operating system platform */ platform: NodeJS.Platform; /** Detected terminal emulator name */ terminal: string; /** Whether the terminal supports Unicode/box-drawing characters */ supportsUnicode: boolean; /** Whether 256-color ANSI is supported */ supports256Color: boolean; /** Whether 24-bit true-color is supported */ supportsTrueColor: boolean; /** Whether mouse events (click/scroll/drag) are supported */ supportsMouseEvents: boolean; /** Whether OSC 8 hyperlinks are supported */ supportsHyperlinks: boolean; /** Windows: whether ConPTY (modern virtual terminal) is active */ supportsConPTY: boolean; /** Whether the terminal is running inside WSL */ isWSL: boolean; /** Whether running inside VS Code integrated terminal */ isVSCode: boolean; /** Whether running inside Windows Terminal */ isWindowsTerminal: boolean; /** Whether running inside tmux or screen */ isMultiplexer: boolean; /** Whether running in a CI/CD environment */ isCI: boolean; /** Terminal column width */ columns: number; /** Terminal row height */ rows: number; /** Whether stdout is a TTY */ isTTY: boolean; } declare function getTerminalCapabilities(): TerminalCapabilities; /** * Reset the capabilities cache (useful in tests). */ declare function resetCapabilitiesCache(): void; /** @deprecated Use getTerminalCapabilities() instead */ declare function getCapabilities(): TerminalCapabilities; /** @deprecated Use resetCapabilitiesCache() then getTerminalCapabilities() instead */ declare function refreshCapabilities(): TerminalCapabilities; /** @deprecated Use getTerminalCapabilities() instead */ declare function detectCapabilities(): TerminalCapabilities; /** * Design token types for TermUI theming. * All theme objects must conform to this shape. */ interface ColorTokens { primary: string; primaryForeground: string; secondary: string; secondaryForeground: string; accent: string; accentForeground: string; success: string; successForeground: string; warning: string; warningForeground: string; error: string; errorForeground: string; info: string; infoForeground: string; background: string; foreground: string; muted: string; mutedForeground: string; border: string; focusRing: string; selection: string; selectionForeground: string; } interface SpacingTokens { 0: number; 1: number; 2: number; 3: number; 4: number; 6: number; 8: number; } interface TypographyTokens { bold: boolean; sm: string; base: string; lg: string; xl: string; } interface BorderTokens { style: 'single' | 'double' | 'round' | 'bold' | 'singleDouble' | 'doubleSingle' | 'classic'; color: string; focusColor: string; } interface Theme { name: string; colors: ColorTokens; spacing: SpacingTokens; typography: TypographyTokens; border: BorderTokens; } /** * Detect whether the terminal uses a dark or light background. * * Reads the `COLORFGBG` environment variable (set by most terminals in * `"foreground;background"` format) and falls back to `TERM_BACKGROUND`. * Defaults to `'dark'` when neither variable is present — most developer * terminals use dark themes. * * @returns `'dark'` or `'light'`. * * @example * ```tsx * const scheme = detectColorScheme(); * const theme = scheme === 'dark' ? darkTheme : lightTheme; * ``` */ declare function detectColorScheme(): 'dark' | 'light'; /** Props for `AutoThemeProvider`. */ interface AutoThemeProviderProps { /** Theme applied when the terminal background is detected as dark. */ darkTheme: Theme; /** Theme applied when the terminal background is detected as light. */ lightTheme: Theme; children: ReactNode; } /** * Automatically selects between a dark and light theme based on the terminal's * colour scheme, detected via `detectColorScheme()`. Renders a `ThemeProvider` * with the appropriate theme so child components receive the correct tokens * without any manual switching logic. * * @param props.darkTheme - Theme used when the terminal background is dark. * @param props.lightTheme - Theme used when the terminal background is light. * @param props.children - React subtree that will receive the selected theme. * * @example * ```tsx * function App() { * return ( * * * * ); * } * ``` */ declare function AutoThemeProvider({ darkTheme, lightTheme, children }: AutoThemeProviderProps): react_jsx_runtime.JSX.Element; interface ThemeProviderProps { theme?: Theme; reducedMotion?: boolean; /** * Force ASCII/no-Unicode mode for all child components. * When omitted, auto-detected from `NO_UNICODE=1` env var and terminal * capability detection (`supportsUnicode`). */ noUnicode?: boolean; children: ReactNode; } /** * Provide a theme to all child TermUI components. * * Wrap your root component with `ThemeProvider` to apply a custom theme. * All TermUI components consume the theme via `useTheme()`. The theme can * be changed at runtime by passing a new `theme` prop. * * @param props.theme - Theme object (default: `defaultTheme`). Create custom * themes with `createTheme()`. * @param props.reducedMotion - Force reduced motion for all animated children. * When omitted, automatically detected from `NO_MOTION` / `CI` env vars. * @param props.noUnicode - Force ASCII fallbacks for all animated children. * When omitted, automatically detected from `NO_UNICODE=1` / terminal capabilities. * @param props.children - React child tree that will receive the theme. * * @example * ```tsx * import { ThemeProvider, createTheme } from 'termui'; * * const myTheme = createTheme({ name: 'my-theme', colors: { primary: '#ff6b6b' } }); * * function App() { * return ( * * * * ); * } * ``` */ declare function ThemeProvider({ theme, reducedMotion, noUnicode, children, }: ThemeProviderProps): react_jsx_runtime.JSX.Element; /** * Consume the current theme from `ThemeProvider` context. * * Returns the active `Theme` object. Falls back to `defaultTheme` when used * outside a `ThemeProvider`. Re-renders the component whenever the theme changes. * * @returns The active `Theme` object. * * @example * ```tsx * function MyComponent() { * const theme = useTheme(); * return Hello; * } * ``` */ declare function useTheme(): Theme; /** * Return the `setTheme` setter from the nearest `ThemeProvider`. Call the * returned function with a new `Theme` object to swap the active theme at * runtime (e.g. in response to a user preference toggle). * * @returns A stable `(theme: Theme) => void` dispatcher. Falls back to a * no-op when called outside a `ThemeProvider`. * * @example * ```tsx * function ThemeToggle() { * const setTheme = useThemeUpdater(); * return ( * * ); * } * ``` */ declare function useThemeUpdater(): (theme: Theme) => void; /** * Create a custom theme by deep-merging with the default theme. * * Top-level keys (`colors`, `spacing`, `typography`, `border`) are merged * shallowly so you only need to provide the values you want to override. * All other keys from `defaultTheme` are preserved. * * @param overrides - Partial theme overrides. `name` is required to identify * the theme. Nested objects (`colors`, `spacing`, etc.) are merged with the * defaults — only the keys you specify are overridden. * @returns A complete `Theme` object ready for use with `ThemeProvider`. * * @example * ```tsx * const myTheme = createTheme({ * name: 'ocean', * colors: { primary: '#0ea5e9', secondary: '#38bdf8' }, * }); * ``` */ declare function createTheme(overrides: Partial & { name: string; }): Theme; /** * Track and control focus state for a single component. Delegates to Ink's * `useFocus` and participates in the global tab-focus cycle managed by * `useFocusManager`. * * @param options.autoFocus - When `true`, the component captures focus * immediately on mount without waiting for a tab keypress. Defaults to `false`. * @param options.isActive - When `false`, the component is excluded from the * focus cycle entirely (useful for conditionally disabled elements). Defaults * to `true`. * @param options.id - Optional stable identifier so `useFocusManager().focus(id)` * can target this component by name. Must be unique across the component tree. * @returns An object with `isFocused: boolean` — `true` when this component * currently holds keyboard focus. * * @example * ```tsx * function SearchInput() { * const { isFocused } = useFocus({ autoFocus: true, id: 'search' }); * return ( * * * * ); * } * ``` */ declare function useFocus(options?: { autoFocus?: boolean; isActive?: boolean; id?: string; }): { isFocused: boolean; focus: (id: string) => void; }; /** * Programmatically control the global focus cycle across all focusable * components. Delegates to Ink's `useFocusManager` and is most useful for * implementing custom keyboard navigation, modal traps, or focus-reset logic. * * @returns An object with the following methods: * - `focus(id)` — Move focus directly to the component registered with the * given `id` (set via `useFocus({ id })`). * - `disableFocus()` — Suspend the entire focus system; no component will * receive focus until `enableFocus()` is called. Useful when a modal or * overlay should capture all input exclusively. * - `enableFocus()` — Resume normal focus management after a * `disableFocus()` call. * - `focusNext()` — Advance focus to the next component in tab order. * - `focusPrevious()` — Move focus back to the previous component in tab * order (equivalent to Shift+Tab). * * @example * ```tsx * function App() { * const { focus, focusNext, focusPrevious, disableFocus, enableFocus } = * useFocusManager(); * * useInput((input, key) => { * if (key.tab) focusNext(); * if (key.shift && key.tab) focusPrevious(); * if (input === 'r') focus('search'); // jump to a named component * }); * * return ; * } * ``` */ declare function useFocusManager(): { enableFocus: () => void; disableFocus: () => void; focusNext: () => void; focusPrevious: () => void; focus: (id: string) => void; }; interface UseTerminalResult extends TerminalCapabilities { /** Full cross-platform capability snapshot (same object as the hook result itself) */ capabilities: TerminalCapabilities; } /** * Get terminal size and capabilities. * * Returns live terminal dimensions (updates on resize) and a snapshot * of terminal capability flags (color depth, Unicode support, etc.). * * @returns Object with `columns`, `rows`, `isTTY`, `supportsUnicode`, * `supports256Color`, `supportsTrueColor`, `capabilities` (full snapshot). * * @example * ```tsx * const { columns, rows, supportsTrueColor } = useTerminal(); * const label = columns > 80 ? 'Wide layout' : 'Narrow layout'; * ``` */ declare function useTerminal(): UseTerminalResult; /** * Drive frame-based animations at a configurable frame rate. * * Returns a monotonically increasing frame counter. Use `frame % frames.length` * to cycle through animation frames. The counter increments at `fps` times per * second using `requestAnimationFrame`-equivalent timing. * * All instances at the same fps share a single interval for efficient batching — * React 18 can batch their `setState` calls into a single re-render per tick. * * @param fps - Frames per second (default: 12). Lower values (6–10) save CPU; * higher values (24–30) produce smoother animations. * @returns Current frame index (increments at the given fps rate). * * @example * ```tsx * const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴']; * function Spinner() { * const frame = useAnimation(12); * return {FRAMES[frame % FRAMES.length]}; * } * ``` */ declare function useAnimation(fps?: number): number; /** * React-safe `setInterval` with automatic cleanup. * * Clears the interval when the component unmounts. The latest `callback` * reference is always used (no stale closure issues). * * @param callback - Function called on each interval tick. * @param delay - Interval delay in milliseconds. Pass `null` to pause. * * @example * ```tsx * const [count, setCount] = useState(0); * useInterval(() => setCount(c => c + 1), 1000); * // count increments every second * ``` */ declare function useInterval(callback: () => void, delay: number | null): void; /** * Write to the system clipboard using OSC 52 sequences. * * OSC 52 is supported by most modern terminals (iTerm2, Windows Terminal, * Alacritty, Kitty, VS Code terminal). Falls back gracefully when not * supported — writes are silently ignored. * * @returns `{ write(text): void }` — `write` sends `text` to the terminal * clipboard via an OSC 52 escape sequence. * * @example * ```tsx * const { write } = useClipboard(); * // Copy to clipboard: * write('some text'); * ``` */ declare function useClipboard(): { write: (text: string) => void; }; type KeyBinding = { key?: string; ctrl?: boolean; shift?: boolean; meta?: boolean; action: () => void; }; /** * Register declarative keybindings with conflict detection. * * Provides a structured way to declare keyboard shortcuts. Conflicts * (two handlers registered for the same key combination) are warned at runtime. * * @param bindings - Array of `KeyBinding` objects with `key`, optional modifier * flags (`ctrl`, `shift`, `meta`), and an `action` callback. `key` can be a * single character or a special key name (`escape`, `return`). * @param isActive - Whether input handling is active (default: true). * Set to `false` to pause all bindings without unmounting. * * @example * ```tsx * useKeymap([ * { key: 'q', action: () => process.exit(0) }, * { key: 'r', action: reload }, * { key: 'c', ctrl: true, action: () => process.exit(0) }, * ]); * ``` */ declare function useKeymap(bindings: KeyBinding[], isActive?: boolean): void; type MouseButton = 'left' | 'middle' | 'right' | 'scrollUp' | 'scrollDown'; interface MouseEvent { type: 'press' | 'release' | 'move'; button: MouseButton; x: number; y: number; ctrl: boolean; shift: boolean; meta: boolean; } type MouseHandler = (event: MouseEvent) => void; /** * Subscribe to terminal mouse events including clicks, releases, and scroll * wheel input. Enables the xterm SGR mouse protocol (`?1000h`, `?1002h`, * `?1006h`) on mount and cleanly disables it on unmount. Has no effect in * non-TTY environments (e.g. CI pipes). * * @param handler - Callback invoked for every mouse event. Receives a * `MouseEvent` describing the interaction: * - `type` — `'press'` on button-down, `'release'` on button-up. * - `button` — Which button triggered the event: `'left'`, `'middle'`, * `'right'`, `'scrollUp'`, or `'scrollDown'`. * - `x` / `y` — 1-based terminal column and row of the cursor. * - `ctrl` / `shift` / `meta` — Modifier key state at the time of the event. * The handler reference is kept stable internally via a ref, so it is safe * to pass an inline function without wrapping in `useCallback`. * * @example * ```tsx * function ClickableBox() { * useMouse((event) => { * if (event.type === 'press' && event.button === 'left') { * console.log(`Left click at (${event.x}, ${event.y})`); * } * if (event.button === 'scrollUp') { * setOffset((o) => Math.max(0, o - 1)); * } * if (event.button === 'scrollDown') { * setOffset((o) => o + 1); * } * }); * * return Scroll or click me; * } * ``` */ declare function useMouse(handler: MouseHandler): void; interface TerminalSize { columns: number; rows: number; } /** * Reactively track terminal size changes. * * Returns the current `{ columns, rows }` and re-renders the component * whenever the terminal is resized. Updates are debounced to avoid * excessive re-renders during resize drags. * * @param debounceMs - Debounce delay in milliseconds (default: 50). * @returns `TerminalSize` — `{ columns, rows }`. * * @example * ```tsx * const { columns } = useResize(); * return Full width content; * ``` */ declare function useResize(debounceMs?: number): TerminalSize; type AsyncState = { status: 'idle'; data: null; error: null; } | { status: 'loading'; data: null; error: null; } | { status: 'success'; data: T; error: null; } | { status: 'error'; data: null; error: Error; }; /** * Manage async data loading with loading/error/data states. * * Re-runs the async function when `deps` change (same semantics as `useEffect`). * Returns `{ data, loading, error }` — exactly one of `data` or `error` will be * non-null after the promise settles. Stale requests (superseded by a newer * `deps` change) are automatically cancelled via a mounted ref guard. * * @param fn - Async factory that returns the data. Called on mount and * whenever `deps` change. * @param deps - Dependency array (same as React `useEffect` deps). * @returns `AsyncState` — `{ status, data, error, refetch }`. * * @example * ```tsx * const { data, status, error } = useAsync(() => fetchPackages(), [query]); * if (status === 'loading') return ; * if (status === 'error') return {error.message}; * return ; * ``` */ declare function useAsync(asyncFn: () => Promise, deps?: unknown[]): AsyncState & { refetch: () => void; }; export { type AsyncState as A, type BorderTokens as B, type ColorTokens as C, type KeyBinding as K, type MouseButton as M, type SpacingTokens as S, type TerminalCapabilities as T, AutoThemeProvider as a, type AutoThemeProviderProps as b, type MouseEvent as c, type TerminalSize as d, type Theme as e, ThemeProvider as f, type TypographyTokens as g, createTheme as h, detectCapabilities as i, detectColorScheme as j, getCapabilities as k, getTerminalCapabilities as l, resetCapabilitiesCache as m, useAsync as n, useClipboard as o, useFocus as p, useFocusManager as q, refreshCapabilities as r, useInterval as s, useKeymap as t, useAnimation as u, useMouse as v, useResize as w, useTerminal as x, useTheme as y, useThemeUpdater as z };