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