ink-component-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseInk Component Patterns
Ink组件模式
You are an expert in building terminal UIs with Ink, React for the terminal.
你是使用Ink(终端版React)构建终端UI的专家。
Core Principles
核心原则
- Use functional components with TypeScript for type safety
- Leverage Ink's built-in components (Box, Text, Newline, Spacer)
- Keep components focused and composable
- Use proper prop types and interfaces
- Handle terminal resizing gracefully
- 使用带TypeScript的函数式组件以保证类型安全
- 利用Ink的内置组件(Box、Text、Newline、Spacer)
- 保持组件聚焦且可组合
- 使用正确的属性类型和接口
- 优雅处理终端窗口大小变化
Component Structure
组件结构
Basic Component
基础组件
tsx
import { Box, Text } from 'ink';
import React from 'react';
interface MyComponentProps {
title: string;
items: string[];
}
export const MyComponent: React.FC<MyComponentProps> = ({ title, items }) => {
return (
<Box flexDirection="column">
<Text bold color="cyan">
{title}
</Text>
{items.map((item, index) => (
<Box key={index} marginLeft={2}>
<Text>• {item}</Text>
</Box>
))}
</Box>
);
};tsx
import { Box, Text } from 'ink';
import React from 'react';
interface MyComponentProps {
title: string;
items: string[];
}
export const MyComponent: React.FC<MyComponentProps> = ({ title, items }) => {
return (
<Box flexDirection="column">
<Text bold color="cyan">
{title}
</Text>
{items.map((item, index) => (
<Box key={index} marginLeft={2}>
<Text>• {item}</Text>
</Box>
))}
</Box>
);
};Layout Patterns
布局模式
Vertical Stack
垂直堆叠
tsx
<Box flexDirection="column">
<Text>First item</Text>
<Text>Second item</Text>
</Box>tsx
<Box flexDirection="column">
<Text>First item</Text>
<Text>Second item</Text>
</Box>Horizontal Row
水平行布局
tsx
<Box>
<Text>Left</Text>
<Spacer />
<Text>Right</Text>
</Box>tsx
<Box>
<Text>Left</Text>
<Spacer />
<Text>Right</Text>
</Box>Centered Content
居中内容
tsx
<Box justifyContent="center" alignItems="center" height={10}>
<Text>Centered content</Text>
</Box>tsx
<Box justifyContent="center" alignItems="center" height={10}>
<Text>Centered content</Text>
</Box>Padded Container
带内边距的容器
tsx
<Box padding={1} borderStyle="round" borderColor="cyan">
<Text>Content with border and padding</Text>
</Box>tsx
<Box padding={1} borderStyle="round" borderColor="cyan">
<Text>Content with border and padding</Text>
</Box>Common Patterns
常见模式
List with Icons
带图标列表
tsx
interface ListItem {
icon: string;
label: string;
value: string;
}
const List: React.FC<{ items: ListItem[] }> = ({ items }) => (
<Box flexDirection="column">
{items.map((item, i) => (
<Box key={i}>
<Text color="yellow">{item.icon} </Text>
<Text bold>{item.label}: </Text>
<Text>{item.value}</Text>
</Box>
))}
</Box>
);tsx
interface ListItem {
icon: string;
label: string;
value: string;
}
const List: React.FC<{ items: ListItem[] }> = ({ items }) => (
<Box flexDirection="column">
{items.map((item, i) => (
<Box key={i}>
<Text color="yellow">{item.icon} </Text>
<Text bold>{item.label}: </Text>
<Text>{item.value}</Text>
</Box>
))}
</Box>
);Status Messages
状态消息
tsx
const StatusMessage: React.FC<{ type: 'success' | 'error' | 'warning'; message: string }> = ({
type,
message,
}) => {
const config = {
success: { icon: '✅', color: 'green' },
error: { icon: '❌', color: 'red' },
warning: { icon: '⚠️', color: 'yellow' },
};
const { icon, color } = config[type];
return (
<Box>
<Text color={color}>
{icon} {message}
</Text>
</Box>
);
};tsx
const StatusMessage: React.FC<{ type: 'success' | 'error' | 'warning'; message: string }> = ({
type,
message,
}) => {
const config = {
success: { icon: '✅', color: 'green' },
error: { icon: '❌', color: 'red' },
warning: { icon: '⚠️', color: 'yellow' },
};
const { icon, color } = config[type];
return (
<Box>
<Text color={color}>
{icon} {message}
</Text>
</Box>
);
};Progress Indicator
进度指示器
tsx
const ProgressIndicator: React.FC<{ current: number; total: number; label: string }> = ({
current,
total,
label,
}) => (
<Box>
<Text color="blue">
{label}: {current}/{total}
</Text>
</Box>
);tsx
const ProgressIndicator: React.FC<{ current: number; total: number; label: string }> = ({
current,
total,
label,
}) => (
<Box>
<Text color="blue">
{label}: {current}/{total}
</Text>
</Box>
);Collapsible Section
可折叠区域
tsx
const CollapsibleSection: React.FC<{ title: string; isOpen: boolean; children: React.ReactNode }> = ({
title,
isOpen,
children,
}) => (
<Box flexDirection="column">
<Text bold>
{isOpen ? '▼' : '▶'} {title}
</Text>
{isOpen && <Box marginLeft={2}>{children}</Box>}
</Box>
);tsx
const CollapsibleSection: React.FC<{ title: string; isOpen: boolean; children: React.ReactNode }> = ({
title,
isOpen,
children,
}) => (
<Box flexDirection="column">
<Text bold>
{isOpen ? '▼' : '▶'} {title}
</Text>
{isOpen && <Box marginLeft={2}>{children}</Box>}
</Box>
);Best Practices
最佳实践
- Type Safety: Always define prop interfaces
- Performance: Use React.memo for expensive renders
- Accessibility: Use semantic structure and clear labels
- Error Boundaries: Wrap components in error boundaries
- Testing: Test components with ink-testing-library
- 类型安全:始终定义属性接口
- 性能优化:对开销大的渲染使用React.memo
- 可访问性:使用语义化结构和清晰标签
- 错误边界:用错误边界包裹组件
- 测试:使用ink-testing-library测试组件
Anti-Patterns to Avoid
需避免的反模式
- Don't use DOM-specific APIs (document, window)
- Don't use CSS classes or inline styles (use Ink props)
- Don't mutate terminal state directly
- Don't forget to handle edge cases (empty arrays, null values)
- Don't create deeply nested component trees (keep it flat)
- 不要使用DOM特定API(document、window)
- 不要使用CSS类或内联样式(使用Ink属性)
- 不要直接修改终端状态
- 不要忘记处理边缘情况(空数组、null值)
- 不要创建深度嵌套的组件树(保持扁平化)