Skip to content

Commit f6daa8d

Browse files
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 <[email protected]>
1 parent 48ab5a2 commit f6daa8d

File tree

11 files changed

+204
-86
lines changed

11 files changed

+204
-86
lines changed

components/date-picker/demo/presetted-ranges.vue

+37-9
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ We can set presetted ranges to RangePicker to improve user experience.
1818

1919
<template>
2020
<a-space direction="vertical" :size="12">
21-
<a-range-picker v-model:value="value1" :ranges="ranges" />
21+
<a-date-picker :presets="presets" @change="onChange" />
22+
<a-range-picker :presets="rangePresets" @change="onRangeChange" />
2223
<a-range-picker
23-
v-model:value="value2"
2424
style="width: 400px"
25-
:ranges="ranges"
2625
show-time
2726
format="YYYY/MM/DD HH:mm:ss"
27+
:presets="rangePresets"
28+
@change="onRangeChange"
2829
/>
2930
</a-space>
3031
</template>
@@ -34,13 +35,40 @@ import { defineComponent, ref } from 'vue';
3435
type RangeValue = [Dayjs, Dayjs];
3536
export default defineComponent({
3637
setup() {
38+
const onChange = (date: Dayjs) => {
39+
if (date) {
40+
console.log('Date: ', date);
41+
} else {
42+
console.log('Clear');
43+
}
44+
};
45+
const onRangeChange = (dates: RangeValue, dateStrings: string[]) => {
46+
if (dates) {
47+
console.log('From: ', dates[0], ', to: ', dates[1]);
48+
console.log('From: ', dateStrings[0], ', to: ', dateStrings[1]);
49+
} else {
50+
console.log('Clear');
51+
}
52+
};
53+
54+
const presets = ref([
55+
{ label: 'Yesterday', value: dayjs().add(-1, 'd') },
56+
{ label: 'Last Week', value: dayjs().add(-7, 'd') },
57+
{ label: 'Last Month', value: dayjs().add(-1, 'month') },
58+
]);
59+
60+
const rangePresets = ref([
61+
{ label: 'Last 7 Days', value: [dayjs().add(-7, 'd'), dayjs()] },
62+
{ label: 'Last 14 Days', value: [dayjs().add(-14, 'd'), dayjs()] },
63+
{ label: 'Last 30 Days', value: [dayjs().add(-30, 'd'), dayjs()] },
64+
{ label: 'Last 90 Days', value: [dayjs().add(-90, 'd'), dayjs()] },
65+
]);
3766
return {
38-
value1: ref<RangeValue>(),
39-
value2: ref<RangeValue>(),
40-
ranges: {
41-
Today: [dayjs(), dayjs()] as RangeValue,
42-
'This Month': [dayjs(), dayjs().endOf('month')] as RangeValue,
43-
},
67+
presets,
68+
rangePresets,
69+
70+
onChange,
71+
onRangeChange,
4472
};
4573
},
4674
});

