Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: disabledTime validate user input #690

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 46 additions & 13 deletions src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
import type { AlignType } from '@rc-component/trigger/lib/interface';
import classNames from 'classnames';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import warning from 'rc-util/lib/warning';
import pickAttrs from 'rc-util/lib/pickAttrs';
import warning from 'rc-util/lib/warning';
import * as React from 'react';
import { GenerateConfig } from './generate';
import useHoverValue from './hooks/useHoverValue';
import usePickerInput from './hooks/usePickerInput';
import usePresets from './hooks/usePresets';
import useTextValueMapping from './hooks/useTextValueMapping';
import useValueTexts from './hooks/useValueTexts';
import type { CustomFormat, PickerMode, PresetDate } from './interface';
import type { CustomFormat, DisabledTime, PickerMode, PresetDate } from './interface';
import type { ContextOperationRefProps } from './PanelContext';
import PanelContext from './PanelContext';
import type {
Expand All @@ -34,10 +35,10 @@
import PickerTrigger from './PickerTrigger';
import PresetPanel from './PresetPanel';
import { formatValue, isEqual, parseValue } from './utils/dateUtil';
import { getClearIcon } from './utils/getClearIcon';
import { toArray } from './utils/miscUtil';
import { elementsContains, getDefaultFormat, getInputSize } from './utils/uiUtil';
import { legacyPropsWarning } from './utils/warnUtil';
import { getClearIcon } from './utils/getClearIcon';

export type PickerRefConfig = {
focus: () => void;
Expand Down Expand Up @@ -67,8 +68,8 @@

// Render
suffixIcon?: React.ReactNode;
/**
* Clear all icon
/**
* Clear all icon
* @deprecated Please use `allowClear` instead
**/
clearIcon?: React.ReactNode;
Expand Down Expand Up @@ -145,6 +146,32 @@
picker?: PickerMode;
} & OmitType<DateType>;

function testValueInSet(num: number, range: number[]) {
if (typeof num === 'undefined' || typeof range === 'undefined') return;
const set = new Set(range);
return set.has(num);
}

function validateTime<DateType>(
picker: PickerMode,
disabledTime: DisabledTime<DateType>,
date: DateType,
generateConfig: GenerateConfig<DateType>,
) {
if (!disabledTime || picker !== 'date') return false;
const disabledTimes = disabledTime(date);
if (!disabledTimes) return false;
const { disabledHours, disabledMinutes, disabledSeconds } = disabledTimes;
const hour = generateConfig.getHour(date);
const minter = generateConfig.getMinute(date);
const second = generateConfig.getSecond(date);

const validateHour = testValueInSet(hour, disabledHours?.());
const validateMinute = testValueInSet(minter, disabledMinutes?.(hour));
const validateSecond = testValueInSet(second, disabledSeconds?.(hour, minter));
return validateHour || validateMinute || validateSecond;
}

function InnerPicker<DateType>(props: PickerProps<DateType>) {
const {
prefixCls = 'rc-picker',
Expand Down Expand Up @@ -196,6 +223,7 @@
autoComplete = 'off',
inputRender,
changeOnBlur,
disabledTime,
} = props as MergedPickerProps<DateType>;

const inputRef = React.useRef<HTMLInputElement>(null);
Expand Down Expand Up @@ -253,6 +281,8 @@
locale,
});

const timeProps = typeof showTime === 'object' ? showTime : {};

const [text, triggerTextChange, resetText] = useTextValueMapping({
valueTexts,
onTextChange: (newText) => {
Expand All @@ -261,7 +291,11 @@
formatList,
generateConfig,
});
if (inputDate && (!disabledDate || !disabledDate(inputDate))) {
if (
inputDate &&
(!disabledDate || !disabledDate(inputDate)) &&
!validateTime(picker, disabledTime, inputDate || timeProps?.defaultValue, generateConfig)
) {
setSelectedValue(inputDate);
}
},
Expand Down Expand Up @@ -340,7 +374,8 @@
// When user typing disabledDate with keyboard and enter, this value will be empty
!selectedValue ||
// Normal disabled check
(disabledDate && disabledDate(selectedValue))
(disabledDate && disabledDate(selectedValue)) ||
validateTime(picker, disabledTime, selectedValue || timeProps?.defaultValue, generateConfig)
Fixed Show fixed Hide fixed
) {
return false;
}
Expand Down Expand Up @@ -490,11 +525,7 @@
);
}

const mergedClearIcon: React.ReactNode = getClearIcon(
prefixCls,
allowClear,
clearIcon,
);
const mergedClearIcon: React.ReactNode = getClearIcon(prefixCls, allowClear, clearIcon);

const clearNode: React.ReactNode = (
<span
Expand All @@ -517,7 +548,9 @@

const mergedAllowClear = !!allowClear && mergedValue && !disabled;

const mergedInputProps: React.InputHTMLAttributes<HTMLInputElement> & { ref: React.MutableRefObject<HTMLInputElement> } = {
const mergedInputProps: React.InputHTMLAttributes<HTMLInputElement> & {
ref: React.MutableRefObject<HTMLInputElement>;
} = {
id,
tabIndex,
disabled,
Expand Down
Loading