iter(g158): 日期选择支持快捷区间预设

This commit is contained in:
HIsheR
2026-10-26 16:00:40 +08:00
parent 476747aaca
commit 638f623750
7 changed files with 73 additions and 7 deletions
+20 -1
View File
@@ -2,7 +2,7 @@ import { effect, h, signal } from '@ui-arch/frame';
import type { Signal } from '@ui-arch/frame';
import { bindOutside, pushOverlay } from './overlay.js';
import { flip } from './position.js';
import type { DatePickerProps } from './types.js';
import type { DatePickerProps, DatePreset } from './types.js';
import { fmt, pad, parse, shiftDay, today } from './dateKit.js';
/*** 日期选择:单月网格 + 上下月翻页 + 今天快捷键,value 信号双向绑定,方向键/PageUp/PageDown 可导航 ***/
@@ -26,10 +26,16 @@ export function datePicker(props: DatePickerProps): HTMLElement {
label,
h('button', { type: 'button', class: 'ua-datepicker-nav', 'aria-label': '下一月', onClick: () => turn(1) }, '›'),
);
const presetRow = props.range && props.presets?.length // 快捷区间只在区间模式有意义
? h('div', { class: 'ua-datepicker-presets' }, ...props.presets.map((p) => h('button', {
type: 'button', class: 'ua-datepicker-preset', onClick: () => applyPreset(p),
}, p.label)))
: null;
const pop = h(
'div',
{ class: () => `ua-datepicker-pop${open() ? ' ua-open' : ''}${place() === 'top' ? ' is-flip' : ''}` },
head,
...(presetRow ? [presetRow] : []),
h('div', { class: 'ua-datepicker-week' }, ...['日', '一', '二', '三', '四', '五', '六'].map((w) => h('span', {}, w))),
grid,
h('div', { class: 'ua-datepicker-foot' }, h('button', { type: 'button', class: 'ua-datepicker-today', onClick: () => commit(fmt(...today())) }, '今天')),
@@ -65,6 +71,19 @@ export function datePicker(props: DatePickerProps): HTMLElement {
trigger.focus();
}
/*** 应用快捷区间:days 优先(今天往前共 N 天),否则用绝对 from/to;按 min/max 钳制后写值并收起 ***/
function applyPreset(p: DatePreset): void {
const stop = p.days ? fmt(...today()) : (p.to || fmt(...today()));
const start = p.days ? shiftDay(stop, -(p.days - 1)) : (p.from || stop);
const [lo, hi] = start <= stop ? [start, stop] : [stop, start]; // 防御:from 晚于 to 时自动交换
const fit = (v: string): string => (props.min && v < props.min ? props.min : props.max && v > props.max ? props.max : v); // 钳进合法区间
value(fit(lo));
end(fit(hi));
props.onRangeChange?.(value(), end());
open(false);
trigger.focus();
}
/*** 是否越界:min / max 为闭区间,缺省视为不限制 ***/
const outOfRange = (date: string): boolean => (props.min ? date < props.min : false) || (props.max ? date > props.max : false);
+9
View File
@@ -597,6 +597,14 @@ export interface AutoCompleteProps {
onSelect?: (option: AutoCompleteOption) => void; // 选中回调(点击或 Enter)
}
/*** 日期快捷区间:days 与 from/to 二选一,days 优先 ***/
export interface DatePreset {
label: string; // 按钮文案,如「最近 7 天」
days?: number; // 相对今天的天数(含今天):7 表示今天往前共 7 天
from?: string; // 绝对起始日(YYYY-MM-DD),未给 days 时使用
to?: string; // 绝对结束日(YYYY-MM-DD),未给 days 时使用;缺省取今天
}
/*** 日期选择入参 ***/
export interface DatePickerProps {
value?: Signal<string>; // 选中日期(YYYY-MM-DD);区间模式下是起始日
@@ -607,6 +615,7 @@ export interface DatePickerProps {
min?: string; // 最早可选日期(含);早于此的日置灰
max?: string; // 最晚可选日期(含);晚于此的日置灰
disabled?: boolean | Signal<boolean>; // 禁用触发器
presets?: DatePreset[]; // 快捷区间按钮组(仅区间模式渲染);缺省不显示
onChange?: (date: string) => void; // 选中回调(点击或 Enter)
}