components/date-picker/generatePicker/props.ts

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { CSSProperties } from 'vue';
33
import type { PickerLocale } from '.';
44
import type { SizeType } from '../../config-provider';
55
import type {
6+
PresetDate,
67
CustomFormat,
78
DisabledTime,
89
DisabledTimes,
@@ -118,6 +119,7 @@ export interface CommonProps<DateType> {
118119
* @deprecated `dropdownClassName` is deprecated which will be removed in next major
119120
* version.Please use `popupClassName` instead.
120121
*/
122+
121123
dropdownClassName?: string;
122124
popupClassName?: string;
123125
popupStyle?: CSSProperties;
@@ -176,6 +178,7 @@ function datePickerProps<DateType = any>() {
176178
defaultPickerValue: someType<DateType | string>([Object, String]),
177179
defaultValue: someType<DateType | string>([Object, String]),
178180
value: someType<DateType | string>([Object, String]),
181+
presets: arrayType<PresetDate<DateType>[]>(),
179182
disabledTime: functionType<DisabledTime<DateType>>(),
180183
renderExtraFooter: functionType<(mode: PanelMode) => VueNode>(),
181184
showNow: booleanType(),
@@ -189,6 +192,7 @@ export interface DatePickerProps<DateType> {
189192
defaultPickerValue?: DateType | string;
190193
defaultValue?: DateType | string;
191194
value?: DateType | string;
195+
presets?: PresetDate<DateType>[];
192196
disabledTime?: DisabledTime<DateType>;
193197
renderExtraFooter?: (mode: PanelMode) => VueNode;
194198
showNow?: boolean;
@@ -204,6 +208,7 @@ function rangePickerProps<DateType>() {
204208
defaultPickerValue: arrayType<RangeValue<DateType> | RangeValue<string>>(),
205209
defaultValue: arrayType<RangeValue<DateType> | RangeValue<string>>(),
206210
value: arrayType<RangeValue<DateType> | RangeValue<string>>(),
211+
presets: arrayType<PresetDate<Array<DateType>>[]>(),
207212
disabledTime: functionType<(date: EventValue<DateType>, type: RangeType) => DisabledTimes>(),
208213
disabled: someType<boolean | [boolean, boolean]>([Boolean, Array]),
209214
renderExtraFooter: functionType<() => VueNode>(),
@@ -249,6 +254,7 @@ export interface RangePickerProps<DateType> {
249254
defaultPickerValue?: RangeValue<DateType> | RangeValue<string>;
250255
defaultValue?: RangeValue<DateType> | RangeValue<string>;
251256
value?: RangeValue<DateType> | RangeValue<string>;
257+
presets?: PresetDate<RangeValue<DateType>>[];
252258
disabledTime?: (date: EventValue<DateType>, type: RangeType) => DisabledTimes;
253259
disabled?: [boolean, boolean];
254260
renderExtraFooter?: () => VueNode;

components/date-picker/index.en-US.md

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ The following APIs are shared by DatePicker, RangePicker.
9696
| placeholder | The placeholder of date input | string \| \[string,string] | - | |
9797
| placement | The position where the selection box pops up | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | 3.3.0 |
9898
| popupStyle | To customize the style of the popup calendar | CSSProperties | {} | |
99+
| presets | The preset ranges for quick selection | { label: slot, value: [dayjs](https://day.js.org/) }[] | - | |
99100
| prevIcon | The custom prev icon | slot | - | 3.0 |
100101
| 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` | - | |
101102
| status | Set validation status | 'error' \| 'warning' | - | 3.3.0 |
@@ -174,6 +175,7 @@ The following APIs are shared by DatePicker, RangePicker.
174175
| disabled | If disable start or end | \[boolean, boolean] | - | |
175176
| disabledTime | To specify the time that cannot be selected | function(date: dayjs, partial: `start` \| `end`) | - | |
176177
| format | To set the date format, refer to [dayjs](https://day.js.org/) | [formatType](#formatType) | `YYYY-MM-DD HH:mm:ss` | |
178+
| presets | The preset ranges for quick selection | { label: slot, value: [dayjs](https://day.js.org/)\[] }[] | - | |
177179
| ranges | The preseted ranges for quick selection | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | |
178180
| renderExtraFooter | Render extra footer in panel | v-slot:renderExtraFooter="mode" | - | |
179181
| separator | Set separator between inputs | string \| v-slot:separator | `<SwapRightOutlined />` | |

components/date-picker/index.zh-CN.md

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*3OpRQKcygo8AAA
9898
| placement | 选择框弹出的位置 | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | 3.3.0 |
9999
| popupStyle | 额外的弹出日历样式 | CSSProperties | {} | |
100100
| prevIcon | 自定义上一个图标 | slot | - | 3.0 |
101+
| presets | 预设时间范围快捷选择 | { label: slot, value: [dayjs](https://day.js.org/) }[] | - | |
101102
| size | 输入框大小,`large` 高度为 40px,`small` 为 24px,默认是 32px | `large` \| `middle` \| `small` | - | |
102103
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
103104
| suffixIcon | 自定义的选择框后缀图标 | v-slot:suffixIcon | - | |
@@ -175,6 +176,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*3OpRQKcygo8AAA
175176
| disabled | 禁用起始项 | \[boolean, boolean] | - | |
176177
| disabledTime | 不可选择的时间 | function(date: dayjs, partial: `start` \| `end`) | - | |
177178
| format | 展示的日期格式 | [formatType](#formatType) | `YYYY-MM-DD HH:mm:ss` | |
179+
| presets | 预设时间范围快捷选择 | { label: slot, value: [dayjs](https://day.js.org/)\[] }[] | - | |
178180
| ranges | 预设时间范围快捷选择 | { \[range: string]: [dayjs](https://day.js.org/)\[] } \| { \[range: string]: () => [dayjs](https://day.js.org/)\[] } | - | |
179181
| renderExtraFooter | 在面板中添加额外的页脚 | v-slot:renderExtraFooter="mode" | - | |
180182
| separator | 设置分隔符 | string \| v-slot:separator | `<SwapRightOutlined />` | |

components/vc-picker/Picker.tsx

+36-19
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,18 @@ import type {
1818
} from './PickerPanel';
1919
import PickerPanel from './PickerPanel';
2020
import PickerTrigger from './PickerTrigger';
21+
import PresetPanel from './PresetPanel';
2122
import { formatValue, isEqual, parseValue } from './utils/dateUtil';
2223
import getDataOrAriaProps, { toArray } from './utils/miscUtil';
2324
import type { ContextOperationRefProps } from './PanelContext';
2425
import { useProvidePanel } from './PanelContext';
25-
import type { CustomFormat, PickerMode } from './interface';
26+
import type { CustomFormat, PickerMode, PresetDate } from './interface';
2627
import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil';
2728
import usePickerInput from './hooks/usePickerInput';
2829
import useTextValueMapping from './hooks/useTextValueMapping';
2930
import useValueTexts from './hooks/useValueTexts';
3031
import useHoverValue from './hooks/useHoverValue';
32+
import usePresets from './hooks/usePresets';
3133
import type { CSSProperties, HTMLAttributes, Ref } from 'vue';
3234
import { computed, defineComponent, ref, toRef, watch } from 'vue';
3335
import type { ChangeEvent, FocusEventHandler, MouseEventHandler } from '../_util/EventInterface';
@@ -61,6 +63,8 @@ export type PickerSharedProps<DateType> = {
6163
inputReadOnly?: boolean;
6264
id?: string;
6365

66+
presets?: PresetDate<DateType>[];
67+
6468
// Value
6569
format?: string | CustomFormat<DateType> | (string | CustomFormat<DateType>)[];
6670

@@ -163,6 +167,7 @@ function Picker<DateType>() {
163167
'defaultOpen',
164168
'defaultOpenValue',
165169
'suffixIcon',
170+
'presets',
166171
'clearIcon',
167172
'disabled',
168173
'disabledDate',
@@ -203,6 +208,8 @@ function Picker<DateType>() {
203208
// ],
204209
setup(props, { attrs, expose }) {
205210
const inputRef = ref(null);
211+
const presets = computed(() => props.presets);
212+
const presetList = usePresets(presets);
206213
const picker = computed(() => props.picker ?? 'date');
207214
const needConfirmButton = computed(
208215
() => (picker.value === 'date' && !!props.showTime) || picker.value === 'time',
@@ -408,7 +415,6 @@ function Picker<DateType>() {
408415
useProvidePanel({
409416
operationRef,
410417
hideHeader: computed(() => picker.value === 'time'),
411-
panelRef: panelDivRef,
412418
onSelect: onContextSelect,
413419
open: mergedOpen,
414420
defaultOpenValue: toRef(props, 'defaultOpenValue'),
@@ -477,23 +483,33 @@ function Picker<DateType>() {
477483
};
478484

479485
let panelNode: VueNode = (
480-
<PickerPanel
481-
{...panelProps}
482-
generateConfig={generateConfig}
483-
value={selectedValue.value}
484-
locale={locale}
485-
tabindex={-1}
486-
onSelect={date => {
487-
onSelect?.(date);
488-
setSelectedValue(date);
489-
}}
490-
direction={direction}
491-
onPanelChange={(viewDate, mode) => {
492-
const { onPanelChange } = props;
493-
onLeave(true);
494-
onPanelChange?.(viewDate, mode);
495-
}}
496-
/>
486+
<div class={`${prefixCls}-panel-layout`}>
487+
<PresetPanel
488+
prefixCls={prefixCls}
489+
presets={presetList.value}
490+
onClick={nextValue => {
491+
triggerChange(nextValue);
492+
triggerOpen(false);
493+
}}
494+
/>
495+
<PickerPanel
496+
{...panelProps}
497+
generateConfig={generateConfig}
498+
value={selectedValue.value}
499+
locale={locale}
500+
tabindex={-1}
501+
onSelect={date => {
502+
onSelect?.(date);
503+
setSelectedValue(date);
504+
}}
505+
direction={direction}
506+
onPanelChange={(viewDate, mode) => {
507+
const { onPanelChange } = props;
508+
onLeave(true);
509+
onPanelChange?.(viewDate, mode);
510+
}}
511+
/>
512+
</div>
497513
);
498514

499515
if (panelRender) {
@@ -503,6 +519,7 @@ function Picker<DateType>() {
503519
const panel = (
504520
<div
505521
class={`${prefixCls}-panel-container`}
522+
ref={panelDivRef}
506523
onMousedown={e => {
507524
e.preventDefault();
508525
}}

components/vc-picker/PickerPanel.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ function PickerPanel<DateType>() {
186186
const panelContext = useInjectPanel();
187187
const {
188188
operationRef,
189-
panelRef: panelDivRef,
190189
onSelect: onContextSelect,
191190
hideRanges,
192191
defaultOpenValue,
@@ -601,7 +600,6 @@ function PickerPanel<DateType>() {
601600
onKeydown={onInternalKeydown}
602601
onBlur={onInternalBlur}
603602
onMousedown={onMousedown}
604-
ref={panelDivRef}
605603
>
606604
{panelNode}
607605
{extraFooter || rangesNode || todayNode ? (

components/vc-picker/PresetPanel.tsx

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { defineComponent } from 'vue';
2+
3+
export default defineComponent({
4+
name: 'PresetPanel',
5+
props: {
6+
prefixCls: String,
7+
presets: {
8+
type: Array,
9+
default: () => [],
10+
},
11+
onClick: Function,
12+
onHover: Function,
13+
},
14+
setup(props) {
15+
return () => {
16+
if (!props.presets.length) {
17+
return null;
18+
}
19+
return (
20+
<div class={`${props.prefixCls}-presets`}>
21+
<ul>
22+
{props.presets.map(({ label, value }, index) => (
23+
<li
24+
key={index}
25+
onClick={() => {
26+
props.onClick(value);
27+
}}
28+
onMouseenter={() => {
29+
props.onHover?.(value);
30+
}}
31+
onMouseleave={() => {
32+
props.onHover?.(null);
33+
}}
34+
>
35+
{label}
36+
</li>
37+
))}
38+
</ul>
39+
</div>
40+
);
41+
};
42+
},
43+
});

0 commit comments

Comments
 (0)