refactor: date
parent
a448e57475
commit
a020c2f681
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { inject, InjectionKey, provide, Ref } from 'vue';
|
||||||
|
import type { OnSelect, PanelMode } from './interface';
|
||||||
|
|
||||||
|
export type ContextOperationRefProps = {
|
||||||
|
onKeyDown?: (e: KeyboardEvent) => boolean;
|
||||||
|
onClose?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PanelContextProps = {
|
||||||
|
operationRef?: Ref<ContextOperationRefProps | null>;
|
||||||
|
/** Only work with time panel */
|
||||||
|
hideHeader?: boolean;
|
||||||
|
panelRef?: Ref<HTMLDivElement>;
|
||||||
|
hidePrevBtn?: boolean;
|
||||||
|
hideNextBtn?: boolean;
|
||||||
|
onDateMouseEnter?: (date: any) => void;
|
||||||
|
onDateMouseLeave?: (date: any) => void;
|
||||||
|
onSelect?: OnSelect<any>;
|
||||||
|
hideRanges?: boolean;
|
||||||
|
open?: boolean;
|
||||||
|
mode?: PanelMode;
|
||||||
|
|
||||||
|
/** Only used for TimePicker and this is a deprecated prop */
|
||||||
|
defaultOpenValue?: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const PanelContextKey: InjectionKey<PanelContextProps> = Symbol('PanelContextProps');
|
||||||
|
|
||||||
|
export const useProvidePanel = (props: PanelContextProps) => {
|
||||||
|
provide(PanelContextKey, props);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useInjectPanel = () => {
|
||||||
|
return inject(PanelContextKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PanelContextKey;
|
||||||
|
|
@ -0,0 +1,561 @@
|
||||||
|
/**
|
||||||
|
* Removed:
|
||||||
|
* - getCalendarContainer: use `getPopupContainer` instead
|
||||||
|
* - onOk
|
||||||
|
*
|
||||||
|
* New Feature:
|
||||||
|
* - picker
|
||||||
|
* - allowEmpty
|
||||||
|
* - selectable
|
||||||
|
*
|
||||||
|
* 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 {
|
||||||
|
PickerPanelBaseProps,
|
||||||
|
PickerPanelDateProps,
|
||||||
|
PickerPanelTimeProps,
|
||||||
|
} from './PickerPanel';
|
||||||
|
import PickerPanel from './PickerPanel';
|
||||||
|
import PickerTrigger from './PickerTrigger';
|
||||||
|
import { formatValue, isEqual, parseValue } from './utils/dateUtil';
|
||||||
|
import getDataOrAriaProps, { toArray } from './utils/miscUtil';
|
||||||
|
import type { ContextOperationRefProps } from './PanelContext';
|
||||||
|
import PanelContext from './PanelContext';
|
||||||
|
import type { CustomFormat, PickerMode } from './interface';
|
||||||
|
import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil';
|
||||||
|
import usePickerInput from './hooks/usePickerInput';
|
||||||
|
import useTextValueMapping from './hooks/useTextValueMapping';
|
||||||
|
import useValueTexts from './hooks/useValueTexts';
|
||||||
|
import useHoverValue from './hooks/useHoverValue';
|
||||||
|
|
||||||
|
export type PickerRefConfig = {
|
||||||
|
focus: () => void;
|
||||||
|
blur: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PickerSharedProps<DateType> = {
|
||||||
|
dropdownClassName?: string;
|
||||||
|
dropdownAlign?: AlignType;
|
||||||
|
popupStyle?: React.CSSProperties;
|
||||||
|
transitionName?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
allowClear?: boolean;
|
||||||
|
autoFocus?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
tabIndex?: number;
|
||||||
|
open?: boolean;
|
||||||
|
defaultOpen?: boolean;
|
||||||
|
/** Make input readOnly to avoid popup keyboard in mobile */
|
||||||
|
inputReadOnly?: boolean;
|
||||||
|
id?: string;
|
||||||
|
|
||||||
|
// Value
|
||||||
|
format?: string | CustomFormat<DateType> | (string | CustomFormat<DateType>)[];
|
||||||
|
|
||||||
|
// Render
|
||||||
|
suffixIcon?: React.ReactNode;
|
||||||
|
clearIcon?: React.ReactNode;
|
||||||
|
prevIcon?: React.ReactNode;
|
||||||
|
nextIcon?: React.ReactNode;
|
||||||
|
superPrevIcon?: React.ReactNode;
|
||||||
|
superNextIcon?: React.ReactNode;
|
||||||
|
getPopupContainer?: (node: HTMLElement) => HTMLElement;
|
||||||
|
panelRender?: (originPanel: React.ReactNode) => React.ReactNode;
|
||||||
|
|
||||||
|
// Events
|
||||||
|
onChange?: (value: DateType | null, dateString: string) => void;
|
||||||
|
onOpenChange?: (open: boolean) => void;
|
||||||
|
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
||||||
|
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
||||||
|
onMouseDown?: React.MouseEventHandler<HTMLDivElement>;
|
||||||
|
onMouseUp?: React.MouseEventHandler<HTMLDivElement>;
|
||||||
|
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
|
||||||
|
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
|
||||||
|
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
||||||
|
onContextMenu?: React.MouseEventHandler<HTMLDivElement>;
|
||||||
|
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>, preventDefault: () => void) => void;
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
/** @private Internal usage, do not use in production mode!!! */
|
||||||
|
pickerRef?: React.MutableRefObject<PickerRefConfig>;
|
||||||
|
|
||||||
|
// WAI-ARIA
|
||||||
|
role?: string;
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
autoComplete?: string;
|
||||||
|
direction?: 'ltr' | 'rtl';
|
||||||
|
} & React.AriaAttributes;
|
||||||
|
|
||||||
|
type OmitPanelProps<Props> = Omit<
|
||||||
|
Props,
|
||||||
|
'onChange' | 'hideHeader' | 'pickerValue' | 'onPickerValueChange'
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type PickerBaseProps<DateType> = {} & PickerSharedProps<DateType> &
|
||||||
|
OmitPanelProps<PickerPanelBaseProps<DateType>>;
|
||||||
|
|
||||||
|
export type PickerDateProps<DateType> = {} & PickerSharedProps<DateType> &
|
||||||
|
OmitPanelProps<PickerPanelDateProps<DateType>>;
|
||||||
|
|
||||||
|
export type PickerTimeProps<DateType> = {
|
||||||
|
picker: 'time';
|
||||||
|
/**
|
||||||
|
* @deprecated Please use `defaultValue` directly instead
|
||||||
|
* since `defaultOpenValue` will confuse user of current value status
|
||||||
|
*/
|
||||||
|
defaultOpenValue?: DateType;
|
||||||
|
} & PickerSharedProps<DateType> &
|
||||||
|
Omit<OmitPanelProps<PickerPanelTimeProps<DateType>>, 'format'>;
|
||||||
|
|
||||||
|
export type PickerProps<DateType> =
|
||||||
|
| PickerBaseProps<DateType>
|
||||||
|
| PickerDateProps<DateType>
|
||||||
|
| PickerTimeProps<DateType>;
|
||||||
|
|
||||||
|
// TMP type to fit for ts 3.9.2
|
||||||
|
type OmitType<DateType> = Omit<PickerBaseProps<DateType>, 'picker'> &
|
||||||
|
Omit<PickerDateProps<DateType>, 'picker'> &
|
||||||
|
Omit<PickerTimeProps<DateType>, 'picker'>;
|
||||||
|
type MergedPickerProps<DateType> = {
|
||||||
|
picker?: PickerMode;
|
||||||
|
} & OmitType<DateType>;
|
||||||
|
|
||||||
|
function InnerPicker<DateType>(props: PickerProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls = 'rc-picker',
|
||||||
|
id,
|
||||||
|
tabIndex,
|
||||||
|
style,
|
||||||
|
className,
|
||||||
|
dropdownClassName,
|
||||||
|
dropdownAlign,
|
||||||
|
popupStyle,
|
||||||
|
transitionName,
|
||||||
|
generateConfig,
|
||||||
|
locale,
|
||||||
|
inputReadOnly,
|
||||||
|
allowClear,
|
||||||
|
autoFocus,
|
||||||
|
showTime,
|
||||||
|
picker = 'date',
|
||||||
|
format,
|
||||||
|
use12Hours,
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
open,
|
||||||
|
defaultOpen,
|
||||||
|
defaultOpenValue,
|
||||||
|
suffixIcon,
|
||||||
|
clearIcon,
|
||||||
|
disabled,
|
||||||
|
disabledDate,
|
||||||
|
placeholder,
|
||||||
|
getPopupContainer,
|
||||||
|
pickerRef,
|
||||||
|
panelRender,
|
||||||
|
onChange,
|
||||||
|
onOpenChange,
|
||||||
|
onFocus,
|
||||||
|
onBlur,
|
||||||
|
onMouseDown,
|
||||||
|
onMouseUp,
|
||||||
|
onMouseEnter,
|
||||||
|
onMouseLeave,
|
||||||
|
onContextMenu,
|
||||||
|
onClick,
|
||||||
|
onKeyDown,
|
||||||
|
onSelect,
|
||||||
|
direction,
|
||||||
|
autoComplete = 'off',
|
||||||
|
} = props as MergedPickerProps<DateType>;
|
||||||
|
|
||||||
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const needConfirmButton: boolean = (picker === 'date' && !!showTime) || picker === 'time';
|
||||||
|
|
||||||
|
// ============================= State =============================
|
||||||
|
const formatList = toArray(getDefaultFormat(format, picker, showTime, use12Hours));
|
||||||
|
|
||||||
|
// Panel ref
|
||||||
|
const panelDivRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
const inputDivRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// Real value
|
||||||
|
const [mergedValue, setInnerValue] = useMergedState(null, {
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Selected value
|
||||||
|
const [selectedValue, setSelectedValue] = React.useState<DateType | null>(mergedValue);
|
||||||
|
|
||||||
|
// Operation ref
|
||||||
|
const operationRef: React.MutableRefObject<ContextOperationRefProps | null> =
|
||||||
|
React.useRef<ContextOperationRefProps>(null);
|
||||||
|
|
||||||
|
// Open
|
||||||
|
const [mergedOpen, triggerInnerOpen] = useMergedState(false, {
|
||||||
|
value: open,
|
||||||
|
defaultValue: defaultOpen,
|
||||||
|
postState: (postOpen) => (disabled ? false : postOpen),
|
||||||
|
onChange: (newOpen) => {
|
||||||
|
if (onOpenChange) {
|
||||||
|
onOpenChange(newOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newOpen && operationRef.current && operationRef.current.onClose) {
|
||||||
|
operationRef.current.onClose();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================= Text ==============================
|
||||||
|
const [valueTexts, firstValueText] = useValueTexts(selectedValue, {
|
||||||
|
formatList,
|
||||||
|
generateConfig,
|
||||||
|
locale,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [text, triggerTextChange, resetText] = useTextValueMapping({
|
||||||
|
valueTexts,
|
||||||
|
onTextChange: (newText) => {
|
||||||
|
const inputDate = parseValue(newText, {
|
||||||
|
locale,
|
||||||
|
formatList,
|
||||||
|
generateConfig,
|
||||||
|
});
|
||||||
|
if (inputDate && (!disabledDate || !disabledDate(inputDate))) {
|
||||||
|
setSelectedValue(inputDate);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================ Trigger ============================
|
||||||
|
const triggerChange = (newValue: DateType | null) => {
|
||||||
|
setSelectedValue(newValue);
|
||||||
|
setInnerValue(newValue);
|
||||||
|
|
||||||
|
if (onChange && !isEqual(generateConfig, mergedValue, newValue)) {
|
||||||
|
onChange(
|
||||||
|
newValue,
|
||||||
|
newValue ? formatValue(newValue, { generateConfig, locale, format: formatList[0] }) : '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const triggerOpen = (newOpen: boolean) => {
|
||||||
|
if (disabled && newOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerInnerOpen(newOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
const forwardKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
|
||||||
|
if (mergedOpen && operationRef.current && operationRef.current.onKeyDown) {
|
||||||
|
// Let popup panel handle keyboard
|
||||||
|
return operationRef.current.onKeyDown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
/* eslint-disable no-lone-blocks */
|
||||||
|
{
|
||||||
|
warning(
|
||||||
|
false,
|
||||||
|
'Picker not correct forward KeyDown operation. Please help to fire issue about this.',
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInternalMouseUp: React.MouseEventHandler<HTMLDivElement> = (...args) => {
|
||||||
|
if (onMouseUp) {
|
||||||
|
onMouseUp(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputRef.current) {
|
||||||
|
inputRef.current.focus();
|
||||||
|
triggerOpen(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================= Input =============================
|
||||||
|
const [inputProps, { focused, typing }] = usePickerInput({
|
||||||
|
blurToCancel: needConfirmButton,
|
||||||
|
open: mergedOpen,
|
||||||
|
value: text,
|
||||||
|
triggerOpen,
|
||||||
|
forwardKeyDown,
|
||||||
|
isClickOutside: (target) =>
|
||||||
|
!elementsContains([panelDivRef.current, inputDivRef.current], target as HTMLElement),
|
||||||
|
onSubmit: () => {
|
||||||
|
if (disabledDate && disabledDate(selectedValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerChange(selectedValue);
|
||||||
|
triggerOpen(false);
|
||||||
|
resetText();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
onCancel: () => {
|
||||||
|
triggerOpen(false);
|
||||||
|
setSelectedValue(mergedValue);
|
||||||
|
resetText();
|
||||||
|
},
|
||||||
|
onKeyDown: (e, preventDefault) => {
|
||||||
|
onKeyDown?.(e, preventDefault);
|
||||||
|
},
|
||||||
|
onFocus,
|
||||||
|
onBlur,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================= Sync ==============================
|
||||||
|
// Close should sync back with text value
|
||||||
|
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}
|
||||||
|
className={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
|
||||||
|
className={`${prefixCls}-panel-container`}
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{panelNode}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
let suffixNode: React.ReactNode;
|
||||||
|
if (suffixIcon) {
|
||||||
|
suffixNode = <span className={`${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);
|
||||||
|
}}
|
||||||
|
className={`${prefixCls}-clear`}
|
||||||
|
role="button"
|
||||||
|
>
|
||||||
|
{clearIcon || <span className={`${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
|
||||||
|
className={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
|
||||||
|
className={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
|
||||||
|
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;
|
||||||
|
|
@ -0,0 +1,569 @@
|
||||||
|
/**
|
||||||
|
* Logic:
|
||||||
|
* When `mode` === `picker`,
|
||||||
|
* click will trigger `onSelect` (if value changed trigger `onChange` also).
|
||||||
|
* 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 TimePanel from './panels/TimePanel';
|
||||||
|
import DatetimePanel from './panels/DatetimePanel';
|
||||||
|
import DatePanel from './panels/DatePanel';
|
||||||
|
import WeekPanel from './panels/WeekPanel';
|
||||||
|
import MonthPanel from './panels/MonthPanel';
|
||||||
|
import QuarterPanel from './panels/QuarterPanel';
|
||||||
|
import YearPanel from './panels/YearPanel';
|
||||||
|
import DecadePanel from './panels/DecadePanel';
|
||||||
|
import type { GenerateConfig } from './generate';
|
||||||
|
import type {
|
||||||
|
Locale,
|
||||||
|
PanelMode,
|
||||||
|
PanelRefProps,
|
||||||
|
PickerMode,
|
||||||
|
DisabledTime,
|
||||||
|
OnPanelChange,
|
||||||
|
Components,
|
||||||
|
} from './interface';
|
||||||
|
import { isEqual } from './utils/dateUtil';
|
||||||
|
import PanelContext from './PanelContext';
|
||||||
|
import type { DateRender } from './panels/DatePanel/DateBody';
|
||||||
|
import { PickerModeMap } from './utils/uiUtil';
|
||||||
|
import type { MonthCellRender } from './panels/MonthPanel/MonthBody';
|
||||||
|
import RangeContext from './RangeContext';
|
||||||
|
import getExtraFooter from './utils/getExtraFooter';
|
||||||
|
import getRanges from './utils/getRanges';
|
||||||
|
import { getLowerBoundTime, setDateTime, setTime } from './utils/timeUtil';
|
||||||
|
|
||||||
|
export type PickerPanelSharedProps<DateType> = {
|
||||||
|
prefixCls?: string;
|
||||||
|
className?: string;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
/** @deprecated Will be removed in next big version. Please use `mode` instead */
|
||||||
|
mode?: PanelMode;
|
||||||
|
tabIndex?: number;
|
||||||
|
|
||||||
|
// Locale
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
|
||||||
|
// Value
|
||||||
|
value?: DateType | null;
|
||||||
|
defaultValue?: DateType;
|
||||||
|
/** [Legacy] Set default display picker view date */
|
||||||
|
pickerValue?: DateType;
|
||||||
|
/** [Legacy] Set default display picker view date */
|
||||||
|
defaultPickerValue?: DateType;
|
||||||
|
|
||||||
|
// Date
|
||||||
|
disabledDate?: (date: DateType) => boolean;
|
||||||
|
|
||||||
|
// Render
|
||||||
|
dateRender?: DateRender<DateType>;
|
||||||
|
monthCellRender?: MonthCellRender<DateType>;
|
||||||
|
renderExtraFooter?: (mode: PanelMode) => React.ReactNode;
|
||||||
|
|
||||||
|
// Event
|
||||||
|
onSelect?: (value: DateType) => void;
|
||||||
|
onChange?: (value: DateType) => void;
|
||||||
|
onPanelChange?: OnPanelChange<DateType>;
|
||||||
|
onMouseDown?: React.MouseEventHandler<HTMLDivElement>;
|
||||||
|
onOk?: (date: DateType) => void;
|
||||||
|
|
||||||
|
direction?: 'ltr' | 'rtl';
|
||||||
|
|
||||||
|
/** @private This is internal usage. Do not use in your production env */
|
||||||
|
hideHeader?: boolean;
|
||||||
|
/** @private This is internal usage. Do not use in your production env */
|
||||||
|
onPickerValueChange?: (date: DateType) => void;
|
||||||
|
|
||||||
|
/** @private Internal usage. Do not use in your production env */
|
||||||
|
components?: Components;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PickerPanelBaseProps<DateType> = {
|
||||||
|
picker: Exclude<PickerMode, 'date' | 'time'>;
|
||||||
|
} & PickerPanelSharedProps<DateType>;
|
||||||
|
|
||||||
|
export type PickerPanelDateProps<DateType> = {
|
||||||
|
picker?: 'date';
|
||||||
|
showToday?: boolean;
|
||||||
|
showNow?: boolean;
|
||||||
|
|
||||||
|
// Time
|
||||||
|
showTime?: boolean | SharedTimeProps<DateType>;
|
||||||
|
disabledTime?: DisabledTime<DateType>;
|
||||||
|
} & PickerPanelSharedProps<DateType>;
|
||||||
|
|
||||||
|
export type PickerPanelTimeProps<DateType> = {
|
||||||
|
picker: 'time';
|
||||||
|
} & PickerPanelSharedProps<DateType> & SharedTimeProps<DateType>;
|
||||||
|
|
||||||
|
export type PickerPanelProps<DateType> =
|
||||||
|
| PickerPanelBaseProps<DateType>
|
||||||
|
| PickerPanelDateProps<DateType>
|
||||||
|
| PickerPanelTimeProps<DateType>;
|
||||||
|
|
||||||
|
// TMP type to fit for ts 3.9.2
|
||||||
|
type OmitType<DateType> = Omit<PickerPanelBaseProps<DateType>, 'picker'> &
|
||||||
|
Omit<PickerPanelDateProps<DateType>, 'picker'> &
|
||||||
|
Omit<PickerPanelTimeProps<DateType>, 'picker'>;
|
||||||
|
type MergedPickerPanelProps<DateType> = {
|
||||||
|
picker?: PickerMode;
|
||||||
|
} & OmitType<DateType>;
|
||||||
|
|
||||||
|
function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls = 'rc-picker',
|
||||||
|
className,
|
||||||
|
style,
|
||||||
|
locale,
|
||||||
|
generateConfig,
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
pickerValue,
|
||||||
|
defaultPickerValue,
|
||||||
|
disabledDate,
|
||||||
|
mode,
|
||||||
|
picker = 'date',
|
||||||
|
tabIndex = 0,
|
||||||
|
showNow,
|
||||||
|
showTime,
|
||||||
|
showToday,
|
||||||
|
renderExtraFooter,
|
||||||
|
hideHeader,
|
||||||
|
onSelect,
|
||||||
|
onChange,
|
||||||
|
onPanelChange,
|
||||||
|
onMouseDown,
|
||||||
|
onPickerValueChange,
|
||||||
|
onOk,
|
||||||
|
components,
|
||||||
|
direction,
|
||||||
|
hourStep = 1,
|
||||||
|
minuteStep = 1,
|
||||||
|
secondStep = 1,
|
||||||
|
} = props as MergedPickerPanelProps<DateType>;
|
||||||
|
|
||||||
|
const needConfirmButton: boolean = (picker === 'date' && !!showTime) || picker === 'time';
|
||||||
|
|
||||||
|
const isHourStepValid = 24 % hourStep === 0;
|
||||||
|
const isMinuteStepValid = 60 % minuteStep === 0;
|
||||||
|
const isSecondStepValid = 60 % secondStep === 0;
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
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(
|
||||||
|
isMinuteStepValid,
|
||||||
|
`\`minuteStep\` ${minuteStep} is invalid. It should be a factor of 60.`,
|
||||||
|
);
|
||||||
|
warning(
|
||||||
|
isSecondStepValid,
|
||||||
|
`\`secondStep\` ${secondStep} is invalid. It should be a factor of 60.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================ State =============================
|
||||||
|
|
||||||
|
const panelContext = React.useContext(PanelContext);
|
||||||
|
const {
|
||||||
|
operationRef,
|
||||||
|
panelRef: panelDivRef,
|
||||||
|
onSelect: onContextSelect,
|
||||||
|
hideRanges,
|
||||||
|
defaultOpenValue,
|
||||||
|
} = panelContext;
|
||||||
|
|
||||||
|
const { inRange, panelPosition, rangedValue, hoverRangedValue } = React.useContext(RangeContext);
|
||||||
|
const panelRef = React.useRef<PanelRefProps>({});
|
||||||
|
|
||||||
|
// Handle init logic
|
||||||
|
const initRef = React.useRef(true);
|
||||||
|
|
||||||
|
// Value
|
||||||
|
const [mergedValue, setInnerValue] = useMergedState(null, {
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
postState: (val) => {
|
||||||
|
if (!val && defaultOpenValue && picker === 'time') {
|
||||||
|
return defaultOpenValue;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// View date control
|
||||||
|
const [viewDate, setInnerViewDate] = useMergedState<DateType | null, DateType>(null, {
|
||||||
|
value: pickerValue,
|
||||||
|
defaultValue: defaultPickerValue || mergedValue,
|
||||||
|
postState: (date) => {
|
||||||
|
const now = generateConfig.getNow();
|
||||||
|
if (!date) return now;
|
||||||
|
// When value is null and set showTime
|
||||||
|
if (!mergedValue && showTime) {
|
||||||
|
if (typeof showTime === 'object') {
|
||||||
|
return setDateTime(generateConfig, date, showTime.defaultValue || now);
|
||||||
|
}
|
||||||
|
if (defaultValue) {
|
||||||
|
return setDateTime(generateConfig, date, defaultValue);
|
||||||
|
}
|
||||||
|
return setDateTime(generateConfig, date, now);
|
||||||
|
}
|
||||||
|
return date;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const setViewDate = (date: DateType) => {
|
||||||
|
setInnerViewDate(date);
|
||||||
|
if (onPickerValueChange) {
|
||||||
|
onPickerValueChange(date);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Panel control
|
||||||
|
const getInternalNextMode = (nextMode: PanelMode): PanelMode => {
|
||||||
|
const getNextMode = PickerModeMap[picker!];
|
||||||
|
if (getNextMode) {
|
||||||
|
return getNextMode(nextMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Save panel is changed from which panel
|
||||||
|
const [mergedMode, setInnerMode] = useMergedState(
|
||||||
|
() => {
|
||||||
|
if (picker === 'time') {
|
||||||
|
return 'time';
|
||||||
|
}
|
||||||
|
return getInternalNextMode('date');
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: mode,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setInnerMode(picker);
|
||||||
|
}, [picker]);
|
||||||
|
|
||||||
|
const [sourceMode, setSourceMode] = React.useState<PanelMode>(() => mergedMode);
|
||||||
|
|
||||||
|
const onInternalPanelChange = (newMode: PanelMode | null, viewValue: DateType) => {
|
||||||
|
const nextMode = getInternalNextMode(newMode || mergedMode);
|
||||||
|
setSourceMode(mergedMode);
|
||||||
|
setInnerMode(nextMode);
|
||||||
|
|
||||||
|
if (onPanelChange && (mergedMode !== nextMode || isEqual(generateConfig, viewDate, viewDate))) {
|
||||||
|
onPanelChange(viewValue, nextMode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const triggerSelect = (
|
||||||
|
date: DateType,
|
||||||
|
type: 'key' | 'mouse' | 'submit',
|
||||||
|
forceTriggerSelect: boolean = false,
|
||||||
|
) => {
|
||||||
|
if (mergedMode === picker || forceTriggerSelect) {
|
||||||
|
setInnerValue(date);
|
||||||
|
|
||||||
|
if (onSelect) {
|
||||||
|
onSelect(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onContextSelect) {
|
||||||
|
onContextSelect(date, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onChange && !isEqual(generateConfig, date, mergedValue) && !disabledDate?.(date)) {
|
||||||
|
onChange(date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========================= Interactive ==========================
|
||||||
|
const onInternalKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
|
||||||
|
if (panelRef.current && panelRef.current.onKeyDown) {
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
KeyCode.LEFT,
|
||||||
|
KeyCode.RIGHT,
|
||||||
|
KeyCode.UP,
|
||||||
|
KeyCode.DOWN,
|
||||||
|
KeyCode.PAGE_UP,
|
||||||
|
KeyCode.PAGE_DOWN,
|
||||||
|
KeyCode.ENTER,
|
||||||
|
].includes(e.which)
|
||||||
|
) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
return panelRef.current.onKeyDown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
/* eslint-disable no-lone-blocks */
|
||||||
|
{
|
||||||
|
warning(
|
||||||
|
false,
|
||||||
|
'Panel not correct handle keyDown event. Please help to fire issue about this.',
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* eslint-enable no-lone-blocks */
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInternalBlur: React.FocusEventHandler<HTMLElement> = (e) => {
|
||||||
|
if (panelRef.current && panelRef.current.onBlur) {
|
||||||
|
panelRef.current.onBlur(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (operationRef && panelPosition !== 'right') {
|
||||||
|
operationRef.current = {
|
||||||
|
onKeyDown: onInternalKeyDown,
|
||||||
|
onClose: () => {
|
||||||
|
if (panelRef.current && panelRef.current.onClose) {
|
||||||
|
panelRef.current.onClose();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================ Effect ============================
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (value && !initRef.current) {
|
||||||
|
setInnerViewDate(value);
|
||||||
|
}
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
initRef.current = false;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// ============================ Panels ============================
|
||||||
|
let panelNode: React.ReactNode;
|
||||||
|
|
||||||
|
const pickerProps = {
|
||||||
|
...(props as MergedPickerPanelProps<DateType>),
|
||||||
|
operationRef: panelRef,
|
||||||
|
prefixCls,
|
||||||
|
viewDate,
|
||||||
|
value: mergedValue,
|
||||||
|
onViewDateChange: setViewDate,
|
||||||
|
sourceMode,
|
||||||
|
onPanelChange: onInternalPanelChange,
|
||||||
|
disabledDate,
|
||||||
|
};
|
||||||
|
delete pickerProps.onChange;
|
||||||
|
delete pickerProps.onSelect;
|
||||||
|
|
||||||
|
switch (mergedMode) {
|
||||||
|
case 'decade':
|
||||||
|
panelNode = (
|
||||||
|
<DecadePanel<DateType>
|
||||||
|
{...pickerProps}
|
||||||
|
onSelect={(date, type) => {
|
||||||
|
setViewDate(date);
|
||||||
|
triggerSelect(date, type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'year':
|
||||||
|
panelNode = (
|
||||||
|
<YearPanel<DateType>
|
||||||
|
{...pickerProps}
|
||||||
|
onSelect={(date, type) => {
|
||||||
|
setViewDate(date);
|
||||||
|
triggerSelect(date, type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'month':
|
||||||
|
panelNode = (
|
||||||
|
<MonthPanel<DateType>
|
||||||
|
{...pickerProps}
|
||||||
|
onSelect={(date, type) => {
|
||||||
|
setViewDate(date);
|
||||||
|
triggerSelect(date, type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'quarter':
|
||||||
|
panelNode = (
|
||||||
|
<QuarterPanel<DateType>
|
||||||
|
{...pickerProps}
|
||||||
|
onSelect={(date, type) => {
|
||||||
|
setViewDate(date);
|
||||||
|
triggerSelect(date, type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'week':
|
||||||
|
panelNode = (
|
||||||
|
<WeekPanel
|
||||||
|
{...pickerProps}
|
||||||
|
onSelect={(date, type) => {
|
||||||
|
setViewDate(date);
|
||||||
|
triggerSelect(date, type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'time':
|
||||||
|
delete pickerProps.showTime;
|
||||||
|
panelNode = (
|
||||||
|
<TimePanel<DateType>
|
||||||
|
{...pickerProps}
|
||||||
|
{...(typeof showTime === 'object' ? showTime : null)}
|
||||||
|
onSelect={(date, type) => {
|
||||||
|
setViewDate(date);
|
||||||
|
triggerSelect(date, type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (showTime) {
|
||||||
|
panelNode = (
|
||||||
|
<DatetimePanel
|
||||||
|
{...pickerProps}
|
||||||
|
onSelect={(date, type) => {
|
||||||
|
setViewDate(date);
|
||||||
|
triggerSelect(date, type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panelNode = (
|
||||||
|
<DatePanel<DateType>
|
||||||
|
{...pickerProps}
|
||||||
|
onSelect={(date, type) => {
|
||||||
|
setViewDate(date);
|
||||||
|
triggerSelect(date, type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================ Footer ============================
|
||||||
|
let extraFooter: React.ReactNode;
|
||||||
|
let rangesNode: React.ReactNode;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
extraFooter = getExtraFooter(prefixCls, mergedMode, renderExtraFooter);
|
||||||
|
rangesNode = getRanges({
|
||||||
|
prefixCls,
|
||||||
|
components,
|
||||||
|
needConfirmButton,
|
||||||
|
okDisabled: !mergedValue || (disabledDate && disabledDate(mergedValue)),
|
||||||
|
locale,
|
||||||
|
showNow,
|
||||||
|
onNow: needConfirmButton && onNow,
|
||||||
|
onOk: () => {
|
||||||
|
if (mergedValue) {
|
||||||
|
triggerSelect(mergedValue, 'submit', true);
|
||||||
|
if (onOk) {
|
||||||
|
onOk(mergedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let todayNode: React.ReactNode;
|
||||||
|
|
||||||
|
if (showToday && mergedMode === 'date' && picker === 'date' && !showTime) {
|
||||||
|
const now = generateConfig.getNow();
|
||||||
|
const todayCls = `${prefixCls}-today-btn`;
|
||||||
|
const disabled = disabledDate && disabledDate(now);
|
||||||
|
todayNode = (
|
||||||
|
<a
|
||||||
|
className={classNames(todayCls, disabled && `${todayCls}-disabled`)}
|
||||||
|
aria-disabled={disabled}
|
||||||
|
onClick={() => {
|
||||||
|
if (!disabled) {
|
||||||
|
triggerSelect(now, 'mouse', true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{locale.today}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PanelContext.Provider
|
||||||
|
value={{
|
||||||
|
...panelContext,
|
||||||
|
mode: mergedMode,
|
||||||
|
hideHeader: 'hideHeader' in props ? hideHeader : panelContext.hideHeader,
|
||||||
|
hidePrevBtn: inRange && panelPosition === 'right',
|
||||||
|
hideNextBtn: inRange && panelPosition === 'left',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
tabIndex={tabIndex}
|
||||||
|
className={classNames(`${prefixCls}-panel`, className, {
|
||||||
|
[`${prefixCls}-panel-has-range`]: rangedValue && rangedValue[0] && rangedValue[1],
|
||||||
|
[`${prefixCls}-panel-has-range-hover`]:
|
||||||
|
hoverRangedValue && hoverRangedValue[0] && hoverRangedValue[1],
|
||||||
|
[`${prefixCls}-panel-rtl`]: direction === 'rtl',
|
||||||
|
})}
|
||||||
|
style={style}
|
||||||
|
onKeyDown={onInternalKeyDown}
|
||||||
|
onBlur={onInternalBlur}
|
||||||
|
onMouseDown={onMouseDown}
|
||||||
|
ref={panelDivRef}
|
||||||
|
>
|
||||||
|
{panelNode}
|
||||||
|
{extraFooter || rangesNode || todayNode ? (
|
||||||
|
<div className={`${prefixCls}-footer`}>
|
||||||
|
{extraFooter}
|
||||||
|
{rangesNode}
|
||||||
|
{todayNode}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</PanelContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PickerPanel;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import Trigger from 'rc-trigger';
|
||||||
|
import type { AlignType } from 'rc-trigger/lib/interface';
|
||||||
|
|
||||||
|
const BUILT_IN_PLACEMENTS = {
|
||||||
|
bottomLeft: {
|
||||||
|
points: ['tl', 'bl'],
|
||||||
|
offset: [0, 4],
|
||||||
|
overflow: {
|
||||||
|
adjustX: 1,
|
||||||
|
adjustY: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
bottomRight: {
|
||||||
|
points: ['tr', 'br'],
|
||||||
|
offset: [0, 4],
|
||||||
|
overflow: {
|
||||||
|
adjustX: 1,
|
||||||
|
adjustY: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
topLeft: {
|
||||||
|
points: ['bl', 'tl'],
|
||||||
|
offset: [0, -4],
|
||||||
|
overflow: {
|
||||||
|
adjustX: 0,
|
||||||
|
adjustY: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
topRight: {
|
||||||
|
points: ['br', 'tr'],
|
||||||
|
offset: [0, -4],
|
||||||
|
overflow: {
|
||||||
|
adjustX: 0,
|
||||||
|
adjustY: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type Placement = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight';
|
||||||
|
|
||||||
|
export type PickerTriggerProps = {
|
||||||
|
prefixCls: string;
|
||||||
|
visible: boolean;
|
||||||
|
popupElement: React.ReactElement;
|
||||||
|
popupStyle?: React.CSSProperties;
|
||||||
|
children: React.ReactElement;
|
||||||
|
dropdownClassName?: string;
|
||||||
|
transitionName?: string;
|
||||||
|
getPopupContainer?: (node: HTMLElement) => HTMLElement;
|
||||||
|
dropdownAlign?: AlignType;
|
||||||
|
range?: boolean;
|
||||||
|
popupPlacement?: Placement;
|
||||||
|
direction?: 'ltr' | 'rtl';
|
||||||
|
};
|
||||||
|
|
||||||
|
function PickerTrigger({
|
||||||
|
prefixCls,
|
||||||
|
popupElement,
|
||||||
|
popupStyle,
|
||||||
|
visible,
|
||||||
|
dropdownClassName,
|
||||||
|
dropdownAlign,
|
||||||
|
transitionName,
|
||||||
|
getPopupContainer,
|
||||||
|
children,
|
||||||
|
range,
|
||||||
|
popupPlacement,
|
||||||
|
direction,
|
||||||
|
}: PickerTriggerProps) {
|
||||||
|
const dropdownPrefixCls = `${prefixCls}-dropdown`;
|
||||||
|
|
||||||
|
const getPopupPlacement = () => {
|
||||||
|
if (popupPlacement !== undefined) {
|
||||||
|
return popupPlacement;
|
||||||
|
}
|
||||||
|
return direction === 'rtl' ? 'bottomRight' : 'bottomLeft';
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Trigger
|
||||||
|
showAction={[]}
|
||||||
|
hideAction={[]}
|
||||||
|
popupPlacement={getPopupPlacement()}
|
||||||
|
builtinPlacements={BUILT_IN_PLACEMENTS}
|
||||||
|
prefixCls={dropdownPrefixCls}
|
||||||
|
popupTransitionName={transitionName}
|
||||||
|
popup={popupElement}
|
||||||
|
popupAlign={dropdownAlign}
|
||||||
|
popupVisible={visible}
|
||||||
|
popupClassName={classNames(dropdownClassName, {
|
||||||
|
[`${dropdownPrefixCls}-range`]: range,
|
||||||
|
[`${dropdownPrefixCls}-rtl`]: direction === 'rtl',
|
||||||
|
})}
|
||||||
|
popupStyle={popupStyle}
|
||||||
|
getPopupContainer={getPopupContainer}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Trigger>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PickerTrigger;
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { inject, InjectionKey, provide } from 'vue';
|
||||||
|
import type { NullableDateType, RangeValue } from './interface';
|
||||||
|
|
||||||
|
export type RangeContextProps = {
|
||||||
|
/**
|
||||||
|
* Set displayed range value style.
|
||||||
|
* Panel only has one value, this is only style effect.
|
||||||
|
*/
|
||||||
|
rangedValue?: [NullableDateType<any>, NullableDateType<any>] | null;
|
||||||
|
hoverRangedValue?: RangeValue<any>;
|
||||||
|
inRange?: boolean;
|
||||||
|
panelPosition?: 'left' | 'right' | false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const RangeContextKey: InjectionKey<RangeContextProps> = Symbol('RangeContextProps');
|
||||||
|
|
||||||
|
export const useProvideRange = (props: RangeContextProps) => {
|
||||||
|
provide(RangeContextKey, props);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useInjectRange = () => {
|
||||||
|
return inject(RangeContextKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default RangeContextKey;
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,132 @@
|
||||||
|
import type { Dayjs } from 'dayjs';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import weekday from 'dayjs/plugin/weekday';
|
||||||
|
import localeData from 'dayjs/plugin/localeData';
|
||||||
|
import weekOfYear from 'dayjs/plugin/weekOfYear';
|
||||||
|
import weekYear from 'dayjs/plugin/weekYear';
|
||||||
|
import advancedFormat from 'dayjs/plugin/advancedFormat';
|
||||||
|
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||||
|
import type { GenerateConfig } from '.';
|
||||||
|
import { noteOnce } from '../../vc-util/warning';
|
||||||
|
|
||||||
|
dayjs.extend(customParseFormat);
|
||||||
|
dayjs.extend(advancedFormat);
|
||||||
|
dayjs.extend(weekday);
|
||||||
|
dayjs.extend(localeData);
|
||||||
|
dayjs.extend(weekOfYear);
|
||||||
|
dayjs.extend(weekYear);
|
||||||
|
|
||||||
|
dayjs.extend((_o, c) => {
|
||||||
|
// todo support Wo (ISO week)
|
||||||
|
const proto = c.prototype;
|
||||||
|
const oldFormat = proto.format;
|
||||||
|
proto.format = function f(formatStr: string) {
|
||||||
|
const str = (formatStr || '').replace('Wo', 'wo');
|
||||||
|
return oldFormat.bind(this)(str);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
type IlocaleMapObject = Record<string, string>;
|
||||||
|
const localeMap: IlocaleMapObject = {
|
||||||
|
en_GB: 'en-gb',
|
||||||
|
en_US: 'en',
|
||||||
|
zh_CN: 'zh-cn',
|
||||||
|
zh_TW: 'zh-tw',
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseLocale = (locale: string) => {
|
||||||
|
const mapLocale = localeMap[locale];
|
||||||
|
return mapLocale || locale.split('_')[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseNoMatchNotice = () => {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
noteOnce(false, 'Not match any format. Please help to fire a issue about this.');
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateConfig: GenerateConfig<Dayjs> = {
|
||||||
|
// get
|
||||||
|
getNow: () => dayjs(),
|
||||||
|
getFixedDate: string => dayjs(string, 'YYYY-MM-DD'),
|
||||||
|
getEndDate: date => date.endOf('month'),
|
||||||
|
getWeekDay: date => {
|
||||||
|
const clone = date.locale('en');
|
||||||
|
return clone.weekday() + clone.localeData().firstDayOfWeek();
|
||||||
|
},
|
||||||
|
getYear: date => date.year(),
|
||||||
|
getMonth: date => date.month(),
|
||||||
|
getDate: date => date.date(),
|
||||||
|
getHour: date => date.hour(),
|
||||||
|
getMinute: date => date.minute(),
|
||||||
|
getSecond: date => date.second(),
|
||||||
|
|
||||||
|
// set
|
||||||
|
addYear: (date, diff) => date.add(diff, 'year'),
|
||||||
|
addMonth: (date, diff) => date.add(diff, 'month'),
|
||||||
|
addDate: (date, diff) => date.add(diff, 'day'),
|
||||||
|
setYear: (date, year) => date.year(year),
|
||||||
|
setMonth: (date, month) => date.month(month),
|
||||||
|
setDate: (date, num) => date.date(num),
|
||||||
|
setHour: (date, hour) => date.hour(hour),
|
||||||
|
setMinute: (date, minute) => date.minute(minute),
|
||||||
|
setSecond: (date, second) => date.second(second),
|
||||||
|
|
||||||
|
// Compare
|
||||||
|
isAfter: (date1, date2) => date1.isAfter(date2),
|
||||||
|
isValidate: date => date.isValid(),
|
||||||
|
|
||||||
|
locale: {
|
||||||
|
getWeekFirstDay: locale =>
|
||||||
|
dayjs()
|
||||||
|
.locale(parseLocale(locale))
|
||||||
|
.localeData()
|
||||||
|
.firstDayOfWeek(),
|
||||||
|
getWeekFirstDate: (locale, date) => date.locale(parseLocale(locale)).weekday(0),
|
||||||
|
getWeek: (locale, date) => date.locale(parseLocale(locale)).week(),
|
||||||
|
getShortWeekDays: locale =>
|
||||||
|
dayjs()
|
||||||
|
.locale(parseLocale(locale))
|
||||||
|
.localeData()
|
||||||
|
.weekdaysMin(),
|
||||||
|
getShortMonths: locale =>
|
||||||
|
dayjs()
|
||||||
|
.locale(parseLocale(locale))
|
||||||
|
.localeData()
|
||||||
|
.monthsShort(),
|
||||||
|
format: (locale, date, format) => date.locale(parseLocale(locale)).format(format),
|
||||||
|
parse: (locale, text, formats) => {
|
||||||
|
const localeStr = parseLocale(locale);
|
||||||
|
for (let i = 0; i < formats.length; i += 1) {
|
||||||
|
const format = formats[i];
|
||||||
|
const formatText = text;
|
||||||
|
if (format.includes('wo') || format.includes('Wo')) {
|
||||||
|
// parse Wo
|
||||||
|
const year = formatText.split('-')[0];
|
||||||
|
const weekStr = formatText.split('-')[1];
|
||||||
|
const firstWeek = dayjs(year, 'YYYY')
|
||||||
|
.startOf('year')
|
||||||
|
.locale(localeStr);
|
||||||
|
for (let j = 0; j <= 52; j += 1) {
|
||||||
|
const nextWeek = firstWeek.add(j, 'week');
|
||||||
|
if (nextWeek.format('Wo') === weekStr) {
|
||||||
|
return nextWeek;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parseNoMatchNotice();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const date = dayjs(formatText, format).locale(localeStr);
|
||||||
|
if (date.isValid()) {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
parseNoMatchNotice();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default generateConfig;
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
import { noteOnce } from '../../vc-util/warning';
|
||||||
|
import type { Moment } from 'moment';
|
||||||
|
import moment from 'moment';
|
||||||
|
import type { GenerateConfig } from '.';
|
||||||
|
|
||||||
|
const generateConfig: GenerateConfig<Moment> = {
|
||||||
|
// get
|
||||||
|
getNow: () => moment(),
|
||||||
|
getFixedDate: string => moment(string, 'YYYY-MM-DD'),
|
||||||
|
getEndDate: date => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.endOf('month');
|
||||||
|
},
|
||||||
|
getWeekDay: date => {
|
||||||
|
const clone = date.clone().locale('en_US');
|
||||||
|
return clone.weekday() + clone.localeData().firstDayOfWeek();
|
||||||
|
},
|
||||||
|
getYear: date => date.year(),
|
||||||
|
getMonth: date => date.month(),
|
||||||
|
getDate: date => date.date(),
|
||||||
|
getHour: date => date.hour(),
|
||||||
|
getMinute: date => date.minute(),
|
||||||
|
getSecond: date => date.second(),
|
||||||
|
|
||||||
|
// set
|
||||||
|
addYear: (date, diff) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.add(diff, 'year');
|
||||||
|
},
|
||||||
|
addMonth: (date, diff) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.add(diff, 'month');
|
||||||
|
},
|
||||||
|
addDate: (date, diff) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.add(diff, 'day');
|
||||||
|
},
|
||||||
|
setYear: (date, year) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.year(year);
|
||||||
|
},
|
||||||
|
setMonth: (date, month) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.month(month);
|
||||||
|
},
|
||||||
|
setDate: (date, num) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.date(num);
|
||||||
|
},
|
||||||
|
setHour: (date, hour) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.hour(hour);
|
||||||
|
},
|
||||||
|
setMinute: (date, minute) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.minute(minute);
|
||||||
|
},
|
||||||
|
setSecond: (date, second) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
return clone.second(second);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Compare
|
||||||
|
isAfter: (date1, date2) => date1.isAfter(date2),
|
||||||
|
isValidate: date => date.isValid(),
|
||||||
|
|
||||||
|
locale: {
|
||||||
|
getWeekFirstDay: locale => {
|
||||||
|
const date = moment().locale(locale);
|
||||||
|
return date.localeData().firstDayOfWeek();
|
||||||
|
},
|
||||||
|
getWeekFirstDate: (locale, date) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
const result = clone.locale(locale);
|
||||||
|
return result.weekday(0);
|
||||||
|
},
|
||||||
|
getWeek: (locale, date) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
const result = clone.locale(locale);
|
||||||
|
return result.week();
|
||||||
|
},
|
||||||
|
getShortWeekDays: locale => {
|
||||||
|
const date = moment().locale(locale);
|
||||||
|
return date.localeData().weekdaysMin();
|
||||||
|
},
|
||||||
|
getShortMonths: locale => {
|
||||||
|
const date = moment().locale(locale);
|
||||||
|
return date.localeData().monthsShort();
|
||||||
|
},
|
||||||
|
format: (locale, date, format) => {
|
||||||
|
const clone = date.clone();
|
||||||
|
const result = clone.locale(locale);
|
||||||
|
return result.format(format);
|
||||||
|
},
|
||||||
|
parse: (locale, text, formats) => {
|
||||||
|
const fallbackFormatList: string[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < formats.length; i += 1) {
|
||||||
|
let format = formats[i];
|
||||||
|
let formatText = text;
|
||||||
|
|
||||||
|
if (format.includes('wo') || format.includes('Wo')) {
|
||||||
|
format = format.replace(/wo/g, 'w').replace(/Wo/g, 'W');
|
||||||
|
const matchFormat = format.match(/[-YyMmDdHhSsWwGg]+/g);
|
||||||
|
const matchText = formatText.match(/[-\d]+/g);
|
||||||
|
|
||||||
|
if (matchFormat && matchText) {
|
||||||
|
format = matchFormat.join('');
|
||||||
|
formatText = matchText.join('');
|
||||||
|
} else {
|
||||||
|
fallbackFormatList.push(format.replace(/o/g, ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = moment(formatText, format, locale, true);
|
||||||
|
if (date.isValid()) {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to fuzzy matching, this should always not reach match or need fire a issue
|
||||||
|
for (let i = 0; i < fallbackFormatList.length; i += 1) {
|
||||||
|
const date = moment(text, fallbackFormatList[i], locale, false);
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (date.isValid()) {
|
||||||
|
noteOnce(
|
||||||
|
false,
|
||||||
|
'Not match any format strictly and fallback to fuzzy match. Please help to fire a issue about this.',
|
||||||
|
);
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default generateConfig;
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
import { isInRange } from '../utils/dateUtil';
|
||||||
|
import type { GenerateConfig } from '../generate';
|
||||||
|
import type { RangeValue, NullableDateType } from '../interface';
|
||||||
|
import { getValue } from '../utils/miscUtil';
|
||||||
|
|
||||||
|
export default function useCellClassName<DateType>({
|
||||||
|
cellPrefixCls,
|
||||||
|
generateConfig,
|
||||||
|
rangedValue,
|
||||||
|
hoverRangedValue,
|
||||||
|
isInView,
|
||||||
|
isSameCell,
|
||||||
|
offsetCell,
|
||||||
|
today,
|
||||||
|
value,
|
||||||
|
}: {
|
||||||
|
cellPrefixCls: string;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
isSameCell: (
|
||||||
|
current: NullableDateType<DateType>,
|
||||||
|
target: NullableDateType<DateType>,
|
||||||
|
) => boolean;
|
||||||
|
offsetCell: (date: DateType, offset: number) => DateType;
|
||||||
|
isInView: (date: DateType) => boolean;
|
||||||
|
rangedValue?: RangeValue<DateType>;
|
||||||
|
hoverRangedValue?: RangeValue<DateType>;
|
||||||
|
today?: NullableDateType<DateType>;
|
||||||
|
value?: NullableDateType<DateType>;
|
||||||
|
}) {
|
||||||
|
function getClassName(currentDate: DateType) {
|
||||||
|
const prevDate = offsetCell(currentDate, -1);
|
||||||
|
const nextDate = offsetCell(currentDate, 1);
|
||||||
|
|
||||||
|
const rangeStart = getValue(rangedValue, 0);
|
||||||
|
const rangeEnd = getValue(rangedValue, 1);
|
||||||
|
|
||||||
|
const hoverStart = getValue(hoverRangedValue, 0);
|
||||||
|
const hoverEnd = getValue(hoverRangedValue, 1);
|
||||||
|
|
||||||
|
const isRangeHovered = isInRange(
|
||||||
|
generateConfig,
|
||||||
|
hoverStart,
|
||||||
|
hoverEnd,
|
||||||
|
currentDate,
|
||||||
|
);
|
||||||
|
|
||||||
|
function isRangeStart(date: DateType) {
|
||||||
|
return isSameCell(rangeStart, date);
|
||||||
|
}
|
||||||
|
function isRangeEnd(date: DateType) {
|
||||||
|
return isSameCell(rangeEnd, date);
|
||||||
|
}
|
||||||
|
const isHoverStart = isSameCell(hoverStart, currentDate);
|
||||||
|
const isHoverEnd = isSameCell(hoverEnd, currentDate);
|
||||||
|
|
||||||
|
const isHoverEdgeStart =
|
||||||
|
(isRangeHovered || isHoverEnd) &&
|
||||||
|
(!isInView(prevDate) || isRangeEnd(prevDate));
|
||||||
|
const isHoverEdgeEnd =
|
||||||
|
(isRangeHovered || isHoverStart) &&
|
||||||
|
(!isInView(nextDate) || isRangeStart(nextDate));
|
||||||
|
|
||||||
|
return {
|
||||||
|
// In view
|
||||||
|
[`${cellPrefixCls}-in-view`]: isInView(currentDate),
|
||||||
|
|
||||||
|
// Range
|
||||||
|
[`${cellPrefixCls}-in-range`]: isInRange<DateType>(
|
||||||
|
generateConfig,
|
||||||
|
rangeStart,
|
||||||
|
rangeEnd,
|
||||||
|
currentDate,
|
||||||
|
),
|
||||||
|
[`${cellPrefixCls}-range-start`]: isRangeStart(currentDate),
|
||||||
|
[`${cellPrefixCls}-range-end`]: isRangeEnd(currentDate),
|
||||||
|
[`${cellPrefixCls}-range-start-single`]:
|
||||||
|
isRangeStart(currentDate) && !rangeEnd,
|
||||||
|
[`${cellPrefixCls}-range-end-single`]:
|
||||||
|
isRangeEnd(currentDate) && !rangeStart,
|
||||||
|
[`${cellPrefixCls}-range-start-near-hover`]:
|
||||||
|
isRangeStart(currentDate) &&
|
||||||
|
(isSameCell(prevDate, hoverStart) ||
|
||||||
|
isInRange(generateConfig, hoverStart, hoverEnd, prevDate)),
|
||||||
|
[`${cellPrefixCls}-range-end-near-hover`]:
|
||||||
|
isRangeEnd(currentDate) &&
|
||||||
|
(isSameCell(nextDate, hoverEnd) ||
|
||||||
|
isInRange(generateConfig, hoverStart, hoverEnd, nextDate)),
|
||||||
|
|
||||||
|
// Range Hover
|
||||||
|
[`${cellPrefixCls}-range-hover`]: isRangeHovered,
|
||||||
|
[`${cellPrefixCls}-range-hover-start`]: isHoverStart,
|
||||||
|
[`${cellPrefixCls}-range-hover-end`]: isHoverEnd,
|
||||||
|
|
||||||
|
// Range Edge
|
||||||
|
[`${cellPrefixCls}-range-hover-edge-start`]: isHoverEdgeStart,
|
||||||
|
[`${cellPrefixCls}-range-hover-edge-end`]: isHoverEdgeEnd,
|
||||||
|
[`${cellPrefixCls}-range-hover-edge-start-near-range`]:
|
||||||
|
isHoverEdgeStart && isSameCell(prevDate, rangeEnd),
|
||||||
|
[`${cellPrefixCls}-range-hover-edge-end-near-range`]:
|
||||||
|
isHoverEdgeEnd && isSameCell(nextDate, rangeStart),
|
||||||
|
|
||||||
|
// Others
|
||||||
|
[`${cellPrefixCls}-today`]: isSameCell(today, currentDate),
|
||||||
|
[`${cellPrefixCls}-selected`]: isSameCell(value, currentDate),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return getClassName;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { useState, useEffect, useRef } from 'react';
|
||||||
|
import type { ValueTextConfig } from './useValueTexts';
|
||||||
|
import useValueTexts from './useValueTexts';
|
||||||
|
|
||||||
|
export default function useHoverValue<DateType>(
|
||||||
|
valueText: string,
|
||||||
|
{ formatList, generateConfig, locale }: ValueTextConfig<DateType>,
|
||||||
|
): [string, (date: DateType) => void, (immediately?: boolean) => void] {
|
||||||
|
const [value, internalSetValue] = useState<DateType>(null);
|
||||||
|
const raf = useRef(null);
|
||||||
|
|
||||||
|
function setValue(val: DateType, immediately: boolean = false) {
|
||||||
|
cancelAnimationFrame(raf.current);
|
||||||
|
if (immediately) {
|
||||||
|
internalSetValue(val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
raf.current = requestAnimationFrame(() => {
|
||||||
|
internalSetValue(val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, firstText] = useValueTexts(value, {
|
||||||
|
formatList,
|
||||||
|
generateConfig,
|
||||||
|
locale,
|
||||||
|
});
|
||||||
|
|
||||||
|
function onEnter(date: DateType) {
|
||||||
|
setValue(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLeave(immediately: boolean = false) {
|
||||||
|
setValue(null, immediately);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onLeave(true);
|
||||||
|
}, [valueText]);
|
||||||
|
|
||||||
|
useEffect(() => () => cancelAnimationFrame(raf.current), []);
|
||||||
|
|
||||||
|
return [firstText, onEnter, onLeave];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
import type * as React from 'react';
|
||||||
|
import { useState, useEffect, useRef } from 'react';
|
||||||
|
import KeyCode from 'rc-util/lib/KeyCode';
|
||||||
|
import { addGlobalMouseDownEvent, getTargetFromEvent } from '../utils/uiUtil';
|
||||||
|
|
||||||
|
export default function usePickerInput({
|
||||||
|
open,
|
||||||
|
value,
|
||||||
|
isClickOutside,
|
||||||
|
triggerOpen,
|
||||||
|
forwardKeyDown,
|
||||||
|
onKeyDown,
|
||||||
|
blurToCancel,
|
||||||
|
onSubmit,
|
||||||
|
onCancel,
|
||||||
|
onFocus,
|
||||||
|
onBlur,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
value: string;
|
||||||
|
isClickOutside: (clickElement: EventTarget | null) => boolean;
|
||||||
|
triggerOpen: (open: boolean) => void;
|
||||||
|
forwardKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => boolean;
|
||||||
|
onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>, preventDefault: () => void) => void;
|
||||||
|
blurToCancel?: boolean;
|
||||||
|
onSubmit: () => void | boolean;
|
||||||
|
onCancel: () => void;
|
||||||
|
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
||||||
|
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
||||||
|
}): [React.DOMAttributes<HTMLInputElement>, { focused: boolean; typing: boolean }] {
|
||||||
|
const [typing, setTyping] = useState(false);
|
||||||
|
const [focused, setFocused] = useState(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We will prevent blur to handle open event when user click outside,
|
||||||
|
* since this will repeat trigger `onOpenChange` event.
|
||||||
|
*/
|
||||||
|
const preventBlurRef = useRef<boolean>(false);
|
||||||
|
|
||||||
|
const valueChangedRef = useRef<boolean>(false);
|
||||||
|
|
||||||
|
const preventDefaultRef = useRef<boolean>(false);
|
||||||
|
|
||||||
|
const inputProps: React.DOMAttributes<HTMLInputElement> = {
|
||||||
|
onMouseDown: () => {
|
||||||
|
setTyping(true);
|
||||||
|
triggerOpen(true);
|
||||||
|
},
|
||||||
|
onKeyDown: (e) => {
|
||||||
|
const preventDefault = (): void => {
|
||||||
|
preventDefaultRef.current = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
onKeyDown(e, preventDefault);
|
||||||
|
|
||||||
|
if (preventDefaultRef.current) return;
|
||||||
|
|
||||||
|
switch (e.which) {
|
||||||
|
case KeyCode.ENTER: {
|
||||||
|
if (!open) {
|
||||||
|
triggerOpen(true);
|
||||||
|
} else if (onSubmit() !== false) {
|
||||||
|
setTyping(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KeyCode.TAB: {
|
||||||
|
if (typing && open && !e.shiftKey) {
|
||||||
|
setTyping(false);
|
||||||
|
e.preventDefault();
|
||||||
|
} else if (!typing && open) {
|
||||||
|
if (!forwardKeyDown(e) && e.shiftKey) {
|
||||||
|
setTyping(true);
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KeyCode.ESC: {
|
||||||
|
setTyping(true);
|
||||||
|
onCancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!open && ![KeyCode.SHIFT].includes(e.which)) {
|
||||||
|
triggerOpen(true);
|
||||||
|
} else if (!typing) {
|
||||||
|
// Let popup panel handle keyboard
|
||||||
|
forwardKeyDown(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onFocus: (e) => {
|
||||||
|
setTyping(true);
|
||||||
|
setFocused(true);
|
||||||
|
|
||||||
|
if (onFocus) {
|
||||||
|
onFocus(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onBlur: (e) => {
|
||||||
|
if (preventBlurRef.current || !isClickOutside(document.activeElement)) {
|
||||||
|
preventBlurRef.current = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blurToCancel) {
|
||||||
|
setTimeout(() => {
|
||||||
|
let { activeElement } = document;
|
||||||
|
while (activeElement && activeElement.shadowRoot) {
|
||||||
|
activeElement = activeElement.shadowRoot.activeElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isClickOutside(activeElement)) {
|
||||||
|
onCancel();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
} else if (open) {
|
||||||
|
triggerOpen(false);
|
||||||
|
|
||||||
|
if (valueChangedRef.current) {
|
||||||
|
onSubmit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setFocused(false);
|
||||||
|
|
||||||
|
if (onBlur) {
|
||||||
|
onBlur(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// check if value changed
|
||||||
|
useEffect(() => {
|
||||||
|
valueChangedRef.current = false;
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
valueChangedRef.current = true;
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
// Global click handler
|
||||||
|
useEffect(() =>
|
||||||
|
addGlobalMouseDownEvent((e: MouseEvent) => {
|
||||||
|
const target = getTargetFromEvent(e);
|
||||||
|
|
||||||
|
if (open) {
|
||||||
|
const clickedOutside = isClickOutside(target);
|
||||||
|
|
||||||
|
if (!clickedOutside) {
|
||||||
|
preventBlurRef.current = true;
|
||||||
|
|
||||||
|
// Always set back in case `onBlur` prevented by user
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
preventBlurRef.current = false;
|
||||||
|
});
|
||||||
|
} else if (!focused || clickedOutside) {
|
||||||
|
triggerOpen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return [inputProps, { focused, typing }];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import type { RangeValue, PickerMode, Locale } from '../interface';
|
||||||
|
import { getValue } from '../utils/miscUtil';
|
||||||
|
import type { GenerateConfig } from '../generate';
|
||||||
|
import { isSameDate, getQuarter } from '../utils/dateUtil';
|
||||||
|
|
||||||
|
export default function useRangeDisabled<DateType>(
|
||||||
|
{
|
||||||
|
picker,
|
||||||
|
locale,
|
||||||
|
selectedValue,
|
||||||
|
disabledDate,
|
||||||
|
disabled,
|
||||||
|
generateConfig,
|
||||||
|
}: {
|
||||||
|
picker: PickerMode;
|
||||||
|
selectedValue: RangeValue<DateType>;
|
||||||
|
disabledDate?: (date: DateType) => boolean;
|
||||||
|
disabled: [boolean, boolean];
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
},
|
||||||
|
disabledStart: boolean,
|
||||||
|
disabledEnd: boolean,
|
||||||
|
) {
|
||||||
|
const startDate = getValue(selectedValue, 0);
|
||||||
|
const endDate = getValue(selectedValue, 1);
|
||||||
|
|
||||||
|
function weekFirstDate(date: DateType) {
|
||||||
|
return generateConfig.locale.getWeekFirstDate(locale.locale, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
function monthNumber(date: DateType) {
|
||||||
|
const year = generateConfig.getYear(date);
|
||||||
|
const month = generateConfig.getMonth(date);
|
||||||
|
return year * 100 + month;
|
||||||
|
}
|
||||||
|
|
||||||
|
function quarterNumber(date: DateType) {
|
||||||
|
const year = generateConfig.getYear(date);
|
||||||
|
const quarter = getQuarter(generateConfig, date);
|
||||||
|
return year * 10 + quarter;
|
||||||
|
}
|
||||||
|
|
||||||
|
const disabledStartDate = React.useCallback(
|
||||||
|
(date: DateType) => {
|
||||||
|
if (disabledDate && disabledDate(date)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled range
|
||||||
|
if (disabled[1] && endDate) {
|
||||||
|
return !isSameDate(generateConfig, date, endDate) && generateConfig.isAfter(date, endDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled part
|
||||||
|
if (disabledStart && endDate) {
|
||||||
|
switch (picker) {
|
||||||
|
case 'quarter':
|
||||||
|
return quarterNumber(date) > quarterNumber(endDate);
|
||||||
|
case 'month':
|
||||||
|
return monthNumber(date) > monthNumber(endDate);
|
||||||
|
case 'week':
|
||||||
|
return weekFirstDate(date) > weekFirstDate(endDate);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
!isSameDate(generateConfig, date, endDate) && generateConfig.isAfter(date, endDate)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
[disabledDate, disabled[1], endDate, disabledStart],
|
||||||
|
);
|
||||||
|
|
||||||
|
const disabledEndDate = React.useCallback(
|
||||||
|
(date: DateType) => {
|
||||||
|
if (disabledDate && disabledDate(date)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled range
|
||||||
|
if (disabled[0] && startDate) {
|
||||||
|
return (
|
||||||
|
!isSameDate(generateConfig, date, endDate) && generateConfig.isAfter(startDate, date)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled part
|
||||||
|
if (disabledEnd && startDate) {
|
||||||
|
switch (picker) {
|
||||||
|
case 'quarter':
|
||||||
|
return quarterNumber(date) < quarterNumber(startDate);
|
||||||
|
case 'month':
|
||||||
|
return monthNumber(date) < monthNumber(startDate);
|
||||||
|
case 'week':
|
||||||
|
return weekFirstDate(date) < weekFirstDate(startDate);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
!isSameDate(generateConfig, date, startDate) &&
|
||||||
|
generateConfig.isAfter(startDate, date)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
[disabledDate, disabled[0], startDate, disabledEnd],
|
||||||
|
);
|
||||||
|
|
||||||
|
return [disabledStartDate, disabledEndDate];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import type { RangeValue, PickerMode } from '../interface';
|
||||||
|
import type { GenerateConfig } from '../generate';
|
||||||
|
import { getValue, updateValues } from '../utils/miscUtil';
|
||||||
|
import { getClosingViewDate, isSameYear, isSameMonth, isSameDecade } from '../utils/dateUtil';
|
||||||
|
|
||||||
|
function getStartEndDistance<DateType>(
|
||||||
|
startDate: DateType,
|
||||||
|
endDate: DateType,
|
||||||
|
picker: PickerMode,
|
||||||
|
generateConfig: GenerateConfig<DateType>,
|
||||||
|
): 'same' | 'closing' | 'far' {
|
||||||
|
const startNext = getClosingViewDate(startDate, picker, generateConfig, 1);
|
||||||
|
|
||||||
|
function getDistance(compareFunc: (start: DateType | null, end: DateType | null) => boolean) {
|
||||||
|
if (compareFunc(startDate, endDate)) {
|
||||||
|
return 'same';
|
||||||
|
}
|
||||||
|
if (compareFunc(startNext, endDate)) {
|
||||||
|
return 'closing';
|
||||||
|
}
|
||||||
|
return 'far';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (picker) {
|
||||||
|
case 'year':
|
||||||
|
return getDistance((start, end) => isSameDecade(generateConfig, start, end));
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
return getDistance((start, end) => isSameYear(generateConfig, start, end));
|
||||||
|
default:
|
||||||
|
return getDistance((start, end) => isSameMonth(generateConfig, start, end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRangeViewDate<DateType>(
|
||||||
|
values: RangeValue<DateType>,
|
||||||
|
index: 0 | 1,
|
||||||
|
picker: PickerMode,
|
||||||
|
generateConfig: GenerateConfig<DateType>,
|
||||||
|
): DateType | null {
|
||||||
|
const startDate = getValue(values, 0);
|
||||||
|
const endDate = getValue(values, 1);
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
return startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startDate && endDate) {
|
||||||
|
const distance = getStartEndDistance(startDate, endDate, picker, generateConfig);
|
||||||
|
switch (distance) {
|
||||||
|
case 'same':
|
||||||
|
return startDate;
|
||||||
|
case 'closing':
|
||||||
|
return startDate;
|
||||||
|
default:
|
||||||
|
return getClosingViewDate(endDate, picker, generateConfig, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useRangeViewDates<DateType>({
|
||||||
|
values,
|
||||||
|
picker,
|
||||||
|
defaultDates,
|
||||||
|
generateConfig,
|
||||||
|
}: {
|
||||||
|
values: RangeValue<DateType>;
|
||||||
|
picker: PickerMode;
|
||||||
|
defaultDates: RangeValue<DateType> | undefined;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
}): [(activePickerIndex: 0 | 1) => DateType, (viewDate: DateType | null, index: 0 | 1) => void] {
|
||||||
|
const [defaultViewDates, setDefaultViewDates] = React.useState<
|
||||||
|
[DateType | null, DateType | null]
|
||||||
|
>(() => [getValue(defaultDates, 0), getValue(defaultDates, 1)]);
|
||||||
|
const [viewDates, setInternalViewDates] = React.useState<RangeValue<DateType>>(null);
|
||||||
|
|
||||||
|
const startDate = getValue(values, 0);
|
||||||
|
const endDate = getValue(values, 1);
|
||||||
|
|
||||||
|
function getViewDate(index: 0 | 1): DateType {
|
||||||
|
// If set default view date, use it
|
||||||
|
if (defaultViewDates[index]) {
|
||||||
|
return defaultViewDates[index]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
getValue(viewDates, index) ||
|
||||||
|
getRangeViewDate(values, index, picker, generateConfig) ||
|
||||||
|
startDate ||
|
||||||
|
endDate ||
|
||||||
|
generateConfig.getNow()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setViewDate(viewDate: DateType | null, index: 0 | 1) {
|
||||||
|
if (viewDate) {
|
||||||
|
let newViewDates = updateValues(viewDates, viewDate, index);
|
||||||
|
// Set view date will clean up default one
|
||||||
|
setDefaultViewDates(
|
||||||
|
// Should always be an array
|
||||||
|
updateValues(defaultViewDates, null, index) || [null, null],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Reset another one when not have value
|
||||||
|
const anotherIndex = (index + 1) % 2;
|
||||||
|
if (!getValue(values, anotherIndex)) {
|
||||||
|
newViewDates = updateValues(newViewDates, viewDate, anotherIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInternalViewDates(newViewDates);
|
||||||
|
} else if (startDate || endDate) {
|
||||||
|
// Reset all when has values when `viewDate` is `null` which means from open trigger
|
||||||
|
setInternalViewDates(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [getViewDate, setViewDate];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export default function useTextValueMapping({
|
||||||
|
valueTexts,
|
||||||
|
onTextChange,
|
||||||
|
}: {
|
||||||
|
/** Must useMemo, to assume that `valueTexts` only match on the first change */
|
||||||
|
valueTexts: string[];
|
||||||
|
onTextChange: (text: string) => void;
|
||||||
|
}): [string, (text: string) => void, () => void] {
|
||||||
|
const [text, setInnerText] = React.useState('');
|
||||||
|
const valueTextsRef = React.useRef<string[]>([]);
|
||||||
|
valueTextsRef.current = valueTexts;
|
||||||
|
|
||||||
|
function triggerTextChange(value: string) {
|
||||||
|
setInnerText(value);
|
||||||
|
onTextChange(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetText() {
|
||||||
|
setInnerText(valueTextsRef.current[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (valueTexts.every(valText => valText !== text)) {
|
||||||
|
resetText();
|
||||||
|
}
|
||||||
|
}, [valueTexts.join('||')]);
|
||||||
|
|
||||||
|
return [text, triggerTextChange, resetText];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import shallowEqual from 'shallowequal';
|
||||||
|
import useMemo from 'rc-util/lib/hooks/useMemo';
|
||||||
|
import type { GenerateConfig } from '../generate';
|
||||||
|
import type { CustomFormat, Locale } from '../interface';
|
||||||
|
import { formatValue } from '../utils/dateUtil';
|
||||||
|
|
||||||
|
export type ValueTextConfig<DateType> = {
|
||||||
|
formatList: (string | CustomFormat<DateType>)[];
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
locale: Locale;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function useValueTexts<DateType>(
|
||||||
|
value: DateType | null,
|
||||||
|
{ formatList, generateConfig, locale }: ValueTextConfig<DateType>,
|
||||||
|
) {
|
||||||
|
return useMemo<[string[], string]>(
|
||||||
|
() => {
|
||||||
|
if (!value) {
|
||||||
|
return [[''], ''];
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will convert data format back to first format
|
||||||
|
let firstValueText: string = '';
|
||||||
|
const fullValueTexts: string[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < formatList.length; i += 1) {
|
||||||
|
const format = formatList[i];
|
||||||
|
const formatStr = formatValue(value, { generateConfig, locale, format });
|
||||||
|
fullValueTexts.push(formatStr);
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
firstValueText = formatStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [fullValueTexts, firstValueText];
|
||||||
|
},
|
||||||
|
[value, formatList],
|
||||||
|
(prev, next) => prev[0] !== next[0] || !shallowEqual(prev[1], next[1]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import Picker, { PickerProps } from './Picker';
|
||||||
|
import PickerPanel, { PickerPanelProps } from './PickerPanel';
|
||||||
|
import RangePicker, { RangePickerProps } from './RangePicker';
|
||||||
|
|
||||||
|
export {
|
||||||
|
PickerPanel,
|
||||||
|
RangePicker,
|
||||||
|
PickerProps,
|
||||||
|
PickerPanelProps,
|
||||||
|
RangePickerProps,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Picker;
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
import type { GenerateConfig } from './generate';
|
||||||
|
|
||||||
|
export type Locale = {
|
||||||
|
locale: string;
|
||||||
|
|
||||||
|
// ===================== Date Panel =====================
|
||||||
|
/** Display month before year in date panel header */
|
||||||
|
monthBeforeYear?: boolean;
|
||||||
|
yearFormat: string;
|
||||||
|
monthFormat?: string;
|
||||||
|
quarterFormat?: string;
|
||||||
|
|
||||||
|
today: string;
|
||||||
|
now: string;
|
||||||
|
backToToday: string;
|
||||||
|
ok: string;
|
||||||
|
timeSelect: string;
|
||||||
|
dateSelect: string;
|
||||||
|
weekSelect?: string;
|
||||||
|
clear: string;
|
||||||
|
month: string;
|
||||||
|
year: string;
|
||||||
|
previousMonth: string;
|
||||||
|
nextMonth: string;
|
||||||
|
monthSelect: string;
|
||||||
|
yearSelect: string;
|
||||||
|
decadeSelect: string;
|
||||||
|
|
||||||
|
dayFormat: string;
|
||||||
|
dateFormat: string;
|
||||||
|
dateTimeFormat: string;
|
||||||
|
previousYear: string;
|
||||||
|
nextYear: string;
|
||||||
|
previousDecade: string;
|
||||||
|
nextDecade: string;
|
||||||
|
previousCentury: string;
|
||||||
|
nextCentury: string;
|
||||||
|
|
||||||
|
shortWeekDays?: string[];
|
||||||
|
shortMonths?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PanelMode = 'time' | 'date' | 'week' | 'month' | 'quarter' | 'year' | 'decade';
|
||||||
|
|
||||||
|
export type PickerMode = Exclude<PanelMode, 'datetime' | 'decade'>;
|
||||||
|
|
||||||
|
export type PanelRefProps = {
|
||||||
|
onKeyDown?: (e: KeyboardEvent) => boolean;
|
||||||
|
onBlur?: (e: FocusEvent)=> void;
|
||||||
|
onClose?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NullableDateType<DateType> = DateType | null | undefined;
|
||||||
|
|
||||||
|
export type OnSelect<DateType> = (value: DateType, type: 'key' | 'mouse' | 'submit') => void;
|
||||||
|
|
||||||
|
export type PanelSharedProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
value?: NullableDateType<DateType>;
|
||||||
|
viewDate: DateType;
|
||||||
|
/** [Legacy] Set default display picker view date */
|
||||||
|
defaultPickerValue?: DateType;
|
||||||
|
locale: Locale;
|
||||||
|
disabledDate?: (date: DateType) => boolean;
|
||||||
|
|
||||||
|
// prevIcon?: React.ReactNode;
|
||||||
|
// nextIcon?: React.ReactNode;
|
||||||
|
// superPrevIcon?: React.ReactNode;
|
||||||
|
// superNextIcon?: React.ReactNode;
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Typescript can not handle generic type so we can not use `forwardRef` here.
|
||||||
|
// * Thus, move ref into operationRef.
|
||||||
|
// * This is little hack which should refactor after typescript support.
|
||||||
|
// */
|
||||||
|
// operationRef: React.MutableRefObject<PanelRefProps>;
|
||||||
|
|
||||||
|
onSelect: OnSelect<DateType>;
|
||||||
|
onViewDateChange: (value: DateType) => void;
|
||||||
|
onPanelChange: (mode: PanelMode | null, viewValue: DateType) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DisabledTimes = {
|
||||||
|
disabledHours?: () => number[];
|
||||||
|
disabledMinutes?: (hour: number) => number[];
|
||||||
|
disabledSeconds?: (hour: number, minute: number) => number[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DisabledTime<DateType> = (date: DateType | null) => DisabledTimes;
|
||||||
|
|
||||||
|
export type OnPanelChange<DateType> = (value: DateType, mode: PanelMode) => void;
|
||||||
|
|
||||||
|
export type EventValue<DateType> = DateType | null;
|
||||||
|
export type RangeValue<DateType> = [EventValue<DateType>, EventValue<DateType>] | null;
|
||||||
|
|
||||||
|
export type Components = {
|
||||||
|
button?: any;
|
||||||
|
rangeItem?: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RangeList = {
|
||||||
|
label: string;
|
||||||
|
onClick: () => void;
|
||||||
|
onMouseEnter: () => void;
|
||||||
|
onMouseLeave: () => void;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
export type CustomFormat<DateType> = (value: DateType) => string;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ar_EG',
|
||||||
|
today: 'اليوم',
|
||||||
|
now: 'الأن',
|
||||||
|
backToToday: 'العودة إلى اليوم',
|
||||||
|
ok: 'تأكيد',
|
||||||
|
clear: 'مسح',
|
||||||
|
month: 'الشهر',
|
||||||
|
year: 'السنة',
|
||||||
|
timeSelect: 'اختيار الوقت',
|
||||||
|
dateSelect: 'اختيار التاريخ',
|
||||||
|
monthSelect: 'اختيار الشهر',
|
||||||
|
yearSelect: 'اختيار السنة',
|
||||||
|
decadeSelect: 'اختيار العقد',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'الشهر السابق (PageUp)',
|
||||||
|
nextMonth: 'الشهر التالى(PageDown)',
|
||||||
|
previousYear: 'العام السابق (Control + left)',
|
||||||
|
nextYear: 'العام التالى (Control + right)',
|
||||||
|
previousDecade: 'العقد السابق',
|
||||||
|
nextDecade: 'العقد التالى',
|
||||||
|
previousCentury: 'القرن السابق',
|
||||||
|
nextCentury: 'القرن التالى',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'az_AZ',
|
||||||
|
today: 'Bugün',
|
||||||
|
now: 'İndi',
|
||||||
|
backToToday: 'Bugünə qayıt',
|
||||||
|
ok: 'Təsdiq',
|
||||||
|
clear: 'Təmizlə',
|
||||||
|
month: 'Ay',
|
||||||
|
year: 'İl',
|
||||||
|
timeSelect: 'vaxtı seç',
|
||||||
|
dateSelect: 'tarixi seç',
|
||||||
|
weekSelect: 'Həftə seç',
|
||||||
|
monthSelect: 'Ay seç',
|
||||||
|
yearSelect: 'il seç',
|
||||||
|
decadeSelect: 'Onillik seçin',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D.M.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D.M.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Əvvəlki ay (PageUp)',
|
||||||
|
nextMonth: 'Növbəti ay (PageDown)',
|
||||||
|
previousYear: 'Sonuncu il (Control + left)',
|
||||||
|
nextYear: 'Növbəti il (Control + right)',
|
||||||
|
previousDecade: 'Sonuncu onillik',
|
||||||
|
nextDecade: 'Növbəti onillik',
|
||||||
|
previousCentury: 'Sonuncu əsr',
|
||||||
|
nextCentury: 'Növbəti əsr',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'bg_BG',
|
||||||
|
today: 'Днес',
|
||||||
|
now: 'Сега',
|
||||||
|
backToToday: 'Към днес',
|
||||||
|
ok: 'Добре',
|
||||||
|
clear: 'Изчистване',
|
||||||
|
month: 'Месец',
|
||||||
|
year: 'Година',
|
||||||
|
timeSelect: 'Избор на час',
|
||||||
|
dateSelect: 'Избор на дата',
|
||||||
|
monthSelect: 'Избор на месец',
|
||||||
|
yearSelect: 'Избор на година',
|
||||||
|
decadeSelect: 'Десетилетие',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D M YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D M YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Предишен месец (PageUp)',
|
||||||
|
nextMonth: 'Следващ месец (PageDown)',
|
||||||
|
previousYear: 'Последна година (Control + left)',
|
||||||
|
nextYear: 'Следваща година (Control + right)',
|
||||||
|
previousDecade: 'Предишно десетилетие',
|
||||||
|
nextDecade: 'Следващо десетилетие',
|
||||||
|
previousCentury: 'Последен век',
|
||||||
|
nextCentury: 'Следващ век',
|
||||||
|
};
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'by_BY',
|
||||||
|
today: 'Сёння',
|
||||||
|
now: 'Зараз',
|
||||||
|
backToToday: 'Дадзеная дата',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Ачысціць',
|
||||||
|
month: 'Месяц',
|
||||||
|
year: 'Год',
|
||||||
|
timeSelect: 'Выбраць час',
|
||||||
|
dateSelect: 'Выбраць дату',
|
||||||
|
weekSelect: 'Выбраць тыдзень',
|
||||||
|
monthSelect: 'Выбраць месяц',
|
||||||
|
yearSelect: 'Выбраць год',
|
||||||
|
decadeSelect: 'Выбраць дзесяцігоддзе',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D-M-YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D-M-YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Папярэдні месяц (PageUp)',
|
||||||
|
nextMonth: 'Наступны месяц (PageDown)',
|
||||||
|
previousYear: 'Папярэдні год (Control + left)',
|
||||||
|
nextYear: 'Наступны год (Control + right)',
|
||||||
|
previousDecade: 'Папярэдняе дзесяцігоддзе',
|
||||||
|
nextDecade: 'Наступнае дзесяцігоддзе',
|
||||||
|
previousCentury: 'Папярэдні век',
|
||||||
|
nextCentury: 'Наступны век',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ca_ES',
|
||||||
|
today: 'Avui',
|
||||||
|
now: 'Ara',
|
||||||
|
backToToday: 'Tornar a avui',
|
||||||
|
ok: 'Acceptar',
|
||||||
|
clear: 'Netejar',
|
||||||
|
month: 'Mes',
|
||||||
|
year: 'Any',
|
||||||
|
timeSelect: 'Seleccionar hora',
|
||||||
|
dateSelect: 'Seleccionar data',
|
||||||
|
monthSelect: 'Escollir un mes',
|
||||||
|
yearSelect: 'Escollir un any',
|
||||||
|
decadeSelect: 'Escollir una dècada',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Mes anterior (PageUp)',
|
||||||
|
nextMonth: 'Mes següent (PageDown)',
|
||||||
|
previousYear: 'Any anterior (Control + left)',
|
||||||
|
nextYear: 'Mes següent (Control + right)',
|
||||||
|
previousDecade: 'Dècada anterior',
|
||||||
|
nextDecade: 'Dècada següent',
|
||||||
|
previousCentury: 'Segle anterior',
|
||||||
|
nextCentury: 'Segle següent',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'cs_CZ',
|
||||||
|
today: 'Dnes',
|
||||||
|
now: 'Nyní',
|
||||||
|
backToToday: 'Zpět na dnešek',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Vymazat',
|
||||||
|
month: 'Měsíc',
|
||||||
|
year: 'Rok',
|
||||||
|
timeSelect: 'Vybrat čas',
|
||||||
|
dateSelect: 'Vybrat datum',
|
||||||
|
monthSelect: 'Vyberte měsíc',
|
||||||
|
yearSelect: 'Vyberte rok',
|
||||||
|
decadeSelect: 'Vyberte dekádu',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D.M.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D.M.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Předchozí měsíc (PageUp)',
|
||||||
|
nextMonth: 'Následující (PageDown)',
|
||||||
|
previousYear: 'Předchozí rok (Control + left)',
|
||||||
|
nextYear: 'Následující rok (Control + right)',
|
||||||
|
previousDecade: 'Předchozí dekáda',
|
||||||
|
nextDecade: 'Následující dekáda',
|
||||||
|
previousCentury: 'Předchozí století',
|
||||||
|
nextCentury: 'Následující století',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'da_DK',
|
||||||
|
today: 'I dag',
|
||||||
|
now: 'Nu',
|
||||||
|
backToToday: 'Gå til i dag',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Ryd',
|
||||||
|
month: 'Måned',
|
||||||
|
year: 'År',
|
||||||
|
timeSelect: 'Vælg tidspunkt',
|
||||||
|
dateSelect: 'Vælg dato',
|
||||||
|
monthSelect: 'Vælg måned',
|
||||||
|
yearSelect: 'Vælg år',
|
||||||
|
decadeSelect: 'Vælg årti',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Forrige måned (Page Up)',
|
||||||
|
nextMonth: 'Næste måned (Page Down)',
|
||||||
|
previousYear: 'Forrige år (Ctrl-venstre pil)',
|
||||||
|
nextYear: 'Næste år (Ctrl-højre pil)',
|
||||||
|
previousDecade: 'Forrige årti',
|
||||||
|
nextDecade: 'Næste årti',
|
||||||
|
previousCentury: 'Forrige århundrede',
|
||||||
|
nextCentury: 'Næste århundrede',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'de_DE',
|
||||||
|
today: 'Heute',
|
||||||
|
now: 'Jetzt',
|
||||||
|
backToToday: 'Zurück zu Heute',
|
||||||
|
ok: 'OK',
|
||||||
|
clear: 'Zurücksetzen',
|
||||||
|
month: 'Monat',
|
||||||
|
year: 'Jahr',
|
||||||
|
timeSelect: 'Zeit wählen',
|
||||||
|
dateSelect: 'Datum wählen',
|
||||||
|
monthSelect: 'Wähle einen Monat',
|
||||||
|
yearSelect: 'Wähle ein Jahr',
|
||||||
|
decadeSelect: 'Wähle ein Jahrzehnt',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D.M.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D.M.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Vorheriger Monat (PageUp)',
|
||||||
|
nextMonth: 'Nächster Monat (PageDown)',
|
||||||
|
previousYear: 'Vorheriges Jahr (Ctrl + left)',
|
||||||
|
nextYear: 'Nächstes Jahr (Ctrl + right)',
|
||||||
|
previousDecade: 'Vorheriges Jahrzehnt',
|
||||||
|
nextDecade: 'Nächstes Jahrzehnt',
|
||||||
|
previousCentury: 'Vorheriges Jahrhundert',
|
||||||
|
nextCentury: 'Nächstes Jahrhundert',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'el_GR',
|
||||||
|
today: 'Σήμερα',
|
||||||
|
now: 'Τώρα',
|
||||||
|
backToToday: 'Πίσω στη σημερινή μέρα',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Καθαρισμός',
|
||||||
|
month: 'Μήνας',
|
||||||
|
year: 'Έτος',
|
||||||
|
timeSelect: 'Επιλογή ώρας',
|
||||||
|
dateSelect: 'Επιλογή ημερομηνίας',
|
||||||
|
monthSelect: 'Επιλογή μήνα',
|
||||||
|
yearSelect: 'Επιλογή έτους',
|
||||||
|
decadeSelect: 'Επιλογή δεκαετίας',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Προηγούμενος μήνας (PageUp)',
|
||||||
|
nextMonth: 'Επόμενος μήνας (PageDown)',
|
||||||
|
previousYear: 'Προηγούμενο έτος (Control + αριστερά)',
|
||||||
|
nextYear: 'Επόμενο έτος (Control + δεξιά)',
|
||||||
|
previousDecade: 'Προηγούμενη δεκαετία',
|
||||||
|
nextDecade: 'Επόμενη δεκαετία',
|
||||||
|
previousCentury: 'Προηγούμενος αιώνας',
|
||||||
|
nextCentury: 'Επόμενος αιώνας',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'en_GB',
|
||||||
|
today: 'Today',
|
||||||
|
now: 'Now',
|
||||||
|
backToToday: 'Back to today',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Clear',
|
||||||
|
month: 'Month',
|
||||||
|
year: 'Year',
|
||||||
|
timeSelect: 'Select time',
|
||||||
|
dateSelect: 'Select date',
|
||||||
|
monthSelect: 'Choose a month',
|
||||||
|
yearSelect: 'Choose a year',
|
||||||
|
decadeSelect: 'Choose a decade',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Previous month (PageUp)',
|
||||||
|
nextMonth: 'Next month (PageDown)',
|
||||||
|
previousYear: 'Last year (Control + left)',
|
||||||
|
nextYear: 'Next year (Control + right)',
|
||||||
|
previousDecade: 'Last decade',
|
||||||
|
nextDecade: 'Next decade',
|
||||||
|
previousCentury: 'Last century',
|
||||||
|
nextCentury: 'Next century',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'en_US',
|
||||||
|
today: 'Today',
|
||||||
|
now: 'Now',
|
||||||
|
backToToday: 'Back to today',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Clear',
|
||||||
|
month: 'Month',
|
||||||
|
year: 'Year',
|
||||||
|
timeSelect: 'select time',
|
||||||
|
dateSelect: 'select date',
|
||||||
|
weekSelect: 'Choose a week',
|
||||||
|
monthSelect: 'Choose a month',
|
||||||
|
yearSelect: 'Choose a year',
|
||||||
|
decadeSelect: 'Choose a decade',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Previous month (PageUp)',
|
||||||
|
nextMonth: 'Next month (PageDown)',
|
||||||
|
previousYear: 'Last year (Control + left)',
|
||||||
|
nextYear: 'Next year (Control + right)',
|
||||||
|
previousDecade: 'Last decade',
|
||||||
|
nextDecade: 'Next decade',
|
||||||
|
previousCentury: 'Last century',
|
||||||
|
nextCentury: 'Next century',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'es_ES',
|
||||||
|
today: 'Hoy',
|
||||||
|
now: 'Ahora',
|
||||||
|
backToToday: 'Volver a hoy',
|
||||||
|
ok: 'Aceptar',
|
||||||
|
clear: 'Limpiar',
|
||||||
|
month: 'Mes',
|
||||||
|
year: 'Año',
|
||||||
|
timeSelect: 'Seleccionar hora',
|
||||||
|
dateSelect: 'Seleccionar fecha',
|
||||||
|
monthSelect: 'Elegir un mes',
|
||||||
|
yearSelect: 'Elegir un año',
|
||||||
|
decadeSelect: 'Elegir una década',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Mes anterior (PageUp)',
|
||||||
|
nextMonth: 'Mes siguiente (PageDown)',
|
||||||
|
previousYear: 'Año anterior (Control + left)',
|
||||||
|
nextYear: 'Año siguiente (Control + right)',
|
||||||
|
previousDecade: 'Década anterior',
|
||||||
|
nextDecade: 'Década siguiente',
|
||||||
|
previousCentury: 'Siglo anterior',
|
||||||
|
nextCentury: 'Siglo siguiente',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'et_EE',
|
||||||
|
today: 'Täna',
|
||||||
|
now: 'Praegu',
|
||||||
|
backToToday: 'Tagasi tänase juurde',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Tühista',
|
||||||
|
month: 'Kuu',
|
||||||
|
year: 'Aasta',
|
||||||
|
timeSelect: 'Vali aeg',
|
||||||
|
dateSelect: 'Vali kuupäev',
|
||||||
|
monthSelect: 'Vali kuu',
|
||||||
|
yearSelect: 'Vali aasta',
|
||||||
|
decadeSelect: 'Vali dekaad',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D.M.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D.M.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Eelmine kuu (PageUp)',
|
||||||
|
nextMonth: 'Järgmine kuu (PageDown)',
|
||||||
|
previousYear: 'Eelmine aasta (Control + left)',
|
||||||
|
nextYear: 'Järgmine aasta (Control + right)',
|
||||||
|
previousDecade: 'Eelmine dekaad',
|
||||||
|
nextDecade: 'Järgmine dekaad',
|
||||||
|
previousCentury: 'Eelmine sajand',
|
||||||
|
nextCentury: 'Järgmine sajand',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'fa_IR',
|
||||||
|
today: 'امروز',
|
||||||
|
now: 'اکنون',
|
||||||
|
backToToday: 'بازگشت به روز',
|
||||||
|
ok: 'باشه',
|
||||||
|
clear: 'پاک کردن',
|
||||||
|
month: 'ماه',
|
||||||
|
year: 'سال',
|
||||||
|
timeSelect: 'انتخاب زمان',
|
||||||
|
dateSelect: 'انتخاب تاریخ',
|
||||||
|
monthSelect: 'یک ماه را انتخاب کنید',
|
||||||
|
yearSelect: 'یک سال را انتخاب کنید',
|
||||||
|
decadeSelect: 'یک دهه را انتخاب کنید',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'ماه قبل (PageUp)',
|
||||||
|
nextMonth: 'ماه بعد (PageDown)',
|
||||||
|
previousYear: 'سال قبل (Control + left)',
|
||||||
|
nextYear: 'سال بعد (Control + right)',
|
||||||
|
previousDecade: 'دهه قبل',
|
||||||
|
nextDecade: 'دهه بعد',
|
||||||
|
previousCentury: 'قرن قبل',
|
||||||
|
nextCentury: 'قرن بعد',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'fi_FI',
|
||||||
|
today: 'Tänään',
|
||||||
|
now: 'Nyt',
|
||||||
|
backToToday: 'Tämä päivä',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Tyhjennä',
|
||||||
|
month: 'Kuukausi',
|
||||||
|
year: 'Vuosi',
|
||||||
|
timeSelect: 'Valise aika',
|
||||||
|
dateSelect: 'Valitse päivä',
|
||||||
|
monthSelect: 'Valitse kuukausi',
|
||||||
|
yearSelect: 'Valitse vuosi',
|
||||||
|
decadeSelect: 'Valitse vuosikymmen',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D.M.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D.M.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Edellinen kuukausi (PageUp)',
|
||||||
|
nextMonth: 'Seuraava kuukausi (PageDown)',
|
||||||
|
previousYear: 'Edellinen vuosi (Control + left)',
|
||||||
|
nextYear: 'Seuraava vuosi (Control + right)',
|
||||||
|
previousDecade: 'Edellinen vuosikymmen',
|
||||||
|
nextDecade: 'Seuraava vuosikymmen',
|
||||||
|
previousCentury: 'Edellinen vuosisata',
|
||||||
|
nextCentury: 'Seuraava vuosisata',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'fr_BE',
|
||||||
|
today: "Aujourd'hui",
|
||||||
|
now: 'Maintenant',
|
||||||
|
backToToday: "Aujourd'hui",
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Rétablir',
|
||||||
|
month: 'Mois',
|
||||||
|
year: 'Année',
|
||||||
|
timeSelect: "Sélectionner l'heure",
|
||||||
|
dateSelect: "Sélectionner l'heure",
|
||||||
|
monthSelect: 'Choisissez un mois',
|
||||||
|
yearSelect: 'Choisissez une année',
|
||||||
|
decadeSelect: 'Choisissez une décennie',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Mois précédent (PageUp)',
|
||||||
|
nextMonth: 'Mois suivant (PageDown)',
|
||||||
|
previousYear: 'Année précédente (Ctrl + gauche)',
|
||||||
|
nextYear: 'Année prochaine (Ctrl + droite)',
|
||||||
|
previousDecade: 'Décennie précédente',
|
||||||
|
nextDecade: 'Décennie suivante',
|
||||||
|
previousCentury: 'Siècle précédent',
|
||||||
|
nextCentury: 'Siècle suivant',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'fr_CA',
|
||||||
|
today: "Aujourd'hui",
|
||||||
|
now: 'Maintenant',
|
||||||
|
backToToday: "Aujourd'hui",
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Rétablir',
|
||||||
|
month: 'Mois',
|
||||||
|
year: 'Année',
|
||||||
|
timeSelect: "Sélectionner l'heure",
|
||||||
|
dateSelect: 'Sélectionner la date',
|
||||||
|
monthSelect: 'Choisissez un mois',
|
||||||
|
yearSelect: 'Choisissez une année',
|
||||||
|
decadeSelect: 'Choisissez une décennie',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'DD/MM/YYYY',
|
||||||
|
dayFormat: 'DD',
|
||||||
|
dateTimeFormat: 'DD/MM/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Mois précédent (PageUp)',
|
||||||
|
nextMonth: 'Mois suivant (PageDown)',
|
||||||
|
previousYear: 'Année précédente (Ctrl + gauche)',
|
||||||
|
nextYear: 'Année prochaine (Ctrl + droite)',
|
||||||
|
previousDecade: 'Décennie précédente',
|
||||||
|
nextDecade: 'Décennie suivante',
|
||||||
|
previousCentury: 'Siècle précédent',
|
||||||
|
nextCentury: 'Siècle suivant',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'fr_FR',
|
||||||
|
today: "Aujourd'hui",
|
||||||
|
now: 'Maintenant',
|
||||||
|
backToToday: "Aujourd'hui",
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Rétablir',
|
||||||
|
month: 'Mois',
|
||||||
|
year: 'Année',
|
||||||
|
timeSelect: "Sélectionner l'heure",
|
||||||
|
dateSelect: 'Sélectionner la date',
|
||||||
|
monthSelect: 'Choisissez un mois',
|
||||||
|
yearSelect: 'Choisissez une année',
|
||||||
|
decadeSelect: 'Choisissez une décennie',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'DD/MM/YYYY',
|
||||||
|
dayFormat: 'DD',
|
||||||
|
dateTimeFormat: 'DD/MM/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Mois précédent (PageUp)',
|
||||||
|
nextMonth: 'Mois suivant (PageDown)',
|
||||||
|
previousYear: 'Année précédente (Ctrl + gauche)',
|
||||||
|
nextYear: 'Année prochaine (Ctrl + droite)',
|
||||||
|
previousDecade: 'Décennie précédente',
|
||||||
|
nextDecade: 'Décennie suivante',
|
||||||
|
previousCentury: 'Siècle précédent',
|
||||||
|
nextCentury: 'Siècle suivant',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ga_IE',
|
||||||
|
today: 'inniu',
|
||||||
|
now: 'anois',
|
||||||
|
backToToday: 'Ar ais inniu',
|
||||||
|
ok: 'ceart go leor',
|
||||||
|
clear: 'soiléir',
|
||||||
|
month: 'mhí',
|
||||||
|
year: 'bhliain',
|
||||||
|
timeSelect: 'roghnaigh am',
|
||||||
|
dateSelect: 'roghnaigh dáta',
|
||||||
|
weekSelect: 'Roghnaigh seachtain',
|
||||||
|
monthSelect: 'Roghnaigh mí',
|
||||||
|
yearSelect: 'Roghnaigh bliain',
|
||||||
|
decadeSelect: 'Roghnaigh deich mbliana',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'An mhí roimhe seo (PageUp)',
|
||||||
|
nextMonth: 'An mhí seo chugainn (PageDown)',
|
||||||
|
previousYear: 'Anuraidh (Control + left)',
|
||||||
|
nextYear: 'An bhliain seo chugainn (Control + right)',
|
||||||
|
previousDecade: 'Le deich mbliana anuas',
|
||||||
|
nextDecade: 'Deich mbliana amach romhainn',
|
||||||
|
previousCentury: 'An chéid seo caite',
|
||||||
|
nextCentury: 'An chéad aois eile',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'gl_ES',
|
||||||
|
today: 'Hoxe',
|
||||||
|
now: 'Agora',
|
||||||
|
backToToday: 'Voltar a hoxe',
|
||||||
|
ok: 'Aceptar',
|
||||||
|
clear: 'Limpar',
|
||||||
|
month: 'Mes',
|
||||||
|
year: 'Ano',
|
||||||
|
timeSelect: 'Seleccionar hora',
|
||||||
|
dateSelect: 'Seleccionar data',
|
||||||
|
monthSelect: 'Elexir un mes',
|
||||||
|
yearSelect: 'Elexir un año',
|
||||||
|
decadeSelect: 'Elexir unha década',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Mes anterior (PageUp)',
|
||||||
|
nextMonth: 'Mes seguinte (PageDown)',
|
||||||
|
previousYear: 'Ano anterior (Control + left)',
|
||||||
|
nextYear: 'Ano seguinte (Control + right)',
|
||||||
|
previousDecade: 'Década anterior',
|
||||||
|
nextDecade: 'Década seguinte',
|
||||||
|
previousCentury: 'Século anterior',
|
||||||
|
nextCentury: 'Século seguinte',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'he_IL',
|
||||||
|
today: 'היום',
|
||||||
|
now: 'עכשיו',
|
||||||
|
backToToday: 'חזור להיום',
|
||||||
|
ok: 'אישור',
|
||||||
|
clear: 'איפוס',
|
||||||
|
month: 'חודש',
|
||||||
|
year: 'שנה',
|
||||||
|
timeSelect: 'בחר שעה',
|
||||||
|
dateSelect: 'בחר תאריך',
|
||||||
|
weekSelect: 'בחר שבוע',
|
||||||
|
monthSelect: 'בחר חודש',
|
||||||
|
yearSelect: 'בחר שנה',
|
||||||
|
decadeSelect: 'בחר עשור',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'חודש קודם (PageUp)',
|
||||||
|
nextMonth: 'חודש הבא (PageDown)',
|
||||||
|
previousYear: 'שנה שעברה (Control + left)',
|
||||||
|
nextYear: 'שנה הבאה (Control + right)',
|
||||||
|
previousDecade: 'העשור הקודם',
|
||||||
|
nextDecade: 'העשור הבא',
|
||||||
|
previousCentury: 'המאה הקודמת',
|
||||||
|
nextCentury: 'המאה הבאה',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'hi_IN',
|
||||||
|
today: 'आज',
|
||||||
|
now: 'अभी',
|
||||||
|
backToToday: 'आज तक',
|
||||||
|
ok: 'ठीक',
|
||||||
|
clear: 'स्पष्ट',
|
||||||
|
month: 'महीना',
|
||||||
|
year: 'साल',
|
||||||
|
timeSelect: 'समय का चयन करें',
|
||||||
|
dateSelect: 'तारीख़ चुनें',
|
||||||
|
weekSelect: 'एक सप्ताह चुनें',
|
||||||
|
monthSelect: 'एक महीना चुनें',
|
||||||
|
yearSelect: 'एक वर्ष चुनें',
|
||||||
|
decadeSelect: 'एक दशक चुनें',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'पिछला महीना (पेजअप)',
|
||||||
|
nextMonth: 'अगले महीने (पेजडाउन)',
|
||||||
|
previousYear: 'पिछले साल (Ctrl + बाएं)',
|
||||||
|
nextYear: 'अगले साल (Ctrl + दाहिना)',
|
||||||
|
previousDecade: 'पिछला दशक',
|
||||||
|
nextDecade: 'अगले दशक',
|
||||||
|
previousCentury: 'पीछ्ली शताब्दी',
|
||||||
|
nextCentury: 'अगली सदी',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'hr_HR',
|
||||||
|
today: 'Danas',
|
||||||
|
now: 'Sad',
|
||||||
|
backToToday: 'Natrag na danas',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Očisti',
|
||||||
|
month: 'Mjesec',
|
||||||
|
year: 'Godina',
|
||||||
|
timeSelect: 'odaberite vrijeme',
|
||||||
|
dateSelect: 'odaberite datum',
|
||||||
|
weekSelect: 'Odaberite tjedan',
|
||||||
|
monthSelect: 'Odaberite mjesec',
|
||||||
|
yearSelect: 'Odaberite godinu',
|
||||||
|
decadeSelect: 'Odaberite desetljeće',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D.M.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D.M.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Prošli mjesec (PageUp)',
|
||||||
|
nextMonth: 'Sljedeći mjesec (PageDown)',
|
||||||
|
previousYear: 'Prošla godina (Control + left)',
|
||||||
|
nextYear: 'Sljedeća godina (Control + right)',
|
||||||
|
previousDecade: 'Prošlo desetljeće',
|
||||||
|
nextDecade: 'Sljedeće desetljeće',
|
||||||
|
previousCentury: 'Prošlo stoljeće',
|
||||||
|
nextCentury: 'Sljedeće stoljeće',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'hu_HU',
|
||||||
|
today: 'Ma', // 'Today',
|
||||||
|
now: 'Most', // 'Now',
|
||||||
|
backToToday: 'Vissza a mai napra', // 'Back to today',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Törlés', // 'Clear',
|
||||||
|
month: 'Hónap', // 'Month',
|
||||||
|
year: 'Év', // 'Year',
|
||||||
|
timeSelect: 'Időpont kiválasztása', // 'Select time',
|
||||||
|
dateSelect: 'Dátum kiválasztása', // 'Select date',
|
||||||
|
monthSelect: 'Hónap kiválasztása', // 'Choose a month',
|
||||||
|
yearSelect: 'Év kiválasztása', // 'Choose a year',
|
||||||
|
decadeSelect: 'Évtized kiválasztása', // 'Choose a decade',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'YYYY/MM/DD', // 'M/D/YYYY',
|
||||||
|
dayFormat: 'DD', // 'D',
|
||||||
|
dateTimeFormat: 'YYYY/MM/DD HH:mm:ss', // 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Előző hónap (PageUp)', // 'Previous month (PageUp)',
|
||||||
|
nextMonth: 'Következő hónap (PageDown)', // 'Next month (PageDown)',
|
||||||
|
previousYear: 'Múlt év (Control + left)', // 'Last year (Control + left)',
|
||||||
|
nextYear: 'Jövő év (Control + right)', // 'Next year (Control + right)',
|
||||||
|
previousDecade: 'Előző évtized', // 'Last decade',
|
||||||
|
nextDecade: 'Következő évtized', // 'Next decade',
|
||||||
|
previousCentury: 'Múlt évszázad', // 'Last century',
|
||||||
|
nextCentury: 'Jövő évszázad', // 'Next century',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'id_ID',
|
||||||
|
today: 'Hari ini',
|
||||||
|
now: 'Sekarang',
|
||||||
|
backToToday: 'Kembali ke hari ini',
|
||||||
|
ok: 'Baik',
|
||||||
|
clear: 'Bersih',
|
||||||
|
month: 'Bulan',
|
||||||
|
year: 'Tahun',
|
||||||
|
timeSelect: 'pilih waktu',
|
||||||
|
dateSelect: 'pilih tanggal',
|
||||||
|
weekSelect: 'Pilih satu minggu',
|
||||||
|
monthSelect: 'Pilih satu bulan',
|
||||||
|
yearSelect: 'Pilih satu tahun',
|
||||||
|
decadeSelect: 'Pilih satu dekade',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Bulan sebelumnya (PageUp)',
|
||||||
|
nextMonth: 'Bulan selanjutnya (PageDown)',
|
||||||
|
previousYear: 'Tahun lalu (Control + kiri)',
|
||||||
|
nextYear: 'Tahun selanjutnya (Kontrol + kanan)',
|
||||||
|
previousDecade: 'Dekade terakhir',
|
||||||
|
nextDecade: 'Dekade berikutnya',
|
||||||
|
previousCentury: 'Abad terakhir',
|
||||||
|
nextCentury: 'Abad berikutnya',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'is_IS',
|
||||||
|
today: 'Í dag',
|
||||||
|
now: 'Núna',
|
||||||
|
backToToday: 'Til baka til dagsins í dag',
|
||||||
|
ok: 'Í lagi',
|
||||||
|
clear: 'Hreinsa',
|
||||||
|
month: 'Mánuður',
|
||||||
|
year: 'Ár',
|
||||||
|
timeSelect: 'Velja tíma',
|
||||||
|
dateSelect: 'Velja dag',
|
||||||
|
monthSelect: 'Velja mánuð',
|
||||||
|
yearSelect: 'Velja ár',
|
||||||
|
decadeSelect: 'Velja áratug',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Fyrri mánuður (PageUp)',
|
||||||
|
nextMonth: 'Næsti mánuður (PageDown)',
|
||||||
|
previousYear: 'Fyrra ár (Control + left)',
|
||||||
|
nextYear: 'Næsta ár (Control + right)',
|
||||||
|
previousDecade: 'Fyrri áratugur',
|
||||||
|
nextDecade: 'Næsti áratugur',
|
||||||
|
previousCentury: 'Fyrri öld',
|
||||||
|
nextCentury: 'Næsta öld',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'it_IT',
|
||||||
|
today: 'Oggi',
|
||||||
|
now: 'Adesso',
|
||||||
|
backToToday: 'Torna ad oggi',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Cancella',
|
||||||
|
month: 'Mese',
|
||||||
|
year: 'Anno',
|
||||||
|
timeSelect: "Seleziona l'ora",
|
||||||
|
dateSelect: 'Seleziona la data',
|
||||||
|
monthSelect: 'Seleziona il mese',
|
||||||
|
yearSelect: "Seleziona l'anno",
|
||||||
|
decadeSelect: 'Seleziona il decennio',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Il mese scorso (PageUp)',
|
||||||
|
nextMonth: 'Il prossimo mese (PageDown)',
|
||||||
|
previousYear: "L'anno scorso (Control + sinistra)",
|
||||||
|
nextYear: "L'anno prossimo (Control + destra)",
|
||||||
|
previousDecade: 'Ultimo decennio',
|
||||||
|
nextDecade: 'Prossimo decennio',
|
||||||
|
previousCentury: 'Secolo precedente',
|
||||||
|
nextCentury: 'Prossimo secolo',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ja_JP',
|
||||||
|
today: '今日',
|
||||||
|
now: '現在時刻',
|
||||||
|
backToToday: '今日に戻る',
|
||||||
|
ok: '決定',
|
||||||
|
timeSelect: '時間を選択',
|
||||||
|
dateSelect: '日時を選択',
|
||||||
|
weekSelect: '週を選択',
|
||||||
|
clear: 'クリア',
|
||||||
|
month: '月',
|
||||||
|
year: '年',
|
||||||
|
previousMonth: '前月 (ページアップキー)',
|
||||||
|
nextMonth: '翌月 (ページダウンキー)',
|
||||||
|
monthSelect: '月を選択',
|
||||||
|
yearSelect: '年を選択',
|
||||||
|
decadeSelect: '年代を選択',
|
||||||
|
yearFormat: 'YYYY年',
|
||||||
|
dayFormat: 'D日',
|
||||||
|
dateFormat: 'YYYY年M月D日',
|
||||||
|
dateTimeFormat: 'YYYY年M月D日 HH時mm分ss秒',
|
||||||
|
previousYear: '前年 (Controlを押しながら左キー)',
|
||||||
|
nextYear: '翌年 (Controlを押しながら右キー)',
|
||||||
|
previousDecade: '前の年代',
|
||||||
|
nextDecade: '次の年代',
|
||||||
|
previousCentury: '前の世紀',
|
||||||
|
nextCentury: '次の世紀',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'kk_KZ',
|
||||||
|
today: 'Бүгін',
|
||||||
|
now: 'Қазір',
|
||||||
|
backToToday: 'Ағымдағы күн',
|
||||||
|
ok: 'Таңдау',
|
||||||
|
clear: 'Таза',
|
||||||
|
month: 'Ай',
|
||||||
|
year: 'Жыл',
|
||||||
|
timeSelect: 'Уақытты таңдау',
|
||||||
|
dateSelect: 'Күнді таңдау',
|
||||||
|
monthSelect: 'Айды таңдаңыз',
|
||||||
|
yearSelect: 'Жылды таңдаңыз',
|
||||||
|
decadeSelect: 'Онжылды таңдаңыз',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D-M-YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D-M-YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Алдыңғы ай (PageUp)',
|
||||||
|
nextMonth: 'Келесі ай (PageDown)',
|
||||||
|
previousYear: 'Алдыңғы жыл (Control + left)',
|
||||||
|
nextYear: 'Келесі жыл (Control + right)',
|
||||||
|
previousDecade: 'Алдыңғы онжылдық',
|
||||||
|
nextDecade: 'Келесі онжылдық',
|
||||||
|
previousCentury: 'Алдыңғы ғасыр',
|
||||||
|
nextCentury: 'Келесі ғасыр',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'km',
|
||||||
|
today: 'ថ្ងៃនេះ',
|
||||||
|
now: 'ឥឡូវនេះ',
|
||||||
|
backToToday: 'ត្រលប់ទៅថ្ងៃនេះ',
|
||||||
|
ok: 'កំណត់',
|
||||||
|
timeSelect: 'រយៈពេលជ្រើសរើស',
|
||||||
|
dateSelect: 'ជ្រើសរើសកាលបរិច្ឆេទ',
|
||||||
|
weekSelect: 'ជ្រើសរើសសប្តាហ៍',
|
||||||
|
clear: 'ច្បាស់',
|
||||||
|
month: 'ខែ',
|
||||||
|
year: 'ឆ្នាំ',
|
||||||
|
previousMonth: 'ខែមុន (ឡើងទំព័រ)',
|
||||||
|
nextMonth: 'ខែបន្ទាប់ (ប៊ូតុងចុះទំព័រ)',
|
||||||
|
monthSelect: 'ជ្រើសរើសខែ',
|
||||||
|
yearSelect: 'ជ្រើសរើសឆ្នាំ',
|
||||||
|
decadeSelect: 'ជ្រើសរើសអាយុ',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateFormat: 'YYYY-M-D',
|
||||||
|
dateTimeFormat: 'YYYY-M-D HH:mm:ss',
|
||||||
|
previousYear: 'ឆ្នាំមុន (Controlគ្រាប់ចុចបូកព្រួញខាងឆ្វេង)',
|
||||||
|
nextYear: 'ឆ្នាំក្រោយ (Control គ្រាប់ចុចបូកព្រួញស្ដាំ)',
|
||||||
|
previousDecade: 'ជំនាន់ចុងក្រោយ',
|
||||||
|
nextDecade: 'ជំនាន់ក្រោយ',
|
||||||
|
previousCentury: 'សតវត្សចុងក្រោយ',
|
||||||
|
nextCentury: 'សតវត្សរ៍បន្ទាប់',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ku',
|
||||||
|
today: 'Îro',
|
||||||
|
now: 'Niha',
|
||||||
|
backToToday: 'Vegere îro',
|
||||||
|
ok: 'Temam',
|
||||||
|
clear: 'Paqij bike',
|
||||||
|
month: 'Meh',
|
||||||
|
year: 'Sal',
|
||||||
|
timeSelect: 'Demê hilbijêre',
|
||||||
|
dateSelect: 'Dîrok hilbijêre',
|
||||||
|
monthSelect: 'Meh hilbijêre',
|
||||||
|
yearSelect: 'Sal hilbijêre',
|
||||||
|
decadeSelect: 'Dehsal hilbijêre',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Meha peş (PageUp))',
|
||||||
|
nextMonth: 'Meha paş (PageDown)',
|
||||||
|
previousYear: 'Sala peş (Control + şep)',
|
||||||
|
nextYear: 'Sala paş (Control + rast)',
|
||||||
|
previousDecade: 'Dehsalen peş',
|
||||||
|
nextDecade: 'Dehsalen paş',
|
||||||
|
previousCentury: 'Sedsalen peş',
|
||||||
|
nextCentury: 'Sedsalen paş',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'kn_IN',
|
||||||
|
today: 'ಇಂದು',
|
||||||
|
now: 'ಈಗ',
|
||||||
|
backToToday: 'ಇಂದು ಹಿಂದಿರುಗಿ',
|
||||||
|
ok: 'ಸರಿ',
|
||||||
|
clear: 'ಸ್ಪಷ್ಟ',
|
||||||
|
month: 'ತಿಂಗಳು',
|
||||||
|
year: 'ವರ್ಷ',
|
||||||
|
timeSelect: 'ಸಮಯ ಆಯ್ಕೆಮಾಡಿ',
|
||||||
|
dateSelect: 'ದಿನಾಂಕವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ',
|
||||||
|
weekSelect: 'ಒಂದು ವಾರದ ಆರಿಸಿ',
|
||||||
|
monthSelect: 'ಒಂದು ತಿಂಗಳು ಆಯ್ಕೆಮಾಡಿ',
|
||||||
|
yearSelect: 'ಒಂದು ವರ್ಷ ಆರಿಸಿ',
|
||||||
|
decadeSelect: 'ಒಂದು ದಶಕದ ಆಯ್ಕೆಮಾಡಿ',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'ಹಿಂದಿನ ತಿಂಗಳು (ಪೇಜ್ಅಪ್)',
|
||||||
|
nextMonth: 'ಮುಂದಿನ ತಿಂಗಳು (ಪೇಜ್ಡೌನ್)',
|
||||||
|
previousYear: 'ಕಳೆದ ವರ್ಷ (Ctrl + ಎಡ)',
|
||||||
|
nextYear: 'ಮುಂದಿನ ವರ್ಷ (Ctrl + ಬಲ)',
|
||||||
|
previousDecade: 'ಕಳೆದ ದಶಕ',
|
||||||
|
nextDecade: 'ಮುಂದಿನ ದಶಕ',
|
||||||
|
previousCentury: 'ಕಳೆದ ಶತಮಾನ',
|
||||||
|
nextCentury: 'ಮುಂದಿನ ಶತಮಾನ',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ko_KR',
|
||||||
|
today: '오늘',
|
||||||
|
now: '현재 시각',
|
||||||
|
backToToday: '오늘로 돌아가기',
|
||||||
|
ok: '확인',
|
||||||
|
clear: '지우기',
|
||||||
|
month: '월',
|
||||||
|
year: '년',
|
||||||
|
timeSelect: '시간 선택',
|
||||||
|
dateSelect: '날짜 선택',
|
||||||
|
monthSelect: '달 선택',
|
||||||
|
yearSelect: '연 선택',
|
||||||
|
decadeSelect: '연대 선택',
|
||||||
|
yearFormat: 'YYYY년',
|
||||||
|
dateFormat: 'YYYY-MM-DD',
|
||||||
|
dayFormat: 'Do',
|
||||||
|
dateTimeFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
monthBeforeYear: false,
|
||||||
|
previousMonth: '이전 달 (PageUp)',
|
||||||
|
nextMonth: '다음 달 (PageDown)',
|
||||||
|
previousYear: '이전 해 (Control + left)',
|
||||||
|
nextYear: '다음 해 (Control + right)',
|
||||||
|
previousDecade: '이전 연대',
|
||||||
|
nextDecade: '다음 연대',
|
||||||
|
previousCentury: '이전 세기',
|
||||||
|
nextCentury: '다음 세기',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'lt_LT',
|
||||||
|
today: 'Šiandien',
|
||||||
|
now: 'Dabar',
|
||||||
|
backToToday: 'Rodyti šiandien',
|
||||||
|
ok: 'Gerai',
|
||||||
|
clear: 'Išvalyti',
|
||||||
|
month: 'Mėnesis',
|
||||||
|
year: 'Metai',
|
||||||
|
timeSelect: 'Pasirinkti laiką',
|
||||||
|
dateSelect: 'Pasirinkti datą',
|
||||||
|
monthSelect: 'Pasirinkti mėnesį',
|
||||||
|
yearSelect: 'Pasirinkti metus',
|
||||||
|
decadeSelect: 'Pasirinkti dešimtmetį',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'YYYY-MM-DD',
|
||||||
|
dayFormat: 'DD',
|
||||||
|
dateTimeFormat: 'YYYY-MM-DD HH:MM:SS',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Buvęs mėnesis (PageUp)',
|
||||||
|
nextMonth: 'Sekantis mėnesis (PageDown)',
|
||||||
|
previousYear: 'Buvę metai (Control + left)',
|
||||||
|
nextYear: 'Sekantis metai (Control + right)',
|
||||||
|
previousDecade: 'Buvęs dešimtmetis',
|
||||||
|
nextDecade: 'Sekantis dešimtmetis',
|
||||||
|
previousCentury: 'Buvęs amžius',
|
||||||
|
nextCentury: 'Sekantis amžius',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'lv_LV',
|
||||||
|
today: 'Šodien',
|
||||||
|
now: 'Tagad',
|
||||||
|
backToToday: 'Atpakaļ pie šodienas',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Skaidrs',
|
||||||
|
month: 'Mēnesis',
|
||||||
|
year: 'Gads',
|
||||||
|
timeSelect: 'Izvēlieties laiku',
|
||||||
|
dateSelect: 'Izvēlieties datumu',
|
||||||
|
monthSelect: 'Izvēlieties mēnesi',
|
||||||
|
yearSelect: 'Izvēlieties gadu',
|
||||||
|
decadeSelect: 'Izvēlieties desmit gadus',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D.M.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D.M.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Iepriekšējais mēnesis (PageUp)',
|
||||||
|
nextMonth: 'Nākammēnes (PageDown)',
|
||||||
|
previousYear: 'Pagājušais gads (Control + left)',
|
||||||
|
nextYear: 'Nākamgad (Control + right)',
|
||||||
|
previousDecade: 'Pēdējā desmitgadē',
|
||||||
|
nextDecade: 'Nākamā desmitgade',
|
||||||
|
previousCentury: 'Pagājušajā gadsimtā',
|
||||||
|
nextCentury: 'Nākamajā gadsimtā',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'mk_MK',
|
||||||
|
today: 'Денес',
|
||||||
|
now: 'Сега',
|
||||||
|
backToToday: 'Назад до денес',
|
||||||
|
ok: 'ОК',
|
||||||
|
clear: 'Избриши',
|
||||||
|
month: 'Месец',
|
||||||
|
year: 'Година',
|
||||||
|
timeSelect: 'Избери време',
|
||||||
|
dateSelect: 'Избери датум',
|
||||||
|
monthSelect: 'Избери месец',
|
||||||
|
yearSelect: 'Избери година',
|
||||||
|
decadeSelect: 'Избери деценија',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D.M.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D.M.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Претходен месец (PageUp)',
|
||||||
|
nextMonth: 'Нареден месец (PageDown)',
|
||||||
|
previousYear: 'Претходна година (Control + left)',
|
||||||
|
nextYear: 'Наредна година (Control + right)',
|
||||||
|
previousDecade: 'Претходна деценија',
|
||||||
|
nextDecade: 'Наредна деценија',
|
||||||
|
previousCentury: 'Претходен век',
|
||||||
|
nextCentury: 'Нареден век',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ml_IN',
|
||||||
|
today: 'ഇന്ന്',
|
||||||
|
now: 'ഇപ്പോൾ',
|
||||||
|
backToToday: 'ഇന്നത്തെ ദിവസത്തിലേക്ക് തിരിച്ചു പോകുക',
|
||||||
|
ok: 'ശരിയാണ്',
|
||||||
|
clear: 'നീക്കം ചെയ്യുക',
|
||||||
|
month: 'മാസം',
|
||||||
|
year: 'വർഷം',
|
||||||
|
timeSelect: 'സമയം തിരഞ്ഞെടുക്കുക',
|
||||||
|
dateSelect: 'ദിവസം തിരഞ്ഞെടുക്കുക',
|
||||||
|
weekSelect: 'വാരം തിരഞ്ഞെടുക്കുക',
|
||||||
|
monthSelect: 'മാസം തിരഞ്ഞെടുക്കുക',
|
||||||
|
yearSelect: 'വർഷം തിരഞ്ഞെടുക്കുക',
|
||||||
|
decadeSelect: 'ദശാബ്ദം തിരഞ്ഞെടുക്കുക',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'കഴിഞ്ഞ മാസം (PageUp)',
|
||||||
|
nextMonth: 'അടുത്ത മാസം (PageDown)',
|
||||||
|
previousYear: 'കഴിഞ്ഞ വർഷം (Control + left)',
|
||||||
|
nextYear: 'അടുത്ത വർഷം (Control + right)',
|
||||||
|
previousDecade: 'കഴിഞ്ഞ ദശാബ്ദം',
|
||||||
|
nextDecade: 'അടുത്ത ദശാബ്ദം',
|
||||||
|
previousCentury: 'കഴിഞ്ഞ നൂറ്റാണ്ട്',
|
||||||
|
nextCentury: 'അടുത്ത നൂറ്റാണ്ട്',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'mm_MM',
|
||||||
|
today: 'ယနေ့',
|
||||||
|
now: 'ယခု',
|
||||||
|
backToToday: 'ယနေ့ မတိုင်ခင် သို့',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'ရှင်းမည်',
|
||||||
|
month: 'လ',
|
||||||
|
year: 'နှစ်',
|
||||||
|
timeSelect: 'အချိန်ကို ရွေး',
|
||||||
|
dateSelect: 'နေ့ကို ရွေး',
|
||||||
|
weekSelect: 'အပတ်ကို ရွေး',
|
||||||
|
monthSelect: 'လကို ရွေး',
|
||||||
|
yearSelect: 'နှစ်ကို ရွေး',
|
||||||
|
decadeSelect: 'ဆယ်စုနှစ်ကို ရွေး',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'ယခင် လ (PageUp)',
|
||||||
|
nextMonth: 'နောက် လ (PageDown)',
|
||||||
|
previousYear: 'ယခင် နှစ် (Control + left)',
|
||||||
|
nextYear: 'နောက် နှစ် (Control + right)',
|
||||||
|
previousDecade: 'ယခင် ဆယ်စုနှစ်',
|
||||||
|
nextDecade: 'နောက် ဆယ်စုနှစ်',
|
||||||
|
previousCentury: 'ယခင် ရာစုနှစ်',
|
||||||
|
nextCentury: 'နောက် ရာစုနှစ်',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'mn_MN',
|
||||||
|
today: 'Өнөөдөр',
|
||||||
|
now: 'Одоо',
|
||||||
|
backToToday: 'Өнөөдөрлүү буцах',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Цэвэрлэх',
|
||||||
|
month: 'Сар',
|
||||||
|
year: 'Жил',
|
||||||
|
timeSelect: 'Цаг сонгох',
|
||||||
|
dateSelect: 'Огноо сонгох',
|
||||||
|
weekSelect: '7 хоног сонгох',
|
||||||
|
monthSelect: 'Сар сонгох',
|
||||||
|
yearSelect: 'Жил сонгох',
|
||||||
|
decadeSelect: 'Арван сонгох',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'YYYY/MM/DD',
|
||||||
|
dayFormat: 'DD',
|
||||||
|
dateTimeFormat: 'YYYY/MM/DD HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Өмнөх сар (PageUp)',
|
||||||
|
nextMonth: 'Дараа сар (PageDown)',
|
||||||
|
previousYear: 'Өмнөх жил (Control + left)',
|
||||||
|
nextYear: 'Дараа жил (Control + right)',
|
||||||
|
previousDecade: 'Өмнөх арван',
|
||||||
|
nextDecade: 'Дараа арван',
|
||||||
|
previousCentury: 'Өмнөх зуун',
|
||||||
|
nextCentury: 'Дараа зуун',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ms_MY',
|
||||||
|
today: 'Hari ini',
|
||||||
|
now: 'Sekarang',
|
||||||
|
backToToday: 'Kembali ke hari ini',
|
||||||
|
ok: 'Ok',
|
||||||
|
timeSelect: 'Pilih masa',
|
||||||
|
dateSelect: 'Pilih tarikh',
|
||||||
|
weekSelect: 'Pilih minggu',
|
||||||
|
clear: 'Padam',
|
||||||
|
month: 'Bulan',
|
||||||
|
year: 'Tahun',
|
||||||
|
previousMonth: 'Bulan lepas',
|
||||||
|
nextMonth: 'Bulan depan',
|
||||||
|
monthSelect: 'Pilih bulan',
|
||||||
|
yearSelect: 'Pilih tahun',
|
||||||
|
decadeSelect: 'Pilih dekad',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
previousYear: 'Tahun lepas (Ctrl+left)',
|
||||||
|
nextYear: 'Tahun depan (Ctrl+right)',
|
||||||
|
previousDecade: 'Dekad lepas',
|
||||||
|
nextDecade: 'Dekad depan',
|
||||||
|
previousCentury: 'Abad lepas',
|
||||||
|
nextCentury: 'Abad depan',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'nb_NO',
|
||||||
|
today: 'I dag',
|
||||||
|
now: 'Nå',
|
||||||
|
backToToday: 'Gå til i dag',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Annuller',
|
||||||
|
month: 'Måned',
|
||||||
|
year: 'År',
|
||||||
|
timeSelect: 'Velg tidspunkt',
|
||||||
|
dateSelect: 'Velg dato',
|
||||||
|
weekSelect: 'Velg uke',
|
||||||
|
monthSelect: 'Velg måned',
|
||||||
|
yearSelect: 'Velg år',
|
||||||
|
decadeSelect: 'Velg tiår',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'DD.MM.YYYY',
|
||||||
|
dayFormat: 'DD',
|
||||||
|
dateTimeFormat: 'DD.MM.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Forrige måned (PageUp)',
|
||||||
|
nextMonth: 'Neste måned (PageDown)',
|
||||||
|
previousYear: 'Forrige år (Control + venstre)',
|
||||||
|
nextYear: 'Neste år (Control + høyre)',
|
||||||
|
previousDecade: 'Forrige tiår',
|
||||||
|
nextDecade: 'Neste tiår',
|
||||||
|
previousCentury: 'Forrige århundre',
|
||||||
|
nextCentury: 'Neste århundre',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'nl_BE',
|
||||||
|
today: 'Vandaag',
|
||||||
|
now: 'Nu',
|
||||||
|
backToToday: 'Terug naar vandaag',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Reset',
|
||||||
|
month: 'Maand',
|
||||||
|
year: 'Jaar',
|
||||||
|
timeSelect: 'Selecteer tijd',
|
||||||
|
dateSelect: 'Selecteer datum',
|
||||||
|
monthSelect: 'Kies een maand',
|
||||||
|
yearSelect: 'Kies een jaar',
|
||||||
|
decadeSelect: 'Kies een decennium',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D-M-YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D-M-YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Vorige maand (PageUp)',
|
||||||
|
nextMonth: 'Volgende maand (PageDown)',
|
||||||
|
previousYear: 'Vorig jaar (Control + left)',
|
||||||
|
nextYear: 'Volgend jaar (Control + right)',
|
||||||
|
previousDecade: 'Vorig decennium',
|
||||||
|
nextDecade: 'Volgend decennium',
|
||||||
|
previousCentury: 'Vorige eeuw',
|
||||||
|
nextCentury: 'Volgende eeuw',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'nl_NL',
|
||||||
|
today: 'Vandaag',
|
||||||
|
now: 'Nu',
|
||||||
|
backToToday: 'Terug naar vandaag',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Reset',
|
||||||
|
month: 'Maand',
|
||||||
|
year: 'Jaar',
|
||||||
|
timeSelect: 'Selecteer tijd',
|
||||||
|
dateSelect: 'Selecteer datum',
|
||||||
|
monthSelect: 'Kies een maand',
|
||||||
|
yearSelect: 'Kies een jaar',
|
||||||
|
decadeSelect: 'Kies een decennium',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D-M-YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D-M-YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Vorige maand (PageUp)',
|
||||||
|
nextMonth: 'Volgende maand (PageDown)',
|
||||||
|
previousYear: 'Vorig jaar (Control + left)',
|
||||||
|
nextYear: 'Volgend jaar (Control + right)',
|
||||||
|
previousDecade: 'Vorig decennium',
|
||||||
|
nextDecade: 'Volgend decennium',
|
||||||
|
previousCentury: 'Vorige eeuw',
|
||||||
|
nextCentury: 'Volgende eeuw',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'pl_PL',
|
||||||
|
today: 'Dzisiaj',
|
||||||
|
now: 'Teraz',
|
||||||
|
backToToday: 'Ustaw dzisiaj',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Wyczyść',
|
||||||
|
month: 'Miesiąc',
|
||||||
|
year: 'Rok',
|
||||||
|
timeSelect: 'Ustaw czas',
|
||||||
|
dateSelect: 'Ustaw datę',
|
||||||
|
monthSelect: 'Wybierz miesiąc',
|
||||||
|
yearSelect: 'Wybierz rok',
|
||||||
|
decadeSelect: 'Wybierz dekadę',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Poprzedni miesiąc (PageUp)',
|
||||||
|
nextMonth: 'Następny miesiąc (PageDown)',
|
||||||
|
previousYear: 'Ostatni rok (Ctrl + left)',
|
||||||
|
nextYear: 'Następny rok (Ctrl + right)',
|
||||||
|
previousDecade: 'Ostatnia dekada',
|
||||||
|
nextDecade: 'Następna dekada',
|
||||||
|
previousCentury: 'Ostatni wiek',
|
||||||
|
nextCentury: 'Następny wiek',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'pt_BR',
|
||||||
|
today: 'Hoje',
|
||||||
|
now: 'Agora',
|
||||||
|
backToToday: 'Voltar para hoje',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Limpar',
|
||||||
|
month: 'Mês',
|
||||||
|
year: 'Ano',
|
||||||
|
timeSelect: 'Selecionar hora',
|
||||||
|
dateSelect: 'Selecionar data',
|
||||||
|
monthSelect: 'Escolher mês',
|
||||||
|
yearSelect: 'Escolher ano',
|
||||||
|
decadeSelect: 'Escolher década',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: false,
|
||||||
|
previousMonth: 'Mês anterior (PageUp)',
|
||||||
|
nextMonth: 'Próximo mês (PageDown)',
|
||||||
|
previousYear: 'Ano anterior (Control + esquerda)',
|
||||||
|
nextYear: 'Próximo ano (Control + direita)',
|
||||||
|
previousDecade: 'Década anterior',
|
||||||
|
nextDecade: 'Próxima década',
|
||||||
|
previousCentury: 'Século anterior',
|
||||||
|
nextCentury: 'Próximo século',
|
||||||
|
shortWeekDays: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],
|
||||||
|
shortMonths: [
|
||||||
|
'Jan',
|
||||||
|
'Fev',
|
||||||
|
'Mar',
|
||||||
|
'Abr',
|
||||||
|
'Mai',
|
||||||
|
'Jun',
|
||||||
|
'Jul',
|
||||||
|
'Ago',
|
||||||
|
'Set',
|
||||||
|
'Out',
|
||||||
|
'Nov',
|
||||||
|
'Dez',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'pt_PT',
|
||||||
|
today: 'Hoje',
|
||||||
|
now: 'Agora',
|
||||||
|
backToToday: 'Hoje',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Limpar',
|
||||||
|
month: 'Mês',
|
||||||
|
year: 'Ano',
|
||||||
|
timeSelect: 'Selecionar hora',
|
||||||
|
dateSelect: 'Selecionar data',
|
||||||
|
monthSelect: 'Selecionar mês',
|
||||||
|
yearSelect: 'Selecionar ano',
|
||||||
|
decadeSelect: 'Selecionar década',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Mês anterior (PageUp)',
|
||||||
|
nextMonth: 'Mês seguinte (PageDown)',
|
||||||
|
previousYear: 'Ano anterior (Control + left)',
|
||||||
|
nextYear: 'Ano seguinte (Control + right)',
|
||||||
|
previousDecade: 'Década anterior',
|
||||||
|
nextDecade: 'Década seguinte',
|
||||||
|
previousCentury: 'Século anterior',
|
||||||
|
nextCentury: 'Século seguinte',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ro_RO',
|
||||||
|
today: 'Azi',
|
||||||
|
now: 'Acum',
|
||||||
|
backToToday: 'Înapoi la azi',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Șterge',
|
||||||
|
month: 'Lună',
|
||||||
|
year: 'An',
|
||||||
|
timeSelect: 'selectează timpul',
|
||||||
|
dateSelect: 'selectează data',
|
||||||
|
weekSelect: 'Alege o săptămână',
|
||||||
|
monthSelect: 'Alege o lună',
|
||||||
|
yearSelect: 'Alege un an',
|
||||||
|
decadeSelect: 'Alege un deceniu',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Luna anterioară (PageUp)',
|
||||||
|
nextMonth: 'Luna următoare (PageDown)',
|
||||||
|
previousYear: 'Anul anterior (Control + stânga)',
|
||||||
|
nextYear: 'Anul următor (Control + dreapta)',
|
||||||
|
previousDecade: 'Deceniul anterior',
|
||||||
|
nextDecade: 'Deceniul următor',
|
||||||
|
previousCentury: 'Secolul anterior',
|
||||||
|
nextCentury: 'Secolul următor',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ru_RU',
|
||||||
|
today: 'Сегодня',
|
||||||
|
now: 'Сейчас',
|
||||||
|
backToToday: 'Текущая дата',
|
||||||
|
ok: 'ОК',
|
||||||
|
clear: 'Очистить',
|
||||||
|
month: 'Месяц',
|
||||||
|
year: 'Год',
|
||||||
|
timeSelect: 'Выбрать время',
|
||||||
|
dateSelect: 'Выбрать дату',
|
||||||
|
monthSelect: 'Выбрать месяц',
|
||||||
|
yearSelect: 'Выбрать год',
|
||||||
|
decadeSelect: 'Выбрать десятилетие',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D-M-YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D-M-YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Предыдущий месяц (PageUp)',
|
||||||
|
nextMonth: 'Следующий месяц (PageDown)',
|
||||||
|
previousYear: 'Предыдущий год (Control + left)',
|
||||||
|
nextYear: 'Следующий год (Control + right)',
|
||||||
|
previousDecade: 'Предыдущее десятилетие',
|
||||||
|
nextDecade: 'Следущее десятилетие',
|
||||||
|
previousCentury: 'Предыдущий век',
|
||||||
|
nextCentury: 'Следующий век',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'sk_SK',
|
||||||
|
today: 'Dnes',
|
||||||
|
now: 'Teraz',
|
||||||
|
backToToday: 'Späť na dnes',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Vymazať',
|
||||||
|
month: 'Mesiac',
|
||||||
|
year: 'Rok',
|
||||||
|
timeSelect: 'Vybrať čas',
|
||||||
|
dateSelect: 'Vybrať dátum',
|
||||||
|
monthSelect: 'Vybrať mesiac',
|
||||||
|
yearSelect: 'Vybrať rok',
|
||||||
|
decadeSelect: 'Vybrať dekádu',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D.M.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D.M.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Predchádzajúci mesiac (PageUp)',
|
||||||
|
nextMonth: 'Nasledujúci mesiac (PageDown)',
|
||||||
|
previousYear: 'Predchádzajúci rok (Control + left)',
|
||||||
|
nextYear: 'Nasledujúci rok (Control + right)',
|
||||||
|
previousDecade: 'Predchádzajúca dekáda',
|
||||||
|
nextDecade: 'Nasledujúca dekáda',
|
||||||
|
previousCentury: 'Predchádzajúce storočie',
|
||||||
|
nextCentury: 'Nasledujúce storočie',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'sl_SI',
|
||||||
|
today: 'Danes',
|
||||||
|
now: 'Trenutno',
|
||||||
|
backToToday: 'Nazaj na danes',
|
||||||
|
ok: 'V redu',
|
||||||
|
clear: 'Počisti',
|
||||||
|
month: 'Mesec',
|
||||||
|
year: 'Leto',
|
||||||
|
timeSelect: 'Izberite čas',
|
||||||
|
dateSelect: 'Izberite datum',
|
||||||
|
monthSelect: 'Izberite mesec',
|
||||||
|
yearSelect: 'Izberite leto',
|
||||||
|
decadeSelect: 'Izberite desetletje',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'DD.MM.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'DD.MM.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Prejšnji mesec (PageUp)',
|
||||||
|
nextMonth: 'Naslednji mesec (PageDown)',
|
||||||
|
previousYear: 'Prejšnje leto (Control + left)',
|
||||||
|
nextYear: 'Naslednje leto (Control + right)',
|
||||||
|
previousDecade: 'Prejšnje desetletje',
|
||||||
|
nextDecade: 'Naslednje desetletje',
|
||||||
|
previousCentury: 'Prejšnje stoletje',
|
||||||
|
nextCentury: 'Naslednje stoletje',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'sr_RS',
|
||||||
|
today: 'Danas',
|
||||||
|
now: 'Sada',
|
||||||
|
backToToday: 'Vrati se na danas',
|
||||||
|
ok: 'U redu',
|
||||||
|
clear: 'Obriši',
|
||||||
|
month: 'Mesec',
|
||||||
|
year: 'Godina',
|
||||||
|
timeSelect: 'Izaberi vreme',
|
||||||
|
dateSelect: 'Izaberi datum',
|
||||||
|
monthSelect: 'Izaberi mesec',
|
||||||
|
yearSelect: 'Izaberi godinu',
|
||||||
|
decadeSelect: 'Izaberi deceniju',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'DD.MM.YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'DD.MM.YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Prethodni mesec (PageUp)',
|
||||||
|
nextMonth: 'Sledeći mesec (PageDown)',
|
||||||
|
previousYear: 'Prethodna godina (Control + left)',
|
||||||
|
nextYear: 'Sledeća godina (Control + right)',
|
||||||
|
previousDecade: 'Prethodna decenija',
|
||||||
|
nextDecade: 'Sledeća decenija',
|
||||||
|
previousCentury: 'Prethodni vek',
|
||||||
|
nextCentury: 'Sledeći vek',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'sv_SE',
|
||||||
|
today: 'I dag',
|
||||||
|
now: 'Nu',
|
||||||
|
backToToday: 'Till idag',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Avbryt',
|
||||||
|
month: 'Månad',
|
||||||
|
year: 'År',
|
||||||
|
timeSelect: 'Välj tidpunkt',
|
||||||
|
dateSelect: 'Välj datum',
|
||||||
|
monthSelect: 'Välj månad',
|
||||||
|
yearSelect: 'Välj år',
|
||||||
|
decadeSelect: 'Välj årtionde',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'YYYY-MM-DD',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'YYYY-MM-DD H:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Förra månaden (PageUp)',
|
||||||
|
nextMonth: 'Nästa månad (PageDown)',
|
||||||
|
previousYear: 'Föreg år (Control + left)',
|
||||||
|
nextYear: 'Nästa år (Control + right)',
|
||||||
|
previousDecade: 'Föreg årtionde',
|
||||||
|
nextDecade: 'Nästa årtionde',
|
||||||
|
previousCentury: 'Föreg århundrade',
|
||||||
|
nextCentury: 'Nästa århundrade',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ta_IN',
|
||||||
|
today: 'இன்று',
|
||||||
|
now: 'இப்போது',
|
||||||
|
backToToday: 'இன்றுக்கு திரும்பு',
|
||||||
|
ok: 'சரி',
|
||||||
|
clear: 'அழி',
|
||||||
|
month: 'மாதம்',
|
||||||
|
year: 'வருடம்',
|
||||||
|
timeSelect: 'நேரத்தைத் தேர்ந்தெடு',
|
||||||
|
dateSelect: 'தேதியைத் தேர்ந்தெடு',
|
||||||
|
weekSelect: 'வாரத்தைத் தேர்வுசெய்க',
|
||||||
|
monthSelect: 'மாதத்தைத் தேர்வுசெய்க',
|
||||||
|
yearSelect: 'வருடத்தைத் தேர்வுசெய்க',
|
||||||
|
decadeSelect: 'தசாப்தத்தைத் தேர்வுசெய்க',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'முந்தைய மாதம் (PageUp)',
|
||||||
|
nextMonth: 'அடுத்த மாதம் (PageDown)',
|
||||||
|
previousYear: 'முந்தைய வருடம் (Control + left)',
|
||||||
|
nextYear: 'அடுத்த வருடம் (Control + right)',
|
||||||
|
previousDecade: 'முந்தைய தசாப்தம்',
|
||||||
|
nextDecade: 'அடுத்த தசாப்தம்',
|
||||||
|
previousCentury: 'முந்தைய நூற்றாண்டு',
|
||||||
|
nextCentury: 'அடுத்த நூற்றாண்டு',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'th_TH',
|
||||||
|
today: 'วันนี้',
|
||||||
|
now: 'ตอนนี้',
|
||||||
|
backToToday: 'กลับไปยังวันนี้',
|
||||||
|
ok: 'ตกลง',
|
||||||
|
clear: 'ลบล้าง',
|
||||||
|
month: 'เดือน',
|
||||||
|
year: 'ปี',
|
||||||
|
timeSelect: 'เลือกเวลา',
|
||||||
|
dateSelect: 'เลือกวัน',
|
||||||
|
monthSelect: 'เลือกเดือน',
|
||||||
|
yearSelect: 'เลือกปี',
|
||||||
|
decadeSelect: 'เลือกทศวรรษ',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'เดือนก่อนหน้า (PageUp)',
|
||||||
|
nextMonth: 'เดือนถัดไป (PageDown)',
|
||||||
|
previousYear: 'ปีก่อนหน้า (Control + left)',
|
||||||
|
nextYear: 'ปีถัดไป (Control + right)',
|
||||||
|
previousDecade: 'ทศวรรษก่อนหน้า',
|
||||||
|
nextDecade: 'ทศวรรษถัดไป',
|
||||||
|
previousCentury: 'ศตวรรษก่อนหน้า',
|
||||||
|
nextCentury: 'ศตวรรษถัดไป',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'tr_TR',
|
||||||
|
today: 'Bugün',
|
||||||
|
now: 'Şimdi',
|
||||||
|
backToToday: 'Bugüne Geri Dön',
|
||||||
|
ok: 'tamam',
|
||||||
|
clear: 'Temizle',
|
||||||
|
month: 'Ay',
|
||||||
|
year: 'Yıl',
|
||||||
|
timeSelect: 'Zaman Seç',
|
||||||
|
dateSelect: 'Tarih Seç',
|
||||||
|
monthSelect: 'Ay Seç',
|
||||||
|
yearSelect: 'Yıl Seç',
|
||||||
|
decadeSelect: 'On Yıl Seç',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'M/D/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'M/D/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Önceki Ay (PageUp)',
|
||||||
|
nextMonth: 'Sonraki Ay (PageDown)',
|
||||||
|
previousYear: 'Önceki Yıl (Control + Sol)',
|
||||||
|
nextYear: 'Sonraki Yıl (Control + Sağ)',
|
||||||
|
previousDecade: 'Önceki On Yıl',
|
||||||
|
nextDecade: 'Sonraki On Yıl',
|
||||||
|
previousCentury: 'Önceki Yüzyıl',
|
||||||
|
nextCentury: 'Sonraki Yüzyıl',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'ug_CN',
|
||||||
|
today: 'بۈگۈن',
|
||||||
|
now: 'ھازىر',
|
||||||
|
backToToday: 'بۈگۈنگە قايتىش',
|
||||||
|
ok: 'مۇقىملاشتۇرۇش',
|
||||||
|
timeSelect: 'ۋاقىت تاللاش',
|
||||||
|
dateSelect: 'كۈن تاللاش',
|
||||||
|
clear: 'تازىلاش',
|
||||||
|
month: 'ئاي',
|
||||||
|
year: 'يىل',
|
||||||
|
previousMonth: 'ئالدىنقى ئاي(ئالدىنقى بەت )',
|
||||||
|
nextMonth: 'كېلەركى ئاي (كېلەركى بەت)',
|
||||||
|
monthSelect: 'ئاي تاللاش',
|
||||||
|
yearSelect: 'يىل تاللاش',
|
||||||
|
decadeSelect: 'يىللارنى تاللاش',
|
||||||
|
yearFormat: 'YYYY-يىلى',
|
||||||
|
dayFormat: 'D-كۈنى',
|
||||||
|
dateFormat: 'YYYY-يىلىM-ئاينىڭD-كۈنى',
|
||||||
|
dateTimeFormat: 'YYYY-يىلىM—ئاينىڭD-كۈنى، HH:mm:ss',
|
||||||
|
previousYear: 'ئالدىنقى يىلى (Controlبىلەن يۆنىلىش كونۇپكىسى)',
|
||||||
|
nextYear: 'كېلەركى يىلى (Controlبىلەن يۆنىلىش كونۇپكىسى)',
|
||||||
|
previousDecade: 'ئالدىنقى يىللار',
|
||||||
|
nextDecade: 'كېيىنكى يىللار',
|
||||||
|
previousCentury: 'ئالدىنقى ئەسىر',
|
||||||
|
nextCentury: 'كېيىنكى ئەسىر',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'uk_UA',
|
||||||
|
today: 'Сьогодні',
|
||||||
|
now: 'Зараз',
|
||||||
|
backToToday: 'Поточна дата',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Очистити',
|
||||||
|
month: 'Місяць',
|
||||||
|
year: 'Рік',
|
||||||
|
timeSelect: 'Обрати час',
|
||||||
|
dateSelect: 'Обрати дату',
|
||||||
|
monthSelect: 'Обрати місяць',
|
||||||
|
yearSelect: 'Обрати рік',
|
||||||
|
decadeSelect: 'Обрати десятиріччя',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D-M-YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D-M-YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Попередній місяць (PageUp)',
|
||||||
|
nextMonth: 'Наступний місяць (PageDown)',
|
||||||
|
previousYear: 'Попередній рік (Control + left)',
|
||||||
|
nextYear: 'Наступний рік (Control + right)',
|
||||||
|
previousDecade: 'Попереднє десятиріччя',
|
||||||
|
nextDecade: 'Наступне десятиріччя',
|
||||||
|
previousCentury: 'Попереднє століття',
|
||||||
|
nextCentury: 'Наступне століття',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'vi_VN',
|
||||||
|
today: 'Hôm nay',
|
||||||
|
now: 'Bây giờ',
|
||||||
|
backToToday: 'Trở về hôm nay',
|
||||||
|
ok: 'Ok',
|
||||||
|
clear: 'Xóa',
|
||||||
|
month: 'Tháng',
|
||||||
|
year: 'Năm',
|
||||||
|
timeSelect: 'Chọn thời gian',
|
||||||
|
dateSelect: 'Chọn ngày',
|
||||||
|
weekSelect: 'Chọn tuần',
|
||||||
|
monthSelect: 'Chọn tháng',
|
||||||
|
yearSelect: 'Chọn năm',
|
||||||
|
decadeSelect: 'Chọn thập kỷ',
|
||||||
|
yearFormat: 'YYYY',
|
||||||
|
dateFormat: 'D/M/YYYY',
|
||||||
|
dayFormat: 'D',
|
||||||
|
dateTimeFormat: 'D/M/YYYY HH:mm:ss',
|
||||||
|
monthBeforeYear: true,
|
||||||
|
previousMonth: 'Tháng trước (PageUp)',
|
||||||
|
nextMonth: 'Tháng sau (PageDown)',
|
||||||
|
previousYear: 'Năm trước (Control + left)',
|
||||||
|
nextYear: 'Năm sau (Control + right)',
|
||||||
|
previousDecade: 'Thập kỷ trước',
|
||||||
|
nextDecade: 'Thập kỷ sau',
|
||||||
|
previousCentury: 'Thế kỷ trước',
|
||||||
|
nextCentury: 'Thế kỷ sau',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'zh_CN',
|
||||||
|
today: '今天',
|
||||||
|
now: '此刻',
|
||||||
|
backToToday: '返回今天',
|
||||||
|
ok: '确定',
|
||||||
|
timeSelect: '选择时间',
|
||||||
|
dateSelect: '选择日期',
|
||||||
|
weekSelect: '选择周',
|
||||||
|
clear: '清除',
|
||||||
|
month: '月',
|
||||||
|
year: '年',
|
||||||
|
previousMonth: '上个月 (翻页上键)',
|
||||||
|
nextMonth: '下个月 (翻页下键)',
|
||||||
|
monthSelect: '选择月份',
|
||||||
|
yearSelect: '选择年份',
|
||||||
|
decadeSelect: '选择年代',
|
||||||
|
yearFormat: 'YYYY年',
|
||||||
|
dayFormat: 'D日',
|
||||||
|
dateFormat: 'YYYY年M月D日',
|
||||||
|
dateTimeFormat: 'YYYY年M月D日 HH时mm分ss秒',
|
||||||
|
previousYear: '上一年 (Control键加左方向键)',
|
||||||
|
nextYear: '下一年 (Control键加右方向键)',
|
||||||
|
previousDecade: '上一年代',
|
||||||
|
nextDecade: '下一年代',
|
||||||
|
previousCentury: '上一世纪',
|
||||||
|
nextCentury: '下一世纪',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import type { Locale } from '../interface';
|
||||||
|
|
||||||
|
const locale: Locale = {
|
||||||
|
locale: 'zh_TW',
|
||||||
|
|
||||||
|
today: '今天',
|
||||||
|
now: '此刻',
|
||||||
|
backToToday: '返回今天',
|
||||||
|
ok: '確定',
|
||||||
|
timeSelect: '選擇時間',
|
||||||
|
dateSelect: '選擇日期',
|
||||||
|
weekSelect: '選擇周',
|
||||||
|
clear: '清除',
|
||||||
|
month: '月',
|
||||||
|
year: '年',
|
||||||
|
previousMonth: '上個月 (翻頁上鍵)',
|
||||||
|
nextMonth: '下個月 (翻頁下鍵)',
|
||||||
|
monthSelect: '選擇月份',
|
||||||
|
yearSelect: '選擇年份',
|
||||||
|
decadeSelect: '選擇年代',
|
||||||
|
yearFormat: 'YYYY年',
|
||||||
|
dayFormat: 'D日',
|
||||||
|
dateFormat: 'YYYY年M月D日',
|
||||||
|
dateTimeFormat: 'YYYY年M月D日 HH時mm分ss秒',
|
||||||
|
previousYear: '上一年 (Control鍵加左方向鍵)',
|
||||||
|
nextYear: '下一年 (Control鍵加右方向鍵)',
|
||||||
|
previousDecade: '上一年代',
|
||||||
|
nextDecade: '下一年代',
|
||||||
|
previousCentury: '上一世紀',
|
||||||
|
nextCentury: '下一世紀',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import {
|
||||||
|
WEEK_DAY_COUNT,
|
||||||
|
getWeekStartDate,
|
||||||
|
isSameDate,
|
||||||
|
isSameMonth,
|
||||||
|
formatValue,
|
||||||
|
} from '../../utils/dateUtil';
|
||||||
|
import type { Locale } from '../../interface';
|
||||||
|
import useCellClassName from '../../hooks/useCellClassName';
|
||||||
|
import PanelBody from '../PanelBody';
|
||||||
|
import { VueNode } from '../../../_util/type';
|
||||||
|
import { useInjectRange } from '../../RangeContext';
|
||||||
|
|
||||||
|
export type DateRender<DateType> = (currentDate: DateType, today: DateType) => VueNode;
|
||||||
|
|
||||||
|
export type DateBodyPassProps<DateType> = {
|
||||||
|
dateRender?: DateRender<DateType>;
|
||||||
|
disabledDate?: (date: DateType) => boolean;
|
||||||
|
|
||||||
|
// Used for week panel
|
||||||
|
prefixColumn?: (date: DateType) => VueNode;
|
||||||
|
rowClassName?: (date: DateType) => string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DateBodyProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
value?: DateType | null;
|
||||||
|
viewDate: DateType;
|
||||||
|
locale: Locale;
|
||||||
|
rowCount: number;
|
||||||
|
onSelect: (value: DateType) => void;
|
||||||
|
} & DateBodyPassProps<DateType>;
|
||||||
|
|
||||||
|
function DateBody<DateType>(props: DateBodyProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
generateConfig,
|
||||||
|
prefixColumn,
|
||||||
|
locale,
|
||||||
|
rowCount,
|
||||||
|
viewDate,
|
||||||
|
value,
|
||||||
|
dateRender,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const { rangedValue, hoverRangedValue } =useInjectRange()
|
||||||
|
|
||||||
|
const baseDate = getWeekStartDate(locale.locale, generateConfig, viewDate);
|
||||||
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
const weekFirstDay = generateConfig.locale.getWeekFirstDay(locale.locale);
|
||||||
|
const today = generateConfig.getNow();
|
||||||
|
|
||||||
|
// ============================== Header ==============================
|
||||||
|
const headerCells: VueNode[] = [];
|
||||||
|
const weekDaysLocale: string[] =
|
||||||
|
locale.shortWeekDays ||
|
||||||
|
(generateConfig.locale.getShortWeekDays
|
||||||
|
? generateConfig.locale.getShortWeekDays(locale.locale)
|
||||||
|
: []);
|
||||||
|
|
||||||
|
if (prefixColumn) {
|
||||||
|
headerCells.push(<th key="empty" aria-label="empty cell" />);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < WEEK_DAY_COUNT; i += 1) {
|
||||||
|
headerCells.push(<th key={i}>{weekDaysLocale[(i + weekFirstDay) % WEEK_DAY_COUNT]}</th>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================== Body ===============================
|
||||||
|
const getCellClassName = useCellClassName({
|
||||||
|
cellPrefixCls,
|
||||||
|
today,
|
||||||
|
value,
|
||||||
|
generateConfig,
|
||||||
|
rangedValue: prefixColumn ? null : rangedValue,
|
||||||
|
hoverRangedValue: prefixColumn ? null : hoverRangedValue,
|
||||||
|
isSameCell: (current, target) => isSameDate(generateConfig, current, target),
|
||||||
|
isInView: date => isSameMonth(generateConfig, date, viewDate),
|
||||||
|
offsetCell: (date, offset) => generateConfig.addDate(date, offset),
|
||||||
|
});
|
||||||
|
|
||||||
|
const getCellNode = dateRender ? (date: DateType) => dateRender(date, today) : undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PanelBody
|
||||||
|
{...props}
|
||||||
|
rowNum={rowCount}
|
||||||
|
colNum={WEEK_DAY_COUNT}
|
||||||
|
baseDate={baseDate}
|
||||||
|
getCellNode={getCellNode}
|
||||||
|
getCellText={generateConfig.getDate}
|
||||||
|
getCellClassName={getCellClassName}
|
||||||
|
getCellDate={generateConfig.addDate}
|
||||||
|
titleCell={date =>
|
||||||
|
formatValue(date, {
|
||||||
|
locale,
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
generateConfig,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
headerCells={headerCells}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DateBody.displayName = 'DateBody'
|
||||||
|
DateBody.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default DateBody;
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
|
||||||
|
import Header from '../Header';
|
||||||
|
import type { Locale } from '../../interface';
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
|
import { formatValue } from '../../utils/dateUtil';
|
||||||
|
import { VueNode } from '../../../_util/type';
|
||||||
|
|
||||||
|
export type DateHeaderProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
viewDate: DateType;
|
||||||
|
value?: DateType | null;
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
|
||||||
|
onPrevYear: () => void;
|
||||||
|
onNextYear: () => void;
|
||||||
|
onPrevMonth: () => void;
|
||||||
|
onNextMonth: () => void;
|
||||||
|
onYearClick: () => void;
|
||||||
|
onMonthClick: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function DateHeader<DateType>(props: DateHeaderProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
generateConfig,
|
||||||
|
locale,
|
||||||
|
viewDate,
|
||||||
|
onNextMonth,
|
||||||
|
onPrevMonth,
|
||||||
|
onNextYear,
|
||||||
|
onPrevYear,
|
||||||
|
onYearClick,
|
||||||
|
onMonthClick,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const { hideHeader } = useInjectPanel()
|
||||||
|
if (hideHeader) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerPrefixCls = `${prefixCls}-header`;
|
||||||
|
|
||||||
|
const monthsLocale: string[] =
|
||||||
|
locale.shortMonths ||
|
||||||
|
(generateConfig.locale.getShortMonths
|
||||||
|
? generateConfig.locale.getShortMonths(locale.locale)
|
||||||
|
: []);
|
||||||
|
|
||||||
|
const month = generateConfig.getMonth(viewDate);
|
||||||
|
|
||||||
|
// =================== Month & Year ===================
|
||||||
|
const yearNode: VueNode = (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
key="year"
|
||||||
|
onClick={onYearClick}
|
||||||
|
tabindex={-1}
|
||||||
|
class={`${prefixCls}-year-btn`}
|
||||||
|
>
|
||||||
|
{formatValue(viewDate, {
|
||||||
|
locale,
|
||||||
|
format: locale.yearFormat,
|
||||||
|
generateConfig,
|
||||||
|
})}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
const monthNode: VueNode = (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
key="month"
|
||||||
|
onClick={onMonthClick}
|
||||||
|
tabindex={-1}
|
||||||
|
class={`${prefixCls}-month-btn`}
|
||||||
|
>
|
||||||
|
{locale.monthFormat
|
||||||
|
? formatValue(viewDate, {
|
||||||
|
locale,
|
||||||
|
format: locale.monthFormat,
|
||||||
|
generateConfig,
|
||||||
|
})
|
||||||
|
: monthsLocale[month]}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
|
const monthYearNodes = locale.monthBeforeYear ? [monthNode, yearNode] : [yearNode, monthNode];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Header
|
||||||
|
{...props}
|
||||||
|
prefixCls={headerPrefixCls}
|
||||||
|
onSuperPrev={onPrevYear}
|
||||||
|
onPrev={onPrevMonth}
|
||||||
|
onNext={onNextMonth}
|
||||||
|
onSuperNext={onNextYear}
|
||||||
|
>
|
||||||
|
{monthYearNodes}
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DateHeader.displayName = 'DateHeader'
|
||||||
|
DateHeader.inheritAttrs = false;
|
||||||
|
export default DateHeader;
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
|
||||||
|
import type { DateBodyPassProps, DateRender } from './DateBody';
|
||||||
|
import DateBody from './DateBody';
|
||||||
|
import DateHeader from './DateHeader';
|
||||||
|
import type { PanelSharedProps } from '../../interface';
|
||||||
|
import { WEEK_DAY_COUNT } from '../../utils/dateUtil';
|
||||||
|
import type { KeyboardConfig } from '../../utils/uiUtil';
|
||||||
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
import classNames from '../../../_util/classNames';
|
||||||
|
import { ref } from '@vue/reactivity';
|
||||||
|
|
||||||
|
const DATE_ROW_COUNT = 6;
|
||||||
|
|
||||||
|
export type DatePanelProps<DateType> = {
|
||||||
|
active?: boolean;
|
||||||
|
dateRender?: DateRender<DateType>;
|
||||||
|
|
||||||
|
// Used for week panel
|
||||||
|
panelName?: string;
|
||||||
|
keyboardConfig?: KeyboardConfig;
|
||||||
|
} & PanelSharedProps<DateType> & DateBodyPassProps<DateType>;
|
||||||
|
|
||||||
|
function DatePanel<DateType>(props: DatePanelProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
panelName = 'date',
|
||||||
|
keyboardConfig,
|
||||||
|
active,
|
||||||
|
generateConfig,
|
||||||
|
value,
|
||||||
|
viewDate,
|
||||||
|
onViewDateChange,
|
||||||
|
onPanelChange,
|
||||||
|
onSelect,
|
||||||
|
} = props;
|
||||||
|
const panelPrefixCls = `${prefixCls}-${panelName}-panel`;
|
||||||
|
const operationRef = ref()
|
||||||
|
// ======================= Keyboard =======================
|
||||||
|
operationRef.value = {
|
||||||
|
onKeyDown: event =>
|
||||||
|
createKeyDownHandler(event, {
|
||||||
|
onLeftRight: diff => {
|
||||||
|
onSelect(generateConfig.addDate(value || viewDate, diff), 'key');
|
||||||
|
},
|
||||||
|
onCtrlLeftRight: diff => {
|
||||||
|
onSelect(generateConfig.addYear(value || viewDate, diff), 'key');
|
||||||
|
},
|
||||||
|
onUpDown: diff => {
|
||||||
|
onSelect(generateConfig.addDate(value || viewDate, diff * WEEK_DAY_COUNT), 'key');
|
||||||
|
},
|
||||||
|
onPageUpDown: diff => {
|
||||||
|
onSelect(generateConfig.addMonth(value || viewDate, diff), 'key');
|
||||||
|
},
|
||||||
|
...keyboardConfig,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== View Operation ====================
|
||||||
|
const onYearChange = (diff: number) => {
|
||||||
|
const newDate = generateConfig.addYear(viewDate, diff);
|
||||||
|
onViewDateChange(newDate);
|
||||||
|
onPanelChange(null, newDate);
|
||||||
|
};
|
||||||
|
const onMonthChange = (diff: number) => {
|
||||||
|
const newDate = generateConfig.addMonth(viewDate, diff);
|
||||||
|
onViewDateChange(newDate);
|
||||||
|
onPanelChange(null, newDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={classNames(panelPrefixCls, {
|
||||||
|
[`${panelPrefixCls}-active`]: active,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<DateHeader
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
value={value}
|
||||||
|
viewDate={viewDate}
|
||||||
|
// View Operation
|
||||||
|
onPrevYear={() => {
|
||||||
|
onYearChange(-1);
|
||||||
|
}}
|
||||||
|
onNextYear={() => {
|
||||||
|
onYearChange(1);
|
||||||
|
}}
|
||||||
|
onPrevMonth={() => {
|
||||||
|
onMonthChange(-1);
|
||||||
|
}}
|
||||||
|
onNextMonth={() => {
|
||||||
|
onMonthChange(1);
|
||||||
|
}}
|
||||||
|
onMonthClick={() => {
|
||||||
|
onPanelChange('month', viewDate);
|
||||||
|
}}
|
||||||
|
onYearClick={() => {
|
||||||
|
onPanelChange('year', viewDate);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<DateBody
|
||||||
|
{...props}
|
||||||
|
onSelect={date => onSelect(date, 'mouse')}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
value={value}
|
||||||
|
viewDate={viewDate}
|
||||||
|
rowCount={DATE_ROW_COUNT}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DatePanel.displayName ='DatePanel'
|
||||||
|
DatePanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default DatePanel;
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
|
||||||
|
import type { DatePanelProps } from '../DatePanel';
|
||||||
|
import DatePanel from '../DatePanel';
|
||||||
|
import type { SharedTimeProps } from '../TimePanel';
|
||||||
|
import TimePanel from '../TimePanel';
|
||||||
|
import { tuple } from '../../utils/miscUtil';
|
||||||
|
import { setDateTime as setTime } from '../../utils/timeUtil';
|
||||||
|
import type { PanelRefProps, DisabledTime } from '../../interface';
|
||||||
|
import KeyCode from '../../../_util/KeyCode';
|
||||||
|
import classNames from '../../../_util/classNames';
|
||||||
|
import { ref } from '@vue/reactivity';
|
||||||
|
|
||||||
|
export type DatetimePanelProps<DateType> = {
|
||||||
|
disabledTime?: DisabledTime<DateType>;
|
||||||
|
showTime?: boolean | SharedTimeProps<DateType>;
|
||||||
|
defaultValue?: DateType;
|
||||||
|
} & Omit<
|
||||||
|
DatePanelProps<DateType>,
|
||||||
|
'disabledHours' | 'disabledMinutes' | 'disabledSeconds'
|
||||||
|
>;
|
||||||
|
|
||||||
|
const ACTIVE_PANEL = tuple('date', 'time');
|
||||||
|
type ActivePanelType = typeof ACTIVE_PANEL[number];
|
||||||
|
|
||||||
|
function DatetimePanel<DateType>(props: DatetimePanelProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
operationRef,
|
||||||
|
generateConfig,
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
disabledTime,
|
||||||
|
showTime,
|
||||||
|
onSelect,
|
||||||
|
} = props;
|
||||||
|
const panelPrefixCls = `${prefixCls}-datetime-panel`;
|
||||||
|
const activePanel = ref<ActivePanelType | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const dateOperationRef = ref<PanelRefProps>({});
|
||||||
|
const timeOperationRef = ref<PanelRefProps>({});
|
||||||
|
|
||||||
|
const timeProps = typeof showTime === 'object' ? { ...showTime } : {};
|
||||||
|
|
||||||
|
// ======================= Keyboard =======================
|
||||||
|
function getNextActive(offset: number) {
|
||||||
|
const activeIndex = ACTIVE_PANEL.indexOf(activePanel.value!) + offset;
|
||||||
|
const nextActivePanel = ACTIVE_PANEL[activeIndex] || null;
|
||||||
|
return nextActivePanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBlur = (e?: FocusEvent) => {
|
||||||
|
if (timeOperationRef.value.onBlur) {
|
||||||
|
timeOperationRef.value.onBlur(e!);
|
||||||
|
}
|
||||||
|
activePanel.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
operationRef.current = {
|
||||||
|
onKeyDown: event => {
|
||||||
|
// Switch active panel
|
||||||
|
if (event.which === KeyCode.TAB) {
|
||||||
|
const nextActivePanel = getNextActive(event.shiftKey ? -1 : 1);
|
||||||
|
activePanel.value = nextActivePanel
|
||||||
|
|
||||||
|
if (nextActivePanel) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operate on current active panel
|
||||||
|
if (activePanel.value) {
|
||||||
|
const ref =
|
||||||
|
activePanel.value === 'date' ? dateOperationRef : timeOperationRef;
|
||||||
|
|
||||||
|
if (ref.value && ref.value.onKeyDown) {
|
||||||
|
ref.value.onKeyDown(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch first active panel if operate without panel
|
||||||
|
if (
|
||||||
|
[KeyCode.LEFT, KeyCode.RIGHT, KeyCode.UP, KeyCode.DOWN].includes(
|
||||||
|
event.which,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
activePanel.value = 'date'
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
onBlur,
|
||||||
|
onClose: onBlur,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ======================== Events ========================
|
||||||
|
const onInternalSelect = (date: DateType, source: 'date' | 'time') => {
|
||||||
|
let selectedDate = date;
|
||||||
|
|
||||||
|
if (source === 'date' && !value && timeProps.defaultValue) {
|
||||||
|
// Date with time defaultValue
|
||||||
|
selectedDate = generateConfig.setHour(
|
||||||
|
selectedDate,
|
||||||
|
generateConfig.getHour(timeProps.defaultValue),
|
||||||
|
);
|
||||||
|
selectedDate = generateConfig.setMinute(
|
||||||
|
selectedDate,
|
||||||
|
generateConfig.getMinute(timeProps.defaultValue),
|
||||||
|
);
|
||||||
|
selectedDate = generateConfig.setSecond(
|
||||||
|
selectedDate,
|
||||||
|
generateConfig.getSecond(timeProps.defaultValue),
|
||||||
|
);
|
||||||
|
} else if (source === 'time' && !value && defaultValue) {
|
||||||
|
selectedDate = generateConfig.setYear(
|
||||||
|
selectedDate,
|
||||||
|
generateConfig.getYear(defaultValue),
|
||||||
|
);
|
||||||
|
selectedDate = generateConfig.setMonth(
|
||||||
|
selectedDate,
|
||||||
|
generateConfig.getMonth(defaultValue),
|
||||||
|
);
|
||||||
|
selectedDate = generateConfig.setDate(
|
||||||
|
selectedDate,
|
||||||
|
generateConfig.getDate(defaultValue),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onSelect) {
|
||||||
|
onSelect(selectedDate, 'mouse');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ======================== Render ========================
|
||||||
|
const disabledTimes = disabledTime ? disabledTime(value || null) : {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={classNames(panelPrefixCls, {
|
||||||
|
[`${panelPrefixCls}-active`]: activePanel.value,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<DatePanel
|
||||||
|
{...props}
|
||||||
|
operationRef={dateOperationRef}
|
||||||
|
active={activePanel.value === 'date'}
|
||||||
|
onSelect={date => {
|
||||||
|
onInternalSelect(
|
||||||
|
setTime(
|
||||||
|
generateConfig,
|
||||||
|
date,
|
||||||
|
showTime && typeof showTime === 'object'
|
||||||
|
? showTime.defaultValue
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
'date',
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TimePanel
|
||||||
|
{...props}
|
||||||
|
format={undefined}
|
||||||
|
{...timeProps}
|
||||||
|
{...disabledTimes}
|
||||||
|
defaultValue={undefined}
|
||||||
|
operationRef={timeOperationRef}
|
||||||
|
active={activePanel.value === 'time'}
|
||||||
|
onSelect={date => {
|
||||||
|
onInternalSelect(date, 'time');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DatetimePanel.displayName ='DatetimePanel'
|
||||||
|
DatetimePanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default DatetimePanel;
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import { DECADE_DISTANCE_COUNT, DECADE_UNIT_DIFF } from '.';
|
||||||
|
import PanelBody from '../PanelBody';
|
||||||
|
|
||||||
|
export const DECADE_COL_COUNT = 3;
|
||||||
|
const DECADE_ROW_COUNT = 4;
|
||||||
|
|
||||||
|
export type YearBodyProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
viewDate: DateType;
|
||||||
|
disabledDate?: (date: DateType) => boolean;
|
||||||
|
onSelect: (value: DateType) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function DecadeBody<DateType>(props: YearBodyProps<DateType>) {
|
||||||
|
const DECADE_UNIT_DIFF_DES = DECADE_UNIT_DIFF - 1;
|
||||||
|
const { prefixCls, viewDate, generateConfig } = props;
|
||||||
|
|
||||||
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
||||||
|
const yearNumber = generateConfig.getYear(viewDate);
|
||||||
|
const decadeYearNumber = Math.floor(yearNumber / DECADE_UNIT_DIFF) * DECADE_UNIT_DIFF;
|
||||||
|
|
||||||
|
const startDecadeYear = Math.floor(yearNumber / DECADE_DISTANCE_COUNT) * DECADE_DISTANCE_COUNT;
|
||||||
|
const endDecadeYear = startDecadeYear + DECADE_DISTANCE_COUNT - 1;
|
||||||
|
|
||||||
|
const baseDecadeYear = generateConfig.setYear(
|
||||||
|
viewDate,
|
||||||
|
startDecadeYear -
|
||||||
|
Math.ceil(
|
||||||
|
(DECADE_COL_COUNT * DECADE_ROW_COUNT * DECADE_UNIT_DIFF - DECADE_DISTANCE_COUNT) / 2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const getCellClassName = (date: DateType) => {
|
||||||
|
const startDecadeNumber = generateConfig.getYear(date);
|
||||||
|
const endDecadeNumber = startDecadeNumber + DECADE_UNIT_DIFF_DES;
|
||||||
|
|
||||||
|
return {
|
||||||
|
[`${cellPrefixCls}-in-view`]:
|
||||||
|
startDecadeYear <= startDecadeNumber && endDecadeNumber <= endDecadeYear,
|
||||||
|
[`${cellPrefixCls}-selected`]: startDecadeNumber === decadeYearNumber,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PanelBody
|
||||||
|
{...props}
|
||||||
|
rowNum={DECADE_ROW_COUNT}
|
||||||
|
colNum={DECADE_COL_COUNT}
|
||||||
|
baseDate={baseDecadeYear}
|
||||||
|
getCellText={date => {
|
||||||
|
const startDecadeNumber = generateConfig.getYear(date);
|
||||||
|
return `${startDecadeNumber}-${startDecadeNumber + DECADE_UNIT_DIFF_DES}`;
|
||||||
|
}}
|
||||||
|
getCellClassName={getCellClassName}
|
||||||
|
getCellDate={(date, offset) => generateConfig.addYear(date, offset * DECADE_UNIT_DIFF)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DecadeBody.displayName ='DecadeBody'
|
||||||
|
DecadeBody.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default DecadeBody;
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
|
||||||
|
import Header from '../Header';
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import { DECADE_DISTANCE_COUNT } from '.';
|
||||||
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
|
|
||||||
|
export type YearHeaderProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
viewDate: DateType;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
|
||||||
|
onPrevDecades: () => void;
|
||||||
|
onNextDecades: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function DecadeHeader<DateType>(props: YearHeaderProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
generateConfig,
|
||||||
|
viewDate,
|
||||||
|
onPrevDecades,
|
||||||
|
onNextDecades,
|
||||||
|
} = props;
|
||||||
|
const { hideHeader } =useInjectPanel()
|
||||||
|
if (hideHeader) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerPrefixCls = `${prefixCls}-header`;
|
||||||
|
|
||||||
|
const yearNumber = generateConfig.getYear(viewDate);
|
||||||
|
const startYear =
|
||||||
|
Math.floor(yearNumber / DECADE_DISTANCE_COUNT) * DECADE_DISTANCE_COUNT;
|
||||||
|
const endYear = startYear + DECADE_DISTANCE_COUNT - 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Header
|
||||||
|
{...props}
|
||||||
|
prefixCls={headerPrefixCls}
|
||||||
|
onSuperPrev={onPrevDecades}
|
||||||
|
onSuperNext={onNextDecades}
|
||||||
|
>
|
||||||
|
{startYear}-{endYear}
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DecadeHeader.displayName ='DecadeHeader'
|
||||||
|
DecadeHeader.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default DecadeHeader;
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
|
||||||
|
import DecadeHeader from './DecadeHeader';
|
||||||
|
import DecadeBody, { DECADE_COL_COUNT } from './DecadeBody';
|
||||||
|
import type { PanelSharedProps } from '../../interface';
|
||||||
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
|
||||||
|
export type DecadePanelProps<DateType> = PanelSharedProps<DateType>;
|
||||||
|
|
||||||
|
export const DECADE_UNIT_DIFF = 10;
|
||||||
|
export const DECADE_DISTANCE_COUNT = DECADE_UNIT_DIFF * 10;
|
||||||
|
|
||||||
|
function DecadePanel<DateType>(props: DecadePanelProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
onViewDateChange,
|
||||||
|
generateConfig,
|
||||||
|
viewDate,
|
||||||
|
operationRef,
|
||||||
|
onSelect,
|
||||||
|
onPanelChange,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const panelPrefixCls = `${prefixCls}-decade-panel`;
|
||||||
|
|
||||||
|
// ======================= Keyboard =======================
|
||||||
|
operationRef.current = {
|
||||||
|
onKeyDown: event =>
|
||||||
|
createKeyDownHandler(event, {
|
||||||
|
onLeftRight: diff => {
|
||||||
|
onSelect(
|
||||||
|
generateConfig.addYear(viewDate, diff * DECADE_UNIT_DIFF),
|
||||||
|
'key',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onCtrlLeftRight: diff => {
|
||||||
|
onSelect(
|
||||||
|
generateConfig.addYear(viewDate, diff * DECADE_DISTANCE_COUNT),
|
||||||
|
'key',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onUpDown: diff => {
|
||||||
|
onSelect(
|
||||||
|
generateConfig.addYear(
|
||||||
|
viewDate,
|
||||||
|
diff * DECADE_UNIT_DIFF * DECADE_COL_COUNT,
|
||||||
|
),
|
||||||
|
'key',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onEnter: () => {
|
||||||
|
onPanelChange('year', viewDate);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== View Operation ====================
|
||||||
|
const onDecadesChange = (diff: number) => {
|
||||||
|
const newDate = generateConfig.addYear(
|
||||||
|
viewDate,
|
||||||
|
diff * DECADE_DISTANCE_COUNT,
|
||||||
|
);
|
||||||
|
onViewDateChange(newDate);
|
||||||
|
onPanelChange(null, newDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInternalSelect = (date: DateType) => {
|
||||||
|
onSelect(date, 'mouse');
|
||||||
|
onPanelChange('year', date);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={panelPrefixCls}>
|
||||||
|
<DecadeHeader
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
onPrevDecades={() => {
|
||||||
|
onDecadesChange(-1);
|
||||||
|
}}
|
||||||
|
onNextDecades={() => {
|
||||||
|
onDecadesChange(1);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<DecadeBody
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
onSelect={onInternalSelect}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DecadePanel.displayName ='DecadePanel'
|
||||||
|
DecadePanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default DecadePanel;
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { CSSProperties } from '@vue/runtime-dom';
|
||||||
|
import { VueNode } from '../../_util/type';
|
||||||
|
import { useInjectPanel } from '../PanelContext';
|
||||||
|
|
||||||
|
const HIDDEN_STYLE: CSSProperties = {
|
||||||
|
visibility: 'hidden',
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HeaderProps = {
|
||||||
|
prefixCls: string;
|
||||||
|
|
||||||
|
// Icons
|
||||||
|
prevIcon?: VueNode;
|
||||||
|
nextIcon?: VueNode;
|
||||||
|
superPrevIcon?: VueNode;
|
||||||
|
superNextIcon?: VueNode;
|
||||||
|
|
||||||
|
/** Last one step */
|
||||||
|
onPrev?: () => void;
|
||||||
|
/** Next one step */
|
||||||
|
onNext?: () => void;
|
||||||
|
/** Last multiple steps */
|
||||||
|
onSuperPrev?: () => void;
|
||||||
|
/** Next multiple steps */
|
||||||
|
onSuperNext?: () => void;
|
||||||
|
|
||||||
|
children?: VueNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
function Header(
|
||||||
|
{
|
||||||
|
prefixCls,
|
||||||
|
prevIcon = '\u2039',
|
||||||
|
nextIcon = '\u203A',
|
||||||
|
superPrevIcon = '\u00AB',
|
||||||
|
superNextIcon = '\u00BB',
|
||||||
|
onSuperPrev,
|
||||||
|
onSuperNext,
|
||||||
|
onPrev,
|
||||||
|
onNext,
|
||||||
|
}: HeaderProps,
|
||||||
|
{ slots },
|
||||||
|
) {
|
||||||
|
const { hideNextBtn, hidePrevBtn } = useInjectPanel();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={prefixCls}>
|
||||||
|
{onSuperPrev && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onSuperPrev}
|
||||||
|
tabindex={-1}
|
||||||
|
class={`${prefixCls}-super-prev-btn`}
|
||||||
|
style={hidePrevBtn ? HIDDEN_STYLE : {}}
|
||||||
|
>
|
||||||
|
{superPrevIcon}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{onPrev && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onPrev}
|
||||||
|
tabindex={-1}
|
||||||
|
class={`${prefixCls}-prev-btn`}
|
||||||
|
style={hidePrevBtn ? HIDDEN_STYLE : {}}
|
||||||
|
>
|
||||||
|
{prevIcon}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<div class={`${prefixCls}-view`}>{slots.default?.()}</div>
|
||||||
|
{onNext && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onNext}
|
||||||
|
tabindex={-1}
|
||||||
|
class={`${prefixCls}-next-btn`}
|
||||||
|
style={hideNextBtn ? HIDDEN_STYLE : {}}
|
||||||
|
>
|
||||||
|
{nextIcon}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{onSuperNext && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onSuperNext}
|
||||||
|
tabindex={-1}
|
||||||
|
class={`${prefixCls}-super-next-btn`}
|
||||||
|
style={hideNextBtn ? HIDDEN_STYLE : {}}
|
||||||
|
>
|
||||||
|
{superNextIcon}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Header.displayName = 'Header';
|
||||||
|
Header.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default Header;
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import type { Locale } from '../../interface';
|
||||||
|
import { formatValue, isSameMonth } from '../../utils/dateUtil';
|
||||||
|
import { useInjectRange } from '../../RangeContext';
|
||||||
|
import useCellClassName from '../../hooks/useCellClassName';
|
||||||
|
import PanelBody from '../PanelBody';
|
||||||
|
import { VueNode } from '../../../_util/type';
|
||||||
|
|
||||||
|
export const MONTH_COL_COUNT = 3;
|
||||||
|
const MONTH_ROW_COUNT = 4;
|
||||||
|
|
||||||
|
export type MonthCellRender<DateType> = (currentDate: DateType, locale: Locale) => VueNode;
|
||||||
|
|
||||||
|
export type MonthBodyProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
value?: DateType | null;
|
||||||
|
viewDate: DateType;
|
||||||
|
disabledDate?: (date: DateType) => boolean;
|
||||||
|
monthCellRender?: MonthCellRender<DateType>;
|
||||||
|
onSelect: (value: DateType) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function MonthBody<DateType>(props: MonthBodyProps<DateType>) {
|
||||||
|
const { prefixCls, locale, value, viewDate, generateConfig, monthCellRender } = props;
|
||||||
|
|
||||||
|
const { rangedValue, hoverRangedValue } = useInjectRange()
|
||||||
|
|
||||||
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
||||||
|
const getCellClassName = useCellClassName({
|
||||||
|
cellPrefixCls,
|
||||||
|
value,
|
||||||
|
generateConfig,
|
||||||
|
rangedValue,
|
||||||
|
hoverRangedValue,
|
||||||
|
isSameCell: (current, target) => isSameMonth(generateConfig, current, target),
|
||||||
|
isInView: () => true,
|
||||||
|
offsetCell: (date, offset) => generateConfig.addMonth(date, offset),
|
||||||
|
});
|
||||||
|
|
||||||
|
const monthsLocale: string[] =
|
||||||
|
locale.shortMonths ||
|
||||||
|
(generateConfig.locale.getShortMonths
|
||||||
|
? generateConfig.locale.getShortMonths(locale.locale)
|
||||||
|
: []);
|
||||||
|
|
||||||
|
const baseMonth = generateConfig.setMonth(viewDate, 0);
|
||||||
|
|
||||||
|
const getCellNode = monthCellRender
|
||||||
|
? (date: DateType) => monthCellRender(date, locale)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PanelBody
|
||||||
|
{...props}
|
||||||
|
rowNum={MONTH_ROW_COUNT}
|
||||||
|
colNum={MONTH_COL_COUNT}
|
||||||
|
baseDate={baseMonth}
|
||||||
|
getCellNode={getCellNode}
|
||||||
|
getCellText={date =>
|
||||||
|
locale.monthFormat
|
||||||
|
? formatValue(date, {
|
||||||
|
locale,
|
||||||
|
format: locale.monthFormat,
|
||||||
|
generateConfig,
|
||||||
|
})
|
||||||
|
: monthsLocale[generateConfig.getMonth(date)]
|
||||||
|
}
|
||||||
|
getCellClassName={getCellClassName}
|
||||||
|
getCellDate={generateConfig.addMonth}
|
||||||
|
titleCell={date =>
|
||||||
|
formatValue(date, {
|
||||||
|
locale,
|
||||||
|
format: 'YYYY-MM',
|
||||||
|
generateConfig,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MonthBody.displayName ='MonthBody'
|
||||||
|
MonthBody.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default MonthBody;
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
|
||||||
|
import Header from '../Header';
|
||||||
|
import type { Locale } from '../../interface';
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
|
import { formatValue } from '../../utils/dateUtil';
|
||||||
|
|
||||||
|
export type MonthHeaderProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
viewDate: DateType;
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
|
||||||
|
onPrevYear: () => void;
|
||||||
|
onNextYear: () => void;
|
||||||
|
onYearClick: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function MonthHeader<DateType>(props: MonthHeaderProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
generateConfig,
|
||||||
|
locale,
|
||||||
|
viewDate,
|
||||||
|
onNextYear,
|
||||||
|
onPrevYear,
|
||||||
|
onYearClick,
|
||||||
|
} = props;
|
||||||
|
const { hideHeader } = useInjectPanel()
|
||||||
|
if (hideHeader) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerPrefixCls = `${prefixCls}-header`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Header
|
||||||
|
{...props}
|
||||||
|
prefixCls={headerPrefixCls}
|
||||||
|
onSuperPrev={onPrevYear}
|
||||||
|
onSuperNext={onNextYear}
|
||||||
|
>
|
||||||
|
<button type="button" onClick={onYearClick} class={`${prefixCls}-year-btn`}>
|
||||||
|
{formatValue(viewDate, {
|
||||||
|
locale,
|
||||||
|
format: locale.yearFormat,
|
||||||
|
generateConfig,
|
||||||
|
})}
|
||||||
|
</button>
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MonthHeader.displayName ='MonthHeader'
|
||||||
|
MonthHeader.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default MonthHeader;
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
|
||||||
|
import MonthHeader from './MonthHeader';
|
||||||
|
import type { MonthCellRender } from './MonthBody';
|
||||||
|
import MonthBody, { MONTH_COL_COUNT } from './MonthBody';
|
||||||
|
import type { PanelSharedProps } from '../../interface';
|
||||||
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
|
||||||
|
export type MonthPanelProps<DateType> = {
|
||||||
|
monthCellContentRender?: MonthCellRender<DateType>;
|
||||||
|
} & PanelSharedProps<DateType>;
|
||||||
|
|
||||||
|
function MonthPanel<DateType>(props: MonthPanelProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
operationRef,
|
||||||
|
onViewDateChange,
|
||||||
|
generateConfig,
|
||||||
|
value,
|
||||||
|
viewDate,
|
||||||
|
onPanelChange,
|
||||||
|
onSelect,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const panelPrefixCls = `${prefixCls}-month-panel`;
|
||||||
|
|
||||||
|
// ======================= Keyboard =======================
|
||||||
|
operationRef.current = {
|
||||||
|
onKeyDown: event =>
|
||||||
|
createKeyDownHandler(event, {
|
||||||
|
onLeftRight: diff => {
|
||||||
|
onSelect(generateConfig.addMonth(value || viewDate, diff), 'key');
|
||||||
|
},
|
||||||
|
onCtrlLeftRight: diff => {
|
||||||
|
onSelect(generateConfig.addYear(value || viewDate, diff), 'key');
|
||||||
|
},
|
||||||
|
onUpDown: diff => {
|
||||||
|
onSelect(
|
||||||
|
generateConfig.addMonth(value || viewDate, diff * MONTH_COL_COUNT),
|
||||||
|
'key',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onEnter: () => {
|
||||||
|
onPanelChange('date', value || viewDate);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== View Operation ====================
|
||||||
|
const onYearChange = (diff: number) => {
|
||||||
|
const newDate = generateConfig.addYear(viewDate, diff);
|
||||||
|
onViewDateChange(newDate);
|
||||||
|
onPanelChange(null, newDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={panelPrefixCls}>
|
||||||
|
<MonthHeader
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
onPrevYear={() => {
|
||||||
|
onYearChange(-1);
|
||||||
|
}}
|
||||||
|
onNextYear={() => {
|
||||||
|
onYearChange(1);
|
||||||
|
}}
|
||||||
|
onYearClick={() => {
|
||||||
|
onPanelChange('year', viewDate);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<MonthBody<DateType>
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
onSelect={date => {
|
||||||
|
onSelect(date, 'mouse');
|
||||||
|
onPanelChange('date', date);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MonthPanel.displayName ='MonthPanel'
|
||||||
|
MonthPanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default MonthPanel;
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
|
||||||
|
import { useInjectPanel } from '../PanelContext';
|
||||||
|
import type { GenerateConfig } from '../generate';
|
||||||
|
import { getLastDay } from '../utils/timeUtil';
|
||||||
|
import type { PanelMode } from '../interface';
|
||||||
|
import { getCellDateDisabled } from '../utils/dateUtil';
|
||||||
|
import { VueNode } from '../../_util/type';
|
||||||
|
import classNames from '../../_util/classNames';
|
||||||
|
|
||||||
|
export type PanelBodyProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
disabledDate?: (date: DateType) => boolean;
|
||||||
|
onSelect: (value: DateType) => void;
|
||||||
|
picker?: PanelMode;
|
||||||
|
|
||||||
|
// By panel
|
||||||
|
headerCells?: VueNode;
|
||||||
|
rowNum: number;
|
||||||
|
colNum: number;
|
||||||
|
baseDate: DateType;
|
||||||
|
getCellClassName: (date: DateType) => Record<string, boolean | undefined>;
|
||||||
|
getCellDate: (date: DateType, offset: number) => DateType;
|
||||||
|
getCellText: (date: DateType) => VueNode;
|
||||||
|
getCellNode?: (date: DateType) => VueNode;
|
||||||
|
titleCell?: (date: DateType) => string;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
|
||||||
|
// Used for week panel
|
||||||
|
prefixColumn?: (date: DateType) => VueNode;
|
||||||
|
rowClassName?: (date: DateType) => string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function PanelBody<DateType>({
|
||||||
|
prefixCls,
|
||||||
|
disabledDate,
|
||||||
|
onSelect,
|
||||||
|
picker,
|
||||||
|
rowNum,
|
||||||
|
colNum,
|
||||||
|
prefixColumn,
|
||||||
|
rowClassName,
|
||||||
|
baseDate,
|
||||||
|
getCellClassName,
|
||||||
|
getCellText,
|
||||||
|
getCellNode,
|
||||||
|
getCellDate,
|
||||||
|
generateConfig,
|
||||||
|
titleCell,
|
||||||
|
headerCells,
|
||||||
|
}: PanelBodyProps<DateType>) {
|
||||||
|
const { onDateMouseEnter, onDateMouseLeave, mode } = useInjectPanel()
|
||||||
|
|
||||||
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
||||||
|
// =============================== Body ===============================
|
||||||
|
const rows: VueNode[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < rowNum; i += 1) {
|
||||||
|
const row: VueNode[] = [];
|
||||||
|
let rowStartDate: DateType;
|
||||||
|
|
||||||
|
for (let j = 0; j < colNum; j += 1) {
|
||||||
|
const offset = i * colNum + j;
|
||||||
|
const currentDate = getCellDate(baseDate, offset);
|
||||||
|
const disabled = getCellDateDisabled({
|
||||||
|
cellDate: currentDate,
|
||||||
|
mode,
|
||||||
|
disabledDate,
|
||||||
|
generateConfig,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (j === 0) {
|
||||||
|
rowStartDate = currentDate;
|
||||||
|
|
||||||
|
if (prefixColumn) {
|
||||||
|
row.push(prefixColumn(rowStartDate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = titleCell && titleCell(currentDate);
|
||||||
|
|
||||||
|
row.push(
|
||||||
|
<td
|
||||||
|
key={j}
|
||||||
|
title={title}
|
||||||
|
class={classNames(cellPrefixCls, {
|
||||||
|
[`${cellPrefixCls}-disabled`]: disabled,
|
||||||
|
[`${cellPrefixCls}-start`]:
|
||||||
|
getCellText(currentDate) === 1 || (picker === 'year' && Number(title) % 10 === 0),
|
||||||
|
[`${cellPrefixCls}-end`]:
|
||||||
|
title === getLastDay(generateConfig, currentDate) ||
|
||||||
|
(picker === 'year' && Number(title) % 10 === 9),
|
||||||
|
...getCellClassName(currentDate),
|
||||||
|
})}
|
||||||
|
onClick={() => {
|
||||||
|
if (!disabled) {
|
||||||
|
onSelect(currentDate);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseenter={() => {
|
||||||
|
if (!disabled && onDateMouseEnter) {
|
||||||
|
onDateMouseEnter(currentDate);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseleave={() => {
|
||||||
|
if (!disabled && onDateMouseLeave) {
|
||||||
|
onDateMouseLeave(currentDate);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getCellNode ? (
|
||||||
|
getCellNode(currentDate)
|
||||||
|
) : (
|
||||||
|
<div class={`${cellPrefixCls}-inner`}>{getCellText(currentDate)}</div>
|
||||||
|
)}
|
||||||
|
</td>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.push(
|
||||||
|
<tr key={i} class={rowClassName && rowClassName(rowStartDate!)}>
|
||||||
|
{row}
|
||||||
|
</tr>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={`${prefixCls}-body`}>
|
||||||
|
<table class={`${prefixCls}-content`}>
|
||||||
|
{headerCells && (
|
||||||
|
<thead>
|
||||||
|
<tr>{headerCells}</tr>
|
||||||
|
</thead>
|
||||||
|
)}
|
||||||
|
<tbody>{rows}</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelBody.displayName = 'PanelBody';
|
||||||
|
PanelBody.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default PanelBody;
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import type { Locale } from '../../interface';
|
||||||
|
import { formatValue, isSameQuarter } from '../../utils/dateUtil';
|
||||||
|
import RangeContext, { useInjectRange } from '../../RangeContext';
|
||||||
|
import useCellClassName from '../../hooks/useCellClassName';
|
||||||
|
import PanelBody from '../PanelBody';
|
||||||
|
|
||||||
|
export const QUARTER_COL_COUNT = 4;
|
||||||
|
const QUARTER_ROW_COUNT = 1;
|
||||||
|
|
||||||
|
export type QuarterBodyProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
value?: DateType | null;
|
||||||
|
viewDate: DateType;
|
||||||
|
disabledDate?: (date: DateType) => boolean;
|
||||||
|
onSelect: (value: DateType) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function QuarterBody<DateType>(props: QuarterBodyProps<DateType>) {
|
||||||
|
const { prefixCls, locale, value, viewDate, generateConfig } = props;
|
||||||
|
|
||||||
|
const { rangedValue, hoverRangedValue } = useInjectRange()
|
||||||
|
|
||||||
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
||||||
|
const getCellClassName = useCellClassName({
|
||||||
|
cellPrefixCls,
|
||||||
|
value,
|
||||||
|
generateConfig,
|
||||||
|
rangedValue,
|
||||||
|
hoverRangedValue,
|
||||||
|
isSameCell: (current, target) => isSameQuarter(generateConfig, current, target),
|
||||||
|
isInView: () => true,
|
||||||
|
offsetCell: (date, offset) => generateConfig.addMonth(date, offset * 3),
|
||||||
|
});
|
||||||
|
|
||||||
|
const baseQuarter = generateConfig.setDate(generateConfig.setMonth(viewDate, 0), 1);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PanelBody
|
||||||
|
{...props}
|
||||||
|
rowNum={QUARTER_ROW_COUNT}
|
||||||
|
colNum={QUARTER_COL_COUNT}
|
||||||
|
baseDate={baseQuarter}
|
||||||
|
getCellText={date =>
|
||||||
|
formatValue(date, {
|
||||||
|
locale,
|
||||||
|
format: locale.quarterFormat || '[Q]Q',
|
||||||
|
generateConfig,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getCellClassName={getCellClassName}
|
||||||
|
getCellDate={(date, offset) => generateConfig.addMonth(date, offset * 3)}
|
||||||
|
titleCell={date =>
|
||||||
|
formatValue(date, {
|
||||||
|
locale,
|
||||||
|
format: 'YYYY-[Q]Q',
|
||||||
|
generateConfig,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QuarterBody.displayName ='QuarterBody'
|
||||||
|
QuarterBody.inheritAttrs = false;
|
||||||
|
export default QuarterBody;
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
import Header from '../Header';
|
||||||
|
import type { Locale } from '../../interface';
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
|
import { formatValue } from '../../utils/dateUtil';
|
||||||
|
|
||||||
|
export type QuarterHeaderProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
viewDate: DateType;
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
|
||||||
|
onPrevYear: () => void;
|
||||||
|
onNextYear: () => void;
|
||||||
|
onYearClick: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function QuarterHeader<DateType>(props: QuarterHeaderProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
generateConfig,
|
||||||
|
locale,
|
||||||
|
viewDate,
|
||||||
|
onNextYear,
|
||||||
|
onPrevYear,
|
||||||
|
onYearClick,
|
||||||
|
} = props;
|
||||||
|
const { hideHeader } =useInjectPanel()
|
||||||
|
if (hideHeader) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerPrefixCls = `${prefixCls}-header`;
|
||||||
|
return (
|
||||||
|
<Header
|
||||||
|
{...props}
|
||||||
|
prefixCls={headerPrefixCls}
|
||||||
|
onSuperPrev={onPrevYear}
|
||||||
|
onSuperNext={onNextYear}
|
||||||
|
>
|
||||||
|
<button type="button" onClick={onYearClick} class={`${prefixCls}-year-btn`}>
|
||||||
|
{formatValue(viewDate, {
|
||||||
|
locale,
|
||||||
|
format: locale.yearFormat,
|
||||||
|
generateConfig,
|
||||||
|
})}
|
||||||
|
</button>
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QuarterHeader.displayName ='QuarterHeader'
|
||||||
|
QuarterHeader.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default QuarterHeader;
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
|
||||||
|
import QuarterHeader from './QuarterHeader';
|
||||||
|
import QuarterBody from './QuarterBody';
|
||||||
|
import type { PanelSharedProps } from '../../interface';
|
||||||
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
|
||||||
|
export type QuarterPanelProps<DateType> = {} & PanelSharedProps<DateType>;
|
||||||
|
|
||||||
|
function QuarterPanel<DateType>(props: QuarterPanelProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
operationRef,
|
||||||
|
onViewDateChange,
|
||||||
|
generateConfig,
|
||||||
|
value,
|
||||||
|
viewDate,
|
||||||
|
onPanelChange,
|
||||||
|
onSelect,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const panelPrefixCls = `${prefixCls}-quarter-panel`;
|
||||||
|
|
||||||
|
// ======================= Keyboard =======================
|
||||||
|
operationRef.current = {
|
||||||
|
onKeyDown: event =>
|
||||||
|
createKeyDownHandler(event, {
|
||||||
|
onLeftRight: diff => {
|
||||||
|
onSelect(generateConfig.addMonth(value || viewDate, diff * 3), 'key');
|
||||||
|
},
|
||||||
|
onCtrlLeftRight: diff => {
|
||||||
|
onSelect(generateConfig.addYear(value || viewDate, diff), 'key');
|
||||||
|
},
|
||||||
|
onUpDown: diff => {
|
||||||
|
onSelect(generateConfig.addYear(value || viewDate, diff), 'key');
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== View Operation ====================
|
||||||
|
const onYearChange = (diff: number) => {
|
||||||
|
const newDate = generateConfig.addYear(viewDate, diff);
|
||||||
|
onViewDateChange(newDate);
|
||||||
|
onPanelChange(null, newDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={panelPrefixCls}>
|
||||||
|
<QuarterHeader
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
onPrevYear={() => {
|
||||||
|
onYearChange(-1);
|
||||||
|
}}
|
||||||
|
onNextYear={() => {
|
||||||
|
onYearChange(1);
|
||||||
|
}}
|
||||||
|
onYearClick={() => {
|
||||||
|
onPanelChange('year', viewDate);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<QuarterBody<DateType>
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
onSelect={date => {
|
||||||
|
onSelect(date, 'mouse');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QuarterPanel.displayName ='QuarterPanel'
|
||||||
|
QuarterPanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default QuarterPanel;
|
||||||
|
|
@ -0,0 +1,249 @@
|
||||||
|
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import type { Locale, OnSelect } from '../../interface';
|
||||||
|
import type { Unit } from './TimeUnitColumn';
|
||||||
|
import TimeUnitColumn from './TimeUnitColumn';
|
||||||
|
import { leftPad } from '../../utils/miscUtil';
|
||||||
|
import type { SharedTimeProps } from '.';
|
||||||
|
import { setTime as utilSetTime } from '../../utils/timeUtil';
|
||||||
|
import { cloneElement } from '../../../_util/vnode';
|
||||||
|
import { VueNode } from '../../../_util/type';
|
||||||
|
import { Ref } from '@vue/reactivity';
|
||||||
|
|
||||||
|
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(
|
||||||
|
start: number,
|
||||||
|
end: number,
|
||||||
|
step: number,
|
||||||
|
disabledUnits: number[] | undefined,
|
||||||
|
) {
|
||||||
|
const units: Unit[] = [];
|
||||||
|
for (let i = start; i <= end; i += step) {
|
||||||
|
units.push({
|
||||||
|
label: leftPad(i, 2),
|
||||||
|
value: i,
|
||||||
|
disabled: (disabledUnits || []).includes(i),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BodyOperationRef = {
|
||||||
|
onUpDown: (diff: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TimeBodyProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
value?: DateType | null;
|
||||||
|
onSelect: OnSelect<DateType>;
|
||||||
|
activeColumnIndex: number;
|
||||||
|
operationRef: Ref<BodyOperationRef | undefined>;
|
||||||
|
} & SharedTimeProps<DateType>;
|
||||||
|
|
||||||
|
function TimeBody<DateType>(props: TimeBodyProps<DateType>) {
|
||||||
|
const {
|
||||||
|
generateConfig,
|
||||||
|
prefixCls,
|
||||||
|
operationRef,
|
||||||
|
activeColumnIndex,
|
||||||
|
value,
|
||||||
|
showHour,
|
||||||
|
showMinute,
|
||||||
|
showSecond,
|
||||||
|
use12Hours,
|
||||||
|
hourStep = 1,
|
||||||
|
minuteStep = 1,
|
||||||
|
secondStep = 1,
|
||||||
|
disabledHours,
|
||||||
|
disabledMinutes,
|
||||||
|
disabledSeconds,
|
||||||
|
hideDisabledOptions,
|
||||||
|
onSelect,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const columns: {
|
||||||
|
node: VueNode;
|
||||||
|
value: number;
|
||||||
|
units: Unit[];
|
||||||
|
onSelect: (diff: number) => void;
|
||||||
|
}[] = [];
|
||||||
|
const contentPrefixCls = `${prefixCls}-content`;
|
||||||
|
const columnPrefixCls = `${prefixCls}-time-panel`;
|
||||||
|
|
||||||
|
let isPM: boolean | undefined;
|
||||||
|
const originHour = value ? generateConfig.getHour(value) : -1;
|
||||||
|
let hour = originHour;
|
||||||
|
const minute = value ? generateConfig.getMinute(value) : -1;
|
||||||
|
const second = value ? generateConfig.getSecond(value) : -1;
|
||||||
|
|
||||||
|
const setTime = (
|
||||||
|
isNewPM: boolean | undefined,
|
||||||
|
newHour: number,
|
||||||
|
newMinute: number,
|
||||||
|
newSecond: number,
|
||||||
|
) => {
|
||||||
|
let newDate = value || generateConfig.getNow();
|
||||||
|
|
||||||
|
const mergedHour = Math.max(0, newHour);
|
||||||
|
const mergedMinute = Math.max(0, newMinute);
|
||||||
|
const mergedSecond = Math.max(0, newSecond);
|
||||||
|
|
||||||
|
newDate = utilSetTime(
|
||||||
|
generateConfig,
|
||||||
|
newDate,
|
||||||
|
!use12Hours || !isNewPM ? mergedHour : mergedHour + 12,
|
||||||
|
mergedMinute,
|
||||||
|
mergedSecond,
|
||||||
|
);
|
||||||
|
|
||||||
|
return newDate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========================= Unit =========================
|
||||||
|
const rawHours = generateUnits(0, 23, hourStep, disabledHours && disabledHours());
|
||||||
|
|
||||||
|
const memorizedRawHours = useMemo(() => rawHours, rawHours, shouldUnitsUpdate);
|
||||||
|
|
||||||
|
// Should additional logic to handle 12 hours
|
||||||
|
if (use12Hours) {
|
||||||
|
isPM = hour >= 12; // -1 means should display AM
|
||||||
|
hour %= 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [AMDisabled, PMDisabled] = React.useMemo(() => {
|
||||||
|
if (!use12Hours) {
|
||||||
|
return [false, false];
|
||||||
|
}
|
||||||
|
const AMPMDisabled = [true, true];
|
||||||
|
memorizedRawHours.forEach(({ disabled, value: hourValue }) => {
|
||||||
|
if (disabled) return;
|
||||||
|
if (hourValue >= 12) {
|
||||||
|
AMPMDisabled[1] = false;
|
||||||
|
} else {
|
||||||
|
AMPMDisabled[0] = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return AMPMDisabled;
|
||||||
|
}, [use12Hours, memorizedRawHours]);
|
||||||
|
|
||||||
|
const hours = React.useMemo(() => {
|
||||||
|
if (!use12Hours) return memorizedRawHours;
|
||||||
|
return memorizedRawHours
|
||||||
|
.filter(isPM ? hourMeta => hourMeta.value >= 12 : hourMeta => hourMeta.value < 12)
|
||||||
|
.map(hourMeta => {
|
||||||
|
const hourValue = hourMeta.value % 12;
|
||||||
|
const hourLabel = hourValue === 0 ? '12' : leftPad(hourValue, 2);
|
||||||
|
return {
|
||||||
|
...hourMeta,
|
||||||
|
label: hourLabel,
|
||||||
|
value: hourValue,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [use12Hours, isPM, memorizedRawHours]);
|
||||||
|
|
||||||
|
const minutes = generateUnits(0, 59, minuteStep, disabledMinutes && disabledMinutes(originHour));
|
||||||
|
|
||||||
|
const seconds = generateUnits(
|
||||||
|
0,
|
||||||
|
59,
|
||||||
|
secondStep,
|
||||||
|
disabledSeconds && disabledSeconds(originHour, minute),
|
||||||
|
);
|
||||||
|
|
||||||
|
// ====================== Operations ======================
|
||||||
|
operationRef.value = {
|
||||||
|
onUpDown: diff => {
|
||||||
|
const column = columns[activeColumnIndex];
|
||||||
|
if (column) {
|
||||||
|
const valueIndex = column.units.findIndex(unit => unit.value === column.value);
|
||||||
|
|
||||||
|
const unitLen = column.units.length;
|
||||||
|
for (let i = 1; i < unitLen; i += 1) {
|
||||||
|
const nextUnit = column.units[(valueIndex + diff * i + unitLen) % unitLen];
|
||||||
|
|
||||||
|
if (nextUnit.disabled !== true) {
|
||||||
|
column.onSelect(nextUnit.value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// ======================== Render ========================
|
||||||
|
function addColumnNode(
|
||||||
|
condition: boolean | undefined,
|
||||||
|
node: VueNode,
|
||||||
|
columnValue: number,
|
||||||
|
units: Unit[],
|
||||||
|
onColumnSelect: (diff: number) => void,
|
||||||
|
) {
|
||||||
|
if (condition !== false) {
|
||||||
|
columns.push({
|
||||||
|
node: cloneElement(node, {
|
||||||
|
prefixCls: columnPrefixCls,
|
||||||
|
value: columnValue,
|
||||||
|
active: activeColumnIndex === columns.length,
|
||||||
|
onSelect: onColumnSelect,
|
||||||
|
units,
|
||||||
|
hideDisabledOptions,
|
||||||
|
}),
|
||||||
|
onSelect: onColumnSelect,
|
||||||
|
value: columnValue,
|
||||||
|
units,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hour
|
||||||
|
addColumnNode(showHour, <TimeUnitColumn key="hour" />, hour, hours, num => {
|
||||||
|
onSelect(setTime(isPM, num, minute, second), 'mouse');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Minute
|
||||||
|
addColumnNode(showMinute, <TimeUnitColumn key="minute" />, minute, minutes, num => {
|
||||||
|
onSelect(setTime(isPM, hour, num, second), 'mouse');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Second
|
||||||
|
addColumnNode(showSecond, <TimeUnitColumn key="second" />, second, seconds, num => {
|
||||||
|
onSelect(setTime(isPM, hour, minute, num), 'mouse');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 12 Hours
|
||||||
|
let PMIndex = -1;
|
||||||
|
if (typeof isPM === 'boolean') {
|
||||||
|
PMIndex = isPM ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addColumnNode(
|
||||||
|
use12Hours === true,
|
||||||
|
<TimeUnitColumn key="12hours" />,
|
||||||
|
PMIndex,
|
||||||
|
[
|
||||||
|
{ label: 'AM', value: 0, disabled: AMDisabled },
|
||||||
|
{ label: 'PM', value: 1, disabled: PMDisabled },
|
||||||
|
],
|
||||||
|
num => {
|
||||||
|
onSelect(setTime(!!num, hour, minute, second), 'mouse');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return <div class={contentPrefixCls}>{columns.map(({ node }) => node)}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TimeBody.displayName ='TimeBody'
|
||||||
|
TimeBody.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default TimeBody;
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
|
||||||
|
import Header from '../Header';
|
||||||
|
import type { Locale } from '../../interface';
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
|
import { formatValue } from '../../utils/dateUtil';
|
||||||
|
|
||||||
|
export type TimeHeaderProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
value?: DateType | null;
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
format: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function TimeHeader<DateType>(props: TimeHeaderProps<DateType>) {
|
||||||
|
const { hideHeader } = useInjectPanel()
|
||||||
|
if (hideHeader) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { prefixCls, generateConfig, locale, value, format } = props;
|
||||||
|
const headerPrefixCls = `${prefixCls}-header`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Header prefixCls={headerPrefixCls}>
|
||||||
|
{value
|
||||||
|
? formatValue(value, {
|
||||||
|
locale,
|
||||||
|
format,
|
||||||
|
generateConfig,
|
||||||
|
})
|
||||||
|
: '\u00A0'}
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TimeHeader.displayName ='TimeHeader'
|
||||||
|
TimeHeader.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default TimeHeader;
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
import { scrollTo, waitElementReady } from '../../utils/uiUtil';
|
||||||
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
|
import classNames from '../../../_util/classNames';
|
||||||
|
import { ref } from '@vue/reactivity';
|
||||||
|
import { onBeforeUnmount, watch } from '@vue/runtime-core';
|
||||||
|
|
||||||
|
export type Unit = {
|
||||||
|
label: any;
|
||||||
|
value: number;
|
||||||
|
disabled: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TimeUnitColumnProps = {
|
||||||
|
prefixCls?: string;
|
||||||
|
units?: Unit[];
|
||||||
|
value?: number;
|
||||||
|
active?: boolean;
|
||||||
|
hideDisabledOptions?: boolean;
|
||||||
|
onSelect?: (value: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function TimeUnitColumn(props: TimeUnitColumnProps) {
|
||||||
|
const { prefixCls, units, onSelect, value, active, hideDisabledOptions } = props;
|
||||||
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
const { open } = useInjectPanel();
|
||||||
|
|
||||||
|
const ulRef = ref<HTMLUListElement>(null);
|
||||||
|
const liRefs = ref<Map<number, HTMLElement | null>>(new Map());
|
||||||
|
const scrollRef = ref<Function>();
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
() => {
|
||||||
|
const li = liRefs.value.get(value!);
|
||||||
|
if (li && open !== false) {
|
||||||
|
scrollTo(ulRef.value!, li.offsetTop, 120);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
scrollRef.value?.();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(open, () => {
|
||||||
|
scrollRef.value?.();
|
||||||
|
if (open) {
|
||||||
|
const li = liRefs.value.get(value!);
|
||||||
|
if (li) {
|
||||||
|
scrollRef.value = waitElementReady(li, () => {
|
||||||
|
scrollTo(ulRef.value!, li.offsetTop, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul
|
||||||
|
class={classNames(`${prefixCls}-column`, {
|
||||||
|
[`${prefixCls}-column-active`]: active,
|
||||||
|
})}
|
||||||
|
ref={ulRef}
|
||||||
|
style={{ position: 'relative' }}
|
||||||
|
>
|
||||||
|
{units!.map(unit => {
|
||||||
|
if (hideDisabledOptions && unit.disabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={unit.value}
|
||||||
|
ref={element => {
|
||||||
|
liRefs.value.set(unit.value, element as HTMLElement);
|
||||||
|
}}
|
||||||
|
class={classNames(cellPrefixCls, {
|
||||||
|
[`${cellPrefixCls}-disabled`]: unit.disabled,
|
||||||
|
[`${cellPrefixCls}-selected`]: value === unit.value,
|
||||||
|
})}
|
||||||
|
onClick={() => {
|
||||||
|
if (unit.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onSelect!(unit.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class={`${cellPrefixCls}-inner`}>{unit.label}</div>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeUnitColumn.displayName = 'TimeUnitColumn';
|
||||||
|
TimeUnitColumn.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default TimeUnitColumn;
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
|
||||||
|
import TimeHeader from './TimeHeader';
|
||||||
|
import type { BodyOperationRef } from './TimeBody';
|
||||||
|
import TimeBody from './TimeBody';
|
||||||
|
import type { PanelSharedProps, DisabledTimes } from '../../interface';
|
||||||
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
import classNames from '../../../_util/classNames';
|
||||||
|
import { ref } from '@vue/reactivity';
|
||||||
|
|
||||||
|
export type SharedTimeProps<DateType> = {
|
||||||
|
format?: string;
|
||||||
|
showNow?: boolean;
|
||||||
|
showHour?: boolean;
|
||||||
|
showMinute?: boolean;
|
||||||
|
showSecond?: boolean;
|
||||||
|
use12Hours?: boolean;
|
||||||
|
hourStep?: number;
|
||||||
|
minuteStep?: number;
|
||||||
|
secondStep?: number;
|
||||||
|
hideDisabledOptions?: boolean;
|
||||||
|
defaultValue?: DateType;
|
||||||
|
} & DisabledTimes;
|
||||||
|
|
||||||
|
export type TimePanelProps<DateType> = {
|
||||||
|
format?: string;
|
||||||
|
active?: boolean;
|
||||||
|
} & PanelSharedProps<DateType> & SharedTimeProps<DateType>;
|
||||||
|
|
||||||
|
const countBoolean = (boolList: (boolean | undefined)[]) =>
|
||||||
|
boolList.filter(bool => bool !== false).length;
|
||||||
|
|
||||||
|
function TimePanel<DateType>(props: TimePanelProps<DateType>) {
|
||||||
|
const {
|
||||||
|
generateConfig,
|
||||||
|
format = 'HH:mm:ss',
|
||||||
|
prefixCls,
|
||||||
|
active,
|
||||||
|
operationRef,
|
||||||
|
showHour,
|
||||||
|
showMinute,
|
||||||
|
showSecond,
|
||||||
|
use12Hours = false,
|
||||||
|
onSelect,
|
||||||
|
value,
|
||||||
|
} = props;
|
||||||
|
const panelPrefixCls = `${prefixCls}-time-panel`;
|
||||||
|
const bodyOperationRef = ref<BodyOperationRef>();
|
||||||
|
|
||||||
|
// ======================= Keyboard =======================
|
||||||
|
const activeColumnIndex = ref(-1);
|
||||||
|
const columnsCount = countBoolean([showHour, showMinute, showSecond, use12Hours]);
|
||||||
|
|
||||||
|
operationRef.current = {
|
||||||
|
onKeyDown: event =>
|
||||||
|
createKeyDownHandler(event, {
|
||||||
|
onLeftRight: diff => {
|
||||||
|
activeColumnIndex.value = (activeColumnIndex.value + diff + columnsCount) % columnsCount;
|
||||||
|
},
|
||||||
|
onUpDown: diff => {
|
||||||
|
if (activeColumnIndex.value === -1) {
|
||||||
|
activeColumnIndex.value = 0
|
||||||
|
} else if (bodyOperationRef.value) {
|
||||||
|
bodyOperationRef.value.onUpDown(diff);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEnter: () => {
|
||||||
|
onSelect(value || generateConfig.getNow(), 'key');
|
||||||
|
activeColumnIndex.value = -1
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
onBlur: () => {
|
||||||
|
activeColumnIndex.value = -1
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={classNames(panelPrefixCls, {
|
||||||
|
[`${panelPrefixCls}-active`]: active,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<TimeHeader {...props} format={format} prefixCls={prefixCls} />
|
||||||
|
<TimeBody
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
activeColumnIndex={activeColumnIndex.value}
|
||||||
|
operationRef={bodyOperationRef}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TimePanel.displayName ='TimePanel'
|
||||||
|
TimePanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default TimePanel;
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
import DatePanel from '../DatePanel';
|
||||||
|
import type { PanelSharedProps } from '../../interface';
|
||||||
|
import { isSameWeek } from '../../utils/dateUtil';
|
||||||
|
import classNames from '../../../_util/classNames';
|
||||||
|
|
||||||
|
export type WeekPanelProps<DateType> = PanelSharedProps<DateType>;
|
||||||
|
|
||||||
|
function WeekPanel<DateType>(props: WeekPanelProps<DateType>) {
|
||||||
|
const { prefixCls, generateConfig, locale, value } = props;
|
||||||
|
|
||||||
|
// Render additional column
|
||||||
|
const cellPrefixCls = `${prefixCls}-cell`;
|
||||||
|
const prefixColumn = (date: DateType) => (
|
||||||
|
<td
|
||||||
|
key="week"
|
||||||
|
class={classNames(cellPrefixCls, `${cellPrefixCls}-week`)}
|
||||||
|
>
|
||||||
|
{generateConfig.locale.getWeek(locale.locale, date)}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add row className
|
||||||
|
const rowPrefixCls = `${prefixCls}-week-panel-row`;
|
||||||
|
const rowClassName = (date: DateType) =>
|
||||||
|
classNames(rowPrefixCls, {
|
||||||
|
[`${rowPrefixCls}-selected`]: isSameWeek(
|
||||||
|
generateConfig,
|
||||||
|
locale.locale,
|
||||||
|
value,
|
||||||
|
date,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DatePanel
|
||||||
|
{...props}
|
||||||
|
panelName="week"
|
||||||
|
prefixColumn={prefixColumn}
|
||||||
|
rowClassName={rowClassName}
|
||||||
|
keyboardConfig={{
|
||||||
|
onLeftRight: null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WeekPanel.displayName = 'WeekPanel';
|
||||||
|
WeekPanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default WeekPanel;
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import { YEAR_DECADE_COUNT } from '.';
|
||||||
|
import type { Locale, NullableDateType } from '../../interface';
|
||||||
|
import useCellClassName from '../../hooks/useCellClassName';
|
||||||
|
import { formatValue, isSameYear } from '../../utils/dateUtil';
|
||||||
|
import RangeContext, { useInjectRange } from '../../RangeContext';
|
||||||
|
import PanelBody from '../PanelBody';
|
||||||
|
|
||||||
|
export const YEAR_COL_COUNT = 3;
|
||||||
|
const YEAR_ROW_COUNT = 4;
|
||||||
|
|
||||||
|
export type YearBodyProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
locale: Locale;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
value?: NullableDateType<DateType>;
|
||||||
|
viewDate: DateType;
|
||||||
|
disabledDate?: (date: DateType) => boolean;
|
||||||
|
onSelect: (value: DateType) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function YearBody<DateType>(props: YearBodyProps<DateType>) {
|
||||||
|
const { prefixCls, value, viewDate, locale, generateConfig } = props;
|
||||||
|
const { rangedValue, hoverRangedValue } = useInjectRange()
|
||||||
|
|
||||||
|
const yearPrefixCls = `${prefixCls}-cell`;
|
||||||
|
|
||||||
|
// =============================== Year ===============================
|
||||||
|
const yearNumber = generateConfig.getYear(viewDate);
|
||||||
|
const startYear = Math.floor(yearNumber / YEAR_DECADE_COUNT) * YEAR_DECADE_COUNT;
|
||||||
|
const endYear = startYear + YEAR_DECADE_COUNT - 1;
|
||||||
|
const baseYear = generateConfig.setYear(
|
||||||
|
viewDate,
|
||||||
|
startYear - Math.ceil((YEAR_COL_COUNT * YEAR_ROW_COUNT - YEAR_DECADE_COUNT) / 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
const isInView = (date: DateType) => {
|
||||||
|
const currentYearNumber = generateConfig.getYear(date);
|
||||||
|
return startYear <= currentYearNumber && currentYearNumber <= endYear;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCellClassName = useCellClassName<DateType>({
|
||||||
|
cellPrefixCls: yearPrefixCls,
|
||||||
|
value,
|
||||||
|
generateConfig,
|
||||||
|
rangedValue,
|
||||||
|
hoverRangedValue,
|
||||||
|
isSameCell: (current, target) => isSameYear(generateConfig, current, target),
|
||||||
|
isInView,
|
||||||
|
offsetCell: (date, offset) => generateConfig.addYear(date, offset),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PanelBody
|
||||||
|
{...props}
|
||||||
|
rowNum={YEAR_ROW_COUNT}
|
||||||
|
colNum={YEAR_COL_COUNT}
|
||||||
|
baseDate={baseYear}
|
||||||
|
getCellText={generateConfig.getYear}
|
||||||
|
getCellClassName={getCellClassName}
|
||||||
|
getCellDate={generateConfig.addYear}
|
||||||
|
titleCell={date =>
|
||||||
|
formatValue(date, {
|
||||||
|
locale,
|
||||||
|
format: 'YYYY',
|
||||||
|
generateConfig,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
YearBody.displayName = 'YearBody';
|
||||||
|
YearBody.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default YearBody;
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
import Header from '../Header';
|
||||||
|
import type { GenerateConfig } from '../../generate';
|
||||||
|
import { YEAR_DECADE_COUNT } from '.';
|
||||||
|
import { useInjectPanel } from '../../PanelContext';
|
||||||
|
|
||||||
|
export type YearHeaderProps<DateType> = {
|
||||||
|
prefixCls: string;
|
||||||
|
viewDate: DateType;
|
||||||
|
value?: DateType | null;
|
||||||
|
generateConfig: GenerateConfig<DateType>;
|
||||||
|
|
||||||
|
onPrevDecade: () => void;
|
||||||
|
onNextDecade: () => void;
|
||||||
|
onDecadeClick: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function YearHeader<DateType>(props: YearHeaderProps<DateType>) {
|
||||||
|
const { prefixCls, generateConfig, viewDate, onPrevDecade, onNextDecade, onDecadeClick } = props;
|
||||||
|
const { hideHeader } = useInjectPanel()
|
||||||
|
if (hideHeader) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerPrefixCls = `${prefixCls}-header`;
|
||||||
|
|
||||||
|
const yearNumber = generateConfig.getYear(viewDate);
|
||||||
|
const startYear = Math.floor(yearNumber / YEAR_DECADE_COUNT) * YEAR_DECADE_COUNT;
|
||||||
|
const endYear = startYear + YEAR_DECADE_COUNT - 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Header
|
||||||
|
{...props}
|
||||||
|
prefixCls={headerPrefixCls}
|
||||||
|
onSuperPrev={onPrevDecade}
|
||||||
|
onSuperNext={onNextDecade}
|
||||||
|
>
|
||||||
|
<button type="button" onClick={onDecadeClick} class={`${prefixCls}-decade-btn`}>
|
||||||
|
{startYear}-{endYear}
|
||||||
|
</button>
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
YearHeader.displayName = 'YearHeader';
|
||||||
|
YearHeader.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default YearHeader;
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
|
||||||
|
import YearHeader from './YearHeader';
|
||||||
|
import YearBody, { YEAR_COL_COUNT } from './YearBody';
|
||||||
|
import type { PanelSharedProps, PanelMode } from '../../interface';
|
||||||
|
import { createKeyDownHandler } from '../../utils/uiUtil';
|
||||||
|
|
||||||
|
export type YearPanelProps<DateType> = {
|
||||||
|
sourceMode: PanelMode;
|
||||||
|
} & PanelSharedProps<DateType>;
|
||||||
|
|
||||||
|
export const YEAR_DECADE_COUNT = 10;
|
||||||
|
|
||||||
|
function YearPanel<DateType>(props: YearPanelProps<DateType>) {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
operationRef,
|
||||||
|
onViewDateChange,
|
||||||
|
generateConfig,
|
||||||
|
value,
|
||||||
|
viewDate,
|
||||||
|
sourceMode,
|
||||||
|
onSelect,
|
||||||
|
onPanelChange,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const panelPrefixCls = `${prefixCls}-year-panel`;
|
||||||
|
|
||||||
|
// ======================= Keyboard =======================
|
||||||
|
operationRef.current = {
|
||||||
|
onKeyDown: event =>
|
||||||
|
createKeyDownHandler(event, {
|
||||||
|
onLeftRight: diff => {
|
||||||
|
onSelect(generateConfig.addYear(value || viewDate, diff), 'key');
|
||||||
|
},
|
||||||
|
onCtrlLeftRight: diff => {
|
||||||
|
onSelect(
|
||||||
|
generateConfig.addYear(value || viewDate, diff * YEAR_DECADE_COUNT),
|
||||||
|
'key',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onUpDown: diff => {
|
||||||
|
onSelect(
|
||||||
|
generateConfig.addYear(value || viewDate, diff * YEAR_COL_COUNT),
|
||||||
|
'key',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onEnter: () => {
|
||||||
|
onPanelChange(
|
||||||
|
sourceMode === 'date' ? 'date' : 'month',
|
||||||
|
value || viewDate,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== View Operation ====================
|
||||||
|
const onDecadeChange = (diff: number) => {
|
||||||
|
const newDate = generateConfig.addYear(viewDate, diff * 10);
|
||||||
|
onViewDateChange(newDate);
|
||||||
|
onPanelChange(null, newDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={panelPrefixCls}>
|
||||||
|
<YearHeader
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
onPrevDecade={() => {
|
||||||
|
onDecadeChange(-1);
|
||||||
|
}}
|
||||||
|
onNextDecade={() => {
|
||||||
|
onDecadeChange(1);
|
||||||
|
}}
|
||||||
|
onDecadeClick={() => {
|
||||||
|
onPanelChange('decade', viewDate);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<YearBody
|
||||||
|
{...props}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
onSelect={date => {
|
||||||
|
onPanelChange(sourceMode === 'date' ? 'date' : 'month', date);
|
||||||
|
onSelect(date, 'mouse');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
YearPanel.displayName = 'YearPanel';
|
||||||
|
YearPanel.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default YearPanel;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue