Claude Code 使用的命令行 UI 库: ink(使用 react 编写命令行界面)

ink 是一个使用 react 编写界面的库。我编写了方便学习 ink 的网站 ink learn

如果在使用的过程中有任何需求或 bug ,可以通过: github.com/wutiange/in... 进行反馈。

1. Text

tsx 复制代码
export default function App() {
    return (
        <>
            <Text color={'green'}>I am green</Text>
            <Text color={'black'} backgroundColor={'white'}>I am black on white</Text>
            <Text color={'#fff'}>I am white</Text>
            <Text bold>I am bold</Text>
            <Text underline>I am underline</Text>
            <Text strikethrough>I am strikethrough</Text>
            <Text inverse>I am inversed</Text>
        </>
    );
}

这是文字相关的设置,包括字体颜色,背景颜色,加粗等等。

  • color 文字颜色,可以是英文单词,也可以是十六进制的颜色值,只能输入 #rgb#rrggbb ,还可以设置 rgb(255, 0, 255)
  • backgroundColor 背景颜色,颜色值跟 color 相同;
  • bold 是否加粗;
  • underline 是否有下划线;
  • strikethrough 是否有删除线;
  • inverse color 是否反转,也就是颜色是否变成背景色;
  • wrap 换行策略

2. Box

Box 主要控制宽高/内外边距/边框等等。

  1. 宽高
tsx 复制代码
const Example = () => (
    <>
        <Box width={4} borderStyle="classic">
            <Text>X</Text>
        </Box>

        <Box height={4} borderStyle="classic">
            <Text>X</Text>
        </Box>
    </>
);

其效果如下:

可以看到加上边框总共宽度和高度是 4 。宽度不指定的情况下是整个终端的宽度。

  1. 内边距
tsx 复制代码
const Example = () => (
    <>
        <Box paddingTop={2} borderStyle="classic"><Text>Top</Text></Box>
        <Box paddingBottom={2} borderStyle="classic"><Text>Bottom</Text></Box>
        <Box paddingLeft={2} borderStyle="classic"><Text>Left</Text></Box>
        <Box paddingRight={2} borderStyle="classic"><Text>Right</Text></Box>
        <Box paddingX={2} borderStyle="classic"><Text>Left and right</Text></Box>
        <Box paddingY={2} borderStyle="classic"><Text>Top and bottom</Text></Box>
        <Box padding={2} borderStyle="classic"><Text>Top, bottom, left and right</Text></Box>
    </>
);

其效果为:

  1. 外边距
tsx 复制代码
const Example = () => (
    <>
        <Box marginTop={2} borderStyle="classic"><Text>Top</Text></Box>
        <Box marginBottom={2} borderStyle="classic"><Text>Bottom</Text></Box>
        <Box marginLeft={2} borderStyle="classic"><Text>Left</Text></Box>
        <Box marginRight={2} borderStyle="classic"><Text>Right</Text></Box>
        <Box marginX={2} borderStyle="classic"><Text>Left and right</Text></Box>
        <Box marginY={2} borderStyle="classic"><Text>Top and bottom</Text></Box>
        <Box margin={2} borderStyle="classic"><Text>Top, bottom, left and right</Text></Box>
    </>
);

其效果为:

  1. 布局

ink 默认是采用 Yoga 进行布局的,默认是水平排列( display 只有两个值 flexnone ):

tsx 复制代码
<Box>
  <Text>A</Text>
  <Text>B</Text>
  <Text>C</Text>
</Box>

其效果为:

我们可以利用 gap 属性来调整它们之间的距离。

tsx 复制代码
<Box gap={2}>
  <Text>A</Text>
  <Text>B</Text>
  <Text>C</Text>
</Box>

其效果:

布局相关的属性同样也是支持的,比如:flexGrow, flexShrink, flexBasis, flexDirection, flexWrap, alignItems, alignSelf, justifyContent

  1. 边框
tsx 复制代码
const Example = () => (
    <>
        <Box flexDirection="column">
            <Box>
                <Box borderStyle="single" marginRight={2}>
                        <Text>single</Text>
                </Box>
                <Box borderStyle="double" marginRight={2}>
                        <Text>double</Text>
                </Box>
                <Box borderStyle="round" marginRight={2}>
                        <Text>round</Text>
                </Box>
                <Box borderStyle="bold">
                        <Text>bold</Text>
                </Box>
            </Box>
            <Box marginTop={1}>
                <Box borderStyle="singleDouble" marginRight={2}>
                        <Text>singleDouble</Text>
                </Box>
                <Box borderStyle="doubleSingle" marginRight={2}>
                        <Text>doubleSingle</Text>
                </Box>
                <Box borderStyle="classic">
                        <Text>classic</Text>
                </Box>
            </Box>
        </Box>

        <Box
            borderStyle={{
                    topLeft: '↘',
                    top: '↓',
                    topRight: '↙',
                    left: '→',
                    bottomLeft: '↗',
                    bottom: '↑',
                    bottomRight: '↖',
                    right: '←'
            }}
        >
            <Text>Custom</Text>
        </Box>
    </>
);

