Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/avatar/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { ImageProps } from '../image';
import { PopupProps } from '../popup';
import { TNode } from '../common';
import { TNode, ShapeEnum } from '../common';

export interface TdAvatarProps {
/**
Expand Down Expand Up @@ -81,6 +81,4 @@ export interface TdAvatarGroupProps {
size?: string;
}

export type ShapeEnum = 'circle' | 'round';

export type CascadingValue = 'left-up' | 'right-up';
2 changes: 2 additions & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export type TreeOptionData<T = string | number> = {

export type SizeEnum = 'small' | 'medium' | 'large';

export type ShapeEnum = 'circle' | 'round';

export type HorizontalAlignEnum = 'left' | 'center' | 'right';

export type VerticalAlignEnum = 'top' | 'middle' | 'bottom';
Expand Down
84 changes: 73 additions & 11 deletions src/date-picker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,30 @@ import dayjs from 'dayjs';
import { CalendarIcon as TdCalendarIcon } from 'tdesign-icons-vue';
import isDate from 'lodash/isDate';

import { usePrefixClass } from '../hooks/useConfig';
import { usePrefixClass, useConfig } from '../hooks/useConfig';
import { useGlobalIcon } from '../hooks/useGlobalIcon';
import useSingle from './hooks/useSingle';
import {
parseToDayjs, getDefaultFormat, formatTime, formatDate,
} from '../_common/js/date-picker/format';
import {
subtractMonth, addMonth, extractTimeObj, covertToDate,
subtractMonth, addMonth, extractTimeObj, covertToDate, isSame,
} from '../_common/js/date-picker/utils';
import type { DateValue } from './type';
import type { DateMultipleValue, DateValue } from './type';
import props from './props';

import TSelectInput from '../select-input';
import TSinglePanel from './panel/SinglePanel';
import useFormDisabled from '../hooks/useFormDisabled';
import type { TagInputRemoveContext } from '../tag-input';

export default defineComponent({
name: 'TDatePicker',
props,
setup(props, { emit }) {
const COMPONENT_NAME = usePrefixClass('date-picker');
const { CalendarIcon } = useGlobalIcon({ CalendarIcon: TdCalendarIcon });
const { global } = useConfig('datePicker');

const {
inputValue,
Expand All @@ -45,13 +47,14 @@ export default defineComponent({
mode: props.mode,
format: props.format,
valueType: props.valueType,
enableTimePicker: props.enableTimePicker,
enableTimePicker: props.multiple ? false : props.enableTimePicker,
}));

const { formDisabled } = useFormDisabled();
const isDisabled = computed(() => formDisabled.value || props.disabled);

watch(popupVisible, (visible) => {
if (props.multiple) return;
// Date valueType、week mode 、quarter mode nad empty string don't need to be parsed
const dateValue = value.value && !isDate(value.value) && !['week', 'quarter'].includes(props.mode)
? covertToDate(value.value as string, formatRef.value?.valueType)
Expand All @@ -66,8 +69,8 @@ export default defineComponent({

// 面板展开重置数据
if (visible) {
year.value = parseToDayjs(value.value, formatRef.value.format).year();
month.value = parseToDayjs(value.value, formatRef.value.format).month();
year.value = parseToDayjs(value.value as DateValue, formatRef.value.format).year();
month.value = parseToDayjs(value.value as DateValue, formatRef.value.format).month();
time.value = formatTime(value.value, formatRef.value.format, formatRef.value.timeFormat, props.defaultTime);
} else {
isHoverCell.value = false;
Expand All @@ -76,6 +79,7 @@ export default defineComponent({

// 日期 hover
function onCellMouseEnter(date: Date) {
if (props.multiple) return;
isHoverCell.value = true;
inputValue.value = formatDate(date, {
format: formatRef.value.format,
Expand All @@ -84,6 +88,7 @@ export default defineComponent({

// 日期 leave
function onCellMouseLeave() {
if (props.multiple) return;
isHoverCell.value = false;
inputValue.value = formatDate(cacheValue.value, {
format: formatRef.value.format,
Expand All @@ -103,6 +108,14 @@ export default defineComponent({
format: formatRef.value.format,
});
} else {
if (props.multiple) {
const newDate = processDate(date);
onChange?.(newDate, {
dayjsValue: parseToDayjs(date, formatRef.value.format),
trigger: 'pick',
});
return;
}
onChange?.(
formatDate(date, {
format: formatRef.value.format,
Expand Down Expand Up @@ -228,21 +241,56 @@ export default defineComponent({
month.value = nextMonth;
}

function processDate(date: Date) {
const val = value.value as DateMultipleValue;
const isSameDate = val.some((val) => isSame(dayjs(val).toDate(), date));
let currentDate: DateMultipleValue;

if (!isSameDate) {
currentDate = val.concat(
formatDate(date, { format: formatRef.value.format, targetFormat: formatRef.value.valueType }),
);
} else {
currentDate = val.filter(
(val) => formatDate(val, { format: formatRef.value.format, targetFormat: formatRef.value.valueType })
!== formatDate(date, { format: formatRef.value.format, targetFormat: formatRef.value.valueType }),
);
}

return currentDate.sort((a, b) => dayjs(a).valueOf() - dayjs(b).valueOf());
}

const onTagRemoveClick = (ctx: TagInputRemoveContext) => {
const removeDate = dayjs(ctx.item).toDate();
const newDate = processDate(removeDate);
onChange?.(newDate, {
dayjsValue: parseToDayjs(removeDate, formatRef.value.format),
trigger: 'tag-remove',
});
};

const onTagClearClick = ({ e }: { e: MouseEvent }) => {
e.stopPropagation();
popupVisible.value = false;
onChange?.([], { dayjsValue: dayjs(), trigger: 'clear' });
};

const panelProps: any = computed(() => ({
value: cacheValue.value as string,
value: cacheValue.value,
year: year.value,
month: month.value,
format: formatRef.value.format,
mode: props.mode,
presets: props.presets,
time: time.value as string,
time: props.multiple ? '' : time.value,
disableDate: props.disableDate,
disableTime: props.disableTime,
firstDayOfWeek: props.firstDayOfWeek,
timePickerProps: props.timePickerProps,
enableTimePicker: props.enableTimePicker,
enableTimePicker: props.multiple ? false : props.enableTimePicker,
presetsPlacement: props.presetsPlacement,
popupVisible: popupVisible.value,
multiple: props.multiple,
onCellClick,
onCellMouseEnter,
onCellMouseLeave,
Expand All @@ -263,7 +311,10 @@ export default defineComponent({
popupVisible,
panelProps,
isDisabled,
onTagRemoveClick,
onTagClearClick,
CalendarIcon,
global,
};
},
render() {
Expand All @@ -275,6 +326,8 @@ export default defineComponent({
popupVisible,
panelProps,
isDisabled,
onTagRemoveClick,
onTagClearClick,
CalendarIcon,
} = this;

Expand All @@ -292,16 +345,25 @@ export default defineComponent({
disabled={isDisabled}
readonly={this.readonly}
value={inputValue}
inputValue={inputValue}
inputValue={this.multiple ? '' : inputValue}
label={this.label}
status={this.status}
tips={this.tips}
popupProps={datePickerPopupProps}
inputProps={{ suffixIcon: renderSuffixIcon(), ...datePickerInputProps }}
inputProps={{ ...datePickerInputProps }}
popupVisible={popupVisible}
clearable={this.clearable}
allowInput={this.allowInput && !this.readonly}
panel={() => <TSinglePanel {...{ props: panelProps }} />}
multiple={this.multiple}
placeholder={
this.placeholder ?? (this.global.placeholder as { [key in typeof this.mode]: string })[this.mode]
}
suffixIcon={renderSuffixIcon()}
tagInputProps={{
onRemove: onTagRemoveClick,
}}
onClear={onTagClearClick}
/>
</div>
);
Expand Down
22 changes: 11 additions & 11 deletions src/date-picker/DatePickerPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default defineComponent({
}

// 头部快速切换
function onJumperClick({ trigger }: { trigger: string }) {
function onJumperClick({ trigger }: { trigger: 'prev' | 'next' | 'current' }) {
const triggerMap = {
prev: 'arrow-previous',
next: 'arrow-next',
Expand Down Expand Up @@ -95,24 +95,24 @@ export default defineComponent({
if (year.value !== nextYear) {
props.onYearChange?.({
year: nextYear,
date: dayjs(value.value).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: trigger === 'current' ? 'today' : (`year-${triggerMap[trigger]}` as DatePickerYearChangeTrigger),
});
emit('year-change', {
year: nextYear,
date: dayjs(value.value).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: trigger === 'current' ? 'today' : (`year-${triggerMap[trigger]}` as DatePickerYearChangeTrigger),
});
}
if (month.value !== nextMonth) {
props.onMonthChange?.({
month: nextMonth,
date: dayjs(value.value).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: trigger === 'current' ? 'today' : (`month-${triggerMap[trigger]}` as DatePickerMonthChangeTrigger),
});
emit('month-change', {
month: nextMonth,
date: dayjs(value.value).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: trigger === 'current' ? 'today' : (`month-${triggerMap[trigger]}` as DatePickerMonthChangeTrigger),
});
}
Expand Down Expand Up @@ -142,12 +142,12 @@ export default defineComponent({

props.onTimeChange?.({
time: val,
date: parseToDayjs(value.value, formatRef.value.format).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: 'time-hour',
});
emit('time-change', {
time: val,
date: parseToDayjs(value.value, formatRef.value.format).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: 'time-hour',
});
}
Expand Down Expand Up @@ -183,12 +183,12 @@ export default defineComponent({

props.onYearChange?.({
year: year.value,
date: parseToDayjs(value.value, formatRef.value.format).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: 'year-select',
});
emit('year-change', {
year: year.value,
date: parseToDayjs(value.value, formatRef.value.format).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: 'year-select',
});
}
Expand All @@ -198,12 +198,12 @@ export default defineComponent({

props.onMonthChange?.({
month: month.value,
date: parseToDayjs(value.value, formatRef.value.format).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: 'month-select',
});
emit('month-change', {
month: month.value,
date: parseToDayjs(value.value, formatRef.value.format).toDate(),
date: parseToDayjs(value.value as DateValue, formatRef.value.format).toDate(),
trigger: 'month-select',
});
}
Expand Down
3 changes: 2 additions & 1 deletion src/date-picker/DateRangePickerPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import TRangePanel from './panel/RangePanel';
import useRangeValue from './hooks/useRangeValue';
import { formatDate, getDefaultFormat, parseToDayjs } from '../_common/js/date-picker/format';
import { subtractMonth, addMonth, extractTimeObj } from '../_common/js/date-picker/utils';
import type { TdDateRangePickerProps } from './type';
import { dateCorrection } from './utils';

export default defineComponent({
Expand All @@ -37,7 +38,7 @@ export default defineComponent({
panelPreselection: dateRangePickerProps.panelPreselection,
...dateRangePickerPanelProps,
},
setup(props: TdDateRangePickerPanelProps, { emit, attrs }) {
setup(props: TdDateRangePickerPanelProps & { disableTime: TdDateRangePickerProps['disableTime'] }, { emit, attrs }) {
const {
value, year, month, time, cacheValue, isFirstValueSelected, onChange,
} = useRangeValue(props);
Expand Down
16 changes: 16 additions & 0 deletions src/date-picker/_example-composition/multiple.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<t-space direction="vertical">
<t-date-picker v-model="date" placeholder="可清除、可输入的日期选择器" clearable multiple @change="handleChange" />
</t-space>
</template>

<script setup>
import { ref } from 'vue';

const date = ref(['2000-01-04', '2000-01-03', '2000-01-05']);
const handleChange = (value, context) => {
console.log('onChange:', value, context);
console.log('timestamp:', context.dayjsValue.valueOf());
console.log('YYYYMMDD:', context.dayjsValue.format('YYYYMMDD'));
};
</script>
2 changes: 1 addition & 1 deletion src/date-picker/_example/base.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<t-space direction="vertical">
<t-date-picker v-model="date2" @change="handleChange" :firstDayOfWeek="3" :inputProps="inputProps" />
<t-date-picker v-model="date2" @change="handleChange" :firstDayOfWeek="3" :inputProps="inputProps" readonly />
<t-date-picker
v-model="date"
placeholder="可清除、可输入的日期选择器"
Expand Down
22 changes: 22 additions & 0 deletions src/date-picker/_example/multiple.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<template>
<t-space direction="vertical">
<t-date-picker v-model="date" placeholder="支持日期的多选" clearable multiple @change="handleChange" />
</t-space>
</template>

<script>
export default {
data() {
return {
date: ['2024-01-04'],
};
},
methods: {
handleChange(value, context) {
console.log('onChange:', value, context);
console.log('timestamp:', context.dayjsValue.valueOf());
console.log('YYYYMMDD:', context.dayjsValue.format('YYYYMMDD'));
},
},
};
</script>
Loading
Loading