Skip to content

Commit 727ea20

Browse files
authored
feat(date-range-input): add isClearable prop (#745)
* feat(date-range-input): add is clearable prop
1 parent 3f8900c commit 727ea20

File tree

5 files changed

+121
-2
lines changed

5 files changed

+121
-2
lines changed

src/components/inputs/date-range-input/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ The `DateRangeInput` component allows the user to select a date range.
3232
| `id` | `string` | - | - | - | Used as the HTML `id` attribute. |
3333
| `name` | `string` | - | - | - | Used as the HTML `name` attribute. |
3434
| `placeholder` | `string` | - | - | - | Placeholder value to show in the input field |
35+
| `isClearable` | `bool` | - | - | `true` | allows the range to be cleared |
3536
| `isDisabled` | `bool` | - | - | `false` | Disables the date picker |
3637
| `hasError` | `bool` | - | - | - | Indicates the input field has an error |
3738
| `hasWarning` | `bool` | - | - | - | Indicates the input field has a warning |

src/components/inputs/date-range-input/date-range-input.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class DateRangeCalendar extends React.Component {
8989
formatMessage: PropTypes.func.isRequired,
9090
}).isRequired,
9191
horizontalConstraint: PropTypes.oneOf(['m', 'l', 'xl', 'scale']),
92+
isClearable: PropTypes.bool,
9293
value: PropTypes.arrayOf(PropTypes.string).isRequired,
9394
onChange: PropTypes.func.isRequired,
9495
onFocus: PropTypes.func,
@@ -100,6 +101,9 @@ class DateRangeCalendar extends React.Component {
100101
hasError: PropTypes.bool,
101102
hasWarning: PropTypes.bool,
102103
};
104+
static defaultProps = {
105+
isClearable: true,
106+
};
103107
static isEmpty = range => range.length === 0;
104108
static getDerivedStateFromProps(props, state) {
105109
// We need to update the input value string in case so that is is formatted
@@ -347,7 +351,8 @@ class DateRangeCalendar extends React.Component {
347351
// do not clear value when user presses Enter to
348352
// select the end date (so only clear when there is no
349353
// startDate)
350-
!this.state.startDate
354+
!this.state.startDate &&
355+
this.props.isClearable
351356
) {
352357
clearSelection();
353358
this.emit([]);
@@ -358,6 +363,7 @@ class DateRangeCalendar extends React.Component {
358363
...filterDataAttributes(this.props),
359364
})}
360365
hasSelection={this.props.value.length === 2}
366+
isClearable={this.props.isClearable}
361367
onClear={() => {
362368
this.setState({ startDate: null });
363369
this.emit([]);

src/components/inputs/date-range-input/date-range-input.spec.js

+105
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,111 @@ describe('when disabled', () => {
9494
});
9595
});
9696

