iter(g216): 时间选择支持清空

This commit is contained in:
HIsheR
2026-10-26 19:57:20 +08:00
parent 050534a07f
commit 17da5618f5
6 changed files with 67 additions and 4 deletions
+26 -1
View File
@@ -28,6 +28,14 @@ export function timePicker(props: TimePickerProps): HTMLElement {
props.onChange?.(next);
};
/*** 清空:回到「未选」态,收起弹层并写回空串(与 select / multiSelect 的清空语义一致) ***/
const clear = () => {
if (!value()) return; // 卫语句:本来就没选,不重复派发回调
value('');
props.onChange?.('');
open(false);
};
/*** 列内聚焦导航:↑↓ 环形移动、Home/End 直达首末(列内按钮顺序即时间顺序) ***/
const navigate = (col: HTMLElement, cells: HTMLButtonElement[]) => {
col.addEventListener('keydown', (e: KeyboardEvent) => {
@@ -82,13 +90,23 @@ export function timePicker(props: TimePickerProps): HTMLElement {
h('span', { class: 'ua-timepicker-arrow', 'aria-hidden': 'true' }, '▾'),
);
// —— 清空按钮:clearable 且有值时出现,压在触发器右缘(与箭头错开)——
const clearable = props.clearable ?? false; // 缺省不带清空:没选的场景多,按钮会白占位置
const clearBtn = h('button', {
type: 'button',
class: 'ua-timepicker-clear',
'aria-label': '清空时间',
tabindex: '-1', // 不进 Tab 序:清空是鼠标 / 触屏便利,键盘用 Delete / Backspace
onClick: () => clear(),
}, '×') as HTMLElement;
const pop = h(
'div',
{ class: () => `ua-timepicker-pop${open() ? ' ua-open' : ''}${place() === 'top' ? ' is-flip' : ''}`, role: 'dialog', 'aria-label': '选择时间' },
hourCol.col,
minuteCol.col,
);
const root = h('div', { class: () => `ua-timepicker${open() ? ' is-open' : ''}` }, trigger, pop);
const root = h('div', { class: () => `ua-timepicker${open() ? ' is-open' : ''}${props.clearable && value() ? ' has-clear' : ''}` }, trigger, clearable ? clearBtn : null, pop);
/*** 把激活格滚到列中部:列是独立滚动容器,直接算 scrollTop 不惊动页面 ***/
const reveal = (col: HTMLElement, cells: HTMLButtonElement[]) => {
@@ -98,6 +116,13 @@ export function timePicker(props: TimePickerProps): HTMLElement {
col.scrollTop = Math.max(0, target);
};
effect(() => { clearBtn.hidden = !clearable || !value(); }); // 无值或未开启时藏起来(hidden 一并移出点击区)
root.addEventListener('keydown', (e: KeyboardEvent) => {
if (open() || !clearable) return; // 卫语句:展开时按键归列内导航,未开启清空则不接管
if (e.key !== 'Backspace' && e.key !== 'Delete') return; // 卫语句:只接管这两个键
e.preventDefault();
clear(); // 键盘等价:不必伸手去点 ×
});
bindOutside(root, open, () => open(false)); // 点外部收起:仅展开期间挂监听
effect(() => {
if (open()) {