* feat: 第一版大重构 * fix: 修复类型问题 * chore: 更新版本到 1.3.2 * Add brave as alternative WebSearchTool * fix: 修正顺序 * fix: 修复对穷鬼模式的 auto dream 和 session memory 越过 * feat: 穷鬼模式去除 session-summary * feat: 创建 builtin-tools 包,搬运所有工具实现 将 src/tools/ 下的全部 60 个工具目录迁移至 packages/builtin-tools/src/tools/, 内部导入路径已更新为 src/ alias 模式。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: 更新 src/ 中所有工具引用至 builtin-tools 包,删除 src/tools/ - src/tools.ts 及 178 个 src/ 文件的 import 路径从 ./tools/ 改为 builtin-tools/tools/ - 删除 src/tools/ 整个目录(已迁移至 packages/builtin-tools/) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: 添加 builtin-tools 路径别名至 tsconfig,更新 bun.lock - tsconfig.json 新增 builtin-tools/* 和 builtin-tools 路径映射 - 新增 packages/builtin-tools/src 至 include Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: 为 builtin-tools、mcp-client、agent-tools 添加 @claude-code-best 作用域前缀 所有包名及 import 路径统一添加 @claude-code-best/ 前缀: - builtin-tools → @claude-code-best/builtin-tools - mcp-client → @claude-code-best/mcp-client - agent-tools → @claude-code-best/agent-tools Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 修复 node 环境没有 bun 的问题 --------- Co-authored-by: Eric-Guo <eric.guocz@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
8.5 KiB
Chapter 2: Layout System
Ink uses Yoga (Facebook's cross-platform layout engine) to implement CSS Flexbox in the terminal. Every layout is flexbox-based -- there is no CSS Grid or flow layout.
Box Component
Box is the fundamental layout primitive. It is the terminal equivalent of <div style="display: flex">.
import { Box, Text } from '@anthropic/ink'
<Box flexDirection="row" gap={1}>
<Text>Left</Text>
<Text>Right</Text>
</Box>
Box Props (Styles)
All layout props are passed directly as JSX props (no style={} wrapper needed):
Flex Direction
Controls the main axis direction.
<Box flexDirection="row">...</Box> // Left to right (default)
<Box flexDirection="column">...</Box> // Top to bottom
<Box flexDirection="row-reverse">...</Box> // Right to left
<Box flexDirection="column-reverse">...</Box> // Bottom to top
Flex Grow / Shrink / Basis
<Box flexGrow={1}>...</Box> // Grow to fill available space
<Box flexShrink={0}>...</Box> // Don't shrink below intrinsic size
<Box flexBasis={20}>...</Box> // Initial size before flex distribution
<Box flexBasis="50%">...</Box> // Percentage basis
Default values: flexGrow={0}, flexShrink={1}, flexBasis=auto.
Flex Wrap
<Box flexWrap="nowrap">...</Box> // Single line (default)
<Box flexWrap="wrap">...</Box> // Multiple lines
<Box flexWrap="wrap-reverse">...</Box> // Reverse cross-axis stacking
Alignment
<Box alignItems="flex-start">...</Box> // Cross-axis start
<Box alignItems="center">...</Box> // Cross-axis center
<Box alignItems="flex-end">...</Box> // Cross-axis end
<Box alignItems="stretch">...</Box> // Stretch to fill (default)
<Box alignSelf="flex-start">...</Box> // Override parent's alignItems
<Box alignSelf="center">...</Box>
<Box alignSelf="flex-end">...</Box>
<Box alignSelf="auto">...</Box> // Inherit from parent
Justify Content
<Box justifyContent="flex-start">...</Box> // Main-axis start (default)
<Box justifyContent="flex-end">...</Box> // Main-axis end
<Box justifyContent="center">...</Box> // Center
<Box justifyContent="space-between">...</Box> // Equal gaps, no edges
<Box justifyContent="space-around">...</Box> // Equal gaps with edges
<Box justifyContent="space-evenly">...</Box> // Evenly distributed
Gap
Spacing between children (only accepts integers):
<Box gap={1}>...</Box> // Both row and column gap
<Box columnGap={2}>...</Box> // Gap between columns only
<Box rowGap={1}>...</Box> // Gap between rows only
Padding
Inner spacing (only accepts integers):
<Box padding={1}>...</Box> // All sides
<Box paddingX={2}>...</Box> // Left and right
<Box paddingY={1}>...</Box> // Top and bottom
<Box paddingLeft={2}>...</Box> // Left only
<Box paddingRight={2}>...</Box> // Right only
<Box paddingTop={1}>...</Box> // Top only
<Box paddingBottom={1}>...</Box> // Bottom only
Margin
Outer spacing (only accepts integers):
<Box margin={1}>...</Box> // All sides
<Box marginX={2}>...</Box> // Left and right
<Box marginY={1}>...</Box> // Top and bottom
<Box marginLeft={2}>...</Box> // Left only
<Box marginRight={2}>...</Box> // Right only
<Box marginTop={1}>...</Box> // Top only
<Box marginBottom={1}>...</Box> // Bottom only
Note: Fractional values for padding, margin, and gap are not supported. Ink will emit warnings if non-integer values are used.
Width & Height
<Box width={40}>...</Box> // Fixed 40 characters wide
<Box height={10}>...</Box> // Fixed 10 rows tall
<Box width="50%">...</Box> // 50% of parent's width
<Box width="100%">...</Box> // Full parent width
Min/Max Dimensions
<Box minWidth={20}>...</Box>
<Box maxWidth={80}>...</Box>
<Box minHeight={5}>...</Box>
<Box maxHeight={20}>...</Box>
Percentage values are supported: minWidth="30%".
Position
<Box position="absolute" top={0} right={0}>...</Box>
<Box position="absolute" top="10%" left="20%">...</Box>
<Box position="relative">...</Box> // Default
Position absolute removes the element from normal flow and positions it relative to its nearest positioned ancestor. Useful for overlays.
Display
<Box display="flex">...</Box> // Visible (default)
<Box display="none">...</Box> // Hidden (removed from layout)
Border
<Box borderStyle="single">...</Box> // Thin border
<Box borderStyle="double">...</Box> // Double-line border
<Box borderStyle="round">...</Box> // Rounded corners
<Box borderStyle="bold">...</Box> // Bold border
<Box borderStyle="singleDouble">...</Box> // Mixed
<Box borderStyle="doubleSingle">...</Box> // Mixed
<Box borderStyle="classic">...</Box> // ASCII art border
Control individual sides and colors:
<Box
borderStyle="single"
borderTop={false} // Hide top border
borderBottom={true} // Show bottom border
borderColor="rgb(255,0,0)" // Red border
borderDimColor={true} // Dim the border
>
...
</Box>
Per-side colors:
<Box
borderStyle="single"
borderTopColor="rgb(255,0,0)"
borderBottomColor="ansi:green"
borderLeftColor="#0000FF"
borderRightColor="ansi256(200)"
/>
Border text (labels in the border):
<Box
borderStyle="round"
borderText={{ title: "My Panel", align: "left" }}
/>
Background
<Box backgroundColor="rgb(40,40,40)">...</Box>
Overflow
<Box overflow="visible">...</Box> // Content expands container (default)
<Box overflow="hidden">...</Box> // Clip without scrolling
<Box overflow="scroll">...</Box> // Enable scrolling (use ScrollBox)
overflowX and overflowY control each axis independently.
Opaque
<Box opaque={true}>...</Box>
Fills the box interior with spaces (using terminal's default background) before rendering children. Useful for absolute-positioned overlays where gaps would otherwise be transparent.
NoSelect
<Box noSelect={true}>...</Box> // Exclude from text selection
<Box noSelect="from-left-edge">...</Box> // Exclude from column 0 to box edge
Only affects alt-screen text selection. Useful for gutters (line numbers, diff markers).
Spacer
Spacer fills all available space along the main axis (equivalent to flexGrow: 1).
<Box flexDirection="row">
<Text>Left</Text>
<Spacer />
<Text>Right</Text>
</Box>
Newline
Inserts line breaks.
<Text>
Line 1
<Newline />
Line 2
<Newline count={2} />
Line 4 (after double break)
</Text>
Layout Examples
Two-column layout
<Box flexDirection="row" width={80}>
<Box width="50%" padding={1}>
<Text>Left column</Text>
</Box>
<Box width="50%" padding={1}>
<Text>Right column</Text>
</Box>
</Box>
Centered content
<Box justifyContent="center" alignItems="center" height={20}>
<Text>Centered!</Text>
</Box>
Sticky footer
<Box flexDirection="column" height={24}>
<Box flexGrow={1}>
<Text>Scrollable content area</Text>
</Box>
<Box>
<Text>Status bar at bottom</Text>
</Box>
</Box>
Bordered panel with title
<Box
flexDirection="column"
borderStyle="round"
borderColor="rgb(87,105,247)"
padding={1}
width={60}
>
<Text bold>Panel Title</Text>
<Text>Panel content goes here.</Text>
</Box>
NoSelect
Wraps a region to exclude it from text selection in alt-screen mode. A convenience wrapper around Box with noSelect set.
import { NoSelect } from '@anthropic/ink'
<Box flexDirection="row">
<NoSelect>
<Text dimColor>1 │ </Text>
</NoSelect>
<Text>selectable code here</Text>
</Box>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
children |
ReactNode |
- | Content |
fromLeftEdge |
boolean |
false |
Extend exclusion from column 0 to box's right edge |
Accepts all BoxProps except noSelect.
BaseBox vs ThemedBox
Two versions of Box are exported:
BaseBox(imported asBaseBox) -- Raw box, color props accept only rawColorvaluesBox(themed, imported asBox) -- Theme-aware, color props acceptkeyof Theme | Color
// Raw
<BaseBox borderStyle="single" borderColor="rgb(255,0,0)" />
// Theme-aware (resolves 'permission' to the current theme's blue)
<Box borderStyle="single" borderColor="permission" />