@nmakarov/cli-toolkit 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/screen/index.ts","../src/screen/screens.ts","../src/screen/components.ts","../src/screen/list-components.ts","../src/screen/ui-elements.ts","../src/screen/utils.ts","../src/screen/footer-builder.ts"],"sourcesContent":["/**\n * Screen System - Action-based architecture\n * Converted from legacy/screenSystem/src\n */\n\n// Screen functions\nexport {\n showScreen,\n showListScreen,\n showMultiColumnListScreen,\n showMultiColumnListWithPreviewScreen,\n // Backward compatibility aliases\n showMenuScreen,\n showWordGridScreen\n} from \"./screens.js\";\n\n// Reusable components\nexport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\nexport { ScreenContainer, ScreenRow, ScreenTitle, ScreenBody, ScreenFooter, ScreenDivider } from \"./components.js\";\nexport { ListItem, TextBlock, Divider, GridCell, InputField } from \"./ui-elements.js\";\n\n// Utilities\nexport { buildBreadcrumb, buildDetailBreadcrumb } from \"./utils.js\";\nexport { buildFooter, FooterPresets, organizeFooterMessages } from \"./footer-builder.js\";\n","/**\n * Screen System - Action-based architecture\n */\n\nimport React, { useState, useRef, useEffect, createElement as h } from \"react\";\nimport { render, useInput, Box, Text } from \"ink\";\nimport { ScreenContainer, ScreenRow, ScreenTitle, ScreenDivider, ScreenFooter } from \"./components.js\";\nimport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\n\n// Types\ninterface KeyBinding {\n key: string;\n caption: string | (() => string | JSX.Element);\n action: string;\n order?: number;\n protected?: boolean;\n enabled?: boolean;\n condition?: (ctx: ScreenContext) => boolean;\n}\n\ninterface BindingGroup {\n keys: string[];\n caption: string;\n order: number;\n}\n\ninterface ActionPayload {\n input: string;\n key: any;\n binding: KeyBinding;\n}\n\ninterface ScreenContext {\n setAction: (actionName: string, handlerFn: (payload?: ActionPayload) => void | any) => void;\n setKeyBinding: (bindingOrBindings: KeyBinding | KeyBinding[]) => void;\n updateKeyBinding: (keyName: string, updates: Partial<KeyBinding>) => void;\n removeKeyBinding: (keyName: string) => void;\n addFooter: (item: string | JSX.Element) => void;\n clearFooter: () => void;\n setFooter: (items: string | string[] | JSX.Element | JSX.Element[]) => void;\n update: () => void;\n goBack: () => void;\n close: (result: any) => void;\n parentData: any;\n}\n\ninterface ShowScreenConfig {\n title: string;\n onRender: (ctx: ScreenContext) => JSX.Element;\n parentData?: any;\n}\n\ninterface ShowListScreenConfig {\n title: string;\n items: Array<{ name: string; value: any }>;\n onSelect?: (value: any, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n renderItem?: (item: { name: string; value: any }, isSelected: boolean, displayIndex: number) => JSX.Element;\n getTitle?: (item: { name: string; value: any }) => string;\n sortable?: boolean;\n maxHeight?: number;\n sortHighlightStyle?: {\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n };\n selectionMarker?: string; // Customizable selection marker, default: \" \"\n}\n\ninterface ShowMultiColumnListScreenConfig {\n title: string;\n items: string[];\n onSelect?: (item: string, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n}\n\ninterface ShowMultiColumnListWithPreviewScreenConfig {\n title: string;\n items: string[];\n getPreviewContent?: (item: string) => string | JSX.Element | Record<string, any>;\n onSelect?: (item: string, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n}\n\n/**\n * Group key bindings by caption for footer display\n */\nexport function groupKeyBindings(bindings: KeyBinding[]): BindingGroup[] {\n const groups: Record<string, BindingGroup> = {};\n\n // Filter out disabled bindings\n const enabledBindings = bindings.filter(b => b.enabled !== false);\n\n enabledBindings.forEach(binding => {\n const caption = typeof binding.caption === \"string\" ? binding.caption : \"\";\n if (!groups[caption]) {\n groups[caption] = {\n keys: [],\n caption: caption,\n order: binding.order || 999\n };\n }\n groups[caption].keys.push(binding.key);\n });\n\n return Object.values(groups);\n}\n\n/**\n * Format key bindings for footer (returns array of strings/components)\n */\nexport function formatKeyBindings(bindings: KeyBinding[], mode: string = \"long\"): (string | JSX.Element)[] {\n // Resolve function captions\n const resolvedBindings = bindings.map(binding => {\n let resolvedCaption = binding.caption;\n\n // If caption is a function, call it\n if (typeof binding.caption === \"function\") {\n resolvedCaption = binding.caption();\n }\n\n return {\n ...binding,\n resolvedCaption\n };\n });\n\n const groups = groupKeyBindings(resolvedBindings.map(b => ({\n ...b,\n caption: typeof b.resolvedCaption === \"string\" ? b.resolvedCaption : \"\"\n })));\n\n // Sort by order\n groups.sort((a, b) => a.order - b.order);\n\n const items: (string | JSX.Element)[] = [];\n\n groups.forEach(group => {\n // Check if any binding in this group has a component/custom caption\n const bindingWithCustom = resolvedBindings.find(b =>\n group.keys.includes(b.key) && typeof b.resolvedCaption !== \"string\"\n );\n\n if (bindingWithCustom && bindingWithCustom.resolvedCaption) {\n // Use the full custom display (component or complex structure)\n items.push(bindingWithCustom.resolvedCaption as JSX.Element);\n } else {\n // Standard format with string caption\n const keyStr = formatKeys(group.keys);\n\n if (mode === \"long\") {\n items.push(`${keyStr} to ${group.caption}`);\n } else {\n items.push(keyStr);\n }\n }\n });\n\n return items;\n}\n\n/**\n * Format keys for display\n */\nexport function formatKeys(keys: string[]): string {\n const keyMap: Record<string, string> = {\n \"escape\": \"esc\",\n \"leftArrow\": \"←\",\n \"rightArrow\": \"→\",\n \"upArrow\": \"↑\",\n \"downArrow\": \"↓\",\n \"return\": \"enter\"\n };\n\n return keys.map(k => keyMap[k] || k).join(\"/\");\n}\n\n/**\n * Show screen with action-based architecture\n */\nexport async function showScreen(config: ShowScreenConfig): Promise<any> {\n const {\n title,\n onRender,\n parentData = {}\n } = config;\n\n\n return new Promise((resolve) => {\n let instance: any;\n\n // Persistent collections (closure variables survive re-renders)\n const keyBindings: KeyBinding[] = [];\n const actions: Record<string, (payload?: ActionPayload) => void | any> = {};\n const customFooterItems: (string | JSX.Element)[] = [];\n let renderResult: JSX.Element | null = null;\n let initialized = false;\n\n const Screen = (): JSX.Element => {\n const [updateCounter, setUpdateCounter] = useState(0);\n\n // Initialize defaults only once\n if (!initialized) {\n const defaultBindings: KeyBinding[] = [\n { key: \"escape\", caption: \"go back\", action: \"back\", protected: true, order: 1 },\n { key: \"leftArrow\", caption: \"go back\", action: \"back\", protected: false, order: 1 }\n // Note: 'select' is not a default - components add it if needed\n ];\n\n // Add defaults\n defaultBindings.forEach(binding => {\n keyBindings.push(binding);\n });\n\n // Default actions\n actions.back = () => {\n cleanup(null);\n };\n\n initialized = true;\n }\n\n // Context for onRender\n const context: ScreenContext = {\n setAction: (actionName: string, handlerFn: (payload?: ActionPayload) => void | any) => {\n actions[actionName] = handlerFn;\n },\n\n setKeyBinding: (bindingOrBindings: KeyBinding | KeyBinding[]) => {\n // Support both single object and array\n const bindingsToSet = Array.isArray(bindingOrBindings) ? bindingOrBindings : [bindingOrBindings];\n\n bindingsToSet.forEach(binding => {\n // Check if key already exists\n const existingIndex = keyBindings.findIndex(b => b.key === binding.key);\n\n if (existingIndex >= 0) {\n const existing = keyBindings[existingIndex];\n\n // Can't override protected keys\n if (existing.protected) {\n console.warn(`Cannot override protected key: ${binding.key}`);\n return;\n }\n\n // Replace binding (keep original order if not specified)\n keyBindings[existingIndex] = {\n ...existing,\n ...binding,\n order: binding.order !== undefined ? binding.order : existing.order,\n enabled: binding.enabled !== undefined ? binding.enabled : (existing.enabled !== undefined ? existing.enabled : true)\n };\n } else {\n // Add new binding\n keyBindings.push({\n protected: false,\n order: 999,\n enabled: true,\n ...binding\n });\n }\n });\n },\n\n updateKeyBinding: (keyName: string, updates: Partial<KeyBinding>) => {\n const index = keyBindings.findIndex(b => b.key === keyName);\n if (index >= 0) {\n // Update only specified properties\n keyBindings[index] = {\n ...keyBindings[index],\n ...updates\n };\n }\n },\n\n removeKeyBinding: (keyName: string) => {\n const index = keyBindings.findIndex(b => b.key === keyName);\n if (index >= 0) {\n if (keyBindings[index].protected) {\n console.warn(`Cannot remove protected key: ${keyName}`);\n return;\n }\n keyBindings.splice(index, 1);\n }\n },\n\n addFooter: (item: string | JSX.Element) => {\n customFooterItems.push(item);\n },\n\n clearFooter: () => {\n customFooterItems.length = 0;\n },\n\n setFooter: (items: string | string[] | JSX.Element | JSX.Element[]) => {\n customFooterItems.length = 0;\n const itemsArray = Array.isArray(items) ? items : [items];\n customFooterItems.push(...itemsArray);\n },\n\n update: () => {\n setUpdateCounter(c => c + 1);\n },\n\n goBack: () => {\n if (actions.back) {\n actions.back();\n }\n },\n\n close: (result: any) => {\n cleanup(result);\n },\n\n parentData\n };\n\n // Call onRender once to let component set up\n if (!renderResult) {\n renderResult = onRender(context);\n }\n\n // Handle input - dispatch to actions\n useInput((input: string, key: any) => {\n // Check Ctrl+C for exit\n if (key.ctrl && input === \"c\") {\n cleanup(null);\n process.exit(0);\n return;\n }\n\n // Find matching key binding\n let matchedBinding: KeyBinding | null = null;\n\n for (const binding of keyBindings) {\n let keyMatches = false;\n\n // Check key match\n if (key[binding.key]) {\n keyMatches = true;\n } else if (input === binding.key) {\n keyMatches = true;\n }\n\n if (keyMatches) {\n // Check if binding is enabled\n if (binding.enabled === false) {\n continue;\n }\n\n // Check condition if present\n if (binding.condition && !binding.condition(context)) {\n continue;\n }\n\n matchedBinding = binding;\n break;\n }\n }\n\n if (matchedBinding && actions[matchedBinding.action]) {\n // Execute action\n const actionResult = actions[matchedBinding.action]({\n input,\n key,\n binding: matchedBinding\n });\n\n // If action returns a value, might be used for something\n // For now, actions manage their own state via closures\n }\n });\n\n // Build footer\n const footerLines: (string | JSX.Element | (string | JSX.Element)[])[] = [];\n\n // Add key bindings (returns array of strings/components)\n const bindingItems = formatKeyBindings(keyBindings, \"long\");\n\n if (bindingItems.length > 0) {\n // Build a single line with all binding items separated by \", \"\n const bindingsLine: (string | JSX.Element)[] = [];\n bindingItems.forEach((item, idx) => {\n if (idx > 0) {\n bindingsLine.push(\", \");\n }\n bindingsLine.push(item);\n });\n\n // If all items are strings, join them; otherwise create a Box\n const allStrings = bindingItems.every(item => typeof item === \"string\");\n if (allStrings) {\n footerLines.push(bindingsLine.join(\"\"));\n } else {\n // Mixed strings and components - wrap all strings in Text components\n const wrappedBindingsLine = bindingsLine.map(item => \n typeof item === \"string\" ? h(Text, {}, item) : item\n );\n footerLines.push(wrappedBindingsLine);\n }\n }\n\n // Add custom footer items\n customFooterItems.forEach(item => {\n if (typeof item === \"string\") {\n footerLines.push(item);\n } else {\n footerLines.push(item);\n }\n });\n\n return h(ScreenContainer, {},\n h(ScreenTitle, { text: title }),\n h(ScreenDivider),\n h(ScreenRow, {}, h(Text, {}, \" \")),\n renderResult,\n h(ScreenRow, {}, h(Text, {}, \" \")),\n h(ScreenDivider),\n h(ScreenFooter, { lines: footerLines })\n );\n };\n\n const cleanup = (result: any) => {\n if (instance) instance.unmount();\n setTimeout(() => resolve(result), 50);\n };\n\n instance = render(h(Screen));\n });\n}\n\n/**\n * Helper: Show list screen (single column menu)\n */\nexport async function showListScreen(config: ShowListScreenConfig): Promise<any> {\n const { title, items, onSelect, onEscape, parentData, initialSelectedIndex = 0, renderItem, getTitle, sortable, maxHeight, sortHighlightStyle, selectionMarker } = config;\n\n return showScreen({\n title,\n parentData,\n onRender: (ctx) => {\n // Shared state ref\n const selectedIndexRef = { current: initialSelectedIndex };\n\n // Set up select action at screen level\n ctx.setAction(\"select\", () => {\n const selected = items[selectedIndexRef.current];\n if (onSelect) {\n const result = onSelect(selected.value, selectedIndexRef.current);\n ctx.close(result);\n }\n });\n\n // Set up back action if provided\n if (onEscape) {\n ctx.setAction(\"back\", () => {\n const result = onEscape(selectedIndexRef.current);\n ctx.close(result);\n });\n }\n\n // Add select key binding\n ctx.setKeyBinding({ key: \"return\", caption: \"select\", action: \"select\", order: 2 });\n\n // Return the component (it will set up its own navigation actions and bindings)\n return h(ListComponent, { items, ctx, selectedIndexRef, renderItem, getTitle, sortable, maxHeight, sortHighlightStyle, selectionMarker });\n }\n });\n}\n\n/**\n * Helper: Show multi-column list screen (grid layout)\n */\nexport async function showMultiColumnListScreen(config: ShowMultiColumnListScreenConfig): Promise<any> {\n const { title, items, onSelect, onEscape, parentData, initialSelectedIndex = 0 } = config;\n\n return showScreen({\n title,\n parentData,\n onRender: (ctx) => {\n // Shared state ref\n const selectedIndexRef = { current: initialSelectedIndex };\n\n // Set up select action at screen level\n ctx.setAction(\"select\", () => {\n const selected = items[selectedIndexRef.current];\n if (onSelect) {\n const result = onSelect(selected, selectedIndexRef.current);\n ctx.close(result);\n }\n });\n\n // Set up back action if provided\n if (onEscape) {\n ctx.setAction(\"back\", () => {\n const result = onEscape(selectedIndexRef.current);\n ctx.close(result);\n });\n }\n\n // Add select key binding\n ctx.setKeyBinding({ key: \"return\", caption: \"select\", action: \"select\", order: 2 });\n\n // Return the component (it will set up its own navigation actions and bindings)\n return h(MultiColumnListComponent, { items, ctx, selectedIndexRef });\n }\n });\n}\n\n/**\n * Helper: Show multi-column list with preview panel below\n */\nexport async function showMultiColumnListWithPreviewScreen(config: ShowMultiColumnListWithPreviewScreenConfig): Promise<any> {\n const { title, items, getPreviewContent, onSelect, onEscape, parentData, initialSelectedIndex = 0 } = config;\n\n return showScreen({\n title,\n parentData,\n onRender: (ctx) => {\n // Shared state ref\n const selectedIndexRef = { current: initialSelectedIndex };\n\n // Set up select action at screen level\n ctx.setAction(\"select\", () => {\n const selected = items[selectedIndexRef.current];\n if (onSelect) {\n const result = onSelect(selected, selectedIndexRef.current);\n ctx.close(result);\n }\n });\n\n // Set up back action if provided\n if (onEscape) {\n ctx.setAction(\"back\", () => {\n const result = onEscape(selectedIndexRef.current);\n ctx.close(result);\n });\n }\n\n // Add select key binding\n ctx.setKeyBinding({ key: \"return\", caption: \"select\", action: \"select\", order: 2 });\n\n // Return the component (it will set up its own navigation actions and bindings)\n return h(MultiColumnListWithPreviewComponent, { items, getPreviewContent, ctx, selectedIndexRef });\n }\n });\n}\n\n// Backward compatibility aliases\nexport const showMenuScreen = showListScreen;\nexport const showWordGridScreen = showMultiColumnListScreen;\n","/**\n * Core screen layout components\n */\n\nimport React, { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\n\n/**\n * Get screen width for borders\n * @param maxWidth - Optional max width (null = no limit)\n */\nexport function getScreenWidth(maxWidth: number | null = null): number {\n const terminalWidth = process.stdout.columns || 80;\n // Leave some margin for borders and padding\n const availableWidth = Math.max(20, terminalWidth - 4);\n return maxWidth ? Math.min(availableWidth, maxWidth) : availableWidth;\n}\n\n// Types\nexport interface ScreenContainerProps {\n children: React.ReactNode;\n}\n\nexport interface ScreenRowProps {\n children: React.ReactNode;\n}\n\nexport interface ScreenTitleProps {\n text: string;\n}\n\nexport interface ScreenDividerProps {\n width?: number;\n}\n\nexport interface ScreenBodyProps {\n children: React.ReactNode;\n alignItems?: \"flex-start\" | \"center\" | \"flex-end\";\n}\n\nexport interface ScreenFooterProps {\n lines: (string | JSX.Element)[];\n textStyle?: {\n color?: string;\n dimColor?: boolean;\n bold?: boolean;\n };\n}\n\n/**\n * Screen Container - uses Ink's built-in borderStyle for proper text wrapping\n */\nexport function ScreenContainer({ children }: ScreenContainerProps): JSX.Element {\n const width = getScreenWidth();\n\n return h(Box, {\n flexDirection: \"column\",\n marginTop: 1,\n borderStyle: \"single\",\n borderColor: \"cyan\",\n paddingX: 1,\n width: width // Use the calculated width directly\n }, children);\n}\n\n/**\n * Screen row - just a wrapper for spacing, borders handled by container\n */\nexport function ScreenRow({ children }: ScreenRowProps): JSX.Element {\n return h(Box, { flexDirection: \"column\" }, children);\n}\n\n/**\n * Screen Title - first line inside container (left-aligned, breadcrumb-style)\n */\nexport function ScreenTitle({ text }: ScreenTitleProps): JSX.Element {\n return h(ScreenRow, {},\n h(Text, { bold: true, color: \"cyan\" }, text)\n );\n}\n\n/**\n * Horizontal divider line\n */\nexport function ScreenDivider({ width }: ScreenDividerProps): JSX.Element {\n const dividerWidth = width || (getScreenWidth() - 4); // Account for border and padding\n return h(Text, { color: \"cyan\", dimColor: true }, \"─\".repeat(dividerWidth));\n}\n\n/**\n * Screen Body - main content area\n */\nexport function ScreenBody({ children, alignItems = \"flex-start\" }: ScreenBodyProps): JSX.Element {\n return h(Box, { flexDirection: \"column\", alignItems }, children);\n}\n\n/**\n * Screen Footer - bottom area with key bindings and status\n * \n * @example\n * <ScreenFooter lines={[\"esc to go back\", \"enter to select\"]} />\n * \n * @example\n * <ScreenFooter \n * lines={[\"esc to go back\", \"enter to select\"]} \n * textStyle={{ color: \"white\" }}\n * />\n * \n * @example\n * <ScreenFooter \n * lines={[\"esc to go back\", \"enter to select\"]} \n * textStyle={{ dimColor: false, color: \"green\" }}\n * />\n */\nexport function ScreenFooter({ lines, textStyle }: ScreenFooterProps): JSX.Element {\n const defaultTextStyle = {\n dimColor: true,\n color: \"white\"\n };\n \n const finalTextStyle = { ...defaultTextStyle, ...textStyle };\n\n // Flatten nested arrays and ensure all items are properly wrapped\n const flattenAndWrap = (items: (string | JSX.Element | (string | JSX.Element)[])[], keyPrefix: string = \"\"): JSX.Element[] => {\n const result: JSX.Element[] = [];\n let keyIndex = 0;\n\n items.forEach((item, index) => {\n if (Array.isArray(item)) {\n // Handle nested arrays\n const nested = flattenAndWrap(item, `${keyPrefix}-${index}`);\n result.push(...nested);\n } else if (typeof item === \"string\") {\n // Wrap strings in Text components\n result.push(\n h(Text, { key: `${keyPrefix}-${keyIndex++}`, ...finalTextStyle }, item)\n );\n } else {\n // JSX elements - add key if missing\n const element = item as JSX.Element;\n if (element.key === null || element.key === undefined) {\n result.push(\n h(Text, { key: `${keyPrefix}-${keyIndex++}`, ...finalTextStyle }, element)\n );\n } else {\n result.push(element);\n }\n }\n });\n\n return result;\n };\n\n const wrappedItems = flattenAndWrap(lines);\n\n return h(Box, { flexDirection: \"column\" },\n h(Box, { flexDirection: \"row\" }, ...wrappedItems)\n );\n}","/**\n * Reusable screen components for V2 architecture\n */\n\nimport React, { useState, useEffect, useRef, createElement } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { ScreenRow, ScreenDivider } from \"./components.js\";\n\nconst h = createElement;\n\n// TODO: Define proper context type interface\ninterface ScreenContext {\n setAction: (name: string, handler: () => void) => void;\n setKeyBinding: (bindings: KeyBinding | KeyBinding[]) => void;\n addFooter: (message: string) => void;\n setFooter: (items: string | string[]) => void;\n goBack: () => void;\n update: () => void;\n}\n\ninterface KeyBinding {\n key: string;\n caption: string;\n action: string;\n order: number;\n}\n\ninterface ListItem {\n name: string;\n value: any;\n}\n\ninterface MultiColumnListComponentProps {\n items: string[];\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n}\n\ninterface MultiColumnListWithPreviewComponentProps {\n items: string[];\n getPreviewContent?: (item: string) => string | JSX.Element | Record<string, any>;\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n}\n\ninterface ListComponentProps {\n items: ListItem[];\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n renderItem?: (item: ListItem, isSelected: boolean, displayIndex: number) => JSX.Element;\n getTitle?: (item: ListItem) => string;\n sortable?: boolean;\n maxHeight?: number;\n sortHighlightStyle?: {\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n };\n selectionMarker?: string; // Customizable selection marker, default: \" \"\n}\n\n/**\n * Multi-column list component\n * Handles its own navigation, actions, and key bindings\n */\nexport function MultiColumnListComponent({ items, ctx, selectedIndexRef }: MultiColumnListComponentProps): JSX.Element {\n const [, forceUpdate] = useState({});\n\n // Calculate layout\n const termWidth = (process.stdout.columns || 80) - 8;\n const maxItemLength = Math.max(...items.map(w => w.length));\n const columnWidth = maxItemLength + 3;\n const columns = Math.max(1, Math.floor(termWidth / columnWidth));\n const itemsPerColumn = Math.ceil(items.length / columns);\n\n // Set up actions in useEffect (runs once)\n useEffect(() => {\n ctx.setAction(\"moveUp\", () => {\n selectedIndexRef.current = Math.max(0, selectedIndexRef.current - 1);\n forceUpdate({});\n });\n\n ctx.setAction(\"moveDown\", () => {\n selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + 1);\n forceUpdate({});\n });\n\n ctx.setAction(\"moveLeft\", () => {\n if (selectedIndexRef.current === 0) {\n ctx.goBack();\n } else {\n selectedIndexRef.current = Math.max(0, selectedIndexRef.current - itemsPerColumn);\n forceUpdate({});\n }\n });\n\n ctx.setAction(\"moveRight\", () => {\n selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + itemsPerColumn);\n forceUpdate({});\n });\n\n // Set up key bindings\n ctx.setKeyBinding([\n { key: \"leftArrow\", caption: \"navigate\", action: \"moveLeft\", order: 0 },\n { key: \"rightArrow\", caption: \"navigate\", action: \"moveRight\", order: 0 },\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n ]);\n\n // Add footer\n ctx.addFooter(`Total: ${items.length} items`);\n }, []);\n\n const selectedIndex = selectedIndexRef.current;\n\n // Build grid\n const rows: JSX.Element[] = [];\n for (let row = 0; row < itemsPerColumn; row++) {\n const cols: JSX.Element[] = [];\n for (let col = 0; col < columns; col++) {\n const index = col * itemsPerColumn + row;\n if (index < items.length) {\n const isSelected = index === selectedIndex;\n cols.push(\n h(Box, { key: index, width: columnWidth },\n h(Text, {\n color: isSelected ? \"black\" : \"white\",\n backgroundColor: isSelected ? \"cyan\" : undefined,\n bold: isSelected\n }, items[index].padEnd(maxItemLength))\n )\n );\n }\n }\n rows.push(\n h(ScreenRow, { key: row, children: h(Box, { flexDirection: \"row\" }, ...cols) })\n );\n }\n\n return h(Box, { flexDirection: \"column\" }, ...rows);\n}\n\n/**\n * Multi-column list with preview panel component\n * Shows selected item details below the list\n */\nexport function MultiColumnListWithPreviewComponent({\n items,\n getPreviewContent,\n ctx,\n selectedIndexRef\n}: MultiColumnListWithPreviewComponentProps): JSX.Element {\n const [, forceUpdate] = useState({});\n\n // Calculate layout\n const termWidth = (process.stdout.columns || 80) - 8;\n const maxItemLength = Math.max(...items.map(w => w.length));\n const columnWidth = maxItemLength + 3;\n const columns = Math.max(1, Math.floor(termWidth / columnWidth));\n const itemsPerColumn = Math.ceil(items.length / columns);\n\n // Set up actions in useEffect (runs once)\n useEffect(() => {\n ctx.setAction(\"moveUp\", () => {\n selectedIndexRef.current = Math.max(0, selectedIndexRef.current - 1);\n forceUpdate({});\n });\n\n ctx.setAction(\"moveDown\", () => {\n selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + 1);\n forceUpdate({});\n });\n\n ctx.setAction(\"moveLeft\", () => {\n if (selectedIndexRef.current === 0) {\n ctx.goBack();\n } else {\n selectedIndexRef.current = Math.max(0, selectedIndexRef.current - itemsPerColumn);\n forceUpdate({});\n }\n });\n\n ctx.setAction(\"moveRight\", () => {\n selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + itemsPerColumn);\n forceUpdate({});\n });\n\n // Set up key bindings\n ctx.setKeyBinding([\n { key: \"leftArrow\", caption: \"navigate\", action: \"moveLeft\", order: 0 },\n { key: \"rightArrow\", caption: \"navigate\", action: \"moveRight\", order: 0 },\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n ]);\n\n // Add footer\n ctx.addFooter(`Total: ${items.length} items`);\n }, []);\n\n const selectedIndex = selectedIndexRef.current;\n const selectedItem = items[selectedIndex];\n\n // Build grid\n const rows: JSX.Element[] = [];\n for (let row = 0; row < itemsPerColumn; row++) {\n const cols: JSX.Element[] = [];\n for (let col = 0; col < columns; col++) {\n const index = col * itemsPerColumn + row;\n if (index < items.length) {\n const isSelected = index === selectedIndex;\n cols.push(\n h(Box, { key: index, width: columnWidth },\n h(Text, {\n color: isSelected ? \"black\" : \"white\",\n backgroundColor: isSelected ? \"cyan\" : undefined,\n bold: isSelected\n }, items[index].padEnd(maxItemLength))\n )\n );\n }\n }\n rows.push(\n h(ScreenRow, { key: row, children: h(Box, { flexDirection: \"row\" }, ...cols) })\n );\n }\n\n // Get preview content for selected item\n const previewContent = getPreviewContent ? getPreviewContent(selectedItem) : selectedItem;\n\n const previewRows: JSX.Element[] = [];\n if (typeof previewContent === \"string\") {\n previewRows.push(h(ScreenRow, { key: \"preview-string\", children: h(Text, { bold: true }, previewContent) }));\n } else if (typeof previewContent === \"object\" && !React.isValidElement(previewContent) && previewContent !== null) {\n Object.entries(previewContent).forEach(([key, value], idx) => {\n previewRows.push(h(ScreenRow, { key: `preview-${key}-${idx}`, children: h(Text, {}, `${key}: ${value}`) }));\n });\n } else if (React.isValidElement(previewContent)) {\n previewRows.push(h(ScreenRow, { key: \"preview-element\", children: previewContent }));\n }\n\n return h(Box, { flexDirection: \"column\" },\n ...rows,\n h(ScreenRow, { key: \"spacer-1\", children: h(Text, {}, \" \") }),\n h(ScreenDivider, { key: \"divider\" }),\n h(ScreenRow, { key: \"spacer-2\", children: h(Text, {}, \" \") }),\n ...previewRows\n );\n}\n\n/**\n * Single-column list component\n * Simple vertical menu with optional sorting\n */\nexport function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sortable = false, maxHeight, sortHighlightStyle, selectionMarker = \" \" }: ListComponentProps): JSX.Element {\n const [, forceUpdate] = useState({});\n const [sortOrder, setSortOrder] = useState<\"none\" | \"asc\" | \"desc\">(\"none\");\n const [scrollOffset, setScrollOffset] = useState(0);\n \n // Use refs to store current scroll values to avoid stale closures\n const scrollStateRef = useRef({ scrollOffset: 0, maxHeight: 0, totalItems: 0 });\n\n // Default getTitle - returns item if string, otherwise item.title\n const defaultGetTitle = (item: ListItem): string => {\n return getTitle ? getTitle(item) : (typeof item.value === \"string\" ? item.value : (item.value?.title || item.name));\n };\n\n // Get title for sorting\n const titleGetter = getTitle || defaultGetTitle;\n\n // Apply sorting if enabled\n const displayItems = sortable && sortOrder !== \"none\" ? [...items].sort((a, b) => {\n const titleA = titleGetter(a).toLowerCase();\n const titleB = titleGetter(b).toLowerCase();\n if (sortOrder === \"asc\") {\n return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;\n } else {\n return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;\n }\n }) : items;\n\n // Calculate scrolling\n const effectiveMaxHeight = maxHeight || displayItems.length;\n const canScroll = displayItems.length > effectiveMaxHeight;\n const maxScrollOffset = Math.max(0, displayItems.length - effectiveMaxHeight);\n \n // Ensure scroll offset is within bounds\n const clampedScrollOffset = Math.min(Math.max(0, scrollOffset), maxScrollOffset);\n \n // Get visible items\n const visibleItems = displayItems.slice(clampedScrollOffset, clampedScrollOffset + effectiveMaxHeight);\n \n // Check if we can scroll up/down\n const canScrollUp = clampedScrollOffset > 0;\n const canScrollDown = clampedScrollOffset < maxScrollOffset;\n \n // Update scroll state ref with current values\n scrollStateRef.current = { scrollOffset, maxHeight: effectiveMaxHeight, totalItems: displayItems.length };\n \n\n // Set up actions in useEffect (runs once)\n useEffect(() => {\n ctx.setAction(\"moveUp\", () => {\n const newIndex = Math.max(0, selectedIndexRef.current - 1);\n selectedIndexRef.current = newIndex;\n \n // Auto-scroll to keep selected item visible\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);\n \n if (newIndex < currentClampedScrollOffset) {\n setScrollOffset(newIndex);\n }\n \n // Force update to trigger re-render with new selected index\n forceUpdate({});\n });\n\n ctx.setAction(\"moveDown\", () => {\n const currentItems = sortable && sortOrder !== \"none\" ? [...items].sort((a, b) => {\n const titleA = titleGetter(a).toLowerCase();\n const titleB = titleGetter(b).toLowerCase();\n if (sortOrder === \"asc\") {\n return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;\n } else {\n return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;\n }\n }) : items;\n \n const maxIndex = currentItems.length - 1;\n const newIndex = Math.min(maxIndex, selectedIndexRef.current + 1);\n selectedIndexRef.current = newIndex;\n \n // Auto-scroll to keep selected item visible\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);\n \n if (newIndex >= currentClampedScrollOffset + currentMaxHeight) {\n setScrollOffset(newIndex - currentMaxHeight + 1);\n }\n \n // Force update to trigger re-render with new selected index\n forceUpdate({});\n });\n\n // Add scroll actions for arrow clicks\n ctx.setAction(\"scrollUp\", () => {\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const newScrollOffset = Math.max(0, currentScrollOffset - 1);\n setScrollOffset(newScrollOffset);\n forceUpdate({});\n });\n\n ctx.setAction(\"scrollDown\", () => {\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const newScrollOffset = Math.min(currentMaxScrollOffset, currentScrollOffset + 1);\n setScrollOffset(newScrollOffset);\n forceUpdate({});\n });\n\n // Set up sort action if sortable\n if (sortable) {\n ctx.setAction(\"toggleSort\", () => {\n const nextSort: \"none\" | \"asc\" | \"desc\" = \n sortOrder === \"none\" ? \"asc\" : \n sortOrder === \"asc\" ? \"desc\" : \"none\";\n \n // Store the currently selected item from the current display items\n const currentSelectedItem = displayItems[selectedIndexRef.current];\n \n setSortOrder(nextSort);\n \n // Calculate the new sorted items\n const newSortedItems = nextSort !== \"none\" ? [...items].sort((a, b) => {\n const titleA = titleGetter(a).toLowerCase();\n const titleB = titleGetter(b).toLowerCase();\n if (nextSort === \"asc\") {\n return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;\n } else {\n return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;\n }\n }) : items;\n \n // Find the new index of the selected item in the new sorted list\n const newIndex = newSortedItems.findIndex(item => item === currentSelectedItem);\n if (newIndex !== -1) {\n selectedIndexRef.current = newIndex;\n // Set scroll position to show the selected item at the top\n setScrollOffset(newIndex);\n } else {\n // Fallback: if item not found, select first item\n selectedIndexRef.current = 0;\n setScrollOffset(0);\n }\n \n forceUpdate({});\n });\n\n // Default highlight style (green background, black text, bold)\n const defaultHighlightStyle = {\n color: \"black\",\n backgroundColor: \"green\", \n bold: true\n };\n const highlightStyle = { ...defaultHighlightStyle, ...sortHighlightStyle };\n\n // Create caption that includes sort status\n const sortCaption = () => {\n if (sortOrder === \"none\") {\n return h(Text, {}, \"s to toggle sort\");\n } else {\n const sortLabel = sortOrder === \"asc\" ? \"ASC\" : \"DESC\";\n return h(Text, {}, \n \"s to toggle \",\n h(Text, { color: \"white\", bold: true }, \"sort\"),\n \" \",\n h(Text, highlightStyle, ` ${sortLabel} `)\n );\n }\n };\n\n // Update key bindings with sort\n ctx.setKeyBinding([\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 },\n { \n key: \"s\", \n caption: sortCaption,\n action: \"toggleSort\", \n order: 5 \n }\n ]);\n\n // Force update to show the new caption in footer\n ctx.update();\n } else {\n // No sorting\n ctx.setKeyBinding([\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n ]);\n }\n }, [sortOrder, sortable]);\n\n const selectedIndex = selectedIndexRef.current;\n \n\n // Default renderer with static scroll indicators for debugging\n const defaultRenderItem = (item: ListItem, isSelected: boolean, displayIndex: number, actualIndex: number) => {\n const isFirstVisible = displayIndex === 0;\n const isLastVisible = displayIndex === visibleItems.length - 1;\n \n // Build prefix with arrows and selection marker\n let arrowPrefix = \"\";\n let selectionPrefix = \"\";\n \n // Only show arrows when scrolling is actually needed and available\n if (isFirstVisible && canScrollUp) {\n arrowPrefix = \"↑ \";\n } else if (isLastVisible && canScrollDown) {\n arrowPrefix = \"↓ \";\n } else {\n // No arrow, but reserve the same space\n arrowPrefix = \" \";\n }\n \n // Always reserve space for selection marker (pad with spaces if not selected)\n if (isSelected) {\n selectionPrefix = selectionMarker;\n } else {\n // Pad with spaces to match the length of the selection marker\n selectionPrefix = \" \".repeat(selectionMarker.length);\n }\n \n return h(Box, { flexDirection: \"row\" },\n // Arrow (clickable if functional, not highlighted)\n h(Text, { \n key: `arrow-${actualIndex}`,\n color: \"white\"\n }, arrowPrefix),\n // Selection marker space (always same width, not highlighted) \n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n // Item name (highlighted if selected)\n h(Text, {\n key: `name-${actualIndex}`,\n color: isSelected ? \"black\" : \"white\",\n backgroundColor: isSelected ? \"cyan\" : undefined,\n bold: isSelected\n }, item.name)\n );\n };\n\n // Use custom renderer if provided, otherwise use default\n const itemRenderer = renderItem || defaultRenderItem;\n\n // Render visible menu items with scroll indicators\n return h(Box, { flexDirection: \"column\" },\n ...visibleItems.map((item, displayIndex) => {\n const actualIndex = clampedScrollOffset + displayIndex;\n const isSelected = actualIndex === selectedIndex;\n \n // If using custom renderer, wrap it with scroll indicators\n if (renderItem) {\n const isFirstVisible = displayIndex === 0;\n const isLastVisible = displayIndex === visibleItems.length - 1;\n \n // Build prefix with arrows and selection marker\n let arrowPrefix = \"\";\n let selectionPrefix = \"\";\n \n // Only show arrows when scrolling is actually needed and available\n if (isFirstVisible && canScrollUp) {\n arrowPrefix = \"↑ \";\n } else if (isLastVisible && canScrollDown) {\n arrowPrefix = \"↓ \";\n } else {\n // No arrow, but reserve the same space\n arrowPrefix = \" \";\n }\n \n // Always reserve space for selection marker (pad with spaces if not selected)\n if (isSelected) {\n selectionPrefix = selectionMarker;\n } else {\n // Pad with spaces to match the length of the selection marker\n selectionPrefix = \" \".repeat(selectionMarker.length);\n }\n \n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: h(Box, { flexDirection: \"row\" },\n // Arrow (clickable if functional, not highlighted)\n h(Text, { \n key: `arrow-${actualIndex}`,\n color: \"white\"\n }, arrowPrefix),\n // Selection marker space (always same width, not highlighted) \n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n // Custom rendered content\n renderItem(item, isSelected, displayIndex)\n )\n });\n } else {\n // Use default renderer (which already includes scroll indicators)\n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: itemRenderer(item, isSelected, displayIndex, actualIndex)\n });\n }\n })\n );\n}\n","/**\n * Reusable UI elements for the screen system\n */\n\nimport React, { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\n\n// Types\nexport interface ListItemProps {\n children: React.ReactNode;\n isSelected?: boolean;\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n dimColor?: boolean;\n}\n\nexport interface TextBlockProps {\n text: string;\n color?: string;\n dimmed?: boolean;\n bold?: boolean;\n maxWidth?: number;\n}\n\nexport interface DividerProps {\n character?: string;\n width?: number;\n}\n\nexport interface GridCellProps {\n children: React.ReactNode;\n width?: number;\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n dimColor?: boolean;\n align?: \"left\" | \"center\" | \"right\";\n}\n\nexport interface InputFieldProps {\n prompt: string;\n value: string;\n onChange?: (value: string) => void;\n onSubmit?: (value: string) => void;\n}\n\n/**\n * List item component\n */\nexport function ListItem({ \n children, \n isSelected = false, \n color = \"white\", \n backgroundColor, \n bold = false, \n dimColor = false \n}: ListItemProps): JSX.Element {\n return h(Box, {},\n h(Text, {\n color: isSelected ? backgroundColor || \"green\" : color,\n backgroundColor: isSelected ? color : backgroundColor,\n bold: isSelected || bold,\n dimColor: !isSelected && dimColor\n }, children)\n );\n}\n\n/**\n * Text block component with customizable styling\n */\nexport function TextBlock({ \n text, \n color = \"white\", \n dimmed = false, \n bold = false, \n maxWidth \n}: TextBlockProps): JSX.Element {\n return h(Box, {},\n h(Text, { \n color, \n dimColor: dimmed, \n bold \n }, text)\n );\n}\n\n/**\n * Horizontal divider\n */\nexport function Divider({ character = \"─\", width = 80 }: DividerProps): JSX.Element {\n return h(Box, { marginY: 1 },\n h(Text, { dimColor: true }, character.repeat(width))\n );\n}\n\n/**\n * Grid cell component\n */\nexport function GridCell({ \n children, \n width, \n color = \"white\", \n backgroundColor, \n bold = false, \n dimColor = false, \n align = \"left\" \n}: GridCellProps): JSX.Element {\n return h(Box, { width },\n h(Text, {\n color,\n backgroundColor,\n bold,\n dimColor,\n textAlign: align\n }, children)\n );\n}\n\n/**\n * Input field component\n */\nexport function InputField({ prompt, value, onChange, onSubmit }: InputFieldProps): JSX.Element {\n return h(Box, { flexDirection: \"column\" },\n h(Text, {}, prompt),\n h(Box, { marginTop: 1 },\n h(Text, { color: \"cyan\" }, \" > \", value, \"_\")\n )\n );\n}","/**\n * Utility functions for Screen System\n */\n\n/**\n * Build breadcrumb-style title\n * @param parts - Parts of the breadcrumb path\n * @returns Formatted breadcrumb\n *\n * Examples:\n * buildBreadcrumb(['Menu']) → 'Menu'\n * buildBreadcrumb(['Menu', 'Info']) → '← Info'\n * buildBreadcrumb(['Menu', 'Words', 'nefarious']) → '← Words ← nefarious'\n */\nexport function buildBreadcrumb(parts: string[]): string {\n if (parts.length === 0) return \"\";\n if (parts.length === 1) return parts[0];\n\n // Skip first part (root), add arrows with spaces to rest\n return parts.slice(1).map(part => `← ${part}`).join(\" \");\n}\n\n/**\n * Create multi-line breadcrumb with details\n * @param path - Navigation path\n * @param suffix - Additional suffix (e.g., 'Details')\n * @returns Formatted breadcrumb with suffix\n *\n * Example:\n * buildDetailBreadcrumb(['Menu', 'Words', 'nefarious'], 'Details')\n * → '← Words ← nefarious Details'\n */\nexport function buildDetailBreadcrumb(path: string[], suffix: string = \"\"): string {\n if (path.length <= 1) {\n return suffix ? `← ${suffix}` : path[0] || \"\";\n }\n\n const breadcrumb = buildBreadcrumb(path);\n return suffix ? `${breadcrumb} ${suffix}` : breadcrumb;\n}\n","/**\n * Footer builder - composes footer messages from multiple sources\n */\n\ninterface FooterConfig {\n navigation?: string | string[];\n actions?: string | string[];\n info?: string | string[];\n escape?: string | string[];\n custom?: string | string[];\n}\n\n/**\n * Build footer lines from multiple message sources\n *\n * @param config - Footer configuration object\n * @returns Array of footer lines\n */\nexport function buildFooter(config: FooterConfig = {}): string[] {\n const {\n navigation = null,\n actions = null,\n info = null,\n escape = \"Esc to go back\",\n custom = null\n } = config;\n\n const lines: string[] = [];\n\n // Build main help line (navigation + actions + escape)\n const mainParts: (string | string[])[] = [];\n\n if (navigation) {\n mainParts.push(navigation);\n }\n\n if (actions) {\n mainParts.push(actions);\n }\n\n if (escape) {\n mainParts.push(escape);\n }\n\n if (mainParts.length > 0) {\n lines.push(mainParts.join(\", \"));\n }\n\n // Add info line if present\n if (info) {\n const infoLines = Array.isArray(info) ? info : [info];\n lines.push(...infoLines);\n }\n\n // Add custom lines if present\n if (custom) {\n const customLines = Array.isArray(custom) ? custom : [custom];\n lines.push(...customLines);\n }\n\n return lines;\n}\n\n/**\n * Predefined footer configurations for common screen types\n */\nexport const FooterPresets = {\n /**\n * Menu screen footer\n */\n menu: (customInfo: string | string[] | null = null): string[] => buildFooter({\n navigation: \"↑/↓ to navigate\",\n actions: \"Enter to select\",\n escape: \"Esc to go back\",\n info: customInfo\n }),\n\n /**\n * Word grid footer\n */\n wordGrid: (totalWords: number): string[] => buildFooter({\n navigation: \"↑↓←→ to navigate\",\n actions: \"Enter to select\",\n escape: \"Esc to go back\",\n info: `Total: ${totalWords} words`\n }),\n\n /**\n * Text input footer\n */\n textInput: (): string[] => buildFooter({\n actions: \"Type and press Enter to submit\",\n escape: \"Esc to cancel\"\n }),\n\n /**\n * Info/static screen footer\n */\n info: (): string[] => buildFooter({\n escape: \"Esc to continue\"\n }),\n\n /**\n * Main menu footer (escape exits)\n */\n mainMenu: (): string[] => buildFooter({\n navigation: \"↑/↓ to navigate\",\n actions: \"Enter to select\",\n escape: \"Esc to exit\"\n }),\n\n /**\n * Action menu footer (for word cards, etc.)\n */\n actionMenu: (hasAudio: boolean = false): string[] => {\n const parts = buildFooter({\n navigation: \"↑/↓ to navigate\",\n actions: \"Enter to select\",\n escape: \"Esc to go back\"\n });\n\n if (hasAudio) {\n parts.push(\"Audio available\");\n }\n\n return parts;\n }\n};\n\n/**\n * Combine multiple footer messages into organized lines\n * Smart grouping of related messages\n *\n * @param messages - Individual footer messages\n * @returns Organized footer lines\n */\nexport function organizeFooterMessages(messages: string[] | null | undefined): string[] {\n if (!messages || messages.length === 0) {\n return [\"Esc to go back\"];\n }\n\n // Group similar messages\n const navigation = messages.filter(m => m.includes(\"↑\") || m.includes(\"↓\") || m.includes(\"←\") || m.includes(\"→\"));\n const actions = messages.filter(m => m.includes(\"Enter\") || m.includes(\"select\") || m.includes(\"submit\"));\n const escape = messages.filter(m => m.includes(\"Esc\"));\n const others = messages.filter(m =>\n !navigation.includes(m) &&\n !actions.includes(m) &&\n !escape.includes(m)\n );\n\n const lines: string[] = [];\n\n // Combine navigation, actions, and escape on one line\n const mainLine = [...navigation, ...actions, ...escape].join(\", \");\n if (mainLine) lines.push(mainLine);\n\n // Add other messages as separate lines\n lines.push(...others);\n\n return lines;\n}\n"],"mappings":"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","names":["import_react","import_ink","h","import_react","import_ink","h","React","h","import_react","import_ink","h"]}
1
+ {"version":3,"sources":["../src/screen/index.ts","../src/screen/screens.ts","../src/screen/components.ts","../src/screen/list-components.ts","../src/screen/ui-elements.ts","../src/screen/utils.ts","../src/screen/footer-builder.ts"],"sourcesContent":["/**\n * Screen System - Action-based architecture\n * Converted from legacy/screenSystem/src\n */\n\n// Re-export React and React hooks (encapsulated)\nimport React, { useState, useEffect, useRef, useMemo, useCallback, createElement } from \"react\";\nexport { React, useState, useEffect, useRef, useMemo, useCallback };\nexport { createElement as h };\n\n// Re-export Ink components (encapsulated)\nexport { Box, Text, useInput } from \"ink\";\n\n// Screen functions\nexport {\n showScreen,\n showListScreen,\n showMultiColumnListScreen,\n showMultiColumnListWithPreviewScreen,\n // Backward compatibility aliases\n showMenuScreen,\n showWordGridScreen\n} from \"./screens.js\";\n\n// Reusable components\nexport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\nexport { ScreenContainer, ScreenRow, ScreenTitle, ScreenBody, ScreenFooter, ScreenDivider } from \"./components.js\";\nexport { ListItem, TextBlock, Divider, GridCell, InputField } from \"./ui-elements.js\";\n\n// Utilities\nexport { buildBreadcrumb, buildDetailBreadcrumb } from \"./utils.js\";\nexport { buildFooter, FooterPresets, organizeFooterMessages } from \"./footer-builder.js\";\n","/**\n * Screen System - Action-based architecture\n */\n\nimport React, { useState, useRef, useEffect, createElement as h } from \"react\";\nimport { render, useInput, Box, Text } from \"ink\";\nimport { ScreenContainer, ScreenRow, ScreenTitle, ScreenDivider, ScreenFooter } from \"./components.js\";\nimport { MultiColumnListComponent, MultiColumnListWithPreviewComponent, ListComponent } from \"./list-components.js\";\n\n// Types\ninterface KeyBinding {\n key: string;\n caption: string | (() => string | JSX.Element);\n action: string;\n order?: number;\n protected?: boolean;\n enabled?: boolean;\n condition?: (ctx: ScreenContext) => boolean;\n}\n\ninterface BindingGroup {\n keys: string[];\n caption: string;\n order: number;\n}\n\ninterface ActionPayload {\n input: string;\n key: any;\n binding: KeyBinding;\n}\n\ninterface ScreenContext {\n setAction: (actionName: string, handlerFn: (payload?: ActionPayload) => void | any) => void;\n setKeyBinding: (bindingOrBindings: KeyBinding | KeyBinding[]) => void;\n updateKeyBinding: (keyName: string, updates: Partial<KeyBinding>) => void;\n removeKeyBinding: (keyName: string) => void;\n addFooter: (item: string | JSX.Element) => void;\n clearFooter: () => void;\n setFooter: (items: string | string[] | JSX.Element | JSX.Element[]) => void;\n update: () => void;\n goBack: () => void;\n close: (result: any) => void;\n parentData: any;\n}\n\ninterface ShowScreenConfig {\n title: string;\n onRender: (ctx: ScreenContext) => JSX.Element;\n parentData?: any;\n}\n\ninterface ShowListScreenConfig {\n title: string;\n items: Array<{ name: string; value: any }>;\n onSelect?: (value: any, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n renderItem?: (item: { name: string; value: any }, isSelected: boolean, displayIndex: number) => JSX.Element;\n getTitle?: (item: { name: string; value: any }) => string;\n sortable?: boolean;\n maxHeight?: number;\n sortHighlightStyle?: {\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n };\n selectionMarker?: string; // Customizable selection marker, default: \" \"\n}\n\ninterface ShowMultiColumnListScreenConfig {\n title: string;\n items: string[];\n onSelect?: (item: string, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n}\n\ninterface ShowMultiColumnListWithPreviewScreenConfig {\n title: string;\n items: string[];\n getPreviewContent?: (item: string) => string | JSX.Element | Record<string, any>;\n onSelect?: (item: string, index: number) => any;\n onEscape?: (index: number) => any;\n parentData?: any;\n initialSelectedIndex?: number;\n}\n\n/**\n * Group key bindings by caption for footer display\n */\nexport function groupKeyBindings(bindings: KeyBinding[]): BindingGroup[] {\n const groups: Record<string, BindingGroup> = {};\n\n // Filter out disabled bindings\n const enabledBindings = bindings.filter(b => b.enabled !== false);\n\n enabledBindings.forEach(binding => {\n const caption = typeof binding.caption === \"string\" ? binding.caption : \"\";\n if (!groups[caption]) {\n groups[caption] = {\n keys: [],\n caption: caption,\n order: binding.order || 999\n };\n }\n groups[caption].keys.push(binding.key);\n });\n\n return Object.values(groups);\n}\n\n/**\n * Format key bindings for footer (returns array of strings/components)\n */\nexport function formatKeyBindings(bindings: KeyBinding[], mode: string = \"long\"): (string | JSX.Element)[] {\n // Resolve function captions\n const resolvedBindings = bindings.map(binding => {\n let resolvedCaption = binding.caption;\n\n // If caption is a function, call it\n if (typeof binding.caption === \"function\") {\n resolvedCaption = binding.caption();\n }\n\n return {\n ...binding,\n resolvedCaption\n };\n });\n\n const groups = groupKeyBindings(resolvedBindings.map(b => ({\n ...b,\n caption: typeof b.resolvedCaption === \"string\" ? b.resolvedCaption : \"\"\n })));\n\n // Sort by order\n groups.sort((a, b) => a.order - b.order);\n\n const items: (string | JSX.Element)[] = [];\n\n groups.forEach(group => {\n // Check if any binding in this group has a component/custom caption\n const bindingWithCustom = resolvedBindings.find(b =>\n group.keys.includes(b.key) && typeof b.resolvedCaption !== \"string\"\n );\n\n if (bindingWithCustom && bindingWithCustom.resolvedCaption) {\n // Use the full custom display (component or complex structure)\n items.push(bindingWithCustom.resolvedCaption as JSX.Element);\n } else {\n // Standard format with string caption\n const keyStr = formatKeys(group.keys);\n\n if (mode === \"long\") {\n items.push(`${keyStr} to ${group.caption}`);\n } else {\n items.push(keyStr);\n }\n }\n });\n\n return items;\n}\n\n/**\n * Format keys for display\n */\nexport function formatKeys(keys: string[]): string {\n const keyMap: Record<string, string> = {\n \"escape\": \"esc\",\n \"leftArrow\": \"←\",\n \"rightArrow\": \"→\",\n \"upArrow\": \"↑\",\n \"downArrow\": \"↓\",\n \"return\": \"enter\"\n };\n\n return keys.map(k => keyMap[k] || k).join(\"/\");\n}\n\n/**\n * Show screen with action-based architecture\n */\nexport async function showScreen(config: ShowScreenConfig): Promise<any> {\n const {\n title,\n onRender,\n parentData = {}\n } = config;\n\n\n return new Promise((resolve) => {\n let instance: any;\n\n // Persistent collections (closure variables survive re-renders)\n const keyBindings: KeyBinding[] = [];\n const actions: Record<string, (payload?: ActionPayload) => void | any> = {};\n const customFooterItems: (string | JSX.Element)[] = [];\n let renderResult: JSX.Element | null = null;\n let initialized = false;\n\n const Screen = (): JSX.Element => {\n const [updateCounter, setUpdateCounter] = useState(0);\n\n // Initialize defaults only once\n if (!initialized) {\n const defaultBindings: KeyBinding[] = [\n { key: \"escape\", caption: \"go back\", action: \"back\", protected: true, order: 1 },\n { key: \"leftArrow\", caption: \"go back\", action: \"back\", protected: false, order: 1 }\n // Note: 'select' is not a default - components add it if needed\n ];\n\n // Add defaults\n defaultBindings.forEach(binding => {\n keyBindings.push(binding);\n });\n\n // Default actions\n actions.back = () => {\n cleanup(null);\n };\n\n initialized = true;\n }\n\n // Context for onRender\n const context: ScreenContext = {\n setAction: (actionName: string, handlerFn: (payload?: ActionPayload) => void | any) => {\n actions[actionName] = handlerFn;\n },\n\n setKeyBinding: (bindingOrBindings: KeyBinding | KeyBinding[]) => {\n // Support both single object and array\n const bindingsToSet = Array.isArray(bindingOrBindings) ? bindingOrBindings : [bindingOrBindings];\n\n bindingsToSet.forEach(binding => {\n // Check if key already exists\n const existingIndex = keyBindings.findIndex(b => b.key === binding.key);\n\n if (existingIndex >= 0) {\n const existing = keyBindings[existingIndex];\n\n // Can't override protected keys\n if (existing.protected) {\n console.warn(`Cannot override protected key: ${binding.key}`);\n return;\n }\n\n // Replace binding (keep original order if not specified)\n keyBindings[existingIndex] = {\n ...existing,\n ...binding,\n order: binding.order !== undefined ? binding.order : existing.order,\n enabled: binding.enabled !== undefined ? binding.enabled : (existing.enabled !== undefined ? existing.enabled : true)\n };\n } else {\n // Add new binding\n keyBindings.push({\n protected: false,\n order: 999,\n enabled: true,\n ...binding\n });\n }\n });\n },\n\n updateKeyBinding: (keyName: string, updates: Partial<KeyBinding>) => {\n const index = keyBindings.findIndex(b => b.key === keyName);\n if (index >= 0) {\n // Update only specified properties\n keyBindings[index] = {\n ...keyBindings[index],\n ...updates\n };\n }\n },\n\n removeKeyBinding: (keyName: string) => {\n const index = keyBindings.findIndex(b => b.key === keyName);\n if (index >= 0) {\n if (keyBindings[index].protected) {\n console.warn(`Cannot remove protected key: ${keyName}`);\n return;\n }\n keyBindings.splice(index, 1);\n }\n },\n\n addFooter: (item: string | JSX.Element) => {\n customFooterItems.push(item);\n },\n\n clearFooter: () => {\n customFooterItems.length = 0;\n },\n\n setFooter: (items: string | string[] | JSX.Element | JSX.Element[]) => {\n customFooterItems.length = 0;\n const itemsArray = Array.isArray(items) ? items : [items];\n customFooterItems.push(...itemsArray);\n },\n\n update: () => {\n setUpdateCounter(c => c + 1);\n },\n\n goBack: () => {\n if (actions.back) {\n actions.back();\n }\n },\n\n close: (result: any) => {\n cleanup(result);\n },\n\n parentData\n };\n\n // Call onRender once to let component set up\n if (!renderResult) {\n renderResult = onRender(context);\n }\n\n // Handle input - dispatch to actions\n useInput((input: string, key: any) => {\n // Check Ctrl+C for exit\n if (key.ctrl && input === \"c\") {\n cleanup(null);\n process.exit(0);\n return;\n }\n\n // Find matching key binding\n let matchedBinding: KeyBinding | null = null;\n\n for (const binding of keyBindings) {\n let keyMatches = false;\n\n // Check key match\n if (key[binding.key]) {\n keyMatches = true;\n } else if (input === binding.key) {\n keyMatches = true;\n }\n\n if (keyMatches) {\n // Check if binding is enabled\n if (binding.enabled === false) {\n continue;\n }\n\n // Check condition if present\n if (binding.condition && !binding.condition(context)) {\n continue;\n }\n\n matchedBinding = binding;\n break;\n }\n }\n\n if (matchedBinding && actions[matchedBinding.action]) {\n // Execute action\n const actionResult = actions[matchedBinding.action]({\n input,\n key,\n binding: matchedBinding\n });\n\n // If action returns a value, might be used for something\n // For now, actions manage their own state via closures\n }\n });\n\n // Build footer\n const footerLines: (string | JSX.Element | (string | JSX.Element)[])[] = [];\n\n // Add key bindings (returns array of strings/components)\n const bindingItems = formatKeyBindings(keyBindings, \"long\");\n\n if (bindingItems.length > 0) {\n // Build a single line with all binding items separated by \", \"\n const bindingsLine: (string | JSX.Element)[] = [];\n bindingItems.forEach((item, idx) => {\n if (idx > 0) {\n bindingsLine.push(\", \");\n }\n bindingsLine.push(item);\n });\n\n // If all items are strings, join them; otherwise create a Box\n const allStrings = bindingItems.every(item => typeof item === \"string\");\n if (allStrings) {\n footerLines.push(bindingsLine.join(\"\"));\n } else {\n // Mixed strings and components - wrap all strings in Text components\n const wrappedBindingsLine = bindingsLine.map(item => \n typeof item === \"string\" ? h(Text, {}, item) : item\n );\n footerLines.push(wrappedBindingsLine);\n }\n }\n\n // Add custom footer items\n customFooterItems.forEach(item => {\n if (typeof item === \"string\") {\n footerLines.push(item);\n } else {\n footerLines.push(item);\n }\n });\n\n return h(ScreenContainer, {},\n h(ScreenTitle, { text: title }),\n h(ScreenDivider),\n h(ScreenRow, {}, h(Text, {}, \" \")),\n renderResult,\n h(ScreenRow, {}, h(Text, {}, \" \")),\n h(ScreenDivider),\n h(ScreenFooter, { lines: footerLines })\n );\n };\n\n const cleanup = (result: any) => {\n if (instance) instance.unmount();\n setTimeout(() => resolve(result), 50);\n };\n\n instance = render(h(Screen));\n });\n}\n\n/**\n * Helper: Show list screen (single column menu)\n */\nexport async function showListScreen(config: ShowListScreenConfig): Promise<any> {\n const { title, items, onSelect, onEscape, parentData, initialSelectedIndex = 0, renderItem, getTitle, sortable, maxHeight, sortHighlightStyle, selectionMarker } = config;\n\n return showScreen({\n title,\n parentData,\n onRender: (ctx) => {\n // Shared state ref\n const selectedIndexRef = { current: initialSelectedIndex };\n\n // Set up select action at screen level\n ctx.setAction(\"select\", () => {\n const selected = items[selectedIndexRef.current];\n if (onSelect) {\n const result = onSelect(selected.value, selectedIndexRef.current);\n ctx.close(result);\n }\n });\n\n // Set up back action if provided\n if (onEscape) {\n ctx.setAction(\"back\", () => {\n const result = onEscape(selectedIndexRef.current);\n ctx.close(result);\n });\n }\n\n // Add select key binding\n ctx.setKeyBinding({ key: \"return\", caption: \"select\", action: \"select\", order: 2 });\n\n // Return the component (it will set up its own navigation actions and bindings)\n return h(ListComponent, { items, ctx, selectedIndexRef, renderItem, getTitle, sortable, maxHeight, sortHighlightStyle, selectionMarker });\n }\n });\n}\n\n/**\n * Helper: Show multi-column list screen (grid layout)\n */\nexport async function showMultiColumnListScreen(config: ShowMultiColumnListScreenConfig): Promise<any> {\n const { title, items, onSelect, onEscape, parentData, initialSelectedIndex = 0 } = config;\n\n return showScreen({\n title,\n parentData,\n onRender: (ctx) => {\n // Shared state ref\n const selectedIndexRef = { current: initialSelectedIndex };\n\n // Set up select action at screen level\n ctx.setAction(\"select\", () => {\n const selected = items[selectedIndexRef.current];\n if (onSelect) {\n const result = onSelect(selected, selectedIndexRef.current);\n ctx.close(result);\n }\n });\n\n // Set up back action if provided\n if (onEscape) {\n ctx.setAction(\"back\", () => {\n const result = onEscape(selectedIndexRef.current);\n ctx.close(result);\n });\n }\n\n // Add select key binding\n ctx.setKeyBinding({ key: \"return\", caption: \"select\", action: \"select\", order: 2 });\n\n // Return the component (it will set up its own navigation actions and bindings)\n return h(MultiColumnListComponent, { items, ctx, selectedIndexRef });\n }\n });\n}\n\n/**\n * Helper: Show multi-column list with preview panel below\n */\nexport async function showMultiColumnListWithPreviewScreen(config: ShowMultiColumnListWithPreviewScreenConfig): Promise<any> {\n const { title, items, getPreviewContent, onSelect, onEscape, parentData, initialSelectedIndex = 0 } = config;\n\n return showScreen({\n title,\n parentData,\n onRender: (ctx) => {\n // Shared state ref\n const selectedIndexRef = { current: initialSelectedIndex };\n\n // Set up select action at screen level\n ctx.setAction(\"select\", () => {\n const selected = items[selectedIndexRef.current];\n if (onSelect) {\n const result = onSelect(selected, selectedIndexRef.current);\n ctx.close(result);\n }\n });\n\n // Set up back action if provided\n if (onEscape) {\n ctx.setAction(\"back\", () => {\n const result = onEscape(selectedIndexRef.current);\n ctx.close(result);\n });\n }\n\n // Add select key binding\n ctx.setKeyBinding({ key: \"return\", caption: \"select\", action: \"select\", order: 2 });\n\n // Return the component (it will set up its own navigation actions and bindings)\n return h(MultiColumnListWithPreviewComponent, { items, getPreviewContent, ctx, selectedIndexRef });\n }\n });\n}\n\n// Backward compatibility aliases\nexport const showMenuScreen = showListScreen;\nexport const showWordGridScreen = showMultiColumnListScreen;\n","/**\n * Core screen layout components\n */\n\nimport React, { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\n\n/**\n * Get screen width for borders\n * @param maxWidth - Optional max width (null = no limit)\n */\nexport function getScreenWidth(maxWidth: number | null = null): number {\n const terminalWidth = process.stdout.columns || 80;\n // Leave some margin for borders and padding\n const availableWidth = Math.max(20, terminalWidth - 4);\n return maxWidth ? Math.min(availableWidth, maxWidth) : availableWidth;\n}\n\n// Types\nexport interface ScreenContainerProps {\n children: React.ReactNode;\n}\n\nexport interface ScreenRowProps {\n children: React.ReactNode;\n}\n\nexport interface ScreenTitleProps {\n text: string;\n}\n\nexport interface ScreenDividerProps {\n width?: number;\n}\n\nexport interface ScreenBodyProps {\n children: React.ReactNode;\n alignItems?: \"flex-start\" | \"center\" | \"flex-end\";\n}\n\nexport interface ScreenFooterProps {\n lines: (string | JSX.Element)[];\n textStyle?: {\n color?: string;\n dimColor?: boolean;\n bold?: boolean;\n };\n}\n\n/**\n * Screen Container - uses Ink's built-in borderStyle for proper text wrapping\n */\nexport function ScreenContainer({ children }: ScreenContainerProps): JSX.Element {\n const width = getScreenWidth();\n\n return h(Box, {\n flexDirection: \"column\",\n marginTop: 1,\n borderStyle: \"single\",\n borderColor: \"cyan\",\n paddingX: 1,\n width: width // Use the calculated width directly\n }, children);\n}\n\n/**\n * Screen row - just a wrapper for spacing, borders handled by container\n */\nexport function ScreenRow({ children }: ScreenRowProps): JSX.Element {\n return h(Box, { flexDirection: \"column\" }, children);\n}\n\n/**\n * Screen Title - first line inside container (left-aligned, breadcrumb-style)\n */\nexport function ScreenTitle({ text }: ScreenTitleProps): JSX.Element {\n return h(ScreenRow, {},\n h(Text, { bold: true, color: \"cyan\" }, text)\n );\n}\n\n/**\n * Horizontal divider line\n */\nexport function ScreenDivider({ width }: ScreenDividerProps): JSX.Element {\n const dividerWidth = width || (getScreenWidth() - 4); // Account for border and padding\n return h(Text, { color: \"cyan\", dimColor: true }, \"─\".repeat(dividerWidth));\n}\n\n/**\n * Screen Body - main content area\n */\nexport function ScreenBody({ children, alignItems = \"flex-start\" }: ScreenBodyProps): JSX.Element {\n return h(Box, { flexDirection: \"column\", alignItems }, children);\n}\n\n/**\n * Screen Footer - bottom area with key bindings and status\n * \n * @example\n * <ScreenFooter lines={[\"esc to go back\", \"enter to select\"]} />\n * \n * @example\n * <ScreenFooter \n * lines={[\"esc to go back\", \"enter to select\"]} \n * textStyle={{ color: \"white\" }}\n * />\n * \n * @example\n * <ScreenFooter \n * lines={[\"esc to go back\", \"enter to select\"]} \n * textStyle={{ dimColor: false, color: \"green\" }}\n * />\n */\nexport function ScreenFooter({ lines, textStyle }: ScreenFooterProps): JSX.Element {\n const defaultTextStyle = {\n dimColor: true,\n color: \"white\"\n };\n \n const finalTextStyle = { ...defaultTextStyle, ...textStyle };\n\n // Flatten nested arrays and ensure all items are properly wrapped\n const flattenAndWrap = (items: (string | JSX.Element | (string | JSX.Element)[])[], keyPrefix: string = \"\"): JSX.Element[] => {\n const result: JSX.Element[] = [];\n let keyIndex = 0;\n\n items.forEach((item, index) => {\n if (Array.isArray(item)) {\n // Handle nested arrays\n const nested = flattenAndWrap(item, `${keyPrefix}-${index}`);\n result.push(...nested);\n } else if (typeof item === \"string\") {\n // Wrap strings in Text components\n result.push(\n h(Text, { key: `${keyPrefix}-${keyIndex++}`, ...finalTextStyle }, item)\n );\n } else {\n // JSX elements - add key if missing\n const element = item as JSX.Element;\n if (element.key === null || element.key === undefined) {\n result.push(\n h(Text, { key: `${keyPrefix}-${keyIndex++}`, ...finalTextStyle }, element)\n );\n } else {\n result.push(element);\n }\n }\n });\n\n return result;\n };\n\n const wrappedItems = flattenAndWrap(lines);\n\n return h(Box, { flexDirection: \"column\" },\n h(Box, { flexDirection: \"row\" }, ...wrappedItems)\n );\n}","/**\n * Reusable screen components for V2 architecture\n */\n\nimport React, { useState, useEffect, useRef, createElement } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { ScreenRow, ScreenDivider } from \"./components.js\";\n\nconst h = createElement;\n\n// TODO: Define proper context type interface\ninterface ScreenContext {\n setAction: (name: string, handler: () => void) => void;\n setKeyBinding: (bindings: KeyBinding | KeyBinding[]) => void;\n addFooter: (message: string) => void;\n setFooter: (items: string | string[]) => void;\n goBack: () => void;\n update: () => void;\n}\n\ninterface KeyBinding {\n key: string;\n caption: string;\n action: string;\n order: number;\n}\n\ninterface ListItem {\n name: string;\n value: any;\n}\n\ninterface MultiColumnListComponentProps {\n items: string[];\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n}\n\ninterface MultiColumnListWithPreviewComponentProps {\n items: string[];\n getPreviewContent?: (item: string) => string | JSX.Element | Record<string, any>;\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n}\n\ninterface ListComponentProps {\n items: ListItem[];\n ctx: ScreenContext;\n selectedIndexRef: { current: number };\n renderItem?: (item: ListItem, isSelected: boolean, displayIndex: number) => JSX.Element;\n getTitle?: (item: ListItem) => string;\n sortable?: boolean;\n maxHeight?: number;\n sortHighlightStyle?: {\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n };\n selectionMarker?: string; // Customizable selection marker, default: \" \"\n}\n\n/**\n * Multi-column list component\n * Handles its own navigation, actions, and key bindings\n */\nexport function MultiColumnListComponent({ items, ctx, selectedIndexRef }: MultiColumnListComponentProps): JSX.Element {\n const [, forceUpdate] = useState({});\n\n // Calculate layout\n const termWidth = (process.stdout.columns || 80) - 8;\n const maxItemLength = Math.max(...items.map(w => w.length));\n const columnWidth = maxItemLength + 3;\n const columns = Math.max(1, Math.floor(termWidth / columnWidth));\n const itemsPerColumn = Math.ceil(items.length / columns);\n\n // Set up actions in useEffect (runs once)\n useEffect(() => {\n ctx.setAction(\"moveUp\", () => {\n selectedIndexRef.current = Math.max(0, selectedIndexRef.current - 1);\n forceUpdate({});\n });\n\n ctx.setAction(\"moveDown\", () => {\n selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + 1);\n forceUpdate({});\n });\n\n ctx.setAction(\"moveLeft\", () => {\n if (selectedIndexRef.current === 0) {\n ctx.goBack();\n } else {\n selectedIndexRef.current = Math.max(0, selectedIndexRef.current - itemsPerColumn);\n forceUpdate({});\n }\n });\n\n ctx.setAction(\"moveRight\", () => {\n selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + itemsPerColumn);\n forceUpdate({});\n });\n\n // Set up key bindings\n ctx.setKeyBinding([\n { key: \"leftArrow\", caption: \"navigate\", action: \"moveLeft\", order: 0 },\n { key: \"rightArrow\", caption: \"navigate\", action: \"moveRight\", order: 0 },\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n ]);\n\n // Add footer\n ctx.addFooter(`Total: ${items.length} items`);\n }, []);\n\n const selectedIndex = selectedIndexRef.current;\n\n // Build grid\n const rows: JSX.Element[] = [];\n for (let row = 0; row < itemsPerColumn; row++) {\n const cols: JSX.Element[] = [];\n for (let col = 0; col < columns; col++) {\n const index = col * itemsPerColumn + row;\n if (index < items.length) {\n const isSelected = index === selectedIndex;\n cols.push(\n h(Box, { key: index, width: columnWidth },\n h(Text, {\n color: isSelected ? \"black\" : \"white\",\n backgroundColor: isSelected ? \"cyan\" : undefined,\n bold: isSelected\n }, items[index].padEnd(maxItemLength))\n )\n );\n }\n }\n rows.push(\n h(ScreenRow, { key: row, children: h(Box, { flexDirection: \"row\" }, ...cols) })\n );\n }\n\n return h(Box, { flexDirection: \"column\" }, ...rows);\n}\n\n/**\n * Multi-column list with preview panel component\n * Shows selected item details below the list\n */\nexport function MultiColumnListWithPreviewComponent({\n items,\n getPreviewContent,\n ctx,\n selectedIndexRef\n}: MultiColumnListWithPreviewComponentProps): JSX.Element {\n const [, forceUpdate] = useState({});\n\n // Calculate layout\n const termWidth = (process.stdout.columns || 80) - 8;\n const maxItemLength = Math.max(...items.map(w => w.length));\n const columnWidth = maxItemLength + 3;\n const columns = Math.max(1, Math.floor(termWidth / columnWidth));\n const itemsPerColumn = Math.ceil(items.length / columns);\n\n // Set up actions in useEffect (runs once)\n useEffect(() => {\n ctx.setAction(\"moveUp\", () => {\n selectedIndexRef.current = Math.max(0, selectedIndexRef.current - 1);\n forceUpdate({});\n });\n\n ctx.setAction(\"moveDown\", () => {\n selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + 1);\n forceUpdate({});\n });\n\n ctx.setAction(\"moveLeft\", () => {\n if (selectedIndexRef.current === 0) {\n ctx.goBack();\n } else {\n selectedIndexRef.current = Math.max(0, selectedIndexRef.current - itemsPerColumn);\n forceUpdate({});\n }\n });\n\n ctx.setAction(\"moveRight\", () => {\n selectedIndexRef.current = Math.min(items.length - 1, selectedIndexRef.current + itemsPerColumn);\n forceUpdate({});\n });\n\n // Set up key bindings\n ctx.setKeyBinding([\n { key: \"leftArrow\", caption: \"navigate\", action: \"moveLeft\", order: 0 },\n { key: \"rightArrow\", caption: \"navigate\", action: \"moveRight\", order: 0 },\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n ]);\n\n // Add footer\n ctx.addFooter(`Total: ${items.length} items`);\n }, []);\n\n const selectedIndex = selectedIndexRef.current;\n const selectedItem = items[selectedIndex];\n\n // Build grid\n const rows: JSX.Element[] = [];\n for (let row = 0; row < itemsPerColumn; row++) {\n const cols: JSX.Element[] = [];\n for (let col = 0; col < columns; col++) {\n const index = col * itemsPerColumn + row;\n if (index < items.length) {\n const isSelected = index === selectedIndex;\n cols.push(\n h(Box, { key: index, width: columnWidth },\n h(Text, {\n color: isSelected ? \"black\" : \"white\",\n backgroundColor: isSelected ? \"cyan\" : undefined,\n bold: isSelected\n }, items[index].padEnd(maxItemLength))\n )\n );\n }\n }\n rows.push(\n h(ScreenRow, { key: row, children: h(Box, { flexDirection: \"row\" }, ...cols) })\n );\n }\n\n // Get preview content for selected item\n const previewContent = getPreviewContent ? getPreviewContent(selectedItem) : selectedItem;\n\n const previewRows: JSX.Element[] = [];\n if (typeof previewContent === \"string\") {\n previewRows.push(h(ScreenRow, { key: \"preview-string\", children: h(Text, { bold: true }, previewContent) }));\n } else if (typeof previewContent === \"object\" && !React.isValidElement(previewContent) && previewContent !== null) {\n Object.entries(previewContent).forEach(([key, value], idx) => {\n previewRows.push(h(ScreenRow, { key: `preview-${key}-${idx}`, children: h(Text, {}, `${key}: ${value}`) }));\n });\n } else if (React.isValidElement(previewContent)) {\n previewRows.push(h(ScreenRow, { key: \"preview-element\", children: previewContent }));\n }\n\n return h(Box, { flexDirection: \"column\" },\n ...rows,\n h(ScreenRow, { key: \"spacer-1\", children: h(Text, {}, \" \") }),\n h(ScreenDivider, { key: \"divider\" }),\n h(ScreenRow, { key: \"spacer-2\", children: h(Text, {}, \" \") }),\n ...previewRows\n );\n}\n\n/**\n * Single-column list component\n * Simple vertical menu with optional sorting\n */\nexport function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sortable = false, maxHeight, sortHighlightStyle, selectionMarker = \" \" }: ListComponentProps): JSX.Element {\n const [, forceUpdate] = useState({});\n const [sortOrder, setSortOrder] = useState<\"none\" | \"asc\" | \"desc\">(\"none\");\n const [scrollOffset, setScrollOffset] = useState(0);\n \n // Use refs to store current scroll values to avoid stale closures\n const scrollStateRef = useRef({ scrollOffset: 0, maxHeight: 0, totalItems: 0 });\n\n // Default getTitle - returns item if string, otherwise item.title\n const defaultGetTitle = (item: ListItem): string => {\n return getTitle ? getTitle(item) : (typeof item.value === \"string\" ? item.value : (item.value?.title || item.name));\n };\n\n // Get title for sorting\n const titleGetter = getTitle || defaultGetTitle;\n\n // Apply sorting if enabled\n const displayItems = sortable && sortOrder !== \"none\" ? [...items].sort((a, b) => {\n const titleA = titleGetter(a).toLowerCase();\n const titleB = titleGetter(b).toLowerCase();\n if (sortOrder === \"asc\") {\n return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;\n } else {\n return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;\n }\n }) : items;\n\n // Calculate scrolling\n const effectiveMaxHeight = maxHeight || displayItems.length;\n const canScroll = displayItems.length > effectiveMaxHeight;\n const maxScrollOffset = Math.max(0, displayItems.length - effectiveMaxHeight);\n \n // Ensure scroll offset is within bounds\n const clampedScrollOffset = Math.min(Math.max(0, scrollOffset), maxScrollOffset);\n \n // Get visible items\n const visibleItems = displayItems.slice(clampedScrollOffset, clampedScrollOffset + effectiveMaxHeight);\n \n // Check if we can scroll up/down\n const canScrollUp = clampedScrollOffset > 0;\n const canScrollDown = clampedScrollOffset < maxScrollOffset;\n \n // Update scroll state ref with current values\n scrollStateRef.current = { scrollOffset, maxHeight: effectiveMaxHeight, totalItems: displayItems.length };\n \n\n // Set up actions in useEffect (runs once)\n useEffect(() => {\n ctx.setAction(\"moveUp\", () => {\n const newIndex = Math.max(0, selectedIndexRef.current - 1);\n selectedIndexRef.current = newIndex;\n \n // Auto-scroll to keep selected item visible\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);\n \n if (newIndex < currentClampedScrollOffset) {\n setScrollOffset(newIndex);\n }\n \n // Force update to trigger re-render with new selected index\n forceUpdate({});\n });\n\n ctx.setAction(\"moveDown\", () => {\n const currentItems = sortable && sortOrder !== \"none\" ? [...items].sort((a, b) => {\n const titleA = titleGetter(a).toLowerCase();\n const titleB = titleGetter(b).toLowerCase();\n if (sortOrder === \"asc\") {\n return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;\n } else {\n return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;\n }\n }) : items;\n \n const maxIndex = currentItems.length - 1;\n const newIndex = Math.min(maxIndex, selectedIndexRef.current + 1);\n selectedIndexRef.current = newIndex;\n \n // Auto-scroll to keep selected item visible\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const currentClampedScrollOffset = Math.min(Math.max(0, currentScrollOffset), currentMaxScrollOffset);\n \n if (newIndex >= currentClampedScrollOffset + currentMaxHeight) {\n setScrollOffset(newIndex - currentMaxHeight + 1);\n }\n \n // Force update to trigger re-render with new selected index\n forceUpdate({});\n });\n\n // Add scroll actions for arrow clicks\n ctx.setAction(\"scrollUp\", () => {\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const newScrollOffset = Math.max(0, currentScrollOffset - 1);\n setScrollOffset(newScrollOffset);\n forceUpdate({});\n });\n\n ctx.setAction(\"scrollDown\", () => {\n const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;\n const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);\n const newScrollOffset = Math.min(currentMaxScrollOffset, currentScrollOffset + 1);\n setScrollOffset(newScrollOffset);\n forceUpdate({});\n });\n\n // Set up sort action if sortable\n if (sortable) {\n ctx.setAction(\"toggleSort\", () => {\n const nextSort: \"none\" | \"asc\" | \"desc\" = \n sortOrder === \"none\" ? \"asc\" : \n sortOrder === \"asc\" ? \"desc\" : \"none\";\n \n // Store the currently selected item from the current display items\n const currentSelectedItem = displayItems[selectedIndexRef.current];\n \n setSortOrder(nextSort);\n \n // Calculate the new sorted items\n const newSortedItems = nextSort !== \"none\" ? [...items].sort((a, b) => {\n const titleA = titleGetter(a).toLowerCase();\n const titleB = titleGetter(b).toLowerCase();\n if (nextSort === \"asc\") {\n return titleA < titleB ? -1 : titleA > titleB ? 1 : 0;\n } else {\n return titleA > titleB ? -1 : titleA < titleB ? 1 : 0;\n }\n }) : items;\n \n // Find the new index of the selected item in the new sorted list\n const newIndex = newSortedItems.findIndex(item => item === currentSelectedItem);\n if (newIndex !== -1) {\n selectedIndexRef.current = newIndex;\n // Set scroll position to show the selected item at the top\n setScrollOffset(newIndex);\n } else {\n // Fallback: if item not found, select first item\n selectedIndexRef.current = 0;\n setScrollOffset(0);\n }\n \n forceUpdate({});\n });\n\n // Default highlight style (green background, black text, bold)\n const defaultHighlightStyle = {\n color: \"black\",\n backgroundColor: \"green\", \n bold: true\n };\n const highlightStyle = { ...defaultHighlightStyle, ...sortHighlightStyle };\n\n // Create caption that includes sort status\n const sortCaption = () => {\n if (sortOrder === \"none\") {\n return h(Text, {}, \"s to toggle sort\");\n } else {\n const sortLabel = sortOrder === \"asc\" ? \"ASC\" : \"DESC\";\n return h(Text, {}, \n \"s to toggle \",\n h(Text, { color: \"white\", bold: true }, \"sort\"),\n \" \",\n h(Text, highlightStyle, ` ${sortLabel} `)\n );\n }\n };\n\n // Update key bindings with sort\n ctx.setKeyBinding([\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 },\n { \n key: \"s\", \n caption: sortCaption,\n action: \"toggleSort\", \n order: 5 \n }\n ]);\n\n // Force update to show the new caption in footer\n ctx.update();\n } else {\n // No sorting\n ctx.setKeyBinding([\n { key: \"upArrow\", caption: \"navigate\", action: \"moveUp\", order: 0 },\n { key: \"downArrow\", caption: \"navigate\", action: \"moveDown\", order: 0 }\n ]);\n }\n }, [sortOrder, sortable]);\n\n const selectedIndex = selectedIndexRef.current;\n \n\n // Default renderer with static scroll indicators for debugging\n const defaultRenderItem = (item: ListItem, isSelected: boolean, displayIndex: number, actualIndex: number) => {\n const isFirstVisible = displayIndex === 0;\n const isLastVisible = displayIndex === visibleItems.length - 1;\n \n // Build prefix with arrows and selection marker\n let arrowPrefix = \"\";\n let selectionPrefix = \"\";\n \n // Only show arrows when scrolling is actually needed and available\n if (isFirstVisible && canScrollUp) {\n arrowPrefix = \"↑ \";\n } else if (isLastVisible && canScrollDown) {\n arrowPrefix = \"↓ \";\n } else {\n // No arrow, but reserve the same space\n arrowPrefix = \" \";\n }\n \n // Always reserve space for selection marker (pad with spaces if not selected)\n if (isSelected) {\n selectionPrefix = selectionMarker;\n } else {\n // Pad with spaces to match the length of the selection marker\n selectionPrefix = \" \".repeat(selectionMarker.length);\n }\n \n return h(Box, { flexDirection: \"row\" },\n // Arrow (clickable if functional, not highlighted)\n h(Text, { \n key: `arrow-${actualIndex}`,\n color: \"white\"\n }, arrowPrefix),\n // Selection marker space (always same width, not highlighted) \n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n // Item name (highlighted if selected)\n h(Text, {\n key: `name-${actualIndex}`,\n color: isSelected ? \"black\" : \"white\",\n backgroundColor: isSelected ? \"cyan\" : undefined,\n bold: isSelected\n }, item.name)\n );\n };\n\n // Use custom renderer if provided, otherwise use default\n const itemRenderer = renderItem || defaultRenderItem;\n\n // Render visible menu items with scroll indicators\n return h(Box, { flexDirection: \"column\" },\n ...visibleItems.map((item, displayIndex) => {\n const actualIndex = clampedScrollOffset + displayIndex;\n const isSelected = actualIndex === selectedIndex;\n \n // If using custom renderer, wrap it with scroll indicators\n if (renderItem) {\n const isFirstVisible = displayIndex === 0;\n const isLastVisible = displayIndex === visibleItems.length - 1;\n \n // Build prefix with arrows and selection marker\n let arrowPrefix = \"\";\n let selectionPrefix = \"\";\n \n // Only show arrows when scrolling is actually needed and available\n if (isFirstVisible && canScrollUp) {\n arrowPrefix = \"↑ \";\n } else if (isLastVisible && canScrollDown) {\n arrowPrefix = \"↓ \";\n } else {\n // No arrow, but reserve the same space\n arrowPrefix = \" \";\n }\n \n // Always reserve space for selection marker (pad with spaces if not selected)\n if (isSelected) {\n selectionPrefix = selectionMarker;\n } else {\n // Pad with spaces to match the length of the selection marker\n selectionPrefix = \" \".repeat(selectionMarker.length);\n }\n \n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: h(Box, { flexDirection: \"row\" },\n // Arrow (clickable if functional, not highlighted)\n h(Text, { \n key: `arrow-${actualIndex}`,\n color: \"white\"\n }, arrowPrefix),\n // Selection marker space (always same width, not highlighted) \n h(Text, { key: `marker-${actualIndex}`, color: \"white\" }, selectionPrefix),\n // Custom rendered content\n renderItem(item, isSelected, displayIndex)\n )\n });\n } else {\n // Use default renderer (which already includes scroll indicators)\n return h(ScreenRow, {\n key: `item-${actualIndex}`,\n children: itemRenderer(item, isSelected, displayIndex, actualIndex)\n });\n }\n })\n );\n}\n","/**\n * Reusable UI elements for the screen system\n */\n\nimport React, { createElement as h } from \"react\";\nimport { Box, Text } from \"ink\";\n\n// Types\nexport interface ListItemProps {\n children: React.ReactNode;\n isSelected?: boolean;\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n dimColor?: boolean;\n}\n\nexport interface TextBlockProps {\n text: string;\n color?: string;\n dimmed?: boolean;\n bold?: boolean;\n maxWidth?: number;\n}\n\nexport interface DividerProps {\n character?: string;\n width?: number;\n}\n\nexport interface GridCellProps {\n children: React.ReactNode;\n width?: number;\n color?: string;\n backgroundColor?: string;\n bold?: boolean;\n dimColor?: boolean;\n align?: \"left\" | \"center\" | \"right\";\n}\n\nexport interface InputFieldProps {\n prompt: string;\n value: string;\n onChange?: (value: string) => void;\n onSubmit?: (value: string) => void;\n}\n\n/**\n * List item component\n */\nexport function ListItem({ \n children, \n isSelected = false, \n color = \"white\", \n backgroundColor, \n bold = false, \n dimColor = false \n}: ListItemProps): JSX.Element {\n return h(Box, {},\n h(Text, {\n color: isSelected ? backgroundColor || \"green\" : color,\n backgroundColor: isSelected ? color : backgroundColor,\n bold: isSelected || bold,\n dimColor: !isSelected && dimColor\n }, children)\n );\n}\n\n/**\n * Text block component with customizable styling\n */\nexport function TextBlock({ \n text, \n color = \"white\", \n dimmed = false, \n bold = false, \n maxWidth \n}: TextBlockProps): JSX.Element {\n return h(Box, {},\n h(Text, { \n color, \n dimColor: dimmed, \n bold \n }, text)\n );\n}\n\n/**\n * Horizontal divider\n */\nexport function Divider({ character = \"─\", width = 80 }: DividerProps): JSX.Element {\n return h(Box, { marginY: 1 },\n h(Text, { dimColor: true }, character.repeat(width))\n );\n}\n\n/**\n * Grid cell component\n */\nexport function GridCell({ \n children, \n width, \n color = \"white\", \n backgroundColor, \n bold = false, \n dimColor = false, \n align = \"left\" \n}: GridCellProps): JSX.Element {\n return h(Box, { width },\n h(Text, {\n color,\n backgroundColor,\n bold,\n dimColor,\n textAlign: align\n }, children)\n );\n}\n\n/**\n * Input field component\n */\nexport function InputField({ prompt, value, onChange, onSubmit }: InputFieldProps): JSX.Element {\n return h(Box, { flexDirection: \"column\" },\n h(Text, {}, prompt),\n h(Box, { marginTop: 1 },\n h(Text, { color: \"cyan\" }, \" > \", value, \"_\")\n )\n );\n}","/**\n * Utility functions for Screen System\n */\n\n/**\n * Build breadcrumb-style title\n * @param parts - Parts of the breadcrumb path\n * @returns Formatted breadcrumb\n *\n * Examples:\n * buildBreadcrumb(['Menu']) → 'Menu'\n * buildBreadcrumb(['Menu', 'Info']) → '← Info'\n * buildBreadcrumb(['Menu', 'Words', 'nefarious']) → '← Words ← nefarious'\n */\nexport function buildBreadcrumb(parts: string[]): string {\n if (parts.length === 0) return \"\";\n if (parts.length === 1) return parts[0];\n\n // Skip first part (root), add arrows with spaces to rest\n return parts.slice(1).map(part => `← ${part}`).join(\" \");\n}\n\n/**\n * Create multi-line breadcrumb with details\n * @param path - Navigation path\n * @param suffix - Additional suffix (e.g., 'Details')\n * @returns Formatted breadcrumb with suffix\n *\n * Example:\n * buildDetailBreadcrumb(['Menu', 'Words', 'nefarious'], 'Details')\n * → '← Words ← nefarious Details'\n */\nexport function buildDetailBreadcrumb(path: string[], suffix: string = \"\"): string {\n if (path.length <= 1) {\n return suffix ? `← ${suffix}` : path[0] || \"\";\n }\n\n const breadcrumb = buildBreadcrumb(path);\n return suffix ? `${breadcrumb} ${suffix}` : breadcrumb;\n}\n","/**\n * Footer builder - composes footer messages from multiple sources\n */\n\ninterface FooterConfig {\n navigation?: string | string[];\n actions?: string | string[];\n info?: string | string[];\n escape?: string | string[];\n custom?: string | string[];\n}\n\n/**\n * Build footer lines from multiple message sources\n *\n * @param config - Footer configuration object\n * @returns Array of footer lines\n */\nexport function buildFooter(config: FooterConfig = {}): string[] {\n const {\n navigation = null,\n actions = null,\n info = null,\n escape = \"Esc to go back\",\n custom = null\n } = config;\n\n const lines: string[] = [];\n\n // Build main help line (navigation + actions + escape)\n const mainParts: (string | string[])[] = [];\n\n if (navigation) {\n mainParts.push(navigation);\n }\n\n if (actions) {\n mainParts.push(actions);\n }\n\n if (escape) {\n mainParts.push(escape);\n }\n\n if (mainParts.length > 0) {\n lines.push(mainParts.join(\", \"));\n }\n\n // Add info line if present\n if (info) {\n const infoLines = Array.isArray(info) ? info : [info];\n lines.push(...infoLines);\n }\n\n // Add custom lines if present\n if (custom) {\n const customLines = Array.isArray(custom) ? custom : [custom];\n lines.push(...customLines);\n }\n\n return lines;\n}\n\n/**\n * Predefined footer configurations for common screen types\n */\nexport const FooterPresets = {\n /**\n * Menu screen footer\n */\n menu: (customInfo: string | string[] | null = null): string[] => buildFooter({\n navigation: \"↑/↓ to navigate\",\n actions: \"Enter to select\",\n escape: \"Esc to go back\",\n info: customInfo\n }),\n\n /**\n * Word grid footer\n */\n wordGrid: (totalWords: number): string[] => buildFooter({\n navigation: \"↑↓←→ to navigate\",\n actions: \"Enter to select\",\n escape: \"Esc to go back\",\n info: `Total: ${totalWords} words`\n }),\n\n /**\n * Text input footer\n */\n textInput: (): string[] => buildFooter({\n actions: \"Type and press Enter to submit\",\n escape: \"Esc to cancel\"\n }),\n\n /**\n * Info/static screen footer\n */\n info: (): string[] => buildFooter({\n escape: \"Esc to continue\"\n }),\n\n /**\n * Main menu footer (escape exits)\n */\n mainMenu: (): string[] => buildFooter({\n navigation: \"↑/↓ to navigate\",\n actions: \"Enter to select\",\n escape: \"Esc to exit\"\n }),\n\n /**\n * Action menu footer (for word cards, etc.)\n */\n actionMenu: (hasAudio: boolean = false): string[] => {\n const parts = buildFooter({\n navigation: \"↑/↓ to navigate\",\n actions: \"Enter to select\",\n escape: \"Esc to go back\"\n });\n\n if (hasAudio) {\n parts.push(\"Audio available\");\n }\n\n return parts;\n }\n};\n\n/**\n * Combine multiple footer messages into organized lines\n * Smart grouping of related messages\n *\n * @param messages - Individual footer messages\n * @returns Organized footer lines\n */\nexport function organizeFooterMessages(messages: string[] | null | undefined): string[] {\n if (!messages || messages.length === 0) {\n return [\"Esc to go back\"];\n }\n\n // Group similar messages\n const navigation = messages.filter(m => m.includes(\"↑\") || m.includes(\"↓\") || m.includes(\"←\") || m.includes(\"→\"));\n const actions = messages.filter(m => m.includes(\"Enter\") || m.includes(\"select\") || m.includes(\"submit\"));\n const escape = messages.filter(m => m.includes(\"Esc\"));\n const others = messages.filter(m =>\n !navigation.includes(m) &&\n !actions.includes(m) &&\n !escape.includes(m)\n );\n\n const lines: string[] = [];\n\n // Combine navigation, actions, and escape on one line\n const mainLine = [...navigation, ...actions, ...escape].join(\", \");\n if (mainLine) lines.push(mainLine);\n\n // Add other messages as separate lines\n lines.push(...others);\n\n return lines;\n}\n"],"mappings":"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","names":["React","import_react","import_ink","import_react","import_ink","h","import_react","import_ink","h","React","h","import_react","import_ink","h"]}
package/dist/screen.js CHANGED
@@ -1,3 +1,7 @@
1
+ // src/screen/index.ts
2
+ import React5, { useState as useState3, useEffect as useEffect3, useRef as useRef3, useMemo, useCallback, createElement as createElement2 } from "react";
3
+ import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
4
+
1
5
  // src/screen/screens.ts
