import { effect, h } from '@ui-arch/frame'; import type { StepperProps } from './types.js'; /*** 步骤条:done/current/upcoming 三态横向流程指示,clickable 时已完成步骤可点回跳并写回 active 信号 ***/ export function stepper(props: StepperProps): HTMLElement { const active = props.active; const clickStep = (i: number): void => { if (!props.clickable || i >= active()) return; // 卫语句:不可点或未完成不回跳 active(i); if (props.onChange) props.onChange(i); }; // 写回信号并回调 const render = (): HTMLElement => { const cur = active(); const items = props.steps.map((s, i) => { const state = i < cur ? 'done' : i === cur ? 'current' : 'upcoming'; // 三态:已完成 / 当前 / 未到 const mark = state === 'done' ? '✓' : String(i + 1); // 完成打勾,其余显示序号 const clickable = !!props.clickable && i < cur; // 仅已完成步骤可回跳 const head = clickable ? h('button', { class: 'ua-step-dot', type: 'button', onClick: () => clickStep(i) }, mark) : h('span', { class: 'ua-step-dot' }, mark); const body = h('div', { class: 'ua-step-text' }, h('span', { class: 'ua-step-label' }, s.label), s.description ? h('span', { class: 'ua-step-desc' }, s.description) : null); const li = h('li', { class: `ua-step ua-step-${state}`, 'aria-current': state === 'current' ? 'step' : null }, head, body); return li; }); return h('ol', { class: 'ua-stepper' }, ...items); }; let el!: HTMLElement; // 当前渲染产物(effect 首跑赋值) effect(() => { const next = render(); if (el) el.replaceWith(next); el = next; }); // active 变化整条重渲染(条目少,开销可忽略) return el; }