iter(g130): 新增栅格容器 grid

This commit is contained in:
HIsheR
2026-10-26 15:20:04 +08:00
parent 88c2515f2e
commit 23d1e063dc
13 changed files with 202 additions and 13 deletions
+21
View File
@@ -0,0 +1,21 @@
import { h } from '@ui-arch/frame';
import type { GridProps } from './types.js';
// 间距档位 → 令牌(数字档位不入表,直接拼像素)
const GUTTER: Record<string, string> = { sm: 'var(--ua-space-2)', md: 'var(--ua-space-3)', lg: 'var(--ua-space-4)' };
// 交叉轴对齐 → grid align-items 取值
const ALIGN: Record<string, string> = { start: 'start', center: 'center', end: 'end', stretch: 'stretch' };
/*** 栅格容器:columns 固定列数、min 走 auto-fit 自适应列宽,gutter 统一列间距;列模板写进 --ua-grid-cols,窄屏由样式表降为单列 ***/
export function grid(props: GridProps, ...children: unknown[]): HTMLElement {
const gutter = typeof props.gutter === 'number' ? `${props.gutter}px` : GUTTER[props.gutter ?? 'md']; // 数字档位按像素透传
const template = props.min
? `repeat(auto-fit, minmax(${props.min}, 1fr))` // 自适应:列数由可用宽度决定
: `repeat(${props.columns ?? 3}, minmax(0, 1fr))`; // 固定列数:minmax(0,1fr) 防止长内容撑破
const el = h('div', {
class: ['ua-grid', props.dense ? 'is-dense' : '', props.align ? `is-align-${props.align}` : ''].filter(Boolean).join(' '),
style: `gap:${gutter};align-items:${ALIGN[props.align ?? 'stretch']};`,
}, ...children);
el.style.setProperty('--ua-grid-cols', template); // 列模板交给 CSS 变量,媒体查询可覆盖
return el;
}
+1
View File
@@ -61,3 +61,4 @@ export { anchor } from './anchor.js';
export { popconfirm } from './popconfirm.js';
export { calendar } from './calendar.js';
export { typography } from './typography.js';
export { grid } from './grid.js';
+9
View File
@@ -757,4 +757,13 @@ export interface TypographyProps {
copyable?: boolean; // 附复制按钮:点后写剪贴板并短暂回显结果;缺省 false
}
/*** 栅格容器入参 ***/
export interface GridProps {
columns?: number; // 固定列数;缺省 3(窄屏一律降为单列)
min?: string; // 自适应最小列宽(如 '220px'):给了就按 auto-fit 铺列,忽略 columns
gutter?: SpaceSize; // 列间距:sm/md/lg 走令牌,数字按像素;缺省 md
align?: 'start' | 'center' | 'end' | 'stretch'; // 交叉轴对齐(行高不一致时定子项位置);缺省 stretch
dense?: boolean; // 紧凑填充:小项回填空洞(瀑布式排布);缺省 false
}
export type { ColumnDef, RowKey }; // 再导出常用内核类型,方便调用方
+47 -1
View File
@@ -75,7 +75,8 @@
"anchor(props):锚点导航,竖排区块链接,滚动时按目标位置高亮当前区块(aria-current 同步),点击按 offset 偏移量平滑定位并回写 hash;container 可指定内滚容器",
"popconfirm(props, trigger):二次确认气泡,挂在任意触发器上,就地确认危险操作;确定后先收起再回调,取消 / 点外部 / Esc 走 onCancel,展开即聚焦「取消」",
"calendar(props):月历,整月网格内嵌页面(排期 / 值班 / 日程),每日可带 marker 标记文案,方向键漫游 + Enter 选中,翻月走 onMonthChange",
"typography(props):排版文本,variant 决定语义(标题出 h1-h5 / 段落出 p / 行内出 span),支持语义色、装饰位、对齐、多行截断与复制按钮"
"typography(props):排版文本,variant 决定语义(标题出 h1-h5 / 段落出 p / 行内出 span),支持语义色、装饰位、对齐、多行截断与复制按钮",
"grid(props, ...children):栅格容器,columns 固定列数或 min 走 auto-fit 自适应列宽,gutter 统一列间距,窄屏自动降为单列"
],
"keyTypes": [
"ButtonProps",
@@ -3032,6 +3033,51 @@
"content 传 DOM 时组件只负责语义标签与类名:截断与复制对 DOM 内容不生效(取不到稳定文本)",
"段落连续排列时相邻 .ua-type-paragraph 自动留出间距,单个段落不额外撑高,嵌进卡片也不会有空隙"
]
},
{
"id": "grid",
"title": "栅格容器 Grid",
"demo": "sec-grid",
"props": [
{
"n": "columns",
"t": "number",
"df": "3",
"d": "固定列数(按等宽铺开);窄屏(≤640px)由样式表统一降为单列"
},
{
"n": "min",
"t": "string",
"d": "自适应最小列宽(如 '220px'):给了就按 auto-fit 铺列,列数随可用宽度自然增减,此时忽略 columns"
},
{
"n": "gutter",
"t": "SpaceSize",
"df": "md",
"d": "列间距:sm/md/lg 走令牌,数字按像素"
},
{
"n": "align",
"t": "'start' | 'center' | 'end' | 'stretch'",
"df": "stretch",
"d": "交叉轴对齐:同行子项高度不一时决定各自贴哪边或拉满"
},
{
"n": "dense",
"t": "boolean",
"df": "false",
"d": "紧凑填充:小项回填前面留下的空洞(瀑布式排布)"
}
],
"example": "grid({ columns: 3, gutter: 'md' }, card({ title: '实例数' }, statistic({ value: total })), card({ title: '错误率' }, statistic({ value: errRate }))); grid({ min: '240px', align: 'start' }, ...items)",
"steps": [
"页面骨架用 grid({ columns: n }) 铺等宽卡片:子项宽度由列模板算,别在子项上写 width,窄屏会自动变成单列",
"卡片宽度要求「不窄于 X」时用 min(如 '240px'):auto-fit 会按可用宽度决定列数,比手写断点稳,此时不要再传 columns",
"列间距统一走 gutter(sm/md/lg 令牌或像素),不要在子项上写 margin——相邻 margin 会叠加成双倍间距",
"同行卡片高度参差时:要等高(默认 stretch),要各自顶端对齐传 align: 'start'",
"子项必须是单个元素(card / div / 自定义块),grid 只负责排布且已对子项设 min-width: 0,长文本不会撑破列宽",
"只要横向一排展示且元素不等宽,用 space 更轻;grid 面向二维对齐"
]
}
]
}
+21
View File
@@ -4045,3 +4045,24 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); }
transition: none;
}
}
/* —— 栅格容器:列模板由内联变量给,窄屏统一降为单列 —— */
.ua-grid {
display: grid;
grid-template-columns: var(--ua-grid-cols, repeat(3, minmax(0, 1fr)));
align-items: stretch;
}
.ua-grid > * {
min-width: 0; /* 长文本 / 表格不撑破列宽 */
}
.ua-grid.is-dense {
grid-auto-flow: dense;
}
.ua-grid.is-align-start { align-items: start; }
.ua-grid.is-align-center { align-items: center; }
.ua-grid.is-align-end { align-items: end; }
@media (max-width: 640px) {
.ua-grid {
grid-template-columns: 1fr;
}
}