Merge branch 'refactor-date' of github.com:vueComponent/ant-design-vue into refactor-date
# Conflicts: # components/vc-picker/generate/dayjs.ts # components/vc-picker/generate/moment.ts # v2-docpull/4499/head
parent
a501b592a2
commit
16fc2a10a9
|
|
@ -0,0 +1,3 @@
|
||||||
|
export type FocusEventHandler = (e: FocusEvent) => void;
|
||||||
|
export type MouseEventHandler = (e: MouseEvent) => void;
|
||||||
|
export type KeyboardEventHandler = (e: KeyboardEvent) => void;
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import type { Ref } from 'vue';
|
import type { Ref, WatchSource } from 'vue';
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
|
|
||||||
export default function useMemo<T>(
|
export default function useMemo<T>(
|
||||||
getValue: () => T,
|
getValue: () => T,
|
||||||
condition: any[],
|
condition: (WatchSource<unknown> | object)[],
|
||||||
shouldUpdate?: (prev: any[], next: any[]) => boolean,
|
shouldUpdate?: (prev: any[], next: any[]) => boolean,
|
||||||
) {
|
) {
|
||||||
const cacheRef: Ref<T> = ref(getValue() as any);
|
const cacheRef: Ref<T> = ref(getValue() as any);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
import type { Ref, UnwrapRef } 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 } = 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 (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];
|
||||||
|
}
|
||||||
|
|
@ -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];
|
||||||
|
}
|
||||||
|
|
@ -9,22 +9,21 @@ export type ContextOperationRefProps = {
|
||||||
export type PanelContextProps = {
|
export type PanelContextProps = {
|
||||||
operationRef?: Ref<ContextOperationRefProps | null>;
|
operationRef?: Ref<ContextOperationRefProps | null>;
|
||||||
/** Only work with time panel */
|
/** Only work with time panel */
|
||||||
hideHeader?: boolean;
|
hideHeader?: Ref<boolean>;
|
||||||
panelRef?: Ref<HTMLDivElement>;
|
panelRef?: Ref<HTMLDivElement>;
|
||||||
hidePrevBtn?: boolean;
|
hidePrevBtn?: Ref<boolean>;
|
||||||
hideNextBtn?: boolean;
|
hideNextBtn?: Ref<boolean>;
|
||||||
onDateMouseEnter?: (date: any) => void;
|
onDateMouseEnter?: (date: any) => void;
|
||||||
onDateMouseLeave?: (date: any) => void;
|
onDateMouseLeave?: (date: any) => void;
|
||||||
onSelect?: OnSelect<any>;
|
onSelect?: OnSelect<any>;
|
||||||
hideRanges?: boolean;
|
hideRanges?: Ref<boolean>;
|
||||||
open?: boolean;
|
open?: Ref<boolean>;
|
||||||
mode?: PanelMode;
|
mode?: Ref<PanelMode>;
|
||||||
|
|
||||||
/** Only used for TimePicker and this is a deprecated prop */
|
/** Only used for TimePicker and this is a deprecated prop */
|
||||||
defaultOpenValue?: any;
|
defaultOpenValue?: Ref<any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const PanelContextKey: InjectionKey<PanelContextProps> = Symbol('PanelContextProps');
|
const PanelContextKey: InjectionKey<PanelContextProps> = Symbol('PanelContextProps');
|
||||||
|
|
||||||
export const useProvidePanel = (props: PanelContextProps) => {
|
export const useProvidePanel = (props: PanelContextProps) => {
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,6 @@
|
||||||
* Tips: Should add faq about `datetime` mode with `defaultValue`
|
* Tips: Should add faq about `datetime` mode with `defaultValue`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import type { AlignType } from 'rc-trigger/lib/interface';
|
|
||||||
import warning from 'rc-util/lib/warning';
|
|
||||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
|
||||||
import type {
|
import type {
|
||||||
PickerPanelBaseProps,
|
PickerPanelBaseProps,
|
||||||
PickerPanelDateProps,
|
PickerPanelDateProps,
|
||||||
|
|
@ -33,6 +28,22 @@ import usePickerInput from './hooks/usePickerInput';
|
||||||
import useTextValueMapping from './hooks/useTextValueMapping';
|
import useTextValueMapping from './hooks/useTextValueMapping';
|
||||||
import useValueTexts from './hooks/useValueTexts';
|
import useValueTexts from './hooks/useValueTexts';
|
||||||
import useHoverValue from './hooks/useHoverValue';
|
import useHoverValue from './hooks/useHoverValue';
|
||||||
|
import {
|
||||||
|
computed,
|
||||||
|
CSSProperties,
|
||||||
|
defineComponent,
|
||||||
|
HtmlHTMLAttributes,
|
||||||
|
ref,
|
||||||
|
Ref,
|
||||||
|
toRef,
|
||||||
|
toRefs,
|
||||||
|
} from 'vue';
|
||||||
|
import { FocusEventHandler, MouseEventHandler } from '../_util/EventInterface';
|
||||||
|
import { VueNode } from '../_util/type';
|
||||||
|
import { AlignType } from '../vc-align/interface';
|
||||||
|
import useMergedState from '../_util/hooks/useMergedState';
|
||||||
|
import { locale } from 'dayjs';
|
||||||
|
import { warning } from '../vc-util/warning';
|
||||||
|
|
||||||
export type PickerRefConfig = {
|
export type PickerRefConfig = {
|
||||||
focus: () => void;
|
focus: () => void;
|
||||||
|
|
@ -42,13 +53,13 @@ export type PickerRefConfig = {
|
||||||
export type PickerSharedProps<DateType> = {
|
export type PickerSharedProps<DateType> = {
|
||||||
dropdownClassName?: string;
|
dropdownClassName?: string;
|
||||||
dropdownAlign?: AlignType;
|
dropdownAlign?: AlignType;
|
||||||
popupStyle?: React.CSSProperties;
|
popupStyle?: CSSProperties;
|
||||||
transitionName?: string;
|
transitionName?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
autoFocus?: boolean;
|
autofocus?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
tabIndex?: number;
|
tabindex?: number;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
defaultOpen?: boolean;
|
defaultOpen?: boolean;
|
||||||
/** Make input readOnly to avoid popup keyboard in mobile */
|
/** Make input readOnly to avoid popup keyboard in mobile */
|
||||||
|
|
@ -59,39 +70,39 @@ export type PickerSharedProps<DateType> = {
|
||||||
format?: string | CustomFormat<DateType> | (string | CustomFormat<DateType>)[];
|
format?: string | CustomFormat<DateType> | (string | CustomFormat<DateType>)[];
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
suffixIcon?: React.ReactNode;
|
suffixIcon?: VueNode;
|
||||||
clearIcon?: React.ReactNode;
|
clearIcon?: VueNode;
|
||||||
prevIcon?: React.ReactNode;
|
prevIcon?: VueNode;
|
||||||
nextIcon?: React.ReactNode;
|
nextIcon?: VueNode;
|
||||||
superPrevIcon?: React.ReactNode;
|
superPrevIcon?: VueNode;
|
||||||
superNextIcon?: React.ReactNode;
|
superNextIcon?: VueNode;
|
||||||
getPopupContainer?: (node: HTMLElement) => HTMLElement;
|
getPopupContainer?: (node: HTMLElement) => HTMLElement;
|
||||||
panelRender?: (originPanel: React.ReactNode) => React.ReactNode;
|
panelRender?: (originPanel: VueNode) => VueNode;
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
onChange?: (value: DateType | null, dateString: string) => void;
|
onChange?: (value: DateType | null, dateString: string) => void;
|
||||||
onOpenChange?: (open: boolean) => void;
|
onOpenChange?: (open: boolean) => void;
|
||||||
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
onFocus?: FocusEventHandler;
|
||||||
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
onBlur?: FocusEventHandler;
|
||||||
onMouseDown?: React.MouseEventHandler<HTMLDivElement>;
|
onMouseDown?: MouseEventHandler;
|
||||||
onMouseUp?: React.MouseEventHandler<HTMLDivElement>;
|
onMouseUp?: MouseEventHandler;
|
||||||
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
|
onMouseEnter?: MouseEventHandler;
|
||||||
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
|
onMouseLeave?: MouseEventHandler;
|
||||||
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
onClick?: MouseEventHandler;
|
||||||
onContextMenu?: React.MouseEventHandler<HTMLDivElement>;
|
onContextMenu?: MouseEventHandler;
|
||||||
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>, preventDefault: () => void) => void;
|
onKeyDown?: (event: KeyboardEvent, preventDefault: () => void) => void;
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
/** @private Internal usage, do not use in production mode!!! */
|
/** @private Internal usage, do not use in production mode!!! */
|
||||||
pickerRef?: React.MutableRefObject<PickerRefConfig>;
|
pickerRef?: Ref<PickerRefConfig>;
|
||||||
|
|
||||||
// WAI-ARIA
|
// WAI-ARIA
|
||||||
role?: string;
|
role?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
||||||
autoComplete?: string;
|
autocomplete?: string;
|
||||||
direction?: 'ltr' | 'rtl';
|
direction?: 'ltr' | 'rtl';
|
||||||
} & React.AriaAttributes;
|
} & HtmlHTMLAttributes;
|
||||||
|
|
||||||
type OmitPanelProps<Props> = Omit<
|
type OmitPanelProps<Props> = Omit<
|
||||||
Props,
|
Props,
|
||||||
|
|
@ -127,111 +138,127 @@ type MergedPickerProps<DateType> = {
|
||||||
picker?: PickerMode;
|
picker?: PickerMode;
|
||||||
} & OmitType<DateType>;
|
} & OmitType<DateType>;
|
||||||
|
|
||||||
function InnerPicker<DateType>(props: PickerProps<DateType>) {
|
function Picker<DateType>() {
|
||||||
const {
|
return defineComponent<MergedPickerProps<DateType>>({
|
||||||
prefixCls = 'rc-picker',
|
name: 'Picker',
|
||||||
id,
|
props: [
|
||||||
tabIndex,
|
'prefixCls',
|
||||||
style,
|
'id',
|
||||||
className,
|
'tabindex',
|
||||||
dropdownClassName,
|
'dropdownClassName',
|
||||||
dropdownAlign,
|
'dropdownAlign',
|
||||||
popupStyle,
|
'popupStyle',
|
||||||
transitionName,
|
'transitionName',
|
||||||
generateConfig,
|
'generateConfig',
|
||||||
locale,
|
'locale',
|
||||||
inputReadOnly,
|
'inputReadOnly',
|
||||||
allowClear,
|
'allowClear',
|
||||||
autoFocus,
|
'autofocus',
|
||||||
showTime,
|
'showTime',
|
||||||
picker = 'date',
|
'picker',
|
||||||
format,
|
'format',
|
||||||
use12Hours,
|
'use12Hours',
|
||||||
value,
|
'value',
|
||||||
defaultValue,
|
'defaultValue',
|
||||||
open,
|
'open',
|
||||||
defaultOpen,
|
'defaultOpen',
|
||||||
defaultOpenValue,
|
'defaultOpenValue',
|
||||||
suffixIcon,
|
'suffixIcon',
|
||||||
clearIcon,
|
'clearIcon',
|
||||||
disabled,
|
'disabled',
|
||||||
disabledDate,
|
'disabledDate',
|
||||||
placeholder,
|
'placeholder',
|
||||||
getPopupContainer,
|
'getPopupContainer',
|
||||||
pickerRef,
|
'pickerRef',
|
||||||
panelRender,
|
'panelRender',
|
||||||
onChange,
|
'onChange',
|
||||||
onOpenChange,
|
'onOpenChange',
|
||||||
onFocus,
|
'onFocus',
|
||||||
onBlur,
|
'onBlur',
|
||||||
onMouseDown,
|
'onMouseDown',
|
||||||
onMouseUp,
|
'onMouseUp',
|
||||||
onMouseEnter,
|
'onMouseEnter',
|
||||||
onMouseLeave,
|
'onMouseLeave',
|
||||||
onContextMenu,
|
'onContextMenu',
|
||||||
onClick,
|
'onClick',
|
||||||
onKeyDown,
|
'onKeyDown',
|
||||||
onSelect,
|
'onSelect',
|
||||||
direction,
|
'direction',
|
||||||
autoComplete = 'off',
|
'autocomplete',
|
||||||
} = props as MergedPickerProps<DateType>;
|
] as any,
|
||||||
|
inheritAttrs: false,
|
||||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
slots: [
|
||||||
|
'suffixIcon',
|
||||||
const needConfirmButton: boolean = (picker === 'date' && !!showTime) || picker === 'time';
|
'clearIcon',
|
||||||
|
'prevIcon',
|
||||||
|
'nextIcon',
|
||||||
|
'superPrevIcon',
|
||||||
|
'superNextIcon',
|
||||||
|
'panelRender',
|
||||||
|
],
|
||||||
|
setup(props, { slots, attrs, expose }) {
|
||||||
|
const inputRef = ref(null);
|
||||||
|
const needConfirmButton = computed(
|
||||||
|
() => (props.picker === 'date' && !!props.showTime) || props.picker === 'time',
|
||||||
|
);
|
||||||
|
|
||||||
// ============================= State =============================
|
// ============================= State =============================
|
||||||
const formatList = toArray(getDefaultFormat(format, picker, showTime, use12Hours));
|
const formatList = computed(() =>
|
||||||
|
toArray(getDefaultFormat(props.format, props.picker, props.showTime, props.use12Hours)),
|
||||||
|
);
|
||||||
|
|
||||||
// Panel ref
|
// Panel ref
|
||||||
const panelDivRef = React.useRef<HTMLDivElement>(null);
|
const panelDivRef = ref(null);
|
||||||
const inputDivRef = React.useRef<HTMLDivElement>(null);
|
const inputDivRef = ref(null);
|
||||||
|
|
||||||
// Real value
|
// Real value
|
||||||
const [mergedValue, setInnerValue] = useMergedState(null, {
|
const [mergedValue, setInnerValue] = useMergedState<DateType>(null, {
|
||||||
value,
|
value: toRef(props, 'value'),
|
||||||
defaultValue,
|
defaultValue: props.defaultValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Selected value
|
const selectedValue = ref(mergedValue.value) as Ref<DateType>;
|
||||||
const [selectedValue, setSelectedValue] = React.useState<DateType | null>(mergedValue);
|
const setSelectedValue = (val: DateType) => {
|
||||||
|
selectedValue.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
// Operation ref
|
// Operation ref
|
||||||
const operationRef: React.MutableRefObject<ContextOperationRefProps | null> =
|
const operationRef = ref<ContextOperationRefProps>(null);
|
||||||
React.useRef<ContextOperationRefProps>(null);
|
|
||||||
|
|
||||||
// Open
|
// Open
|
||||||
const [mergedOpen, triggerInnerOpen] = useMergedState(false, {
|
const [mergedOpen, triggerInnerOpen] = useMergedState(false, {
|
||||||
value: open,
|
value: toRef(props, 'open'),
|
||||||
defaultValue: defaultOpen,
|
defaultValue: props.defaultOpen,
|
||||||
postState: (postOpen) => (disabled ? false : postOpen),
|
postState: postOpen => (props.disabled ? false : postOpen),
|
||||||
onChange: (newOpen) => {
|
onChange: newOpen => {
|
||||||
if (onOpenChange) {
|
if (props.onOpenChange) {
|
||||||
onOpenChange(newOpen);
|
props.onOpenChange(newOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newOpen && operationRef.current && operationRef.current.onClose) {
|
if (!newOpen && operationRef.value && operationRef.value.onClose) {
|
||||||
operationRef.current.onClose();
|
operationRef.value.onClose();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// ============================= Text ==============================
|
// ============================= Text ==============================
|
||||||
const [valueTexts, firstValueText] = useValueTexts(selectedValue, {
|
const texts = useValueTexts(selectedValue, {
|
||||||
formatList,
|
formatList,
|
||||||
generateConfig,
|
generateConfig: toRef(props, 'generateConfig'),
|
||||||
locale,
|
locale: toRef(props, 'locale'),
|
||||||
});
|
});
|
||||||
|
const valueTexts = computed(() => texts.value[0]);
|
||||||
|
const firstValueText = computed(() => texts.value[1]);
|
||||||
|
|
||||||
const [text, triggerTextChange, resetText] = useTextValueMapping({
|
const [text, triggerTextChange, resetText] = useTextValueMapping({
|
||||||
valueTexts,
|
valueTexts,
|
||||||
onTextChange: (newText) => {
|
onTextChange: newText => {
|
||||||
const inputDate = parseValue(newText, {
|
const inputDate = parseValue(newText, {
|
||||||
locale,
|
locale: props.locale,
|
||||||
formatList,
|
formatList: formatList.value,
|
||||||
generateConfig,
|
generateConfig: props.generateConfig,
|
||||||
});
|
});
|
||||||
if (inputDate && (!disabledDate || !disabledDate(inputDate))) {
|
if (inputDate && (!props.disabledDate || !props.disabledDate(inputDate))) {
|
||||||
setSelectedValue(inputDate);
|
setSelectedValue(inputDate);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -239,29 +266,32 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
|
||||||
|
|
||||||
// ============================ Trigger ============================
|
// ============================ Trigger ============================
|
||||||
const triggerChange = (newValue: DateType | null) => {
|
const triggerChange = (newValue: DateType | null) => {
|
||||||
|
const { onChange, generateConfig, locale } = props;
|
||||||
setSelectedValue(newValue);
|
setSelectedValue(newValue);
|
||||||
setInnerValue(newValue);
|
setInnerValue(newValue);
|
||||||
|
|
||||||
if (onChange && !isEqual(generateConfig, mergedValue, newValue)) {
|
if (onChange && !isEqual(generateConfig, mergedValue.value, newValue)) {
|
||||||
onChange(
|
onChange(
|
||||||
newValue,
|
newValue,
|
||||||
newValue ? formatValue(newValue, { generateConfig, locale, format: formatList[0] }) : '',
|
newValue
|
||||||
|
? formatValue(newValue, { generateConfig, locale, format: formatList[0] })
|
||||||
|
: '',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const triggerOpen = (newOpen: boolean) => {
|
const triggerOpen = (newOpen: boolean) => {
|
||||||
if (disabled && newOpen) {
|
if (props.disabled && newOpen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerInnerOpen(newOpen);
|
triggerInnerOpen(newOpen);
|
||||||
};
|
};
|
||||||
|
|
||||||
const forwardKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
|
const forwardKeyDown = (e: KeyboardEvent) => {
|
||||||
if (mergedOpen && operationRef.current && operationRef.current.onKeyDown) {
|
if (mergedOpen && operationRef.value && operationRef.value.onKeyDown) {
|
||||||
// Let popup panel handle keyboard
|
// Let popup panel handle keyboard
|
||||||
return operationRef.current.onKeyDown(e);
|
return operationRef.value.onKeyDown(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
|
|
@ -275,13 +305,13 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onInternalMouseUp: React.MouseEventHandler<HTMLDivElement> = (...args) => {
|
const onInternalMouseUp: MouseEventHandler = (...args) => {
|
||||||
if (onMouseUp) {
|
if (props.onMouseUp) {
|
||||||
onMouseUp(...args);
|
props.onMouseUp(...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputRef.current) {
|
if (inputRef.value) {
|
||||||
inputRef.current.focus();
|
inputRef.value.focus();
|
||||||
triggerOpen(true);
|
triggerOpen(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -293,269 +323,39 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
|
||||||
value: text,
|
value: text,
|
||||||
triggerOpen,
|
triggerOpen,
|
||||||
forwardKeyDown,
|
forwardKeyDown,
|
||||||
isClickOutside: (target) =>
|
isClickOutside: target =>
|
||||||
!elementsContains([panelDivRef.current, inputDivRef.current], target as HTMLElement),
|
!elementsContains([panelDivRef.current, inputDivRef.current], target as HTMLElement),
|
||||||
onSubmit: () => {
|
onSubmit: () => {
|
||||||
if (disabledDate && disabledDate(selectedValue)) {
|
if (props.disabledDate && props.disabledDate(selectedValue.value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerChange(selectedValue);
|
triggerChange(selectedValue.value);
|
||||||
triggerOpen(false);
|
triggerOpen(false);
|
||||||
resetText();
|
resetText();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
onCancel: () => {
|
onCancel: () => {
|
||||||
triggerOpen(false);
|
triggerOpen(false);
|
||||||
setSelectedValue(mergedValue);
|
setSelectedValue(mergedValue.value);
|
||||||
resetText();
|
resetText();
|
||||||
},
|
},
|
||||||
onKeyDown: (e, preventDefault) => {
|
onKeyDown: (e, preventDefault) => {
|
||||||
onKeyDown?.(e, preventDefault);
|
props.onKeyDown?.(e, preventDefault);
|
||||||
|
},
|
||||||
|
onFocus: (e: FocusEvent) => {
|
||||||
|
props.onFocus?.(e);
|
||||||
|
},
|
||||||
|
onBlur: (e: FocusEvent) => {
|
||||||
|
props.onBlur?.(e);
|
||||||
},
|
},
|
||||||
onFocus,
|
|
||||||
onBlur,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// ============================= Sync ==============================
|
return () => {
|
||||||
// Close should sync back with text value
|
return null;
|
||||||
React.useEffect(() => {
|
|
||||||
if (!mergedOpen) {
|
|
||||||
setSelectedValue(mergedValue);
|
|
||||||
|
|
||||||
if (!valueTexts.length || valueTexts[0] === '') {
|
|
||||||
triggerTextChange('');
|
|
||||||
} else if (firstValueText !== text) {
|
|
||||||
resetText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [mergedOpen, valueTexts]);
|
|
||||||
|
|
||||||
// Change picker should sync back with text value
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (!mergedOpen) {
|
|
||||||
resetText();
|
|
||||||
}
|
|
||||||
}, [picker]);
|
|
||||||
|
|
||||||
// Sync innerValue with control mode
|
|
||||||
React.useEffect(() => {
|
|
||||||
// Sync select value
|
|
||||||
setSelectedValue(mergedValue);
|
|
||||||
}, [mergedValue]);
|
|
||||||
|
|
||||||
// ============================ Private ============================
|
|
||||||
if (pickerRef) {
|
|
||||||
pickerRef.current = {
|
|
||||||
focus: () => {
|
|
||||||
if (inputRef.current) {
|
|
||||||
inputRef.current.focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
blur: () => {
|
|
||||||
if (inputRef.current) {
|
|
||||||
inputRef.current.blur();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
|
|
||||||
const [hoverValue, onEnter, onLeave] = useHoverValue(text, {
|
|
||||||
formatList,
|
|
||||||
generateConfig,
|
|
||||||
locale,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// ============================= Panel =============================
|
|
||||||
const panelProps = {
|
|
||||||
// Remove `picker` & `format` here since TimePicker is little different with other panel
|
|
||||||
...(props as Omit<MergedPickerProps<DateType>, 'picker' | 'format'>),
|
|
||||||
className: undefined,
|
|
||||||
style: undefined,
|
|
||||||
pickerValue: undefined,
|
|
||||||
onPickerValueChange: undefined,
|
|
||||||
onChange: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
let panelNode: React.ReactNode = (
|
|
||||||
<PickerPanel<DateType>
|
|
||||||
{...panelProps}
|
|
||||||
generateConfig={generateConfig}
|
|
||||||
class={classNames({
|
|
||||||
[`${prefixCls}-panel-focused`]: !typing,
|
|
||||||
})}
|
|
||||||
value={selectedValue}
|
|
||||||
locale={locale}
|
|
||||||
tabIndex={-1}
|
|
||||||
onSelect={(date) => {
|
|
||||||
onSelect?.(date);
|
|
||||||
setSelectedValue(date);
|
|
||||||
}}
|
|
||||||
direction={direction}
|
|
||||||
onPanelChange={(viewDate, mode) => {
|
|
||||||
const { onPanelChange } = props;
|
|
||||||
onLeave(true);
|
|
||||||
onPanelChange?.(viewDate, mode);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (panelRender) {
|
|
||||||
panelNode = panelRender(panelNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
const panel = (
|
|
||||||
<div
|
|
||||||
class={`${prefixCls}-panel-container`}
|
|
||||||
onMousedown={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{panelNode}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
let suffixNode: React.ReactNode;
|
|
||||||
if (suffixIcon) {
|
|
||||||
suffixNode = <span class={`${prefixCls}-suffix`}>{suffixIcon}</span>;
|
|
||||||
}
|
|
||||||
|
|
||||||
let clearNode: React.ReactNode;
|
|
||||||
if (allowClear && mergedValue && !disabled) {
|
|
||||||
clearNode = (
|
|
||||||
<span
|
|
||||||
onMousedown={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
onMouseup={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
triggerChange(null);
|
|
||||||
triggerOpen(false);
|
|
||||||
}}
|
|
||||||
class={`${prefixCls}-clear`}
|
|
||||||
role="button"
|
|
||||||
>
|
|
||||||
{clearIcon || <span class={`${prefixCls}-clear-btn`} />}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================ Warning ============================
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
warning(
|
|
||||||
!defaultOpenValue,
|
|
||||||
'`defaultOpenValue` may confuse user for the current value status. Please use `defaultValue` instead.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================ Return =============================
|
|
||||||
const onContextSelect = (date: DateType, type: 'key' | 'mouse' | 'submit') => {
|
|
||||||
if (type === 'submit' || (type !== 'key' && !needConfirmButton)) {
|
|
||||||
// triggerChange will also update selected values
|
|
||||||
triggerChange(date);
|
|
||||||
triggerOpen(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const popupPlacement = direction === 'rtl' ? 'bottomRight' : 'bottomLeft';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PanelContext.Provider
|
|
||||||
value={{
|
|
||||||
operationRef,
|
|
||||||
hideHeader: picker === 'time',
|
|
||||||
panelRef: panelDivRef,
|
|
||||||
onSelect: onContextSelect,
|
|
||||||
open: mergedOpen,
|
|
||||||
defaultOpenValue,
|
|
||||||
onDateMouseEnter: onEnter,
|
|
||||||
onDateMouseLeave: onLeave,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PickerTrigger
|
|
||||||
visible={mergedOpen}
|
|
||||||
popupElement={panel}
|
|
||||||
popupStyle={popupStyle}
|
|
||||||
prefixCls={prefixCls}
|
|
||||||
dropdownClassName={dropdownClassName}
|
|
||||||
dropdownAlign={dropdownAlign}
|
|
||||||
getPopupContainer={getPopupContainer}
|
|
||||||
transitionName={transitionName}
|
|
||||||
popupPlacement={popupPlacement}
|
|
||||||
direction={direction}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class={classNames(prefixCls, className, {
|
|
||||||
[`${prefixCls}-disabled`]: disabled,
|
|
||||||
[`${prefixCls}-focused`]: focused,
|
|
||||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
|
||||||
})}
|
|
||||||
style={style}
|
|
||||||
onMousedown={onMouseDown}
|
|
||||||
onMouseup={onInternalMouseUp}
|
|
||||||
onMouseenter={onMouseEnter}
|
|
||||||
onMouseleave={onMouseLeave}
|
|
||||||
onContextmenu={onContextMenu}
|
|
||||||
onClick={onClick}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class={classNames(`${prefixCls}-input`, {
|
|
||||||
[`${prefixCls}-input-placeholder`]: !!hoverValue,
|
|
||||||
})}
|
|
||||||
ref={inputDivRef}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
id={id}
|
|
||||||
tabIndex={tabIndex}
|
|
||||||
disabled={disabled}
|
|
||||||
readonly={inputReadOnly || typeof formatList[0] === 'function' || !typing}
|
|
||||||
value={hoverValue || text}
|
|
||||||
onChange={(e) => {
|
|
||||||
triggerTextChange(e.target.value);
|
|
||||||
}}
|
|
||||||
autofocus={autoFocus}
|
|
||||||
placeholder={placeholder}
|
|
||||||
ref={inputRef}
|
|
||||||
title={text}
|
|
||||||
{...inputProps}
|
|
||||||
size={getInputSize(picker, formatList[0], generateConfig)}
|
|
||||||
{...getDataOrAriaProps(props)}
|
|
||||||
autocomplete={autoComplete}
|
|
||||||
/>
|
|
||||||
{suffixNode}
|
|
||||||
{clearNode}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PickerTrigger>
|
|
||||||
</PanelContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap with class component to enable pass generic with instance method
|
export default Picker();
|
||||||
class Picker<DateType> extends React.Component<PickerProps<DateType>> {
|
|
||||||
pickerRef = React.createRef<PickerRefConfig>();
|
|
||||||
|
|
||||||
focus = () => {
|
|
||||||
if (this.pickerRef.current) {
|
|
||||||
this.pickerRef.current.focus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
blur = () => {
|
|
||||||
if (this.pickerRef.current) {
|
|
||||||
this.pickerRef.current.blur();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<InnerPicker<DateType>
|
|
||||||
{...this.props}
|
|
||||||
pickerRef={this.pickerRef as React.MutableRefObject<PickerRefConfig>}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Picker;
|
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,6 @@
|
||||||
* click will trigger `onSelect` (if value changed trigger `onChange` also).
|
* click will trigger `onSelect` (if value changed trigger `onChange` also).
|
||||||
* Panel change will not trigger `onSelect` but trigger `onPanelChange`
|
* Panel change will not trigger `onSelect` but trigger `onPanelChange`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import KeyCode from 'rc-util/lib/KeyCode';
|
|
||||||
import warning from 'rc-util/lib/warning';
|
|
||||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
|
||||||
import type { SharedTimeProps } from './panels/TimePanel';
|
import type { SharedTimeProps } from './panels/TimePanel';
|
||||||
import TimePanel from './panels/TimePanel';
|
import TimePanel from './panels/TimePanel';
|
||||||
import DatetimePanel from './panels/DatetimePanel';
|
import DatetimePanel from './panels/DatetimePanel';
|
||||||
|
|
@ -30,22 +24,28 @@ import type {
|
||||||
Components,
|
Components,
|
||||||
} from './interface';
|
} from './interface';
|
||||||
import { isEqual } from './utils/dateUtil';
|
import { isEqual } from './utils/dateUtil';
|
||||||
import PanelContext from './PanelContext';
|
import { useInjectPanel, useProvidePanel } from './PanelContext';
|
||||||
import type { DateRender } from './panels/DatePanel/DateBody';
|
import type { DateRender } from './panels/DatePanel/DateBody';
|
||||||
import { PickerModeMap } from './utils/uiUtil';
|
import { PickerModeMap } from './utils/uiUtil';
|
||||||
import type { MonthCellRender } from './panels/MonthPanel/MonthBody';
|
import type { MonthCellRender } from './panels/MonthPanel/MonthBody';
|
||||||
import RangeContext from './RangeContext';
|
import { useInjectRange } from './RangeContext';
|
||||||
import getExtraFooter from './utils/getExtraFooter';
|
import getExtraFooter from './utils/getExtraFooter';
|
||||||
import getRanges from './utils/getRanges';
|
import getRanges from './utils/getRanges';
|
||||||
import { getLowerBoundTime, setDateTime, setTime } from './utils/timeUtil';
|
import { getLowerBoundTime, setDateTime, setTime } from './utils/timeUtil';
|
||||||
|
import { VueNode } from '../_util/type';
|
||||||
|
import { computed, defineComponent, ref, toRef, watch, watchEffect } from 'vue';
|
||||||
|
import useMergedState from '../_util/hooks/useMergedState';
|
||||||
|
import { warning } from '../vc-util/warning';
|
||||||
|
import KeyCode from '../_util/KeyCode';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
|
||||||
export type PickerPanelSharedProps<DateType> = {
|
export type PickerPanelSharedProps<DateType> = {
|
||||||
prefixCls?: string;
|
prefixCls?: string;
|
||||||
className?: string;
|
// className?: string;
|
||||||
style?: React.CSSProperties;
|
// style?: React.CSSProperties;
|
||||||
/** @deprecated Will be removed in next big version. Please use `mode` instead */
|
/** @deprecated Will be removed in next big version. Please use `mode` instead */
|
||||||
mode?: PanelMode;
|
mode?: PanelMode;
|
||||||
tabIndex?: number;
|
tabindex?: number;
|
||||||
|
|
||||||
// Locale
|
// Locale
|
||||||
locale: Locale;
|
locale: Locale;
|
||||||
|
|
@ -65,13 +65,13 @@ export type PickerPanelSharedProps<DateType> = {
|
||||||
// Render
|
// Render
|
||||||
dateRender?: DateRender<DateType>;
|
dateRender?: DateRender<DateType>;
|
||||||
monthCellRender?: MonthCellRender<DateType>;
|
monthCellRender?: MonthCellRender<DateType>;
|
||||||
renderExtraFooter?: (mode: PanelMode) => React.ReactNode;
|
renderExtraFooter?: (mode: PanelMode) => VueNode;
|
||||||
|
|
||||||
// Event
|
// Event
|
||||||
onSelect?: (value: DateType) => void;
|
onSelect?: (value: DateType) => void;
|
||||||
onChange?: (value: DateType) => void;
|
onChange?: (value: DateType) => void;
|
||||||
onPanelChange?: OnPanelChange<DateType>;
|
onPanelChange?: OnPanelChange<DateType>;
|
||||||
onMouseDown?: React.MouseEventHandler<HTMLDivElement>;
|
onMouseDown?: (e: MouseEvent) => void;
|
||||||
onOk?: (date: DateType) => void;
|
onOk?: (date: DateType) => void;
|
||||||
|
|
||||||
direction?: 'ltr' | 'rtl';
|
direction?: 'ltr' | 'rtl';
|
||||||
|
|
@ -101,7 +101,8 @@ export type PickerPanelDateProps<DateType> = {
|
||||||
|
|
||||||
export type PickerPanelTimeProps<DateType> = {
|
export type PickerPanelTimeProps<DateType> = {
|
||||||
picker: 'time';
|
picker: 'time';
|
||||||
} & PickerPanelSharedProps<DateType> & SharedTimeProps<DateType>;
|
} & PickerPanelSharedProps<DateType> &
|
||||||
|
SharedTimeProps<DateType>;
|
||||||
|
|
||||||
export type PickerPanelProps<DateType> =
|
export type PickerPanelProps<DateType> =
|
||||||
| PickerPanelBaseProps<DateType>
|
| PickerPanelBaseProps<DateType>
|
||||||
|
|
@ -116,62 +117,71 @@ type MergedPickerPanelProps<DateType> = {
|
||||||
picker?: PickerMode;
|
picker?: PickerMode;
|
||||||
} & OmitType<DateType>;
|
} & OmitType<DateType>;
|
||||||
|
|
||||||
function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
function PickerPanel<DateType>() {
|
||||||
const {
|
return defineComponent<MergedPickerPanelProps<DateType>>({
|
||||||
prefixCls = 'rc-picker',
|
name: 'PickerPanel',
|
||||||
className,
|
inheritAttrs: false,
|
||||||
style,
|
props: [
|
||||||
locale,
|
'prefixCls',
|
||||||
generateConfig,
|
'locale',
|
||||||
value,
|
'generateConfig',
|
||||||
defaultValue,
|
'value',
|
||||||
pickerValue,
|
'defaultValue',
|
||||||
defaultPickerValue,
|
'pickerValue',
|
||||||
disabledDate,
|
'defaultPickerValue',
|
||||||
mode,
|
'disabledDate',
|
||||||
picker = 'date',
|
'mode',
|
||||||
tabIndex = 0,
|
{ picker: { default: 'date' } },
|
||||||
showNow,
|
{ tabindex: { default: 0 } },
|
||||||
showTime,
|
'showNow',
|
||||||
showToday,
|
'showTime',
|
||||||
renderExtraFooter,
|
'showToday',
|
||||||
hideHeader,
|
'renderExtraFooter',
|
||||||
onSelect,
|
'hideHeader',
|
||||||
onChange,
|
'onSelect',
|
||||||
onPanelChange,
|
'onChange',
|
||||||
onMouseDown,
|
'onPanelChange',
|
||||||
onPickerValueChange,
|
'onMouseDown',
|
||||||
onOk,
|
'onPickerValueChange',
|
||||||
components,
|
'onOk',
|
||||||
direction,
|
'components',
|
||||||
hourStep = 1,
|
'direction',
|
||||||
minuteStep = 1,
|
{ hourStep: { default: 1 } },
|
||||||
secondStep = 1,
|
{ minuteStep: { default: 1 } },
|
||||||
} = props as MergedPickerPanelProps<DateType>;
|
{ secondStep: { default: 1 } },
|
||||||
|
] as any,
|
||||||
const needConfirmButton: boolean = (picker === 'date' && !!showTime) || picker === 'time';
|
setup(props, { attrs }) {
|
||||||
|
const needConfirmButton = computed(
|
||||||
const isHourStepValid = 24 % hourStep === 0;
|
() => (props.picker === 'date' && !!props.showTime) || props.picker === 'time',
|
||||||
const isMinuteStepValid = 60 % minuteStep === 0;
|
);
|
||||||
const isSecondStepValid = 60 % secondStep === 0;
|
|
||||||
|
|
||||||
|
const isHourStepValid = computed(() => 24 % props.hourStep === 0);
|
||||||
|
const isMinuteStepValid = computed(() => 60 % props.minuteStep === 0);
|
||||||
|
const isSecondStepValid = computed(() => 60 % props.secondStep === 0);
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
watchEffect(() => {
|
||||||
|
const { generateConfig, value, hourStep = 1, minuteStep = 1, secondStep = 1 } = props;
|
||||||
warning(!value || generateConfig.isValidate(value), 'Invalidate date pass to `value`.');
|
warning(!value || generateConfig.isValidate(value), 'Invalidate date pass to `value`.');
|
||||||
warning(!value || generateConfig.isValidate(value), 'Invalidate date pass to `defaultValue`.');
|
|
||||||
warning(isHourStepValid, `\`hourStep\` ${hourStep} is invalid. It should be a factor of 24.`);
|
|
||||||
warning(
|
warning(
|
||||||
isMinuteStepValid,
|
!value || generateConfig.isValidate(value),
|
||||||
|
'Invalidate date pass to `defaultValue`.',
|
||||||
|
);
|
||||||
|
warning(
|
||||||
|
isHourStepValid.value,
|
||||||
|
`\`hourStep\` ${hourStep} is invalid. It should be a factor of 24.`,
|
||||||
|
);
|
||||||
|
warning(
|
||||||
|
isMinuteStepValid.value,
|
||||||
`\`minuteStep\` ${minuteStep} is invalid. It should be a factor of 60.`,
|
`\`minuteStep\` ${minuteStep} is invalid. It should be a factor of 60.`,
|
||||||
);
|
);
|
||||||
warning(
|
warning(
|
||||||
isSecondStepValid,
|
isSecondStepValid.value,
|
||||||
`\`secondStep\` ${secondStep} is invalid. It should be a factor of 60.`,
|
`\`secondStep\` ${secondStep} is invalid. It should be a factor of 60.`,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================ State =============================
|
const panelContext = useInjectPanel();
|
||||||
|
|
||||||
const panelContext = React.useContext(PanelContext);
|
|
||||||
const {
|
const {
|
||||||
operationRef,
|
operationRef,
|
||||||
panelRef: panelDivRef,
|
panelRef: panelDivRef,
|
||||||
|
|
@ -179,34 +189,30 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
hideRanges,
|
hideRanges,
|
||||||
defaultOpenValue,
|
defaultOpenValue,
|
||||||
} = panelContext;
|
} = panelContext;
|
||||||
|
const { inRange, panelPosition, rangedValue, hoverRangedValue } = useInjectRange();
|
||||||
const { inRange, panelPosition, rangedValue, hoverRangedValue } = React.useContext(RangeContext);
|
const panelRef = ref<PanelRefProps>({});
|
||||||
const panelRef = React.useRef<PanelRefProps>({});
|
|
||||||
|
|
||||||
// Handle init logic
|
|
||||||
const initRef = React.useRef(true);
|
|
||||||
|
|
||||||
// Value
|
// Value
|
||||||
const [mergedValue, setInnerValue] = useMergedState(null, {
|
const [mergedValue, setInnerValue] = useMergedState<DateType | null>(null, {
|
||||||
value,
|
value: toRef(props, 'value'),
|
||||||
defaultValue,
|
defaultValue: props.defaultValue,
|
||||||
postState: (val) => {
|
postState: val => {
|
||||||
if (!val && defaultOpenValue && picker === 'time') {
|
if (!val && defaultOpenValue.value && props.picker === 'time') {
|
||||||
return defaultOpenValue;
|
return defaultOpenValue.value;
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// View date control
|
// View date control
|
||||||
const [viewDate, setInnerViewDate] = useMergedState<DateType | null, DateType>(null, {
|
const [viewDate, setInnerViewDate] = useMergedState<DateType | null>(null, {
|
||||||
value: pickerValue,
|
value: toRef(props, 'pickerValue'),
|
||||||
defaultValue: defaultPickerValue || mergedValue,
|
defaultValue: props.defaultPickerValue || mergedValue.value,
|
||||||
postState: (date) => {
|
postState: date => {
|
||||||
|
const { generateConfig, showTime, defaultValue } = props;
|
||||||
const now = generateConfig.getNow();
|
const now = generateConfig.getNow();
|
||||||
if (!date) return now;
|
if (!date) return now;
|
||||||
// When value is null and set showTime
|
// When value is null and set showTime
|
||||||
if (!mergedValue && showTime) {
|
if (!mergedValue && props.showTime) {
|
||||||
if (typeof showTime === 'object') {
|
if (typeof showTime === 'object') {
|
||||||
return setDateTime(generateConfig, date, showTime.defaultValue || now);
|
return setDateTime(generateConfig, date, showTime.defaultValue || now);
|
||||||
}
|
}
|
||||||
|
|
@ -221,14 +227,14 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
|
|
||||||
const setViewDate = (date: DateType) => {
|
const setViewDate = (date: DateType) => {
|
||||||
setInnerViewDate(date);
|
setInnerViewDate(date);
|
||||||
if (onPickerValueChange) {
|
if (props.onPickerValueChange) {
|
||||||
onPickerValueChange(date);
|
props.onPickerValueChange(date);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Panel control
|
// Panel control
|
||||||
const getInternalNextMode = (nextMode: PanelMode): PanelMode => {
|
const getInternalNextMode = (nextMode: PanelMode): PanelMode => {
|
||||||
const getNextMode = PickerModeMap[picker!];
|
const getNextMode = PickerModeMap[props.picker!];
|
||||||
if (getNextMode) {
|
if (getNextMode) {
|
||||||
return getNextMode(nextMode);
|
return getNextMode(nextMode);
|
||||||
}
|
}
|
||||||
|
|
@ -239,28 +245,37 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
// Save panel is changed from which panel
|
// Save panel is changed from which panel
|
||||||
const [mergedMode, setInnerMode] = useMergedState(
|
const [mergedMode, setInnerMode] = useMergedState(
|
||||||
() => {
|
() => {
|
||||||
if (picker === 'time') {
|
if (props.picker === 'time') {
|
||||||
return 'time';
|
return 'time';
|
||||||
}
|
}
|
||||||
return getInternalNextMode('date');
|
return getInternalNextMode('date');
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: mode,
|
value: toRef(props, 'mode'),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => props.picker,
|
||||||
|
() => {
|
||||||
|
setInnerMode(props.picker);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
const sourceMode = ref(mergedMode.value);
|
||||||
setInnerMode(picker);
|
const setSourceMode = (val: PanelMode) => {
|
||||||
}, [picker]);
|
sourceMode.value = val;
|
||||||
|
};
|
||||||
const [sourceMode, setSourceMode] = React.useState<PanelMode>(() => mergedMode);
|
|
||||||
|
|
||||||
const onInternalPanelChange = (newMode: PanelMode | null, viewValue: DateType) => {
|
const onInternalPanelChange = (newMode: PanelMode | null, viewValue: DateType) => {
|
||||||
const nextMode = getInternalNextMode(newMode || mergedMode);
|
const { onPanelChange, generateConfig } = props;
|
||||||
setSourceMode(mergedMode);
|
const nextMode = getInternalNextMode(newMode || mergedMode.value);
|
||||||
|
setSourceMode(mergedMode.value);
|
||||||
setInnerMode(nextMode);
|
setInnerMode(nextMode);
|
||||||
|
|
||||||
if (onPanelChange && (mergedMode !== nextMode || isEqual(generateConfig, viewDate, viewDate))) {
|
if (
|
||||||
|
onPanelChange &&
|
||||||
|
(mergedMode.value !== nextMode || isEqual(generateConfig, viewDate.value, viewDate.value))
|
||||||
|
) {
|
||||||
onPanelChange(viewValue, nextMode);
|
onPanelChange(viewValue, nextMode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -270,7 +285,8 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
type: 'key' | 'mouse' | 'submit',
|
type: 'key' | 'mouse' | 'submit',
|
||||||
forceTriggerSelect: boolean = false,
|
forceTriggerSelect: boolean = false,
|
||||||
) => {
|
) => {
|
||||||
if (mergedMode === picker || forceTriggerSelect) {
|
const { picker, generateConfig, onSelect, onChange, disabledDate } = props;
|
||||||
|
if (mergedMode.value === picker || forceTriggerSelect) {
|
||||||
setInnerValue(date);
|
setInnerValue(date);
|
||||||
|
|
||||||
if (onSelect) {
|
if (onSelect) {
|
||||||
|
|
@ -281,15 +297,19 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
onContextSelect(date, type);
|
onContextSelect(date, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onChange && !isEqual(generateConfig, date, mergedValue) && !disabledDate?.(date)) {
|
if (
|
||||||
|
onChange &&
|
||||||
|
!isEqual(generateConfig, date, mergedValue.value) &&
|
||||||
|
!disabledDate?.(date)
|
||||||
|
) {
|
||||||
onChange(date);
|
onChange(date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========================= Interactive ==========================
|
// ========================= Interactive ==========================
|
||||||
const onInternalKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
|
const onInternalKeyDown = (e: KeyboardEvent) => {
|
||||||
if (panelRef.current && panelRef.current.onKeyDown) {
|
if (panelRef.value && panelRef.value.onKeyDown) {
|
||||||
if (
|
if (
|
||||||
[
|
[
|
||||||
KeyCode.LEFT,
|
KeyCode.LEFT,
|
||||||
|
|
@ -303,7 +323,7 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
) {
|
) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
return panelRef.current.onKeyDown(e);
|
return panelRef.value.onKeyDown(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
|
|
@ -318,52 +338,99 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
/* eslint-enable no-lone-blocks */
|
/* eslint-enable no-lone-blocks */
|
||||||
};
|
};
|
||||||
|
|
||||||
const onInternalBlur: React.FocusEventHandler<HTMLElement> = (e) => {
|
const onInternalBlur = (e: FocusEvent) => {
|
||||||
if (panelRef.current && panelRef.current.onBlur) {
|
if (panelRef.value && panelRef.value.onBlur) {
|
||||||
panelRef.current.onBlur(e);
|
panelRef.value.onBlur(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const onNow = () => {
|
||||||
|
const { generateConfig, hourStep, minuteStep, secondStep } = props;
|
||||||
|
const now = generateConfig.getNow();
|
||||||
|
const lowerBoundTime = getLowerBoundTime(
|
||||||
|
generateConfig.getHour(now),
|
||||||
|
generateConfig.getMinute(now),
|
||||||
|
generateConfig.getSecond(now),
|
||||||
|
isHourStepValid ? hourStep : 1,
|
||||||
|
isMinuteStepValid ? minuteStep : 1,
|
||||||
|
isSecondStepValid ? secondStep : 1,
|
||||||
|
);
|
||||||
|
const adjustedNow = setTime(
|
||||||
|
generateConfig,
|
||||||
|
now,
|
||||||
|
lowerBoundTime[0], // hour
|
||||||
|
lowerBoundTime[1], // minute
|
||||||
|
lowerBoundTime[2], // second
|
||||||
|
);
|
||||||
|
triggerSelect(adjustedNow, 'submit');
|
||||||
|
};
|
||||||
|
|
||||||
if (operationRef && panelPosition !== 'right') {
|
const classString = computed(() => {
|
||||||
operationRef.current = {
|
const { prefixCls, direction } = props;
|
||||||
|
return classNames(`${prefixCls}-panel`, {
|
||||||
|
[`${prefixCls}-panel-has-range`]:
|
||||||
|
rangedValue && rangedValue.value && rangedValue.value[0] && rangedValue.value[1],
|
||||||
|
[`${prefixCls}-panel-has-range-hover`]:
|
||||||
|
hoverRangedValue &&
|
||||||
|
hoverRangedValue.value &&
|
||||||
|
hoverRangedValue.value[0] &&
|
||||||
|
hoverRangedValue.value[1],
|
||||||
|
[`${prefixCls}-panel-rtl`]: direction === 'rtl',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
useProvidePanel({
|
||||||
|
...panelContext,
|
||||||
|
mode: mergedMode,
|
||||||
|
hideHeader: computed(() =>
|
||||||
|
props.hideHeader !== undefined ? props.hideHeader : panelContext.hideHeader?.value,
|
||||||
|
),
|
||||||
|
hidePrevBtn: computed(() => inRange.value && panelPosition.value === 'right'),
|
||||||
|
hideNextBtn: computed(() => inRange.value && panelPosition.value === 'left'),
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
const {
|
||||||
|
prefixCls = 'ant-picker',
|
||||||
|
locale,
|
||||||
|
generateConfig,
|
||||||
|
disabledDate,
|
||||||
|
picker = 'date',
|
||||||
|
tabindex = 0,
|
||||||
|
showNow,
|
||||||
|
showTime,
|
||||||
|
showToday,
|
||||||
|
renderExtraFooter,
|
||||||
|
onMouseDown,
|
||||||
|
onOk,
|
||||||
|
components,
|
||||||
|
} = props;
|
||||||
|
if (operationRef && panelPosition.value !== 'right') {
|
||||||
|
operationRef.value = {
|
||||||
onKeyDown: onInternalKeyDown,
|
onKeyDown: onInternalKeyDown,
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
if (panelRef.current && panelRef.current.onClose) {
|
if (panelRef.value && panelRef.value.onClose) {
|
||||||
panelRef.current.onClose();
|
panelRef.value.onClose();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================ Effect ============================
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (value && !initRef.current) {
|
|
||||||
setInnerViewDate(value);
|
|
||||||
}
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
initRef.current = false;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// ============================ Panels ============================
|
// ============================ Panels ============================
|
||||||
let panelNode: React.ReactNode;
|
let panelNode: VueNode;
|
||||||
|
|
||||||
const pickerProps = {
|
const pickerProps = {
|
||||||
...(props as MergedPickerPanelProps<DateType>),
|
...(props as MergedPickerPanelProps<DateType>),
|
||||||
operationRef: panelRef,
|
operationRef: panelRef,
|
||||||
prefixCls,
|
prefixCls,
|
||||||
viewDate,
|
viewDate: viewDate.value,
|
||||||
value: mergedValue,
|
value: mergedValue.value,
|
||||||
onViewDateChange: setViewDate,
|
onViewDateChange: setViewDate,
|
||||||
sourceMode,
|
sourceMode: sourceMode.value,
|
||||||
onPanelChange: onInternalPanelChange,
|
onPanelChange: onInternalPanelChange,
|
||||||
disabledDate,
|
disabledDate,
|
||||||
};
|
};
|
||||||
delete pickerProps.onChange;
|
delete pickerProps.onChange;
|
||||||
delete pickerProps.onSelect;
|
delete pickerProps.onSelect;
|
||||||
|
|
||||||
switch (mergedMode) {
|
switch (mergedMode.value) {
|
||||||
case 'decade':
|
case 'decade':
|
||||||
panelNode = (
|
panelNode = (
|
||||||
<DecadePanel<DateType>
|
<DecadePanel<DateType>
|
||||||
|
|
@ -463,53 +530,33 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================ Footer ============================
|
// ============================ Footer ============================
|
||||||
let extraFooter: React.ReactNode;
|
let extraFooter: VueNode;
|
||||||
let rangesNode: React.ReactNode;
|
let rangesNode: VueNode;
|
||||||
|
|
||||||
const onNow = () => {
|
|
||||||
const now = generateConfig.getNow();
|
|
||||||
const lowerBoundTime = getLowerBoundTime(
|
|
||||||
generateConfig.getHour(now),
|
|
||||||
generateConfig.getMinute(now),
|
|
||||||
generateConfig.getSecond(now),
|
|
||||||
isHourStepValid ? hourStep : 1,
|
|
||||||
isMinuteStepValid ? minuteStep : 1,
|
|
||||||
isSecondStepValid ? secondStep : 1,
|
|
||||||
);
|
|
||||||
const adjustedNow = setTime(
|
|
||||||
generateConfig,
|
|
||||||
now,
|
|
||||||
lowerBoundTime[0], // hour
|
|
||||||
lowerBoundTime[1], // minute
|
|
||||||
lowerBoundTime[2], // second
|
|
||||||
);
|
|
||||||
triggerSelect(adjustedNow, 'submit');
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!hideRanges) {
|
if (!hideRanges) {
|
||||||
extraFooter = getExtraFooter(prefixCls, mergedMode, renderExtraFooter);
|
extraFooter = getExtraFooter(prefixCls, mergedMode.value, renderExtraFooter);
|
||||||
rangesNode = getRanges({
|
rangesNode = getRanges({
|
||||||
prefixCls,
|
prefixCls,
|
||||||
components,
|
components,
|
||||||
needConfirmButton,
|
needConfirmButton: needConfirmButton.value,
|
||||||
okDisabled: !mergedValue || (disabledDate && disabledDate(mergedValue)),
|
okDisabled: !mergedValue || (disabledDate && disabledDate(mergedValue.value)),
|
||||||
locale,
|
locale,
|
||||||
showNow,
|
showNow,
|
||||||
onNow: needConfirmButton && onNow,
|
onNow: needConfirmButton.value && onNow,
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
if (mergedValue) {
|
if (mergedValue) {
|
||||||
triggerSelect(mergedValue, 'submit', true);
|
triggerSelect(mergedValue.value, 'submit', true);
|
||||||
if (onOk) {
|
if (onOk) {
|
||||||
onOk(mergedValue);
|
onOk(mergedValue.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let todayNode: React.ReactNode;
|
let todayNode: VueNode;
|
||||||
|
|
||||||
if (showToday && mergedMode === 'date' && picker === 'date' && !showTime) {
|
if (showToday && mergedMode.value === 'date' && picker === 'date' && !showTime) {
|
||||||
const now = generateConfig.getNow();
|
const now = generateConfig.getNow();
|
||||||
const todayCls = `${prefixCls}-today-btn`;
|
const todayCls = `${prefixCls}-today-btn`;
|
||||||
const disabled = disabledDate && disabledDate(now);
|
const disabled = disabledDate && disabledDate(now);
|
||||||
|
|
@ -527,26 +574,11 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelContext.Provider
|
|
||||||
value={{
|
|
||||||
...panelContext,
|
|
||||||
mode: mergedMode,
|
|
||||||
hideHeader: 'hideHeader' in props ? hideHeader : panelContext.hideHeader,
|
|
||||||
hidePrevBtn: inRange && panelPosition === 'right',
|
|
||||||
hideNextBtn: inRange && panelPosition === 'left',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
tabindex={tabIndex}
|
tabindex={tabindex}
|
||||||
class={classNames(`${prefixCls}-panel`, className, {
|
class={classNames(classString.value, attrs.class)}
|
||||||
[`${prefixCls}-panel-has-range`]: rangedValue && rangedValue[0] && rangedValue[1],
|
style={attrs.style}
|
||||||
[`${prefixCls}-panel-has-range-hover`]:
|
|
||||||
hoverRangedValue && hoverRangedValue[0] && hoverRangedValue[1],
|
|
||||||
[`${prefixCls}-panel-rtl`]: direction === 'rtl',
|
|
||||||
})}
|
|
||||||
style={style}
|
|
||||||
onKeydown={onInternalKeyDown}
|
onKeydown={onInternalKeyDown}
|
||||||
onBlur={onInternalBlur}
|
onBlur={onInternalBlur}
|
||||||
onMousedown={onMouseDown}
|
onMousedown={onMouseDown}
|
||||||
|
|
@ -561,9 +593,10 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</PanelContext.Provider>
|
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PickerPanel;
|
export default PickerPanel();
|
||||||
/* eslint-enable */
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { AlignType } from '../vc-align/interface';
|
||||||
import Trigger from '../vc-trigger';
|
import Trigger from '../vc-trigger';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import { VueNode } from '../_util/type';
|
import { VueNode } from '../_util/type';
|
||||||
|
import useMergeProps from './hooks/useMergeProps';
|
||||||
|
|
||||||
const BUILT_IN_PLACEMENTS = {
|
const BUILT_IN_PLACEMENTS = {
|
||||||
bottomLeft: {
|
bottomLeft: {
|
||||||
|
|
@ -56,8 +57,8 @@ export type PickerTriggerProps = {
|
||||||
direction?: 'ltr' | 'rtl';
|
direction?: 'ltr' | 'rtl';
|
||||||
};
|
};
|
||||||
|
|
||||||
function PickerTrigger(
|
function PickerTrigger(props: PickerTriggerProps, { slots }) {
|
||||||
{
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
popupElement,
|
popupElement,
|
||||||
popupStyle,
|
popupStyle,
|
||||||
|
|
@ -69,9 +70,7 @@ function PickerTrigger(
|
||||||
range,
|
range,
|
||||||
popupPlacement,
|
popupPlacement,
|
||||||
direction,
|
direction,
|
||||||
}: PickerTriggerProps,
|
} = useMergeProps(props);
|
||||||
{ slots },
|
|
||||||
) {
|
|
||||||
const dropdownPrefixCls = `${prefixCls}-dropdown`;
|
const dropdownPrefixCls = `${prefixCls}-dropdown`;
|
||||||
|
|
||||||
const getPopupPlacement = () => {
|
const getPopupPlacement = () => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { inject, InjectionKey, provide } from 'vue';
|
import { inject, InjectionKey, provide, Ref } from 'vue';
|
||||||
import type { NullableDateType, RangeValue } from './interface';
|
import type { NullableDateType, RangeValue } from './interface';
|
||||||
|
|
||||||
export type RangeContextProps = {
|
export type RangeContextProps = {
|
||||||
|
|
@ -6,13 +6,12 @@ export type RangeContextProps = {
|
||||||
* Set displayed range value style.
|
* Set displayed range value style.
|
||||||
* Panel only has one value, this is only style effect.
|
* Panel only has one value, this is only style effect.
|
||||||
*/
|
*/
|
||||||
rangedValue?: [NullableDateType<any>, NullableDateType<any>] | null;
|
rangedValue?: Ref<[NullableDateType<any>, NullableDateType<any>] | null>;
|
||||||
hoverRangedValue?: RangeValue<any>;
|
hoverRangedValue?: Ref<RangeValue<any>>;
|
||||||
inRange?: boolean;
|
inRange?: Ref<boolean>;
|
||||||
panelPosition?: 'left' | 'right' | false;
|
panelPosition?: Ref<'left' | 'right' | false>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const RangeContextKey: InjectionKey<RangeContextProps> = Symbol('RangeContextProps');
|
const RangeContextKey: InjectionKey<RangeContextProps> = Symbol('RangeContextProps');
|
||||||
|
|
||||||
export const useProvideRange = (props: RangeContextProps) => {
|
export const useProvideRange = (props: RangeContextProps) => {
|
||||||
|
|
@ -23,5 +22,4 @@ export const useInjectRange = () => {
|
||||||
return inject(RangeContextKey);
|
return inject(RangeContextKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default RangeContextKey;
|
export default RangeContextKey;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,7 @@ export default function useCellClassName<DateType>({
|
||||||
}: {
|
}: {
|
||||||
cellPrefixCls: string;
|
cellPrefixCls: string;
|
||||||
generateConfig: GenerateConfig<DateType>;
|
generateConfig: GenerateConfig<DateType>;
|
||||||
isSameCell: (
|
isSameCell: (current: NullableDateType<DateType>, target: NullableDateType<DateType>) => boolean;
|
||||||
current: NullableDateType<DateType>,
|
|
||||||
target: NullableDateType<DateType>,
|
|
||||||
) => boolean;
|
|
||||||
offsetCell: (date: DateType, offset: number) => DateType;
|
offsetCell: (date: DateType, offset: number) => DateType;
|
||||||
isInView: (date: DateType) => boolean;
|
isInView: (date: DateType) => boolean;
|
||||||
rangedValue?: RangeValue<DateType>;
|
rangedValue?: RangeValue<DateType>;
|
||||||
|
|
@ -37,12 +34,7 @@ export default function useCellClassName<DateType>({
|
||||||
const hoverStart = getValue(hoverRangedValue, 0);
|
const hoverStart = getValue(hoverRangedValue, 0);
|
||||||
const hoverEnd = getValue(hoverRangedValue, 1);
|
const hoverEnd = getValue(hoverRangedValue, 1);
|
||||||
|
|
||||||
const isRangeHovered = isInRange(
|
const isRangeHovered = isInRange(generateConfig, hoverStart, hoverEnd, currentDate);
|
||||||
generateConfig,
|
|
||||||
hoverStart,
|
|
||||||
hoverEnd,
|
|
||||||
currentDate,
|
|
||||||
);
|
|
||||||
|
|
||||||
function isRangeStart(date: DateType) {
|
function isRangeStart(date: DateType) {
|
||||||
return isSameCell(rangeStart, date);
|
return isSameCell(rangeStart, date);
|
||||||
|
|
@ -54,11 +46,9 @@ export default function useCellClassName<DateType>({
|
||||||
const isHoverEnd = isSameCell(hoverEnd, currentDate);
|
const isHoverEnd = isSameCell(hoverEnd, currentDate);
|
||||||
|
|
||||||
const isHoverEdgeStart =
|
const isHoverEdgeStart =
|
||||||
(isRangeHovered || isHoverEnd) &&
|
(isRangeHovered || isHoverEnd) && (!isInView(prevDate) || isRangeEnd(prevDate));
|
||||||
(!isInView(prevDate) || isRangeEnd(prevDate));
|
|
||||||
const isHoverEdgeEnd =
|
const isHoverEdgeEnd =
|
||||||
(isRangeHovered || isHoverStart) &&
|
(isRangeHovered || isHoverStart) && (!isInView(nextDate) || isRangeStart(nextDate));
|
||||||
(!isInView(nextDate) || isRangeStart(nextDate));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// In view
|
// In view
|
||||||
|
|
@ -73,10 +63,8 @@ export default function useCellClassName<DateType>({
|
||||||
),
|
),
|
||||||
[`${cellPrefixCls}-range-start`]: isRangeStart(currentDate),
|
[`${cellPrefixCls}-range-start`]: isRangeStart(currentDate),
|
||||||
[`${cellPrefixCls}-range-end`]: isRangeEnd(currentDate),
|
[`${cellPrefixCls}-range-end`]: isRangeEnd(currentDate),
|
||||||
[`${cellPrefixCls}-range-start-single`]:
|
[`${cellPrefixCls}-range-start-single`]: isRangeStart(currentDate) && !rangeEnd,
|
||||||
isRangeStart(currentDate) && !rangeEnd,
|
[`${cellPrefixCls}-range-end-single`]: isRangeEnd(currentDate) && !rangeStart,
|
||||||
[`${cellPrefixCls}-range-end-single`]:
|
|
||||||
isRangeEnd(currentDate) && !rangeStart,
|
|
||||||
[`${cellPrefixCls}-range-start-near-hover`]:
|
[`${cellPrefixCls}-range-start-near-hover`]:
|
||||||
isRangeStart(currentDate) &&
|
isRangeStart(currentDate) &&
|
||||||
(isSameCell(prevDate, hoverStart) ||
|
(isSameCell(prevDate, hoverStart) ||
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export default function useHoverValue<DateType>(
|
||||||
const [value, internalSetValue] = useState<DateType>(null);
|
const [value, internalSetValue] = useState<DateType>(null);
|
||||||
const raf = useRef(null);
|
const raf = useRef(null);
|
||||||
|
|
||||||
function setValue(val: DateType, immediately: boolean = false) {
|
function setValue(val: DateType, immediately = false) {
|
||||||
cancelAnimationFrame(raf.current);
|
cancelAnimationFrame(raf.current);
|
||||||
if (immediately) {
|
if (immediately) {
|
||||||
internalSetValue(val);
|
internalSetValue(val);
|
||||||
|
|
@ -30,7 +30,7 @@ export default function useHoverValue<DateType>(
|
||||||
setValue(date);
|
setValue(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onLeave(immediately: boolean = false) {
|
function onLeave(immediately = false) {
|
||||||
setValue(null, immediately);
|
setValue(null, immediately);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
import type { HTMLAttributes } from 'vue';
|
||||||
|
import { useAttrs } from 'vue';
|
||||||
|
|
||||||
|
// 仅用在函数式组件中,不用考虑响应式问题
|
||||||
|
export default function useMergeProps<T>(props: T) {
|
||||||
|
const attrs: HTMLAttributes = useAttrs();
|
||||||
|
return { ...props, ...attrs };
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import type * as React from 'react';
|
import type { ComputedRef, HTMLAttributes, Ref } from 'vue';
|
||||||
import { useState, useEffect, useRef } from 'react';
|
import { onBeforeUnmount } from 'vue';
|
||||||
import KeyCode from 'rc-util/lib/KeyCode';
|
import { watchEffect } from 'vue';
|
||||||
|
import { watch } from 'vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import type { FocusEventHandler } from '../../_util/EventInterface';
|
||||||
|
import KeyCode from '../../_util/KeyCode';
|
||||||
import { addGlobalMouseDownEvent, getTargetFromEvent } from '../utils/uiUtil';
|
import { addGlobalMouseDownEvent, getTargetFromEvent } from '../utils/uiUtil';
|
||||||
|
|
||||||
export default function usePickerInput({
|
export default function usePickerInput({
|
||||||
|
|
@ -16,51 +21,51 @@ export default function usePickerInput({
|
||||||
onFocus,
|
onFocus,
|
||||||
onBlur,
|
onBlur,
|
||||||
}: {
|
}: {
|
||||||
open: boolean;
|
open: Ref<boolean>;
|
||||||
value: string;
|
value: Ref<string>;
|
||||||
isClickOutside: (clickElement: EventTarget | null) => boolean;
|
isClickOutside: (clickElement: EventTarget | null) => boolean;
|
||||||
triggerOpen: (open: boolean) => void;
|
triggerOpen: (open: boolean) => void;
|
||||||
forwardKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => boolean;
|
forwardKeyDown: (e: KeyboardEvent) => boolean;
|
||||||
onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>, preventDefault: () => void) => void;
|
onKeyDown: (e: KeyboardEvent, preventDefault: () => void) => void;
|
||||||
blurToCancel?: boolean;
|
blurToCancel?: ComputedRef<boolean>;
|
||||||
onSubmit: () => void | boolean;
|
onSubmit: () => void | boolean;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
onFocus?: FocusEventHandler;
|
||||||
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
onBlur?: FocusEventHandler;
|
||||||
}): [React.DOMAttributes<HTMLInputElement>, { focused: boolean; typing: boolean }] {
|
}): [ComputedRef<HTMLAttributes>, { focused: Ref<boolean>; typing: Ref<boolean> }] {
|
||||||
const [typing, setTyping] = useState(false);
|
const typing = ref(false);
|
||||||
const [focused, setFocused] = useState(false);
|
const focused = ref(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We will prevent blur to handle open event when user click outside,
|
* We will prevent blur to handle open event when user click outside,
|
||||||
* since this will repeat trigger `onOpenChange` event.
|
* since this will repeat trigger `onOpenChange` event.
|
||||||
*/
|
*/
|
||||||
const preventBlurRef = useRef<boolean>(false);
|
const preventBlurRef = ref<boolean>(false);
|
||||||
|
|
||||||
const valueChangedRef = useRef<boolean>(false);
|
const valueChangedRef = ref<boolean>(false);
|
||||||
|
|
||||||
const preventDefaultRef = useRef<boolean>(false);
|
const preventDefaultRef = ref<boolean>(false);
|
||||||
|
|
||||||
const inputProps: React.DOMAttributes<HTMLInputElement> = {
|
const inputProps = computed<HTMLAttributes>(() => ({
|
||||||
onMouseDown: () => {
|
onMousedown: () => {
|
||||||
setTyping(true);
|
typing.value = true;
|
||||||
triggerOpen(true);
|
triggerOpen(true);
|
||||||
},
|
},
|
||||||
onKeyDown: (e) => {
|
onKeydown: e => {
|
||||||
const preventDefault = (): void => {
|
const preventDefault = (): void => {
|
||||||
preventDefaultRef.current = true;
|
preventDefaultRef.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
onKeyDown(e, preventDefault);
|
onKeyDown(e, preventDefault);
|
||||||
|
|
||||||
if (preventDefaultRef.current) return;
|
if (preventDefaultRef.value) return;
|
||||||
|
|
||||||
switch (e.which) {
|
switch (e.which) {
|
||||||
case KeyCode.ENTER: {
|
case KeyCode.ENTER: {
|
||||||
if (!open) {
|
if (!open.value) {
|
||||||
triggerOpen(true);
|
triggerOpen(true);
|
||||||
} else if (onSubmit() !== false) {
|
} else if (onSubmit() !== false) {
|
||||||
setTyping(true);
|
typing.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -68,12 +73,12 @@ export default function usePickerInput({
|
||||||
}
|
}
|
||||||
|
|
||||||
case KeyCode.TAB: {
|
case KeyCode.TAB: {
|
||||||
if (typing && open && !e.shiftKey) {
|
if (typing.value && open.value && !e.shiftKey) {
|
||||||
setTyping(false);
|
typing.value = false;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
} else if (!typing && open) {
|
} else if (!typing.value && open.value) {
|
||||||
if (!forwardKeyDown(e) && e.shiftKey) {
|
if (!forwardKeyDown(e) && e.shiftKey) {
|
||||||
setTyping(true);
|
typing.value = true;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -81,32 +86,32 @@ export default function usePickerInput({
|
||||||
}
|
}
|
||||||
|
|
||||||
case KeyCode.ESC: {
|
case KeyCode.ESC: {
|
||||||
setTyping(true);
|
typing.value = true;
|
||||||
onCancel();
|
onCancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!open && ![KeyCode.SHIFT].includes(e.which)) {
|
if (!open.value && ![KeyCode.SHIFT].includes(e.which)) {
|
||||||
triggerOpen(true);
|
triggerOpen(true);
|
||||||
} else if (!typing) {
|
} else if (!typing.value) {
|
||||||
// Let popup panel handle keyboard
|
// Let popup panel handle keyboard
|
||||||
forwardKeyDown(e);
|
forwardKeyDown(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onFocus: (e) => {
|
onFocus: e => {
|
||||||
setTyping(true);
|
typing.value = true;
|
||||||
setFocused(true);
|
focused.value = true;
|
||||||
|
|
||||||
if (onFocus) {
|
if (onFocus) {
|
||||||
onFocus(e);
|
onFocus(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onBlur: (e) => {
|
onBlur: e => {
|
||||||
if (preventBlurRef.current || !isClickOutside(document.activeElement)) {
|
if (preventBlurRef.value || !isClickOutside(document.activeElement)) {
|
||||||
preventBlurRef.current = false;
|
preventBlurRef.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,51 +126,58 @@ export default function usePickerInput({
|
||||||
onCancel();
|
onCancel();
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
} else if (open) {
|
} else if (open.value) {
|
||||||
triggerOpen(false);
|
triggerOpen(false);
|
||||||
|
|
||||||
if (valueChangedRef.current) {
|
if (valueChangedRef.value) {
|
||||||
onSubmit();
|
onSubmit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setFocused(false);
|
focused.value = false;
|
||||||
|
|
||||||
if (onBlur) {
|
if (onBlur) {
|
||||||
onBlur(e);
|
onBlur(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
}));
|
||||||
|
|
||||||
// check if value changed
|
// check if value changed
|
||||||
useEffect(() => {
|
watch(open, () => {
|
||||||
valueChangedRef.current = false;
|
valueChangedRef.value = false;
|
||||||
}, [open]);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
valueChangedRef.current = true;
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
|
watch(value, () => {
|
||||||
|
valueChangedRef.value = true;
|
||||||
|
});
|
||||||
|
const globalMouseDownEvent = ref();
|
||||||
// Global click handler
|
// Global click handler
|
||||||
useEffect(() =>
|
watchEffect(
|
||||||
addGlobalMouseDownEvent((e: MouseEvent) => {
|
() =>
|
||||||
|
globalMouseDownEvent.value &&
|
||||||
|
globalMouseDownEvent.value()(
|
||||||
|
(globalMouseDownEvent.value = addGlobalMouseDownEvent((e: MouseEvent) => {
|
||||||
const target = getTargetFromEvent(e);
|
const target = getTargetFromEvent(e);
|
||||||
|
|
||||||
if (open) {
|
if (open) {
|
||||||
const clickedOutside = isClickOutside(target);
|
const clickedOutside = isClickOutside(target);
|
||||||
|
|
||||||
if (!clickedOutside) {
|
if (!clickedOutside) {
|
||||||
preventBlurRef.current = true;
|
preventBlurRef.value = true;
|
||||||
|
|
||||||
// Always set back in case `onBlur` prevented by user
|
// Always set back in case `onBlur` prevented by user
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
preventBlurRef.current = false;
|
preventBlurRef.value = false;
|
||||||
});
|
});
|
||||||
} else if (!focused || clickedOutside) {
|
} else if (!focused.value || clickedOutside) {
|
||||||
triggerOpen(false);
|
triggerOpen(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
})),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
globalMouseDownEvent.value && globalMouseDownEvent.value();
|
||||||
|
});
|
||||||
|
|
||||||
return [inputProps, { focused, typing }];
|
return [inputProps, { focused, typing }];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,36 @@
|
||||||
import * as React from 'react';
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
|
||||||
export default function useTextValueMapping({
|
export default function useTextValueMapping({
|
||||||
valueTexts,
|
valueTexts,
|
||||||
onTextChange,
|
onTextChange,
|
||||||
}: {
|
}: {
|
||||||
/** Must useMemo, to assume that `valueTexts` only match on the first change */
|
/** Must useMemo, to assume that `valueTexts` only match on the first change */
|
||||||
valueTexts: string[];
|
valueTexts: ComputedRef<string[]>;
|
||||||
onTextChange: (text: string) => void;
|
onTextChange: (text: string) => void;
|
||||||
}): [string, (text: string) => void, () => void] {
|
}): [Ref<string>, (text: string) => void, () => void] {
|
||||||
const [text, setInnerText] = React.useState('');
|
const text = ref('');
|
||||||
const valueTextsRef = React.useRef<string[]>([]);
|
|
||||||
valueTextsRef.current = valueTexts;
|
|
||||||
|
|
||||||
function triggerTextChange(value: string) {
|
function triggerTextChange(value: string) {
|
||||||
setInnerText(value);
|
text.value = value;
|
||||||
onTextChange(value);
|
onTextChange(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetText() {
|
function resetText() {
|
||||||
setInnerText(valueTextsRef.current[0]);
|
text.value = valueTexts.value[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
watch(
|
||||||
if (valueTexts.every(valText => valText !== text)) {
|
() => [...valueTexts.value],
|
||||||
|
(cur, pre) => {
|
||||||
|
if (
|
||||||
|
cur.join('||') !== pre.join('||') &&
|
||||||
|
valueTexts.value.every(valText => valText !== text.value)
|
||||||
|
) {
|
||||||
resetText();
|
resetText();
|
||||||
}
|
}
|
||||||
}, [valueTexts.join('||')]);
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return [text, triggerTextChange, resetText];
|
return [text, triggerTextChange, resetText];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,37 @@
|
||||||
import shallowEqual from 'shallowequal';
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
import useMemo from 'rc-util/lib/hooks/useMemo';
|
import useMemo from '../../_util/hooks/useMemo';
|
||||||
|
import shallowequal from '../../_util/shallowequal';
|
||||||
import type { GenerateConfig } from '../generate';
|
import type { GenerateConfig } from '../generate';
|
||||||
import type { CustomFormat, Locale } from '../interface';
|
import type { CustomFormat, Locale } from '../interface';
|
||||||
import { formatValue } from '../utils/dateUtil';
|
import { formatValue } from '../utils/dateUtil';
|
||||||
|
|
||||||
export type ValueTextConfig<DateType> = {
|
export type ValueTextConfig<DateType> = {
|
||||||
formatList: (string | CustomFormat<DateType>)[];
|
formatList: ComputedRef<(string | CustomFormat<DateType>)[]>;
|
||||||
generateConfig: GenerateConfig<DateType>;
|
generateConfig: Ref<GenerateConfig<DateType>>;
|
||||||
locale: Locale;
|
locale: Ref<Locale>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function useValueTexts<DateType>(
|
export default function useValueTexts<DateType>(
|
||||||
value: DateType | null,
|
value: Ref<DateType | null>,
|
||||||
{ formatList, generateConfig, locale }: ValueTextConfig<DateType>,
|
{ formatList, generateConfig, locale }: ValueTextConfig<DateType>,
|
||||||
) {
|
) {
|
||||||
return useMemo<[string[], string]>(
|
return useMemo<[string[], string]>(
|
||||||
() => {
|
() => {
|
||||||
if (!value) {
|
if (!value.value) {
|
||||||
return [[''], ''];
|
return [[''], ''];
|
||||||
}
|
}
|
||||||
|
|
||||||
// We will convert data format back to first format
|
// We will convert data format back to first format
|
||||||
let firstValueText: string = '';
|
let firstValueText = '';
|
||||||
const fullValueTexts: string[] = [];
|
const fullValueTexts: string[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < formatList.length; i += 1) {
|
for (let i = 0; i < formatList.value.length; i += 1) {
|
||||||
const format = formatList[i];
|
const format = formatList[i];
|
||||||
const formatStr = formatValue(value, { generateConfig, locale, format });
|
const formatStr = formatValue(value.value, {
|
||||||
|
generateConfig: generateConfig.value,
|
||||||
|
locale: locale.value,
|
||||||
|
format,
|
||||||
|
});
|
||||||
fullValueTexts.push(formatStr);
|
fullValueTexts.push(formatStr);
|
||||||
|
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
|
|
@ -37,6 +42,6 @@ export default function useValueTexts<DateType>(
|
||||||
return [fullValueTexts, firstValueText];
|
return [fullValueTexts, firstValueText];
|
||||||
},
|
},
|
||||||
[value, formatList],
|
[value, formatList],
|
||||||
(prev, next) => prev[0] !== next[0] || !shallowEqual(prev[1], next[1]),
|
(next, prev) => prev[0] !== next[0] || !shallowequal(prev[1], next[1]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { Ref } from 'vue';
|
||||||
import type { GenerateConfig } from './generate';
|
import type { GenerateConfig } from './generate';
|
||||||
|
|
||||||
export type Locale = {
|
export type Locale = {
|
||||||
|
|
@ -46,7 +47,7 @@ export type PickerMode = Exclude<PanelMode, 'datetime' | 'decade'>;
|
||||||
|
|
||||||
export type PanelRefProps = {
|
export type PanelRefProps = {
|
||||||
onKeyDown?: (e: KeyboardEvent) => boolean;
|
onKeyDown?: (e: KeyboardEvent) => boolean;
|
||||||
onBlur?: (e: FocusEvent)=> void;
|
onBlur?: (e: FocusEvent) => void;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -74,7 +75,7 @@ export type PanelSharedProps<DateType> = {
|
||||||
// * Thus, move ref into operationRef.
|
// * Thus, move ref into operationRef.
|
||||||
// * This is little hack which should refactor after typescript support.
|
// * This is little hack which should refactor after typescript support.
|
||||||
// */
|
// */
|
||||||
// operationRef: React.MutableRefObject<PanelRefProps>;
|
operationRef: Ref<PanelRefProps>;
|
||||||
|
|
||||||
onSelect: OnSelect<DateType>;
|
onSelect: OnSelect<DateType>;
|
||||||
onViewDateChange: (value: DateType) => void;
|
onViewDateChange: (value: DateType) => void;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import {
|
import {
|
||||||
WEEK_DAY_COUNT,
|
WEEK_DAY_COUNT,
|
||||||
|
|
@ -12,6 +11,7 @@ import useCellClassName from '../../hooks/useCellClassName';
|
||||||
import PanelBody from '../PanelBody';
|
import PanelBody from '../PanelBody';
|
||||||
import { VueNode } from '../../../_util/type';
|
import { VueNode } from '../../../_util/type';
|
||||||
import { useInjectRange } from '../../RangeContext';
|
import { useInjectRange } from '../../RangeContext';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type DateRender<DateType> = (currentDate: DateType, today: DateType) => VueNode;
|
export type DateRender<DateType> = (currentDate: DateType, today: DateType) => VueNode;
|
||||||
|
|
||||||
|
|
@ -34,19 +34,12 @@ export type DateBodyProps<DateType> = {
|
||||||
onSelect: (value: DateType) => void;
|
onSelect: (value: DateType) => void;
|
||||||
} & DateBodyPassProps<DateType>;
|
} & DateBodyPassProps<DateType>;
|
||||||
|
|
||||||
function DateBody<DateType>(props: DateBodyProps<DateType>) {
|
function DateBody<DateType>(_props: DateBodyProps<DateType>) {
|
||||||
const {
|
const props = useMergeProps(_props);
|
||||||
prefixCls,
|
const { prefixCls, generateConfig, prefixColumn, locale, rowCount, viewDate, value, dateRender } =
|
||||||
generateConfig,
|
props;
|
||||||
prefixColumn,
|
|
||||||
locale,
|
|
||||||
rowCount,
|
|
||||||
viewDate,
|
|
||||||
value,
|
|
||||||
dateRender,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const { rangedValue, hoverRangedValue } =useInjectRange()
|
const { rangedValue, hoverRangedValue } = useInjectRange();
|
||||||
|
|
||||||
const baseDate = getWeekStartDate(locale.locale, generateConfig, viewDate);
|
const baseDate = getWeekStartDate(locale.locale, generateConfig, viewDate);
|
||||||
const cellPrefixCls = `${prefixCls}-cell`;
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
@ -74,8 +67,8 @@ function DateBody<DateType>(props: DateBodyProps<DateType>) {
|
||||||
today,
|
today,
|
||||||
value,
|
value,
|
||||||
generateConfig,
|
generateConfig,
|
||||||
rangedValue: prefixColumn ? null : rangedValue,
|
rangedValue: prefixColumn ? null : rangedValue.value,
|
||||||
hoverRangedValue: prefixColumn ? null : hoverRangedValue,
|
hoverRangedValue: prefixColumn ? null : hoverRangedValue.value,
|
||||||
isSameCell: (current, target) => isSameDate(generateConfig, current, target),
|
isSameCell: (current, target) => isSameDate(generateConfig, current, target),
|
||||||
isInView: date => isSameMonth(generateConfig, date, viewDate),
|
isInView: date => isSameMonth(generateConfig, date, viewDate),
|
||||||
offsetCell: (date, offset) => generateConfig.addDate(date, offset),
|
offsetCell: (date, offset) => generateConfig.addDate(date, offset),
|
||||||
|
|
@ -105,7 +98,20 @@ function DateBody<DateType>(props: DateBodyProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DateBody.displayName = 'DateBody'
|
DateBody.displayName = 'DateBody';
|
||||||
DateBody.inheritAttrs = false;
|
DateBody.inheritAttrs = false;
|
||||||
|
DateBody.props = [
|
||||||
|
'prefixCls',
|
||||||
|
'generateConfig',
|
||||||
|
'value?',
|
||||||
|
'viewDate',
|
||||||
|
'locale',
|
||||||
|
'rowCount',
|
||||||
|
'onSelect',
|
||||||
|
'dateRender?',
|
||||||
|
'disabledDate?',
|
||||||
|
// Used for week panel
|
||||||
|
'prefixColumn?',
|
||||||
|
'rowClassName?',
|
||||||
|
];
|
||||||
export default DateBody;
|
export default DateBody;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
import Header from '../Header';
|
import Header from '../Header';
|
||||||
import type { Locale } from '../../interface';
|
import type { Locale } from '../../interface';
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import { useInjectPanel } from '../../PanelContext';
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
import { formatValue } from '../../utils/dateUtil';
|
import { formatValue } from '../../utils/dateUtil';
|
||||||
import { VueNode } from '../../../_util/type';
|
import { VueNode } from '../../../_util/type';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type DateHeaderProps<DateType> = {
|
export type DateHeaderProps<DateType> = {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
|
@ -21,7 +21,8 @@ export type DateHeaderProps<DateType> = {
|
||||||
onMonthClick: () => void;
|
onMonthClick: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function DateHeader<DateType>(props: DateHeaderProps<DateType>) {
|
function DateHeader<DateType>(_props: DateHeaderProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
generateConfig,
|
generateConfig,
|
||||||
|
|
@ -35,8 +36,8 @@ function DateHeader<DateType>(props: DateHeaderProps<DateType>) {
|
||||||
onMonthClick,
|
onMonthClick,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { hideHeader } = useInjectPanel()
|
const { hideHeader } = useInjectPanel();
|
||||||
if (hideHeader) {
|
if (hideHeader.value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,6 +101,6 @@ function DateHeader<DateType>(props: DateHeaderProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DateHeader.displayName = 'DateHeader'
|
DateHeader.displayName = 'DateHeader';
|
||||||
DateHeader.inheritAttrs = false;
|
DateHeader.inheritAttrs = false;
|
||||||
export default DateHeader;
|
export default DateHeader;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import type { DateBodyPassProps, DateRender } from './DateBody';
|
import type { DateBodyPassProps, DateRender } from './DateBody';
|
||||||
import DateBody from './DateBody';
|
import DateBody from './DateBody';
|
||||||
import DateHeader from './DateHeader';
|
import DateHeader from './DateHeader';
|
||||||
|
|
@ -8,6 +7,7 @@ import type { KeyboardConfig } from '../../utils/uiUtil';
|
||||||
import { createKeyDownHandler } from '../../utils/uiUtil';
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
import classNames from '../../../_util/classNames';
|
import classNames from '../../../_util/classNames';
|
||||||
import { ref } from '@vue/reactivity';
|
import { ref } from '@vue/reactivity';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
const DATE_ROW_COUNT = 6;
|
const DATE_ROW_COUNT = 6;
|
||||||
|
|
||||||
|
|
@ -18,14 +18,17 @@ export type DatePanelProps<DateType> = {
|
||||||
// Used for week panel
|
// Used for week panel
|
||||||
panelName?: string;
|
panelName?: string;
|
||||||
keyboardConfig?: KeyboardConfig;
|
keyboardConfig?: KeyboardConfig;
|
||||||
} & PanelSharedProps<DateType> & DateBodyPassProps<DateType>;
|
} & PanelSharedProps<DateType> &
|
||||||
|
DateBodyPassProps<DateType>;
|
||||||
|
|
||||||
function DatePanel<DateType>(props: DatePanelProps<DateType>) {
|
function DatePanel<DateType>(_props: DatePanelProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
panelName = 'date',
|
panelName = 'date',
|
||||||
keyboardConfig,
|
keyboardConfig,
|
||||||
active,
|
active,
|
||||||
|
operationRef,
|
||||||
generateConfig,
|
generateConfig,
|
||||||
value,
|
value,
|
||||||
viewDate,
|
viewDate,
|
||||||
|
|
@ -34,10 +37,9 @@ function DatePanel<DateType>(props: DatePanelProps<DateType>) {
|
||||||
onSelect,
|
onSelect,
|
||||||
} = props;
|
} = props;
|
||||||
const panelPrefixCls = `${prefixCls}-${panelName}-panel`;
|
const panelPrefixCls = `${prefixCls}-${panelName}-panel`;
|
||||||
const operationRef = ref()
|
|
||||||
// ======================= Keyboard =======================
|
// ======================= Keyboard =======================
|
||||||
operationRef.value = {
|
operationRef.value = {
|
||||||
onKeyDown: event =>
|
onKeyDown: (event: KeyboardEvent) =>
|
||||||
createKeyDownHandler(event, {
|
createKeyDownHandler(event, {
|
||||||
onLeftRight: diff => {
|
onLeftRight: diff => {
|
||||||
onSelect(generateConfig.addDate(value || viewDate, diff), 'key');
|
onSelect(generateConfig.addDate(value || viewDate, diff), 'key');
|
||||||
|
|
@ -110,7 +112,7 @@ function DatePanel<DateType>(props: DatePanelProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DatePanel.displayName ='DatePanel'
|
DatePanel.displayName = 'DatePanel';
|
||||||
DatePanel.inheritAttrs = false;
|
DatePanel.inheritAttrs = false;
|
||||||
|
|
||||||
export default DatePanel;
|
export default DatePanel;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import type { DatePanelProps } from '../DatePanel';
|
import type { DatePanelProps } from '../DatePanel';
|
||||||
import DatePanel from '../DatePanel';
|
import DatePanel from '../DatePanel';
|
||||||
import type { SharedTimeProps } from '../TimePanel';
|
import type { SharedTimeProps } from '../TimePanel';
|
||||||
|
|
@ -9,20 +8,19 @@ import type { PanelRefProps, DisabledTime } from '../../interface';
|
||||||
import KeyCode from '../../../_util/KeyCode';
|
import KeyCode from '../../../_util/KeyCode';
|
||||||
import classNames from '../../../_util/classNames';
|
import classNames from '../../../_util/classNames';
|
||||||
import { ref } from '@vue/reactivity';
|
import { ref } from '@vue/reactivity';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type DatetimePanelProps<DateType> = {
|
export type DatetimePanelProps<DateType> = {
|
||||||
disabledTime?: DisabledTime<DateType>;
|
disabledTime?: DisabledTime<DateType>;
|
||||||
showTime?: boolean | SharedTimeProps<DateType>;
|
showTime?: boolean | SharedTimeProps<DateType>;
|
||||||
defaultValue?: DateType;
|
defaultValue?: DateType;
|
||||||
} & Omit<
|
} & Omit<DatePanelProps<DateType>, 'disabledHours' | 'disabledMinutes' | 'disabledSeconds'>;
|
||||||
DatePanelProps<DateType>,
|
|
||||||
'disabledHours' | 'disabledMinutes' | 'disabledSeconds'
|
|
||||||
>;
|
|
||||||
|
|
||||||
const ACTIVE_PANEL = tuple('date', 'time');
|
const ACTIVE_PANEL = tuple('date', 'time');
|
||||||
type ActivePanelType = typeof ACTIVE_PANEL[number];
|
type ActivePanelType = typeof ACTIVE_PANEL[number];
|
||||||
|
|
||||||
function DatetimePanel<DateType>(props: DatetimePanelProps<DateType>) {
|
function DatetimePanel<DateType>(_props: DatetimePanelProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
operationRef,
|
operationRef,
|
||||||
|
|
@ -34,9 +32,7 @@ function DatetimePanel<DateType>(props: DatetimePanelProps<DateType>) {
|
||||||
onSelect,
|
onSelect,
|
||||||
} = props;
|
} = props;
|
||||||
const panelPrefixCls = `${prefixCls}-datetime-panel`;
|
const panelPrefixCls = `${prefixCls}-datetime-panel`;
|
||||||
const activePanel = ref<ActivePanelType | null>(
|
const activePanel = ref<ActivePanelType | null>(null);
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
const dateOperationRef = ref<PanelRefProps>({});
|
const dateOperationRef = ref<PanelRefProps>({});
|
||||||
const timeOperationRef = ref<PanelRefProps>({});
|
const timeOperationRef = ref<PanelRefProps>({});
|
||||||
|
|
@ -57,12 +53,12 @@ function DatetimePanel<DateType>(props: DatetimePanelProps<DateType>) {
|
||||||
activePanel.value = null;
|
activePanel.value = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
operationRef.current = {
|
operationRef.value = {
|
||||||
onKeyDown: event => {
|
onKeyDown: (event: KeyboardEvent) => {
|
||||||
// Switch active panel
|
// Switch active panel
|
||||||
if (event.which === KeyCode.TAB) {
|
if (event.which === KeyCode.TAB) {
|
||||||
const nextActivePanel = getNextActive(event.shiftKey ? -1 : 1);
|
const nextActivePanel = getNextActive(event.shiftKey ? -1 : 1);
|
||||||
activePanel.value = nextActivePanel
|
activePanel.value = nextActivePanel;
|
||||||
|
|
||||||
if (nextActivePanel) {
|
if (nextActivePanel) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -73,8 +69,7 @@ function DatetimePanel<DateType>(props: DatetimePanelProps<DateType>) {
|
||||||
|
|
||||||
// Operate on current active panel
|
// Operate on current active panel
|
||||||
if (activePanel.value) {
|
if (activePanel.value) {
|
||||||
const ref =
|
const ref = activePanel.value === 'date' ? dateOperationRef : timeOperationRef;
|
||||||
activePanel.value === 'date' ? dateOperationRef : timeOperationRef;
|
|
||||||
|
|
||||||
if (ref.value && ref.value.onKeyDown) {
|
if (ref.value && ref.value.onKeyDown) {
|
||||||
ref.value.onKeyDown(event);
|
ref.value.onKeyDown(event);
|
||||||
|
|
@ -84,12 +79,8 @@ function DatetimePanel<DateType>(props: DatetimePanelProps<DateType>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch first active panel if operate without panel
|
// Switch first active panel if operate without panel
|
||||||
if (
|
if ([KeyCode.LEFT, KeyCode.RIGHT, KeyCode.UP, KeyCode.DOWN].includes(event.which)) {
|
||||||
[KeyCode.LEFT, KeyCode.RIGHT, KeyCode.UP, KeyCode.DOWN].includes(
|
activePanel.value = 'date';
|
||||||
event.which,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
activePanel.value = 'date'
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,18 +109,9 @@ function DatetimePanel<DateType>(props: DatetimePanelProps<DateType>) {
|
||||||
generateConfig.getSecond(timeProps.defaultValue),
|
generateConfig.getSecond(timeProps.defaultValue),
|
||||||
);
|
);
|
||||||
} else if (source === 'time' && !value && defaultValue) {
|
} else if (source === 'time' && !value && defaultValue) {
|
||||||
selectedDate = generateConfig.setYear(
|
selectedDate = generateConfig.setYear(selectedDate, generateConfig.getYear(defaultValue));
|
||||||
selectedDate,
|
selectedDate = generateConfig.setMonth(selectedDate, generateConfig.getMonth(defaultValue));
|
||||||
generateConfig.getYear(defaultValue),
|
selectedDate = generateConfig.setDate(selectedDate, generateConfig.getDate(defaultValue));
|
||||||
);
|
|
||||||
selectedDate = generateConfig.setMonth(
|
|
||||||
selectedDate,
|
|
||||||
generateConfig.getMonth(defaultValue),
|
|
||||||
);
|
|
||||||
selectedDate = generateConfig.setDate(
|
|
||||||
selectedDate,
|
|
||||||
generateConfig.getDate(defaultValue),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onSelect) {
|
if (onSelect) {
|
||||||
|
|
@ -155,9 +137,7 @@ function DatetimePanel<DateType>(props: DatetimePanelProps<DateType>) {
|
||||||
setTime(
|
setTime(
|
||||||
generateConfig,
|
generateConfig,
|
||||||
date,
|
date,
|
||||||
showTime && typeof showTime === 'object'
|
showTime && typeof showTime === 'object' ? showTime.defaultValue : null,
|
||||||
? showTime.defaultValue
|
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
'date',
|
'date',
|
||||||
);
|
);
|
||||||
|
|
@ -179,8 +159,7 @@ function DatetimePanel<DateType>(props: DatetimePanelProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DatetimePanel.displayName = 'DatetimePanel';
|
||||||
DatetimePanel.displayName ='DatetimePanel'
|
|
||||||
DatetimePanel.inheritAttrs = false;
|
DatetimePanel.inheritAttrs = false;
|
||||||
|
|
||||||
export default DatetimePanel;
|
export default DatetimePanel;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import { DECADE_DISTANCE_COUNT, DECADE_UNIT_DIFF } from '.';
|
import { DECADE_DISTANCE_COUNT, DECADE_UNIT_DIFF } from '.';
|
||||||
import PanelBody from '../PanelBody';
|
import PanelBody from '../PanelBody';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export const DECADE_COL_COUNT = 3;
|
export const DECADE_COL_COUNT = 3;
|
||||||
const DECADE_ROW_COUNT = 4;
|
const DECADE_ROW_COUNT = 4;
|
||||||
|
|
@ -14,7 +14,8 @@ export type YearBodyProps<DateType> = {
|
||||||
onSelect: (value: DateType) => void;
|
onSelect: (value: DateType) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function DecadeBody<DateType>(props: YearBodyProps<DateType>) {
|
function DecadeBody<DateType>(_props: YearBodyProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const DECADE_UNIT_DIFF_DES = DECADE_UNIT_DIFF - 1;
|
const DECADE_UNIT_DIFF_DES = DECADE_UNIT_DIFF - 1;
|
||||||
const { prefixCls, viewDate, generateConfig } = props;
|
const { prefixCls, viewDate, generateConfig } = props;
|
||||||
|
|
||||||
|
|
@ -61,8 +62,7 @@ function DecadeBody<DateType>(props: YearBodyProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DecadeBody.displayName = 'DecadeBody';
|
||||||
DecadeBody.displayName ='DecadeBody'
|
|
||||||
DecadeBody.inheritAttrs = false;
|
DecadeBody.inheritAttrs = false;
|
||||||
|
|
||||||
export default DecadeBody;
|
export default DecadeBody;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
import Header from '../Header';
|
import Header from '../Header';
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import { DECADE_DISTANCE_COUNT } from '.';
|
import { DECADE_DISTANCE_COUNT } from '.';
|
||||||
import { useInjectPanel } from '../../PanelContext';
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type YearHeaderProps<DateType> = {
|
export type YearHeaderProps<DateType> = {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
|
@ -13,15 +13,10 @@ export type YearHeaderProps<DateType> = {
|
||||||
onNextDecades: () => void;
|
onNextDecades: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function DecadeHeader<DateType>(props: YearHeaderProps<DateType>) {
|
function DecadeHeader<DateType>(_props: YearHeaderProps<DateType>) {
|
||||||
const {
|
const props = useMergeProps(_props);
|
||||||
prefixCls,
|
const { prefixCls, generateConfig, viewDate, onPrevDecades, onNextDecades } = props;
|
||||||
generateConfig,
|
const { hideHeader } = useInjectPanel();
|
||||||
viewDate,
|
|
||||||
onPrevDecades,
|
|
||||||
onNextDecades,
|
|
||||||
} = props;
|
|
||||||
const { hideHeader } =useInjectPanel()
|
|
||||||
if (hideHeader) {
|
if (hideHeader) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -29,8 +24,7 @@ function DecadeHeader<DateType>(props: YearHeaderProps<DateType>) {
|
||||||
const headerPrefixCls = `${prefixCls}-header`;
|
const headerPrefixCls = `${prefixCls}-header`;
|
||||||
|
|
||||||
const yearNumber = generateConfig.getYear(viewDate);
|
const yearNumber = generateConfig.getYear(viewDate);
|
||||||
const startYear =
|
const startYear = Math.floor(yearNumber / DECADE_DISTANCE_COUNT) * DECADE_DISTANCE_COUNT;
|
||||||
Math.floor(yearNumber / DECADE_DISTANCE_COUNT) * DECADE_DISTANCE_COUNT;
|
|
||||||
const endYear = startYear + DECADE_DISTANCE_COUNT - 1;
|
const endYear = startYear + DECADE_DISTANCE_COUNT - 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -45,7 +39,7 @@ function DecadeHeader<DateType>(props: YearHeaderProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DecadeHeader.displayName ='DecadeHeader'
|
DecadeHeader.displayName = 'DecadeHeader';
|
||||||
DecadeHeader.inheritAttrs = false;
|
DecadeHeader.inheritAttrs = false;
|
||||||
|
|
||||||
export default DecadeHeader;
|
export default DecadeHeader;
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
|
|
||||||
import DecadeHeader from './DecadeHeader';
|
import DecadeHeader from './DecadeHeader';
|
||||||
import DecadeBody, { DECADE_COL_COUNT } from './DecadeBody';
|
import DecadeBody, { DECADE_COL_COUNT } from './DecadeBody';
|
||||||
import type { PanelSharedProps } from '../../interface';
|
import type { PanelSharedProps } from '../../interface';
|
||||||
import { createKeyDownHandler } from '../../utils/uiUtil';
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type DecadePanelProps<DateType> = PanelSharedProps<DateType>;
|
export type DecadePanelProps<DateType> = PanelSharedProps<DateType>;
|
||||||
|
|
||||||
export const DECADE_UNIT_DIFF = 10;
|
export const DECADE_UNIT_DIFF = 10;
|
||||||
export const DECADE_DISTANCE_COUNT = DECADE_UNIT_DIFF * 10;
|
export const DECADE_DISTANCE_COUNT = DECADE_UNIT_DIFF * 10;
|
||||||
|
|
||||||
function DecadePanel<DateType>(props: DecadePanelProps<DateType>) {
|
function DecadePanel<DateType>(_props: DecadePanelProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
onViewDateChange,
|
onViewDateChange,
|
||||||
|
|
@ -23,27 +24,18 @@ function DecadePanel<DateType>(props: DecadePanelProps<DateType>) {
|
||||||
const panelPrefixCls = `${prefixCls}-decade-panel`;
|
const panelPrefixCls = `${prefixCls}-decade-panel`;
|
||||||
|
|
||||||
// ======================= Keyboard =======================
|
// ======================= Keyboard =======================
|
||||||
operationRef.current = {
|
operationRef.value = {
|
||||||
onKeyDown: event =>
|
onKeyDown: (event: KeyboardEvent) =>
|
||||||
createKeyDownHandler(event, {
|
createKeyDownHandler(event, {
|
||||||
onLeftRight: diff => {
|
onLeftRight: diff => {
|
||||||
onSelect(
|
onSelect(generateConfig.addYear(viewDate, diff * DECADE_UNIT_DIFF), 'key');
|
||||||
generateConfig.addYear(viewDate, diff * DECADE_UNIT_DIFF),
|
|
||||||
'key',
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
onCtrlLeftRight: diff => {
|
onCtrlLeftRight: diff => {
|
||||||
onSelect(
|
onSelect(generateConfig.addYear(viewDate, diff * DECADE_DISTANCE_COUNT), 'key');
|
||||||
generateConfig.addYear(viewDate, diff * DECADE_DISTANCE_COUNT),
|
|
||||||
'key',
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
onUpDown: diff => {
|
onUpDown: diff => {
|
||||||
onSelect(
|
onSelect(
|
||||||
generateConfig.addYear(
|
generateConfig.addYear(viewDate, diff * DECADE_UNIT_DIFF * DECADE_COL_COUNT),
|
||||||
viewDate,
|
|
||||||
diff * DECADE_UNIT_DIFF * DECADE_COL_COUNT,
|
|
||||||
),
|
|
||||||
'key',
|
'key',
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -55,10 +47,7 @@ function DecadePanel<DateType>(props: DecadePanelProps<DateType>) {
|
||||||
|
|
||||||
// ==================== View Operation ====================
|
// ==================== View Operation ====================
|
||||||
const onDecadesChange = (diff: number) => {
|
const onDecadesChange = (diff: number) => {
|
||||||
const newDate = generateConfig.addYear(
|
const newDate = generateConfig.addYear(viewDate, diff * DECADE_DISTANCE_COUNT);
|
||||||
viewDate,
|
|
||||||
diff * DECADE_DISTANCE_COUNT,
|
|
||||||
);
|
|
||||||
onViewDateChange(newDate);
|
onViewDateChange(newDate);
|
||||||
onPanelChange(null, newDate);
|
onPanelChange(null, newDate);
|
||||||
};
|
};
|
||||||
|
|
@ -80,17 +69,12 @@ function DecadePanel<DateType>(props: DecadePanelProps<DateType>) {
|
||||||
onDecadesChange(1);
|
onDecadesChange(1);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<DecadeBody
|
<DecadeBody {...props} prefixCls={prefixCls} onSelect={onInternalSelect} />
|
||||||
{...props}
|
|
||||||
prefixCls={prefixCls}
|
|
||||||
onSelect={onInternalSelect}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DecadePanel.displayName = 'DecadePanel';
|
||||||
DecadePanel.displayName ='DecadePanel'
|
|
||||||
DecadePanel.inheritAttrs = false;
|
DecadePanel.inheritAttrs = false;
|
||||||
|
|
||||||
export default DecadePanel;
|
export default DecadePanel;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { CSSProperties } from '@vue/runtime-dom';
|
import { CSSProperties } from 'vue';
|
||||||
import { VueNode } from '../../_util/type';
|
import { VueNode } from '../../_util/type';
|
||||||
|
import useMergeProps from '../hooks/useMergeProps';
|
||||||
import { useInjectPanel } from '../PanelContext';
|
import { useInjectPanel } from '../PanelContext';
|
||||||
|
|
||||||
const HIDDEN_STYLE: CSSProperties = {
|
const HIDDEN_STYLE: CSSProperties = {
|
||||||
|
|
@ -27,8 +28,9 @@ export type HeaderProps = {
|
||||||
children?: VueNode;
|
children?: VueNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
function Header(
|
function Header(_props: HeaderProps, { slots }) {
|
||||||
{
|
const props = useMergeProps(_props);
|
||||||
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
prevIcon = '\u2039',
|
prevIcon = '\u2039',
|
||||||
nextIcon = '\u203A',
|
nextIcon = '\u203A',
|
||||||
|
|
@ -38,9 +40,7 @@ function Header(
|
||||||
onSuperNext,
|
onSuperNext,
|
||||||
onPrev,
|
onPrev,
|
||||||
onNext,
|
onNext,
|
||||||
}: HeaderProps,
|
} = props;
|
||||||
{ slots },
|
|
||||||
) {
|
|
||||||
const { hideNextBtn, hidePrevBtn } = useInjectPanel();
|
const { hideNextBtn, hidePrevBtn } = useInjectPanel();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -51,7 +51,7 @@ function Header(
|
||||||
onClick={onSuperPrev}
|
onClick={onSuperPrev}
|
||||||
tabindex={-1}
|
tabindex={-1}
|
||||||
class={`${prefixCls}-super-prev-btn`}
|
class={`${prefixCls}-super-prev-btn`}
|
||||||
style={hidePrevBtn ? HIDDEN_STYLE : {}}
|
style={hidePrevBtn.value ? HIDDEN_STYLE : {}}
|
||||||
>
|
>
|
||||||
{superPrevIcon}
|
{superPrevIcon}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -62,7 +62,7 @@ function Header(
|
||||||
onClick={onPrev}
|
onClick={onPrev}
|
||||||
tabindex={-1}
|
tabindex={-1}
|
||||||
class={`${prefixCls}-prev-btn`}
|
class={`${prefixCls}-prev-btn`}
|
||||||
style={hidePrevBtn ? HIDDEN_STYLE : {}}
|
style={hidePrevBtn.value ? HIDDEN_STYLE : {}}
|
||||||
>
|
>
|
||||||
{prevIcon}
|
{prevIcon}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -74,7 +74,7 @@ function Header(
|
||||||
onClick={onNext}
|
onClick={onNext}
|
||||||
tabindex={-1}
|
tabindex={-1}
|
||||||
class={`${prefixCls}-next-btn`}
|
class={`${prefixCls}-next-btn`}
|
||||||
style={hideNextBtn ? HIDDEN_STYLE : {}}
|
style={hideNextBtn.value ? HIDDEN_STYLE : {}}
|
||||||
>
|
>
|
||||||
{nextIcon}
|
{nextIcon}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -85,7 +85,7 @@ function Header(
|
||||||
onClick={onSuperNext}
|
onClick={onSuperNext}
|
||||||
tabindex={-1}
|
tabindex={-1}
|
||||||
class={`${prefixCls}-super-next-btn`}
|
class={`${prefixCls}-super-next-btn`}
|
||||||
style={hideNextBtn ? HIDDEN_STYLE : {}}
|
style={hideNextBtn.value ? HIDDEN_STYLE : {}}
|
||||||
>
|
>
|
||||||
{superNextIcon}
|
{superNextIcon}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import type { Locale } from '../../interface';
|
import type { Locale } from '../../interface';
|
||||||
import { formatValue, isSameMonth } from '../../utils/dateUtil';
|
import { formatValue, isSameMonth } from '../../utils/dateUtil';
|
||||||
|
|
@ -6,6 +5,7 @@ import { useInjectRange } from '../../RangeContext';
|
||||||
import useCellClassName from '../../hooks/useCellClassName';
|
import useCellClassName from '../../hooks/useCellClassName';
|
||||||
import PanelBody from '../PanelBody';
|
import PanelBody from '../PanelBody';
|
||||||
import { VueNode } from '../../../_util/type';
|
import { VueNode } from '../../../_util/type';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export const MONTH_COL_COUNT = 3;
|
export const MONTH_COL_COUNT = 3;
|
||||||
const MONTH_ROW_COUNT = 4;
|
const MONTH_ROW_COUNT = 4;
|
||||||
|
|
@ -23,10 +23,11 @@ export type MonthBodyProps<DateType> = {
|
||||||
onSelect: (value: DateType) => void;
|
onSelect: (value: DateType) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function MonthBody<DateType>(props: MonthBodyProps<DateType>) {
|
function MonthBody<DateType>(_props: MonthBodyProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const { prefixCls, locale, value, viewDate, generateConfig, monthCellRender } = props;
|
const { prefixCls, locale, value, viewDate, generateConfig, monthCellRender } = props;
|
||||||
|
|
||||||
const { rangedValue, hoverRangedValue } = useInjectRange()
|
const { rangedValue, hoverRangedValue } = useInjectRange();
|
||||||
|
|
||||||
const cellPrefixCls = `${prefixCls}-cell`;
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
||||||
|
|
@ -34,8 +35,8 @@ function MonthBody<DateType>(props: MonthBodyProps<DateType>) {
|
||||||
cellPrefixCls,
|
cellPrefixCls,
|
||||||
value,
|
value,
|
||||||
generateConfig,
|
generateConfig,
|
||||||
rangedValue,
|
rangedValue: rangedValue.value,
|
||||||
hoverRangedValue,
|
hoverRangedValue: hoverRangedValue.value,
|
||||||
isSameCell: (current, target) => isSameMonth(generateConfig, current, target),
|
isSameCell: (current, target) => isSameMonth(generateConfig, current, target),
|
||||||
isInView: () => true,
|
isInView: () => true,
|
||||||
offsetCell: (date, offset) => generateConfig.addMonth(date, offset),
|
offsetCell: (date, offset) => generateConfig.addMonth(date, offset),
|
||||||
|
|
@ -82,8 +83,7 @@ function MonthBody<DateType>(props: MonthBodyProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MonthBody.displayName = 'MonthBody';
|
||||||
MonthBody.displayName ='MonthBody'
|
|
||||||
MonthBody.inheritAttrs = false;
|
MonthBody.inheritAttrs = false;
|
||||||
|
|
||||||
export default MonthBody;
|
export default MonthBody;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
import Header from '../Header';
|
import Header from '../Header';
|
||||||
import type { Locale } from '../../interface';
|
import type { Locale } from '../../interface';
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import { useInjectPanel } from '../../PanelContext';
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
import { formatValue } from '../../utils/dateUtil';
|
import { formatValue } from '../../utils/dateUtil';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type MonthHeaderProps<DateType> = {
|
export type MonthHeaderProps<DateType> = {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
|
@ -16,18 +16,12 @@ export type MonthHeaderProps<DateType> = {
|
||||||
onYearClick: () => void;
|
onYearClick: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function MonthHeader<DateType>(props: MonthHeaderProps<DateType>) {
|
function MonthHeader<DateType>(_props: MonthHeaderProps<DateType>) {
|
||||||
const {
|
const props = useMergeProps(_props);
|
||||||
prefixCls,
|
const { prefixCls, generateConfig, locale, viewDate, onNextYear, onPrevYear, onYearClick } =
|
||||||
generateConfig,
|
props;
|
||||||
locale,
|
const { hideHeader } = useInjectPanel();
|
||||||
viewDate,
|
if (hideHeader.value) {
|
||||||
onNextYear,
|
|
||||||
onPrevYear,
|
|
||||||
onYearClick,
|
|
||||||
} = props;
|
|
||||||
const { hideHeader } = useInjectPanel()
|
|
||||||
if (hideHeader) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,8 +45,7 @@ function MonthHeader<DateType>(props: MonthHeaderProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MonthHeader.displayName = 'MonthHeader';
|
||||||
MonthHeader.displayName ='MonthHeader'
|
|
||||||
MonthHeader.inheritAttrs = false;
|
MonthHeader.inheritAttrs = false;
|
||||||
|
|
||||||
export default MonthHeader;
|
export default MonthHeader;
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
|
|
||||||
import MonthHeader from './MonthHeader';
|
import MonthHeader from './MonthHeader';
|
||||||
import type { MonthCellRender } from './MonthBody';
|
import type { MonthCellRender } from './MonthBody';
|
||||||
import MonthBody, { MONTH_COL_COUNT } from './MonthBody';
|
import MonthBody, { MONTH_COL_COUNT } from './MonthBody';
|
||||||
import type { PanelSharedProps } from '../../interface';
|
import type { PanelSharedProps } from '../../interface';
|
||||||
import { createKeyDownHandler } from '../../utils/uiUtil';
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type MonthPanelProps<DateType> = {
|
export type MonthPanelProps<DateType> = {
|
||||||
monthCellContentRender?: MonthCellRender<DateType>;
|
monthCellContentRender?: MonthCellRender<DateType>;
|
||||||
} & PanelSharedProps<DateType>;
|
} & PanelSharedProps<DateType>;
|
||||||
|
|
||||||
function MonthPanel<DateType>(props: MonthPanelProps<DateType>) {
|
function MonthPanel<DateType>(_props: MonthPanelProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
operationRef,
|
operationRef,
|
||||||
|
|
@ -24,8 +25,8 @@ function MonthPanel<DateType>(props: MonthPanelProps<DateType>) {
|
||||||
const panelPrefixCls = `${prefixCls}-month-panel`;
|
const panelPrefixCls = `${prefixCls}-month-panel`;
|
||||||
|
|
||||||
// ======================= Keyboard =======================
|
// ======================= Keyboard =======================
|
||||||
operationRef.current = {
|
operationRef.value = {
|
||||||
onKeyDown: event =>
|
onKeyDown: (event: KeyboardEvent) =>
|
||||||
createKeyDownHandler(event, {
|
createKeyDownHandler(event, {
|
||||||
onLeftRight: diff => {
|
onLeftRight: diff => {
|
||||||
onSelect(generateConfig.addMonth(value || viewDate, diff), 'key');
|
onSelect(generateConfig.addMonth(value || viewDate, diff), 'key');
|
||||||
|
|
@ -34,10 +35,7 @@ function MonthPanel<DateType>(props: MonthPanelProps<DateType>) {
|
||||||
onSelect(generateConfig.addYear(value || viewDate, diff), 'key');
|
onSelect(generateConfig.addYear(value || viewDate, diff), 'key');
|
||||||
},
|
},
|
||||||
onUpDown: diff => {
|
onUpDown: diff => {
|
||||||
onSelect(
|
onSelect(generateConfig.addMonth(value || viewDate, diff * MONTH_COL_COUNT), 'key');
|
||||||
generateConfig.addMonth(value || viewDate, diff * MONTH_COL_COUNT),
|
|
||||||
'key',
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
onEnter: () => {
|
onEnter: () => {
|
||||||
onPanelChange('date', value || viewDate);
|
onPanelChange('date', value || viewDate);
|
||||||
|
|
@ -79,8 +77,7 @@ function MonthPanel<DateType>(props: MonthPanelProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MonthPanel.displayName = 'MonthPanel';
|
||||||
MonthPanel.displayName ='MonthPanel'
|
|
||||||
MonthPanel.inheritAttrs = false;
|
MonthPanel.inheritAttrs = false;
|
||||||
|
|
||||||
export default MonthPanel;
|
export default MonthPanel;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import { useInjectPanel } from '../PanelContext';
|
import { useInjectPanel } from '../PanelContext';
|
||||||
import type { GenerateConfig } from '../generate';
|
import type { GenerateConfig } from '../generate';
|
||||||
import { getLastDay } from '../utils/timeUtil';
|
import { getLastDay } from '../utils/timeUtil';
|
||||||
|
|
@ -6,6 +5,7 @@ import type { PanelMode } from '../interface';
|
||||||
import { getCellDateDisabled } from '../utils/dateUtil';
|
import { getCellDateDisabled } from '../utils/dateUtil';
|
||||||
import { VueNode } from '../../_util/type';
|
import { VueNode } from '../../_util/type';
|
||||||
import classNames from '../../_util/classNames';
|
import classNames from '../../_util/classNames';
|
||||||
|
import useMergeProps from '../hooks/useMergeProps';
|
||||||
|
|
||||||
export type PanelBodyProps<DateType> = {
|
export type PanelBodyProps<DateType> = {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
|
@ -30,7 +30,8 @@ export type PanelBodyProps<DateType> = {
|
||||||
rowClassName?: (date: DateType) => string;
|
rowClassName?: (date: DateType) => string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function PanelBody<DateType>({
|
function PanelBody<DateType>(_props: PanelBodyProps<DateType>) {
|
||||||
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
disabledDate,
|
disabledDate,
|
||||||
onSelect,
|
onSelect,
|
||||||
|
|
@ -47,8 +48,8 @@ function PanelBody<DateType>({
|
||||||
generateConfig,
|
generateConfig,
|
||||||
titleCell,
|
titleCell,
|
||||||
headerCells,
|
headerCells,
|
||||||
}: PanelBodyProps<DateType>) {
|
} = useMergeProps(_props);
|
||||||
const { onDateMouseEnter, onDateMouseLeave, mode } = useInjectPanel()
|
const { onDateMouseEnter, onDateMouseLeave, mode } = useInjectPanel();
|
||||||
|
|
||||||
const cellPrefixCls = `${prefixCls}-cell`;
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
||||||
|
|
@ -64,7 +65,7 @@ function PanelBody<DateType>({
|
||||||
const currentDate = getCellDate(baseDate, offset);
|
const currentDate = getCellDate(baseDate, offset);
|
||||||
const disabled = getCellDateDisabled({
|
const disabled = getCellDateDisabled({
|
||||||
cellDate: currentDate,
|
cellDate: currentDate,
|
||||||
mode,
|
mode: mode.value,
|
||||||
disabledDate,
|
disabledDate,
|
||||||
generateConfig,
|
generateConfig,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import type { Locale } from '../../interface';
|
import type { Locale } from '../../interface';
|
||||||
import { formatValue, isSameQuarter } from '../../utils/dateUtil';
|
import { formatValue, isSameQuarter } from '../../utils/dateUtil';
|
||||||
import RangeContext, { useInjectRange } from '../../RangeContext';
|
import RangeContext, { useInjectRange } from '../../RangeContext';
|
||||||
import useCellClassName from '../../hooks/useCellClassName';
|
import useCellClassName from '../../hooks/useCellClassName';
|
||||||
import PanelBody from '../PanelBody';
|
import PanelBody from '../PanelBody';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export const QUARTER_COL_COUNT = 4;
|
export const QUARTER_COL_COUNT = 4;
|
||||||
const QUARTER_ROW_COUNT = 1;
|
const QUARTER_ROW_COUNT = 1;
|
||||||
|
|
@ -19,10 +19,11 @@ export type QuarterBodyProps<DateType> = {
|
||||||
onSelect: (value: DateType) => void;
|
onSelect: (value: DateType) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function QuarterBody<DateType>(props: QuarterBodyProps<DateType>) {
|
function QuarterBody<DateType>(_props: QuarterBodyProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const { prefixCls, locale, value, viewDate, generateConfig } = props;
|
const { prefixCls, locale, value, viewDate, generateConfig } = props;
|
||||||
|
|
||||||
const { rangedValue, hoverRangedValue } = useInjectRange()
|
const { rangedValue, hoverRangedValue } = useInjectRange();
|
||||||
|
|
||||||
const cellPrefixCls = `${prefixCls}-cell`;
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
||||||
|
|
@ -30,8 +31,8 @@ function QuarterBody<DateType>(props: QuarterBodyProps<DateType>) {
|
||||||
cellPrefixCls,
|
cellPrefixCls,
|
||||||
value,
|
value,
|
||||||
generateConfig,
|
generateConfig,
|
||||||
rangedValue,
|
rangedValue: rangedValue.value,
|
||||||
hoverRangedValue,
|
hoverRangedValue: hoverRangedValue.value,
|
||||||
isSameCell: (current, target) => isSameQuarter(generateConfig, current, target),
|
isSameCell: (current, target) => isSameQuarter(generateConfig, current, target),
|
||||||
isInView: () => true,
|
isInView: () => true,
|
||||||
offsetCell: (date, offset) => generateConfig.addMonth(date, offset * 3),
|
offsetCell: (date, offset) => generateConfig.addMonth(date, offset * 3),
|
||||||
|
|
@ -65,7 +66,6 @@ function QuarterBody<DateType>(props: QuarterBodyProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QuarterBody.displayName = 'QuarterBody';
|
||||||
QuarterBody.displayName ='QuarterBody'
|
|
||||||
QuarterBody.inheritAttrs = false;
|
QuarterBody.inheritAttrs = false;
|
||||||
export default QuarterBody;
|
export default QuarterBody;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
import Header from '../Header';
|
import Header from '../Header';
|
||||||
import type { Locale } from '../../interface';
|
import type { Locale } from '../../interface';
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import { useInjectPanel } from '../../PanelContext';
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
import { formatValue } from '../../utils/dateUtil';
|
import { formatValue } from '../../utils/dateUtil';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type QuarterHeaderProps<DateType> = {
|
export type QuarterHeaderProps<DateType> = {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
|
@ -16,18 +16,12 @@ export type QuarterHeaderProps<DateType> = {
|
||||||
onYearClick: () => void;
|
onYearClick: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function QuarterHeader<DateType>(props: QuarterHeaderProps<DateType>) {
|
function QuarterHeader<DateType>(_props: QuarterHeaderProps<DateType>) {
|
||||||
const {
|
const props = useMergeProps(_props);
|
||||||
prefixCls,
|
const { prefixCls, generateConfig, locale, viewDate, onNextYear, onPrevYear, onYearClick } =
|
||||||
generateConfig,
|
props;
|
||||||
locale,
|
const { hideHeader } = useInjectPanel();
|
||||||
viewDate,
|
if (hideHeader.value) {
|
||||||
onNextYear,
|
|
||||||
onPrevYear,
|
|
||||||
onYearClick,
|
|
||||||
} = props;
|
|
||||||
const { hideHeader } =useInjectPanel()
|
|
||||||
if (hideHeader) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,8 +44,7 @@ function QuarterHeader<DateType>(props: QuarterHeaderProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QuarterHeader.displayName = 'QuarterHeader';
|
||||||
QuarterHeader.displayName ='QuarterHeader'
|
|
||||||
QuarterHeader.inheritAttrs = false;
|
QuarterHeader.inheritAttrs = false;
|
||||||
|
|
||||||
export default QuarterHeader;
|
export default QuarterHeader;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
|
|
||||||
import QuarterHeader from './QuarterHeader';
|
import QuarterHeader from './QuarterHeader';
|
||||||
import QuarterBody from './QuarterBody';
|
import QuarterBody from './QuarterBody';
|
||||||
import type { PanelSharedProps } from '../../interface';
|
import type { PanelSharedProps } from '../../interface';
|
||||||
import { createKeyDownHandler } from '../../utils/uiUtil';
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type QuarterPanelProps<DateType> = {} & PanelSharedProps<DateType>;
|
export type QuarterPanelProps<DateType> = {} & PanelSharedProps<DateType>;
|
||||||
|
|
||||||
function QuarterPanel<DateType>(props: QuarterPanelProps<DateType>) {
|
function QuarterPanel<DateType>(_props: QuarterPanelProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
operationRef,
|
operationRef,
|
||||||
|
|
@ -21,8 +22,8 @@ function QuarterPanel<DateType>(props: QuarterPanelProps<DateType>) {
|
||||||
const panelPrefixCls = `${prefixCls}-quarter-panel`;
|
const panelPrefixCls = `${prefixCls}-quarter-panel`;
|
||||||
|
|
||||||
// ======================= Keyboard =======================
|
// ======================= Keyboard =======================
|
||||||
operationRef.current = {
|
operationRef.value = {
|
||||||
onKeyDown: event =>
|
onKeyDown: (event: KeyboardEvent) =>
|
||||||
createKeyDownHandler(event, {
|
createKeyDownHandler(event, {
|
||||||
onLeftRight: diff => {
|
onLeftRight: diff => {
|
||||||
onSelect(generateConfig.addMonth(value || viewDate, diff * 3), 'key');
|
onSelect(generateConfig.addMonth(value || viewDate, diff * 3), 'key');
|
||||||
|
|
@ -69,8 +70,7 @@ function QuarterPanel<DateType>(props: QuarterPanelProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QuarterPanel.displayName = 'QuarterPanel';
|
||||||
QuarterPanel.displayName ='QuarterPanel'
|
|
||||||
QuarterPanel.inheritAttrs = false;
|
QuarterPanel.inheritAttrs = false;
|
||||||
|
|
||||||
export default QuarterPanel;
|
export default QuarterPanel;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import type { Locale, OnSelect } from '../../interface';
|
import type { Locale, OnSelect } from '../../interface';
|
||||||
import type { Unit } from './TimeUnitColumn';
|
import type { Unit } from './TimeUnitColumn';
|
||||||
|
|
@ -8,17 +7,8 @@ import type { SharedTimeProps } from '.';
|
||||||
import { setTime as utilSetTime } from '../../utils/timeUtil';
|
import { setTime as utilSetTime } from '../../utils/timeUtil';
|
||||||
import { cloneElement } from '../../../_util/vnode';
|
import { cloneElement } from '../../../_util/vnode';
|
||||||
import { VueNode } from '../../../_util/type';
|
import { VueNode } from '../../../_util/type';
|
||||||
import { ref, Ref } from '@vue/reactivity';
|
import type { Ref } from 'vue';
|
||||||
import { computed, defineComponent, watchEffect } from '@vue/runtime-core';
|
import { computed, defineComponent } from 'vue';
|
||||||
|
|
||||||
function shouldUnitsUpdate(prevUnits: Unit[], nextUnits: Unit[]) {
|
|
||||||
if (prevUnits.length !== nextUnits.length) return true;
|
|
||||||
// if any unit's disabled status is different, the units should be re-evaluted
|
|
||||||
for (let i = 0; i < prevUnits.length; i += 1) {
|
|
||||||
if (prevUnits[i].disabled !== nextUnits[i].disabled) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateUnits(
|
function generateUnits(
|
||||||
start: number,
|
start: number,
|
||||||
|
|
@ -51,7 +41,6 @@ export type TimeBodyProps<DateType> = {
|
||||||
operationRef: Ref<BodyOperationRef | undefined>;
|
operationRef: Ref<BodyOperationRef | undefined>;
|
||||||
} & SharedTimeProps<DateType>;
|
} & SharedTimeProps<DateType>;
|
||||||
|
|
||||||
|
|
||||||
const TimeBody = defineComponent({
|
const TimeBody = defineComponent({
|
||||||
name: 'TimeBody',
|
name: 'TimeBody',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
|
|
@ -75,26 +64,26 @@ const TimeBody = defineComponent({
|
||||||
'onSelect',
|
'onSelect',
|
||||||
],
|
],
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const originHour = computed(() => props.value ? props.generateConfig.getHour(props.value) : -1);
|
const originHour = computed(() =>
|
||||||
const isPM = computed(()=> {
|
props.value ? props.generateConfig.getHour(props.value) : -1,
|
||||||
|
);
|
||||||
|
const isPM = computed(() => {
|
||||||
if (props.use12Hours) {
|
if (props.use12Hours) {
|
||||||
return originHour.value >= 12; // -1 means should display AM
|
return originHour.value >= 12; // -1 means should display AM
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false;
|
||||||
}
|
|
||||||
})
|
|
||||||
let hour = computed(()=> {
|
|
||||||
// Should additional logic to handle 12 hours
|
|
||||||
if (props.use12Hours) {
|
|
||||||
return originHour.value % 12
|
|
||||||
} else {
|
|
||||||
return originHour.value
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const minute = computed(()=> props.value ? props.generateConfig.getMinute(props.value) : -1);
|
let hour = computed(() => {
|
||||||
const second = computed(()=> props.value ? props.generateConfig.getSecond(props.value) : -1);
|
// Should additional logic to handle 12 hours
|
||||||
|
if (props.use12Hours) {
|
||||||
|
return originHour.value % 12;
|
||||||
|
} else {
|
||||||
|
return originHour.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const minute = computed(() => (props.value ? props.generateConfig.getMinute(props.value) : -1));
|
||||||
|
const second = computed(() => (props.value ? props.generateConfig.getSecond(props.value) : -1));
|
||||||
|
|
||||||
const setTime = (
|
const setTime = (
|
||||||
isNewPM: boolean | undefined,
|
isNewPM: boolean | undefined,
|
||||||
|
|
@ -120,7 +109,9 @@ const TimeBody = defineComponent({
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========================= Unit =========================
|
// ========================= Unit =========================
|
||||||
const rawHours = computed(()=> generateUnits(0, 23, props.hourStep ?? 1, props.disabledHours && props.disabledHours()));
|
const rawHours = computed(() =>
|
||||||
|
generateUnits(0, 23, props.hourStep ?? 1, props.disabledHours && props.disabledHours()),
|
||||||
|
);
|
||||||
|
|
||||||
// const memorizedRawHours = useMemo(() => rawHours, rawHours, shouldUnitsUpdate);
|
// const memorizedRawHours = useMemo(() => rawHours, rawHours, shouldUnitsUpdate);
|
||||||
|
|
||||||
|
|
@ -155,16 +146,25 @@ const TimeBody = defineComponent({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const minutes = computed(()=> generateUnits(0, 59, props.minuteStep ?? 1, props.disabledMinutes && props.disabledMinutes(originHour.value)));
|
const minutes = computed(() =>
|
||||||
|
generateUnits(
|
||||||
|
0,
|
||||||
|
59,
|
||||||
|
props.minuteStep ?? 1,
|
||||||
|
props.disabledMinutes && props.disabledMinutes(originHour.value),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
const seconds = computed(()=> generateUnits(
|
const seconds = computed(() =>
|
||||||
|
generateUnits(
|
||||||
0,
|
0,
|
||||||
59,
|
59,
|
||||||
props.secondStep ?? 1,
|
props.secondStep ?? 1,
|
||||||
props.disabledSeconds && props.disabledSeconds(originHour.value, minute),
|
props.disabledSeconds && props.disabledSeconds(originHour.value, minute),
|
||||||
));
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return ()=> {
|
return () => {
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
operationRef,
|
operationRef,
|
||||||
|
|
@ -188,7 +188,7 @@ const TimeBody = defineComponent({
|
||||||
|
|
||||||
// ====================== Operations ======================
|
// ====================== Operations ======================
|
||||||
operationRef.value = {
|
operationRef.value = {
|
||||||
onUpDown: diff => {
|
onUpDown: (diff: number) => {
|
||||||
const column = columns[activeColumnIndex];
|
const column = columns[activeColumnIndex];
|
||||||
if (column) {
|
if (column) {
|
||||||
const valueIndex = column.units.findIndex(unit => unit.value === column.value);
|
const valueIndex = column.units.findIndex(unit => unit.value === column.value);
|
||||||
|
|
@ -237,14 +237,26 @@ const TimeBody = defineComponent({
|
||||||
});
|
});
|
||||||
|
|
||||||
// Minute
|
// Minute
|
||||||
addColumnNode(showMinute, <TimeUnitColumn key="minute" />, minute.value, minutes.value, num => {
|
addColumnNode(
|
||||||
|
showMinute,
|
||||||
|
<TimeUnitColumn key="minute" />,
|
||||||
|
minute.value,
|
||||||
|
minutes.value,
|
||||||
|
num => {
|
||||||
onSelect(setTime(isPM.value, hour.value, num, second.value), 'mouse');
|
onSelect(setTime(isPM.value, hour.value, num, second.value), 'mouse');
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Second
|
// Second
|
||||||
addColumnNode(showSecond, <TimeUnitColumn key="second" />, second.value, seconds.value, num => {
|
addColumnNode(
|
||||||
|
showSecond,
|
||||||
|
<TimeUnitColumn key="second" />,
|
||||||
|
second.value,
|
||||||
|
seconds.value,
|
||||||
|
num => {
|
||||||
onSelect(setTime(isPM.value, hour.value, minute.value, num), 'mouse');
|
onSelect(setTime(isPM.value, hour.value, minute.value, num), 'mouse');
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// 12 Hours
|
// 12 Hours
|
||||||
let PMIndex = -1;
|
let PMIndex = -1;
|
||||||
|
|
@ -266,9 +278,8 @@ const TimeBody = defineComponent({
|
||||||
);
|
);
|
||||||
|
|
||||||
return <div class={contentPrefixCls}>{columns.map(({ node }) => node)}</div>;
|
return <div class={contentPrefixCls}>{columns.map(({ node }) => node)}</div>;
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
export default TimeBody;
|
export default TimeBody;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
import Header from '../Header';
|
import Header from '../Header';
|
||||||
import type { Locale } from '../../interface';
|
import type { Locale } from '../../interface';
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import { useInjectPanel } from '../../PanelContext';
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
import { formatValue } from '../../utils/dateUtil';
|
import { formatValue } from '../../utils/dateUtil';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type TimeHeaderProps<DateType> = {
|
export type TimeHeaderProps<DateType> = {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
|
@ -13,9 +13,10 @@ export type TimeHeaderProps<DateType> = {
|
||||||
format: string;
|
format: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function TimeHeader<DateType>(props: TimeHeaderProps<DateType>) {
|
function TimeHeader<DateType>(_props: TimeHeaderProps<DateType>) {
|
||||||
const { hideHeader } = useInjectPanel()
|
const props = useMergeProps(_props);
|
||||||
if (hideHeader) {
|
const { hideHeader } = useInjectPanel();
|
||||||
|
if (hideHeader.value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,8 +36,7 @@ function TimeHeader<DateType>(props: TimeHeaderProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimeHeader.displayName = 'TimeHeader';
|
||||||
TimeHeader.displayName ='TimeHeader'
|
|
||||||
TimeHeader.inheritAttrs = false;
|
TimeHeader.inheritAttrs = false;
|
||||||
|
|
||||||
export default TimeHeader;
|
export default TimeHeader;
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ function TimeUnitColumn(props: TimeUnitColumnProps) {
|
||||||
() => props.value,
|
() => props.value,
|
||||||
() => {
|
() => {
|
||||||
const li = liRefs.value.get(value!);
|
const li = liRefs.value.get(value!);
|
||||||
if (li && open !== false) {
|
if (li && open.value !== false) {
|
||||||
scrollTo(ulRef.value!, li.offsetTop, 120);
|
scrollTo(ulRef.value!, li.offsetTop, 120);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -43,7 +43,7 @@ function TimeUnitColumn(props: TimeUnitColumnProps) {
|
||||||
|
|
||||||
watch(open, () => {
|
watch(open, () => {
|
||||||
scrollRef.value?.();
|
scrollRef.value?.();
|
||||||
if (open) {
|
if (open.value) {
|
||||||
const li = liRefs.value.get(value!);
|
const li = liRefs.value.get(value!);
|
||||||
if (li) {
|
if (li) {
|
||||||
scrollRef.value = waitElementReady(li, () => {
|
scrollRef.value = waitElementReady(li, () => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import TimeHeader from './TimeHeader';
|
import TimeHeader from './TimeHeader';
|
||||||
import type { BodyOperationRef } from './TimeBody';
|
import type { BodyOperationRef } from './TimeBody';
|
||||||
import TimeBody from './TimeBody';
|
import TimeBody from './TimeBody';
|
||||||
|
|
@ -6,6 +5,7 @@ import type { PanelSharedProps, DisabledTimes } from '../../interface';
|
||||||
import { createKeyDownHandler } from '../../utils/uiUtil';
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
import classNames from '../../../_util/classNames';
|
import classNames from '../../../_util/classNames';
|
||||||
import { ref } from '@vue/reactivity';
|
import { ref } from '@vue/reactivity';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type SharedTimeProps<DateType> = {
|
export type SharedTimeProps<DateType> = {
|
||||||
format?: string;
|
format?: string;
|
||||||
|
|
@ -24,12 +24,14 @@ export type SharedTimeProps<DateType> = {
|
||||||
export type TimePanelProps<DateType> = {
|
export type TimePanelProps<DateType> = {
|
||||||
format?: string;
|
format?: string;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
} & PanelSharedProps<DateType> & SharedTimeProps<DateType>;
|
} & PanelSharedProps<DateType> &
|
||||||
|
SharedTimeProps<DateType>;
|
||||||
|
|
||||||
const countBoolean = (boolList: (boolean | undefined)[]) =>
|
const countBoolean = (boolList: (boolean | undefined)[]) =>
|
||||||
boolList.filter(bool => bool !== false).length;
|
boolList.filter(bool => bool !== false).length;
|
||||||
|
|
||||||
function TimePanel<DateType>(props: TimePanelProps<DateType>) {
|
function TimePanel<DateType>(_props: TimePanelProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const {
|
const {
|
||||||
generateConfig,
|
generateConfig,
|
||||||
format = 'HH:mm:ss',
|
format = 'HH:mm:ss',
|
||||||
|
|
@ -50,27 +52,27 @@ function TimePanel<DateType>(props: TimePanelProps<DateType>) {
|
||||||
const activeColumnIndex = ref(-1);
|
const activeColumnIndex = ref(-1);
|
||||||
const columnsCount = countBoolean([showHour, showMinute, showSecond, use12Hours]);
|
const columnsCount = countBoolean([showHour, showMinute, showSecond, use12Hours]);
|
||||||
|
|
||||||
operationRef.current = {
|
operationRef.value = {
|
||||||
onKeyDown: event =>
|
onKeyDown: (event: KeyboardEvent) =>
|
||||||
createKeyDownHandler(event, {
|
createKeyDownHandler(event, {
|
||||||
onLeftRight: diff => {
|
onLeftRight: diff => {
|
||||||
activeColumnIndex.value = (activeColumnIndex.value + diff + columnsCount) % columnsCount;
|
activeColumnIndex.value = (activeColumnIndex.value + diff + columnsCount) % columnsCount;
|
||||||
},
|
},
|
||||||
onUpDown: diff => {
|
onUpDown: diff => {
|
||||||
if (activeColumnIndex.value === -1) {
|
if (activeColumnIndex.value === -1) {
|
||||||
activeColumnIndex.value = 0
|
activeColumnIndex.value = 0;
|
||||||
} else if (bodyOperationRef.value) {
|
} else if (bodyOperationRef.value) {
|
||||||
bodyOperationRef.value.onUpDown(diff);
|
bodyOperationRef.value.onUpDown(diff);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onEnter: () => {
|
onEnter: () => {
|
||||||
onSelect(value || generateConfig.getNow(), 'key');
|
onSelect(value || generateConfig.getNow(), 'key');
|
||||||
activeColumnIndex.value = -1
|
activeColumnIndex.value = -1;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
onBlur: () => {
|
onBlur: () => {
|
||||||
activeColumnIndex.value = -1
|
activeColumnIndex.value = -1;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -91,8 +93,7 @@ function TimePanel<DateType>(props: TimePanelProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimePanel.displayName = 'TimePanel';
|
||||||
TimePanel.displayName ='TimePanel'
|
|
||||||
TimePanel.inheritAttrs = false;
|
TimePanel.inheritAttrs = false;
|
||||||
|
|
||||||
export default TimePanel;
|
export default TimePanel;
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,19 @@
|
||||||
|
|
||||||
import DatePanel from '../DatePanel';
|
import DatePanel from '../DatePanel';
|
||||||
import type { PanelSharedProps } from '../../interface';
|
import type { PanelSharedProps } from '../../interface';
|
||||||
import { isSameWeek } from '../../utils/dateUtil';
|
import { isSameWeek } from '../../utils/dateUtil';
|
||||||
import classNames from '../../../_util/classNames';
|
import classNames from '../../../_util/classNames';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type WeekPanelProps<DateType> = PanelSharedProps<DateType>;
|
export type WeekPanelProps<DateType> = PanelSharedProps<DateType>;
|
||||||
|
|
||||||
function WeekPanel<DateType>(props: WeekPanelProps<DateType>) {
|
function WeekPanel<DateType>(_props: WeekPanelProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const { prefixCls, generateConfig, locale, value } = props;
|
const { prefixCls, generateConfig, locale, value } = props;
|
||||||
|
|
||||||
// Render additional column
|
// Render additional column
|
||||||
const cellPrefixCls = `${prefixCls}-cell`;
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
const prefixColumn = (date: DateType) => (
|
const prefixColumn = (date: DateType) => (
|
||||||
<td
|
<td key="week" class={classNames(cellPrefixCls, `${cellPrefixCls}-week`)}>
|
||||||
key="week"
|
|
||||||
class={classNames(cellPrefixCls, `${cellPrefixCls}-week`)}
|
|
||||||
>
|
|
||||||
{generateConfig.locale.getWeek(locale.locale, date)}
|
{generateConfig.locale.getWeek(locale.locale, date)}
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
|
|
@ -24,12 +22,7 @@ function WeekPanel<DateType>(props: WeekPanelProps<DateType>) {
|
||||||
const rowPrefixCls = `${prefixCls}-week-panel-row`;
|
const rowPrefixCls = `${prefixCls}-week-panel-row`;
|
||||||
const rowClassName = (date: DateType) =>
|
const rowClassName = (date: DateType) =>
|
||||||
classNames(rowPrefixCls, {
|
classNames(rowPrefixCls, {
|
||||||
[`${rowPrefixCls}-selected`]: isSameWeek(
|
[`${rowPrefixCls}-selected`]: isSameWeek(generateConfig, locale.locale, value, date),
|
||||||
generateConfig,
|
|
||||||
locale.locale,
|
|
||||||
value,
|
|
||||||
date,
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -45,7 +38,6 @@ function WeekPanel<DateType>(props: WeekPanelProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WeekPanel.displayName = 'WeekPanel';
|
WeekPanel.displayName = 'WeekPanel';
|
||||||
WeekPanel.inheritAttrs = false;
|
WeekPanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import { YEAR_DECADE_COUNT } from '.';
|
import { YEAR_DECADE_COUNT } from '.';
|
||||||
import type { Locale, NullableDateType } from '../../interface';
|
import type { Locale, NullableDateType } from '../../interface';
|
||||||
import useCellClassName from '../../hooks/useCellClassName';
|
import useCellClassName from '../../hooks/useCellClassName';
|
||||||
import { formatValue, isSameYear } from '../../utils/dateUtil';
|
import { formatValue, isSameYear } from '../../utils/dateUtil';
|
||||||
import RangeContext, { useInjectRange } from '../../RangeContext';
|
import { useInjectRange } from '../../RangeContext';
|
||||||
import PanelBody from '../PanelBody';
|
import PanelBody from '../PanelBody';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export const YEAR_COL_COUNT = 3;
|
export const YEAR_COL_COUNT = 3;
|
||||||
const YEAR_ROW_COUNT = 4;
|
const YEAR_ROW_COUNT = 4;
|
||||||
|
|
@ -20,9 +20,10 @@ export type YearBodyProps<DateType> = {
|
||||||
onSelect: (value: DateType) => void;
|
onSelect: (value: DateType) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function YearBody<DateType>(props: YearBodyProps<DateType>) {
|
function YearBody<DateType>(_props: YearBodyProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const { prefixCls, value, viewDate, locale, generateConfig } = props;
|
const { prefixCls, value, viewDate, locale, generateConfig } = props;
|
||||||
const { rangedValue, hoverRangedValue } = useInjectRange()
|
const { rangedValue, hoverRangedValue } = useInjectRange();
|
||||||
|
|
||||||
const yearPrefixCls = `${prefixCls}-cell`;
|
const yearPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
||||||
|
|
@ -44,8 +45,8 @@ function YearBody<DateType>(props: YearBodyProps<DateType>) {
|
||||||
cellPrefixCls: yearPrefixCls,
|
cellPrefixCls: yearPrefixCls,
|
||||||
value,
|
value,
|
||||||
generateConfig,
|
generateConfig,
|
||||||
rangedValue,
|
rangedValue: rangedValue.value,
|
||||||
hoverRangedValue,
|
hoverRangedValue: hoverRangedValue.value,
|
||||||
isSameCell: (current, target) => isSameYear(generateConfig, current, target),
|
isSameCell: (current, target) => isSameYear(generateConfig, current, target),
|
||||||
isInView,
|
isInView,
|
||||||
offsetCell: (date, offset) => generateConfig.addYear(date, offset),
|
offsetCell: (date, offset) => generateConfig.addYear(date, offset),
|
||||||
|
|
@ -71,8 +72,6 @@ function YearBody<DateType>(props: YearBodyProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
YearBody.displayName = 'YearBody';
|
YearBody.displayName = 'YearBody';
|
||||||
YearBody.inheritAttrs = false;
|
YearBody.inheritAttrs = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
import Header from '../Header';
|
import Header from '../Header';
|
||||||
import type { GenerateConfig } from '../../generate';
|
import type { GenerateConfig } from '../../generate';
|
||||||
import { YEAR_DECADE_COUNT } from '.';
|
import { YEAR_DECADE_COUNT } from '.';
|
||||||
import { useInjectPanel } from '../../PanelContext';
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type YearHeaderProps<DateType> = {
|
export type YearHeaderProps<DateType> = {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
|
@ -15,10 +15,11 @@ export type YearHeaderProps<DateType> = {
|
||||||
onDecadeClick: () => void;
|
onDecadeClick: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function YearHeader<DateType>(props: YearHeaderProps<DateType>) {
|
function YearHeader<DateType>(_props: YearHeaderProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const { prefixCls, generateConfig, viewDate, onPrevDecade, onNextDecade, onDecadeClick } = props;
|
const { prefixCls, generateConfig, viewDate, onPrevDecade, onNextDecade, onDecadeClick } = props;
|
||||||
const { hideHeader } = useInjectPanel()
|
const { hideHeader } = useInjectPanel();
|
||||||
if (hideHeader) {
|
if (hideHeader.value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,8 +43,6 @@ function YearHeader<DateType>(props: YearHeaderProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
YearHeader.displayName = 'YearHeader';
|
YearHeader.displayName = 'YearHeader';
|
||||||
YearHeader.inheritAttrs = false;
|
YearHeader.inheritAttrs = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
import YearHeader from './YearHeader';
|
import YearHeader from './YearHeader';
|
||||||
import YearBody, { YEAR_COL_COUNT } from './YearBody';
|
import YearBody, { YEAR_COL_COUNT } from './YearBody';
|
||||||
import type { PanelSharedProps, PanelMode } from '../../interface';
|
import type { PanelSharedProps, PanelMode } from '../../interface';
|
||||||
import { createKeyDownHandler } from '../../utils/uiUtil';
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
import useMergeProps from '../../hooks/useMergeProps';
|
||||||
|
|
||||||
export type YearPanelProps<DateType> = {
|
export type YearPanelProps<DateType> = {
|
||||||
sourceMode: PanelMode;
|
sourceMode: PanelMode;
|
||||||
|
|
@ -10,7 +10,8 @@ export type YearPanelProps<DateType> = {
|
||||||
|
|
||||||
export const YEAR_DECADE_COUNT = 10;
|
export const YEAR_DECADE_COUNT = 10;
|
||||||
|
|
||||||
function YearPanel<DateType>(props: YearPanelProps<DateType>) {
|
function YearPanel<DateType>(_props: YearPanelProps<DateType>) {
|
||||||
|
const props = useMergeProps(_props);
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
operationRef,
|
operationRef,
|
||||||
|
|
@ -26,29 +27,20 @@ function YearPanel<DateType>(props: YearPanelProps<DateType>) {
|
||||||
const panelPrefixCls = `${prefixCls}-year-panel`;
|
const panelPrefixCls = `${prefixCls}-year-panel`;
|
||||||
|
|
||||||
// ======================= Keyboard =======================
|
// ======================= Keyboard =======================
|
||||||
operationRef.current = {
|
operationRef.value = {
|
||||||
onKeyDown: event =>
|
onKeyDown: (event: KeyboardEvent) =>
|
||||||
createKeyDownHandler(event, {
|
createKeyDownHandler(event, {
|
||||||
onLeftRight: diff => {
|
onLeftRight: diff => {
|
||||||
onSelect(generateConfig.addYear(value || viewDate, diff), 'key');
|
onSelect(generateConfig.addYear(value || viewDate, diff), 'key');
|
||||||
},
|
},
|
||||||
onCtrlLeftRight: diff => {
|
onCtrlLeftRight: diff => {
|
||||||
onSelect(
|
onSelect(generateConfig.addYear(value || viewDate, diff * YEAR_DECADE_COUNT), 'key');
|
||||||
generateConfig.addYear(value || viewDate, diff * YEAR_DECADE_COUNT),
|
|
||||||
'key',
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
onUpDown: diff => {
|
onUpDown: diff => {
|
||||||
onSelect(
|
onSelect(generateConfig.addYear(value || viewDate, diff * YEAR_COL_COUNT), 'key');
|
||||||
generateConfig.addYear(value || viewDate, diff * YEAR_COL_COUNT),
|
|
||||||
'key',
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
onEnter: () => {
|
onEnter: () => {
|
||||||
onPanelChange(
|
onPanelChange(sourceMode === 'date' ? 'date' : 'month', value || viewDate);
|
||||||
sourceMode === 'date' ? 'date' : 'month',
|
|
||||||
value || viewDate,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
@ -87,8 +79,6 @@ function YearPanel<DateType>(props: YearPanelProps<DateType>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
YearPanel.displayName = 'YearPanel';
|
YearPanel.displayName = 'YearPanel';
|
||||||
YearPanel.inheritAttrs = false;
|
YearPanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import type { PanelMode } from '../interface';
|
import type { PanelMode } from '../interface';
|
||||||
|
|
||||||
export default function getExtraFooter(
|
export default function getExtraFooter(
|
||||||
|
|
@ -10,7 +9,5 @@ export default function getExtraFooter(
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <div class={`${prefixCls}-footer-extra`}>{renderExtraFooter(mode)}</div>;
|
||||||
<div class={`${prefixCls}-footer-extra`}>{renderExtraFooter(mode)}</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import { VueNode } from '../../_util/type';
|
import { VueNode } from '../../_util/type';
|
||||||
import type { Components, RangeList, Locale } from '../interface';
|
import type { Components, RangeList, Locale } from '../interface';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ export function updateValues<T, R = [T | null, T | null] | null>(
|
||||||
typeof value === 'function' ? (value as UpdateValue<T | null>)(newValues[index]) : value;
|
typeof value === 'function' ? (value as UpdateValue<T | null>)(newValues[index]) : value;
|
||||||
|
|
||||||
if (!newValues[0] && !newValues[1]) {
|
if (!newValues[0] && !newValues[1]) {
|
||||||
return (null as unknown) as R;
|
return null as unknown as R;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (newValues as unknown) as R;
|
return newValues as unknown as R;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,22 +24,12 @@ export function setDateTime<DateType>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let newDate = date;
|
let newDate = date;
|
||||||
newDate = generateConfig.setHour(
|
newDate = generateConfig.setHour(newDate, generateConfig.getHour(defaultDate));
|
||||||
newDate,
|
newDate = generateConfig.setMinute(newDate, generateConfig.getMinute(defaultDate));
|
||||||
generateConfig.getHour(defaultDate),
|
newDate = generateConfig.setSecond(newDate, generateConfig.getSecond(defaultDate));
|
||||||
);
|
|
||||||
newDate = generateConfig.setMinute(
|
|
||||||
newDate,
|
|
||||||
generateConfig.getMinute(defaultDate),
|
|
||||||
);
|
|
||||||
newDate = generateConfig.setSecond(
|
|
||||||
newDate,
|
|
||||||
generateConfig.getSecond(defaultDate),
|
|
||||||
);
|
|
||||||
return newDate;
|
return newDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getLowerBoundTime(
|
export function getLowerBoundTime(
|
||||||
hour: number,
|
hour: number,
|
||||||
minute: number,
|
minute: number,
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ export function addGlobalMouseDownEvent(callback: ClickEventHandler) {
|
||||||
if (!globalClickFunc && typeof window !== 'undefined' && window.addEventListener) {
|
if (!globalClickFunc && typeof window !== 'undefined' && window.addEventListener) {
|
||||||
globalClickFunc = (e: MouseEvent) => {
|
globalClickFunc = (e: MouseEvent) => {
|
||||||
// Clone a new list to avoid repeat trigger events
|
// Clone a new list to avoid repeat trigger events
|
||||||
[...clickCallbacks].forEach((queueFunc) => {
|
[...clickCallbacks].forEach(queueFunc => {
|
||||||
queueFunc(e);
|
queueFunc(e);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -272,5 +272,5 @@ export function elementsContains(
|
||||||
elements: (HTMLElement | undefined | null)[],
|
elements: (HTMLElement | undefined | null)[],
|
||||||
target: HTMLElement,
|
target: HTMLElement,
|
||||||
) {
|
) {
|
||||||
return elements.some((ele) => ele && ele.contains(target));
|
return elements.some(ele => ele && ele.contains(target));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue