Compare commits
1 Commits
a57577a995
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 42248bf4bb |
+2
-2
@@ -6,8 +6,8 @@
|
|||||||
"title": "新增 tooltip 组件",
|
"title": "新增 tooltip 组件",
|
||||||
"motivation": "皮肤包 16 组件缺少悬浮提示,表单与工具栏场景常用;可复用自绘弹层与微动画既有模式",
|
"motivation": "皮肤包 16 组件缺少悬浮提示,表单与工具栏场景常用;可复用自绘弹层与微动画既有模式",
|
||||||
"acceptance": "packages/skin/ui 新增 tooltip.ts:content/message 简单 API,hover/focus 触发,延迟约 150ms 出场,带出入场微动画与 prefers-reduced-motion 兜底,只消费 --ua-* 令牌;导出并注册进 ua.manifest.json,文档站 props 表与 llms-full.txt 同步更新;npm run check 全绿",
|
"acceptance": "packages/skin/ui 新增 tooltip.ts:content/message 简单 API,hover/focus 触发,延迟约 150ms 出场,带出入场微动画与 prefers-reduced-motion 兜底,只消费 --ua-* 令牌;导出并注册进 ua.manifest.json,文档站 props 表与 llms-full.txt 同步更新;npm run check 全绿",
|
||||||
"status": "done",
|
"status": "open",
|
||||||
"notes": "API 定为 tooltip(props, trigger) 包裹式;delay 默认 150ms,Esc 立即收起,气泡 pointer-events:none 防抖,aria-describedby + role=tooltip 保证读屏可读;demo 新增 sec-tooltip 区块。顺带修复 ua style 对 https:// 的误判(先剥离字面量再定位 //)"
|
"notes": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "b02",
|
"id": "b02",
|
||||||
|
|||||||
+3
-43
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "ui-arch-registry-index/0.1",
|
"$schema": "ui-arch-registry-index/0.1",
|
||||||
"generatedAt": "2026-10-23T07:34:01.200Z",
|
"generatedAt": "2026-10-23T06:57:51.085Z",
|
||||||
"repoRoot": ".",
|
"repoRoot": ".",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@ui-arch/ui",
|
"name": "@ui-arch/ui",
|
||||||
"type": "skin-dom",
|
"type": "skin-dom",
|
||||||
"description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / tooltip / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
|
"description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
|
||||||
"tags": [
|
"tags": [
|
||||||
"components",
|
"components",
|
||||||
"dom",
|
"dom",
|
||||||
@@ -152,7 +152,6 @@
|
|||||||
"card(props, ...children):卡片容器",
|
"card(props, ...children):卡片容器",
|
||||||
"badge(props):徽标,variant = default | success | warning | danger",
|
"badge(props):徽标,variant = default | success | warning | danger",
|
||||||
"alert(props):提示条,variant = info | success | warning | danger",
|
"alert(props):提示条,variant = info | success | warning | danger",
|
||||||
"tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起",
|
|
||||||
"spinner(props):加载指示器,size 控制直径",
|
"spinner(props):加载指示器,size 控制直径",
|
||||||
"progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色",
|
"progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色",
|
||||||
"tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签",
|
"tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签",
|
||||||
@@ -173,7 +172,6 @@
|
|||||||
"CardProps",
|
"CardProps",
|
||||||
"BadgeProps",
|
"BadgeProps",
|
||||||
"AlertProps",
|
"AlertProps",
|
||||||
"TooltipProps",
|
|
||||||
"SpinnerProps",
|
"SpinnerProps",
|
||||||
"ProgressProps",
|
"ProgressProps",
|
||||||
"TabsProps",
|
"TabsProps",
|
||||||
@@ -192,7 +190,7 @@
|
|||||||
"语义色 variant 四档:default|info / success / warning / danger,一律来自令牌,禁止硬编码颜色"
|
"语义色 variant 四档:default|info / success / warning / danger,一律来自令牌,禁止硬编码颜色"
|
||||||
],
|
],
|
||||||
"docs": {
|
"docs": {
|
||||||
"intro": "17 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
|
"intro": "16 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
|
||||||
"steps": [
|
"steps": [
|
||||||
"安装依赖:pnpm add @ui-arch/ui @ui-arch/frame(workspace 内自动链接)",
|
"安装依赖:pnpm add @ui-arch/ui @ui-arch/frame(workspace 内自动链接)",
|
||||||
"引入样式:在应用入口 import '@ui-arch/ui/ui.css',暗色主题在根元素设 data-theme='dark'",
|
"引入样式:在应用入口 import '@ui-arch/ui/ui.css',暗色主题在根元素设 data-theme='dark'",
|
||||||
@@ -487,44 +485,6 @@
|
|||||||
"传入 message 即可,入场自带下滑动画"
|
"传入 message 即可,入场自带下滑动画"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "tooltip",
|
|
||||||
"title": "悬浮提示 Tooltip",
|
|
||||||
"demo": "sec-tooltip",
|
|
||||||
"props": [
|
|
||||||
{
|
|
||||||
"n": "content",
|
|
||||||
"t": "string",
|
|
||||||
"r": 1,
|
|
||||||
"d": "提示文案(纯文本)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"n": "placement",
|
|
||||||
"t": "'top' | 'bottom'",
|
|
||||||
"d": "气泡方位;缺省 top(触发器上方)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"n": "delay",
|
|
||||||
"t": "number",
|
|
||||||
"d": "出场延迟毫秒;缺省 150,传 0 立即显示"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"n": "trigger",
|
|
||||||
"t": "HTMLElement",
|
|
||||||
"r": 1,
|
|
||||||
"d": "第二个参数:被包裹的触发器元素(按钮 / 输入框等任意 DOM)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"example": "tooltip({ content: '保存后立即生效' }, button({ label: '保存', onClick: save }))",
|
|
||||||
"steps": [
|
|
||||||
"先创建触发器元素,如 const btn = button({ label: '保存' })",
|
|
||||||
"用 tooltip(props, trigger) 包一层:返回带气泡的包裹元素,原触发器仍是独立节点",
|
|
||||||
"鼠标移入或键盘聚焦约 150ms 后出场,移出 / 失焦立即收起;按 Esc 可立刻关闭",
|
|
||||||
"气泡默认在上方,空间不足或需要避让时传 placement: 'bottom'",
|
|
||||||
"气泡 pointer-events: none 不抢指针;判读依赖 aria-describedby + role='tooltip',读屏可读",
|
|
||||||
"只做展示:不要在气泡里放可点击元素,需要交互请用 modal 或自绘弹层"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "spinner",
|
"id": "spinner",
|
||||||
"title": "加载指示器 Spinner",
|
"title": "加载指示器 Spinner",
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{"time":"2026-10-23T15:47:00+08:00","id":"b01","result":"done","summary":"新增 tooltip 悬浮提示组件(包裹式 API / 150ms 延迟 / Esc 收起 / reduced-motion 兜底),同步 manifest + llms-full.txt + demo 区块,并修复 ua style 对 URL 中 // 的误判;npm run check 全绿"}
|
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
- `packages/core/table-core`(@ui-arch/table-core):Headless 表格逻辑内核
|
- `packages/core/table-core`(@ui-arch/table-core):Headless 表格逻辑内核
|
||||||
- `packages/core/frame`(@ui-arch/frame):signal + hyperscript 微框架
|
- `packages/core/frame`(@ui-arch/frame):signal + hyperscript 微框架
|
||||||
- `packages/skin/ui`(@ui-arch/ui):17 个 DOM 组件,样式只消费令牌
|
- `packages/skin/ui`(@ui-arch/ui):16 个 DOM 组件,样式只消费令牌
|
||||||
- `packages/design/tokens`(@ui-arch/tokens):设计令牌
|
- `packages/design/tokens`(@ui-arch/tokens):设计令牌
|
||||||
- `packages/tools/cli`(@ui-arch/cli):`ua` 命令行 + MCP 注册表服务(private)
|
- `packages/tools/cli`(@ui-arch/cli):`ua` 命令行 + MCP 注册表服务(private)
|
||||||
- `apps/demo`(@ui-arch/demo):交互演示,产物 apps/demo/dist/demo.html
|
- `apps/demo`(@ui-arch/demo):交互演示,产物 apps/demo/dist/demo.html
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ ui-arch-mvp/
|
|||||||
│ │ ├── table-core/ # 表格状态内核
|
│ │ ├── table-core/ # 表格状态内核
|
||||||
│ │ └── frame/ # 信号 + hyperscript 微框架
|
│ │ └── frame/ # 信号 + hyperscript 微框架
|
||||||
│ ├── skin/ # 皮肤层(DOM 组件,可发布)
|
│ ├── skin/ # 皮肤层(DOM 组件,可发布)
|
||||||
│ │ └── ui/ # 17 个组件 + ui.css
|
│ │ └── ui/ # 15 个组件 + ui.css
|
||||||
│ ├── design/ # 资产层(可发布)
|
│ ├── design/ # 资产层(可发布)
|
||||||
│ │ └── tokens/ # --ua-* 设计令牌
|
│ │ └── tokens/ # --ua-* 设计令牌
|
||||||
│ └── tools/ # 工程层(private,不发布)
|
│ └── tools/ # 工程层(private,不发布)
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ qa/probe ──门禁通过──▶ qa/stable ──人工审阅──▶ main
|
|||||||
|
|
||||||
## 每轮迭代流程(自动化 Agent 执行)
|
## 每轮迭代流程(自动化 Agent 执行)
|
||||||
|
|
||||||
|
> 所有远程推送一律使用认证包装脚本:`node scripts/gitea.mjs push <remote> <分支>`(令牌读自本地 `.gitea-token`,不入库;凭据管理器不可用)。
|
||||||
|
|
||||||
1. **同步**:`git fetch --all --prune`,切到 `qa/stable` 并 `git pull`;从其最新提交强制重建 `qa/probe` 并切换过去。
|
1. **同步**:`git fetch --all --prune`,切到 `qa/stable` 并 `git pull`;从其最新提交强制重建 `qa/probe` 并切换过去。
|
||||||
2. **选题**:读 `.ua/backlog.json`,取第一条 `status === "open"` 的条目;若全部关闭,按《选题规则》自行补充一条新点子后继续。
|
2. **选题**:读 `.ua/backlog.json`,取第一条 `status === "open"` 的条目;若全部关闭,按《选题规则》自行补充一条新点子后继续。
|
||||||
3. **实现**:按 `CODING.md` 编码规范实现,保持低侵入,单文件 < 200 行,涉及组件需同步 manifest/docs/llms-full.txt。
|
3. **实现**:按 `CODING.md` 编码规范实现,保持低侵入,单文件 < 200 行,涉及组件需同步 manifest/docs/llms-full.txt。
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import {
|
|||||||
tabs,
|
tabs,
|
||||||
textarea,
|
textarea,
|
||||||
textField,
|
textField,
|
||||||
tooltip,
|
|
||||||
} from '@ui-arch/ui';
|
} from '@ui-arch/ui';
|
||||||
|
|
||||||
/*** 生成演示区块;id 供文档站 iframe 锚点定位 ***/
|
/*** 生成演示区块;id 供文档站 iframe 锚点定位 ***/
|
||||||
@@ -113,18 +112,6 @@ const app = h(
|
|||||||
h('div', { class: 'row' }, spinner(), spinner({ size: 26 })),
|
h('div', { class: 'row' }, spinner(), spinner({ size: 26 })),
|
||||||
progress({ value: percent }),
|
progress({ value: percent }),
|
||||||
),
|
),
|
||||||
section(
|
|
||||||
'sec-tooltip',
|
|
||||||
'悬浮提示',
|
|
||||||
'tooltip 包裹触发器:hover / 聚焦延迟 150ms 出场,移出、失焦或 Esc 收起,气泡不抢指针。',
|
|
||||||
h(
|
|
||||||
'div',
|
|
||||||
{ class: 'row' },
|
|
||||||
tooltip({ content: '保存后立即生效' }, button({ label: '保存' })),
|
|
||||||
tooltip({ content: '该操作不可撤销', placement: 'bottom' }, button({ label: '删除', variant: 'danger' })),
|
|
||||||
tooltip({ content: '聚焦输入框同样会显示' }, textField({ placeholder: '聚焦我…' })),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
section(
|
section(
|
||||||
'sec-formlab',
|
'sec-formlab',
|
||||||
'表单校验',
|
'表单校验',
|
||||||
|
|||||||
+2
-29
@@ -1,6 +1,6 @@
|
|||||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||||
|
|
||||||
> 自动生成于 2026-10-23T07:34:01.200Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
> 自动生成于 2026-10-23T06:57:51.085Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||||
|
|
||||||
## 快速上手
|
## 快速上手
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
## @ui-arch/ui(skin-dom)v0.1.0
|
## @ui-arch/ui(skin-dom)v0.1.0
|
||||||
|
|
||||||
17 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。
|
16 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。
|
||||||
|
|
||||||
### button — 按钮 Button
|
### button — 按钮 Button
|
||||||
|
|
||||||
@@ -260,32 +260,6 @@ alert({ message: '操作可能存在风险', variant: 'warning' })
|
|||||||
|
|
||||||
现场演示:apps/docs/demo.html#sec-feedback
|
现场演示:apps/docs/demo.html#sec-feedback
|
||||||
|
|
||||||
### tooltip — 悬浮提示 Tooltip
|
|
||||||
|
|
||||||
参数:
|
|
||||||
|
|
||||||
- content(必填):string —— 提示文案(纯文本)
|
|
||||||
- placement:'top' | 'bottom' —— 气泡方位;缺省 top(触发器上方)
|
|
||||||
- delay:number —— 出场延迟毫秒;缺省 150,传 0 立即显示
|
|
||||||
- trigger(必填):HTMLElement —— 第二个参数:被包裹的触发器元素(按钮 / 输入框等任意 DOM)
|
|
||||||
|
|
||||||
示例:
|
|
||||||
|
|
||||||
```
|
|
||||||
tooltip({ content: '保存后立即生效' }, button({ label: '保存', onClick: save }))
|
|
||||||
```
|
|
||||||
|
|
||||||
手把手:
|
|
||||||
|
|
||||||
1. 先创建触发器元素,如 const btn = button({ label: '保存' })
|
|
||||||
2. 用 tooltip(props, trigger) 包一层:返回带气泡的包裹元素,原触发器仍是独立节点
|
|
||||||
3. 鼠标移入或键盘聚焦约 150ms 后出场,移出 / 失焦立即收起;按 Esc 可立刻关闭
|
|
||||||
4. 气泡默认在上方,空间不足或需要避让时传 placement: 'bottom'
|
|
||||||
5. 气泡 pointer-events: none 不抢指针;判读依赖 aria-describedby + role='tooltip',读屏可读
|
|
||||||
6. 只做展示:不要在气泡里放可点击元素,需要交互请用 modal 或自绘弹层
|
|
||||||
|
|
||||||
现场演示:apps/docs/demo.html#sec-tooltip
|
|
||||||
|
|
||||||
### spinner — 加载指示器 Spinner
|
### spinner — 加载指示器 Spinner
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
@@ -444,7 +418,6 @@ API 速览:
|
|||||||
- card(props, ...children):卡片容器
|
- card(props, ...children):卡片容器
|
||||||
- badge(props):徽标,variant = default | success | warning | danger
|
- badge(props):徽标,variant = default | success | warning | danger
|
||||||
- alert(props):提示条,variant = info | success | warning | danger
|
- alert(props):提示条,variant = info | success | warning | danger
|
||||||
- tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起
|
|
||||||
- spinner(props):加载指示器,size 控制直径
|
- spinner(props):加载指示器,size 控制直径
|
||||||
- progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色
|
- progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色
|
||||||
- tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签
|
- tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
## @ui-arch/ui (v0.1.0)
|
## @ui-arch/ui (v0.1.0)
|
||||||
|
|
||||||
- 类型: skin-dom · 目录: packages/skin/ui
|
- 类型: skin-dom · 目录: packages/skin/ui
|
||||||
- 描述: DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / tooltip / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。
|
- 描述: DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。
|
||||||
- API:
|
- API:
|
||||||
- button(props):按钮,variant = primary | ghost | danger
|
- button(props):按钮,variant = primary | ghost | danger
|
||||||
- textField(props):文本输入,value 信号双向绑定
|
- textField(props):文本输入,value 信号双向绑定
|
||||||
@@ -57,7 +57,6 @@
|
|||||||
- card(props, ...children):卡片容器
|
- card(props, ...children):卡片容器
|
||||||
- badge(props):徽标,variant = default | success | warning | danger
|
- badge(props):徽标,variant = default | success | warning | danger
|
||||||
- alert(props):提示条,variant = info | success | warning | danger
|
- alert(props):提示条,variant = info | success | warning | danger
|
||||||
- tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起
|
|
||||||
- spinner(props):加载指示器,size 控制直径
|
- spinner(props):加载指示器,size 控制直径
|
||||||
- progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色
|
- progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色
|
||||||
- tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签
|
- tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ export { radioGroup } from './radioGroup.js';
|
|||||||
export { card } from './card.js';
|
export { card } from './card.js';
|
||||||
export { badge } from './badge.js';
|
export { badge } from './badge.js';
|
||||||
export { alert } from './alert.js';
|
export { alert } from './alert.js';
|
||||||
export { tooltip } from './tooltip.js';
|
|
||||||
export { spinner } from './spinner.js';
|
export { spinner } from './spinner.js';
|
||||||
export { progress } from './progress.js';
|
export { progress } from './progress.js';
|
||||||
export { tabs } from './tabs.js';
|
export { tabs } from './tabs.js';
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
import { h, signal } from '@ui-arch/frame';
|
|
||||||
import type { TooltipProps } from './types.js';
|
|
||||||
|
|
||||||
let seq = 0; // 全局自增序号:保证每个气泡 id 唯一,供 aria-describedby 关联
|
|
||||||
|
|
||||||
/*** 悬浮提示:包裹触发器,hover / focus 延迟出场,移出 / 失焦 / Esc 收起,纯展示不拦截指针 ***/
|
|
||||||
export function tooltip(props: TooltipProps, trigger: HTMLElement): HTMLElement {
|
|
||||||
// —— 状态集中声明 ——
|
|
||||||
const open = signal(false); // 气泡显隐
|
|
||||||
const id = `ua-tip-${++seq}`; // 气泡唯一 id
|
|
||||||
const delay = props.delay ?? 150; // 出场延迟毫秒;<=0 视为立即显示
|
|
||||||
let timer: number | null = null; // 出场延迟计时器句柄
|
|
||||||
|
|
||||||
const show = () => {
|
|
||||||
if (timer != null) window.clearTimeout(timer); // 重复进入先清旧计时
|
|
||||||
if (delay <= 0) return open(true);
|
|
||||||
timer = window.setTimeout(() => {
|
|
||||||
timer = null;
|
|
||||||
open(true);
|
|
||||||
}, delay);
|
|
||||||
};
|
|
||||||
const hide = () => {
|
|
||||||
if (timer != null) { // 还没出场就离开:直接取消计时,避免闪一下
|
|
||||||
window.clearTimeout(timer);
|
|
||||||
timer = null;
|
|
||||||
}
|
|
||||||
open(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// —— 触发器与气泡 ——
|
|
||||||
trigger.setAttribute('aria-describedby', id); // 无障碍:读屏把提示文案关联到触发器
|
|
||||||
const bubble = h(
|
|
||||||
'span',
|
|
||||||
{
|
|
||||||
id,
|
|
||||||
class: () => `ua-tip ua-tip-${props.placement ?? 'top'}${open() ? ' ua-open' : ''}`,
|
|
||||||
role: 'tooltip',
|
|
||||||
'aria-hidden': () => String(!open()),
|
|
||||||
},
|
|
||||||
props.content,
|
|
||||||
);
|
|
||||||
const root = h('span', { class: 'ua-tip-wrap' }, trigger, bubble);
|
|
||||||
|
|
||||||
root.addEventListener('pointerenter', show); // 鼠标进入
|
|
||||||
root.addEventListener('pointerleave', hide); // 鼠标离开
|
|
||||||
root.addEventListener('focusin', show); // 键盘聚焦(focusin 会冒泡)
|
|
||||||
root.addEventListener('focusout', hide); // 失焦
|
|
||||||
root.addEventListener('keydown', (e: KeyboardEvent) => {
|
|
||||||
if (e.key === 'Escape') hide(); // Esc 立即收起,不必等延迟
|
|
||||||
});
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,6 @@
|
|||||||
import type { ColumnDef, RowKey } from '@ui-arch/table-core';
|
import type { ColumnDef, RowKey } from '@ui-arch/table-core';
|
||||||
import type { Signal } from '@ui-arch/frame';
|
import type { Signal } from '@ui-arch/frame';
|
||||||
|
|
||||||
/*** 悬浮提示入参 ***/
|
|
||||||
export interface TooltipProps {
|
|
||||||
content: string; // 提示文案(纯文本)
|
|
||||||
placement?: 'top' | 'bottom'; // 气泡方位;缺省 top(触发器上方)
|
|
||||||
delay?: number; // 出场延迟毫秒;缺省 150,传 0 立即显示
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** 按钮入参 ***/
|
/*** 按钮入参 ***/
|
||||||
export interface ButtonProps {
|
export interface ButtonProps {
|
||||||
label: string; // 按钮文案
|
label: string; // 按钮文案
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@ui-arch/ui",
|
"name": "@ui-arch/ui",
|
||||||
"type": "skin-dom",
|
"type": "skin-dom",
|
||||||
"description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / tooltip / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
|
"description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / spinner / progress / tabs / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
|
||||||
"tags": [
|
"tags": [
|
||||||
"components",
|
"components",
|
||||||
"dom",
|
"dom",
|
||||||
@@ -23,7 +23,6 @@
|
|||||||
"card(props, ...children):卡片容器",
|
"card(props, ...children):卡片容器",
|
||||||
"badge(props):徽标,variant = default | success | warning | danger",
|
"badge(props):徽标,variant = default | success | warning | danger",
|
||||||
"alert(props):提示条,variant = info | success | warning | danger",
|
"alert(props):提示条,variant = info | success | warning | danger",
|
||||||
"tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起",
|
|
||||||
"spinner(props):加载指示器,size 控制直径",
|
"spinner(props):加载指示器,size 控制直径",
|
||||||
"progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色",
|
"progress(props):进度条,轨道 + 渐变流动填充,value 信号驱动 0-100,满格切 success 色",
|
||||||
"tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签",
|
"tabs(props):标签页,active 信号双向绑定,滑动指示条 + 方向键环形导航,支持禁用页签",
|
||||||
@@ -44,7 +43,6 @@
|
|||||||
"CardProps",
|
"CardProps",
|
||||||
"BadgeProps",
|
"BadgeProps",
|
||||||
"AlertProps",
|
"AlertProps",
|
||||||
"TooltipProps",
|
|
||||||
"SpinnerProps",
|
"SpinnerProps",
|
||||||
"ProgressProps",
|
"ProgressProps",
|
||||||
"TabsProps",
|
"TabsProps",
|
||||||
@@ -63,7 +61,7 @@
|
|||||||
"语义色 variant 四档:default|info / success / warning / danger,一律来自令牌,禁止硬编码颜色"
|
"语义色 variant 四档:default|info / success / warning / danger,一律来自令牌,禁止硬编码颜色"
|
||||||
],
|
],
|
||||||
"docs": {
|
"docs": {
|
||||||
"intro": "17 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
|
"intro": "16 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
|
||||||
"steps": [
|
"steps": [
|
||||||
"安装依赖:pnpm add @ui-arch/ui @ui-arch/frame(workspace 内自动链接)",
|
"安装依赖:pnpm add @ui-arch/ui @ui-arch/frame(workspace 内自动链接)",
|
||||||
"引入样式:在应用入口 import '@ui-arch/ui/ui.css',暗色主题在根元素设 data-theme='dark'",
|
"引入样式:在应用入口 import '@ui-arch/ui/ui.css',暗色主题在根元素设 data-theme='dark'",
|
||||||
@@ -358,44 +356,6 @@
|
|||||||
"传入 message 即可,入场自带下滑动画"
|
"传入 message 即可,入场自带下滑动画"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "tooltip",
|
|
||||||
"title": "悬浮提示 Tooltip",
|
|
||||||
"demo": "sec-tooltip",
|
|
||||||
"props": [
|
|
||||||
{
|
|
||||||
"n": "content",
|
|
||||||
"t": "string",
|
|
||||||
"r": 1,
|
|
||||||
"d": "提示文案(纯文本)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"n": "placement",
|
|
||||||
"t": "'top' | 'bottom'",
|
|
||||||
"d": "气泡方位;缺省 top(触发器上方)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"n": "delay",
|
|
||||||
"t": "number",
|
|
||||||
"d": "出场延迟毫秒;缺省 150,传 0 立即显示"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"n": "trigger",
|
|
||||||
"t": "HTMLElement",
|
|
||||||
"r": 1,
|
|
||||||
"d": "第二个参数:被包裹的触发器元素(按钮 / 输入框等任意 DOM)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"example": "tooltip({ content: '保存后立即生效' }, button({ label: '保存', onClick: save }))",
|
|
||||||
"steps": [
|
|
||||||
"先创建触发器元素,如 const btn = button({ label: '保存' })",
|
|
||||||
"用 tooltip(props, trigger) 包一层:返回带气泡的包裹元素,原触发器仍是独立节点",
|
|
||||||
"鼠标移入或键盘聚焦约 150ms 后出场,移出 / 失焦立即收起;按 Esc 可立刻关闭",
|
|
||||||
"气泡默认在上方,空间不足或需要避让时传 placement: 'bottom'",
|
|
||||||
"气泡 pointer-events: none 不抢指针;判读依赖 aria-describedby + role='tooltip',读屏可读",
|
|
||||||
"只做展示:不要在气泡里放可点击元素,需要交互请用 modal 或自绘弹层"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "spinner",
|
"id": "spinner",
|
||||||
"title": "加载指示器 Spinner",
|
"title": "加载指示器 Spinner",
|
||||||
|
|||||||
@@ -613,39 +613,6 @@
|
|||||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--ua-color-accent) 18%, transparent);
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--ua-color-accent) 18%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* —— 悬浮提示 —— */
|
|
||||||
.ua-tip-wrap {
|
|
||||||
position: relative;
|
|
||||||
display: inline-flex;
|
|
||||||
}
|
|
||||||
.ua-tip {
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
z-index: 30;
|
|
||||||
max-width: 220px;
|
|
||||||
padding: var(--ua-space-1) var(--ua-space-2);
|
|
||||||
border-radius: var(--ua-radius-sm);
|
|
||||||
background: var(--ua-color-text);
|
|
||||||
color: var(--ua-color-bg);
|
|
||||||
font-size: var(--ua-font-size-sm);
|
|
||||||
line-height: 1.5;
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.16s ease-out, transform 0.16s ease-out;
|
|
||||||
}
|
|
||||||
.ua-tip-top {
|
|
||||||
bottom: calc(100% + 6px);
|
|
||||||
transform: translateX(-50%) translateY(3px);
|
|
||||||
}
|
|
||||||
.ua-tip-bottom {
|
|
||||||
top: calc(100% + 6px);
|
|
||||||
transform: translateX(-50%) translateY(-3px);
|
|
||||||
}
|
|
||||||
.ua-tip.ua-open {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(-50%) translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* —— 无障碍:用户偏好减少动效时关闭全部动画 —— */
|
/* —— 无障碍:用户偏好减少动效时关闭全部动画 —— */
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.ua-btn,
|
.ua-btn,
|
||||||
@@ -663,7 +630,6 @@
|
|||||||
.ua-progress-fill,
|
.ua-progress-fill,
|
||||||
.ua-progress-fill::after,
|
.ua-progress-fill::after,
|
||||||
.ua-alert,
|
.ua-alert,
|
||||||
.ua-tip,
|
|
||||||
.ua-form-error,
|
.ua-form-error,
|
||||||
.ua-modal,
|
.ua-modal,
|
||||||
.ua-modal-overlay {
|
.ua-modal-overlay {
|
||||||
|
|||||||
@@ -491,11 +491,6 @@ function collectSourceFiles() {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** 把字符串 / 模板字面量整体替换为等长空格,便于按位置定位真实注释(避开 URL、正则里的 //) ***/
|
|
||||||
function blankStrings(line) {
|
|
||||||
return line.replace(/(['"`])(?:\\.|(?!\1)[^\\])*\1/g, (m) => ' '.repeat(m.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** 检查单文件:导出缺注释块、接口字段缺行尾注释、行注释非中文 ***/
|
/*** 检查单文件:导出缺注释块、接口字段缺行尾注释、行注释非中文 ***/
|
||||||
function styleCheckFile(file, src) {
|
function styleCheckFile(file, src) {
|
||||||
const issues = [];
|
const issues = [];
|
||||||
@@ -533,7 +528,7 @@ function styleCheckFile(file, src) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hash = blankStrings(raw).indexOf('//'); // 注释定位:先剥离字面量,'https://' 不算注释
|
const hash = raw.indexOf('//');
|
||||||
if (hash >= 0) {
|
if (hash >= 0) {
|
||||||
const text = raw.slice(hash + 2);
|
const text = raw.slice(hash + 2);
|
||||||
const isPragma = /^[\s*/]*(eslint|@ts-|prettier-ignore|istanbul|c8|node:)/i.test(text);
|
const isPragma = /^[\s*/]*(eslint|@ts-|prettier-ignore|istanbul|c8|node:)/i.test(text);
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
/*** 作用:Gitea REST API 调用包装器,用法 node scripts/gitea-api.mjs <METHOD> <path不带前导斜杠> [jsonBody],令牌读自 .gitea-token ***/
|
|
||||||
import { readFileSync } from 'node:fs';
|
|
||||||
|
|
||||||
// 仓库与令牌
|
|
||||||
const base = 'https://gitea.yinyuanjingling.icu/api/v1';
|
|
||||||
const token = readFileSync(new URL('../.gitea-token', import.meta.url), 'utf8').trim();
|
|
||||||
const [method = 'GET', path = '', body = ''] = process.argv.slice(2);
|
|
||||||
// 卫语句:缺参数退出
|
|
||||||
if (!method || !path) { console.error('用法: node scripts/gitea-api.mjs <METHOD> <path> [jsonBody]'); process.exit(2); }
|
|
||||||
|
|
||||||
// 发起请求并输出结果(path 不带前导斜杠,规避 Git Bash MSYS 路径转换篡改)
|
|
||||||
const res = await fetch(`${base}/${path.replace(/^\//, '')}`, {
|
|
||||||
method: method.toUpperCase(),
|
|
||||||
headers: { 'Authorization': `token ${token}`, 'Content-Type': 'application/json' },
|
|
||||||
body: body || undefined,
|
|
||||||
});
|
|
||||||
const text = await res.text();
|
|
||||||
console.log(`HTTP ${res.status}\n${text}`);
|
|
||||||
process.exit(res.ok ? 0 : 1);
|
|
||||||
Reference in New Issue
Block a user