From ed2dd1513fb91cf5e968f86ff83877df98852fa7 Mon Sep 17 00:00:00 2001 From: HIsheR Date: Mon, 26 Oct 2026 19:59:22 +0800 Subject: [PATCH] =?UTF-8?q?iter(g218):=20=E6=9C=AA=E9=80=89=E5=80=BC?= =?UTF-8?q?=E6=97=B6=E4=B8=A4=E5=88=97=E5=81=9C=E5=9C=A8=E6=AD=A4=E5=88=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- llms-full.txt | 4 ++-- packages/skin/ui/src/timePicker.ts | 15 ++++++++++----- packages/skin/ui/ua.manifest.json | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/llms-full.txt b/llms-full.txt index 91dbae4..997f9ac 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-26T11:56:46.981Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-26T11:59:09.023Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -2008,7 +2008,7 @@ const at = signal('09:30'); timePicker({ value: at, minuteStep: 15, onChange: (t 手把手: 1. 创建信号 at = signal('09:30') 并传入 value:组件读它显示、选完写回,双向绑定 -2. 点触发器展开时 / 分两列,当前值所在格高亮并自动滚到列中部,不必手动找 +2. 点触发器展开时 / 分两列:当前值所在格高亮并自动滚到列中部;还没选过时停在此刻(当前小时 / 当前分钟档),打开即可就近选 3. 先点时列定小时(分默认落到首个步长值,值立刻可用),再点分列即完成并收起,焦点回到触发器 4. 列内可用 ↑↓ 环形移动、Home/End 直达首末;Tab、Esc、点击外部都能正常进出与收起 5. 需要 15 分钟一档就传 minuteStep: 15,步长只影响分列的可选值,时列始终 24 档 diff --git a/packages/skin/ui/src/timePicker.ts b/packages/skin/ui/src/timePicker.ts index 098f4ce..c953736 100644 --- a/packages/skin/ui/src/timePicker.ts +++ b/packages/skin/ui/src/timePicker.ts @@ -108,10 +108,11 @@ export function timePicker(props: TimePickerProps): HTMLElement { ); 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[]) => { - const cell = cells.find((el) => el.classList.contains('is-active')); - if (!cell) return; // 卫语句:还没选过,停在列首 + /*** 把目标格滚到列中部:优先当前值所在格,还没选过时退到「此刻」的格,打开即可就近选 ***/ + const reveal = (col: HTMLElement, cells: HTMLButtonElement[], fallback: number) => { + const at = cells.findIndex((el) => el.classList.contains('is-active')); + const cell = cells[at >= 0 ? at : Math.min(Math.max(fallback, 0), cells.length - 1)]; + if (!cell) return; // 卫语句:空列(步长异常)不滚 const target = cell.offsetTop - (col.clientHeight - cell.offsetHeight) / 2; // 居中,上下都留出邻近项 col.scrollTop = Math.max(0, target); }; @@ -127,7 +128,11 @@ export function timePicker(props: TimePickerProps): HTMLElement { effect(() => { if (open()) { releaseEsc ??= pushOverlay(() => { open(false); trigger.focus(); }); // 入 Esc 栈:与弹窗/抽屉共用逐层关闭 - requestAnimationFrame(() => { reveal(hourCol.col, hourCol.buttons); reveal(minuteCol.col, minuteCol.buttons); }); // 布局就绪后再量 + requestAnimationFrame(() => { + const now = new Date(); // 未选值时的锚点:打开就停在「此刻」附近,省得从 00:00 开始翻 + reveal(hourCol.col, hourCol.buttons, now.getHours()); + reveal(minuteCol.col, minuteCol.buttons, Math.floor(now.getMinutes() / step)); + }); // 布局就绪后再量 } else { releaseEsc?.(); releaseEsc = null; diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index 3a3e02e..e7588ac 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -3693,7 +3693,7 @@ "example": "const at = signal('09:30'); timePicker({ value: at, minuteStep: 15, onChange: (t) => toast.info(`定在 ${t}`) })", "steps": [ "创建信号 at = signal('09:30') 并传入 value:组件读它显示、选完写回,双向绑定", - "点触发器展开时 / 分两列,当前值所在格高亮并自动滚到列中部,不必手动找", + "点触发器展开时 / 分两列:当前值所在格高亮并自动滚到列中部;还没选过时停在此刻(当前小时 / 当前分钟档),打开即可就近选", "先点时列定小时(分默认落到首个步长值,值立刻可用),再点分列即完成并收起,焦点回到触发器", "列内可用 ↑↓ 环形移动、Home/End 直达首末;Tab、Esc、点击外部都能正常进出与收起", "需要 15 分钟一档就传 minuteStep: 15,步长只影响分列的可选值,时列始终 24 档",