iter(g17): select 键入字母快跳选项

This commit is contained in:
HIsheR
2026-10-26 11:00:17 +08:00
parent 2e48d9413f
commit 27d797ab63
7 changed files with 30 additions and 8 deletions
+15 -1
View File
@@ -51,6 +51,19 @@ export function select(props: SelectProps): HTMLElement {
const root = h('div', { class: () => `ua-select${open() ? ' ua-open' : ''}` }, trigger, pop); // 根带开合类,供箭头旋转
// —— 键入快跳缓冲 ——
let typed = ''; // 最近键入的字母串,用于前缀匹配
let typedAt = 0; // 最近键入时间戳,超 1 秒重置缓冲
const jumpByTyped = (ch: string): void => {
const now = Date.now();
typed = now - typedAt > 1000 ? ch : typed + ch; // 超时重新起词,否则追加
typedAt = now;
const at = options.indexOf(document.activeElement as HTMLElement); // 当前焦点序号,作为环形搜索起点
const order = options.map((_, i) => (at + 1 + i) % options.length); // 从下一项开始环形排列的序号
const hit = order.find((i) => props.options[i].label.toLowerCase().startsWith(typed.toLowerCase())); // 前缀匹配(忽略大小写)
if (hit != null) options[hit]?.focus(); // 命中即聚焦;无命中留在原地
};
root.addEventListener('keydown', (e: KeyboardEvent) => {
if (e.key === 'Escape') { open(false); trigger.focus(); return; } // Esc 关闭并回焦触发器
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
@@ -63,7 +76,8 @@ export function select(props: SelectProps): HTMLElement {
return;
}
if (e.key === 'Home' && open()) { e.preventDefault(); options[0]?.focus(); return; } // Home 跳首项
if (e.key === 'End' && open()) { e.preventDefault(); options[options.length - 1]?.focus(); } // End 跳末项
if (e.key === 'End' && open()) { e.preventDefault(); options[options.length - 1]?.focus(); return; } // End 跳末项
if (open() && e.key.length === 1) jumpByTyped(e.key); // 可打印字符:键入快跳(Home/End/方向键已提前接管)
});
document.addEventListener('click', (e) => {
if (root.contains(e.target as Node)) return; // 卫语句:组件内点击不处理
+1 -1
View File
@@ -20,7 +20,7 @@
"slider(props):滑块,value 信号双向绑定,min/max/step 可配,原生 range 承载键盘交互,右侧可显示当前值",
"checkbox(props):复选框,checked 信号双向绑定,disabled 支持布尔或信号禁用",
"switchButton(props):开关,checked 信号双向绑定,disabled 支持布尔或信号禁用",
"select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画,disabled 支持布尔或信号禁用,空间不足自动翻转",
"select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画,disabled 支持布尔或信号禁用,空间不足自动翻转,键入字母快跳选项",
"menu(props):下拉菜单,触发器 + 自绘弹层,条目支持禁用 / 危险 / 分隔线,↑↓ 环形导航,点外部 / Esc 关闭,空间不足自动翻转",
"flip(trigger, panel, preferred):浮层上下翻转判定,按触发器与面板的视口几何决定 preferred 方位放不下时是否翻转,返回实际生效方位 'top' | 'bottom'",
"radioGroup(props):单选组,options + value 信号双向绑定,disabled 整组禁用",