@gez/date-time-kit
Version:
178 lines (165 loc) • 5.79 kB
text/typescript
import type { Ele as PopoverEle, EventMap as PopoverEvent } from '../popover';
import {
type BaseAttrs,
type BaseEmits,
type Emit2EventMap,
UiBase
} from '../web-component-base';
import {
Ele as YyyyMmDdListGrpEle,
type EventMap as YyyyMmDdListGrpEvent
} from '../yyyymmdd-list-grp';
import styleStr from './index.css';
import html from './index.html';
export interface Attrs extends BaseAttrs {
millisecond: number;
/**
* 选择器的粒度,表示最大可选的时间单位。默认为 year。
*/
'max-granularity'?: 'year' | 'month';
/**
* 选择器的粒度,表示最小可选的时间单位。默认为 month。
*/
'min-granularity'?: 'year' | 'month';
/**
* 是否显示年份控制按钮(快速增减年份)
* @default false
*/
'show-ctrl-btn-year-add'?: boolean;
'show-ctrl-btn-year-sub'?: boolean;
/**
* 是否显示月份控制按钮(快速增减月份)
* @default false
*/
'show-ctrl-btn-month-add'?: boolean;
'show-ctrl-btn-month-sub'?: boolean;
}
export interface Emits extends BaseEmits {
change: {
oldTime: Date;
newTime: Date;
};
'popover-open-change': boolean;
}
export type EventMap = Emit2EventMap<Emits>;
/**
* 日期导航组件
*
* 存在一个 titleFormatter 方法,可以重写该方法以自定义年月标题的回显格式。
*/
export class Ele extends UiBase<Attrs, Emits> {
public static readonly tagName = 'dt-yyyymm-nav' as const;
protected static _style = styleStr;
protected static _template = html;
static get observedAttributes(): string[] {
return [
...(super.observedAttributes as (keyof BaseAttrs)[]),
'millisecond',
'max-granularity',
'min-granularity',
'show-ctrl-btn-month-add',
'show-ctrl-btn-year-sub',
'show-ctrl-btn-month-add',
'show-ctrl-btn-month-sub'
] satisfies (keyof Attrs)[];
}
public get millisecond() {
return Math.floor(+this._getAttr('millisecond', '0'));
}
public set millisecond(v: number) {
if (!Number.isSafeInteger(v)) return;
this.setAttribute('millisecond', '' + Math.floor(v));
}
public get showCtrlBtnYearAdd() {
return this.hasAttribute('show-ctrl-btn-year-add');
}
public set showCtrlBtnYearAdd(val: boolean) {
this.toggleAttribute('show-ctrl-btn-year-add', val);
}
public get showCtrlBtnYearSub() {
return this.hasAttribute('show-ctrl-btn-year-sub');
}
public set showCtrlBtnYearSub(val: boolean) {
this.toggleAttribute('show-ctrl-btn-year-sub', val);
}
public get showCtrlBtnMonthAdd() {
return this.hasAttribute('show-ctrl-btn-month-add');
}
public set showCtrlBtnMonthAdd(val: boolean) {
this.toggleAttribute('show-ctrl-btn-month-add', val);
}
public get showCtrlBtnMonthSub() {
return this.hasAttribute('show-ctrl-btn-month-sub');
}
public set showCtrlBtnMonthSub(val: boolean) {
this.toggleAttribute('show-ctrl-btn-month-sub', val);
}
public connectedCallback() {
if (!super.connectedCallback()) return;
this._render();
this._bindEvt<PopoverEle>`.echo`('open-change', this._onTitleToggle);
this._bindEvt<YyyyMmDdListGrpEle>`dt-yyyymmdd-list-grp`(
'change',
this._onItemSelect
);
this._bindEvt<HTMLElement>`.btn`('click', this._onBtnClick);
}
protected _onAttrChanged(
name: string,
oldValue: string | null,
newValue: string | null
) {
super._onAttrChanged(name, oldValue, newValue);
this._render();
if (name === 'millisecond') {
this.dispatchEvent(
'change',
{
oldTime: new Date(Math.floor(+oldValue!)),
newTime: new Date(Math.floor(+newValue!))
},
true
);
}
}
private _render = super._genRenderFn(() => {
const ms = this.millisecond;
this.$0<YyyyMmDdListGrpEle>`dt-yyyymmdd-list-grp`!.millisecond = ms;
this.$0`.title`!.textContent = this.titleFormatter(ms);
});
private _onTitleToggle = (e: PopoverEvent['open-change']) => {
const isOpen = e.detail;
e.stopPropagation();
this.$0`.wrapper`!.classList.toggle('show-list', isOpen);
this
.$0<YyyyMmDdListGrpEle>`dt-yyyymmdd-list-grp`!.scrollToCurrentItem();
this.dispatchEvent('popover-open-change', isOpen, true);
};
private _onItemSelect = (e: YyyyMmDdListGrpEvent['change']) => {
if (!(e.target instanceof YyyyMmDdListGrpEle)) return;
e.stopPropagation();
this.millisecond = e.target.millisecond;
};
private _onBtnClick = (e: MouseEvent) => {
if (!(e.target instanceof HTMLElement)) return;
const date = new Date(this.millisecond);
date.setDate(1);
if (e.target.matches('.add.year')) {
date.setFullYear(date.getFullYear() + 1);
} else if (e.target.matches('.sub.year')) {
date.setFullYear(date.getFullYear() - 1);
} else if (e.target.matches('.add.month')) {
date.setMonth(date.getMonth() + 1);
} else if (e.target.matches('.sub.month')) {
date.setMonth(date.getMonth() - 1);
}
this.millisecond = +date;
};
public titleFormatter = (ms: number) => {
const date = new Date(ms);
const year = date.getFullYear();
const month = date.getMonth() + 1;
return `${(month < 10 ? '0' : '') + month}/${year}`;
};
}
Ele.define();