其效果:

也可以给边框设置颜色,也可以不显示某一边的边框。

  1. 背景颜色

我在我的电脑上测试发现是不起作用的。

3. Newline

用于在文本中插入一行或多行换行符,必须在 Text 组件内部使用。

tsx 复制代码
<Text>
  <Text color="green">Hello</Text>
  <Newline />
  <Text color="red">World</Text>
</Text>

其效果为:

4. Spacer

这个用于占位的,相当于 <div style="flex: 1" />

tsx 复制代码
<>
  <Box>
    <Text>Left</Text>
    <Spacer />
    <Text>Right</Text>
  </Box>

  <Box flexDirection="column" height={10}>
    <Text>Top</Text>
    <Spacer />
    <Text>Bottom</Text>
  </Box>
</>

其效果为:

在 web 中还可以使用 marginTop: auto 代替,只不过 ink 目前我看到不支持。

5. Static

用于避免重复渲染的,如果我们使用 .map 的方式,那么每一次渲染列表中的每一个都会重复再次渲染,但是使用 Static 就不会。

tsx 复制代码
import React, {useState, useEffect} from 'react';
import {render, Static, Box, Text} from 'ink';

const Example = () => {
    const [tests, setTests] = useState([]);

    useEffect(() => {
        let completedTests = 0;
        let timer;

        const run = () => {
            // Fake 10 completed tests
            if (completedTests++ < 10) {
                setTests(previousTests => [
                    ...previousTests,
                    {
                        id: previousTests.length,
                        title: `Test #${previousTests.length + 1}`
                    }
                ]);

                timer = setTimeout(run, 100);
            }
        };

        run();

        return () => {
            clearTimeout(timer);
        };
    }, []);

    return (
        <>
            {/* This part will be rendered once to the terminal */}
            <Static items={tests}>
                    {test => (
                            <Box key={test.id}>
                                    <Text color="green">✔ {test.title}</Text>
                            </Box>
                    )}
            </Static>

            {/* This part keeps updating as state changes */}
            <Box marginTop={1}>
                    <Text dimColor>Completed tests: {tests.length}</Text>
            </Box>
        </>
    );
};

render(<Example />);

其效果是每个 100ms 就会出现一个新的项。

使用 Static ,当 Test #1 渲染,下次列表改变了也不会重新渲染这个数据。可以封装组件打印日志来验证。

6. Transform

用于在输出到终端之前经过这个进行转换。

tsx 复制代码
const Example = () => (
    <Transform transform={output => output.toUpperCase()}>
        <Text>Hello World</Text>
    </Transform>
);

其效果为:

7. useInput

用户接收用户的输入。

tsx 复制代码
import React, {useState} from 'react';
import {render, Box, Text, useInput} from 'ink';

const UserInput = () => {
    const [message, setMessage] = useState('按箭头键或按 "q" 试试');

    useInput((input, key) => {
        if (input === 'q') {
                setMessage('收到 "q",这里通常会调用 exit() 结束程序');
                return;
        }

        if (key.leftArrow) {
                setMessage('← Left arrow pressed');
        } else if (key.rightArrow) {
                setMessage('→ Right arrow pressed');
        } else if (key.upArrow) {
                setMessage('↑ Up arrow pressed');
        } else if (key.downArrow) {
                setMessage('↓ Down arrow pressed');
        } else if (key.return) {
                setMessage('⏎ Enter pressed');
        }
    });

    return (
        <Box flexDirection="column">
            <Text color="green">{message}</Text>
            <Text dimColor>按方向键、Enter 或 "q" 观察上面的提示变化</Text>
        </Box>
    );
};

render(<UserInput />);

其中像字母这些通过 input 来拿到,而像 esc , return 等等通过 key 来取到。其中 key 可以取到的值有:

  • leftArrow 左
  • rightArrow 右
  • upArrow 上
  • downArrow 下
  • return Enter 键
  • escape Esc 键
  • ctrl Ctrl 键
  • tab
  • backspace
  • delete
  • pageUp
  • pageDown
  • meta

其他的就到网站进行学习,里面是交互的,可以一边修改代码一边看效果,学习起来更加轻松。

相关推荐
yinuo2 小时前
前端跨页面通讯终极指南⑦:ServiceWorker 用法全解析
前端
1024肥宅2 小时前
JavaScript 性能与优化:数据结构和算法
前端·数据结构·算法
沐风。562 小时前
TypeScript
前端·javascript·typescript
用户47949283569152 小时前
XSS、CSRF、CSP、HttpOnly 全扫盲:前端安全不只是后端的事
前端·后端·面试
O***p6042 小时前
当“前端虚拟化”成为可能:构建下一代 Web 应用的新范式
前端
孤酒独酌2 小时前
一次断网重连引发的「模块加载缓存」攻坚战
前端
jinzeming9992 小时前
Vue3 PDF 预览组件设计与实现分析
前端
编程小Y2 小时前
Vue 3 + Vite
前端·javascript·vue.js
GDAL2 小时前
前端保存用户登录信息 深入全面讲解
前端·状态模式