Repository: laboratoriobridge/bold
Pull request #480 (2019-10-03 16:19:38)

Clearing Select value when text input is cleared


Patch:
diff --git a/site/pages/components/select/Select.demo.tsx b/site/pages/components/select/Select.demo.tsx
index 454695128..e228650d4 100644
--- a/site/pages/components/select/Select.demo.tsx
+++ b/site/pages/components/select/Select.demo.tsx
@@ -1,12 +1,29 @@
-import { FormControl, Select } from '../../../../lib'
+import { useState } from 'react'
+
+import { FormControl, Select, Text, VFlow } from '../../../../lib'
 
 const items = ['Carbonara', 'Gnocchi', 'Lasagna', 'Macaroni and Cheese', 'Pesto', 'Pizza']
 
 function SelectDemo() {
-  const itemToString = (item: any) => item
+  const [value, setValue] = useState()
+
+  const handleChange = (item: string) => setValue(item)
+
+  const itemToString = (item: string) => item
 
   return (
-    <Select<string> label='Favorite pasta' items={items} itemToString={itemToString} name='favorite pasta' required />
+    <VFlow>
+      <Text>Selected item: {value || '[none]'}</Text>
+      <Select<string>
+        label='Favorite pasta'
+        items={items}
+        value={value}
+        onChange={handleChange}
+        itemToString={itemToString}
+        name='favorite pasta'
+        required
+      />
+    </VFlow>
   )
 }
 
