Feat(DatePicker): increase presets prop (#6387)
* feat(date-picker): add PresetDate type * feat(date-picker): add usePresets hook * feat(date-picker): add PresetPanel Component * feat(date-picker): add PresetPanel Component * feat(demo): update Preset Ranges Examples * feat(docs): add new prop presets * feat(docs): add new prop presets with english * fix(RangePicker): footer is not managed by panels * chore(Picker): prefixCls default rc-picker * chore(date-picker): update presetted-ranges demo * chore(date-picker): update rangePickerProps'presets * feat(date-picker): presets reactively processing * chore(date-picker): update type * refactor(RangePicker): deprecated ranges prop * chore(date-picker): update type * chore(PickerPanel): del notuse panelRef --------- Co-authored-by: tangjinzhou <415800467@qq.com>pull/6423/head
parent
48ab5a2f99
commit
f6daa8d28f
|
@ -18,13 +18,14 @@ We can set presetted ranges to RangePicker to improve user experience.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a-space direction="vertical" :size="12">
|
<a-space direction="vertical" :size="12">
|
||||||
<a-range-picker v-model:value="value1" :ranges="ranges" />
|
<a-date-picker :presets="presets" @change="onChange" />
|
||||||
|
<a-range-picker :presets="rangePresets" @change="onRangeChange" />
|
||||||
<a-range-picker
|
<a-range-picker
|
||||||
v-model:value="value2"
|
|
||||||
style="width: 400px"
|
style="width: 400px"
|
||||||
:ranges="ranges"
|
|
||||||
show-time
|
show-time
|
||||||
format="YYYY/MM/DD HH:mm:ss"
|
format="YYYY/MM/DD HH:mm:ss"
|
||||||
|
:presets="rangePresets"
|
||||||
|
@change="onRangeChange"
|
||||||
/>
|
/>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
|
@ -34,13 +35,40 @@ import { defineComponent, ref } from 'vue';
|
||||||
type RangeValue = [Dayjs, Dayjs];
|
type RangeValue = [Dayjs, Dayjs];
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
|
const onChange = (date: Dayjs) => {
|
||||||
|
if (date) {
|
||||||
|
console.log('Date: ', date);
|
||||||
|
} else {
|
||||||
|
console.log('Clear');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onRangeChange = (dates: RangeValue, dateStrings: string[]) => {
|
||||||
|
if (dates) {
|
||||||
|
console.log('From: ', dates[0], ', to: ', dates[1]);
|
||||||
|
console.log('From: ', dateStrings[0], ', to: ', dateStrings[1]);
|
||||||
|
} else {
|
||||||
|
console.log('Clear');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const presets = ref([
|
||||||
|
{ label: 'Yesterday', value: dayjs().add(-1, 'd') },
|
||||||
|
{ label: 'Last Week', value: dayjs().add(-7, 'd') },
|
||||||
|
{ label: 'Last Month', value: dayjs().add(-1, 'month') },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const rangePresets = ref([
|
||||||
|
{ label: 'Last 7 Days', value: [dayjs().add(-7, 'd'), dayjs()] },
|
||||||
|
{ label: 'Last 14 Days', value: [dayjs().add(-14, 'd'), dayjs()] },
|
||||||
|
{ label: 'Last 30 Days', value: [dayjs().add(-30, 'd'), dayjs()] },
|
||||||
|
{ label: 'Last 90 Days', value: [dayjs().add(-90, 'd'), dayjs()] },
|
||||||
|
]);
|
||||||
return {
|
return {
|
||||||
value1: ref<RangeValue>(),
|
presets,
|
||||||
value2: ref<RangeValue>(),
|
rangePresets,
|
||||||
ranges: {
|
|
||||||
Today: [dayjs(), dayjs()] as RangeValue,
|
onChange,
|
||||||
'This Month': [dayjs(), dayjs().endOf('month')] as RangeValue,
|
onRangeChange,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { CSSProperties } from 'vue';
|
||||||
import type { PickerLocale } from '.';
|
import type { PickerLocale } from '.';
|
||||||
import type { SizeType } from '../../config-provider';
|
import type { SizeType } from '../../config-provider';
|
||||||
import type {
|
import type {
|
||||||
|
PresetDate,
|
||||||
CustomFormat,
|
CustomFormat,
|
||||||
DisabledTime,
|
DisabledTime,
|
||||||
DisabledTimes,
|
DisabledTimes,
|
||||||
|
@ -118,6 +119,7 @@ export interface CommonProps<DateType> {
|
||||||
* @deprecated `dropdownClassName` is deprecated which will be removed in next major
|
* @deprecated `dropdownClassName` is deprecated which will be removed in next major
|
||||||
* version.Please use `popupClassName` instead.
|
* version.Please use `popupClassName` instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dropdownClassName?: string;
|
dropdownClassName?: string;
|
||||||
popupClassName?: string;
|
popupClassName?: string;
|
||||||
popupStyle?: CSSProperties;
|
popupStyle?: CSSProperties;
|
||||||
|
@ -176,6 +178,7 @@ function datePickerProps<DateType = any>() {
|
||||||
defaultPickerValue: someType<DateType | string>([Object, String]),
|
defaultPickerValue: someType<DateType | string>([Object, String]),
|
||||||
defaultValue: someType<DateType | string>([Object, String]),
|
defaultValue: someType<DateType | string>([Object, String]),
|
||||||
value: someType<DateType | string>([Object, String]),
|
value: someType<DateType | string>([Object, String]),
|
||||||
|
presets: arrayType<PresetDate<DateType>[]>(),
|
||||||
disabledTime: functionType<DisabledTime<DateType>>(),
|
disabledTime: functionType<DisabledTime<DateType>>(),
|
||||||
renderExtraFooter: functionType<(mode: PanelMode) => VueNode>(),
|
renderExtraFooter: functionType<(mode: PanelMode) => VueNode>(),
|
||||||
showNow: booleanType(),
|
showNow: booleanType(),
|
||||||
|
@ -189,6 +192,7 @@ export interface DatePickerProps<DateType> {
|
||||||
defaultPickerValue?: DateType | string;
|
defaultPickerValue?: DateType | string;
|
||||||
defaultValue?: DateType | string;
|
defaultValue?: DateType | string;
|
||||||
value?: DateType | string;
|
value?: DateType | string;
|
||||||
|
presets?: PresetDate<DateType>[];
|
||||||
disabledTime?: DisabledTime<DateType>;
|
disabledTime?: DisabledTime<DateType>;
|
||||||
renderExtraFooter?: (mode: PanelMode) => VueNode;
|
renderExtraFooter?: (mode: PanelMode) => VueNode;
|
||||||
showNow?: boolean;
|
showNow?: boolean;
|
||||||
|
@ -204,6 +208,7 @@ function rangePickerProps<DateType>() {
|
||||||
defaultPickerValue: arrayType<RangeValue<DateType> | RangeValue<string>>(),
|
defaultPickerValue: arrayType<RangeValue<DateType> | RangeValue<string>>(),
|
||||||
defaultValue: arrayType<RangeValue<DateType> | RangeValue<string>>(),
|
defaultValue: arrayType<RangeValue<DateType> | RangeValue<string>>(),
|
||||||
value: arrayType<RangeValue<DateType> | RangeValue<string>>(),
|
value: arrayType<RangeValue<DateType> | RangeValue<string>>(),
|
||||||
|
presets: arrayType<PresetDate<Array<DateType>>[]>(),
|
||||||
disabledTime: functionType<(date: EventValue<DateType>, type: RangeType) => DisabledTimes>(),
|
disabledTime: functionType<(date: EventValue<DateType>, type: RangeType) => DisabledTimes>(),
|
||||||
disabled: someType<boolean | [boolean, boolean]>([Boolean, Array]),
|
disabled: someType<boolean | [boolean, boolean]>([Boolean, Array]),
|
||||||
renderExtraFooter: functionType<() => VueNode>(),
|
renderExtraFooter: functionType<() => VueNode>(),
|
||||||
|
@ -249,6 +254,7 @@ export interface RangePickerProps<DateType> {
|
||||||
defaultPickerValue?: RangeValue<DateType> | RangeValue<string>;
|
defaultPickerValue?: RangeValue<DateType> | RangeValue<string>;
|
||||||
defaultValue?: RangeValue<DateType> | RangeValue<string>;
|
defaultValue?: RangeValue<DateType> | RangeValue<string>;
|
||||||
value?: RangeValue<DateType> | RangeValue<string>;
|
value?: RangeValue<DateType> | RangeValue<string>;
|
||||||
|
presets?: PresetDate<RangeValue<DateType>>[];
|
||||||
disabledTime?: (date: EventValue<DateType>, type: RangeType) => DisabledTimes;
|
disabledTime?: (date: EventValue<DateType>, type: RangeType) => DisabledTimes;
|
||||||
disabled?: [boolean, boolean];
|
disabled?: [boolean, boolean];
|
||||||
renderExtraFooter?: () => VueNode;
|
renderExtraFooter?: () => VueNode;
|
||||||
|
|
|
@ -96,6 +96,7 @@ The following APIs are shared by DatePicker, RangePicker.
|
||||||
| placeholder | The placeholder of date input | string \| \[string,string] | - | |
|
| placeholder | The placeholder of date input | string \| \[string,string] | - | |
|
||||||
| placement | The position where the selection box pops up | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | 3.3.0 |
|
| placement | The position where the selection box pops up | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | 3.3.0 |
|
||||||
| popupStyle | To customize the style of the popup calendar | CSSProperties | {} | |
|
| popupStyle | To customize the style of the popup calendar | CSSProperties | {} | |
|
||||||
|
| presets | The preset ranges for quick selection | { label: slot, value: [dayjs](https://day.js.org/) }[] | - | |
|
||||||
| prevIcon | The custom prev icon | slot | - | 3.0 |
|
| prevIcon | The custom prev icon | slot | - | 3.0 |
|
||||||
| size | To determine the size of the input box, the height of `large` and `small`, are 40px and 24px respectively, while default size is 32px | `large` \| `middle` \| `small` | - | |
|
| size | To determine the size of the input box, the height of `large` and `small`, are 40px and 24px respectively, while default size is 32px | `large` \| `middle` \| `small` | - | |
|
||||||
| status | Set validation status | 'error' \| 'warning' | - | 3.3.0 |
|
| status | Set validation status | 'error' \| 'warning' | - | 3.3.0 |
|
||||||
|
@ -174,6 +175,7 @@ The following APIs are shared by DatePicker, RangePicker.
|
||||||
| disabled | If disable start or end | \[boolean, boolean] | - | |
|
| disabled | If disable start or end | \[boolean, boolean] | - | |
|
||||||
| disabledTime | To specify the time that cannot be selected | function(date: dayjs, partial: `start` \| `end`) | - | |
|
| disabledTime | To specify the time that cannot be selected | function(date: dayjs, partial: `start` \| `end`) | - | |
|
||||||
| format | To set the date format, refer to [dayjs](https://day.js.org/) | [formatType](#formatType) | `YYYY-MM-DD HH:mm:ss` | |
|
| format | To set the date format, refer to [dayjs](https://day.js.org/) | [formatType](#formatType) | `YYYY-MM-DD HH:mm:ss` | |
|
||||||
|
| presets | The preset ranges for quick selection | { label: slot, value: [dayjs](https://day.js.org/)\[] }[] | - | |
|
||||||
| ranges | The preseted ranges for quick selection | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | |
|
| ranges | The preseted ranges for quick selection | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | |
|
||||||
| renderExtraFooter | Render extra footer in panel | v-slot:renderExtraFooter="mode" | - | |
|
| renderExtraFooter | Render extra footer in panel | v-slot:renderExtraFooter="mode" | - | |
|
||||||
| separator | Set separator between inputs | string \| v-slot:separator | `<SwapRightOutlined />` | |
|
| separator | Set separator between inputs | string \| v-slot:separator | `<SwapRightOutlined />` | |
|
||||||
|
|
|
@ -98,6 +98,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*3OpRQKcygo8AAA
|
||||||
| placement | 选择框弹出的位置 | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | 3.3.0 |
|
| placement | 选择框弹出的位置 | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | 3.3.0 |
|
||||||
| popupStyle | 额外的弹出日历样式 | CSSProperties | {} | |
|
| popupStyle | 额外的弹出日历样式 | CSSProperties | {} | |
|
||||||
| prevIcon | 自定义上一个图标 | slot | - | 3.0 |
|
| prevIcon | 自定义上一个图标 | slot | - | 3.0 |
|
||||||
|
| presets | 预设时间范围快捷选择 | { label: slot, value: [dayjs](https://day.js.org/) }[] | - | |
|
||||||
| size | 输入框大小,`large` 高度为 40px,`small` 为 24px,默认是 32px | `large` \| `middle` \| `small` | - | |
|
| size | 输入框大小,`large` 高度为 40px,`small` 为 24px,默认是 32px | `large` \| `middle` \| `small` | - | |
|
||||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
||||||
| suffixIcon | 自定义的选择框后缀图标 | v-slot:suffixIcon | - | |
|
| suffixIcon | 自定义的选择框后缀图标 | v-slot:suffixIcon | - | |
|
||||||
|
@ -175,6 +176,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*3OpRQKcygo8AAA
|
||||||
| disabled | 禁用起始项 | \[boolean, boolean] | - | |
|
| disabled | 禁用起始项 | \[boolean, boolean] | - | |
|
||||||
| disabledTime | 不可选择的时间 | function(date: dayjs, partial: `start` \| `end`) | - | |
|
| disabledTime | 不可选择的时间 | function(date: dayjs, partial: `start` \| `end`) | - | |
|
||||||
| format | 展示的日期格式 | [formatType](#formatType) | `YYYY-MM-DD HH:mm:ss` | |
|
| format | 展示的日期格式 | [formatType](#formatType) | `YYYY-MM-DD HH:mm:ss` | |
|
||||||
|
| presets | 预设时间范围快捷选择 | { label: slot, value: [dayjs](https://day.js.org/)\[] }[] | - | |
|
||||||
| ranges | 预设时间范围快捷选择 | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | |
|
| ranges | 预设时间范围快捷选择 | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | |
|
||||||
| renderExtraFooter | 在面板中添加额外的页脚 | v-slot:renderExtraFooter="mode" | - | |
|
| renderExtraFooter | 在面板中添加额外的页脚 | v-slot:renderExtraFooter="mode" | - | |
|
||||||
| separator | 设置分隔符 | string \| v-slot:separator | `<SwapRightOutlined />` | |
|
| separator | 设置分隔符 | string \| v-slot:separator | `<SwapRightOutlined />` | |
|
||||||
|
|
|
@ -18,16 +18,18 @@ import type {
|
||||||
} from './PickerPanel';
|
} from './PickerPanel';
|
||||||
import PickerPanel from './PickerPanel';
|
import PickerPanel from './PickerPanel';
|
||||||
import PickerTrigger from './PickerTrigger';
|
import PickerTrigger from './PickerTrigger';
|
||||||
|
import PresetPanel from './PresetPanel';
|
||||||
import { formatValue, isEqual, parseValue } from './utils/dateUtil';
|
import { formatValue, isEqual, parseValue } from './utils/dateUtil';
|
||||||
import getDataOrAriaProps, { toArray } from './utils/miscUtil';
|
import getDataOrAriaProps, { toArray } from './utils/miscUtil';
|
||||||
import type { ContextOperationRefProps } from './PanelContext';
|
import type { ContextOperationRefProps } from './PanelContext';
|
||||||
import { useProvidePanel } from './PanelContext';
|
import { useProvidePanel } from './PanelContext';
|
||||||
import type { CustomFormat, PickerMode } from './interface';
|
import type { CustomFormat, PickerMode, PresetDate } from './interface';
|
||||||
import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil';
|
import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil';
|
||||||
import usePickerInput from './hooks/usePickerInput';
|
import usePickerInput from './hooks/usePickerInput';
|
||||||
import useTextValueMapping from './hooks/useTextValueMapping';
|
import useTextValueMapping from './hooks/useTextValueMapping';
|
||||||
import useValueTexts from './hooks/useValueTexts';
|
import useValueTexts from './hooks/useValueTexts';
|
||||||
import useHoverValue from './hooks/useHoverValue';
|
import useHoverValue from './hooks/useHoverValue';
|
||||||
|
import usePresets from './hooks/usePresets';
|
||||||
import type { CSSProperties, HTMLAttributes, Ref } from 'vue';
|
import type { CSSProperties, HTMLAttributes, Ref } from 'vue';
|
||||||
import { computed, defineComponent, ref, toRef, watch } from 'vue';
|
import { computed, defineComponent, ref, toRef, watch } from 'vue';
|
||||||
import type { ChangeEvent, FocusEventHandler, MouseEventHandler } from '../_util/EventInterface';
|
import type { ChangeEvent, FocusEventHandler, MouseEventHandler } from '../_util/EventInterface';
|
||||||
|
@ -61,6 +63,8 @@ export type PickerSharedProps<DateType> = {
|
||||||
inputReadOnly?: boolean;
|
inputReadOnly?: boolean;
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|
||||||
|
presets?: PresetDate<DateType>[];
|
||||||
|
|
||||||
// Value
|
// Value
|
||||||
format?: string | CustomFormat<DateType> | (string | CustomFormat<DateType>)[];
|
format?: string | CustomFormat<DateType> | (string | CustomFormat<DateType>)[];
|
||||||
|
|
||||||
|
@ -163,6 +167,7 @@ function Picker<DateType>() {
|
||||||
'defaultOpen',
|
'defaultOpen',
|
||||||
'defaultOpenValue',
|
'defaultOpenValue',
|
||||||
'suffixIcon',
|
'suffixIcon',
|
||||||
|
'presets',
|
||||||
'clearIcon',
|
'clearIcon',
|
||||||
'disabled',
|
'disabled',
|
||||||
'disabledDate',
|
'disabledDate',
|
||||||
|
@ -203,6 +208,8 @@ function Picker<DateType>() {
|
||||||
// ],
|
// ],
|
||||||
setup(props, { attrs, expose }) {
|
setup(props, { attrs, expose }) {
|
||||||
const inputRef = ref(null);
|
const inputRef = ref(null);
|
||||||
|
const presets = computed(() => props.presets);
|
||||||
|
const presetList = usePresets(presets);
|
||||||
const picker = computed(() => props.picker ?? 'date');
|
const picker = computed(() => props.picker ?? 'date');
|
||||||
const needConfirmButton = computed(
|
const needConfirmButton = computed(
|
||||||
() => (picker.value === 'date' && !!props.showTime) || picker.value === 'time',
|
() => (picker.value === 'date' && !!props.showTime) || picker.value === 'time',
|
||||||
|
@ -408,7 +415,6 @@ function Picker<DateType>() {
|
||||||
useProvidePanel({
|
useProvidePanel({
|
||||||
operationRef,
|
operationRef,
|
||||||
hideHeader: computed(() => picker.value === 'time'),
|
hideHeader: computed(() => picker.value === 'time'),
|
||||||
panelRef: panelDivRef,
|
|
||||||
onSelect: onContextSelect,
|
onSelect: onContextSelect,
|
||||||
open: mergedOpen,
|
open: mergedOpen,
|
||||||
defaultOpenValue: toRef(props, 'defaultOpenValue'),
|
defaultOpenValue: toRef(props, 'defaultOpenValue'),
|
||||||
|
@ -477,23 +483,33 @@ function Picker<DateType>() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let panelNode: VueNode = (
|
let panelNode: VueNode = (
|
||||||
<PickerPanel
|
<div class={`${prefixCls}-panel-layout`}>
|
||||||
{...panelProps}
|
<PresetPanel
|
||||||
generateConfig={generateConfig}
|
prefixCls={prefixCls}
|
||||||
value={selectedValue.value}
|
presets={presetList.value}
|
||||||
locale={locale}
|
onClick={nextValue => {
|
||||||
tabindex={-1}
|
triggerChange(nextValue);
|
||||||
onSelect={date => {
|
triggerOpen(false);
|
||||||
onSelect?.(date);
|
}}
|
||||||
setSelectedValue(date);
|
/>
|
||||||
}}
|
<PickerPanel
|
||||||
direction={direction}
|
{...panelProps}
|
||||||
onPanelChange={(viewDate, mode) => {
|
generateConfig={generateConfig}
|
||||||
const { onPanelChange } = props;
|
value={selectedValue.value}
|
||||||
onLeave(true);
|
locale={locale}
|
||||||
onPanelChange?.(viewDate, mode);
|
tabindex={-1}
|
||||||
}}
|
onSelect={date => {
|
||||||
/>
|
onSelect?.(date);
|
||||||
|
setSelectedValue(date);
|
||||||
|
}}
|
||||||
|
direction={direction}
|
||||||
|
onPanelChange={(viewDate, mode) => {
|
||||||
|
const { onPanelChange } = props;
|
||||||
|
onLeave(true);
|
||||||
|
onPanelChange?.(viewDate, mode);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (panelRender) {
|
if (panelRender) {
|
||||||
|
@ -503,6 +519,7 @@ function Picker<DateType>() {
|
||||||
const panel = (
|
const panel = (
|
||||||
<div
|
<div
|
||||||
class={`${prefixCls}-panel-container`}
|
class={`${prefixCls}-panel-container`}
|
||||||
|
ref={panelDivRef}
|
||||||
onMousedown={e => {
|
onMousedown={e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -186,7 +186,6 @@ function PickerPanel<DateType>() {
|
||||||
const panelContext = useInjectPanel();
|
const panelContext = useInjectPanel();
|
||||||
const {
|
const {
|
||||||
operationRef,
|
operationRef,
|
||||||
panelRef: panelDivRef,
|
|
||||||
onSelect: onContextSelect,
|
onSelect: onContextSelect,
|
||||||
hideRanges,
|
hideRanges,
|
||||||
defaultOpenValue,
|
defaultOpenValue,
|
||||||
|
@ -601,7 +600,6 @@ function PickerPanel<DateType>() {
|
||||||
onKeydown={onInternalKeydown}
|
onKeydown={onInternalKeydown}
|
||||||
onBlur={onInternalBlur}
|
onBlur={onInternalBlur}
|
||||||
onMousedown={onMousedown}
|
onMousedown={onMousedown}
|
||||||
ref={panelDivRef}
|
|
||||||
>
|
>
|
||||||
{panelNode}
|
{panelNode}
|
||||||
{extraFooter || rangesNode || todayNode ? (
|
{extraFooter || rangesNode || todayNode ? (
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'PresetPanel',
|
||||||
|
props: {
|
||||||
|
prefixCls: String,
|
||||||
|
presets: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
onClick: Function,
|
||||||
|
onHover: Function,
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
return () => {
|
||||||
|
if (!props.presets.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div class={`${props.prefixCls}-presets`}>
|
||||||
|
<ul>
|
||||||
|
{props.presets.map(({ label, value }, index) => (
|
||||||
|
<li
|
||||||
|
key={index}
|
||||||
|
onClick={() => {
|
||||||
|
props.onClick(value);
|
||||||
|
}}
|
||||||
|
onMouseenter={() => {
|
||||||
|
props.onHover?.(value);
|
||||||
|
}}
|
||||||
|
onMouseleave={() => {
|
||||||
|
props.onHover?.(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,9 +1,17 @@
|
||||||
import type { DisabledTimes, PanelMode, PickerMode, RangeValue, EventValue } from './interface';
|
import type {
|
||||||
|
DisabledTimes,
|
||||||
|
PanelMode,
|
||||||
|
PickerMode,
|
||||||
|
RangeValue,
|
||||||
|
EventValue,
|
||||||
|
PresetDate,
|
||||||
|
} from './interface';
|
||||||
import type { PickerBaseProps, PickerDateProps, PickerTimeProps } from './Picker';
|
import type { PickerBaseProps, PickerDateProps, PickerTimeProps } from './Picker';
|
||||||
import type { SharedTimeProps } from './panels/TimePanel';
|
import type { SharedTimeProps } from './panels/TimePanel';
|
||||||
import PickerTrigger from './PickerTrigger';
|
import PickerTrigger from './PickerTrigger';
|
||||||
import PickerPanel from './PickerPanel';
|
import PickerPanel from './PickerPanel';
|
||||||
import usePickerInput from './hooks/usePickerInput';
|
import usePickerInput from './hooks/usePickerInput';
|
||||||
|
import PresetPanel from './PresetPanel';
|
||||||
import getDataOrAriaProps, { toArray, getValue, updateValues } from './utils/miscUtil';
|
import getDataOrAriaProps, { toArray, getValue, updateValues } from './utils/miscUtil';
|
||||||
import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil';
|
import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil';
|
||||||
import type { ContextOperationRefProps } from './PanelContext';
|
import type { ContextOperationRefProps } from './PanelContext';
|
||||||
|
@ -19,6 +27,7 @@ import {
|
||||||
} from './utils/dateUtil';
|
} from './utils/dateUtil';
|
||||||
import useValueTexts from './hooks/useValueTexts';
|
import useValueTexts from './hooks/useValueTexts';
|
||||||
import useTextValueMapping from './hooks/useTextValueMapping';
|
import useTextValueMapping from './hooks/useTextValueMapping';
|
||||||
|
import usePresets from './hooks/usePresets';
|
||||||
import type { GenerateConfig } from './generate';
|
import type { GenerateConfig } from './generate';
|
||||||
import type { PickerPanelProps } from '.';
|
import type { PickerPanelProps } from '.';
|
||||||
import { RangeContextProvider } from './RangeContext';
|
import { RangeContextProvider } from './RangeContext';
|
||||||
|
@ -91,6 +100,8 @@ export type RangePickerSharedProps<DateType> = {
|
||||||
placeholder?: [string, string];
|
placeholder?: [string, string];
|
||||||
disabled?: boolean | [boolean, boolean];
|
disabled?: boolean | [boolean, boolean];
|
||||||
disabledTime?: (date: EventValue<DateType>, type: RangeType) => DisabledTimes;
|
disabledTime?: (date: EventValue<DateType>, type: RangeType) => DisabledTimes;
|
||||||
|
presets?: PresetDate<RangeValue<DateType>>[];
|
||||||
|
/** @deprecated Please use `presets` instead */
|
||||||
ranges?: Record<
|
ranges?: Record<
|
||||||
string,
|
string,
|
||||||
Exclude<RangeValue<DateType>, null> | (() => Exclude<RangeValue<DateType>, null>)
|
Exclude<RangeValue<DateType>, null> | (() => Exclude<RangeValue<DateType>, null>)
|
||||||
|
@ -139,6 +150,7 @@ type OmitPickerProps<Props> = Omit<
|
||||||
| 'onPickerValueChange'
|
| 'onPickerValueChange'
|
||||||
| 'onOk'
|
| 'onOk'
|
||||||
| 'dateRender'
|
| 'dateRender'
|
||||||
|
| 'presets'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
type RangeShowTimeObject<DateType> = Omit<SharedTimeProps<DateType>, 'defaultValue'> & {
|
type RangeShowTimeObject<DateType> = Omit<SharedTimeProps<DateType>, 'defaultValue'> & {
|
||||||
|
@ -238,13 +250,17 @@ function RangerPicker<DateType>() {
|
||||||
'secondStep',
|
'secondStep',
|
||||||
'hideDisabledOptions',
|
'hideDisabledOptions',
|
||||||
'disabledMinutes',
|
'disabledMinutes',
|
||||||
|
'presets',
|
||||||
] as any,
|
] as any,
|
||||||
setup(props, { attrs, expose }) {
|
setup(props, { attrs, expose }) {
|
||||||
const needConfirmButton = computed(
|
const needConfirmButton = computed(
|
||||||
() => (props.picker === 'date' && !!props.showTime) || props.picker === 'time',
|
() => (props.picker === 'date' && !!props.showTime) || props.picker === 'time',
|
||||||
);
|
);
|
||||||
const getPortal = useProviderTrigger();
|
const getPortal = useProviderTrigger();
|
||||||
// We record opened status here in case repeat open with picker
|
const presets = computed(() => props.presets);
|
||||||
|
const ranges = computed(() => props.ranges);
|
||||||
|
const presetList = usePresets(presets, ranges);
|
||||||
|
// We record oqqpened status here in case repeat open with picker
|
||||||
const openRecordsRef = ref<Record<number, boolean>>({});
|
const openRecordsRef = ref<Record<number, boolean>>({});
|
||||||
|
|
||||||
const containerRef = ref<HTMLDivElement>(null);
|
const containerRef = ref<HTMLDivElement>(null);
|
||||||
|
@ -830,28 +846,6 @@ function RangerPicker<DateType>() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// ============================ Ranges =============================
|
|
||||||
|
|
||||||
const rangeList = computed(() =>
|
|
||||||
Object.keys(props.ranges || {}).map(label => {
|
|
||||||
const range = props.ranges![label];
|
|
||||||
const newValues = typeof range === 'function' ? range() : range;
|
|
||||||
|
|
||||||
return {
|
|
||||||
label,
|
|
||||||
onClick: () => {
|
|
||||||
triggerChange(newValues, null);
|
|
||||||
triggerOpen(false, mergedActivePickerIndex.value);
|
|
||||||
},
|
|
||||||
onMouseenter: () => {
|
|
||||||
setRangeHoverValue(newValues);
|
|
||||||
},
|
|
||||||
onMouseleave: () => {
|
|
||||||
setRangeHoverValue(null);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
// ============================= Panel =============================
|
// ============================= Panel =============================
|
||||||
const panelHoverRangedValue = computed(() => {
|
const panelHoverRangedValue = computed(() => {
|
||||||
if (
|
if (
|
||||||
|
@ -1044,7 +1038,6 @@ function RangerPicker<DateType>() {
|
||||||
!getValue(selectedValue.value, mergedActivePickerIndex.value) ||
|
!getValue(selectedValue.value, mergedActivePickerIndex.value) ||
|
||||||
(disabledDate && disabledDate(selectedValue.value[mergedActivePickerIndex.value])),
|
(disabledDate && disabledDate(selectedValue.value[mergedActivePickerIndex.value])),
|
||||||
locale,
|
locale,
|
||||||
rangeList: rangeList.value,
|
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
if (getValue(selectedValue.value, mergedActivePickerIndex.value)) {
|
if (getValue(selectedValue.value, mergedActivePickerIndex.value)) {
|
||||||
// triggerChangeOld(selectedValue.value);
|
// triggerChangeOld(selectedValue.value);
|
||||||
|
@ -1099,15 +1092,28 @@ function RangerPicker<DateType>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mergedNodes: VueNode = (
|
let mergedNodes: VueNode = (
|
||||||
<>
|
<div class={`${prefixCls}-panel-layout`}>
|
||||||
<div class={`${prefixCls}-panels`}>{panels}</div>
|
<PresetPanel
|
||||||
{(extraNode || rangesNode) && (
|
prefixCls={prefixCls}
|
||||||
<div class={`${prefixCls}-footer`}>
|
presets={presetList.value}
|
||||||
{extraNode}
|
onClick={nextValue => {
|
||||||
{rangesNode}
|
triggerChange(nextValue, null);
|
||||||
</div>
|
triggerOpen(false, mergedActivePickerIndex.value);
|
||||||
)}
|
}}
|
||||||
</>
|
onHover={hoverValue => {
|
||||||
|
setRangeHoverValue(hoverValue);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<div class={`${prefixCls}-panels`}>{panels}</div>
|
||||||
|
{(extraNode || rangesNode) && (
|
||||||
|
<div class={`${prefixCls}-footer`}>
|
||||||
|
{extraNode}
|
||||||
|
{rangesNode}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (panelRender) {
|
if (panelRender) {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import type { ComputedRef } from 'vue';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import warning from 'ant-design-vue/es/vc-util/warning';
|
||||||
|
import type { PresetDate } from '../interface';
|
||||||
|
|
||||||
|
export default function usePresets<T>(
|
||||||
|
presets?: ComputedRef<PresetDate<T>[]>,
|
||||||
|
legacyRanges?: ComputedRef<Record<string, T | (() => T)>>,
|
||||||
|
): ComputedRef<PresetDate<T>[]> {
|
||||||
|
if (presets.value) {
|
||||||
|
return presets;
|
||||||
|
}
|
||||||
|
if (legacyRanges && legacyRanges.value) {
|
||||||
|
warning(false, '`ranges` is deprecated. Please use `presets` instead.');
|
||||||
|
|
||||||
|
return computed(() => {
|
||||||
|
const rangeLabels = Object.keys(legacyRanges.value);
|
||||||
|
return rangeLabels.map(label => {
|
||||||
|
const range = legacyRanges.value[label];
|
||||||
|
const newValues = typeof range === 'function' ? (range as any)() : range;
|
||||||
|
return {
|
||||||
|
label,
|
||||||
|
value: newValues,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return [] as unknown as ComputedRef<PresetDate<T>[]>;
|
||||||
|
}
|
|
@ -98,14 +98,18 @@ export type RangeValue<DateType> = [EventValue<DateType>, EventValue<DateType>]
|
||||||
|
|
||||||
export type Components = {
|
export type Components = {
|
||||||
button?: any;
|
button?: any;
|
||||||
rangeItem?: any;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RangeList = {
|
export type RangeList = {
|
||||||
label: string;
|
label: VueNode;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
onMouseenter: () => void;
|
onMouseenter: () => void;
|
||||||
onMouseleave: () => void;
|
onMouseleave: () => void;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
export type CustomFormat<DateType> = (value: DateType) => string;
|
export type CustomFormat<DateType> = (value: DateType) => string;
|
||||||
|
|
||||||
|
export interface PresetDate<T> {
|
||||||
|
label: VueNode;
|
||||||
|
value: T;
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import type { VueNode } from '../../_util/type';
|
import type { VueNode } from '../../_util/type';
|
||||||
import type { Components, RangeList, Locale } from '../interface';
|
import type { Components, Locale } from '../interface';
|
||||||
|
|
||||||
export type RangesProps = {
|
export type RangesProps = {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
rangeList?: RangeList;
|
|
||||||
components?: Components;
|
components?: Components;
|
||||||
needConfirmButton: boolean;
|
needConfirmButton: boolean;
|
||||||
onNow?: null | (() => void) | false;
|
onNow?: null | (() => void) | false;
|
||||||
|
@ -15,7 +14,6 @@ export type RangesProps = {
|
||||||
|
|
||||||
export default function getRanges({
|
export default function getRanges({
|
||||||
prefixCls,
|
prefixCls,
|
||||||
rangeList = [],
|
|
||||||
components = {},
|
components = {},
|
||||||
needConfirmButton,
|
needConfirmButton,
|
||||||
onNow,
|
onNow,
|
||||||
|
@ -27,26 +25,10 @@ export default function getRanges({
|
||||||
let presetNode: VueNode;
|
let presetNode: VueNode;
|
||||||
let okNode: VueNode;
|
let okNode: VueNode;
|
||||||
|
|
||||||
if (rangeList.length) {
|
|
||||||
const Item = (components.rangeItem || 'span') as any;
|
|
||||||
|
|
||||||
presetNode = (
|
|
||||||
<>
|
|
||||||
{rangeList.map(({ label, onClick, onMouseenter, onMouseleave }) => (
|
|
||||||
<li key={label} class={`${prefixCls}-preset`}>
|
|
||||||
<Item onClick={onClick} onMouseenter={onMouseenter} onMouseleave={onMouseleave}>
|
|
||||||
{label}
|
|
||||||
</Item>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needConfirmButton) {
|
if (needConfirmButton) {
|
||||||
const Button = (components.button || 'button') as any;
|
const Button = (components.button || 'button') as any;
|
||||||
|
|
||||||
if (onNow && !presetNode && showNow !== false) {
|
if (onNow && showNow !== false) {
|
||||||
presetNode = (
|
presetNode = (
|
||||||
<li class={`${prefixCls}-now`}>
|
<li class={`${prefixCls}-now`}>
|
||||||
<a class={`${prefixCls}-now-btn`} onClick={onNow}>
|
<a class={`${prefixCls}-now-btn`} onClick={onNow}>
|
||||||
|
|
Loading…
Reference in New Issue