Merge branch 'v2.3' into refactor-tree
commit
4465b73602
|
@ -73,3 +73,5 @@ site/dev.js
|
|||
|
||||
# IDE 语法提示临时文件
|
||||
vetur/
|
||||
|
||||
report.html
|
||||
|
|
|
@ -80,7 +80,6 @@ function getWebpackConfig(modules) {
|
|||
},
|
||||
|
||||
module: {
|
||||
noParse: [/moment.js/],
|
||||
rules: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
export type FocusEventHandler = (e: FocusEvent) => void;
|
||||
export type MouseEventHandler = (e: MouseEvent) => void;
|
||||
export type KeyboardEventHandler = (e: KeyboardEvent) => void;
|
||||
export type ChangeEvent = Event & {
|
||||
target: {
|
||||
value?: string | undefined;
|
||||
};
|
||||
};
|
|
@ -1,48 +1,38 @@
|
|||
import PropTypes from './vue-types';
|
||||
import { defineComponent, nextTick, Teleport } from 'vue';
|
||||
import {
|
||||
defineComponent,
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
onUpdated,
|
||||
ref,
|
||||
Teleport,
|
||||
} from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Portal',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
getContainer: PropTypes.func.isRequired,
|
||||
children: PropTypes.any.isRequired,
|
||||
didUpdate: PropTypes.func,
|
||||
},
|
||||
data() {
|
||||
this._container = null;
|
||||
return {};
|
||||
},
|
||||
mounted() {
|
||||
this.createContainer();
|
||||
},
|
||||
updated() {
|
||||
const { didUpdate } = this.$props;
|
||||
if (didUpdate) {
|
||||
setup(props, { slots }) {
|
||||
const container = ref();
|
||||
onMounted(() => {
|
||||
container.value = props.getContainer();
|
||||
});
|
||||
onUpdated(() => {
|
||||
nextTick(() => {
|
||||
didUpdate(this.$props);
|
||||
props.nextTick?.(props);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
this.removeContainer();
|
||||
},
|
||||
methods: {
|
||||
createContainer() {
|
||||
this._container = this.$props.getContainer();
|
||||
this.$forceUpdate();
|
||||
},
|
||||
removeContainer() {
|
||||
if (this._container && this._container.parentNode) {
|
||||
this._container.parentNode.removeChild(this._container);
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
if (container.value && container.value.parentNode) {
|
||||
container.value.parentNode.removeChild(container.value);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
if (this._container) {
|
||||
return <Teleport to={this._container}>{this.$props.children}</Teleport>;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
return () => {
|
||||
return container.value ? <Teleport to={container.value}>{slots.default?.()}</Teleport> : null;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -20,7 +20,6 @@ export default defineComponent({
|
|||
wrapperClassName: PropTypes.string,
|
||||
forceRender: PropTypes.looseBool,
|
||||
getContainer: PropTypes.any,
|
||||
children: PropTypes.func,
|
||||
visible: PropTypes.looseBool,
|
||||
},
|
||||
data() {
|
||||
|
@ -130,7 +129,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
render() {
|
||||
const { children, forceRender, visible } = this.$props;
|
||||
const { forceRender, visible } = this.$props;
|
||||
let portal = null;
|
||||
const childProps = {
|
||||
getOpenCount: () => openCount,
|
||||
|
@ -141,8 +140,8 @@ export default defineComponent({
|
|||
portal = (
|
||||
<Portal
|
||||
getContainer={this.getDomContainer}
|
||||
children={children(childProps)}
|
||||
ref={this.savePortal}
|
||||
v-slots={{ default: () => this.$slots.default?.(childProps) }}
|
||||
></Portal>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ export default (
|
|||
): {
|
||||
configProvider: UnwrapRef<ConfigProviderProps>;
|
||||
prefixCls: ComputedRef<string>;
|
||||
rootPrefixCls: ComputedRef<string>;
|
||||
direction: ComputedRef<Direction>;
|
||||
size: ComputedRef<SizeType>;
|
||||
getTargetContainer: ComputedRef<() => HTMLElement>;
|
||||
|
@ -30,12 +31,12 @@ export default (
|
|||
);
|
||||
const prefixCls = computed(() => configProvider.getPrefixCls(name, props.prefixCls));
|
||||
const direction = computed(() => props.direction ?? configProvider.direction);
|
||||
const rootPrefixCls = computed(() => configProvider.getPrefixCls());
|
||||
const autoInsertSpaceInButton = computed(() => configProvider.autoInsertSpaceInButton);
|
||||
const renderEmpty = computed(() => configProvider.renderEmpty);
|
||||
const space = computed(() => configProvider.space);
|
||||
const pageHeader = computed(() => configProvider.pageHeader);
|
||||
const form = computed(() => configProvider.form);
|
||||
const size = computed(() => props.size ?? configProvider.componentSize);
|
||||
const getTargetContainer = computed(
|
||||
() => props.getTargetContainer || configProvider.getTargetContainer,
|
||||
);
|
||||
|
@ -46,12 +47,14 @@ export default (
|
|||
const dropdownMatchSelectWidth = computed<boolean>(
|
||||
() => props.dropdownMatchSelectWidth ?? configProvider.dropdownMatchSelectWidth,
|
||||
);
|
||||
const size = computed(() => props.size || configProvider.componentSize);
|
||||
return {
|
||||
configProvider,
|
||||
prefixCls,
|
||||
direction,
|
||||
size,
|
||||
getTargetContainer,
|
||||
getPopupContainer,
|
||||
space,
|
||||
pageHeader,
|
||||
form,
|
||||
|
@ -59,6 +62,6 @@ export default (
|
|||
renderEmpty,
|
||||
virtual,
|
||||
dropdownMatchSelectWidth,
|
||||
getPopupContainer,
|
||||
rootPrefixCls,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import type { Ref } from 'vue';
|
||||
import type { Ref, WatchSource } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
export default function useMemo<T>(
|
||||
getValue: () => T,
|
||||
condition: any[],
|
||||
condition: (WatchSource<unknown> | object)[],
|
||||
shouldUpdate?: (prev: any[], next: any[]) => boolean,
|
||||
) {
|
||||
const cacheRef: Ref<T> = ref(getValue() as any);
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import type { Ref, UnwrapRef } from 'vue';
|
||||
import { toRaw } from 'vue';
|
||||
import { watchEffect } from 'vue';
|
||||
import { unref } from 'vue';
|
||||
import { watch } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default function useMergedState<T, R = Ref<T>>(
|
||||
defaultStateValue: T | (() => T),
|
||||
option?: {
|
||||
defaultValue?: T | (() => T);
|
||||
value?: Ref<T> | Ref<UnwrapRef<T>>;
|
||||
onChange?: (val: T, prevValue: T) => void;
|
||||
postState?: (val: T) => T;
|
||||
},
|
||||
): [R, (val: T) => void] {
|
||||
const { defaultValue, value = ref() } = option || {};
|
||||
let initValue: T =
|
||||
typeof defaultStateValue === 'function' ? (defaultStateValue as any)() : defaultStateValue;
|
||||
if (value.value !== undefined) {
|
||||
initValue = unref(value as any) as T;
|
||||
}
|
||||
if (defaultValue !== undefined) {
|
||||
initValue = typeof defaultValue === 'function' ? (defaultValue as any)() : defaultValue;
|
||||
}
|
||||
|
||||
const innerValue = ref(initValue) as Ref<T>;
|
||||
const mergedValue = ref(initValue) as Ref<T>;
|
||||
watchEffect(() => {
|
||||
let val = value.value !== undefined ? value.value : innerValue.value;
|
||||
if (option.postState) {
|
||||
val = option.postState(val as T);
|
||||
}
|
||||
mergedValue.value = val as T;
|
||||
});
|
||||
|
||||
function triggerChange(newValue: T) {
|
||||
const preVal = mergedValue.value;
|
||||
innerValue.value = newValue;
|
||||
if (toRaw(mergedValue.value) !== newValue && option.onChange) {
|
||||
option.onChange(newValue, preVal);
|
||||
}
|
||||
}
|
||||
|
||||
// Effect of reset value to `undefined`
|
||||
watch(value, () => {
|
||||
innerValue.value = value.value as T;
|
||||
});
|
||||
|
||||
return [mergedValue as unknown as R, triggerChange];
|
||||
}
|
|
@ -2,9 +2,9 @@ import type { Ref } from 'vue';
|
|||
import { onBeforeUpdate, ref } from 'vue';
|
||||
|
||||
export type UseRef = [(el: any, key: string | number) => void, Ref<any>];
|
||||
|
||||
export type Refs = Record<string | number, any>;
|
||||
export const useRef = (): UseRef => {
|
||||
const refs = ref<any>({});
|
||||
const refs = ref<Refs>({});
|
||||
const setRef = (el: any, key: string | number) => {
|
||||
refs.value[key] = el;
|
||||
};
|
||||
|
@ -13,3 +13,5 @@ export const useRef = (): UseRef => {
|
|||
});
|
||||
return [setRef, refs];
|
||||
};
|
||||
|
||||
export default useRef;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import type { Ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default function useState<T, R = Ref<T>>(
|
||||
defaultStateValue: T | (() => T),
|
||||
): [R, (val: T) => void] {
|
||||
const initValue: T =
|
||||
typeof defaultStateValue === 'function' ? (defaultStateValue as any)() : defaultStateValue;
|
||||
|
||||
const innerValue = ref(initValue) as Ref<T>;
|
||||
|
||||
function triggerChange(newValue: T) {
|
||||
innerValue.value = newValue;
|
||||
}
|
||||
|
||||
return [innerValue as unknown as R, triggerChange];
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
// https://github.com/moment/moment/issues/3650
|
||||
export default function interopDefault(m) {
|
||||
return m.default || m;
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
import interopDefault from './interopDefault';
|
||||
import moment from 'moment';
|
||||
import warning from './warning';
|
||||
import isNil from 'lodash-es/isNil';
|
||||
|
||||
export const TimeType = {
|
||||
validator(value) {
|
||||
return typeof value === 'string' || isNil(value) || moment.isMoment(value);
|
||||
},
|
||||
};
|
||||
|
||||
export const TimesType = {
|
||||
validator(value) {
|
||||
if (Array.isArray(value)) {
|
||||
return (
|
||||
value.length === 0 ||
|
||||
value.findIndex(val => typeof val !== 'string') === -1 ||
|
||||
value.findIndex(val => !isNil(val) && !moment.isMoment(val)) === -1
|
||||
);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
export const TimeOrTimesType = {
|
||||
validator(value) {
|
||||
if (Array.isArray(value)) {
|
||||
return (
|
||||
value.length === 0 ||
|
||||
value.findIndex(val => typeof val !== 'string') === -1 ||
|
||||
value.findIndex(val => !isNil(val) && !moment.isMoment(val)) === -1
|
||||
);
|
||||
} else {
|
||||
return typeof value === 'string' || isNil(value) || moment.isMoment(value);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export function checkValidate(componentName, value, propName, valueFormat) {
|
||||
const values = Array.isArray(value) ? value : [value];
|
||||
values.forEach(val => {
|
||||
if (!val) return;
|
||||
valueFormat &&
|
||||
warning(
|
||||
interopDefault(moment)(val, valueFormat).isValid(),
|
||||
componentName,
|
||||
`When set \`valueFormat\`, \`${propName}\` should provides invalidate string time. `,
|
||||
);
|
||||
!valueFormat &&
|
||||
warning(
|
||||
interopDefault(moment).isMoment(val) && val.isValid(),
|
||||
componentName,
|
||||
`\`${propName}\` provides invalidate moment time. If you want to set empty value, use \`null\` instead.`,
|
||||
);
|
||||
});
|
||||
}
|
||||
export const stringToMoment = (value, valueFormat) => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(val =>
|
||||
typeof val === 'string' && val ? interopDefault(moment)(val, valueFormat) : val || null,
|
||||
);
|
||||
} else {
|
||||
return typeof value === 'string' && value
|
||||
? interopDefault(moment)(value, valueFormat)
|
||||
: value || null;
|
||||
}
|
||||
};
|
||||
|
||||
export const momentToString = (value, valueFormat) => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(val => (interopDefault(moment).isMoment(val) ? val.format(valueFormat) : val));
|
||||
} else {
|
||||
return interopDefault(moment).isMoment(value) ? value.format(valueFormat) : value;
|
||||
}
|
||||
};
|
|
@ -1,20 +1,27 @@
|
|||
import type { BaseTransitionProps, CSSProperties, Ref } from 'vue';
|
||||
import type {
|
||||
BaseTransitionProps,
|
||||
CSSProperties,
|
||||
Ref,
|
||||
TransitionGroupProps,
|
||||
TransitionProps,
|
||||
} from 'vue';
|
||||
import { onBeforeUpdate } from 'vue';
|
||||
import { getCurrentInstance } from 'vue';
|
||||
import { defineComponent, nextTick, Transition as T, TransitionGroup as TG } from 'vue';
|
||||
|
||||
export const getTransitionProps = (transitionName: string, opt: object = {}) => {
|
||||
export const getTransitionProps = (transitionName: string, opt: TransitionProps = {}) => {
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
return opt;
|
||||
}
|
||||
const transitionProps = transitionName
|
||||
const transitionProps: TransitionProps = transitionName
|
||||
? {
|
||||
appear: true,
|
||||
// type: 'animation',
|
||||
// appearFromClass: `${transitionName}-appear ${transitionName}-appear-prepare`,
|
||||
// appearActiveClass: `antdv-base-transtion`,
|
||||
appearToClass: `${transitionName}-appear ${transitionName}-appear-active`,
|
||||
// appearToClass: `${transitionName}-appear ${transitionName}-appear-active`,
|
||||
enterFromClass: `${transitionName}-enter ${transitionName}-enter-prepare`,
|
||||
// enterActiveClass: `antdv-base-transtion`,
|
||||
// enterActiveClass: `${transitionName}-enter ${transitionName}-enter-active`,
|
||||
enterToClass: `${transitionName}-enter ${transitionName}-enter-active`,
|
||||
leaveFromClass: ` ${transitionName}-leave`,
|
||||
leaveActiveClass: `${transitionName}-leave ${transitionName}-leave-active`,
|
||||
|
@ -25,8 +32,8 @@ export const getTransitionProps = (transitionName: string, opt: object = {}) =>
|
|||
return transitionProps;
|
||||
};
|
||||
|
||||
export const getTransitionGroupProps = (transitionName: string, opt: object = {}) => {
|
||||
const transitionProps = transitionName
|
||||
export const getTransitionGroupProps = (transitionName: string, opt: TransitionProps = {}) => {
|
||||
const transitionProps: TransitionGroupProps = transitionName
|
||||
? {
|
||||
appear: true,
|
||||
// appearFromClass: `${transitionName}-appear ${transitionName}-appear-prepare`,
|
||||
|
|
|
@ -1,211 +1,179 @@
|
|||
import type { PropType } from 'vue';
|
||||
import { defineComponent, inject } from 'vue';
|
||||
import Select from '../select';
|
||||
import { Group, Button } from '../radio';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import type { VueNode } from '../_util/type';
|
||||
import type moment from 'moment';
|
||||
import type { RadioChangeEvent } from '../radio/interface';
|
||||
import type { CalendarMode } from './generateCalendar';
|
||||
import type { Ref } from 'vue';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import type { Locale } from '../vc-picker/interface';
|
||||
import type { GenerateConfig } from '../vc-picker/generate';
|
||||
|
||||
function getMonthsLocale(value: moment.Moment): string[] {
|
||||
const current = value.clone();
|
||||
const localeData = value.localeData();
|
||||
const months = [];
|
||||
for (let i = 0; i < 12; i++) {
|
||||
current.month(i);
|
||||
months.push(localeData.monthsShort(current));
|
||||
const YearSelectOffset = 10;
|
||||
const YearSelectTotal = 20;
|
||||
|
||||
interface SharedProps<DateType> {
|
||||
prefixCls: string;
|
||||
value: DateType;
|
||||
validRange?: [DateType, DateType];
|
||||
generateConfig: GenerateConfig<DateType>;
|
||||
locale: Locale;
|
||||
fullscreen: boolean;
|
||||
divRef: Ref<HTMLDivElement>;
|
||||
onChange: (year: DateType) => void;
|
||||
}
|
||||
|
||||
function YearSelect<DateType>(props: SharedProps<DateType>) {
|
||||
const { fullscreen, validRange, generateConfig, locale, prefixCls, value, onChange, divRef } =
|
||||
props;
|
||||
|
||||
const year = generateConfig.getYear(value || generateConfig.getNow());
|
||||
|
||||
let start = year - YearSelectOffset;
|
||||
let end = start + YearSelectTotal;
|
||||
|
||||
if (validRange) {
|
||||
start = generateConfig.getYear(validRange[0]);
|
||||
end = generateConfig.getYear(validRange[1]) + 1;
|
||||
}
|
||||
return months;
|
||||
}
|
||||
export interface RenderHeader {
|
||||
value: moment.Moment;
|
||||
onChange?: (value: moment.Moment) => void;
|
||||
type: string;
|
||||
onTypeChange: (type: string) => void;
|
||||
}
|
||||
export type HeaderRender = (headerRender: RenderHeader) => VueNode;
|
||||
export const HeaderProps = {
|
||||
prefixCls: PropTypes.string,
|
||||
locale: PropTypes.any,
|
||||
fullscreen: PropTypes.looseBool,
|
||||
yearSelectOffset: PropTypes.number,
|
||||
yearSelectTotal: PropTypes.number,
|
||||
type: PropTypes.string,
|
||||
value: {
|
||||
type: Object as PropType<moment.Moment>,
|
||||
},
|
||||
validRange: {
|
||||
type: Array as PropType<moment.Moment[]>,
|
||||
},
|
||||
headerRender: PropTypes.func,
|
||||
onValueChange: PropTypes.func,
|
||||
onTypeChange: PropTypes.func,
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
const suffix = locale && locale.year === '年' ? '年' : '';
|
||||
const options: { label: string; value: number }[] = [];
|
||||
for (let index = start; index < end; index++) {
|
||||
options.push({ label: `${index}${suffix}`, value: index });
|
||||
}
|
||||
return (
|
||||
<Select
|
||||
size={fullscreen ? undefined : 'small'}
|
||||
options={options}
|
||||
value={year}
|
||||
class={`${prefixCls}-year-select`}
|
||||
onChange={numYear => {
|
||||
let newDate = generateConfig.setYear(value, numYear);
|
||||
|
||||
if (validRange) {
|
||||
const [startDate, endDate] = validRange;
|
||||
const newYear = generateConfig.getYear(newDate);
|
||||
const newMonth = generateConfig.getMonth(newDate);
|
||||
if (
|
||||
newYear === generateConfig.getYear(endDate) &&
|
||||
newMonth > generateConfig.getMonth(endDate)
|
||||
) {
|
||||
newDate = generateConfig.setMonth(newDate, generateConfig.getMonth(endDate));
|
||||
}
|
||||
if (
|
||||
newYear === generateConfig.getYear(startDate) &&
|
||||
newMonth < generateConfig.getMonth(startDate)
|
||||
) {
|
||||
newDate = generateConfig.setMonth(newDate, generateConfig.getMonth(startDate));
|
||||
}
|
||||
}
|
||||
|
||||
onChange(newDate);
|
||||
}}
|
||||
getPopupContainer={() => divRef!.value!}
|
||||
/>
|
||||
);
|
||||
}
|
||||
YearSelect.inheritAttrs = false;
|
||||
|
||||
function MonthSelect<DateType>(props: SharedProps<DateType>) {
|
||||
const { prefixCls, fullscreen, validRange, value, generateConfig, locale, onChange, divRef } =
|
||||
props;
|
||||
const month = generateConfig.getMonth(value || generateConfig.getNow());
|
||||
|
||||
let start = 0;
|
||||
let end = 11;
|
||||
|
||||
if (validRange) {
|
||||
const [rangeStart, rangeEnd] = validRange;
|
||||
const currentYear = generateConfig.getYear(value);
|
||||
if (generateConfig.getYear(rangeEnd) === currentYear) {
|
||||
end = generateConfig.getMonth(rangeEnd);
|
||||
}
|
||||
if (generateConfig.getYear(rangeStart) === currentYear) {
|
||||
start = generateConfig.getMonth(rangeStart);
|
||||
}
|
||||
}
|
||||
|
||||
const months = locale.shortMonths || generateConfig.locale.getShortMonths!(locale.locale);
|
||||
const options: { label: string; value: number }[] = [];
|
||||
for (let index = start; index <= end; index += 1) {
|
||||
options.push({
|
||||
label: months[index],
|
||||
value: index,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
size={fullscreen ? undefined : 'small'}
|
||||
class={`${prefixCls}-month-select`}
|
||||
value={month}
|
||||
options={options}
|
||||
onChange={newMonth => {
|
||||
onChange(generateConfig.setMonth(value, newMonth));
|
||||
}}
|
||||
getPopupContainer={() => divRef!.value!}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
MonthSelect.inheritAttrs = false;
|
||||
|
||||
interface ModeSwitchProps<DateType> extends Omit<SharedProps<DateType>, 'onChange'> {
|
||||
mode: CalendarMode;
|
||||
onModeChange: (type: CalendarMode) => void;
|
||||
}
|
||||
|
||||
function ModeSwitch<DateType>(props: ModeSwitchProps<DateType>) {
|
||||
const { prefixCls, locale, mode, fullscreen, onModeChange } = props;
|
||||
return (
|
||||
<Group
|
||||
onChange={({ target: { value } }) => {
|
||||
onModeChange(value);
|
||||
}}
|
||||
value={mode}
|
||||
size={fullscreen ? undefined : 'small'}
|
||||
class={`${prefixCls}-mode-switch`}
|
||||
>
|
||||
<Button value="month">{locale.month}</Button>
|
||||
<Button value="year">{locale.year}</Button>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
ModeSwitch.inheritAttrs = false;
|
||||
|
||||
export interface CalendarHeaderProps<DateType> {
|
||||
prefixCls: string;
|
||||
value: DateType;
|
||||
validRange?: [DateType, DateType];
|
||||
generateConfig: GenerateConfig<DateType>;
|
||||
locale: Locale;
|
||||
mode: CalendarMode;
|
||||
fullscreen: boolean;
|
||||
onChange: (date: DateType) => void;
|
||||
onModeChange: (mode: CalendarMode) => void;
|
||||
}
|
||||
|
||||
export default defineComponent<CalendarHeaderProps<any>>({
|
||||
name: 'CalendarHeader',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
...HeaderProps,
|
||||
yearSelectOffset: PropTypes.number.def(10),
|
||||
yearSelectTotal: PropTypes.number.def(20),
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
calendarHeaderNode: undefined,
|
||||
setup(_props, { attrs }) {
|
||||
const divRef = ref<HTMLDivElement>(null);
|
||||
return () => {
|
||||
const { prefixCls, fullscreen, mode, onChange, onModeChange } = attrs;
|
||||
const sharedProps = {
|
||||
...attrs,
|
||||
onChange,
|
||||
fullscreen,
|
||||
divRef,
|
||||
} as any;
|
||||
|
||||
return (
|
||||
<div class={`${prefixCls}-header`} ref={divRef}>
|
||||
<YearSelect {...sharedProps} />
|
||||
{mode === 'month' && <MonthSelect {...sharedProps} />}
|
||||
<ModeSwitch {...sharedProps} onModeChange={onModeChange} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
// private calendarHeaderNode: HTMLDivElement;
|
||||
methods: {
|
||||
getYearSelectElement(prefixCls: string, year: number) {
|
||||
const { yearSelectOffset, yearSelectTotal, locale = {}, fullscreen, validRange } = this;
|
||||
let start = year - yearSelectOffset;
|
||||
let end = start + yearSelectTotal;
|
||||
if (validRange) {
|
||||
start = validRange[0].get('year');
|
||||
end = validRange[1].get('year') + 1;
|
||||
}
|
||||
const suffix = locale && locale.year === '年' ? '年' : '';
|
||||
const options: { label: string; value: number }[] = [];
|
||||
for (let index = start; index < end; index++) {
|
||||
options.push({ label: `${index}${suffix}`, value: index });
|
||||
}
|
||||
return (
|
||||
<Select
|
||||
size={fullscreen ? undefined : 'small'}
|
||||
class={`${prefixCls}-year-select`}
|
||||
onChange={this.onYearChange}
|
||||
value={year}
|
||||
options={options}
|
||||
getPopupContainer={() => this.calendarHeaderNode}
|
||||
></Select>
|
||||
);
|
||||
},
|
||||
|
||||
getMonthSelectElement(prefixCls: string, month: number, months: string[]) {
|
||||
const { fullscreen, validRange, value } = this;
|
||||
let start = 0;
|
||||
let end = 11;
|
||||
if (validRange) {
|
||||
const [rangeStart, rangeEnd] = validRange;
|
||||
const currentYear = value.get('year');
|
||||
if (rangeEnd.get('year') === currentYear) {
|
||||
end = rangeEnd.get('month') + 1;
|
||||
}
|
||||
if (rangeStart.get('year') === currentYear) {
|
||||
start = rangeStart.get('month');
|
||||
}
|
||||
}
|
||||
const options: { label: string; value: number }[] = [];
|
||||
for (let index = start; index <= end; index += 1) {
|
||||
options.push({
|
||||
label: months[index],
|
||||
value: index,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
size={fullscreen ? undefined : 'small'}
|
||||
class={`${prefixCls}-month-select`}
|
||||
value={month}
|
||||
options={options}
|
||||
onChange={this.onMonthChange}
|
||||
getPopupContainer={() => this.calendarHeaderNode}
|
||||
></Select>
|
||||
);
|
||||
},
|
||||
|
||||
onYearChange(year: string) {
|
||||
const { value, validRange } = this;
|
||||
const newValue = value.clone();
|
||||
newValue.year(parseInt(year, 10));
|
||||
// switch the month so that it remains within range when year changes
|
||||
if (validRange) {
|
||||
const [start, end] = validRange;
|
||||
const newYear = newValue.get('year');
|
||||
const newMonth = newValue.get('month');
|
||||
if (newYear === end.get('year') && newMonth > end.get('month')) {
|
||||
newValue.month(end.get('month'));
|
||||
}
|
||||
if (newYear === start.get('year') && newMonth < start.get('month')) {
|
||||
newValue.month(start.get('month'));
|
||||
}
|
||||
}
|
||||
this.$emit('valueChange', newValue);
|
||||
},
|
||||
|
||||
onMonthChange(month: string) {
|
||||
const newValue = this.value.clone();
|
||||
newValue.month(parseInt(month, 10));
|
||||
this.$emit('valueChange', newValue);
|
||||
},
|
||||
|
||||
onInternalTypeChange(e: RadioChangeEvent) {
|
||||
this.triggerTypeChange(e.target.value);
|
||||
},
|
||||
|
||||
triggerTypeChange(val: string) {
|
||||
this.$emit('typeChange', val);
|
||||
},
|
||||
getMonthYearSelections(getPrefixCls) {
|
||||
const { prefixCls: customizePrefixCls, type, value } = this.$props;
|
||||
|
||||
const prefixCls = getPrefixCls('fullcalendar', customizePrefixCls);
|
||||
const yearReactNode = this.getYearSelectElement(prefixCls, value.year());
|
||||
const monthReactNode =
|
||||
type === 'month'
|
||||
? this.getMonthSelectElement(prefixCls, value.month(), getMonthsLocale(value))
|
||||
: null;
|
||||
return {
|
||||
yearReactNode,
|
||||
monthReactNode,
|
||||
};
|
||||
},
|
||||
|
||||
getTypeSwitch() {
|
||||
const { locale = {}, type, fullscreen } = this.$props;
|
||||
const size = fullscreen ? 'default' : 'small';
|
||||
return (
|
||||
<Group onChange={this.onInternalTypeChange} value={type} size={size}>
|
||||
<Button value="month">{locale.month}</Button>
|
||||
<Button value="year">{locale.year}</Button>
|
||||
</Group>
|
||||
);
|
||||
},
|
||||
triggerValueChange(...args: any[]) {
|
||||
this.$emit('valueChange', ...args);
|
||||
},
|
||||
saveCalendarHeaderNode(node: HTMLElement) {
|
||||
this.calendarHeaderNode = node;
|
||||
},
|
||||
headerRenderCustom(headerRender: HeaderRender) {
|
||||
const { type, value } = this.$props;
|
||||
return headerRender({
|
||||
value,
|
||||
type: type || 'month',
|
||||
onChange: this.triggerValueChange,
|
||||
onTypeChange: this.triggerTypeChange,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
const { prefixCls: customizePrefixCls, headerRender } = this;
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('fullcalendar', customizePrefixCls);
|
||||
const typeSwitch = this.getTypeSwitch();
|
||||
const { yearReactNode, monthReactNode } = this.getMonthYearSelections(getPrefixCls);
|
||||
return headerRender ? (
|
||||
this.headerRenderCustom(headerRender)
|
||||
) : (
|
||||
<div class={`${prefixCls}-header`} ref={this.saveCalendarHeaderNode as any}>
|
||||
{yearReactNode}
|
||||
{monthReactNode}
|
||||
{typeSwitch}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import generateConfig from '../vc-picker/generate/dateFns';
|
||||
import { withInstall } from '../_util/type';
|
||||
import generateCalendar, { CalendarProps } from './generateCalendar';
|
||||
|
||||
const Calendar = generateCalendar<Date>(generateConfig);
|
||||
|
||||
export { CalendarProps };
|
||||
export default withInstall(Calendar);
|
|
@ -0,0 +1,9 @@
|
|||
import type { Dayjs } from 'dayjs';
|
||||
import generateConfig from '../vc-picker/generate/dayjs';
|
||||
import { withInstall } from '../_util/type';
|
||||
import generateCalendar, { CalendarProps } from './generateCalendar';
|
||||
|
||||
const Calendar = generateCalendar<Dayjs>(generateConfig);
|
||||
|
||||
export { CalendarProps };
|
||||
export default withInstall(Calendar);
|
|
@ -0,0 +1,332 @@
|
|||
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>(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<CalendarProps<DateType>>({
|
||||
name: 'ACalendar',
|
||||
inheritAttrs: false,
|
||||
props: [
|
||||
'prefixCls',
|
||||
'locale',
|
||||
'validRange',
|
||||
'disabledDate',
|
||||
'dateFullCellRender',
|
||||
'dateCellRender',
|
||||
'monthFullCellRender',
|
||||
'monthCellRender',
|
||||
'headerRender',
|
||||
'value',
|
||||
'defaultValue',
|
||||
'mode',
|
||||
'fullscreen',
|
||||
'onChange',
|
||||
'onPanelChange',
|
||||
'onSelect',
|
||||
'valueFormat',
|
||||
] as any,
|
||||
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.install = function (app: App) {
|
||||
app.component(Calendar.name, Calendar);
|
||||
return app;
|
||||
};
|
||||
return Calendar;
|
||||
}
|
||||
|
||||
export default generateCalendar;
|
|
@ -1,258 +1,4 @@
|
|||
import type { PropType } from 'vue';
|
||||
import { defineComponent, inject } from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import { getOptionProps, hasProp } from '../_util/props-util';
|
||||
import moment from 'moment';
|
||||
import FullCalendar from '../vc-calendar/src/FullCalendar';
|
||||
import Header from './Header';
|
||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||
import interopDefault from '../_util/interopDefault';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import enUS from './locale/en_US';
|
||||
import { checkValidate, stringToMoment, momentToString, TimeType } from '../_util/moment-util';
|
||||
import { tuple, withInstall } from '../_util/type';
|
||||
import Calendar from './dayjs';
|
||||
export * from './dayjs';
|
||||
|
||||
function noop() {
|
||||
return null;
|
||||
}
|
||||
|
||||
function zerofixed(v: number) {
|
||||
if (v < 10) {
|
||||
return `0${v}`;
|
||||
}
|
||||
return `${v}`;
|
||||
}
|
||||
|
||||
const CalendarModeTypes = tuple('month', 'year');
|
||||
export type CalendarMode = typeof CalendarModeTypes[number];
|
||||
|
||||
export const CalendarProps = {
|
||||
monthCellRender: PropTypes.func,
|
||||
dateCellRender: PropTypes.func,
|
||||
monthFullCellRender: PropTypes.func,
|
||||
dateFullCellRender: PropTypes.func,
|
||||
prefixCls: PropTypes.string,
|
||||
value: TimeType,
|
||||
defaultValue: TimeType,
|
||||
mode: PropTypes.oneOf(CalendarModeTypes),
|
||||
fullscreen: PropTypes.looseBool.def(true),
|
||||
locale: PropTypes.object.def({}),
|
||||
disabledDate: PropTypes.func,
|
||||
validRange: {
|
||||
type: Array as PropType<moment.Moment[]>,
|
||||
},
|
||||
headerRender: PropTypes.func,
|
||||
valueFormat: PropTypes.string,
|
||||
onPanelChange: PropTypes.func,
|
||||
onSelect: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
'onUpdate:value': PropTypes.func,
|
||||
};
|
||||
|
||||
const Calendar = defineComponent({
|
||||
name: 'ACalendar',
|
||||
mixins: [BaseMixin],
|
||||
inheritAttrs: false,
|
||||
props: CalendarProps,
|
||||
setup() {
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
sPrefixCls: undefined,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
const { value, defaultValue, valueFormat } = this;
|
||||
const sValue = value || defaultValue || interopDefault(moment)();
|
||||
checkValidate('Calendar', defaultValue, 'defaultValue', valueFormat);
|
||||
checkValidate('Calendar', value, 'value', valueFormat);
|
||||
return {
|
||||
sValue: stringToMoment(sValue, valueFormat),
|
||||
sMode: this.mode || 'month',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
checkValidate('Calendar', val, 'value', this.valueFormat);
|
||||
this.setState({
|
||||
sValue: stringToMoment(val, this.valueFormat),
|
||||
});
|
||||
},
|
||||
mode(val) {
|
||||
this.setState({
|
||||
sMode: val,
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onHeaderValueChange(value: moment.Moment) {
|
||||
this.setValue(value, 'changePanel');
|
||||
},
|
||||
onHeaderTypeChange(mode: CalendarMode) {
|
||||
this.sMode = mode;
|
||||
this.triggerPanelChange(this.sValue, mode);
|
||||
},
|
||||
triggerPanelChange(value: moment.Moment, mode: CalendarMode | undefined) {
|
||||
const val = this.valueFormat ? momentToString(value, this.valueFormat) : value;
|
||||
if (value !== this.sValue) {
|
||||
this.$emit('update:value', val);
|
||||
this.$emit('change', val);
|
||||
}
|
||||
this.$emit('panelChange', val, mode);
|
||||
},
|
||||
|
||||
triggerSelect(value: moment.Moment) {
|
||||
this.setValue(value, 'select');
|
||||
},
|
||||
setValue(value: moment.Moment, way: 'select' | 'changePanel') {
|
||||
const prevValue = this.value ? stringToMoment(this.value, this.valueFormat) : this.sValue;
|
||||
const { sMode: mode, valueFormat } = this;
|
||||
if (!hasProp(this, 'value')) {
|
||||
this.setState({ sValue: value });
|
||||
}
|
||||
if (way === 'select') {
|
||||
const val = valueFormat ? momentToString(value, valueFormat) : value;
|
||||
if (prevValue && prevValue.month() !== value.month()) {
|
||||
this.triggerPanelChange(value, mode);
|
||||
} else {
|
||||
this.$emit('update:value', val);
|
||||
}
|
||||
this.$emit('select', val);
|
||||
} else if (way === 'changePanel') {
|
||||
this.triggerPanelChange(value, mode);
|
||||
}
|
||||
},
|
||||
getDateRange(
|
||||
validRange: [moment.Moment, moment.Moment],
|
||||
disabledDate?: (current: moment.Moment) => boolean,
|
||||
) {
|
||||
return (current: moment.Moment) => {
|
||||
if (!current) {
|
||||
return false;
|
||||
}
|
||||
const [startDate, endDate] = validRange;
|
||||
const inRange = !current.isBetween(startDate, endDate, 'days', '[]');
|
||||
if (disabledDate) {
|
||||
return disabledDate(current) || inRange;
|
||||
}
|
||||
return inRange;
|
||||
};
|
||||
},
|
||||
getDefaultLocale() {
|
||||
const result = {
|
||||
...enUS,
|
||||
...this.$props.locale,
|
||||
};
|
||||
result.lang = {
|
||||
...result.lang,
|
||||
...(this.$props.locale || {}).lang,
|
||||
};
|
||||
return result;
|
||||
},
|
||||
monthCellRender2({ current: value }) {
|
||||
const { sPrefixCls, $slots } = this;
|
||||
const monthCellRender: Function = this.monthCellRender || $slots.monthCellRender || noop;
|
||||
return (
|
||||
<div class={`${sPrefixCls}-month`}>
|
||||
<div class={`${sPrefixCls}-value`}>{value.localeData().monthsShort(value)}</div>
|
||||
<div class={`${sPrefixCls}-content`}>{monthCellRender({ current: value })}</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
dateCellRender2({ current: value }) {
|
||||
const { sPrefixCls, $slots } = this;
|
||||
const dateCellRender: Function = this.dateCellRender || $slots.dateCellRender || noop;
|
||||
return (
|
||||
<div class={`${sPrefixCls}-date`}>
|
||||
<div class={`${sPrefixCls}-value`}>{zerofixed(value.date())}</div>
|
||||
<div class={`${sPrefixCls}-content`}>{dateCellRender({ current: value })}</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
renderCalendar(locale: any, localeCode: string) {
|
||||
const props: any = { ...getOptionProps(this), ...this.$attrs };
|
||||
const { sValue: value, sMode: mode, $slots } = this;
|
||||
if (value && localeCode) {
|
||||
value.locale(localeCode);
|
||||
}
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
fullscreen,
|
||||
dateFullCellRender,
|
||||
monthFullCellRender,
|
||||
class: className,
|
||||
style,
|
||||
} = props;
|
||||
const headerRender = this.headerRender || $slots.headerRender;
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('fullcalendar', customizePrefixCls);
|
||||
|
||||
// To support old version react.
|
||||
// Have to add prefixCls on the instance.
|
||||
// https://github.com/facebook/react/issues/12397
|
||||
this.sPrefixCls = prefixCls;
|
||||
|
||||
let cls = className || '';
|
||||
if (fullscreen) {
|
||||
cls += ` ${prefixCls}-fullscreen`;
|
||||
}
|
||||
|
||||
const monthCellRender =
|
||||
monthFullCellRender || $slots.monthFullCellRender || this.monthCellRender2;
|
||||
const dateCellRender =
|
||||
dateFullCellRender || $slots.dateFullCellRender || this.dateCellRender2;
|
||||
|
||||
let disabledDate = props.disabledDate;
|
||||
|
||||
if (props.validRange) {
|
||||
disabledDate = this.getDateRange(props.validRange, disabledDate);
|
||||
}
|
||||
const fullCalendarProps = {
|
||||
...props,
|
||||
...this.$attrs,
|
||||
Select: {},
|
||||
locale: locale.lang,
|
||||
type: mode === 'year' ? 'month' : 'date',
|
||||
prefixCls,
|
||||
showHeader: false,
|
||||
value,
|
||||
monthCellRender,
|
||||
dateCellRender,
|
||||
disabledDate,
|
||||
onSelect: this.triggerSelect,
|
||||
};
|
||||
return (
|
||||
<div class={cls} style={style}>
|
||||
<Header
|
||||
fullscreen={fullscreen}
|
||||
type={mode}
|
||||
headerRender={headerRender}
|
||||
value={value}
|
||||
locale={locale.lang}
|
||||
prefixCls={prefixCls}
|
||||
onTypeChange={this.onHeaderTypeChange}
|
||||
onValueChange={this.onHeaderValueChange}
|
||||
validRange={props.validRange}
|
||||
/>
|
||||
<FullCalendar {...fullCalendarProps} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<LocaleReceiver
|
||||
componentName="Calendar"
|
||||
defaultLocale={this.getDefaultLocale}
|
||||
children={this.renderCalendar}
|
||||
/>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export { HeaderProps } from './Header';
|
||||
|
||||
export default withInstall(Calendar);
|
||||
export default Calendar;
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
import ar_EG from '../../date-picker/locale/ar_EG';
|
||||
export default ar_EG;
|
|
@ -0,0 +1,3 @@
|
|||
import arEG from '../../date-picker/locale/ar_EG';
|
||||
|
||||
export default arEG;
|
|
@ -0,0 +1,3 @@
|
|||
import azAZ from '../../date-picker/locale/az_AZ';
|
||||
|
||||
export default azAZ;
|
|
@ -1,2 +0,0 @@
|
|||
import bg_BG from '../../date-picker/locale/bg_BG';
|
||||
export default bg_BG;
|
|
@ -0,0 +1,3 @@
|
|||
import bgBG from '../../date-picker/locale/bg_BG';
|
||||
|
||||
export default bgBG;
|
|
@ -0,0 +1,3 @@
|
|||
import byBY from '../../date-picker/locale/by_BY';
|
||||
|
||||
export default byBY;
|
|
@ -1,2 +0,0 @@
|
|||
import ca_ES from '../../date-picker/locale/ca_ES';
|
||||
export default ca_ES;
|
|
@ -0,0 +1,3 @@
|
|||
import caES from '../../date-picker/locale/ca_ES';
|
||||
|
||||
export default caES;
|
|
@ -1,2 +0,0 @@
|
|||
import cs_CZ from '../../date-picker/locale/cs_CZ';
|
||||
export default cs_CZ;
|
|
@ -0,0 +1,3 @@
|
|||
import csCZ from '../../date-picker/locale/cs_CZ';
|
||||
|
||||
export default csCZ;
|
|
@ -1,2 +0,0 @@
|
|||
import da_DK from '../../date-picker/locale/da_DK';
|
||||
export default da_DK;
|
|
@ -0,0 +1,3 @@
|
|||
import daDK from '../../date-picker/locale/da_DK';
|
||||
|
||||
export default daDK;
|
|
@ -1,2 +0,0 @@
|
|||
import de_DE from '../../date-picker/locale/de_DE';
|
||||
export default de_DE;
|
|
@ -0,0 +1,3 @@
|
|||
import deDE from '../../date-picker/locale/de_DE';
|
||||
|
||||
export default deDE;
|
|
@ -1,2 +0,0 @@
|
|||
import el_GR from '../../date-picker/locale/el_GR';
|
||||
export default el_GR;
|
|
@ -0,0 +1,3 @@
|
|||
import elGR from '../../date-picker/locale/el_GR';
|
||||
|
||||
export default elGR;
|
|
@ -1,2 +0,0 @@
|
|||
import en_GB from '../../date-picker/locale/en_GB';
|
||||
export default en_GB;
|
|
@ -0,0 +1,3 @@
|
|||
import enGB from '../../date-picker/locale/en_GB';
|
||||
|
||||
export default enGB;
|
|
@ -1,2 +0,0 @@
|
|||
import en_US from '../../date-picker/locale/en_US';
|
||||
export default en_US;
|
|
@ -0,0 +1,3 @@
|
|||
import enUS from '../../date-picker/locale/en_US';
|
||||
|
||||
export default enUS;
|
|
@ -1,2 +0,0 @@
|
|||
import es_ES from '../../date-picker/locale/es_ES';
|
||||
export default es_ES;
|
|
@ -0,0 +1,3 @@
|
|||
import esES from '../../date-picker/locale/es_ES';
|
||||
|
||||
export default esES;
|
|
@ -1,2 +0,0 @@
|
|||
import et_EE from '../../date-picker/locale/et_EE';
|
||||
export default et_EE;
|
|
@ -0,0 +1,3 @@
|
|||
import etEE from '../../date-picker/locale/et_EE';
|
||||
|
||||
export default etEE;
|
|
@ -1,2 +0,0 @@
|
|||
import fa_IR from '../../date-picker/locale/fa_IR';
|
||||
export default fa_IR;
|
|
@ -0,0 +1,3 @@
|
|||
import faIR from '../../date-picker/locale/fa_IR';
|
||||
|
||||
export default faIR;
|
|
@ -1,2 +0,0 @@
|
|||
import fi_FI from '../../date-picker/locale/fi_FI';
|
||||
export default fi_FI;
|
|
@ -0,0 +1,3 @@
|
|||
import fiFI from '../../date-picker/locale/fi_FI';
|
||||
|
||||
export default fiFI;
|
|
@ -1,2 +0,0 @@
|
|||
import fr_BE from '../../date-picker/locale/fr_BE';
|
||||
export default fr_BE;
|
|
@ -0,0 +1,3 @@
|
|||
import frBE from '../../date-picker/locale/fr_BE';
|
||||
|
||||
export default frBE;
|
|
@ -0,0 +1,3 @@
|
|||
import frCA from '../../date-picker/locale/fr_CA';
|
||||
|
||||
export default frCA;
|
|
@ -1,2 +0,0 @@
|
|||
import fr_FR from '../../date-picker/locale/fr_FR';
|
||||
export default fr_FR;
|
|
@ -0,0 +1,3 @@
|
|||
import frFR from '../../date-picker/locale/fr_FR';
|
||||
|
||||
export default frFR;
|
|
@ -1,3 +0,0 @@
|
|||
import ga_IE from '../../date-picker/locale/ga_IE';
|
||||
|
||||
export default ga_IE;
|
|
@ -0,0 +1,3 @@
|
|||
import gaIE from '../../date-picker/locale/ga_IE';
|
||||
|
||||
export default gaIE;
|
|
@ -0,0 +1,3 @@
|
|||
import glES from '../../date-picker/locale/gl_ES';
|
||||
|
||||
export default glES;
|
|
@ -1,2 +0,0 @@
|
|||
import he_IL from '../../date-picker/locale/he_IL';
|
||||
export default he_IL;
|
|
@ -0,0 +1,3 @@
|
|||
import heIL from '../../date-picker/locale/he_IL';
|
||||
|
||||
export default heIL;
|
|
@ -1,2 +0,0 @@
|
|||
import hi_IN from '../../date-picker/locale/hi_IN';
|
||||
export default hi_IN;
|
|
@ -0,0 +1,3 @@
|
|||
import hiIN from '../../date-picker/locale/hi_IN';
|
||||
|
||||
export default hiIN;
|
|
@ -1,3 +0,0 @@
|
|||
import hr_HR from '../../date-picker/locale/hr_HR';
|
||||
|
||||
export default hr_HR;
|
|
@ -0,0 +1,3 @@
|
|||
import hrHR from '../../date-picker/locale/hr_HR';
|
||||
|
||||
export default hrHR;
|
|
@ -1,2 +0,0 @@
|
|||
import hu_HU from '../../date-picker/locale/hu_HU';
|
||||
export default hu_HU;
|
|
@ -0,0 +1,3 @@
|
|||
import huHU from '../../date-picker/locale/hu_HU';
|
||||
|
||||
export default huHU;
|
|
@ -1,2 +0,0 @@
|
|||
import id_ID from '../../date-picker/locale/id_ID';
|
||||
export default id_ID;
|
|
@ -0,0 +1,3 @@
|
|||
import idID from '../../date-picker/locale/id_ID';
|
||||
|
||||
export default idID;
|
|
@ -1,2 +0,0 @@
|
|||
import is_IS from '../../date-picker/locale/is_IS';
|
||||
export default is_IS;
|
|
@ -0,0 +1,3 @@
|
|||
import isIS from '../../date-picker/locale/is_IS';
|
||||
|
||||
export default isIS;
|
|
@ -1,2 +0,0 @@
|
|||
import it_IT from '../../date-picker/locale/it_IT';
|
||||
export default it_IT;
|
|
@ -0,0 +1,3 @@
|
|||
import itIT from '../../date-picker/locale/it_IT';
|
||||
|
||||
export default itIT;
|
|
@ -1,2 +0,0 @@
|
|||
import ja_JP from '../../date-picker/locale/ja_JP';
|
||||
export default ja_JP;
|
|
@ -0,0 +1,3 @@
|
|||
import jaJP from '../../date-picker/locale/ja_JP';
|
||||
|
||||
export default jaJP;
|
|
@ -0,0 +1,3 @@
|
|||
import kkKZ from '../../date-picker/locale/kk_KZ';
|
||||
|
||||
export default kkKZ;
|
|
@ -0,0 +1,3 @@
|
|||
import kmrIQ from '../../date-picker/locale/kmr_IQ';
|
||||
|
||||
export default kmrIQ;
|
|
@ -1,2 +0,0 @@
|
|||
import kn_IN from '../../date-picker/locale/kn_IN';
|
||||
export default kn_IN;
|
|
@ -0,0 +1,3 @@
|
|||
import knIN from '../../date-picker/locale/kn_IN';
|
||||
|
||||
export default knIN;
|
|
@ -1,2 +0,0 @@
|
|||
import ko_KR from '../../date-picker/locale/ko_KR';
|
||||
export default ko_KR;
|
|
@ -0,0 +1,3 @@
|
|||
import koKR from '../../date-picker/locale/ko_KR';
|
||||
|
||||
export default koKR;
|
|
@ -1,2 +0,0 @@
|
|||
import ku_IQ from '../../date-picker/locale/ku_IQ';
|
||||
export default ku_IQ;
|
|
@ -1,2 +0,0 @@
|
|||
import ku_KU from '../../date-picker/locale/ku_KU';
|
||||
export default ku_KU;
|
|
@ -0,0 +1,3 @@
|
|||
import ltLT from '../../date-picker/locale/lt_LT';
|
||||
|
||||
export default ltLT;
|
|
@ -1,3 +0,0 @@
|
|||
import lv_LV from '../../date-picker/locale/lv_LV';
|
||||
|
||||
export default lv_LV;
|
|
@ -0,0 +1,3 @@
|
|||
import lvLV from '../../date-picker/locale/lv_LV';
|
||||
|
||||
export default lvLV;
|
|
@ -1,3 +0,0 @@
|
|||
import mk_MK from '../../date-picker/locale/mk_MK';
|
||||
|
||||
export default mk_MK;
|
|
@ -0,0 +1,3 @@
|
|||
import mkMK from '../../date-picker/locale/mk_MK';
|
||||
|
||||
export default mkMK;
|
|
@ -1,2 +0,0 @@
|
|||
import mn_MN from '../../date-picker/locale/mn_MN';
|
||||
export default mn_MN;
|
|
@ -0,0 +1,3 @@
|
|||
import mnMN from '../../date-picker/locale/mn_MN';
|
||||
|
||||
export default mnMN;
|
|
@ -1,3 +0,0 @@
|
|||
import ms_MY from '../../date-picker/locale/ms_MY';
|
||||
|
||||
export default ms_MY;
|
|
@ -0,0 +1,3 @@
|
|||
import msMY from '../../date-picker/locale/ms_MY';
|
||||
|
||||
export default msMY;
|
|
@ -1,2 +0,0 @@
|
|||
import nb_NO from '../../date-picker/locale/nb_NO';
|
||||
export default nb_NO;
|
|
@ -0,0 +1,3 @@
|
|||
import nbNO from '../../date-picker/locale/nb_NO';
|
||||
|
||||
export default nbNO;
|
|
@ -1,2 +0,0 @@
|
|||
import nl_BE from '../../date-picker/locale/nl_BE';
|
||||
export default nl_BE;
|
|
@ -0,0 +1,3 @@
|
|||
import nlBE from '../../date-picker/locale/nl_BE';
|
||||
|
||||
export default nlBE;
|
|
@ -1,2 +0,0 @@
|
|||
import nl_NL from '../../date-picker/locale/nl_NL';
|
||||
export default nl_NL;
|
|
@ -0,0 +1,3 @@
|
|||
import nlNL from '../../date-picker/locale/nl_NL';
|
||||
|
||||
export default nlNL;
|
|
@ -1,2 +0,0 @@
|
|||
import pl_PL from '../../date-picker/locale/pl_PL';
|
||||
export default pl_PL;
|
|
@ -0,0 +1,3 @@
|
|||
import plPL from '../../date-picker/locale/pl_PL';
|
||||
|
||||
export default plPL;
|
|
@ -1,2 +0,0 @@
|
|||
import pt_BR from '../../date-picker/locale/pt_BR';
|
||||
export default pt_BR;
|
|
@ -0,0 +1,3 @@
|
|||
import ptBR from '../../date-picker/locale/pt_BR';
|
||||
|
||||
export default ptBR;
|
|
@ -1,2 +0,0 @@
|
|||
import pt_PT from '../../date-picker/locale/pt_PT';
|
||||
export default pt_PT;
|
|
@ -0,0 +1,3 @@
|
|||
import ptPT from '../../date-picker/locale/pt_PT';
|
||||
|
||||
export default ptPT;
|
|
@ -1,3 +0,0 @@
|
|||
import ro_RO from '../../date-picker/locale/ro_RO';
|
||||
|
||||
export default ro_RO;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue