/** * AppPickerPanel * * Self-contained app picker UI rendered inside the GenerateDialog when the user * expands "Choose a specific app (optional)". * * Features: * - Debounced search-as-you-type — typing triggers `onSearchSubmit(query)` * after 500ms of inactivity. Parent fires apps.discover(query) and pipes * results back via `apps`. Empty query → parent should revert to apps.list(). * - Modality toggle — when apps carry modality metadata, default-filter to * the field's modality with a "Show all" escape. * - Card grid — 16:9 thumbnails (image or video preview), 2 columns, * responsive. Cards without thumbnails get a uniform "No preview" placeholder. * * The parent (GenerateDialog) owns the apps[] state and load logic; this * component is pure presentation + local search-input state + debounce. */ import type { LaminaPreset } from '../types.js'; export type AppPickerMode = 'list' | 'discover'; export interface AppPickerEntry { appId: string; name: string; description: string | null; modality?: string | null; outputFormats?: string[]; thumbnail?: { url: string; type: 'image' | 'video'; } | null; } interface AppPickerPanelProps { /** Loaded apps (already mapped from list/discover response). */ apps: AppPickerEntry[]; /** Currently selected appId (highlighted in the grid). */ selectedAppId: string | null; /** Mode of the loaded apps: 'list' = all available, 'discover' = ranked-by-search-query. */ mode: AppPickerMode; /** True while the parent is loading apps. */ loading: boolean; /** Error from a failed load (or null). */ error: string | null; /** Field's target modality (e.g. 'image', 'video') used by the modality toggle. */ targetModality: string | null; /** Pin/unpin an app. Parent handles routing memory + estimate fetch. */ onSelect: (app: AppPickerEntry) => void; /** * Fired AFTER the user pauses typing for SEARCH_DEBOUNCE_MS. * Parent should call apps.discover(query) when query is non-empty, * or apps.list() when query is empty (to revert to "all apps"). */ onSearchSubmit: (query: string) => void; /** Clear the pinned selection. */ onClearSelection: () => void; } export declare function AppPickerPanel({ apps, selectedAppId, mode, loading, error, targetModality, onSelect, onSearchSubmit, onClearSelection, }: AppPickerPanelProps): import("react/jsx-runtime").JSX.Element; export type { LaminaPreset };