Skip to content

Commit

Permalink
feat: downshift v7 (#1415)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: updates to useCombobox and useSelect to adhere to the 1.2 version of the ARIA Combobox pattern.

Migration guide is available in [this file](https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V7.md).

Closes #1365.
Closes #1239.
Contains changes from #1149.
  • Loading branch information
silviuaavram authored Oct 22, 2022
1 parent 6bd18eb commit 7540e3d
Show file tree
Hide file tree
Showing 49 changed files with 3,645 additions and 3,461 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ has been around for a while. It established a successful pattern for making
components accessible and functional while giving developers complete freedom
when building the UI.

Both _useSelect_ and _useCombobox_ support he latest ARIA combobox patterns for
W3C, which _Downshift_ does not. Consequently, we strongly recommend the you use
the hooks. The hooks have been migrated to the ARIA 1.2 combobox pattern in the
version 7 of _downshift_. There is a [Migration Guide][migration-guide-v7] that
documents the changes introduced in version 7.

The `README` on this page covers only the component while each hook has its own
`README` page. You can navigate to the [hooks page][hooks-readme] or go directly
to the hook you need by using the links in the list above.
Expand Down Expand Up @@ -1499,3 +1505,5 @@ MIT
https://codesandbox.io/s/github/kentcdodds/downshift-examples?file=/src/downshift/ordered-examples/00-get-root-props-example.js
[code-sandbox-no-get-root-props]:
https://codesandbox.io/s/github/kentcdodds/downshift-examples?file=/src/downshift/ordered-examples/01-basic-autocomplete.js
[migration-guide-v7]:
https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V7.md
4 changes: 2 additions & 2 deletions cypress/e2e/combobox.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('combobox', () => {
it('can arrow up to select last item', () => {
cy.findByTestId('combobox-input')
.type('{uparrow}{enter}') // open menu, last option is focused
.should('have.value', 'Purple')
.should('have.value', 'Skyblue')
})

it('can arrow down to select first item', () => {
Expand All @@ -46,7 +46,7 @@ describe('combobox', () => {
it('can use end arrow to select last item', () => {
cy.findByTestId('combobox-input')
.type('{downarrow}{end}{enter}') // open to first, go to last by end.
.should('have.value', 'Purple')
.should('have.value', 'Skyblue')
})

it('resets the item on blur', () => {
Expand Down
16 changes: 16 additions & 0 deletions cypress/e2e/useMultipleCombobox.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
describe('useMultipleCombobox', () => {
before(() => {
cy.visit('/useMultipleCombobox')
})

it('can select multiple items', () => {
cy.findByRole('button', {name: 'toggle menu'}).click()
cy.findByRole('option', {name: 'Green'}).click()
cy.findByRole('option', {name: 'Gray'}).click()
cy.findByRole('button', {name: 'toggle menu'}).click()
cy.findByText('Black').should('be.visible')
cy.findByText('Red').should('be.visible')
cy.findByText('Green').should('be.visible')
cy.findByText('Gray').should('be.visible')
})
})
16 changes: 16 additions & 0 deletions cypress/e2e/useMultipleSelect.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
describe('useMultipleSelect', () => {
before(() => {
cy.visit('/useMultipleSelect')
})

it('can select multiple options', () => {
cy.findByRole('combobox').click()
cy.findByRole('option', {name: 'Green'}).click()
cy.findByRole('option', {name: 'Gray'}).click()
cy.findByRole('combobox').click()
cy.findByText('Black').should('be.visible')
cy.findByText('Red').should('be.visible')
cy.findByText('Green').should('be.visible')
cy.findByText('Gray').should('be.visible')
})
})
6 changes: 3 additions & 3 deletions cypress/e2e/useSelect.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ describe('useSelect', () => {
})

it('can open and close a menu', () => {
cy.findByTestId('select-toggle-button')
cy.findByRole('combobox')
.click()
cy.findAllByRole('option')
.should('have.length.above', 0)
cy.findByTestId('select-toggle-button')
cy.findByRole('combobox')
.click()
cy.findAllByRole('option')
.should('have.length', 0)
cy.findByTestId('select-toggle-button')
cy.findByRole('combobox')
.click()
cy.findAllByRole('option')
.should('have.length.above', 0)
Expand Down
7 changes: 3 additions & 4 deletions docusaurus/pages/combobox.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as React from 'react'

import Downshift from '../../src'
import {colors} from '../utils'

export default function ComboBox() {
const items = ['Black', 'Red', 'Green', 'Blue', 'Orange', 'Purple']

return (
<Downshift>
{({
Expand Down Expand Up @@ -73,10 +72,10 @@ export default function ComboBox() {
>
{isOpen &&
(inputValue
? items.filter(i =>
? colors.filter(i =>
i.toLowerCase().includes(inputValue.toLowerCase()),
)
: items
: colors
).map((item, index) => (
<li
style={{
Expand Down
14 changes: 6 additions & 8 deletions docusaurus/pages/useCombobox.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
import React, {useState} from 'react'

import {useCombobox} from '../../src'

const items = ['Black', 'Red', 'Green', 'Blue', 'Orange', 'Purple']
import {colors} from '../utils'

export default function DropdownCombobox() {
const [inputItems, setInputItems] = useState(items)
const [inputItems, setInputItems] = useState(colors)
const {
isOpen,
getToggleButtonProps,
getLabelProps,
getMenuProps,
getInputProps,
getComboboxProps,
highlightedIndex,
getItemProps,
selectedItem,
clearSelection,
selectItem,
} = useCombobox({
items: inputItems,
onInputValueChange: ({inputValue}) => {
setInputItems(
items.filter(item =>
colors.filter(item =>
item.toLowerCase().startsWith(inputValue.toLowerCase()),
),
)
Expand All @@ -47,7 +45,7 @@ export default function DropdownCombobox() {
>
Choose an element:
</label>
<div {...getComboboxProps()}>
<div>
<input
style={{padding: '4px'}}
{...getInputProps()}
Expand All @@ -65,7 +63,7 @@ export default function DropdownCombobox() {
style={{padding: '4px 8px'}}
aria-label="toggle menu"
data-testid="clear-button"
onClick={clearSelection}
onClick={() => selectItem(null)}
>
&#10007;
</button>
Expand Down
7 changes: 3 additions & 4 deletions docusaurus/pages/useMultipleCombobox.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react'

import {useCombobox, useMultipleSelection} from '../../src'
import {colors} from '../utils'

const colors = ['Black', 'Red', 'Green', 'Blue', 'Orange', 'Purple']
const initialSelectedItems = [colors[0], colors[1]]

function getFilteredItems(selectedItems, inputValue) {
Expand Down Expand Up @@ -46,7 +46,6 @@ export default function DropdownMultipleCombobox() {
getLabelProps,
getMenuProps,
getInputProps,
getComboboxProps,
highlightedIndex,
getItemProps,
selectedItem,
Expand Down Expand Up @@ -150,7 +149,7 @@ export default function DropdownMultipleCombobox() {
</span>
)
})}
<div {...getComboboxProps()}>
<div>
<input
style={{padding: '4px'}}
{...getInputProps(getDropdownProps({preventKeyAction: isOpen}))}
Expand All @@ -166,7 +165,7 @@ export default function DropdownMultipleCombobox() {
</button>
<button
style={{padding: '4px 8px'}}
aria-label="toggle menu"
aria-label="clear selection"
data-testid="clear-button"
onClick={clearSelection}
>
Expand Down
22 changes: 14 additions & 8 deletions docusaurus/pages/useMultipleSelect.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react'

import {useSelect, useMultipleSelection} from '../../src'
import {colors} from '../utils'

const colors = ['Black', 'Red', 'Green', 'Blue', 'Orange', 'Purple']
const initialSelectedItems = [colors[0], colors[1]]

function getFilteredItems(selectedItems) {
Expand Down Expand Up @@ -33,8 +33,8 @@ export default function DropdownMultipleSelect() {
stateReducer: (state, actionAndChanges) => {
const {changes, type} = actionAndChanges
switch (type) {
case useSelect.stateChangeTypes.MenuKeyDownEnter:
case useSelect.stateChangeTypes.MenuKeyDownSpaceButton:
case useSelect.stateChangeTypes.ToggleButtonKeyDownEnter:
case useSelect.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
case useSelect.stateChangeTypes.ItemClick:
return {
...changes,
Expand All @@ -46,8 +46,8 @@ export default function DropdownMultipleSelect() {
},
onStateChange: ({type, selectedItem: newSelectedItem}) => {
switch (type) {
case useSelect.stateChangeTypes.MenuKeyDownEnter:
case useSelect.stateChangeTypes.MenuKeyDownSpaceButton:
case useSelect.stateChangeTypes.ToggleButtonKeyDownEnter:
case useSelect.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
case useSelect.stateChangeTypes.ItemClick:
if (newSelectedItem) {
addSelectedItem(newSelectedItem)
Expand Down Expand Up @@ -122,15 +122,21 @@ export default function DropdownMultipleSelect() {
</span>
)
})}
<button
style={{padding: '4px'}}
<div
style={{
padding: '4px',
textAlign: 'center',
border: '1px solid black',
backgroundColor: 'lightgray',
cursor: 'pointer',
}}
type="button"
{...getToggleButtonProps(
getDropdownProps({preventKeyAction: isOpen}),
)}
>
Pick some colors {isOpen ? <>&#8593;</> : <>&#8595;</>}
</button>
</div>
</div>
</div>
<ul
Expand Down
20 changes: 12 additions & 8 deletions docusaurus/pages/useSelect.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from 'react'

import {useSelect} from '../../src'

const items = ['Black', 'Red', 'Green', 'Blue', 'Orange', 'Purple']
import {colors} from '../utils'

export default function DropdownSelect() {
const {
Expand All @@ -13,7 +12,7 @@ export default function DropdownSelect() {
getMenuProps,
highlightedIndex,
getItemProps,
} = useSelect({items})
} = useSelect({items: colors})

return (
<div
Expand All @@ -35,14 +34,19 @@ export default function DropdownSelect() {
>
Choose an element:
</label>
<button
data-testid="select-toggle-button"
style={{padding: '4px'}}
<div
style={{
padding: '4px',
textAlign: 'center',
border: '1px solid black',
backgroundColor: 'lightgray',
cursor: 'pointer',
}}
{...getToggleButtonProps()}
>
{selectedItem ?? 'Elements'}
{isOpen ? <>&#8593;</> : <>&#8595;</>}
</button>
</div>
<ul
{...getMenuProps()}
style={{
Expand All @@ -53,7 +57,7 @@ export default function DropdownSelect() {
}}
>
{isOpen &&
items.map((item, index) => (
colors.map((item, index) => (
<li
style={{
padding: '4px',
Expand Down
1 change: 1 addition & 0 deletions docusaurus/utils.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions flow-typed/npm/downshift_v2.x.x.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ declare module downshift {
highlightedIndex: number | null;
inputValue: string | null;
isOpen: boolean;
selectedItem: Item;
selectedItem: Item | null;
}
declare export interface DownshiftProps<Item> {
defaultSelectedItem?: Item;
Expand Down Expand Up @@ -209,7 +209,7 @@ declare module downshift {
openMenu: (cb?: Callback) => void;
closeMenu: (cb?: Callback) => void;
toggleMenu: (otherStateToSet?: {}, cb?: Callback) => void;
selectItem: (item: Item, otherStateToSet?: {}, cb?: Callback) => void;
selectItem: (item: Item | null, otherStateToSet?: {}, cb?: Callback) => void;
selectItemAtIndex: (
index: number,
otherStateToSet?: {},
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
},
"devDependencies": {
"@babel/helpers": "^7.14.8",
"@cypress/webpack-preprocessor": "^5.12.2",
"@cypress/webpack-preprocessor": "^5.14.0",
"@docusaurus/core": "^2.0.1",
"@docusaurus/module-type-aliases": "^2.0.1",
"@docusaurus/preset-classic": "^2.0.1",
Expand All @@ -88,7 +88,7 @@
"@testing-library/preact": "^2.0.1",
"@testing-library/react": "^12.0.0",
"@testing-library/react-hooks": "^7.0.1",
"@testing-library/user-event": "^13.2.1",
"@testing-library/user-event": "^14.4.3",
"@types/jest": "^26.0.24",
"@types/react": "^17.0.15",
"@typescript-eslint/eslint-plugin": "^4.28.5",
Expand All @@ -99,7 +99,7 @@
"buble": "^0.20.0",
"cpy-cli": "^3.1.1",
"cross-env": "^7.0.3",
"cypress": "^10.3.1",
"cypress": "10.8.0",
"eslint": "^7.32.0",
"eslint-plugin-cypress": "^2.11.3",
"eslint-plugin-react": "7.24.0",
Expand Down
Loading

0 comments on commit 7540e3d

Please sign in to comment.