Skip to content

Commit c4c66a9

Browse files
committed
fix(ui-time-select): clear input field after setting an empty value
1 parent 6c85b31 commit c4c66a9

File tree

3 files changed

+48
-10
lines changed

3 files changed

+48
-10
lines changed

cypress/component/TimeSelect.cy.tsx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ import moment from 'moment-timezone'
2626
import 'cypress-real-events'
2727

2828
import '../support/component'
29-
import { TimeSelect } from '../../packages/ui'
30-
import { DateTime } from '../../packages/ui-i18n'
29+
import { TimeSelect } from '@instructure/ui'
30+
import { DateTime } from '@instructure/ui-i18n'
3131

3232
describe('<TimeSelect/>', () => {
3333
it('should render an input and list', async () => {
@@ -70,6 +70,33 @@ describe('<TimeSelect/>', () => {
7070
})
7171
})
7272

73+
it('should fire onChange when input field is cleared and blurred', async () => {
74+
const onChange = cy.spy()
75+
cy.mount(
76+
<TimeSelect
77+
renderLabel="Choose a time"
78+
timezone="US/Eastern"
79+
onChange={onChange}
80+
/>
81+
)
82+
cy.get('input[id^="Select_"]').as('input')
83+
84+
cy.get('@input').click()
85+
86+
cy.get('li[class$="-optionItem"]').eq(0).click()
87+
88+
cy.get('@input').click()
89+
cy.get('@input').clear()
90+
cy.get('@input').blur()
91+
92+
cy.wrap(onChange)
93+
.should('have.been.called')
94+
.then((spy) => {
95+
expect(spy.lastCall.args[1]).to.have.property('value', '')
96+
expect(spy.lastCall.args[1]).to.have.property('inputText', '')
97+
})
98+
})
99+
73100
it('should behave uncontrolled', async () => {
74101
const onChange = cy.spy()
75102
cy.mount(<TimeSelect renderLabel="Choose a time" onChange={onChange} />)

packages/ui-time-select/src/TimeSelect/index.tsx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ class TimeSelect extends Component<TimeSelectProps, TimeSelectState> {
220220
: initialOptions,
221221
isShowingOptions: false,
222222
highlightedOptionId: initialSelection ? initialSelection.id : undefined,
223-
selectedOptionId: initialSelection ? initialSelection.id : undefined
223+
selectedOptionId: initialSelection ? initialSelection.id : undefined,
224+
isInputCleared: false
224225
}
225226
}
226227

@@ -338,7 +339,8 @@ class TimeSelect extends Component<TimeSelectProps, TimeSelectState> {
338339
selectedOptionId: this.isControlled
339340
? this.state.selectedOptionId
340341
: undefined,
341-
fireChangeOnBlur: undefined
342+
fireChangeOnBlur: undefined,
343+
isInputCleared: value === '' ? true : false
342344
})
343345
}
344346
this.setState({
@@ -386,7 +388,7 @@ class TimeSelect extends Component<TimeSelectProps, TimeSelectState> {
386388
// when pressing ESC. NOT called when an item is selected via Enter/click,
387389
// (but in this case it will be called later when the input is blurred.)
388390
handleBlurOrEsc: SelectProps['onRequestHideOptions'] = (event) => {
389-
const { selectedOptionId, inputValue } = this.state
391+
const { selectedOptionId, inputValue, isInputCleared } = this.state
390392
let defaultValue = ''
391393
if (this.props.defaultValue) {
392394
const date = DateTime.parse(
@@ -400,14 +402,13 @@ class TimeSelect extends Component<TimeSelectProps, TimeSelectState> {
400402
}
401403
const selectedOption = this.getOption('id', selectedOptionId)
402404
let newInputValue = defaultValue
403-
if (selectedOption) {
404-
// If there is a selected option use its value in the input field.
405-
newInputValue = selectedOption.label
406-
}
407405
// if input was completely cleared, ensure it stays clear
408406
// e.g. defaultValue defined, but no selection yet made
409-
else if (inputValue === '') {
407+
if (inputValue === '') {
410408
newInputValue = ''
409+
} else if (selectedOption) {
410+
// If there is a selected option use its value in the input field.
411+
newInputValue = selectedOption.label
411412
}
412413
this.setState(() => ({
413414
isShowingOptions: false,
@@ -421,6 +422,12 @@ class TimeSelect extends Component<TimeSelectProps, TimeSelectState> {
421422
value: this.state.fireChangeOnBlur.value.toISOString(),
422423
inputText: this.state.fireChangeOnBlur.label
423424
})
425+
} else if (isInputCleared && (event as any).key !== 'Escape') {
426+
this.setState(() => ({ isInputCleared: false }))
427+
this.props.onChange?.(event, {
428+
value: '',
429+
inputText: ''
430+
})
424431
}
425432
// TODO only fire this if handleSelectOption was not called before.
426433
this.props.onHideOptions?.(event)

packages/ui-time-select/src/TimeSelect/props.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,10 @@ type TimeSelectState = {
356356
* fire onChange event when the popup closes?
357357
*/
358358
fireChangeOnBlur?: TimeSelectOptions
359+
/**
360+
* Whether to selected option is cleared
361+
*/
362+
isInputCleared: boolean
359363
}
360364

361365
export type { TimeSelectProps, TimeSelectState, TimeSelectOptions }

0 commit comments

Comments
 (0)