ink-component-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Ink 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

最佳实践

  1. Type Safety: Always define prop interfaces
  2. Performance: Use React.memo for expensive renders
  3. Accessibility: Use semantic structure and clear labels
  4. Error Boundaries: Wrap components in error boundaries
  5. Testing: Test components with ink-testing-library
  1. 类型安全:始终定义属性接口
  2. 性能优化:对开销大的渲染使用React.memo
  3. 可访问性:使用语义化结构和清晰标签
  4. 错误边界:用错误边界包裹组件
  5. 测试:使用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值)
  • 不要创建深度嵌套的组件树(保持扁平化)