2
6
  import { useState as useState2, createElement as h3 } from "react";
3
7
  import { render, useInput, Text as Text3 } from "ink";
@@ -978,6 +982,7 @@ function organizeFooterMessages(messages) {
978
982
  return lines;
979
983
  }
980
984
  export {
985
+ Box5 as Box,
981
986
  Divider,
982
987
  FooterPresets,
983
988
  GridCell,
@@ -986,22 +991,31 @@ export {
986
991
  ListItem,
987
992
  MultiColumnListComponent,
988
993
  MultiColumnListWithPreviewComponent,
994
+ React5 as React,
989
995
  ScreenBody,
990
996
  ScreenContainer,
991
997
  ScreenDivider,
992
998
  ScreenFooter,
993
999
  ScreenRow,
994
1000
  ScreenTitle,
1001
+ Text5 as Text,
995
1002
  TextBlock,
996
1003
  buildBreadcrumb,
997
1004
  buildDetailBreadcrumb,
998
1005
  buildFooter,
1006
+ createElement2 as h,
999
1007
  organizeFooterMessages,
1000
1008
  showListScreen,
1001
1009
  showMenuScreen,
1002
1010
  showMultiColumnListScreen,
1003
1011
  showMultiColumnListWithPreviewScreen,
1004
1012
  showScreen,
1005
- showWordGridScreen
1013
+ showWordGridScreen,
1014
+ useCallback,
1015
+ useEffect3 as useEffect,
1016
+ useInput2 as useInput,
1017
+ useMemo,
1018
+ useRef3 as useRef,
1019
+ useState3 as useState
1006
1020
  };
1007
1021
  //# sourceMappingURL=screen.js.map