diff --git a/site/pages/components/select/Suggestion.demo.tsx b/site/pages/components/select/Suggestion.demo.tsx
index 4ae94093c..45e1fd200 100644
--- a/site/pages/components/select/Suggestion.demo.tsx
+++ b/site/pages/components/select/Suggestion.demo.tsx
@@ -7,7 +7,9 @@ const items = ['Carbonara', 'Gnocchi', 'Lasagna', 'Macaroni and Cheese', 'Pesto'
 function SuggestionDemo() {
   const [value, setValue] = useState()
 
-  const itemToString = (item: any) => item
+  const handleChange = (item: string) => setValue(item)
+
+  const itemToString = (item: string) => item
   const createNewItem = (inputValue: string) => inputValue
 
   return (
@@ -18,7 +20,7 @@ function SuggestionDemo() {
         label='Favorite pasta'
         name='favorite pasta'
         items={items}
-        onChange={setValue}
+        onChange={handleChange}
         itemToString={itemToString}
         createNewItem={createNewItem}
         icon={null}
diff --git a/src/components/Select/SelectSingle/SelectDownshift.tsx b/src/components/Select/SelectSingle/SelectDownshift.tsx
index 45998e6ac..19d2dfce9 100644
--- a/src/components/Select/SelectSingle/SelectDownshift.tsx
+++ b/src/components/Select/SelectSingle/SelectDownshift.tsx
@@ -63,27 +63,31 @@ export function SelectDownshift<T>(props: SelectDownshiftProps<T>) {
     setVisibleItems(props.items)
   }, [props.items])
 
-  const handleStateChange = (options: StateChangeOptions<T>, downshift: ControllerStateAndHelpers<T>) => {
-    if (createNewItem && options.hasOwnProperty('inputValue')) {
-      rest.onChange && rest.onChange(createNewItem(options.inputValue), getStateAndHelpers(downshift))
+  const handleStateChange = (changes: StateChangeOptions<T>, downshift: ControllerStateAndHelpers<T>) => {
+    if (createNewItem && changes.hasOwnProperty('inputValue')) {
+      rest.onChange && rest.onChange(createNewItem(changes.inputValue), getStateAndHelpers(downshift))
     }
 
-    if (options.isOpen) {
+    if (changes.type === Downshift.stateChangeTypes.changeInput && changes.inputValue === '') {
+      rest.onChange && rest.onChange(null, getStateAndHelpers(downshift))
+    }
+
+    if (changes.isOpen) {
       onFilterChange(null, getStateAndHelpers(downshift))
     }
 
-    if (options.type === Downshift.stateChangeTypes.changeInput) {
-      onFilterChange(options.inputValue, getStateAndHelpers(downshift))
+    if (changes.type === Downshift.stateChangeTypes.changeInput) {
+      onFilterChange(changes.inputValue, getStateAndHelpers(downshift))
     }
 
     if (
-      options.type === Downshift.stateChangeTypes.clickItem ||
-      options.type === Downshift.stateChangeTypes.keyDownEnter
+      changes.type === Downshift.stateChangeTypes.clickItem ||
+      changes.type === Downshift.stateChangeTypes.keyDownEnter
     ) {
       onFilterChange(null, getStateAndHelpers(downshift))
     }
 
-    props.onStateChange && props.onStateChange(options, getStateAndHelpers(downshift))
+    props.onStateChange && props.onStateChange(changes, getStateAndHelpers(downshift))
   }
 
   const handleChange = (item: T, downshift: ControllerStateAndHelpers<T>) => {


Test patch:
diff --git a/src/components/Select/SelectSingle/SelectSingle.test.tsx b/src/components/Select/SelectSingle/SelectSingle.test.tsx
index e900c6030..4dcee613f 100644
--- a/src/components/Select/SelectSingle/SelectSingle.test.tsx
+++ b/src/components/Select/SelectSingle/SelectSingle.test.tsx
@@ -1,4 +1,5 @@
 import { fireEvent, render } from '@testing-library/react'
+import { resetIdCounter } from 'downshift'
 import React from 'react'
 
 import en from '../../../i18n/locales/en-US'
@@ -20,6 +21,8 @@ function SelectTest(props: Partial<SelectSingleProps>) {
   return <SelectSingle items={items} itemToString={item => item.label} placeholder='Select a value...' {...props} />
 }
 
+beforeEach(() => resetIdCounter())
+
 it('should render correctly when closed', () => {
   const { container } = render(<SelectTest />)
   expect(container).toMatchSnapshot()
@@ -50,6 +53,14 @@ it('should call the onChange event when an item is clicked', () => {
   expect(onChange).toHaveBeenLastCalledWith(items[2], expect.anything())
 })
 
+it('should call the onChange event with target.value empty when text input is cleared', () => {
+  const onChange = jest.fn()
+  const { container } = render(<SelectTest onChange={onChange} value={items[0]} />)
+
+  fireEvent.change(container.querySelector('input'), { target: { value: '' } })
+  expect(onChange).toHaveBeenLastCalledWith(null, expect.anything())
+})
+
 it('should render current value and allow changes via prop', () => {
   const { container, rerender } = render(<SelectTest />)
   const input = container.querySelector('input')
diff --git a/src/components/Select/SelectSingle/__snapshots__/SelectSingle.test.tsx.snap b/src/components/Select/SelectSingle/__snapshots__/SelectSingle.test.tsx.snap
index b3867f152..b43328128 100644
--- a/src/components/Select/SelectSingle/__snapshots__/SelectSingle.test.tsx.snap
+++ b/src/components/Select/SelectSingle/__snapshots__/SelectSingle.test.tsx.snap
@@ -187,7 +187,7 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
     <div
       aria-expanded="false"
       aria-haspopup="listbox"
-      aria-labelledby="downshift-12-label"
+      aria-labelledby="downshift-0-label"
       class="emotion-7"
       role="combobox"
     >
@@ -199,7 +199,7 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
             aria-autocomplete="list"
             autocomplete="off"
             class="emotion-1"
-            id="downshift-12-input"
+            id="downshift-0-input"
             placeholder="Select a value..."
             type="text"
             value=""
@@ -438,7 +438,7 @@ exports[`input label should use aria-labelledby equals to an auto-assigned label
             aria-labelledby="label-abc"
             autocomplete="off"
             class="emotion-1"
-            id="downshift-13-input"
+            id="downshift-0-input"
             placeholder="Select a value..."
             type="text"
             value=""
@@ -918,8 +918,8 @@ exports[`should render correctly when opened 1`] = `
     <div
       aria-expanded="true"
       aria-haspopup="listbox"
-      aria-labelledby="downshift-1-label"
-      aria-owns="downshift-1-menu"
+      aria-labelledby="downshift-0-label"
+      aria-owns="downshift-0-menu"
       class="emotion-12"
       role="combobox"
     >
@@ -929,10 +929,10 @@ exports[`should render correctly when opened 1`] = `
         >
           <input
             aria-autocomplete="list"
-            aria-controls="downshift-1-menu"
+            aria-controls="downshift-0-menu"
             autocomplete="off"
             class="emotion-0"
-            id="downshift-1-input"
+            id="downshift-0-input"
             placeholder="Select a value..."
             type="text"
             value=""
@@ -967,15 +967,15 @@ exports[`should render correctly when opened 1`] = `
         class="emotion-11"
       >
         <ul
-          aria-labelledby="downshift-1-label"
+          aria-labelledby="downshift-0-label"
           class="emotion-10"
-          id="downshift-1-menu"
+          id="downshift-0-menu"
           role="listbox"
         >
           <li
             aria-selected="false"
             class="emotion-5"
-            id="downshift-1-item-0"
+            id="downshift-0-item-0"
             role="option"
           >
             Apple
@@ -983,7 +983,7 @@ exports[`should render correctly when opened 1`] = `
           <li
             aria-selected="false"
             class="emotion-5"
-            id="downshift-1-item-1"
+            id="downshift-0-item-1"
             role="option"
           >
             Banana
@@ -991,7 +991,7 @@ exports[`should render correctly when opened 1`] = `
           <li
             aria-selected="false"
             class="emotion-5"
-            id="downshift-1-item-2"
+            id="downshift-0-item-2"
             role="option"
           >
             Grape
@@ -999,7 +999,7 @@ exports[`should render correctly when opened 1`] = `
           <li
             aria-selected="false"
             class="emotion-5"
-            id="downshift-1-item-3"
+            id="downshift-0-item-3"
             role="option"
           >
             Orange
@@ -1007,7 +1007,7 @@ exports[`should render correctly when opened 1`] = `
           <li
             aria-selected="false"
             class="emotion-5"
-            id="downshift-1-item-4"
+            id="downshift-0-item-4"
             role="option"
           >
             Pear