97+
describe('when `isClearable` is true', () => {
98+
it('should allow clearing input with keyboard', () => {
99+
const onChange = jest.fn();
100+
const { queryByLabelText, getByLabelText } = renderDateRangeInput({
101+
onChange,
102+
});
103+
const event = { target: { value: '09/18/2018 - 09/20/2018' } };
104+
fireEvent.focus(getByLabelText('Date'));
105+
fireEvent.change(getByLabelText('Date'), event);
106+
fireEvent.keyDown(getByLabelText('Date'), { key: 'Enter' });
107+
fireEvent.keyUp(getByLabelText('Date'), { key: 'Enter' });
108+
109+
const clearEvent = { target: { value: '' } };
110+
fireEvent.focus(getByLabelText('Date'));
111+
fireEvent.change(getByLabelText('Date'), clearEvent);
112+
fireEvent.keyDown(getByLabelText('Date'), { key: 'Enter' });
113+
fireEvent.keyUp(getByLabelText('Date'), { key: 'Enter' });
114+
115+
expect(queryByLabelText('clear')).not.toBeInTheDocument();
116+
expect(onChange).toHaveBeenCalledWith({
117+
target: {
118+
id: 'date-range-input',
119+
name: undefined,
120+
value: [],
121+
},
122+
});
123+
});
124+
it('should allow clearing the input with icon button', () => {
125+
const onChange = jest.fn();
126+
const { queryByLabelText, getByLabelText } = renderDateRangeInput({
127+
onChange,
128+
});
129+
const event = { target: { value: '09/18/2018 - 09/20/2018' } };
130+
fireEvent.focus(getByLabelText('Date'));
131+
fireEvent.change(getByLabelText('Date'), event);
132+
fireEvent.keyDown(getByLabelText('Date'), { key: 'Enter' });
133+
fireEvent.keyUp(getByLabelText('Date'), { key: 'Enter' });
134+
135+
expect(getByLabelText('clear')).toBeInTheDocument();
136+
137+
getByLabelText('clear').click();
138+
expect(onChange).toHaveBeenCalledWith({
139+
target: {
140+
id: 'date-range-input',
141+
name: undefined,
142+
value: ['2018-09-18', '2018-09-20'],
143+
},
144+
});
145+
146+
expect(queryByLabelText('clear')).not.toBeInTheDocument();
147+
expect(onChange).toHaveBeenCalledWith({
148+
target: {
149+
id: 'date-range-input',
150+
name: undefined,
151+
value: [],
152+
},
153+
});
154+
});
155+
});
156+
157+
describe('when `isClearable` is false', () => {
158+
it('should not allow clearing input with keyboard', () => {
159+
const onChange = jest.fn();
160+
const { queryByLabelText, getByLabelText } = renderDateRangeInput({
161+
onChange,
162+
isClearable: false,
163+
});
164+
const event = { target: { value: '09/18/2018 - 09/20/2018' } };
165+
fireEvent.focus(getByLabelText('Date'));
166+
fireEvent.change(getByLabelText('Date'), event);
167+
fireEvent.keyDown(getByLabelText('Date'), { key: 'Enter' });
168+
fireEvent.keyUp(getByLabelText('Date'), { key: 'Enter' });
169+
170+
const clearEvent = { target: { value: '' } };
171+
fireEvent.focus(getByLabelText('Date'));
172+
fireEvent.change(getByLabelText('Date'), clearEvent);
173+
fireEvent.keyDown(getByLabelText('Date'), { key: 'Enter' });
174+
fireEvent.keyUp(getByLabelText('Date'), { key: 'Enter' });
175+
176+
expect(queryByLabelText('clear')).not.toBeInTheDocument();
177+
expect(onChange).not.toHaveBeenCalledWith({
178+
target: {
179+
id: 'date-range-input',
180+
name: undefined,
181+
value: [],
182+
},
183+
});
184+
});
185+
186+
it('should not allow clearing the input', () => {
187+
const onChange = jest.fn();
188+
const { queryByLabelText, getByLabelText } = renderDateRangeInput({
189+
onChange,
190+
isClearable: false,
191+
});
192+
const event = { target: { value: '09/18/2018 - 09/20/2018' } };
193+
fireEvent.focus(getByLabelText('Date'));
194+
fireEvent.change(getByLabelText('Date'), event);
195+
fireEvent.keyDown(getByLabelText('Date'), { key: 'Enter' });
196+
fireEvent.keyUp(getByLabelText('Date'), { key: 'Enter' });
197+
198+
expect(queryByLabelText('clear')).not.toBeInTheDocument();
199+
});
200+
});
201+
97202
describe('when locale is "en"', () => {
98203
it('should allow changing the value by typing a date in an american format', () => {
99204
const onChange = jest.fn();

src/components/inputs/date-range-input/date-range-input.story.js

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class DateRangeInputStory extends React.Component {
3434
id={text('id', '')}
3535
name={text('name', '')}
3636
placeholder={placeholder === '' ? undefined : placeholder}
37+
isClearable={boolean('isClearable', false)}
3738
isDisabled={boolean('isDisabled', false)}
3839
hasError={boolean('hasError', false)}
3940
hasWarning={boolean('hasWarning', false)}

src/components/internals/calendar-body/calendar-body.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const ClearSection = props => (
1313
<div
1414
onClick={props.isDisabled ? undefined : props.onClear}
1515
css={getClearSectionStyles(props)}
16+
aria-label="clear"
1617
>
1718
{!props.isDisabled && (
1819
<CloseIcon size="medium" theme={props.isDisabled ? 'grey' : 'black'} />
@@ -37,6 +38,7 @@ export default class CalendarBody extends React.PureComponent {
3738
onBlur: PropTypes.func,
3839
onFocus: PropTypes.func,
3940
}),
41+
isClearable: PropTypes.bool,
4042
toggleButtonProps: PropTypes.shape({
4143
onBlur: PropTypes.func,
4244
onFocus: PropTypes.func,
@@ -53,6 +55,10 @@ export default class CalendarBody extends React.PureComponent {
5355
horizontalConstraint: PropTypes.oneOf(['xs', 's', 'm', 'l', 'xl', 'scale']),
5456
};
5557

58+
static defaultProps = {
59+
isClearable: true,
60+
};
61+
5662
state = {
5763
isFocused: false,
5864
};
@@ -76,7 +82,7 @@ export default class CalendarBody extends React.PureComponent {
7682
this.props.inputProps.onBlur(event);
7783
}}
7884
/>
79-
{this.props.hasSelection && (
85+
{this.props.hasSelection && this.props.isClearable && (
8086
<ClearSection
8187
isDisabled={this.props.isDisabled}
8288
hasError={this.props.hasError}

0 commit comments

Comments
 (0)