@within-7/minto 0.3.6 → 0.3.10
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.
- package/{cli.js → cli.cjs} +25 -23
- package/dist/commands/agents/AgentsCommand.js +459 -655
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/agents/types.js +1 -0
- package/dist/commands/agents/types.js.map +2 -2
- package/dist/commands/agents/utils/fileOperations.js +96 -36
- package/dist/commands/agents/utils/fileOperations.js.map +3 -3
- package/dist/commands/agents/utils/index.js +3 -1
- package/dist/commands/agents/utils/index.js.map +2 -2
- package/dist/commands/context.js +54 -23
- package/dist/commands/context.js.map +2 -2
- package/dist/commands/export.js +673 -93
- package/dist/commands/export.js.map +2 -2
- package/dist/commands/language.js +110 -0
- package/dist/commands/language.js.map +7 -0
- package/dist/commands/mcp-interactive.js +419 -217
- package/dist/commands/mcp-interactive.js.map +2 -2
- package/dist/commands/model.js +415 -66
- package/dist/commands/model.js.map +2 -2
- package/dist/commands/new.js +56 -0
- package/dist/commands/new.js.map +7 -0
- package/dist/commands/permissions.js +75 -49
- package/dist/commands/permissions.js.map +2 -2
- package/dist/commands/plugin.js +882 -185
- package/dist/commands/plugin.js.map +3 -3
- package/dist/commands/resume.js +251 -16
- package/dist/commands/resume.js.map +2 -2
- package/dist/commands/sandbox.js +168 -70
- package/dist/commands/sandbox.js.map +2 -2
- package/dist/commands/sessions.js +224 -0
- package/dist/commands/sessions.js.map +7 -0
- package/dist/commands/setup.js +596 -109
- package/dist/commands/setup.js.map +2 -2
- package/dist/commands/stats.js +292 -0
- package/dist/commands/stats.js.map +7 -0
- package/dist/commands/status.js +75 -7
- package/dist/commands/status.js.map +2 -2
- package/dist/commands/undo.js +154 -180
- package/dist/commands/undo.js.map +2 -2
- package/dist/commands.js +6 -0
- package/dist/commands.js.map +2 -2
- package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
- package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
- package/dist/components/Config.js +9 -8
- package/dist/components/Config.js.map +2 -2
- package/dist/components/HeaderBar.js +2 -1
- package/dist/components/HeaderBar.js.map +2 -2
- package/dist/components/Help.js +166 -32
- package/dist/components/Help.js.map +2 -2
- package/dist/components/HotkeyHelpPanel.js +46 -44
- package/dist/components/HotkeyHelpPanel.js.map +2 -2
- package/dist/components/InfoPanel/InfoPanel.js +123 -0
- package/dist/components/InfoPanel/InfoPanel.js.map +7 -0
- package/dist/components/InfoPanel/index.js +5 -0
- package/dist/components/InfoPanel/index.js.map +7 -0
- package/dist/components/InfoPanel/types.js +1 -0
- package/dist/components/InfoPanel/types.js.map +7 -0
- package/dist/components/Logo.js +5 -2
- package/dist/components/Logo.js.map +2 -2
- package/dist/components/MCPServerApprovalDialog.js +6 -5
- package/dist/components/MCPServerApprovalDialog.js.map +2 -2
- package/dist/components/MCPServerMultiselectDialog.js +5 -4
- package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
- package/dist/components/MessageSelector.js +4 -3
- package/dist/components/MessageSelector.js.map +2 -2
- package/dist/components/ModelConfig.js +13 -12
- package/dist/components/ModelConfig.js.map +2 -2
- package/dist/components/ModelListManager.js +4 -3
- package/dist/components/ModelListManager.js.map +2 -2
- package/dist/components/ModelSelector/BrandTextInput.js +43 -0
- package/dist/components/ModelSelector/BrandTextInput.js.map +7 -0
- package/dist/components/ModelSelector/ModelSelector.js +419 -501
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/ModelSelector/WizardContainer.js +45 -0
- package/dist/components/ModelSelector/WizardContainer.js.map +7 -0
- package/dist/components/ModelSelector/index.js +1 -3
- package/dist/components/ModelSelector/index.js.map +2 -2
- package/dist/components/PromptInput.js +77 -44
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/SensitiveFileWarning.js +12 -8
- package/dist/components/SensitiveFileWarning.js.map +2 -2
- package/dist/components/SimpleSelector/SimpleSelector.js +154 -0
- package/dist/components/SimpleSelector/SimpleSelector.js.map +7 -0
- package/dist/components/SimpleSelector/index.js +5 -0
- package/dist/components/SimpleSelector/index.js.map +7 -0
- package/dist/components/SimpleSelector/types.js +1 -0
- package/dist/components/SimpleSelector/types.js.map +7 -0
- package/dist/components/StatusOverlayContent.js +21 -0
- package/dist/components/StatusOverlayContent.js.map +7 -0
- package/dist/components/TabbedListView/ScrollableList.js +117 -0
- package/dist/components/TabbedListView/ScrollableList.js.map +7 -0
- package/dist/components/TabbedListView/SearchInput.js +23 -0
- package/dist/components/TabbedListView/SearchInput.js.map +7 -0
- package/dist/components/TabbedListView/TabBar.js +20 -0
- package/dist/components/TabbedListView/TabBar.js.map +7 -0
- package/dist/components/TabbedListView/TabbedListView.js +246 -0
- package/dist/components/TabbedListView/TabbedListView.js.map +7 -0
- package/dist/components/TabbedListView/index.js +11 -0
- package/dist/components/TabbedListView/index.js.map +7 -0
- package/dist/components/TabbedListView/types.js +1 -0
- package/dist/components/TabbedListView/types.js.map +7 -0
- package/dist/components/TodoChangeBlock.js +6 -5
- package/dist/components/TodoChangeBlock.js.map +3 -3
- package/dist/components/TodoPanel.js +6 -3
- package/dist/components/TodoPanel.js.map +3 -3
- package/dist/components/TrustDialog.js +6 -5
- package/dist/components/TrustDialog.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js +2 -1
- package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js.map +2 -2
- package/dist/constants/macros.js +1 -1
- package/dist/constants/macros.js.map +1 -1
- package/dist/constants/product.js +2 -2
- package/dist/constants/product.js.map +1 -1
- package/dist/constants/prompts.js +17 -0
- package/dist/constants/prompts.js.map +2 -2
- package/dist/constants/toolInputExamples.js +5 -1
- package/dist/constants/toolInputExamples.js.map +2 -2
- package/dist/core/backupHook.js +29 -0
- package/dist/core/backupHook.js.map +7 -0
- package/dist/core/config/defaults.js +8 -2
- package/dist/core/config/defaults.js.map +2 -2
- package/dist/core/config/schema.js +14 -2
- package/dist/core/config/schema.js.map +2 -2
- package/dist/core/costTracker.js +0 -16
- package/dist/core/costTracker.js.map +2 -2
- package/dist/core/tokenStatsManager.js +5 -0
- package/dist/core/tokenStatsManager.js.map +2 -2
- package/dist/cost-tracker.js +0 -16
- package/dist/cost-tracker.js.map +2 -2
- package/dist/entrypoints/bootstrap.js +56 -0
- package/dist/entrypoints/bootstrap.js.map +7 -0
- package/dist/entrypoints/cli.js +164 -23
- package/dist/entrypoints/cli.js.map +3 -3
- package/dist/history.js +75 -15
- package/dist/history.js.map +2 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/index.js.map +2 -2
- package/dist/i18n/locales/en.js +582 -1
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +582 -1
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/i18n/types.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/dist/messages.js +11 -0
- package/dist/messages.js.map +2 -2
- package/dist/permissions.js.map +2 -2
- package/dist/query.js +9 -0
- package/dist/query.js.map +2 -2
- package/dist/screens/REPL.js +45 -7
- package/dist/screens/REPL.js.map +2 -2
- package/dist/services/customCommands.js +44 -16
- package/dist/services/customCommands.js.map +2 -2
- package/dist/services/plugins/lspServers.js +1 -1
- package/dist/services/plugins/lspServers.js.map +2 -2
- package/dist/services/plugins/pluginRuntime.js +2 -1
- package/dist/services/plugins/pluginRuntime.js.map +2 -2
- package/dist/services/plugins/pluginValidation.js +10 -3
- package/dist/services/plugins/pluginValidation.js.map +2 -2
- package/dist/services/plugins/skillMarketplace.js +16 -8
- package/dist/services/plugins/skillMarketplace.js.map +2 -2
- package/dist/services/systemReminder.js +17 -6
- package/dist/services/systemReminder.js.map +2 -2
- package/dist/tools/FileEditTool/FileEditTool.js +7 -0
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileWriteTool/FileWriteTool.js +7 -0
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
- package/dist/tools/MultiEditTool/MultiEditTool.js +7 -0
- package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
- package/dist/tools/NotebookEditTool/NotebookEditTool.js +2 -0
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
- package/dist/tools/TaskTool/TaskTool.js +179 -1
- package/dist/tools/TaskTool/TaskTool.js.map +2 -2
- package/dist/tools/TodoWriteTool/prompt.js +21 -0
- package/dist/tools/TodoWriteTool/prompt.js.map +2 -2
- package/dist/tools/URLFetcherTool/prompt.js +14 -9
- package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
- package/dist/tools/WebSearchTool/prompt.js +12 -6
- package/dist/tools/WebSearchTool/prompt.js.map +2 -2
- package/dist/types/PermissionMode.js +30 -1
- package/dist/types/PermissionMode.js.map +2 -2
- package/dist/types/plugin.js +2 -4
- package/dist/types/plugin.js.map +2 -2
- package/dist/utils/agentHookExecutor.js +103 -0
- package/dist/utils/agentHookExecutor.js.map +7 -0
- package/dist/utils/agentLoader.js +272 -32
- package/dist/utils/agentLoader.js.map +2 -2
- package/dist/utils/agentMemory.js +134 -0
- package/dist/utils/agentMemory.js.map +7 -0
- package/dist/utils/claudeCodeSync.js +439 -0
- package/dist/utils/claudeCodeSync.js.map +7 -0
- package/dist/utils/config.js +52 -24
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/configPaths.js +199 -0
- package/dist/utils/configPaths.js.map +7 -0
- package/dist/utils/execFileNoThrow.js +2 -1
- package/dist/utils/execFileNoThrow.js.map +2 -2
- package/dist/utils/historyManager.js +234 -0
- package/dist/utils/historyManager.js.map +7 -0
- package/dist/utils/marketplaceManager.js +80 -43
- package/dist/utils/marketplaceManager.js.map +2 -2
- package/dist/utils/messages.js +13 -8
- package/dist/utils/messages.js.map +2 -2
- package/dist/utils/migration/index.js +37 -0
- package/dist/utils/migration/index.js.map +7 -0
- package/dist/utils/migration/migrateHistory.js +273 -0
- package/dist/utils/migration/migrateHistory.js.map +7 -0
- package/dist/utils/migration/migrateTodos.js +323 -0
- package/dist/utils/migration/migrateTodos.js.map +7 -0
- package/dist/utils/pasteCache.js +309 -0
- package/dist/utils/pasteCache.js.map +7 -0
- package/dist/utils/pluginInstaller.js +34 -24
- package/dist/utils/pluginInstaller.js.map +2 -2
- package/dist/utils/pluginLoader.js +54 -28
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/repoFetcher.js +110 -0
- package/dist/utils/repoFetcher.js.map +7 -0
- package/dist/utils/sessionIndex.js +192 -0
- package/dist/utils/sessionIndex.js.map +7 -0
- package/dist/utils/sessionTracker.js +170 -0
- package/dist/utils/sessionTracker.js.map +7 -0
- package/dist/utils/skillLoader.js +103 -5
- package/dist/utils/skillLoader.js.map +2 -2
- package/dist/utils/stats.js +417 -0
- package/dist/utils/stats.js.map +7 -0
- package/dist/utils/stringSubstitution.js +106 -0
- package/dist/utils/stringSubstitution.js.map +7 -0
- package/dist/utils/teamConfig.js +156 -14
- package/dist/utils/teamConfig.js.map +2 -2
- package/dist/utils/terminal.js +1 -1
- package/dist/utils/terminal.js.map +2 -2
- package/dist/utils/todoStorage.js +51 -19
- package/dist/utils/todoStorage.js.map +2 -2
- package/dist/utils/tooling/safeRender.js.map +2 -2
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +71 -28
- package/scripts/{postinstall.js → postinstall.cjs} +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/SimpleSelector/SimpleSelector.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * SimpleSelector Component\n *\n * A lightweight single-choice selector visually matching TabbedListView\n * but without tabs or search. Reuses ScrollableList internally.\n *\n * Visual pattern:\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 (BRAND_GRADIENT.START border)\n * \u25C6 Title subtitle\n *\n * Category Name\n * \u25C6 Item A (current)\n * Item B description\n * Item C description\n *\n * \u2191\u2193 Navigate \u00B7 Enter Select \u00B7 Esc Close\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 (BRAND_GRADIENT.START border)\n */\n\nimport React, { useState, useMemo, useCallback } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { ScrollableList } from '@components/TabbedListView'\nimport { StatusOverlayContent } from '@components/StatusOverlayContent'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { t } from '@i18n'\nimport type { ListItem } from '@components/TabbedListView'\nimport type { SimpleSelectorProps, SelectorItem } from './types'\n\n// Heights for dynamic visible count calculation\nconst PROMPT_HEIGHT = 5 // PromptInput borders + input + hints\nconst CHROME_HEIGHT = 4 // title + footer + borders (no tabs/search)\n\n/**\n * Convert SelectorItems to ListItems for ScrollableList\n */\nfunction toListItems(items: SelectorItem[]): ListItem[] {\n return items.map(item => ({\n id: item.id,\n label: item.label,\n description: item.description,\n category: item.category,\n metadata: item.isCurrent ? `(${t('common.selected')})` : undefined,\n status: item.isCurrent ? ('enabled' as const) : undefined,\n data: item,\n }))\n}\n\n/**\n * Custom item renderer that supports statusIcon and statusColor\n */\nfunction SelectorItemRenderer({\n item,\n isFocused,\n selectorItem,\n}: {\n item: ListItem\n isFocused: boolean\n selectorItem?: SelectorItem\n}) {\n const textColor = isFocused ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim\n\n return (\n <Box flexDirection=\"row\">\n {/* Selection indicator */}\n <Text color={isFocused ? BRAND_GRADIENT.START : undefined}>\n {isFocused ? '\\u25C6 ' : ' '}\n </Text>\n\n {/* Status icon if present */}\n {selectorItem?.statusIcon && (\n <Text color={selectorItem.statusColor || SEMANTIC_COLORS.dim}>\n {selectorItem.statusIcon}{' '}\n </Text>\n )}\n\n {/* Main content */}\n <Text color={textColor}>\n {item.label}\n {selectorItem?.isCurrent && (\n <Text color={SEMANTIC_COLORS.success}> ({t('common.selected')})</Text>\n )}\n {item.description && (\n <Text color={SEMANTIC_COLORS.muted}> {item.description}</Text>\n )}\n </Text>\n </Box>\n )\n}\n\nexport function SimpleSelector({\n title,\n subtitle,\n items,\n onSelect,\n onClose,\n groupByCategory = false,\n statusOverlay,\n isActive = true,\n maxVisible,\n}: SimpleSelectorProps) {\n // Dynamic visible count based on terminal height\n const { rows } = useTerminalSize()\n const dynamicVisible = Math.min(\n 8,\n Math.max(3, rows - PROMPT_HEIGHT - CHROME_HEIGHT),\n )\n const effectiveMaxVisible = maxVisible ?? dynamicVisible\n\n const [focusedIndex, setFocusedIndex] = useState(0)\n\n const listItems = useMemo(() => toListItems(items), [items])\n\n // Map from ListItem back to SelectorItem for custom rendering\n const selectorItemMap = useMemo(() => {\n const map = new Map<string, SelectorItem>()\n items.forEach(item => map.set(item.id, item))\n return map\n }, [items])\n\n const handleSelect = useCallback(\n (listItem: ListItem) => {\n const selectorItem = selectorItemMap.get(listItem.id)\n if (selectorItem) {\n onSelect(selectorItem)\n }\n },\n [selectorItemMap, onSelect],\n )\n\n const renderItem = useCallback(\n (item: ListItem, isFocused: boolean) => (\n <SelectorItemRenderer\n item={item}\n isFocused={isFocused}\n selectorItem={selectorItemMap.get(item.id)}\n />\n ),\n [selectorItemMap],\n )\n\n // Keyboard input handling\n useInput(\n (input, key) => {\n // Status overlay: success/error -> ESC/Enter closes\n if (statusOverlay && statusOverlay.type !== 'loading') {\n if (key.escape || key.return) {\n onClose()\n }\n return\n }\n\n // Status overlay: loading -> ignore all input\n if (statusOverlay) return\n\n // Escape closes\n if (key.escape) {\n onClose()\n return\n }\n\n // Arrow navigation\n if (key.downArrow && listItems.length > 0) {\n setFocusedIndex(prev => (prev < listItems.length - 1 ? prev + 1 : prev))\n return\n }\n\n if (key.upArrow && listItems.length > 0) {\n setFocusedIndex(prev => (prev > 0 ? prev - 1 : prev))\n return\n }\n\n // Enter to select\n if (key.return && listItems.length > 0) {\n handleSelect(listItems[focusedIndex])\n return\n }\n },\n { isActive },\n )\n\n // Build footer hint\n const footerHint = statusOverlay\n ? statusOverlay.type === 'loading'\n ? ''\n : t('ui.simpleSelector.dismissHint')\n : t('ui.simpleSelector.navigationHint')\n\n return (\n <Box flexDirection=\"column\" width=\"100%\">\n {/* Header bar with top border */}\n <Box\n borderTop={true}\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n flexDirection=\"column\"\n >\n {/* Title with brand color */}\n <Box>\n <Text color={BRAND_GRADIENT.START}>{'\\u25C6'}</Text>\n <Text bold color={SEMANTIC_COLORS.secondary}>\n {' '}\n {title}\n </Text>\n {subtitle && (\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n {subtitle}\n </Text>\n )}\n </Box>\n </Box>\n\n {/* Content container with bottom border */}\n <Box\n flexDirection=\"column\"\n borderTop={false}\n borderBottom={true}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n paddingY={1}\n >\n {statusOverlay ? (\n <StatusOverlayContent\n type={statusOverlay.type}\n message={statusOverlay.message}\n />\n ) : listItems.length === 0 ? (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('ui.tabbedList.noItems')}\n </Text>\n </Box>\n ) : (\n <ScrollableList\n items={listItems}\n focusedIndex={focusedIndex}\n onFocusChange={setFocusedIndex}\n onSelect={handleSelect}\n visibleCount={effectiveMaxVisible}\n groupByCategory={groupByCategory}\n renderItem={renderItem}\n />\n )}\n\n {/* Footer Hint */}\n {footerHint && (\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.muted}>{footerHint}</Text>\n </Box>\n )}\n </Box>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/SimpleSelector/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * SimpleSelector Component Exports\n *\n * A lightweight single-choice selector for quick selection commands.\n */\n\nexport { SimpleSelector } from './SimpleSelector'\nexport type { SimpleSelectorProps, SelectorItem, StatusOverlay } from './types'\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,sBAAsB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
|
|
4
|
+
import { SimpleSpinner } from "./Spinner.js";
|
|
5
|
+
function StatusOverlayContent({
|
|
6
|
+
type,
|
|
7
|
+
message
|
|
8
|
+
}) {
|
|
9
|
+
switch (type) {
|
|
10
|
+
case "loading":
|
|
11
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(SimpleSpinner, null), /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.MIDDLE }, " ", message));
|
|
12
|
+
case "success":
|
|
13
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, "\u2713", " ", message));
|
|
14
|
+
case "error":
|
|
15
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.error }, "\u2717", " ", message));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
StatusOverlayContent
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=StatusOverlayContent.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/StatusOverlayContent.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared StatusOverlayContent component\n *\n * Renders loading/success/error overlay content used by\n * TabbedListView, InfoPanel, and SimpleSelector.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { SimpleSpinner } from '@components/Spinner'\n\nexport type StatusOverlay = {\n type: 'loading' | 'success' | 'error'\n message: string\n}\n\nexport function StatusOverlayContent({\n type,\n message,\n}: {\n type: 'loading' | 'success' | 'error'\n message: string\n}) {\n switch (type) {\n case 'loading':\n return (\n <Box>\n <SimpleSpinner />\n <Text color={BRAND_GRADIENT.MIDDLE}> {message}</Text>\n </Box>\n )\n case 'success':\n return (\n <Box>\n <Text color={SEMANTIC_COLORS.success}>\n {'\\u2713'} {message}\n </Text>\n </Box>\n )\n case 'error':\n return (\n <Box>\n <Text color={SEMANTIC_COLORS.error}>\n {'\\u2717'} {message}\n </Text>\n </Box>\n )\n }\n}\n"],
|
|
5
|
+
"mappings": "AAOA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB,uBAAuB;AAChD,SAAS,qBAAqB;AAOvB,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AACF,GAGG;AACD,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aACE,oCAAC,WACC,oCAAC,mBAAc,GACf,oCAAC,QAAK,OAAO,eAAe,UAAQ,KAAE,OAAQ,CAChD;AAAA,IAEJ,KAAK;AACH,aACE,oCAAC,WACC,oCAAC,QAAK,OAAO,gBAAgB,WAC1B,UAAS,KAAE,OACd,CACF;AAAA,IAEJ,KAAK;AACH,aACE,oCAAC,WACC,oCAAC,QAAK,OAAO,gBAAgB,SAC1B,UAAS,KAAE,OACd,CACF;AAAA,EAEN;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { SEMANTIC_COLORS, BRAND_GRADIENT } from "../../constants/colors.js";
|
|
4
|
+
const getStatusIcon = (status) => {
|
|
5
|
+
switch (status) {
|
|
6
|
+
case "enabled":
|
|
7
|
+
return { icon: "\u2714", color: SEMANTIC_COLORS.success };
|
|
8
|
+
case "disabled":
|
|
9
|
+
return { icon: "\u25CB", color: SEMANTIC_COLORS.dim };
|
|
10
|
+
case "running":
|
|
11
|
+
return { icon: "\u25D0", color: SEMANTIC_COLORS.running };
|
|
12
|
+
case "error":
|
|
13
|
+
return { icon: "\u2717", color: SEMANTIC_COLORS.error };
|
|
14
|
+
default:
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
function DefaultItemRenderer({
|
|
19
|
+
item,
|
|
20
|
+
isFocused,
|
|
21
|
+
multiSelect,
|
|
22
|
+
isSelected
|
|
23
|
+
}) {
|
|
24
|
+
const statusInfo = getStatusIcon(item.status);
|
|
25
|
+
const checkboxWidth = multiSelect ? 2 : 0;
|
|
26
|
+
const focusWidth = 2;
|
|
27
|
+
const statusWidth = statusInfo ? 2 : 0;
|
|
28
|
+
const prefixPad = checkboxWidth + focusWidth + statusWidth;
|
|
29
|
+
const labelColor = isFocused ? BRAND_GRADIENT.START : SEMANTIC_COLORS.secondary;
|
|
30
|
+
const descColor = SEMANTIC_COLORS.dim;
|
|
31
|
+
const metaColor = SEMANTIC_COLORS.muted;
|
|
32
|
+
const hasDescription = !!item.description;
|
|
33
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, multiSelect && /* @__PURE__ */ React.createElement(
|
|
34
|
+
Text,
|
|
35
|
+
{
|
|
36
|
+
color: isSelected ? SEMANTIC_COLORS.success : SEMANTIC_COLORS.dim
|
|
37
|
+
},
|
|
38
|
+
isSelected ? "\u2611 " : "\u2610 "
|
|
39
|
+
), /* @__PURE__ */ React.createElement(Text, { color: isFocused ? BRAND_GRADIENT.START : void 0 }, isFocused ? "\u25C6 " : " "), statusInfo && /* @__PURE__ */ React.createElement(Text, { color: statusInfo.color }, statusInfo.icon, " "), /* @__PURE__ */ React.createElement(Text, { bold: isFocused, color: labelColor }, item.label), item.metadata && /* @__PURE__ */ React.createElement(Text, { color: metaColor }, " \xB7 ", item.metadata)), hasDescription && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: descColor }, " ".repeat(prefixPad), item.description)));
|
|
40
|
+
}
|
|
41
|
+
function ScrollableList({
|
|
42
|
+
items,
|
|
43
|
+
focusedIndex,
|
|
44
|
+
onFocusChange,
|
|
45
|
+
onSelect,
|
|
46
|
+
visibleCount,
|
|
47
|
+
groupByCategory = false,
|
|
48
|
+
renderItem,
|
|
49
|
+
multiSelect,
|
|
50
|
+
selectedIds
|
|
51
|
+
}) {
|
|
52
|
+
const { visibleItems, startIndex, endIndex } = useMemo(() => {
|
|
53
|
+
if (items.length === 0) {
|
|
54
|
+
return { visibleItems: [], startIndex: 0, endIndex: 0 };
|
|
55
|
+
}
|
|
56
|
+
if (items.length <= visibleCount) {
|
|
57
|
+
return {
|
|
58
|
+
visibleItems: items.map((item, i) => ({ item, globalIndex: i })),
|
|
59
|
+
startIndex: 0,
|
|
60
|
+
endIndex: items.length
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const halfWindow = Math.floor(visibleCount / 2);
|
|
64
|
+
let start = Math.max(0, focusedIndex - halfWindow);
|
|
65
|
+
let end = start + visibleCount;
|
|
66
|
+
if (end > items.length) {
|
|
67
|
+
end = items.length;
|
|
68
|
+
start = Math.max(0, end - visibleCount);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
visibleItems: items.slice(start, end).map((item, i) => ({
|
|
72
|
+
item,
|
|
73
|
+
globalIndex: start + i
|
|
74
|
+
})),
|
|
75
|
+
startIndex: start,
|
|
76
|
+
endIndex: end
|
|
77
|
+
};
|
|
78
|
+
}, [items, focusedIndex, visibleCount]);
|
|
79
|
+
const hasMoreAbove = startIndex > 0;
|
|
80
|
+
const hasMoreBelow = endIndex < items.length;
|
|
81
|
+
const countAbove = startIndex;
|
|
82
|
+
const countBelow = items.length - endIndex;
|
|
83
|
+
const displayElements = [];
|
|
84
|
+
let currentCategory = "";
|
|
85
|
+
visibleItems.forEach(({ item, globalIndex }, visibleIndex) => {
|
|
86
|
+
if (groupByCategory && item.category !== currentCategory) {
|
|
87
|
+
currentCategory = item.category || "Other";
|
|
88
|
+
displayElements.push(
|
|
89
|
+
/* @__PURE__ */ React.createElement(
|
|
90
|
+
Box,
|
|
91
|
+
{
|
|
92
|
+
key: `category-${currentCategory}-${globalIndex}`,
|
|
93
|
+
marginTop: visibleIndex > 0 ? 1 : 0
|
|
94
|
+
},
|
|
95
|
+
/* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, currentCategory)
|
|
96
|
+
)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
const isFocused = globalIndex === focusedIndex;
|
|
100
|
+
const isSelected = selectedIds?.has(item.id) ?? false;
|
|
101
|
+
const itemElement = renderItem ? renderItem(item, isFocused, isSelected) : /* @__PURE__ */ React.createElement(
|
|
102
|
+
DefaultItemRenderer,
|
|
103
|
+
{
|
|
104
|
+
item,
|
|
105
|
+
isFocused,
|
|
106
|
+
multiSelect,
|
|
107
|
+
isSelected
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
displayElements.push(/* @__PURE__ */ React.createElement(Box, { key: item.id }, itemElement));
|
|
111
|
+
});
|
|
112
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, hasMoreAbove && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " \u2191 ", countAbove, " more above...")), displayElements, hasMoreBelow && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " \u2193 ", countBelow, " more below...")));
|
|
113
|
+
}
|
|
114
|
+
export {
|
|
115
|
+
ScrollableList
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=ScrollableList.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/TabbedListView/ScrollableList.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * ScrollableList Component\n *\n * A scrollable list matching the /command suggestion UI pattern.\n * Uses \u25C6 indicator for selection, brand colors, and scroll indicators.\n */\n\nimport React, { useMemo } from 'react'\nimport { Box, Text } from 'ink'\nimport { SEMANTIC_COLORS, BRAND_GRADIENT } from '@constants/colors'\nimport { t } from '@i18n'\nimport type { ListItem, ScrollableListProps, CategoryGroup } from './types'\n\n/** Status icon mapping */\nconst getStatusIcon = (status?: ListItem['status']) => {\n switch (status) {\n case 'enabled':\n return { icon: '\u2714', color: SEMANTIC_COLORS.success }\n case 'disabled':\n return { icon: '\u25CB', color: SEMANTIC_COLORS.dim }\n case 'running':\n return { icon: '\u25D0', color: SEMANTIC_COLORS.running }\n case 'error':\n return { icon: '\u2717', color: SEMANTIC_COLORS.error }\n default:\n return null\n }\n}\n\n/** Default item renderer - two-line layout with clear visual hierarchy */\nfunction DefaultItemRenderer({\n item,\n isFocused,\n multiSelect,\n isSelected,\n}: {\n item: ListItem\n isFocused: boolean\n multiSelect?: boolean\n isSelected?: boolean\n}) {\n const statusInfo = getStatusIcon(item.status)\n\n // Prefix width: checkbox \"\u2611 \" (2) + \"\u25C6 \" (2) + optional status icon \"\u2714 \" (2)\n const checkboxWidth = multiSelect ? 2 : 0\n const focusWidth = 2\n const statusWidth = statusInfo ? 2 : 0\n const prefixPad = checkboxWidth + focusWidth + statusWidth\n\n // Colors: focused items use brand gradient, unfocused use secondary/dim\n const labelColor = isFocused\n ? BRAND_GRADIENT.START\n : SEMANTIC_COLORS.secondary\n const descColor = SEMANTIC_COLORS.dim\n const metaColor = SEMANTIC_COLORS.muted\n\n const hasDescription = !!item.description\n\n return (\n <Box flexDirection=\"column\">\n {/* Line 1: [checkbox] + indicator + status + label + metadata */}\n <Box flexDirection=\"row\">\n {multiSelect && (\n <Text\n color={isSelected ? SEMANTIC_COLORS.success : SEMANTIC_COLORS.dim}\n >\n {isSelected ? '\u2611 ' : '\u2610 '}\n </Text>\n )}\n <Text color={isFocused ? BRAND_GRADIENT.START : undefined}>\n {isFocused ? '\u25C6 ' : ' '}\n </Text>\n {statusInfo && <Text color={statusInfo.color}>{statusInfo.icon} </Text>}\n <Text bold={isFocused} color={labelColor}>\n {item.label}\n </Text>\n {item.metadata && <Text color={metaColor}> \u00B7 {item.metadata}</Text>}\n </Box>\n\n {/* Line 2: description (indented to align under label) */}\n {hasDescription && (\n <Box>\n <Text color={descColor}>\n {' '.repeat(prefixPad)}\n {item.description}\n </Text>\n </Box>\n )}\n </Box>\n )\n}\n\nexport function ScrollableList({\n items,\n focusedIndex,\n onFocusChange,\n onSelect,\n visibleCount,\n groupByCategory = false,\n renderItem,\n multiSelect,\n selectedIds,\n}: ScrollableListProps) {\n // Calculate scroll window to keep selected item visible (same logic as command suggestions)\n const { visibleItems, startIndex, endIndex } = useMemo(() => {\n if (items.length === 0) {\n return { visibleItems: [], startIndex: 0, endIndex: 0 }\n }\n\n // If all items fit in window, show them all\n if (items.length <= visibleCount) {\n return {\n visibleItems: items.map((item, i) => ({ item, globalIndex: i })),\n startIndex: 0,\n endIndex: items.length,\n }\n }\n\n // Calculate scroll window to keep focused item visible\n const halfWindow = Math.floor(visibleCount / 2)\n let start = Math.max(0, focusedIndex - halfWindow)\n let end = start + visibleCount\n\n // Adjust if we're near the end\n if (end > items.length) {\n end = items.length\n start = Math.max(0, end - visibleCount)\n }\n\n return {\n visibleItems: items.slice(start, end).map((item, i) => ({\n item,\n globalIndex: start + i,\n })),\n startIndex: start,\n endIndex: end,\n }\n }, [items, focusedIndex, visibleCount])\n\n // Scroll indicators\n const hasMoreAbove = startIndex > 0\n const hasMoreBelow = endIndex < items.length\n const countAbove = startIndex\n const countBelow = items.length - endIndex\n\n // Build display with optional category headers\n const displayElements: React.ReactNode[] = []\n let currentCategory = ''\n\n visibleItems.forEach(({ item, globalIndex }, visibleIndex) => {\n // Add category header if category changed and grouping is enabled\n if (groupByCategory && item.category !== currentCategory) {\n currentCategory = item.category || 'Other'\n displayElements.push(\n <Box\n key={`category-${currentCategory}-${globalIndex}`}\n marginTop={visibleIndex > 0 ? 1 : 0}\n >\n <Text bold color={SEMANTIC_COLORS.secondary}>\n {currentCategory}\n </Text>\n </Box>,\n )\n }\n\n const isFocused = globalIndex === focusedIndex\n const isSelected = selectedIds?.has(item.id) ?? false\n const itemElement = renderItem ? (\n renderItem(item, isFocused, isSelected)\n ) : (\n <DefaultItemRenderer\n item={item}\n isFocused={isFocused}\n multiSelect={multiSelect}\n isSelected={isSelected}\n />\n )\n\n displayElements.push(<Box key={item.id}>{itemElement}</Box>)\n })\n\n return (\n <Box flexDirection=\"column\">\n {/* Scroll up indicator */}\n {hasMoreAbove && (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}> \u2191 {countAbove} more above...</Text>\n </Box>\n )}\n\n {/* List items */}\n {displayElements}\n\n {/* Scroll down indicator */}\n {hasMoreBelow && (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}> \u2193 {countBelow} more below...</Text>\n </Box>\n )}\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import InkTextInput from "ink-text-input";
|
|
4
|
+
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../../constants/colors.js";
|
|
5
|
+
function SearchInput({
|
|
6
|
+
value,
|
|
7
|
+
onChange,
|
|
8
|
+
placeholder = "Search...",
|
|
9
|
+
isActive
|
|
10
|
+
}) {
|
|
11
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: isActive ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim }, "/"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " "), isActive ? /* @__PURE__ */ React.createElement(
|
|
12
|
+
InkTextInput,
|
|
13
|
+
{
|
|
14
|
+
value,
|
|
15
|
+
onChange,
|
|
16
|
+
placeholder
|
|
17
|
+
}
|
|
18
|
+
) : /* @__PURE__ */ React.createElement(Text, { color: value ? SEMANTIC_COLORS.secondary : SEMANTIC_COLORS.dim }, value || placeholder));
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
SearchInput
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=SearchInput.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/TabbedListView/SearchInput.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * SearchInput Component\n *\n * A styled search input with search icon.\n * Uses inline style matching the overall design.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport InkTextInput from 'ink-text-input'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport type { SearchInputProps } from './types'\n\nexport function SearchInput({\n value,\n onChange,\n placeholder = 'Search...',\n isActive,\n}: SearchInputProps) {\n return (\n <Box>\n <Text color={isActive ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim}>\n /\n </Text>\n <Text color={SEMANTIC_COLORS.dim}> </Text>\n {isActive ? (\n <InkTextInput\n value={value}\n onChange={onChange}\n placeholder={placeholder}\n />\n ) : (\n <Text color={value ? SEMANTIC_COLORS.secondary : SEMANTIC_COLORS.dim}>\n {value || placeholder}\n </Text>\n )}\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "AAOA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,OAAO,kBAAkB;AACzB,SAAS,gBAAgB,uBAAuB;AAGzC,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AACF,GAAqB;AACnB,SACE,oCAAC,WACC,oCAAC,QAAK,OAAO,WAAW,eAAe,QAAQ,gBAAgB,OAAK,GAEpE,GACA,oCAAC,QAAK,OAAO,gBAAgB,OAAK,GAAC,GAClC,WACC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF,IAEA,oCAAC,QAAK,OAAO,QAAQ,gBAAgB,YAAY,gBAAgB,OAC9D,SAAS,WACZ,CAEJ;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../../constants/colors.js";
|
|
4
|
+
function TabBar({ tabs, activeTab, onTabChange }) {
|
|
5
|
+
return /* @__PURE__ */ React.createElement(Box, null, tabs.map((tab, index) => {
|
|
6
|
+
const isActive = tab.id === activeTab;
|
|
7
|
+
const isLast = index === tabs.length - 1;
|
|
8
|
+
return /* @__PURE__ */ React.createElement(Box, { key: tab.id }, isActive ? (
|
|
9
|
+
// Active tab: background highlight with brand color
|
|
10
|
+
/* @__PURE__ */ React.createElement(Text, { backgroundColor: BRAND_GRADIENT.START, color: "black", bold: true }, " ", tab.label, tab.badge !== void 0 && tab.badge > 0 ? ` (${tab.badge})` : "", " ")
|
|
11
|
+
) : (
|
|
12
|
+
// Inactive tab: dim text
|
|
13
|
+
/* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", tab.label, tab.badge !== void 0 && tab.badge > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " (", tab.badge, ")"), " ")
|
|
14
|
+
), !isLast && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, "\u2502"));
|
|
15
|
+
}), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " Tab/\u2190\u2192"));
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
TabBar
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=TabBar.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/TabbedListView/TabBar.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * TabBar Component\n *\n * Displays tab navigation matching the brand style.\n * Uses background color for active tab selection.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport type { TabBarProps } from './types'\n\nexport function TabBar({ tabs, activeTab, onTabChange }: TabBarProps) {\n return (\n <Box>\n {tabs.map((tab, index) => {\n const isActive = tab.id === activeTab\n const isLast = index === tabs.length - 1\n\n return (\n <Box key={tab.id}>\n {isActive ? (\n // Active tab: background highlight with brand color\n <Text backgroundColor={BRAND_GRADIENT.START} color=\"black\" bold>\n {' '}\n {tab.label}\n {tab.badge !== undefined && tab.badge > 0\n ? ` (${tab.badge})`\n : ''}{' '}\n </Text>\n ) : (\n // Inactive tab: dim text\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n {tab.label}\n {tab.badge !== undefined && tab.badge > 0 && (\n <Text color={SEMANTIC_COLORS.muted}> ({tab.badge})</Text>\n )}{' '}\n </Text>\n )}\n {!isLast && <Text color={SEMANTIC_COLORS.muted}>\u2502</Text>}\n </Box>\n )\n })}\n <Text color={SEMANTIC_COLORS.muted}> Tab/\u2190\u2192</Text>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "AAOA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB,uBAAuB;AAGzC,SAAS,OAAO,EAAE,MAAM,WAAW,YAAY,GAAgB;AACpE,SACE,oCAAC,WACE,KAAK,IAAI,CAAC,KAAK,UAAU;AACxB,UAAM,WAAW,IAAI,OAAO;AAC5B,UAAM,SAAS,UAAU,KAAK,SAAS;AAEvC,WACE,oCAAC,OAAI,KAAK,IAAI,MACX;AAAA;AAAA,MAEC,oCAAC,QAAK,iBAAiB,eAAe,OAAO,OAAM,SAAQ,MAAI,QAC5D,KACA,IAAI,OACJ,IAAI,UAAU,UAAa,IAAI,QAAQ,IACpC,KAAK,IAAI,KAAK,MACd,IAAI,GACV;AAAA;AAAA;AAAA,MAGA,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,KACA,IAAI,OACJ,IAAI,UAAU,UAAa,IAAI,QAAQ,KACtC,oCAAC,QAAK,OAAO,gBAAgB,SAAO,MAAG,IAAI,OAAM,GAAC,GACjD,GACL;AAAA,OAED,CAAC,UAAU,oCAAC,QAAK,OAAO,gBAAgB,SAAO,QAAC,CACnD;AAAA,EAEJ,CAAC,GACD,oCAAC,QAAK,OAAO,gBAAgB,SAAO,mBAAO,CAC7C;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import React, { useState, useCallback, useMemo } from "react";
|
|
2
|
+
import { Box, Text, useInput } from "ink";
|
|
3
|
+
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../../constants/colors.js";
|
|
4
|
+
import { TabBar } from "./TabBar.js";
|
|
5
|
+
import { SearchInput } from "./SearchInput.js";
|
|
6
|
+
import { ScrollableList } from "./ScrollableList.js";
|
|
7
|
+
import { SimpleSpinner } from "../Spinner.js";
|
|
8
|
+
import { StatusOverlayContent } from "../StatusOverlayContent.js";
|
|
9
|
+
import { useTerminalSize } from "../../hooks/useTerminalSize.js";
|
|
10
|
+
const PROMPT_HEIGHT = 5;
|
|
11
|
+
const CHROME_HEIGHT = 6;
|
|
12
|
+
function TabbedListView({
|
|
13
|
+
title,
|
|
14
|
+
tabs,
|
|
15
|
+
activeTab,
|
|
16
|
+
onTabChange,
|
|
17
|
+
items,
|
|
18
|
+
searchEnabled = true,
|
|
19
|
+
searchPlaceholder = "Search...",
|
|
20
|
+
searchQuery = "",
|
|
21
|
+
onSearchChange,
|
|
22
|
+
onSearchSubmit,
|
|
23
|
+
onSelect,
|
|
24
|
+
onClose,
|
|
25
|
+
onBack,
|
|
26
|
+
footerHint,
|
|
27
|
+
isLoading = false,
|
|
28
|
+
loadingText = "Loading...",
|
|
29
|
+
emptyText = "No items found",
|
|
30
|
+
groupByCategory = false,
|
|
31
|
+
renderItem,
|
|
32
|
+
statusOverlay,
|
|
33
|
+
isActive = true,
|
|
34
|
+
showItemCount = true,
|
|
35
|
+
statusDismissHint,
|
|
36
|
+
multiSelect,
|
|
37
|
+
selectedIds,
|
|
38
|
+
onSelectionChange,
|
|
39
|
+
onMultiSelect,
|
|
40
|
+
multiSelectActionLabel
|
|
41
|
+
}) {
|
|
42
|
+
const { rows } = useTerminalSize();
|
|
43
|
+
const visibleCount = Math.min(
|
|
44
|
+
8,
|
|
45
|
+
Math.max(3, rows - PROMPT_HEIGHT - CHROME_HEIGHT)
|
|
46
|
+
);
|
|
47
|
+
const [focusArea, setFocusArea] = useState(
|
|
48
|
+
searchEnabled ? "search" : "list"
|
|
49
|
+
);
|
|
50
|
+
const [focusedIndex, setFocusedIndex] = useState(0);
|
|
51
|
+
const filteredItems = useMemo(() => {
|
|
52
|
+
if (!searchQuery.trim()) return items;
|
|
53
|
+
const query = searchQuery.toLowerCase();
|
|
54
|
+
return items.filter(
|
|
55
|
+
(item) => item.label.toLowerCase().includes(query) || item.description?.toLowerCase().includes(query) || item.category?.toLowerCase().includes(query)
|
|
56
|
+
);
|
|
57
|
+
}, [items, searchQuery]);
|
|
58
|
+
React.useEffect(() => {
|
|
59
|
+
setFocusedIndex(0);
|
|
60
|
+
}, [filteredItems.length, activeTab]);
|
|
61
|
+
const cycleTab = useCallback(
|
|
62
|
+
(direction) => {
|
|
63
|
+
const currentIndex = tabs.findIndex((t) => t.id === activeTab);
|
|
64
|
+
let newIndex;
|
|
65
|
+
if (direction === "right") {
|
|
66
|
+
newIndex = (currentIndex + 1) % tabs.length;
|
|
67
|
+
} else {
|
|
68
|
+
newIndex = currentIndex - 1 < 0 ? tabs.length - 1 : currentIndex - 1;
|
|
69
|
+
}
|
|
70
|
+
onTabChange(tabs[newIndex].id);
|
|
71
|
+
},
|
|
72
|
+
[tabs, activeTab, onTabChange]
|
|
73
|
+
);
|
|
74
|
+
const handleSelect = useCallback(
|
|
75
|
+
(item) => {
|
|
76
|
+
if (onSelect) {
|
|
77
|
+
onSelect(item);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
[onSelect]
|
|
81
|
+
);
|
|
82
|
+
useInput(
|
|
83
|
+
(input, key) => {
|
|
84
|
+
if (statusOverlay && statusOverlay.type !== "loading") {
|
|
85
|
+
if (key.escape || key.return) {
|
|
86
|
+
onClose();
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (statusOverlay) return;
|
|
91
|
+
if (key.escape) {
|
|
92
|
+
if (onBack) {
|
|
93
|
+
onBack();
|
|
94
|
+
} else {
|
|
95
|
+
onClose();
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (key.tab) {
|
|
100
|
+
cycleTab(key.shift ? "left" : "right");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (focusArea === "tabs" || focusArea === "search") {
|
|
104
|
+
if (key.leftArrow) {
|
|
105
|
+
cycleTab("left");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (key.rightArrow) {
|
|
109
|
+
cycleTab("right");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (key.downArrow) {
|
|
114
|
+
if (focusArea === "search") {
|
|
115
|
+
setFocusArea("list");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (focusArea === "list" && filteredItems.length > 0) {
|
|
119
|
+
setFocusedIndex(
|
|
120
|
+
(prev) => prev < filteredItems.length - 1 ? prev + 1 : prev
|
|
121
|
+
);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (key.upArrow) {
|
|
126
|
+
if (focusArea === "list") {
|
|
127
|
+
if (focusedIndex > 0) {
|
|
128
|
+
setFocusedIndex((prev) => prev - 1);
|
|
129
|
+
} else if (searchEnabled) {
|
|
130
|
+
setFocusArea("search");
|
|
131
|
+
}
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (key.return && focusArea === "search" && onSearchSubmit) {
|
|
136
|
+
onSearchSubmit(searchQuery);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (input === " " && multiSelect && focusArea === "list" && filteredItems.length > 0) {
|
|
140
|
+
const item = filteredItems[focusedIndex];
|
|
141
|
+
if (item && onSelectionChange) {
|
|
142
|
+
const isCurrentlySelected = selectedIds?.has(item.id) ?? false;
|
|
143
|
+
onSelectionChange(item.id, !isCurrentlySelected);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (input === "a" && multiSelect && focusArea === "list" && filteredItems.length > 0) {
|
|
148
|
+
if (onSelectionChange) {
|
|
149
|
+
const allSelected = filteredItems.every(
|
|
150
|
+
(item) => selectedIds?.has(item.id)
|
|
151
|
+
);
|
|
152
|
+
for (const item of filteredItems) {
|
|
153
|
+
onSelectionChange(item.id, !allSelected);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (key.return && focusArea === "list" && filteredItems.length > 0) {
|
|
159
|
+
if (multiSelect && selectedIds && selectedIds.size > 0 && onMultiSelect) {
|
|
160
|
+
const selectedItems = filteredItems.filter(
|
|
161
|
+
(item) => selectedIds.has(item.id)
|
|
162
|
+
);
|
|
163
|
+
if (selectedItems.length > 0) {
|
|
164
|
+
onMultiSelect(selectedItems);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
handleSelect(filteredItems[focusedIndex]);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (input === "/" && searchEnabled && focusArea !== "search") {
|
|
172
|
+
setFocusArea("search");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
{ isActive }
|
|
177
|
+
);
|
|
178
|
+
const defaultHint = "\u2191\u2193 Navigate \xB7 Enter Select \xB7 Tab/\u2190\u2192 Switch \xB7 Esc Close";
|
|
179
|
+
const multiSelectHint = "\u2191\u2193 Navigate \xB7 Space Select \xB7 a All \xB7 Enter Action \xB7 Tab Switch \xB7 Esc Close";
|
|
180
|
+
const displayHint = statusOverlay ? statusOverlay.type === "loading" ? "" : statusDismissHint || "Esc Close" : multiSelect ? selectedIds && selectedIds.size > 0 && multiSelectActionLabel ? `${multiSelectActionLabel} \xB7 ${footerHint || multiSelectHint}` : footerHint || multiSelectHint : footerHint || defaultHint;
|
|
181
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React.createElement(
|
|
182
|
+
Box,
|
|
183
|
+
{
|
|
184
|
+
borderTop: true,
|
|
185
|
+
borderBottom: false,
|
|
186
|
+
borderLeft: false,
|
|
187
|
+
borderRight: false,
|
|
188
|
+
borderColor: BRAND_GRADIENT.START,
|
|
189
|
+
borderStyle: "single",
|
|
190
|
+
width: "100%",
|
|
191
|
+
paddingX: 1,
|
|
192
|
+
flexDirection: "column"
|
|
193
|
+
},
|
|
194
|
+
/* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "\u25C6"), /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, " ", title), showItemCount && !statusOverlay && filteredItems.length > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " (", filteredItems.length, ")")),
|
|
195
|
+
/* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(TabBar, { tabs, activeTab, onTabChange }))
|
|
196
|
+
), /* @__PURE__ */ React.createElement(
|
|
197
|
+
Box,
|
|
198
|
+
{
|
|
199
|
+
flexDirection: "column",
|
|
200
|
+
borderTop: false,
|
|
201
|
+
borderBottom: true,
|
|
202
|
+
borderLeft: false,
|
|
203
|
+
borderRight: false,
|
|
204
|
+
borderColor: BRAND_GRADIENT.START,
|
|
205
|
+
borderStyle: "single",
|
|
206
|
+
width: "100%",
|
|
207
|
+
paddingX: 1,
|
|
208
|
+
paddingY: 1
|
|
209
|
+
},
|
|
210
|
+
searchEnabled && !statusOverlay && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
211
|
+
SearchInput,
|
|
212
|
+
{
|
|
213
|
+
value: searchQuery,
|
|
214
|
+
onChange: onSearchChange || (() => {
|
|
215
|
+
}),
|
|
216
|
+
placeholder: searchPlaceholder,
|
|
217
|
+
isActive: focusArea === "search"
|
|
218
|
+
}
|
|
219
|
+
)),
|
|
220
|
+
/* @__PURE__ */ React.createElement(Box, { key: `content-${activeTab}`, flexDirection: "column" }, statusOverlay ? /* @__PURE__ */ React.createElement(
|
|
221
|
+
StatusOverlayContent,
|
|
222
|
+
{
|
|
223
|
+
type: statusOverlay.type,
|
|
224
|
+
message: statusOverlay.message
|
|
225
|
+
}
|
|
226
|
+
) : isLoading ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(SimpleSpinner, null), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", loadingText)) : filteredItems.length === 0 ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, emptyText)) : /* @__PURE__ */ React.createElement(
|
|
227
|
+
ScrollableList,
|
|
228
|
+
{
|
|
229
|
+
items: filteredItems,
|
|
230
|
+
focusedIndex,
|
|
231
|
+
onFocusChange: setFocusedIndex,
|
|
232
|
+
onSelect: handleSelect,
|
|
233
|
+
visibleCount,
|
|
234
|
+
groupByCategory,
|
|
235
|
+
renderItem,
|
|
236
|
+
multiSelect,
|
|
237
|
+
selectedIds
|
|
238
|
+
}
|
|
239
|
+
)),
|
|
240
|
+
displayHint && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, displayHint))
|
|
241
|
+
));
|
|
242
|
+
}
|
|
243
|
+
export {
|
|
244
|
+
TabbedListView
|
|
245
|
+
};
|
|
246
|
+
//# sourceMappingURL=TabbedListView.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/TabbedListView/TabbedListView.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * TabbedListView Component\n *\n * A reusable component matching the /command suggestion UI pattern:\n * - Tab navigation (\u2190/\u2192 or Tab key)\n * - Search input (/ to focus)\n * - Scrollable list with \u25C6 selection indicator\n * - Brand gradient colors for selection\n * - Consistent height control (MAX_VISIBLE = 8)\n * - Status overlay for loading/success/error states (maintains frame)\n * - Back navigation support (onBack)\n *\n * Based on Claude Code CLI's /plugins UI pattern.\n */\n\nimport React, { useState, useCallback, useMemo } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { TabBar } from './TabBar'\nimport { SearchInput } from './SearchInput'\nimport { ScrollableList } from './ScrollableList'\nimport { SimpleSpinner } from '@components/Spinner'\nimport { StatusOverlayContent } from '@components/StatusOverlayContent'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport type { TabbedListViewProps, ListItem } from './types'\n\ntype FocusArea = 'tabs' | 'search' | 'list'\n\n// Heights for dynamic visible count calculation\nconst PROMPT_HEIGHT = 5 // PromptInput borders + input + hints\nconst CHROME_HEIGHT = 6 // title + tabs + search + footer + borders\n\nexport function TabbedListView({\n title,\n tabs,\n activeTab,\n onTabChange,\n items,\n searchEnabled = true,\n searchPlaceholder = 'Search...',\n searchQuery = '',\n onSearchChange,\n onSearchSubmit,\n onSelect,\n onClose,\n onBack,\n footerHint,\n isLoading = false,\n loadingText = 'Loading...',\n emptyText = 'No items found',\n groupByCategory = false,\n renderItem,\n statusOverlay,\n isActive = true,\n showItemCount = true,\n statusDismissHint,\n multiSelect,\n selectedIds,\n onSelectionChange,\n onMultiSelect,\n multiSelectActionLabel,\n}: TabbedListViewProps) {\n // Dynamic visible count based on terminal height\n const { rows } = useTerminalSize()\n const visibleCount = Math.min(\n 8,\n Math.max(3, rows - PROMPT_HEIGHT - CHROME_HEIGHT),\n )\n\n // Focus state: which area is currently active\n const [focusArea, setFocusArea] = useState<FocusArea>(\n searchEnabled ? 'search' : 'list',\n )\n\n // Index of focused item in the list\n const [focusedIndex, setFocusedIndex] = useState(0)\n\n // Filter items based on search query\n const filteredItems = useMemo(() => {\n if (!searchQuery.trim()) return items\n\n const query = searchQuery.toLowerCase()\n return items.filter(\n item =>\n item.label.toLowerCase().includes(query) ||\n item.description?.toLowerCase().includes(query) ||\n item.category?.toLowerCase().includes(query),\n )\n }, [items, searchQuery])\n\n // Reset focus index when items change\n React.useEffect(() => {\n setFocusedIndex(0)\n }, [filteredItems.length, activeTab])\n\n // Handle tab cycling\n const cycleTab = useCallback(\n (direction: 'left' | 'right') => {\n const currentIndex = tabs.findIndex(t => t.id === activeTab)\n let newIndex: number\n\n if (direction === 'right') {\n newIndex = (currentIndex + 1) % tabs.length\n } else {\n newIndex = currentIndex - 1 < 0 ? tabs.length - 1 : currentIndex - 1\n }\n\n onTabChange(tabs[newIndex].id)\n },\n [tabs, activeTab, onTabChange],\n )\n\n // Handle item selection\n const handleSelect = useCallback(\n (item: ListItem) => {\n if (onSelect) {\n onSelect(item)\n }\n },\n [onSelect],\n )\n\n // Keyboard input handling\n useInput(\n (input, key) => {\n // Status overlay: success/error \u2192 ESC/Enter closes\n if (statusOverlay && statusOverlay.type !== 'loading') {\n if (key.escape || key.return) {\n onClose()\n }\n return\n }\n\n // Status overlay: loading \u2192 ignore all input\n if (statusOverlay) return\n\n // Escape: onBack if provided, else onClose\n if (key.escape) {\n if (onBack) {\n onBack()\n } else {\n onClose()\n }\n return\n }\n\n // Tab key cycles through tabs\n if (key.tab) {\n cycleTab(key.shift ? 'left' : 'right')\n return\n }\n\n // Left/Right arrows for tab navigation when in tabs or search area\n if (focusArea === 'tabs' || focusArea === 'search') {\n if (key.leftArrow) {\n cycleTab('left')\n return\n }\n if (key.rightArrow) {\n cycleTab('right')\n return\n }\n }\n\n // Handle focus area navigation\n if (key.downArrow) {\n if (focusArea === 'search') {\n setFocusArea('list')\n return\n }\n if (focusArea === 'list' && filteredItems.length > 0) {\n setFocusedIndex(prev =>\n prev < filteredItems.length - 1 ? prev + 1 : prev,\n )\n return\n }\n }\n\n if (key.upArrow) {\n if (focusArea === 'list') {\n if (focusedIndex > 0) {\n setFocusedIndex(prev => prev - 1)\n } else if (searchEnabled) {\n setFocusArea('search')\n }\n return\n }\n }\n\n // Enter in search: submit if onSearchSubmit provided\n if (key.return && focusArea === 'search' && onSearchSubmit) {\n onSearchSubmit(searchQuery)\n return\n }\n\n // Space: toggle selection in multi-select mode\n if (\n input === ' ' &&\n multiSelect &&\n focusArea === 'list' &&\n filteredItems.length > 0\n ) {\n const item = filteredItems[focusedIndex]\n if (item && onSelectionChange) {\n const isCurrentlySelected = selectedIds?.has(item.id) ?? false\n onSelectionChange(item.id, !isCurrentlySelected)\n }\n return\n }\n\n // 'a': toggle select-all / deselect-all in multi-select mode\n if (\n input === 'a' &&\n multiSelect &&\n focusArea === 'list' &&\n filteredItems.length > 0\n ) {\n if (onSelectionChange) {\n const allSelected = filteredItems.every(item =>\n selectedIds?.has(item.id),\n )\n for (const item of filteredItems) {\n onSelectionChange(item.id, !allSelected)\n }\n }\n return\n }\n\n // Enter: batch action if multi-select has selections, otherwise single select\n if (key.return && focusArea === 'list' && filteredItems.length > 0) {\n if (\n multiSelect &&\n selectedIds &&\n selectedIds.size > 0 &&\n onMultiSelect\n ) {\n const selectedItems = filteredItems.filter(item =>\n selectedIds.has(item.id),\n )\n if (selectedItems.length > 0) {\n onMultiSelect(selectedItems)\n return\n }\n }\n handleSelect(filteredItems[focusedIndex])\n return\n }\n\n // '/' to focus search\n if (input === '/' && searchEnabled && focusArea !== 'search') {\n setFocusArea('search')\n return\n }\n },\n { isActive },\n )\n\n // Build footer hint based on current state\n const defaultHint = '\u2191\u2193 Navigate \u00B7 Enter Select \u00B7 Tab/\u2190\u2192 Switch \u00B7 Esc Close'\n const multiSelectHint =\n '\u2191\u2193 Navigate \u00B7 Space Select \u00B7 a All \u00B7 Enter Action \u00B7 Tab Switch \u00B7 Esc Close'\n const displayHint = statusOverlay\n ? statusOverlay.type === 'loading'\n ? ''\n : statusDismissHint || 'Esc Close'\n : multiSelect\n ? selectedIds && selectedIds.size > 0 && multiSelectActionLabel\n ? `${multiSelectActionLabel} \u00B7 ${footerHint || multiSelectHint}`\n : footerHint || multiSelectHint\n : footerHint || defaultHint\n\n return (\n <Box flexDirection=\"column\" width=\"100%\">\n {/* Header bar with top border - mimics PromptInput separator */}\n <Box\n borderTop={true}\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n flexDirection=\"column\"\n >\n {/* Title with brand color */}\n <Box>\n <Text color={BRAND_GRADIENT.START}>\u25C6</Text>\n <Text bold color={SEMANTIC_COLORS.secondary}>\n {' '}\n {title}\n </Text>\n {showItemCount && !statusOverlay && filteredItems.length > 0 && (\n <Text color={SEMANTIC_COLORS.dim}> ({filteredItems.length})</Text>\n )}\n </Box>\n\n {/* Tab Bar - left aligned */}\n <Box marginTop={1}>\n <TabBar tabs={tabs} activeTab={activeTab} onTabChange={onTabChange} />\n </Box>\n </Box>\n\n {/* Content container with bottom border */}\n <Box\n flexDirection=\"column\"\n borderTop={false}\n borderBottom={true}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n paddingY={1}\n >\n {/* Search Input - hidden during status overlay */}\n {searchEnabled && !statusOverlay && (\n <Box marginBottom={1}>\n <SearchInput\n value={searchQuery}\n onChange={onSearchChange || (() => {})}\n placeholder={searchPlaceholder}\n isActive={focusArea === 'search'}\n />\n </Box>\n )}\n\n {/* Content Area - key forces re-render on tab change */}\n <Box key={`content-${activeTab}`} flexDirection=\"column\">\n {statusOverlay ? (\n <StatusOverlayContent\n type={statusOverlay.type}\n message={statusOverlay.message}\n />\n ) : isLoading ? (\n <Box>\n <SimpleSpinner />\n <Text color={SEMANTIC_COLORS.dim}> {loadingText}</Text>\n </Box>\n ) : filteredItems.length === 0 ? (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}>{emptyText}</Text>\n </Box>\n ) : (\n <ScrollableList\n items={filteredItems}\n focusedIndex={focusedIndex}\n onFocusChange={setFocusedIndex}\n onSelect={handleSelect}\n visibleCount={visibleCount}\n groupByCategory={groupByCategory}\n renderItem={renderItem}\n multiSelect={multiSelect}\n selectedIds={selectedIds}\n />\n )}\n </Box>\n\n {/* Footer Hint - compact style */}\n {displayHint && (\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.muted}>{displayHint}</Text>\n </Box>\n )}\n </Box>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TabbedListView } from "./TabbedListView.js";
|
|
2
|
+
import { TabBar } from "./TabBar.js";
|
|
3
|
+
import { SearchInput } from "./SearchInput.js";
|
|
4
|
+
import { ScrollableList } from "./ScrollableList.js";
|
|
5
|
+
export {
|
|
6
|
+
ScrollableList,
|
|
7
|
+
SearchInput,
|
|
8
|
+
TabBar,
|
|
9
|
+
TabbedListView
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/TabbedListView/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * TabbedListView Component Exports\n *\n * A reusable tabbed list view component based on Claude Code CLI's /plugins pattern.\n */\n\nexport { TabbedListView } from './TabbedListView'\nexport { TabBar } from './TabBar'\nexport { SearchInput } from './SearchInput'\nexport { ScrollableList } from './ScrollableList'\nexport type {\n TabbedListViewProps,\n TabDefinition,\n ListItem,\n CategoryGroup,\n TabBarProps,\n SearchInputProps,\n ScrollableListProps,\n} from './types'\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,sBAAsB;AAC/B,SAAS,cAAc;AACvB,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|