iter(g207): progress 支持自定义进度文本
This commit is contained in:
+7
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "ui-arch-registry-index/0.1",
|
"$schema": "ui-arch-registry-index/0.1",
|
||||||
"generatedAt": "2026-10-26T11:16:26.554Z",
|
"generatedAt": "2026-10-26T11:17:54.464Z",
|
||||||
"repoRoot": ".",
|
"repoRoot": ".",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
@@ -1412,6 +1412,12 @@
|
|||||||
"n": "variant",
|
"n": "variant",
|
||||||
"t": "'default' | 'success' | 'warning' | 'danger'",
|
"t": "'default' | 'success' | 'warning' | 'danger'",
|
||||||
"d": "填充语义色;缺省 default(满格自动切 success)"
|
"d": "填充语义色;缺省 default(满格自动切 success)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"n": "format",
|
||||||
|
"t": "(v: number) => string",
|
||||||
|
"k": 1,
|
||||||
|
"d": "文本自定义:传入则线/环形的进度文本用其返回值替代默认「N%」;缺省取整百分比"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"example": "const pct = signal(0); progress({ value: pct }); setInterval(() => pct((pct() + 5) % 105), 400)",
|
"example": "const pct = signal(0); progress({ value: pct }); setInterval(() => pct((pct() + 5) % 105), 400)",
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||||
|
|
||||||
> 自动生成于 2026-10-26T11:16:26.554Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
> 自动生成于 2026-10-26T11:17:54.464Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||||
|
|
||||||
## 快速上手
|
## 快速上手
|
||||||
@@ -685,6 +685,7 @@ spinner(); spinner({ size: 26 })
|
|||||||
- showText:boolean —— 是否右侧显示百分比;缺省 true(不确定态忽略)
|
- showText:boolean —— 是否右侧显示百分比;缺省 true(不确定态忽略)
|
||||||
- label:string —— 可访问名,如「上传进度」;缺省不确定态念「进行中」
|
- label:string —— 可访问名,如「上传进度」;缺省不确定态念「进行中」
|
||||||
- variant:'default' | 'success' | 'warning' | 'danger' —— 填充语义色;缺省 default(满格自动切 success)
|
- variant:'default' | 'success' | 'warning' | 'danger' —— 填充语义色;缺省 default(满格自动切 success)
|
||||||
|
- format(回调):(v: number) => string —— 文本自定义:传入则线/环形的进度文本用其返回值替代默认「N%」;缺省取整百分比
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { effect, h } from '@ui-arch/frame';
|
|||||||
import type { Signal } from '@ui-arch/frame';
|
import type { Signal } from '@ui-arch/frame';
|
||||||
import type { ProgressProps } from './types.js';
|
import type { ProgressProps } from './types.js';
|
||||||
|
|
||||||
/*** 进度条:value 信号驱动 0-100 定量态(缺省则不确定态),type='circle' 且传 value 时出环形;满格切 success 色 ***/
|
/*** 进度条:value 信号驱动 0-100 定量态(缺省则不确定态),type='circle' 且传 value 时出环形;满格切 success 色,format 可自定义文本 ***/
|
||||||
export function progress(props: ProgressProps = {}): HTMLElement {
|
export function progress(props: ProgressProps = {}): HTMLElement {
|
||||||
// —— 状态集中声明 ——
|
// —— 状态集中声明 ——
|
||||||
const value = props.value; // 可选:不传即不确定态
|
const value = props.value; // 可选:不传即不确定态
|
||||||
@@ -13,17 +13,18 @@ export function progress(props: ProgressProps = {}): HTMLElement {
|
|||||||
const label = props.label; // 可访问名:读屏念「上传进度 50%」而不是干巴巴的百分比
|
const label = props.label; // 可访问名:读屏念「上传进度 50%」而不是干巴巴的百分比
|
||||||
const variant = props.variant ?? 'default'; // 语义色:default 之外都带类名,满格时仍以 variant 为准
|
const variant = props.variant ?? 'default'; // 语义色:default 之外都带类名,满格时仍以 variant 为准
|
||||||
const cls = `ua-progress${variant === 'default' ? '' : ` ua-progress-${variant}`}`;
|
const cls = `ua-progress${variant === 'default' ? '' : ` ua-progress-${variant}`}`;
|
||||||
|
const textOf = (v: number): string => (props.format ? props.format(v) : `${Math.round(v)}%`); // 进度文本统一出口:format 优先
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
fill.classList.add('ua-indeterminate'); // 宽度与往复动画交给 CSS
|
fill.classList.add('ua-indeterminate'); // 宽度与往复动画交给 CSS
|
||||||
return h('div', { class: cls, role: 'progressbar', 'aria-label': label ?? '进行中' }, track);
|
return h('div', { class: cls, role: 'progressbar', 'aria-label': label ?? '进行中' }, track);
|
||||||
}
|
}
|
||||||
if (props.type === 'circle') return ring(value, label, variant, withText); // 环形:SVG 版
|
if (props.type === 'circle') return ring(value, label, variant, withText, textOf); // 环形:SVG 版
|
||||||
effect(() => {
|
effect(() => {
|
||||||
const v = clamp(value()); // 依赖收集:信号变化自动写回
|
const v = clamp(value()); // 依赖收集:信号变化自动写回
|
||||||
fill.style.width = `${v}%`;
|
fill.style.width = `${v}%`;
|
||||||
fill.classList.toggle('ua-done', v >= 100); // 满格切语义色
|
fill.classList.toggle('ua-done', v >= 100); // 满格切语义色
|
||||||
text.textContent = `${Math.round(v)}%`;
|
text.textContent = textOf(v);
|
||||||
});
|
});
|
||||||
return h(
|
return h(
|
||||||
'div',
|
'div',
|
||||||
@@ -47,7 +48,7 @@ function clamp(v: number): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*** 环形进度:SVG 双圆用 dashoffset 表达弧长(必须 createElementNS,h() 造不出可渲染的 SVG) ***/
|
/*** 环形进度:SVG 双圆用 dashoffset 表达弧长(必须 createElementNS,h() 造不出可渲染的 SVG) ***/
|
||||||
function ring(value: Signal<number>, label: string | undefined, variant: string, withText: boolean): HTMLElement {
|
function ring(value: Signal<number>, label: string | undefined, variant: string, withText: boolean, textOf: (v: number) => string): HTMLElement {
|
||||||
const NS = 'http://www.w3.org/2000/svg'; // SVG 命名空间
|
const NS = 'http://www.w3.org/2000/svg'; // SVG 命名空间
|
||||||
const R = 26; // 半径:viewBox 64 两侧留出线宽
|
const R = 26; // 半径:viewBox 64 两侧留出线宽
|
||||||
const C = 2 * Math.PI * R; // 周长:dasharray 的基准长度
|
const C = 2 * Math.PI * R; // 周长:dasharray 的基准长度
|
||||||
@@ -70,8 +71,8 @@ function ring(value: Signal<number>, label: string | undefined, variant: string,
|
|||||||
effect(() => {
|
effect(() => {
|
||||||
const v = clamp(value());
|
const v = clamp(value());
|
||||||
arc.setAttribute('stroke-dashoffset', String(C * (1 - v / 100))); // 弧长按比例收缩
|
arc.setAttribute('stroke-dashoffset', String(C * (1 - v / 100))); // 弧长按比例收缩
|
||||||
txt.textContent = `${Math.round(v)}%`;
|
txt.textContent = textOf(v);
|
||||||
svg.setAttribute('aria-label', `${label ?? '进度'} ${Math.round(v)}%`); // 环形没有原生 progressbar,名称自己拼
|
svg.setAttribute('aria-label', `${label ?? '进度'} ${textOf(v)}`); // 环形没有原生 progressbar,名称自己拼
|
||||||
});
|
});
|
||||||
return h('div', { class: 'ua-progress ua-progress-circle' }, svg as unknown as HTMLElement) as HTMLElement;
|
return h('div', { class: 'ua-progress ua-progress-circle' }, svg as unknown as HTMLElement) as HTMLElement;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -350,6 +350,7 @@ export interface ProgressProps {
|
|||||||
showText?: boolean; // 是否右侧显示百分比;缺省 true(不确定态忽略)
|
showText?: boolean; // 是否右侧显示百分比;缺省 true(不确定态忽略)
|
||||||
label?: string; // 可访问名,如「上传进度」;缺省不确定态念「进行中」,定量态无名称
|
label?: string; // 可访问名,如「上传进度」;缺省不确定态念「进行中」,定量态无名称
|
||||||
variant?: 'default' | 'success' | 'warning' | 'danger'; // 填充语义色;缺省 default(满格自动切 success)
|
variant?: 'default' | 'success' | 'warning' | 'danger'; // 填充语义色;缺省 default(满格自动切 success)
|
||||||
|
format?: (v: number) => string; // 文本自定义:传入则线/环形的进度文本用其返回值替代默认「N%」;缺省取整百分比
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** 页签项:通用选项 + 可关闭开关 ***/
|
/*** 页签项:通用选项 + 可关闭开关 ***/
|
||||||
|
|||||||
@@ -1283,6 +1283,12 @@
|
|||||||
"n": "variant",
|
"n": "variant",
|
||||||
"t": "'default' | 'success' | 'warning' | 'danger'",
|
"t": "'default' | 'success' | 'warning' | 'danger'",
|
||||||
"d": "填充语义色;缺省 default(满格自动切 success)"
|
"d": "填充语义色;缺省 default(满格自动切 success)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"n": "format",
|
||||||
|
"t": "(v: number) => string",
|
||||||
|
"k": 1,
|
||||||
|
"d": "文本自定义:传入则线/环形的进度文本用其返回值替代默认「N%」;缺省取整百分比"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"example": "const pct = signal(0); progress({ value: pct }); setInterval(() => pct((pct() + 5) % 105), 400)",
|
"example": "const pct = signal(0); progress({ value: pct }); setInterval(() => pct((pct() + 5) % 105), 400)",
|
||||||
|
|||||||
Reference in New Issue
Block a user