diff --git a/packages/core/src/components/DatePicker/DatePicker.test.tsx b/packages/core/src/components/DatePicker/DatePicker.test.tsx
index 92600519a..71031f801 100644
--- a/packages/core/src/components/DatePicker/DatePicker.test.tsx
+++ b/packages/core/src/components/DatePicker/DatePicker.test.tsx
@@ -236,6 +236,16 @@ describe('DatePicker component', () => {
fireEvent.change(screen.getByRole('textbox'), { target: { value: '01 / 02' } });
expect(mockOnChange).toHaveBeenCalledWith(null);
});
+
+ it('should call onChange with null if we delete char from the middle', async () => {
+ const mockOnChange = jest.fn(),
+ dateToSelect = new Date(2020, 0, 2);
+ render();
+ fireEvent.change(screen.getByRole('textbox'), { target: { value: '01 / 02 / 2020' } });
+ expect(mockOnChange).toHaveBeenCalledWith(dateToSelect);
+ fireEvent.change(screen.getByRole('textbox'), { target: { value: '01 / 0 / 2020' } });
+ expect(mockOnChange).toHaveBeenCalledWith(null);
+ });
});
describe('error messages', () => {
diff --git a/packages/core/src/components/DatePicker/DatePicker.tsx b/packages/core/src/components/DatePicker/DatePicker.tsx
index 0258791d9..0ec554c86 100644
--- a/packages/core/src/components/DatePicker/DatePicker.tsx
+++ b/packages/core/src/components/DatePicker/DatePicker.tsx
@@ -39,6 +39,7 @@ const Component: FC = memo(
() => (value instanceof Date ? value : typeof value === 'string' ? parseToDate(value, displayFormat!) : null),
[value, displayFormat]
);
+
const wrapperRef = useRef(null),
inputRef = useCombinedRefs(ref, useRef(null)),
[inputKey, setInputKey] = useState(0),
@@ -49,9 +50,7 @@ const Component: FC = memo(
isErrorPresent = useMemo(() => !!errorText || !!builtInErrorMessage, [errorText, builtInErrorMessage]);
useEffect(() => {
- if (date === null) {
- setTextValue('');
- } else if (date) {
+ if (date) {
setTextValue(format(date, displayFormat!).replace(new RegExp('\\/|\\-', 'g'), ' $& '));
}
}, [date, displayFormat]);
diff --git a/packages/core/src/components/DatePicker/__snapshots__/DatePicker.test.tsx.snap b/packages/core/src/components/DatePicker/__snapshots__/DatePicker.test.tsx.snap
index cd2fa0d9e..0d5f00b61 100644
--- a/packages/core/src/components/DatePicker/__snapshots__/DatePicker.test.tsx.snap
+++ b/packages/core/src/components/DatePicker/__snapshots__/DatePicker.test.tsx.snap
@@ -175,6 +175,7 @@ exports[`DatePicker component calendar icon should show calendar icon displayed
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
top: 50%;
-webkit-transform: translateY(-50%);
@@ -572,6 +573,7 @@ exports[`DatePicker component calendar icon should show calendar icon displayed
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
top: 50%;
-webkit-transform: translateY(-50%);
@@ -13428,6 +13430,7 @@ exports[`DatePicker component should render properly when hideInput prop is pass
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
@@ -13827,6 +13830,7 @@ exports[`DatePicker component should render properly when value is of date type
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
@@ -14207,6 +14211,7 @@ exports[`DatePicker component should render properly when value is of string typ
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
top: 50%;
-webkit-transform: translateY(-50%);
diff --git a/packages/core/src/components/DateRangePicker/DateRangeTextFields/useDateRangeTextFieldsHandlers.ts b/packages/core/src/components/DateRangePicker/DateRangeTextFields/useDateRangeTextFieldsHandlers.ts
index b28f94010..0857c8d93 100644
--- a/packages/core/src/components/DateRangePicker/DateRangeTextFields/useDateRangeTextFieldsHandlers.ts
+++ b/packages/core/src/components/DateRangePicker/DateRangeTextFields/useDateRangeTextFieldsHandlers.ts
@@ -48,10 +48,10 @@ export const useDateRangeTextFieldsHandlers = (props: Props) => {
}, []),
handleTextChange = useCallback(
(e: React.ChangeEvent) => {
- const maskedValue = getMaskedValue(e, mask),
+ const { maskedValue, selectionStart } = getMaskedValue(e, mask),
parsedDate = parseToDate(e.target.value, displayFormat),
maskedLabel = `${maskedValue}${mask.substr(maskedValue.length)}`;
-
+ e.target.setSelectionRange(selectionStart, selectionStart);
if (e.target.name === 'START_DATE') {
setStartDateText(maskedValue);
setStartDateMaskLabel(maskedLabel);
@@ -101,8 +101,11 @@ export const useDateRangeTextFieldsHandlers = (props: Props) => {
validateOnWrapperBlur = useCallback(
(event: ChangeEvent) => {
const validatorMessage = (validator && validator(selectedDates, event)) || '',
- customMessage = (required && !selectedDates.startDate && !selectedDates.endDate && 'Please fill in this field.') || '',
- message = validator ? validatorMessage : customMessage;
+ customRequiredMessage =
+ required && (!selectedDates.startDate || !selectedDates.endDate) && 'Please fill in this field.',
+ customInvalidMessage =
+ (!isValidDate(selectedDates.startDate) || !isValidDate(selectedDates.endDate)) && 'Enter valid date',
+ message = validator ? validatorMessage : customRequiredMessage || customInvalidMessage || '';
setErrorMessage(message);
if (validator) {
startDateRef.current?.setCustomValidity(validatorMessage);
@@ -115,10 +118,10 @@ export const useDateRangeTextFieldsHandlers = (props: Props) => {
useEffect(() => {
const formattedStartDate = selectedDates.startDate ? getFormattedDate(selectedDates.startDate, displayFormat) : '',
formattedEndDate = selectedDates.endDate ? getFormattedDate(selectedDates.endDate, displayFormat) : '';
- setStartDateText(formattedStartDate);
- setEndDateText(formattedEndDate);
- setStartDateMaskLabel(formattedStartDate || mask);
- setEndDateMaskLabel(formattedEndDate || mask);
+ formattedStartDate && setStartDateText(formattedStartDate);
+ formattedEndDate && setEndDateText(formattedEndDate);
+ formattedStartDate && setStartDateMaskLabel(formattedStartDate || mask);
+ formattedEndDate && setEndDateMaskLabel(formattedEndDate || mask);
isValidDate(selectedDates.startDate) && isValidDate(selectedDates.endDate) && setErrorMessage('');
}, [isActive, selectedDates, displayFormat]);
diff --git a/packages/core/src/components/DateRangePicker/__snapshots__/DateRangePicker.test.tsx.snap b/packages/core/src/components/DateRangePicker/__snapshots__/DateRangePicker.test.tsx.snap
index fab0d8870..57896ad8f 100644
--- a/packages/core/src/components/DateRangePicker/__snapshots__/DateRangePicker.test.tsx.snap
+++ b/packages/core/src/components/DateRangePicker/__snapshots__/DateRangePicker.test.tsx.snap
@@ -1901,6 +1901,7 @@ exports[`DateRangePicker Custom date range options should render properly with c
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
@@ -24175,6 +24176,7 @@ exports[`DateRangePicker should render properly 1`] = `
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
@@ -26424,6 +26426,7 @@ exports[`DateRangePicker should render properly with single month 1`] = `
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
diff --git a/packages/core/src/components/TextField/Styled/MaskPlaceholder.styled.tsx b/packages/core/src/components/TextField/Styled/MaskPlaceholder.styled.tsx
index 0388d0a03..0ef9f5d22 100644
--- a/packages/core/src/components/TextField/Styled/MaskPlaceholder.styled.tsx
+++ b/packages/core/src/components/TextField/Styled/MaskPlaceholder.styled.tsx
@@ -20,6 +20,7 @@ export const MaskPlaceholder = styled('span')<{
cursor: text;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: ${({ theme }) => theme.textField.filled.active.placeholderColor};
${({ isLabelPresent, size }) => (isLabelPresent && size !== 'S' ? bottom : center)}
`;
diff --git a/packages/core/src/components/TextField/TextField.tsx b/packages/core/src/components/TextField/TextField.tsx
index 146136531..684e7fbfb 100644
--- a/packages/core/src/components/TextField/TextField.tsx
+++ b/packages/core/src/components/TextField/TextField.tsx
@@ -91,8 +91,9 @@ const Component: FC = memo(
setCharacterCountValue(valueString.length);
if (mask) {
- const maskedValue = getMaskedValue(e, mask);
+ const { maskedValue, selectionStart } = getMaskedValue(e, mask);
e.target.value = maskedValue;
+ e.target.setSelectionRange(selectionStart, selectionStart);
setMaskLabel(`${maskedValue}${mask.substr(maskedValue.length)}`);
}
props.onChange && props.onChange(e);
diff --git a/packages/core/src/components/TextField/getMaskedValue.test.ts b/packages/core/src/components/TextField/getMaskedValue.test.ts
index ee087fcca..b34f47c20 100644
--- a/packages/core/src/components/TextField/getMaskedValue.test.ts
+++ b/packages/core/src/components/TextField/getMaskedValue.test.ts
@@ -5,14 +5,14 @@ describe('getMaskedValue function', () => {
const maskedValue = (value: string, selectionStart?: number) => getMaskedValue({ target: { value, selectionStart } }, 'DD / MM / YYYY');
it('should return truncated value if selectionStart value is less then value length', () => {
- expect(maskedValue('11 / 11 / 1111', 6)).toEqual('11 / 1');
+ expect(maskedValue('11 / 11 / 1111', 6)).toEqual({ maskedValue: '11 / 1 1 / 1111', selectionStart: 6 });
});
it('should not add extra char if value length is equal to mask length', () => {
- expect(maskedValue('11 / 11 / 11111')).toEqual('11 / 11 / 1111');
+ expect(maskedValue('11 / 11 / 11111')).toEqual({ maskedValue: '11 / 11 / 1111', selectionStart: 14 });
});
it('should add special character in between', () => {
- expect(maskedValue('11 / 111')).toEqual('11 / 11 / 1');
+ expect(maskedValue('11 / 111')).toEqual({ maskedValue: '11 / 11 / 1', selectionStart: 11 });
});
});
diff --git a/packages/core/src/components/TextField/getMaskedValue.ts b/packages/core/src/components/TextField/getMaskedValue.ts
index 1eef3cc63..982e7ca57 100644
--- a/packages/core/src/components/TextField/getMaskedValue.ts
+++ b/packages/core/src/components/TextField/getMaskedValue.ts
@@ -35,15 +35,15 @@ export const getMaskedValue = (event: React.ChangeEvent, mask:
//TODO: Need to remove this if, when we handle masking when user deletes from the middle of the text
if (selectionStart && selectionStart < value.length) {
- maskedValue = value.slice(0, selectionStart);
+ maskedValue = `${value.slice(0, selectionStart)} ${value.slice(selectionStart)}`;
+ return { maskedValue, selectionStart };
} else {
maskedValue = value
.replace(specialCharsRegex, '')
.split('')
.reduce((acc: string, c: string) => applyMasking(acc + c, mask, selectionStart ?? 0), '');
+ return { maskedValue, selectionStart: maskedValue.length };
}
-
- return maskedValue;
};
export default getMaskedValue;
diff --git a/packages/forms/src/components/Form/__snapshots__/Form.test.tsx.snap b/packages/forms/src/components/Form/__snapshots__/Form.test.tsx.snap
index f032f0a5a..b61171318 100644
--- a/packages/forms/src/components/Form/__snapshots__/Form.test.tsx.snap
+++ b/packages/forms/src/components/Form/__snapshots__/Form.test.tsx.snap
@@ -542,6 +542,7 @@ exports[`Form should render properly with initial state 1`] = `
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
@@ -2960,6 +2961,7 @@ exports[`Form should render properly without initial state 1`] = `
-ms-user-select: none;
user-select: none;
pointer-events: none;
+ white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}