Skip to content

Commit

Permalink
feat: datepicker 支持 onChange 返回 trigger 参数定位事件触发源 (#777)
Browse files Browse the repository at this point in the history
  • Loading branch information
honkinglin authored May 19, 2022
1 parent 8ae42f8 commit b75ca5c
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 105 deletions.
11 changes: 8 additions & 3 deletions src/date-picker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>((props, ref) => {
firstDayOfWeek = globalDatePickerConfig.firstDayOfWeek,
presets,
timePickerProps,
onPick,
} = props;

const {
Expand Down Expand Up @@ -91,9 +92,11 @@ const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>((props, ref) => {
if (enableTimePicker) {
setCacheValue(formatDate(date));
} else {
onChange(formatDate(date, 'valueType'), dayjs(date));
onChange(formatDate(date, 'valueType'), { dayjsValue: dayjs(date), trigger: 'pick' });
setPopupVisible(false);
}

onPick?.(date);
}

// 头部快速切换
Expand Down Expand Up @@ -139,13 +142,15 @@ const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>((props, ref) => {
const currentDate = !dayjs(inputValue, format).isValid() ? dayjs() : dayjs(inputValue, format);
const nextDate = currentDate.hour(nextHours).minute(minutes).second(seconds).millisecond(milliseconds).toDate();
setInputValue(formatDate(nextDate));

onPick?.(nextDate);
}

// 确定
function onConfirmClick() {
const nextValue = formatDate(inputValue);
if (nextValue) {
onChange(formatDate(inputValue, 'valueType'), dayjs(inputValue));
onChange(formatDate(inputValue, 'valueType'), { dayjsValue: dayjs(inputValue), trigger: 'confirm' });
} else {
setInputValue(formatDate(value));
}
Expand All @@ -158,7 +163,7 @@ const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>((props, ref) => {
if (typeof preset === 'function') {
presetValue = preset();
}
onChange(formatDate(presetValue, 'valueType'), dayjs(presetValue));
onChange(formatDate(presetValue, 'valueType'), { dayjsValue: dayjs(presetValue), trigger: 'preset' });
setPopupVisible(false);
}

Expand Down
24 changes: 12 additions & 12 deletions src/date-picker/DateRangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>((props,

// 首次点击不关闭、确保两端都有有效值并且无时间选择器时点击后自动关闭
if (notValidIndex === -1 && nextValue.length === 2 && !enableTimePicker && isFirstValueSelected) {
onChange(
formatDate(nextValue, 'valueType'),
nextValue.map((v) => dayjs(v)),
);
onChange(formatDate(nextValue, 'valueType'), {
dayjsValue: nextValue.map((v) => dayjs(v)),
trigger: 'pick',
});
setIsFirstValueSelected(false);
setPopupVisible(false);
} else if (notValidIndex !== -1) {
Expand Down Expand Up @@ -216,10 +216,10 @@ const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>((props,

// 首次点击不关闭、确保两端都有有效值并且无时间选择器时点击后自动关闭
if (notValidIndex === -1 && nextValue.length === 2 && isFirstValueSelected) {
onChange(
formatDate(nextValue, 'valueType'),
nextValue.map((v) => dayjs(v)),
);
onChange(formatDate(nextValue, 'valueType'), {
dayjsValue: nextValue.map((v) => dayjs(v)),
trigger: 'confirm',
});
setYear(nextValue.map((v) => dayjs(v, format).year()));
setMonth(nextValue.map((v) => dayjs(v, format).month()));
setPopupVisible(false);
Expand All @@ -242,10 +242,10 @@ const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>((props,
if (!Array.isArray(presetValue)) {
console.error(`preset: ${preset} 预设值必须是数组!`);
} else {
onChange(
formatDate(presetValue, 'valueType'),
presetValue.map((p) => dayjs(p)),
);
onChange(formatDate(presetValue, 'valueType'), {
dayjsValue: presetValue.map((p) => dayjs(p)),
trigger: 'preset',
});
setPopupVisible(false);
}
}
Expand Down
44 changes: 44 additions & 0 deletions src/date-picker/__tests__/__snapshots__/date-picker.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,50 @@ exports[`disable-date.jsx 1`] = `
</div>
</div>
</div>
<div
class="t-date-picker"
>
<div
class="t-popup__reference t-select-input t-select-input--empty"
>
<div
class="t-input__wrap"
value=""
>
<div
class="t-input t-is-readonly t-size-m t-align-left t-is-default t-input--prefix t-input--suffix"
>
<div
class="t-input__prefix"
/>
<input
class="t-input__inner"
placeholder="禁用日期精确到时间"
readonly=""
type="text"
value=""
/>
<span
class="t-input__suffix t-input__suffix-icon"
>
<svg
class="t-icon t-icon-calendar"
fill="none"
height="1em"
viewBox="0 0 16 16"
width="1em"
>
<path
d="M10 3H6V1.5H5V3H3a1 1 0 00-1 1v9a1 1 0 001 1h10a1 1 0 001-1V4a1 1 0 00-1-1h-2V1.5h-1V3zM5 5h1V4h4v1h1V4h2v2H3V4h2v1zM3 7h10v6H3V7z"
fill="currentColor"
fill-opacity="0.9"
/>
</svg>
</span>
</div>
</div>
</div>
</div>
<div
class="t-date-range-picker"
>
Expand Down
78 changes: 47 additions & 31 deletions src/date-picker/_example/disable-date.jsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,58 @@
import React, { useState } from 'react';
import React, { useState, useMemo } from 'react';
import dayjs from 'dayjs';
import { DatePicker, DateRangePicker } from 'tdesign-react';

export default function YearDatePicker() {
// 禁用昨天、前天
const [disableDate] = useState([dayjs().subtract(1, 'day').format(), dayjs().subtract(2, 'day').format()]);
// 禁用最近 3 天外的日期
const [disableDate2] = useState({
before: dayjs().subtract(3, 'day').format(),
after: dayjs().add(3, 'day').format(),
});
// 明后三天禁用
const [disableDate3] = useState({
from: dayjs().add(1, 'day').format(),
to: dayjs().add(3, 'day').format(),
});
// 只可选择最近 5 天内的日期
const [disableDate4] = useState({
before: dayjs().subtract(5, 'day').format(),
after: dayjs().add(5, 'day').format(),
});
const [pickDate, setPickDate] = useState();

// 禁用所有周六
function getDisableDate(date) {
return dayjs(date).day() === 6;
}

function handleChange(value) {
console.log(value);
}
const timePickerProps = useMemo(() => {
return {
disableTime: () => {
if (pickDate === dayjs().format('YYYY-MM-DD')) {
return {
hour: [0, 1, 2, 3, 4, 5, 6],
};
}
return {};
},
};
}, [pickDate]);

return (
<div className="tdesign-demo-block-column">
<DatePicker placeholder="禁用昨天、前天" disableDate={disableDate} onChange={handleChange} />
<DatePicker placeholder="明后三天禁用" disableDate={disableDate3} onChange={handleChange} />
<DatePicker placeholder="禁用所有周六" disableDate={getDisableDate} onChange={handleChange} />
<DatePicker placeholder="禁用最近 3 天外的日期" disableDate={disableDate2} onChange={handleChange} />
<DateRangePicker placeholder="禁用最近 5 天外的日期" disableDate={disableDate4} onChange={handleChange} />
<DatePicker
placeholder="禁用昨天、前天"
disableDate={[dayjs().subtract(1, 'day').format(), dayjs().subtract(2, 'day').format()]}
/>
<DatePicker
placeholder="明后三天禁用"
disableDate={{
from: dayjs().add(1, 'day').format(),
to: dayjs().add(3, 'day').format(),
}}
/>
<DatePicker placeholder="禁用所有周六" disableDate={(date) => dayjs(date).day() === 6} />
<DatePicker
placeholder="禁用最近 3 天外的日期"
disableDate={{
before: dayjs().subtract(3, 'day').format(),
after: dayjs().add(3, 'day').format(),
}}
/>
<DatePicker
placeholder="禁用日期精确到时间"
enableTimePicker
disableDate={{ before: dayjs().subtract(1, 'day').format() }}
timePickerProps={timePickerProps}
onPick={(date) => setPickDate(dayjs(date).format('YYYY-MM-DD'))}
/>
<DateRangePicker
placeholder="禁用最近 5 天外的日期"
disableDate={{
before: dayjs().subtract(5, 'day').format(),
after: dayjs().add(5, 'day').format(),
}}
/>
</div>
);
}
5 changes: 3 additions & 2 deletions src/date-picker/date-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ value | String / Number / Array / Date | - | 选中值。TS 类型:`DateValue`
defaultValue | String / Number / Array / Date | - | 选中值。非受控属性。TS 类型:`DateValue` `type DateValue = string | number | Date`[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/date-picker/type.ts) | N
valueType | String | YYYY-MM-DD | 用于格式化日期,默认为:'YYYY-MM-DD',可选值:'date/time-stamp/YYY-MM-DD' 等,[更多可选值见 Dayjs 详细文档](https://day.js.org/docs/en/display/format)。<br /> 其中 `valueType=date` 表示 `value` 数据类型为 `Date``valueType='time-stamp'` 表示 `value` 数据类型为时间戳 | N
onBlur | Function | | TS 类型:`(context: { value: DateValue; e: FocusEvent }) => void`<br/>当输入框失去焦点时触发 | N
onChange | Function | | TS 类型:`(value: DateValue, dayjsValue: Dayjs) => void`<br/>选中值发生变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/date-picker/type.ts)。<br/>`import { Dayjs } from 'dayjs'`<br/> | N
onChange | Function | | TS 类型:`(value: DateValue, context: { dayjsValue?: Dayjs, trigger?: DatePickerTriggerSource }) => void`<br/>选中值发生变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/date-picker/type.ts)。<br/>`import { Dayjs } from 'dayjs'`<br/><br/>`type DatePickerTriggerSource = 'confirm' | 'pick' | 'enter' | 'preset' | 'clear'`<br/> | N
onFocus | Function | | TS 类型:`(context: { value: DateValue; e: FocusEvent }) => void`<br/>输入框获得焦点时触发 | N
onInput | Function | | TS 类型:`(context: { input: string; value: DateValue; e: InputEvent }) => void`<br/>输入框数据发生变化时触发,参数 input 表示输入内容,value 表示组件当前有效值 | N
onPick | Function | | TS 类型:`(value: DateValue) => void`<br/>面板选中值后触发 | N

### DateRangePicker Props

Expand Down Expand Up @@ -60,7 +61,7 @@ value | Array | - | 选中值。TS 类型:`DateRangeValue` `type DateRangeValu
defaultValue | Array | - | 选中值。非受控属性。TS 类型:`DateRangeValue` `type DateRangeValue = Array<DateValue>`[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/date-picker/type.ts) | N
valueType | String | YYYY-MM-DD | 用于格式化日期,默认为:'YYYY-MM-DD',可选值:'date/time-stamp/YYY-MM-DD' 等,[更多可选值见 Dayjs 详细文档](https://day.js.org/docs/en/display/format)。<br /> 其中 `valueType=date` 表示 `value` 数据类型为 `Date``valueType='time-stamp'` 表示 `value` 数据类型为时间戳 | N
onBlur | Function | | TS 类型:`(context: { value: DateRangeValue; partial: DateRangePickerPartial; e: FocusEvent }) => void`<br/>当输入框失去焦点时触发 | N
onChange | Function | | TS 类型:`(value: DateRangeValue, dayjsValue: Dayjs[]) => void`<br/>选中值发生变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/date-picker/type.ts)。<br/>`import { Dayjs } from 'dayjs'`<br/> | N
onChange | Function | | TS 类型:`(value: DateRangeValue, context: { dayjsValue?: Dayjs[], trigger?: DatePickerTriggerSource }) => void`<br/>选中值发生变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/date-picker/type.ts)。<br/>`import { Dayjs } from 'dayjs'`<br/> | N
onFocus | Function | | TS 类型:`(context: { value: DateRangeValue; partial: DateRangePickerPartial; e: FocusEvent }) => void`<br/>输入框获得焦点时触发 | N
onInput | Function | | TS 类型:`(context: { input: string; value: DateRangeValue; partial: DateRangePickerPartial; e: InputEvent }) => void`<br/>输入框数据发生变化时触发,参数 input 表示输入内容,value 表示组件当前有效值 | N
onPick | Function | | TS 类型:`(value: DateValue, context: PickContext) => void`<br/>选中日期时触发,可能是开始日期,也可能是结束日期,第二个参数可以区分是开始日期或是结束日期。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/date-picker/type.ts)。<br/>`interface PickContext { e: MouseEvent; partial: DateRangePickerPartial }`<br/> | N
10 changes: 5 additions & 5 deletions src/date-picker/hooks/useRange.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export default function useRange(props: TdDateRangePickerProps) {
onClear: ({ e }) => {
e.stopPropagation();
setPopupVisible(false);
onChange([], []);
onChange([], { dayjsValue: [], trigger: 'clear' });
},
onBlur: (newVal: string[], { e, position }) => {
onBlur?.({ value: newVal, partial: PARTIAL_MAP[position], e });
Expand Down Expand Up @@ -138,10 +138,10 @@ export default function useRange(props: TdDateRangePickerProps) {

setPopupVisible(false);
if (isValidDate(newVal)) {
onChange(
formatDate(newVal, 'valueType') as DateValue[],
newVal.map((v) => dayjs(v)),
);
onChange(formatDate(newVal, 'valueType') as DateValue[], {
dayjsValue: newVal.map((v) => dayjs(v)),
trigger: 'enter',
});
} else if (isValidDate(value)) {
setInputValue(formatDate(value));
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/date-picker/hooks/useSingle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function useSingle(props: TdDatePickerProps) {
onClear: ({ e }) => {
e.stopPropagation();
setPopupVisible(false);
onChange('', dayjs(''));
onChange('', { dayjsValue: dayjs(''), trigger: 'clear' });
},
onBlur: (val: string, { e }) => {
onBlur?.({ value: val, e });
Expand Down Expand Up @@ -88,7 +88,7 @@ export default function useSingle(props: TdDatePickerProps) {

setPopupVisible(false);
if (isValidDate(val)) {
onChange(formatDate(val, 'valueType') as DateValue, dayjs(val));
onChange(formatDate(val, 'valueType') as DateValue, { dayjsValue: dayjs(val), trigger: 'enter' });
} else if (isValidDate(value)) {
setInputValue(formatDate(value));
} else {
Expand Down
10 changes: 8 additions & 2 deletions src/date-picker/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export interface TdDatePickerProps {
/**
* 选中值发生变化时触发
*/
onChange?: (value: DateValue, dayjsValue: Dayjs) => void;
onChange?: (value: DateValue, context: { dayjsValue?: Dayjs; trigger?: DatePickerTriggerSource }) => void;
/**
* 输入框获得焦点时触发
*/
Expand All @@ -117,6 +117,10 @@ export interface TdDatePickerProps {
* 输入框数据发生变化时触发,参数 input 表示输入内容,value 表示组件当前有效值
*/
onInput?: (context: { input: string; value: DateValue; e: FormEvent<HTMLInputElement> }) => void;
/**
* 面板选中值后触发
*/
onPick?: (value: DateValue) => void;
}

export interface TdDateRangePickerProps {
Expand Down Expand Up @@ -216,7 +220,7 @@ export interface TdDateRangePickerProps {
/**
* 选中值发生变化时触发
*/
onChange?: (value: DateRangeValue, dayjsValue: Dayjs[]) => void;
onChange?: (value: DateRangeValue, context: { dayjsValue?: Dayjs[]; trigger?: DatePickerTriggerSource }) => void;
/**
* 输入框获得焦点时触发
*/
Expand Down Expand Up @@ -255,6 +259,8 @@ export interface PresetDate {

export type DateValue = string | number | Date;

export type DatePickerTriggerSource = 'confirm' | 'pick' | 'enter' | 'preset' | 'clear';

export type DisableRangeDate =
| Array<DateValue>
| DisableDateObj
Expand Down
Loading

0 comments on commit b75ca5c

Please sign in to comment.