布局系统

OpenTUI 使用 Yoga 布局引擎提供类似 CSS Flexbox 的能力,用于响应式终端布局。你可以创建适应终端大小变化的复杂动态界面。

Flexbox 基础

布局系统支持标准的 flexbox 属性:

import { BoxRenderable, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

const container = new BoxRenderable(renderer, {
  id: "container",
  flexDirection: "row",
  justifyContent: "space-between",
  alignItems: "center",
  width: "100%",
  height: 10,
})

const leftPanel = new BoxRenderable(renderer, {
  id: "left",
  flexGrow: 1,
  height: 10,
  backgroundColor: "#444",
})

const rightPanel = new BoxRenderable(renderer, {
  id: "right",
  width: 20,
  height: 10,
  backgroundColor: "#666",
})

container.add(leftPanel)
container.add(rightPanel)
renderer.root.add(container)

Flex 方向

控制子元素的方向:

// 垂直布局(默认)
{
  flexDirection: "column"
}

// 水平布局
{
  flexDirection: "row"
}

// 反向
{
  flexDirection: "row-reverse"
}
{
  flexDirection: "column-reverse"
}

主轴对齐(Justify Content)

沿主轴对齐子元素:

{
  justifyContent: "flex-start"
} // 起点对齐
{
  justifyContent: "flex-end"
} // 终点对齐
{
  justifyContent: "center"
} // 居中对齐
{
  justifyContent: "space-between"
} // 均匀间距,两端无间隙
{
  justifyContent: "space-around"
} // 均匀间距,两端有间隙
{
  justifyContent: "space-evenly"
} // 完全均匀间距

交叉轴对齐(Align Items)

沿交叉轴对齐子元素:

{
  alignItems: "flex-start"
} // 起点对齐
{
  alignItems: "flex-end"
} // 终点对齐
{
  alignItems: "center"
} // 交叉轴居中
{
  alignItems: "stretch"
} // 拉伸填充(默认)
{
  alignItems: "baseline"
} // 基线对齐

大小调整

固定大小

{
  width: 30,   // 固定宽度(字符数)
  height: 10,  // 固定高度(行数)
}

百分比大小

{
  width: "100%",  // 父元素的全宽
  height: "50%",  // 父元素高度的一半
}

Flex 增长和收缩

{
  flexGrow: 1,    // 占用可用空间
  flexShrink: 0,  // 不收缩到内容大小以下
  flexBasis: 100, // flex 调整前的初始大小
}

定位

相对定位(默认)

元素在布局中正常流动:

{
  position: "relative",
}

绝对定位

相对于父元素定位元素:

{
  position: "absolute",
  left: 10,
  top: 5,
  right: 10,
  bottom: 5,
}

内边距和外边距

{
  // 统一内边距
  padding: 2,

  // 按轴设置
  paddingX: 4,
  paddingY: 2,

  // 单独设置各边
  paddingTop: 1,
  paddingRight: 2,
  paddingBottom: 1,
  paddingLeft: 2,

  // 外边距同理
  margin: 1,
  marginX: 3,
  marginY: 1,
  marginTop: 1,
  marginRight: 2,
  marginBottom: 1,
  marginLeft: 2,
}

使用 Constructs

相同的布局属性也适用于声明式 API:

import { Box, Text } from "@opentui/core"

renderer.root.add(
  Box(
    {
      flexDirection: "row",
      width: "100%",
      height: 10,
    },
    Box(
      {
        flexGrow: 1,
        backgroundColor: "#333",
        padding: 1,
      },
      Text({ content: "Left Panel" }),
    ),
    Box(
      {
        width: 20,
        backgroundColor: "#555",
        padding: 1,
      },
      Text({ content: "Right Panel" }),
    ),
  ),
)

响应式布局

监听终端大小调整事件以创建响应式布局:

const renderer = await createCliRenderer()

renderer.on("resize", (width, height) => {
  // 根据新尺寸更新布局
  if (width < 80) {
    container.flexDirection = "column"
  } else {
    container.flexDirection = "row"
  }
})