mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-12-15 01:11:53 +08:00
3aeeeb2aed
* refactor: transfer、tooltip (#4306) * refactor(transfer): use composition api (#4135) * refactor(transfer): use composition api * fix: remove console * refactor(tooltip): use composition api (#4059) * refactor(tooltip): use composition api * chore: useConfigInject * fix: remove useless * style: format code * refactor: transfer * refactor: tooltip Co-authored-by: ajuner <106791576@qq.com> * Refactor mentions (#4341) * refactor(mentions): use compositionAPI (#4313) * refactor: mentions * refactor: mentions Co-authored-by: ajuner <106791576@qq.com> * Refactor progress (#4358) * fix: timepicker error border not show #4331 * fix(UploadDragger): fix UploadDrager no export (#4334) * refactor(switch): support customize checked value #4329 (#4332) * refactor(switch): support customize checked value #4329 * test: add test case * refactor: update props name * refactor: update ts * refactor: optimize * style: uncheckedValue to unCheckedValue * test: update snap * feat: udpate switch ts * docs: remove ie11 * fix: tree-select throw error when use slot title * fix: TypeScript definition of Table interface for typescript 4.3.5 (#4353) * fix type for typescript 4.3.5 * Update interface.ts close #4296 * fix: dropdown submenu style error #4351 close #4351 * fix(notification): 完善notification类型 (#4346) * refactor(progress): use composition API (#4355) * refactor(progress): use composition API * refactor(vc-progress): update * refactor: progress * refactor: progress * fix: timepicker error border not show #4331 * fix(UploadDragger): fix UploadDrager no export (#4334) * refactor(switch): support customize checked value #4329 (#4332) * refactor(switch): support customize checked value #4329 * test: add test case * refactor: update props name * refactor: update ts * refactor: optimize * style: uncheckedValue to unCheckedValue * test: update snap * feat: udpate switch ts * docs: remove ie11 * fix: tree-select throw error when use slot title * fix: TypeScript definition of Table interface for typescript 4.3.5 (#4353) * fix type for typescript 4.3.5 * Update interface.ts close #4296 * fix: dropdown submenu style error #4351 close #4351 * fix(notification): 完善notification类型 (#4346) * refactor(progress): use composition API (#4355) * refactor(progress): use composition API * refactor(vc-progress): update * refactor: progress * refactor: progress Co-authored-by: Jarvis <35361626+fanhaoyuan@users.noreply.github.com> Co-authored-by: John <John60676@qq.com> Co-authored-by: 艾斯特洛 <axetroy.dev@gmail.com> Co-authored-by: zanllp <qc@zanllp.cn> * docs: add changelog * refactor: tree * refactor: tree * style: lint * refactor: tree * 热factor: tree * refactor: tree * refactor: tree * refactor: tree * refactor: directory tree * refactor: tree * refactor: tree-select * refactor: tree-select * refactor: tree-select * refactor: tree-select * refactor: tree-select * style: lint format * refactor: tree-select * refactor: tree-select * refactor: tree-select * refactor: tree-select * refactor: tree-select * refactor: tree-select * fix: upload ts error * fix: update tree title render & switchIcon * test: update tree test * feat: add VirtualScroll tree * refactor: datePicker & calendar & trigger (#4522) * style: update * test: update calendar test * test: update test * test: update test * refactor: slider * feat: update slider css * refactor: slider to ts * refactor: slider to ts * perf: update default itemHeight * test: update * fix: uddate ts type * fix: update skeleton * fix: update skeleton * refactor: update vc-pagination * refactor: pagination * refactor: timeline * refactor: steps * refactor: collapse * refactor: collapse * refactor: popconfirm * refactor: popover * refactor: dropdown * doc: merge doc * chore: vite for dev (#4602) * style: js to jsx * doc: add site * style: lint * style: format ts type * doc: update * style: format code * style: format site * doc: update * style: dmeo * style: format scripts * chore: remove sub-modules * chore: update vite * site: add site build * test: update snap * doc(select): add tip (#4606) * refactor: table (#4641) * refactor: table * refactor: table * refactor: table * refactor: table * refactor: table * refactor: table * refactor: table * refactor: table * refactor: table * fix: column not pass to cell * doc: uppate table * fix: update bodyCell headerCell * doc: remove examples * refactor: table * fix: table title not work * fix: table selection * fix: table checkStrictly * refactor: table * fix: table template error * feat: table support summary * test: update snap * perf: table * docs(table): fix ajax demo (#4639) * test: update table * refactor: remove old table * doc: update table doc * doc: update doc * doc: update select * doc: update summary Co-authored-by: John <John60676@qq.com> * doc: update doc * fix: menu arrow not work * test: update * doc: add next site * style: format * doc: update * doc: update site script * fix: expand icon not fixed * feat: use renderSlot * test: update table snap * feat: confirm support reactively * feat: configProvider.config * feat: message support configprovider.config * feat: notification support configprovider.config * doc: update doc * fix: typescript compile error * style: add import eslint * doc: update demo * chore: set transpileOnly true * style: fix eslint error * test: update snap * doc: update * test: mock date * test: update snap * chore: remove gulp-typescript (#4675) * feat: V3 form (#4678) * chore: update husky * perf: update formItem * perf: useInjectFormItemContext * fix: table ts error * doc: add Customized Form Controls demo * feat: export useInjectFormItemContext * doc: update form doc * doc: update doc * doc: update doc * feat: autocomplete support option slot * doc: update * feat: add form item rest * style: remove omit.js * refactor: autocomplete * doc: add changelog to site * doc: update site anchor * doc: update doc layout * test: update table test * doc: update * chore: udpate gulp script * chore: udpate gulp script * doc: add changelog * doc: update * test: ignore some test wait vue-test-utils * fix: form id error #4582 close #4582 * doc: add select Responsive demo * doc: remove temp doc Co-authored-by: ajuner <106791576@qq.com> Co-authored-by: Jarvis <35361626+fanhaoyuan@users.noreply.github.com> Co-authored-by: John <John60676@qq.com> Co-authored-by: 艾斯特洛 <axetroy.dev@gmail.com> Co-authored-by: zanllp <qc@zanllp.cn> Co-authored-by: Amour1688 <lcz_1996@foxmail.com>
338 lines
11 KiB
Vue
338 lines
11 KiB
Vue
import useMergedState from '../_util/hooks/useMergedState';
|
|
import padStart from 'lodash-es/padStart';
|
|
import { PickerPanel } from '../vc-picker';
|
|
import type { Locale } from '../vc-picker/interface';
|
|
import type { GenerateConfig } from '../vc-picker/generate';
|
|
import type {
|
|
PickerPanelBaseProps as RCPickerPanelBaseProps,
|
|
PickerPanelDateProps as RCPickerPanelDateProps,
|
|
PickerPanelTimeProps as RCPickerPanelTimeProps,
|
|
} from '../vc-picker/PickerPanel';
|
|
import { useLocaleReceiver } from '../locale-provider/LocaleReceiver';
|
|
import enUS from './locale/en_US';
|
|
import CalendarHeader from './Header';
|
|
import type { VueNode } from '../_util/type';
|
|
import type { App } from 'vue';
|
|
import { computed, defineComponent, toRef } from 'vue';
|
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
|
import classNames from '../_util/classNames';
|
|
|
|
type InjectDefaultProps<Props> = Omit<
|
|
Props,
|
|
'locale' | 'generateConfig' | 'prevIcon' | 'nextIcon' | 'superPrevIcon' | 'superNextIcon'
|
|
> & {
|
|
locale?: typeof enUS;
|
|
size?: 'large' | 'default' | 'small';
|
|
};
|
|
|
|
// Picker Props
|
|
export type PickerPanelBaseProps<DateType> = InjectDefaultProps<RCPickerPanelBaseProps<DateType>>;
|
|
export type PickerPanelDateProps<DateType> = InjectDefaultProps<RCPickerPanelDateProps<DateType>>;
|
|
export type PickerPanelTimeProps<DateType> = InjectDefaultProps<RCPickerPanelTimeProps<DateType>>;
|
|
|
|
export type PickerProps<DateType> =
|
|
| PickerPanelBaseProps<DateType>
|
|
| PickerPanelDateProps<DateType>
|
|
| PickerPanelTimeProps<DateType>;
|
|
|
|
export type CalendarMode = 'year' | 'month';
|
|
export type HeaderRender<DateType> = (config: {
|
|
value: DateType;
|
|
type: CalendarMode;
|
|
onChange: (date: DateType) => void;
|
|
onTypeChange: (type: CalendarMode) => void;
|
|
}) => VueNode;
|
|
|
|
type CustomRenderType<DateType> = (config: { current: DateType }) => VueNode;
|
|
|
|
export interface CalendarProps<DateType> {
|
|
prefixCls?: string;
|
|
locale?: typeof enUS;
|
|
validRange?: [DateType, DateType];
|
|
disabledDate?: (date: DateType) => boolean;
|
|
dateFullCellRender?: CustomRenderType<DateType>;
|
|
dateCellRender?: CustomRenderType<DateType>;
|
|
monthFullCellRender?: CustomRenderType<DateType>;
|
|
monthCellRender?: CustomRenderType<DateType>;
|
|
headerRender?: HeaderRender<DateType>;
|
|
value?: DateType | string;
|
|
defaultValue?: DateType | string;
|
|
mode?: CalendarMode;
|
|
fullscreen?: boolean;
|
|
onChange?: (date: DateType | string) => void;
|
|
onPanelChange?: (date: DateType | string, mode: CalendarMode) => void;
|
|
onSelect?: (date: DateType | string) => void;
|
|
valueFormat?: string;
|
|
}
|
|
|
|
function generateCalendar<
|
|
DateType,
|
|
Props extends CalendarProps<DateType> = CalendarProps<DateType>,
|
|
>(generateConfig: GenerateConfig<DateType>) {
|
|
function isSameYear(date1: DateType, date2: DateType) {
|
|
return date1 && date2 && generateConfig.getYear(date1) === generateConfig.getYear(date2);
|
|
}
|
|
|
|
function isSameMonth(date1: DateType, date2: DateType) {
|
|
return (
|
|
isSameYear(date1, date2) && generateConfig.getMonth(date1) === generateConfig.getMonth(date2)
|
|
);
|
|
}
|
|
|
|
function isSameDate(date1: DateType, date2: DateType) {
|
|
return (
|
|
isSameMonth(date1, date2) && generateConfig.getDate(date1) === generateConfig.getDate(date2)
|
|
);
|
|
}
|
|
|
|
const Calendar = defineComponent<Props>({
|
|
name: 'ACalendar',
|
|
inheritAttrs: false,
|
|
emits: ['change', 'panelChange', 'select', 'update:value'],
|
|
slots: [
|
|
'dateFullCellRender',
|
|
'dateCellRender',
|
|
'monthFullCellRender',
|
|
'monthCellRender',
|
|
'headerRender',
|
|
],
|
|
setup(props, { emit, slots, attrs }) {
|
|
const { prefixCls, direction } = useConfigInject('picker', props);
|
|
const calendarPrefixCls = computed(() => `${prefixCls.value}-calendar`);
|
|
const maybeToString = (date: DateType) => {
|
|
return props.valueFormat ? generateConfig.toString(date, props.valueFormat) : date;
|
|
};
|
|
const value = computed(() => {
|
|
if (props.value) {
|
|
return props.valueFormat
|
|
? (generateConfig.toDate(props.value, props.valueFormat) as DateType)
|
|
: (props.value as DateType);
|
|
}
|
|
return props.value as DateType;
|
|
});
|
|
const defaultValue = computed(() => {
|
|
if (props.defaultValue) {
|
|
return props.valueFormat
|
|
? (generateConfig.toDate(props.defaultValue, props.valueFormat) as DateType)
|
|
: (props.defaultValue as DateType);
|
|
}
|
|
return props.defaultValue as DateType;
|
|
});
|
|
|
|
// Value
|
|
const [mergedValue, setMergedValue] = useMergedState(
|
|
() => value.value || generateConfig.getNow(),
|
|
{
|
|
defaultValue: defaultValue.value,
|
|
value,
|
|
},
|
|
);
|
|
|
|
// Mode
|
|
const [mergedMode, setMergedMode] = useMergedState('month', {
|
|
value: toRef(props, 'mode'),
|
|
});
|
|
|
|
const panelMode = computed(() => (mergedMode.value === 'year' ? 'month' : 'date'));
|
|
|
|
const mergedDisabledDate = computed(() => {
|
|
return (date: DateType) => {
|
|
const notInRange = props.validRange
|
|
? generateConfig.isAfter(props.validRange[0], date) ||
|
|
generateConfig.isAfter(date, props.validRange[1])
|
|
: false;
|
|
return notInRange || !!props.disabledDate?.(date);
|
|
};
|
|
});
|
|
|
|
// ====================== Events ======================
|
|
const triggerPanelChange = (date: DateType, newMode: CalendarMode) => {
|
|
emit('panelChange', maybeToString(date), newMode);
|
|
};
|
|
|
|
const triggerChange = (date: DateType) => {
|
|
setMergedValue(date);
|
|
|
|
if (!isSameDate(date, mergedValue.value)) {
|
|
// Trigger when month panel switch month
|
|
if (
|
|
(panelMode.value === 'date' && !isSameMonth(date, mergedValue.value)) ||
|
|
(panelMode.value === 'month' && !isSameYear(date, mergedValue.value))
|
|
) {
|
|
triggerPanelChange(date, mergedMode.value);
|
|
}
|
|
const val = maybeToString(date);
|
|
emit('update:value', val);
|
|
emit('change', val);
|
|
}
|
|
};
|
|
|
|
const triggerModeChange = (newMode: CalendarMode) => {
|
|
setMergedMode(newMode);
|
|
triggerPanelChange(mergedValue.value, newMode);
|
|
};
|
|
|
|
const onInternalSelect = (date: DateType) => {
|
|
triggerChange(date);
|
|
emit('select', maybeToString(date));
|
|
};
|
|
// ====================== Locale ======================
|
|
const defaultLocale = computed(() => {
|
|
const { locale } = props;
|
|
const result = {
|
|
...enUS,
|
|
...locale,
|
|
};
|
|
result.lang = {
|
|
...result.lang,
|
|
...(locale || {}).lang,
|
|
};
|
|
return result;
|
|
});
|
|
|
|
const [mergedLocale] = useLocaleReceiver('Calendar', defaultLocale) as [typeof defaultLocale];
|
|
|
|
return () => {
|
|
const today = generateConfig.getNow();
|
|
const {
|
|
dateFullCellRender = slots?.dateFullCellRender,
|
|
dateCellRender = slots?.dateCellRender,
|
|
monthFullCellRender = slots?.monthFullCellRender,
|
|
monthCellRender = slots?.monthCellRender,
|
|
headerRender = slots?.headerRender,
|
|
fullscreen = true,
|
|
validRange,
|
|
} = props;
|
|
// ====================== Render ======================
|
|
const dateRender = ({ current: date }) => {
|
|
if (dateFullCellRender) {
|
|
return dateFullCellRender({ current: date });
|
|
}
|
|
return (
|
|
<div
|
|
class={classNames(
|
|
`${prefixCls.value}-cell-inner`,
|
|
`${calendarPrefixCls.value}-date`,
|
|
{
|
|
[`${calendarPrefixCls.value}-date-today`]: isSameDate(today, date),
|
|
},
|
|
)}
|
|
>
|
|
<div class={`${calendarPrefixCls.value}-date-value`}>
|
|
{padStart(String(generateConfig.getDate(date)), 2, '0')}
|
|
</div>
|
|
<div class={`${calendarPrefixCls.value}-date-content`}>
|
|
{dateCellRender && dateCellRender({ current: date })}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const monthRender = ({ current: date }, locale: Locale) => {
|
|
if (monthFullCellRender) {
|
|
return monthFullCellRender({ current: date });
|
|
}
|
|
|
|
const months = locale.shortMonths || generateConfig.locale.getShortMonths!(locale.locale);
|
|
|
|
return (
|
|
<div
|
|
class={classNames(
|
|
`${prefixCls.value}-cell-inner`,
|
|
`${calendarPrefixCls.value}-date`,
|
|
{
|
|
[`${calendarPrefixCls.value}-date-today`]: isSameMonth(today, date),
|
|
},
|
|
)}
|
|
>
|
|
<div class={`${calendarPrefixCls.value}-date-value`}>
|
|
{months[generateConfig.getMonth(date)]}
|
|
</div>
|
|
<div class={`${calendarPrefixCls.value}-date-content`}>
|
|
{monthCellRender && monthCellRender({ current: date })}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
return (
|
|
<div
|
|
{...attrs}
|
|
class={classNames(
|
|
calendarPrefixCls.value,
|
|
{
|
|
[`${calendarPrefixCls.value}-full`]: fullscreen,
|
|
[`${calendarPrefixCls.value}-mini`]: !fullscreen,
|
|
[`${calendarPrefixCls.value}-rtl`]: direction.value === 'rtl',
|
|
},
|
|
attrs.class,
|
|
)}
|
|
>
|
|
{headerRender ? (
|
|
headerRender({
|
|
value: mergedValue.value,
|
|
type: mergedMode.value,
|
|
onChange: onInternalSelect,
|
|
onTypeChange: triggerModeChange,
|
|
})
|
|
) : (
|
|
<CalendarHeader
|
|
prefixCls={calendarPrefixCls.value}
|
|
value={mergedValue.value}
|
|
generateConfig={generateConfig}
|
|
mode={mergedMode.value}
|
|
fullscreen={fullscreen}
|
|
locale={mergedLocale.value.lang}
|
|
validRange={validRange}
|
|
onChange={onInternalSelect}
|
|
onModeChange={triggerModeChange}
|
|
/>
|
|
)}
|
|
<PickerPanel
|
|
value={mergedValue.value}
|
|
prefixCls={prefixCls.value}
|
|
locale={mergedLocale.value.lang}
|
|
generateConfig={generateConfig}
|
|
dateRender={dateRender}
|
|
monthCellRender={obj => monthRender(obj, mergedLocale.value.lang)}
|
|
onSelect={onInternalSelect}
|
|
mode={panelMode.value}
|
|
picker={panelMode.value}
|
|
disabledDate={mergedDisabledDate.value}
|
|
hideHeader
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
},
|
|
});
|
|
|
|
Calendar.props = [
|
|
'prefixCls',
|
|
'locale',
|
|
'validRange',
|
|
'disabledDate',
|
|
'dateFullCellRender',
|
|
'dateCellRender',
|
|
'monthFullCellRender',
|
|
'monthCellRender',
|
|
'headerRender',
|
|
'value',
|
|
'defaultValue',
|
|
'mode',
|
|
'fullscreen',
|
|
'onChange',
|
|
'onPanelChange',
|
|
'onSelect',
|
|
'valueFormat',
|
|
];
|
|
|
|
Calendar.install = function (app: App) {
|
|
app.component(Calendar.name, Calendar);
|
|
return app;
|
|
};
|
|
|
|
return Calendar;
|
|
}
|
|
|
|
export default generateCalendar;
|