Astryx 布局原语家族契约:Stack、Grid、Center 与共享空间词汇表
【免费下载链接】astryxAn open source design system that's fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx
导读
布局原语(layout primitives)是任何设计系统里最高频、最容易被各业务团队各自为政的部分。Astryx 通过一份 family contract 文档(docs/families/layout-primitives.md)将 Stack、HStack、VStack、StackItem、Grid、GridSpan、Center 七个成员收敛为"同一个小词汇表":选择 Stack、Grid 或 Center 只改变排列模型,而间距刻度、尺寸语义、对齐方向、padding 优先级这些共享概念在家族内保持唯一含义。本文以这份契约为骨架,结合 packages/core/src 下的真实实现与测试,讲解每个成员的能力边界、共享不变量(FR1–FR9)、允许的组件差异(AV1–AV7),以及一份可直接落地的实战组合方案,帮助你写出风格一致、可维护、可主题化的布局代码。
家族契约的意图:排列模型不同,词汇表唯一
契约开宗明义地定义了自己的 Intent:开发者应该能用同一种小词汇表来排列任意内容(一维或二维)、居中它、设置布局盒尺寸、表达空间关系。选择 Stack、Grid 还是 Center 改变的是"排列模型"(arrangement model),而不是引入第二套间距刻度或给共享 prop 名赋予新含义。
这一原则落实到组件层面,意味着:
gap、padding、width、height在七个成员间遵循同一套数值语义(SpacingStep/SizeValue);- 轴的语义(main/cross axis)由当前成员的排列模型解析,而不是各组件自行发明;
- "间距刻度"永远只有一套,来自主题 token,而不是每个组件复制一份魔法数字。
从源码看,这一意图被严格执行:Stack 的 gap 样式、Grid 的 gap/rowGap/columnGap 样式都指向同一个spacingVarstoken 表(见 stack.stylex.ts 与 Grid.tsx),数值经过SpacingStep类型约束后映射到--spacing-*变量,而非各写各的像素值。
成员规则与边界:什么算布局原语
成员规则(Membership rule)
契约用"公共职责"(primary public purpose)而非"实现机制"来判定归属:
一个组件属于该家族,当且仅当它的主要公共用途是通过共享的布局原语词汇表排列任意子内容;一个修饰器(modifier)归属于其父组件,当它改变某个子元素在该排列中的参与方式。
成员(Members):
| 成员 | 职责 |
|---|---|
| Stack | 一维排列:方向、换行、主轴/交叉轴对齐 |
| HStack / VStack | Stack 契约的固定方向形式 |
| StackItem | 修改 Stack 中单个子元素的参与方式 |
| Grid | 二维轨道排列:固定列与固有/流式列 |
| GridSpan | 修改 Grid 中单个子元素的行、列跨距 |
| Center | 沿单轴或双轴居中 |
协作者(Collaborators):共享的SpacingStep、SizeValue类型;Stack 与 StackItem 的样式工具函数;padding.stylex.ts;container-padding 架构(docs/architecture/container-padding.md);组件的.doc.mjs主题元数据与运行时themeProps()发射。
明确排除(Excluded):Section、Layout 及其命名区域、Toolbar 拥有的是"结构区域"契约而非本家族的任意子内容排列词汇。Layout 虽是一般用途原语,但其公共模型是五个命名槽位而非不受限的子元素排列;FormLayout 负责字段排列与表单级可选性;AspectRatio 约束单个子元素的盒子而非排列任意子元素;Card 与 Dialog 是表面(surface);AppShell 拥有页面外壳与应用导航组合。
关键判据:一个组件不会仅仅因为源码里用了 flexbox 或 grid 就加入家族。成员资格跟随公共责任,不跟随实现机制。
共享负责人(Shared owner)
契约为每个共享概念指定了唯一负责人,避免多个组件各自解释同一概念:
| 概念 | 负责人 |
|---|---|
| 数字间距词汇表(gap/padding 的取值) | SpacingStep类型 |
| 盒子尺寸契约(数字=像素,字符串=CSS 值) | SizeValue类型 |
| 一维方向、换行、主轴/交叉轴对齐 | Stack(HStack/VStack 为固定方向形式) |
| 固定列与固有/流式轨道构造 | Grid;GridSpan 负责单个子元素的行列参与 |
| 单轴或双轴居中 | Center |
| bleed 几何(container inset 协议) | architecture:container-padding(本地应用 padding 本身不发布该协议) |
核心概念表:七个成员的公共语义
| 概念 | 取值/状态 | 默认语义 | 稳定性 |
|---|---|---|---|
| spacing step | 00.511.523456810 | 受 token 支持的间距值,用于 gap/padding | current |
| box size | 数字或 CSS 值字符串 | 数字按像素处理;字符串原样透传为 CSS 值 | current |
| flow direction | horizontal / vertical | Stack 默认 vertical;HStack/VStack 固定方向 | current |
| alignment | main/cross axis,或物理横/纵别名 | 由当前排列模型解析轴 | current |
| gap | 支持处为 uniform、row、column | 排列项之间的间距,不是容器内边距 | current |
| padding | 支持处为 uniform、axis、logical edge | 成员自身盒子内部的空间 | current |
| item participation | intrinsic、fill、self-aligned、column span、row span | 修饰器改变单个子元素在父排列中的角色 | current |
| responsiveness | intrinsic、wrapping、consumer-authored | 各成员自文档化自己的可用机制 | component-owned |
SpacingStep 的像素映射(见 utils/types.ts):0=0px、0.5=2px、1=4px、1.5=6px、2=8px、3=12px、4=16px、5=20px、6=24px、8=32px、10=40px,分别对应--spacing-0…--spacing-10主题 token。这就是"只有一个间距刻度"的落地形式:无论你在 Stack 还是 Grid 上写gap={4},得到的都是同一个 16px 的 token 值。
SizeValue 契约:type SizeValue = number | string。数字渲染为像素(${width}px),字符串原样透传(如'100%'、'50vh')。Stack 的width/height/maxWidth/minHeight与 Grid、Center 的同名尺寸 prop 全部遵循此契约(见 Stack.tsx 的 sizingStyle 构造)。
跨组件不变量 FR1–FR9:共享语义的硬约束
契约定义了九条跨组件不变量,它们是"共享词汇表"的执法依据:
- FR1 — 共享名字保持共享值语义。任何被类型化为
SpacingStep或SizeValue的成员 prop 都遵循共享的值与强转契约;成员只暴露其排列模型支持的能力。例如 Stack 暴露 gap(一维 spacing),Grid 暴露 gap/rowGap/columnGap(二维 spacing),但都不会突然改变这些 prop 的含义。 - FR2 — 逻辑间距跟随书写方向。inline-start/end 是逻辑边缘,成员不得将其重新解释为固定的 left/right。Center 与 Stack 的 padding 阶梯使用
paddingInlineStart/End、paddingBlockStart/End逻辑属性(见 padding.stylex.ts),RTL 下自动镜像。 - FR3 — padding 优先级按边计算。在拥有完整 padding 阶梯的成员上,显式的边缘值 > 该轴的值 > uniform
padding;覆盖只改变该边。Stack 与 Center 的解析顺序都是edge ?? axis ?? padding(Stack.tsx、Center.tsx)。 - FR4 — gap 与 padding 保持分离。gap 分隔排列项,padding 内缩容器内内容。Grid 的
rowGap/columnGap只覆盖其所在轴的 uniform gap。 - FR5 — 对齐跟随排列模型。Stack 依据方向解析 main/cross 轴;Grid 在轨道中对齐项目;Center 控制哪个轴(或双轴)被居中。当含义不同时,一个成员不得复制另一个成员的 prop。例如 HStack 的
hAlign是主轴(justify-content),而 Stack 的hAlign在 vertical 方向下是交叉轴(align-items)——这正是契约要求"含义必须由排列模型解析"的原因。 - FR6 — 修饰器组件要求其父模型。StackItem 控制 Stack 中的参与;GridSpan 控制 Grid 中的参与。它们各自的组件契约定义了父模型之外的行为。
- FR7 — 响应式行为是显式的。Grid 可能因固有轨道数学而回流;Stack 仅在配置
wrap时换行;Center 不创建断点。家族不承诺共享断点或自动区域切换。 - FR8 — 本地 padding 不是 bleed 信号。Stack 与 Center 当前应用 padding 时不发布容器 inset 几何。后代组件只有在
architecture:container-padding命名的发布者下才能依赖 bleed 补偿。 - FR9 — 公共契约不规定源码结构。组件可以使用成员工具函数,也可以直接用平台布局,只要可观察的 API 与行为保持正确。
成员逐个深入:从 props 到 StyleX 实现
Stack:一维排列的唯一入口
Stack.tsx 是一个统一的一维排列组件,用direction取代了以往 HStack/VStack 各自为政的实现,默认direction="vertical"。核心 props:
<Stack direction="vertical" // 'horizontal' | 'vertical',默认 'vertical' gap={2} // SpacingStep,0–10 hAlign="center" // 主轴对齐(horizontal 下 justify-content) vAlign="stretch" // 交叉轴对齐(horizontal 下 align-items) justify="between" // 主轴别名,镜像 CSS justify-content align="center" // 交叉轴别名,镜像 CSS align-items wrap="wrap" // 'nowrap' | 'wrap' | 'wrap-reverse' padding={4} // SpacingStep paddingInline={3} // 覆盖 padding 的 inline 轴 paddingInlineStart={2} // 覆盖 inline 起始边(逻辑边) width={320} // SizeValue:数字=px height="100%" // SizeValue:字符串原样透传 isScrollable // overflow: auto as="ul" // 多态渲染 > <li>Item</li> </Stack>关键实现细节:
- 对齐映射:
hAlign/vAlign依据direction自动解析到justify-content(主轴)或align-items(交叉轴)。主轴取值'start' | 'center' | 'end' | 'between' | 'around' | 'evenly',交叉轴取值'start' | 'center' | 'end' | 'stretch'(见 stack.stylex.ts)。 - justify/align 别名:
justify镜像 CSSjustify-content、align镜像align-items,与 Tailwind 的justify-*/items-*语义对齐,降低迁移心智负担。 - 尺寸:数字→px、字符串→透传,全部走 inline style。
- 运行时主题发射:组件调用
themeProps('stack', {direction, gap, wrap}),将视觉 prop 反射为data-*属性与稳定类名(见 themeProps.ts 的 kebab-case 转换:direction→data-direction)。
底层样式由stack()工具函数生成(stack.stylex.ts),它接受{direction, crossAlign, mainAlign, gap, wrap}返回 StyleX 样式数组,这也是"实现机制可替换(FR9)"的体现——其他组件可以直接调用stack()而不经过 Stack 组件本身。
HStack / VStack:固定方向的便捷形式
HStack 是 Stack 的极薄包装(HStack.tsx):
export function HStack({ref, justify, align, hAlign, vAlign, ...props}: HStackProps) { return <Stack {...props} direction="horizontal" {.../* 别名映射 */} />; }HStackProps通过Omit<StackProps, 'direction' | 'hAlign' | 'vAlign'>收窄了类型:hAlign收敛为StackMainAlignment(主轴,justify-content),vAlign收敛为StackCrossAlignment(交叉轴,align-items),从类型层面保证固定方向下的合法取值。VStack 同理固定为direction="vertical"。
使用建议:如果方向是"永不改变的布局事实",用 HStack/VStack 让意图自文档化并享受更窄的类型;如果方向可能随响应式策略切换,直接用Stack direction={...}。
StackItem:单个子元素的参与控制
StackItem.tsx 是 Stack 的修饰器,提供两个能力:
<Stack direction="vertical" gap={2}> <StackItem size="static">Logo</StackItem> {/* flexGrow:0, flexShrink:0,固有尺寸 */} <StackItem size="fill">Content</StackItem> {/* flexGrow:1,吃掉剩余空间 */} <StackItem size="fill" isScrollable>Scroll region</StackItem> <StackItem crossAlignSelf="center">Me</StackItem> {/* align-self 覆盖 */} </Stack>底层(stackItem.stylex.ts)有两个值得注意的设计:
- flex min 尺寸重置:
minHeight: 0; minWidth: 0总是被应用。flex 子项隐式min-size: auto,内容多时永不收缩,这个重置让子项可以被 flex 父容器约束并变得可滚动。 size="fill"+isScrollable构成完整滚动区域:fill 提供flexGrow: 1,isScrollable 提供overflow: auto,加上 min 尺寸重置,一个<StackItem size="fill" isScrollable>就能生长填满 Stack 并滚动自身溢出,无需额外样式管道。Stack 的isScrollable文档也明确建议:当 Stack 本身作为 flex 子项需要滚动时,外层配StackItem size="fill" isScrollable(Stack.tsx)。
Grid:固定列与固有/流式轨道
Grid.tsx 提供 CSS Grid 布局,columnsprop 有两种形态:
// 固定等宽列 <Grid columns={3} gap={4}> <div>A</div><div>B</div><div>C</div> </Grid> // 固有/流式列:基于最小子宽度的响应式 <Grid columns={{minWidth: 280}}> {/* auto-fill,宽度一致 */} <Grid columns={{minWidth: 280, repeat: 'fit'}}> {/* auto-fit,折叠空轨 */} <Grid columns={{minWidth: 280, max: 4}}> {/* 上限 4 列,仍有 1fr 弹性 */} // 轴级 gap 覆盖 <Grid columns={3} gap={2} rowGap={3} columnGap={4} /> // 对齐(默认 stretch) <Grid columns={3} align="center" justify="start" /> // 瀑布流式行高 + GridSpan <Grid columns={3} rowHeight={80} gap={3}> <GridSpan rows={4}>Tall</GridSpan> <GridSpan rows={2}>Short</GridSpan> </Grid>值得展开的实现细节:
max上限列数的数学:buildCappedTemplate(Grid.tsx)把上限放在轨道的min尺寸上:每轨至少(100% - (max-1)*gap) / max,因此永远不会超过max列;而轨道 max 保持1fr,所以当实际列数少于上限时(尤其移动端单列),现有列仍会拉伸填满整行——右侧不留死区。轨道 min 是max(minWidth, perColumn)再包一层min(100%, …),保证窄视口下单列收缩到容器而不溢出。- 动态轨道走 CSS 变量而非 inline style:
grid-template-columns: var(--x)通过 StyleX 动态样式生成(Grid.tsx),这样消费方xstyle覆盖——包括@media内的覆盖——仍能生效;原始 inlinegrid-template-columns会压过任何类。 - gap 三件套:
gap同时写 row+column,rowGap/columnGap只覆盖对应轴,且全部映射 spacing token。
GridSpan:行列跨距修饰器
GridSpan.tsx 是 Grid 的修饰器:
<Grid columns={3} gap={4}> <GridSpan columns={2}>Wide</GridSpan> {/* grid-column: span 2 */} <div>Normal</div> <GridSpan columns="full">Full row</GridSpan> {/* grid-column: 1 / -1 */} <GridSpan rows={2}>Tall</GridSpan> {/* grid-row: span 2 */} </Grid>它的基样式自带minWidth: 0(防溢出)、display: grid、height: 100%,让内容填满所跨的格子。themeProps('grid-span')只发射稳定类名,不携带视觉数据。
Center:单轴或双轴居中
Center.tsx 用 flex 实现居中,axisprop 控制居中范围:
<Center width={300} height={200}> {/* 双轴居中 */} <Content /> </Center> <Center axis="horizontal">…</Center> {/* 仅主轴/inline 轴 */} <Center axis="vertical">…</Center> {/* 仅交叉轴/block 轴 */} <Center isInline>💬 文本/图标行内居中</Center> {/* inline-flex */} <Center padding={4}>…</Center> {/* 与 Stack 相同的 padding 阶梯 */}实现要点:
both同时应用alignItems: center与justifyContent: center;horizontal只应用 justify-content;vertical只应用 align-items(Center.tsx)。- 契约代表矩阵中明确提示:居中可观察的前提是轴上存在可用尺寸。
<Center>不设置尺寸时,其盒子由内容撑开,居中效果不可见;需要配合width/height/maxWidth或父容器的约束。 - 尺寸 prop(width/height/maxWidth/minHeight)通过动态样式一次函数化生成(
dynamicStyles.sizing),padding 阶梯与 Stack 完全一致(edge ?? axis ?? padding)。
允许的组件差异 AV1–AV7:统一中的多样性
契约在共享语义之上,明确允许成员保留自己的特征,防止"统一"演变成"趋同":
| 编号 | 差异维度 | 内容 |
|---|---|---|
| AV1 | 排列模型 | Stack 一维流、Grid 二维轨道、Center 单/双轴对齐 |
| AV2 | 可用 props | Stack/HStack/VStack/Center 暴露完整逻辑边 padding 阶梯;Grid 暴露轴级 gap;修饰器暴露父专属参与方式而非盒级布局控制 |
| AV3 | 元素所有权 | Stack/HStack/VStack/StackItem 多态(asprop);Grid/GridSpan/Center 当前拥有固定 div 元素 |
| AV4 | 溢出 | Stack/HStack/VStack/StackItem 暴露各自当前滚动行为(isScrollable);Grid 与 Center 不因家族成员身份获得该能力 |
| AV5 | 响应式 | Grid 固有列、Stack 换行、消费方自写响应式样式保持组件专属 |
| AV6 | 实现 | 允许裸 flex/grid 与共享工具函数并存,家族成员身份不制造实现级迁移债 |
| AV7 | 主题化 | 各组件的.doc.mjs元数据文档化已发布的 targets 与能力,运行时themeProps()发射它们;跨组件规则由architecture:component-theming-surface拥有 |
关于 AV3 有一个易混淆点:Stack 与 StackItem 的多态能力来自asprop(默认'div'),例如<Stack as="ul">渲染为列表;而 Grid/GridSpan/Center 当前固定渲染div。
代表矩阵:成员状态 × 共享不变量 × 刻意差异
| 成员与状态 | 共享不变量 | 刻意差异 |
|---|---|---|
| Stack / vertical 或 horizontal | 共享 spacing 与 sizing 值;方向解析对齐轴 | 可换行、可滚动、可渲染指定元素 |
| HStack 或 VStack | 同一 Stack 契约 + 固定方向 | 更窄的对齐类型匹配固定轴 |
StackItem /size="fill" | 单个子元素可消耗 Stack 剩余空间 | isScrollable与 StackItem 的 flex min 重置配对 |
| Grid / 固定列 | 共享 size 与 gap 值 | 显式等宽轨道数 |
| Grid / 固有列 | 共享 size 与 gap 值 | minWidth、可选列数上限、fill/fit 构造流式轨道 |
| GridSpan / columns 或 rows | 修饰器参与 Grid | 跨轨道而非控制父几何 |
| Center / 单轴或双轴 | 共享 size 与 padding 值 | 某轴居中可观察前需要可用尺寸 |
实战组合:把七个成员拼成一致布局
以下是一个体现"同一个小词汇表"的页面骨架示例:
import {Stack, HStack, VStack, StackItem, Grid, GridSpan, Center} from '@astryxdesign/core'; export function Dashboard() { return ( <VStack gap={5}> {/* 顶部栏:固定尺寸 Logo + 弹性内容 + 固定操作区 */} <HStack gap={3} vAlign="center" padding={4} isScrollable> <StackItem size="static"><Logo /></StackItem> <StackItem size="fill"><SearchBar /></StackItem> <StackItem size="static"><Avatar /></StackItem> </HStack> {/* 主区域:响应式网格,最大 4 列,移动端单列拉伸全宽 */} <Grid columns={{minWidth: 280, max: 4}} gap={4}> <GridSpan columns={2}><SummaryCard /></GridSpan> <GridSpan columns="full"><TrendChart /></GridSpan> <StatCard /><StatCard /><StatCard /> </Grid> {/* 底部空态:双轴居中并让内容垂直充满 */} <Center height={240} padding={6}> <VStack gap={2} hAlign="center"> <EmptyStateIcon /> <p>No data yet</p> </VStack> </Center> </VStack> ); }这个例子覆盖了全部七个成员,且每处 spacing 都来自同一张SpacingStep表:顶部栏gap={3}是 12px,主网格gap={4}是 16px,外层gap={5}是 20px——数值即 token,无需换算。
采用情况、已知缺口与变更耦合
采用与例外
| 组件/关注点 | 采用情况 | 当前缺口或例外 |
|---|---|---|
| Stack, HStack, VStack | 共享一维契约 | gap token 映射与 Grid 的映射分开实现 |
| StackItem | 共享修饰器契约 | 家族级 flex-item grow/shrink/basis 词汇表不存在 |
| Grid, GridSpan | 共享二维契约 | 没有跨组件测试证明 Grid 与 Stack 对相同 gap step 解析出相等的值 |
| Center | 共享 sizing 与 padding 词汇 | 与 Stack 相同,padding 是局部的、不发布 bleed 几何 |
| 共享验证 | 各组件单元覆盖 | 没有 computed-style 矩阵证明每个共享 spacing/sizing 值跨成员一致 |
契约明确声明:这些是已发布的覆盖或采用缺口,而不是授权在文档 PR 中加 props 或改布局行为的许可。
变更耦合(Change coupling)
契约规定了变更必须联动审查的边界,这直接指导贡献者:
- 增加或修改共享空间 prop,需检查其名称、值类型、强转、逻辑方向、优先级是否仍与本家族一致;
- 修改
SpacingStep或SizeValue,需审查所有暴露该类型的成员,并更新代表性的跨组件证据; - 修改 Stack 的方向/对齐,HStack 与 VStack 必须在同一次审查中同步更新;
- 修改 Grid 的固有轨道构造,需保留其文档化的 fixed、fill、fit、capped 四种状态并有聚焦测试;
- 将成员纳入 container bleed 是独立的
architecture:container-padding变更,需附带渲染兼容性证据; - 新组件加入的唯一条件是公共责任满足成员规则——使用 flexbox、grid 或共享工具函数不足以为凭。
决策记录:DEC-1
契约收录了一条已批准的决策(2026-08-30,决策人cixzhang):
组合原语与结构区域有各自的所有者。Stack、Grid、Center 及其修饰器组成 layout-primitives 家族;Section、Layout 区域与 Toolbar 有独立的结构区域所有者。这让成员资格可预测:原语规则描述任意子内容的组合,而不把槽位、表面或工具栏语义塞进同一契约。
验证地图:不变量如何被测试
契约提供了逐条不变量的验证地图,同时坦诚标注了"已证明"与"缺失证据":
| 契约 | 验证方式 | 证据证明的内容 | 缺失证据 |
|---|---|---|---|
| FR1, FR3 | Stack/Center 源码 + padding 类集测试 | 当前合并顺序:edge > axis > uniform;等价写法产出等价类集 | 无浏览器矩阵比较跨成员的计算值及两种书写方向 |
| FR2 | Stack/Center 的逻辑属性源码声明 | 实现用 inline-start/end 而非物理 left/right | 当前测试未在 LTR 与 RTL 下渲染 padding 阶梯 |
| FR4 | Stack/Grid 源码 + 本地测试 | API 保持 gap 与 padding 分离;Grid 接受 uniform 与轴级 gap props | Grid gap 测试只断言渲染成功而非计算间距;无测试将 step 与 Stack 比较 |
| FR5 | Stack/Grid/Center 源码 + 本地渲染测试 | 每个成员当前都通过自己的排列模型路由对齐 | Stack/Grid 测试未断言接受值的计算对齐 |
| FR6 | StackItem/GridSpan 源码 + 本地测试 | size="fill"映射为 fill 样式;滚动改变类输出;GridSpan 断言精确的 inline 行列跨距 | StackItem 的 fill 测试只断言渲染内容;无集成测试证明修饰器覆盖父组件的每种状态 |
| FR7 | Grid 精确轨道输出测试 + Stack/Center 源码 | Grid 的 fixed/intrinsic 轨道字符串被固定;Stack 仅在配置时换行;Center 无断点路径 | 无跨成员响应式集成矩阵 |
| FR8 | 对照architecture:container-padding的源码审查 | Stack/Center 应用本地 padding 而不发布容器 inset 变量 | 无浏览器断言证明 Divider/Table 后代的非 bleed 行为 |
对应的测试文件即契约 front matter 中的verified_by列表:Stack.test.tsx、StackItem.test.tsx、Grid.test.tsx、Center.test.tsx。
契约的诚实表述值得关注:测试是组件局部的,且若干测试只断言渲染成功或类变化,并不证明计算后的 gap、对齐、逻辑方向或跨组件一致性——那些被点名列为验证缺口,而非隐式覆盖。这意味着贡献者补测试的空间是明确标出的。
内容边界:这份契约不做什么
最后,契约划定了自己的内容边界,防止被误读为组件总规范:
- 不重复组件的 prop 表(请读各成员的
.spec.md,如 Stack.spec.md、Grid.spec.md、Center.spec.md); - 不规定实现机制;
- 不定义结构区域(那是 Section/Layout/Toolbar 的家族职责);
- 不指派响应式断点;
- 不拥有主题 anatomy 与 targets(属
architecture:component-theming-surface)。
当前契约没有未决问题(Open questions: None)——采用表列出的缺失能力与验证缺口是"待办事实",不是悬而未决的家族政策。
小结
Astryx 的 layout-primitives 家族把"排列任意内容"这件最简单也最容易被做乱的事,收敛为一份可审查、可验证、可演进的契约:成员资格看公共职责,共享词汇由SpacingStep/SizeValue与排列模型唯一解释,九条不变量 + 七条允许差异 + 一张验证地图共同保证——无论是用 Stack 排一维、Grid 排二维、Center 居中,还是用 StackItem/GridSpan 微调子元素,写出来的代码在间距、对齐、逻辑方向、padding 优先级上都说着同一种语言。这份契约的完整文本与所有相关决策记录,可在 docs/families/layout-primitives.md 及其引用的架构文档(container-padding、public-component-api、component-theming-surface)中继续追溯。
【免费下载链接】astryxAn open source design system that's fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考