From 82f48aaca10b065390ff798782e156625e86a9f3 Mon Sep 17 00:00:00 2001 From: HIsheR Date: Fri, 23 Oct 2026 17:08:53 +0800 Subject: [PATCH] =?UTF-8?q?iter:=20d26=20select=20=E9=94=AE=E7=9B=98?= =?UTF-8?q?=E5=AF=BC=E8=88=AA=EF=BC=88=E2=86=91=E2=86=93=20=E7=8E=AF?= =?UTF-8?q?=E5=BD=A2=E7=A7=BB=E5=8A=A8=E3=80=81Home/End=E3=80=81Esc=20?= =?UTF-8?q?=E5=9B=9E=E7=84=A6=E8=A7=A6=E5=8F=91=E5=99=A8=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .ua/index.json | 2 +- packages/skin/ui/src/select.ts | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.ua/index.json b/.ua/index.json index dffe5c2..e15295b 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-23T09:06:10.925Z", + "generatedAt": "2026-10-23T09:08:47.698Z", "repoRoot": ".", "packages": [ { diff --git a/packages/skin/ui/src/select.ts b/packages/skin/ui/src/select.ts index 15e0ef7..917ae31 100644 --- a/packages/skin/ui/src/select.ts +++ b/packages/skin/ui/src/select.ts @@ -1,7 +1,7 @@ import { effect, h, signal } from '@ui-arch/frame'; import type { SelectProps } from './types.js'; -/*** 下拉选择:自绘弹层替代原生 select,value 信号双向绑定;点选项 / 点外部 / Esc 关闭 ***/ +/*** 下拉选择:自绘弹层替代原生 select,value 信号双向绑定;支持 ↑↓/Home/End 键盘导航,点选项 / 点外部 / Esc 关闭 ***/ export function select(props: SelectProps): HTMLElement { // —— 状态集中声明 —— const open = signal(false); // 弹层开合 @@ -50,7 +50,18 @@ export function select(props: SelectProps): HTMLElement { const root = h('div', { class: () => `ua-select${open() ? ' ua-open' : ''}` }, trigger, pop); // 根带开合类,供箭头旋转 root.addEventListener('keydown', (e: KeyboardEvent) => { - if (e.key === 'Escape') open(false); // Esc 关闭弹层 + if (e.key === 'Escape') { open(false); trigger.focus(); return; } // Esc 关闭并回焦触发器 + if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { + e.preventDefault(); // 阻止页面滚动 + if (!open()) { open(true); options[0]?.focus(); return; } // 未展开:展开并聚焦首个选项 + const idx = options.indexOf(document.activeElement as HTMLElement); // 展开中:在选项间环形移动 + const dir = e.key === 'ArrowDown' ? 1 : -1; + const next = (idx + dir + options.length) % options.length; + options[next]?.focus(); + 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 跳末项 }); document.addEventListener('click', (e) => { if (root.contains(e.target as Node)) return; // 卫语句:组件内点击不处理