diff --git a/.ua/backlog.json b/.ua/backlog.json index 1ffc75c..d301c8f 100644 --- a/.ua/backlog.json +++ b/.ua/backlog.json @@ -1516,6 +1516,14 @@ "acceptance": "avatarGroup 支持 items(name/src/variant)、max 折叠为 +N、size 与 avatar 对齐;整组 title 列全部姓名、+N 有可访问名;样式只消费 --ua-*;文档与演示同步;npm run check 全绿", "notes": "自补:组件补充方向", "status": "done" + }, + { + "id": "g145", + "title": "滑块支持刻度标注 marks", + "motivation": "0-100 的滑块看不出档位含义,用户只能看右侧数字猜;调用方要在轨道下标 0/50/100 得自己量宽度算百分比", + "acceptance": "slider 新增 marks(value/label),按 min-max 换算百分比绝对定位、随宽度自适应;轨道包一层不影响右侧数值;刻度 aria-hidden;文档与演示同步;npm run check 全绿", + "notes": "自补:既有组件可用性细节", + "status": "open" } ] } diff --git a/.ua/index.json b/.ua/index.json index 0b274ca..7054936 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-26T07:39:42.119Z", + "generatedAt": "2026-10-26T07:41:03.284Z", "repoRoot": ".", "packages": [ { @@ -568,6 +568,11 @@ "d": "是否右侧显示当前值;缺省 true", "df": "true" }, + { + "n": "marks", + "t": "{ value: number; label?: string }[]", + "d": "刻度标注:按值定位在轨道下方,label 缺省显示数值;纯装饰不进读屏(数值由原生 input 播报)" + }, { "n": "onChange", "t": "(value: number) => void", @@ -581,7 +586,8 @@ "用 min / max / step 限定范围与粒度,如 step: 5 只取 5 的倍数", "拖动或按 ←→ 键改变值:原生 range 自带键盘与触屏交互,无需额外处理", "只想看拖动条不显示数字时传 showValue: false;需要自定义展示可自行读 signal", - "禁用场景传 disabled(布尔或信号),置灰且不可拖" + "禁用场景传 disabled(布尔或信号),置灰且不可拖", + "需要在轨道下方标刻度(如 0 / 50 / 100 的档位含义)传 marks:[{ value, label }],按 min-max 换算百分比定位,容器宽度变化时自动跟随" ] }, { diff --git a/apps/demo/main.ts b/apps/demo/main.ts index 38a060c..ca9d210 100644 --- a/apps/demo/main.ts +++ b/apps/demo/main.ts @@ -422,6 +422,7 @@ const content = h( { class: 'row' }, slider({ value: volume, min: 0, max: 100, step: 5, onChange: (v) => toast.info(`音量 ${v}`) }), slider({ value: volume, disabled: locked }), + slider({ value: volume, marks: [{ value: 0, label: '静音' }, { value: 50, label: '中' }, { value: 100, label: '最大' }], onChange: (v) => toast.info(`音量 ${v}`) }), ), ), section( diff --git a/llms-full.txt b/llms-full.txt index fcd65da..cd5f7ae 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-26T07:39:42.119Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-26T07:41:03.284Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -197,6 +197,7 @@ const bio = signal(''); textarea({ value: bio, rows: 4, placeholder: '一句话 - step(默认 1):number —— 步长;缺省 1 - disabled:boolean | Signal —— 禁用态:布尔直接置位,传信号则动态同步 - showValue(默认 true):boolean —— 是否右侧显示当前值;缺省 true +- marks:{ value: number; label?: string }[] —— 刻度标注:按值定位在轨道下方,label 缺省显示数值;纯装饰不进读屏(数值由原生 input 播报) - onChange(回调):(value: number) => void —— 拖动回调 示例: @@ -212,6 +213,7 @@ const vol = signal(40); slider({ value: vol, min: 0, max: 100, step: 5, onChange 3. 拖动或按 ←→ 键改变值:原生 range 自带键盘与触屏交互,无需额外处理 4. 只想看拖动条不显示数字时传 showValue: false;需要自定义展示可自行读 signal 5. 禁用场景传 disabled(布尔或信号),置灰且不可拖 +6. 需要在轨道下方标刻度(如 0 / 50 / 100 的档位含义)传 marks:[{ value, label }],按 min-max 换算百分比定位,容器宽度变化时自动跟随 现场演示:apps/docs/demo.html#sec-slider diff --git a/packages/skin/ui/src/slider.ts b/packages/skin/ui/src/slider.ts index 1994e51..2059fa7 100644 --- a/packages/skin/ui/src/slider.ts +++ b/packages/skin/ui/src/slider.ts @@ -1,14 +1,16 @@ import { effect, h } from '@ui-arch/frame'; import type { SliderProps } from './types.js'; -/*** 滑块:原生 range 承载交互与键盘,value 信号双向绑定;轨道配色走 accent-color 令牌 ***/ +/*** 滑块:原生 range 承载交互与键盘,value 信号双向绑定;marks 在轨道下方标出刻度文案 ***/ export function slider(props: SliderProps): HTMLElement { const value = props.value; // 必需信号:组件不持有数值,一律委托调用方 + const min = props.min ?? 0; // 与 input 的缺省保持一致,供刻度换算百分比 + const max = props.max ?? 100; const input = h('input', { type: 'range', class: 'ua-slider-input', - min: props.min ?? 0, - max: props.max ?? 100, + min, + max, step: props.step ?? 1, disabled: props.disabled, // 布尔或信号禁用,h() 直接透传 }) as HTMLInputElement; @@ -23,10 +25,19 @@ export function slider(props: SliderProps): HTMLElement { if (input.value !== next) input.value = next; // 外部赋值同步滑块位置(等值不重写,避免打断拖动) }); + // 刻度:按值算百分比定位,纯装饰不进读屏(数值本身由原生 input 播报) + const marks = props.marks?.length + ? h('div', { class: 'ua-slider-marks', 'aria-hidden': 'true' }, + ...props.marks.map((mark) => h('span', { + class: 'ua-slider-mark', + style: `left:${((mark.value - min) / (max - min || 1)) * 100}%`, // 分母兜底,避免 min=max 时除零 + }, mark.label ?? String(mark.value)))) + : null; + return h( 'div', { class: 'ua-slider' }, - input, + h('div', { class: 'ua-slider-track' }, input, marks), // 轨道包一层:刻度只跟滑块对齐,不影响右侧数值 props.showValue === false ? null : h('span', { class: 'ua-slider-value' }, () => String(value())), ); } diff --git a/packages/skin/ui/src/types.ts b/packages/skin/ui/src/types.ts index f2e9729..e679c82 100644 --- a/packages/skin/ui/src/types.ts +++ b/packages/skin/ui/src/types.ts @@ -181,6 +181,7 @@ export interface SliderProps { step?: number; // 步长;缺省 1 disabled?: boolean | Signal; // 禁用态:布尔直接置位,传信号则动态同步 showValue?: boolean; // 是否右侧显示当前值;缺省 true + marks?: { value: number; label?: string }[]; // 刻度标注:按值定位在轨道下方,label 缺省显示数值;纯装饰不进读屏 onChange?: (value: number) => void; // 拖动回调 } diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index 3944d32..e637955 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -439,6 +439,11 @@ "d": "是否右侧显示当前值;缺省 true", "df": "true" }, + { + "n": "marks", + "t": "{ value: number; label?: string }[]", + "d": "刻度标注:按值定位在轨道下方,label 缺省显示数值;纯装饰不进读屏(数值由原生 input 播报)" + }, { "n": "onChange", "t": "(value: number) => void", @@ -452,7 +457,8 @@ "用 min / max / step 限定范围与粒度,如 step: 5 只取 5 的倍数", "拖动或按 ←→ 键改变值:原生 range 自带键盘与触屏交互,无需额外处理", "只想看拖动条不显示数字时传 showValue: false;需要自定义展示可自行读 signal", - "禁用场景传 disabled(布尔或信号),置灰且不可拖" + "禁用场景传 disabled(布尔或信号),置灰且不可拖", + "需要在轨道下方标刻度(如 0 / 50 / 100 的档位含义)传 marks:[{ value, label }],按 min-max 换算百分比定位,容器宽度变化时自动跟随" ] }, { diff --git a/packages/skin/ui/ui.css b/packages/skin/ui/ui.css index 0936569..77c103a 100644 --- a/packages/skin/ui/ui.css +++ b/packages/skin/ui/ui.css @@ -4461,3 +4461,24 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); } color: var(--ua-color-text); font-weight: 500; } + +/* —— 滑块轨道与刻度:轨道包一层,刻度按百分比定位在下方 —— */ +.ua-slider-track { + position: relative; + display: flex; + flex: 1; + flex-direction: column; + gap: 2px; +} +.ua-slider-marks { + position: relative; + height: 14px; +} +.ua-slider-mark { + position: absolute; + transform: translateX(-50%); + color: var(--ua-color-text-muted); + font-size: var(--ua-font-size-sm); + line-height: 14px; + white-space: nowrap; +}