iter(g158): 日期选择支持快捷区间预设
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user