iter(g143): 页签栏支持右侧操作区
This commit is contained in:
@@ -1500,6 +1500,14 @@
|
|||||||
"acceptance": "space 新增 split:仅在 2 个以上子元素间插入分隔符,分隔符 aria-hidden、弱化色、不可选中;文档与演示同步;npm run check 全绿",
|
"acceptance": "space 新增 split:仅在 2 个以上子元素间插入分隔符,分隔符 aria-hidden、弱化色、不可选中;文档与演示同步;npm run check 全绿",
|
||||||
"notes": "自补:既有组件可用性细节",
|
"notes": "自补:既有组件可用性细节",
|
||||||
"status": "done"
|
"status": "done"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "g143",
|
||||||
|
"title": "页签栏支持右侧操作区 extra",
|
||||||
|
"motivation": "「新建 / 设置」这类页签级操作只能塞进页签数组或浮在页签栏外,垂直不对齐、分隔线断掉;调用方还得自己包一层 flex",
|
||||||
|
"acceptance": "tabs 新增 extra:与页签同一行、共用一条分隔线,不传时 DOM 结构不变(纯增量);文档 props/steps 与演示同步;npm run check 全绿",
|
||||||
|
"notes": "自补:既有组件可用性细节",
|
||||||
|
"status": "open"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "ui-arch-registry-index/0.1",
|
"$schema": "ui-arch-registry-index/0.1",
|
||||||
"generatedAt": "2026-10-26T07:37:18.841Z",
|
"generatedAt": "2026-10-26T07:38:33.907Z",
|
||||||
"repoRoot": ".",
|
"repoRoot": ".",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
@@ -1385,6 +1385,11 @@
|
|||||||
"k": 1,
|
"k": 1,
|
||||||
"d": "关闭页签回调:组件不自行移除,凭 value 从数据源里摘掉后重绘"
|
"d": "关闭页签回调:组件不自行移除,凭 value 从数据源里摘掉后重绘"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"n": "extra",
|
||||||
|
"t": "unknown",
|
||||||
|
"d": "页签栏右侧操作区内容(按钮 / 链接):与页签同一行、共用一条分隔线;缺省不渲染且页签栏结构不变"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"n": "closable",
|
"n": "closable",
|
||||||
"t": "boolean",
|
"t": "boolean",
|
||||||
@@ -1397,7 +1402,8 @@
|
|||||||
"tabs 只渲染页签头;页签内容用响应式函数按信号切换,如 () => tab() === 'a' ? panelA : panelB",
|
"tabs 只渲染页签头;页签内容用响应式函数按信号切换,如 () => tab() === 'a' ? panelA : panelB",
|
||||||
"点击或方向键(←→ 环形)、Home/End(直达首/末页签)切换,滑动指示条自动跟随;disabled: true 的页签置灰不可点",
|
"点击或方向键(←→ 环形)、Home/End(直达首/末页签)切换,滑动指示条自动跟随;disabled: true 的页签置灰不可点",
|
||||||
"需要可关闭页签时给该项加 closable: true,× 或聚焦后按 Delete 触发 onClose(value);组件不改数据源,调用方从数组里摘掉该项再重绘",
|
"需要可关闭页签时给该项加 closable: true,× 或聚焦后按 Delete 触发 onClose(value);组件不改数据源,调用方从数组里摘掉该项再重绘",
|
||||||
"键盘可访问:Tab 聚焦激活页签,←→ 在启用页签间环形移动,Home/End 跳首个/末个启用页签"
|
"键盘可访问:Tab 聚焦激活页签,←→ 在启用页签间环形移动,Home/End 跳首个/末个启用页签",
|
||||||
|
"页签栏右侧要放「新建 / 设置」这类操作就传 extra(按钮或链接):它与页签同一行共用一条分隔线,不传时 DOM 结构保持不变"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+5
-1
@@ -522,7 +522,11 @@ const content = h(
|
|||||||
'sec-tabs-modal',
|
'sec-tabs-modal',
|
||||||
'标签页与弹窗',
|
'标签页与弹窗',
|
||||||
'tabs 滑动指示条 + 方向键切换(←→),禁用页签置灰,closable 页签带 ×(聚焦后 Delete 也能关,关闭只回调、由数据源摘除后重绘);modal 支持 Esc / 遮罩 / × 关闭(closeOnOverlay: false 时点遮罩不关、防填一半误触),弹窗内的下拉展开时 Esc 先收下拉、再按才关弹窗(逐层关闭)。',
|
'tabs 滑动指示条 + 方向键切换(←→),禁用页签置灰,closable 页签带 ×(聚焦后 Delete 也能关,关闭只回调、由数据源摘除后重绘);modal 支持 Esc / 遮罩 / × 关闭(closeOnOverlay: false 时点遮罩不关、防填一半误触),弹窗内的下拉展开时 Esc 先收下拉、再按才关弹窗(逐层关闭)。',
|
||||||
tabs({ tabs: [{ value: 'a', label: '概览' }, { value: 'b', label: '明细' }, { value: 'c', label: '设置' }, { value: 'd', label: '已停用', disabled: true }], active: activeTab }),
|
tabs({
|
||||||
|
tabs: [{ value: 'a', label: '概览' }, { value: 'b', label: '明细' }, { value: 'c', label: '设置' }, { value: 'd', label: '已停用', disabled: true }],
|
||||||
|
active: activeTab,
|
||||||
|
extra: button({ label: '新建页签', variant: 'ghost', onClick: () => toast.info('右侧操作区与页签同一行') }), // extra 放页签栏右侧
|
||||||
|
}),
|
||||||
h('span', { class: 'out' }, () => `当前页签:${activeTab()}`),
|
h('span', { class: 'out' }, () => `当前页签:${activeTab()}`),
|
||||||
renderList(h('div', { class: 'row' }), () => {
|
renderList(h('div', { class: 'row' }), () => {
|
||||||
const items = closableTabs();
|
const items = closableTabs();
|
||||||
|
|||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||||
|
|
||||||
> 自动生成于 2026-10-26T07:37:18.841Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
> 自动生成于 2026-10-26T07:38:33.907Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||||
|
|
||||||
## 快速上手
|
## 快速上手
|
||||||
@@ -691,6 +691,7 @@ const pct = signal(0); progress({ value: pct }); setInterval(() => pct((pct() +
|
|||||||
- active:Signal<string> —— 当前激活页签 value 信号,双向绑定
|
- active:Signal<string> —— 当前激活页签 value 信号,双向绑定
|
||||||
- onChange(回调):(value: string) => void —— 切换回调
|
- onChange(回调):(value: string) => void —— 切换回调
|
||||||
- onClose(回调):(value: string) => void —— 关闭页签回调:组件不自行移除,凭 value 从数据源里摘掉后重绘
|
- onClose(回调):(value: string) => void —— 关闭页签回调:组件不自行移除,凭 value 从数据源里摘掉后重绘
|
||||||
|
- extra:unknown —— 页签栏右侧操作区内容(按钮 / 链接):与页签同一行、共用一条分隔线;缺省不渲染且页签栏结构不变
|
||||||
- closable:boolean —— 页签项上的开关:true 时渲染关闭按钮(×),关闭按钮不进 Tab 序但可用鼠标点;缺省不可关
|
- closable:boolean —— 页签项上的开关:true 时渲染关闭按钮(×),关闭按钮不进 Tab 序但可用鼠标点;缺省不可关
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
@@ -706,6 +707,7 @@ const tab = signal('a'); tabs({ tabs: [{ value: 'a', label: '概览', closable:
|
|||||||
3. 点击或方向键(←→ 环形)、Home/End(直达首/末页签)切换,滑动指示条自动跟随;disabled: true 的页签置灰不可点
|
3. 点击或方向键(←→ 环形)、Home/End(直达首/末页签)切换,滑动指示条自动跟随;disabled: true 的页签置灰不可点
|
||||||
4. 需要可关闭页签时给该项加 closable: true,× 或聚焦后按 Delete 触发 onClose(value);组件不改数据源,调用方从数组里摘掉该项再重绘
|
4. 需要可关闭页签时给该项加 closable: true,× 或聚焦后按 Delete 触发 onClose(value);组件不改数据源,调用方从数组里摘掉该项再重绘
|
||||||
5. 键盘可访问:Tab 聚焦激活页签,←→ 在启用页签间环形移动,Home/End 跳首个/末个启用页签
|
5. 键盘可访问:Tab 聚焦激活页签,←→ 在启用页签间环形移动,Home/End 跳首个/末个启用页签
|
||||||
|
6. 页签栏右侧要放「新建 / 设置」这类操作就传 extra(按钮或链接):它与页签同一行共用一条分隔线,不传时 DOM 结构保持不变
|
||||||
|
|
||||||
现场演示:apps/docs/demo.html#sec-tabs-modal
|
现场演示:apps/docs/demo.html#sec-tabs-modal
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,9 @@ export function tabs(props: TabsProps): HTMLElement {
|
|||||||
next?.click();
|
next?.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
const root = h('div', { class: 'ua-tabs' }, head);
|
const extra = props.extra ? h('div', { class: 'ua-tabs-extra' }, props.extra) : null; // 右侧操作区:与页签同一行
|
||||||
|
const bar = extra ? h('div', { class: 'ua-tabs-bar' }, head, extra) : head; // 有操作区才包一层,无操作区结构不变
|
||||||
|
const root = h('div', { class: 'ua-tabs' }, bar);
|
||||||
effect(sync);
|
effect(sync);
|
||||||
requestAnimationFrame(sync); // 挂载后再量一次布局,否则指示条宽度为 0
|
requestAnimationFrame(sync); // 挂载后再量一次布局,否则指示条宽度为 0
|
||||||
trackSize(root, sync); // 容器变宽 / 窗口缩放后重算,指示条不会停在旧宽度
|
trackSize(root, sync); // 容器变宽 / 窗口缩放后重算,指示条不会停在旧宽度
|
||||||
|
|||||||
@@ -347,6 +347,7 @@ export interface TabsProps {
|
|||||||
active?: Signal<string>; // 当前激活页签的 value 信号,双向绑定
|
active?: Signal<string>; // 当前激活页签的 value 信号,双向绑定
|
||||||
onChange?: (value: string) => void; // 切换回调
|
onChange?: (value: string) => void; // 切换回调
|
||||||
onClose?: (value: string) => void; // 关闭页签回调:组件不自行移除,凭 value 从数据源里摘掉
|
onClose?: (value: string) => void; // 关闭页签回调:组件不自行移除,凭 value 从数据源里摘掉
|
||||||
|
extra?: unknown; // 页签栏右侧操作区内容(按钮 / 链接);缺省不渲染,页签栏结构不变
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** 弹窗入参 ***/
|
/*** 弹窗入参 ***/
|
||||||
|
|||||||
@@ -1256,6 +1256,11 @@
|
|||||||
"k": 1,
|
"k": 1,
|
||||||
"d": "关闭页签回调:组件不自行移除,凭 value 从数据源里摘掉后重绘"
|
"d": "关闭页签回调:组件不自行移除,凭 value 从数据源里摘掉后重绘"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"n": "extra",
|
||||||
|
"t": "unknown",
|
||||||
|
"d": "页签栏右侧操作区内容(按钮 / 链接):与页签同一行、共用一条分隔线;缺省不渲染且页签栏结构不变"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"n": "closable",
|
"n": "closable",
|
||||||
"t": "boolean",
|
"t": "boolean",
|
||||||
@@ -1268,7 +1273,8 @@
|
|||||||
"tabs 只渲染页签头;页签内容用响应式函数按信号切换,如 () => tab() === 'a' ? panelA : panelB",
|
"tabs 只渲染页签头;页签内容用响应式函数按信号切换,如 () => tab() === 'a' ? panelA : panelB",
|
||||||
"点击或方向键(←→ 环形)、Home/End(直达首/末页签)切换,滑动指示条自动跟随;disabled: true 的页签置灰不可点",
|
"点击或方向键(←→ 环形)、Home/End(直达首/末页签)切换,滑动指示条自动跟随;disabled: true 的页签置灰不可点",
|
||||||
"需要可关闭页签时给该项加 closable: true,× 或聚焦后按 Delete 触发 onClose(value);组件不改数据源,调用方从数组里摘掉该项再重绘",
|
"需要可关闭页签时给该项加 closable: true,× 或聚焦后按 Delete 触发 onClose(value);组件不改数据源,调用方从数组里摘掉该项再重绘",
|
||||||
"键盘可访问:Tab 聚焦激活页签,←→ 在启用页签间环形移动,Home/End 跳首个/末个启用页签"
|
"键盘可访问:Tab 聚焦激活页签,←→ 在启用页签间环形移动,Home/End 跳首个/末个启用页签",
|
||||||
|
"页签栏右侧要放「新建 / 设置」这类操作就传 extra(按钮或链接):它与页签同一行共用一条分隔线,不传时 DOM 结构保持不变"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4419,3 +4419,23 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); }
|
|||||||
font-size: var(--ua-font-size-sm);
|
font-size: var(--ua-font-size-sm);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* —— 页签栏右侧操作区:与页签同一行,分隔线由整条 bar 承担 —— */
|
||||||
|
.ua-tabs-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--ua-space-3);
|
||||||
|
border-bottom: 1px solid var(--ua-color-border);
|
||||||
|
}
|
||||||
|
.ua-tabs-bar .ua-tabs-head {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
border-bottom: 0; /* 线移到 bar 上,操作区也和页签栏同一条线 */
|
||||||
|
}
|
||||||
|
.ua-tabs-extra {
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--ua-space-2);
|
||||||
|
padding-bottom: var(--ua-space-1);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user