diff --git a/docs/downshift.mdx b/docs/downshift.mdx index 2f48f46..9d69319 100644 --- a/docs/downshift.mdx +++ b/docs/downshift.mdx @@ -96,7 +96,7 @@ function ComboBox() { const items = [ {author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {author: 'Lev Tolstoy', title: 'War and Peace'}, - {author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {author: 'George Orwell', title: '1984'}, {author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -215,7 +215,7 @@ function ComboBox() { const items = [ {author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {author: 'Lev Tolstoy', title: 'War and Peace'}, - {author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {author: 'George Orwell', title: '1984'}, {author: 'Jane Austen', title: 'Pride and Prejudice'}, diff --git a/docs/hooks/index.mdx b/docs/hooks/index.mdx index 107ba1c..83d60d0 100644 --- a/docs/hooks/index.mdx +++ b/docs/hooks/index.mdx @@ -18,16 +18,20 @@ If you need to add multiple selection for any of them and have the selected items act as a Tag List next to the _select_ or _combobox_, then [useMultipleSelection](/use-multiple-selection) is the right tool for that. -## Breaking Changes in v8 +## Migration Guides -Since version 8, there have been breaking changes to functionality and TS types. -Check out the -[migration page](https://github.com/downshift-js/downshift/blob/master/src/hooks/MIGRATION_V8.md). - -## Breaking Changes in v7 +### v7 Since version 7, the _useSelect_ and _useCombobox_ hooks to support the ARIA 1.2 pattern for the combobox, which contains some changes from the ARIA 1.1 pattern. This brings changes in the API and the behaviour of _useCombobox_, detailed in the [migration page](https://github.com/downshift-js/downshift/blob/master/src/hooks/MIGRATION_V7.md). + +### v8 & v9 + +Since versions 8 and 9, there have been breaking changes to functionality and TS +types. Check out the migration pages for +[v8](https://github.com/downshift-js/downshift/blob/master/src/hooks/MIGRATION_V8.md) +and +[v9](https://github.com/downshift-js/downshift/blob/master/src/hooks/MIGRATION_V9.md). diff --git a/docs/hooks/useCombobox.mdx b/docs/hooks/useCombobox.mdx index 7c82151..624a357 100644 --- a/docs/hooks/useCombobox.mdx +++ b/docs/hooks/useCombobox.mdx @@ -32,10 +32,10 @@ implement the corresponding ARIA pattern. Every functionality needed should be provided out-of-the-box: menu toggle, item selection and up/down movement between them, screen reader support, focus management etc. -## Breaking Changes in v8 +## Breaking Changes in v8 and v9 -_useCombobox_ has been affected by breaking changes in v8, so check out the -[migration page][migration-guide-v8]. +_useCombobox_ has been affected by breaking changes in v8 and v9, so check out +the migration pages for [v8][migration-guide-v8] and [v9][migration-guide-v9]. ## Breaking Changes in v7 @@ -83,7 +83,7 @@ function ComboBoxExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -207,7 +207,7 @@ with the resulting DOM element, we don't need to do anything specific rather than just spreading the getter props, apart from the case of the _Input_, which renders a wrapper element over the actual HTML _input_. In this case, since _Input_ provides a prop for accessing the _input_ element called _inputRef_, we -will use the getter function like this: _getInputProps({refKey: 'inputRef'})_. +will use the getter function like this: `getInputProps({refKey: 'inputRef'})`. Another point worth mentioning is that in this case items are objects and not strings. As a result, the _itemToString_ prop is passed to _useCombobox_. It @@ -226,7 +226,7 @@ function ComboBoxExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -346,7 +346,7 @@ function ComboBoxExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -477,7 +477,7 @@ function ComboBoxExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -619,7 +619,7 @@ function ComboBoxExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -751,7 +751,7 @@ function ComboBoxExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -906,6 +906,175 @@ function ComboBoxExample() { } ``` +## Multiple selection with Tag Group + +If your multiple selection scenario uses a tag group to display selected items, +you can use the hook in combination with [useTagGroup](/use-tag-group). + +In the example below, we use: + +- _null_ to control **selectedItem** as the hook should not care about + selection. +- **onSelectedItemChange** to be able to call **addItem** from _useTagGroup_. +- control **inputValue** to be able to filter combobox items by query and + selected items. +- **stateReducer** to keep the menu open on selection. + +[CodeSandbox for combobox with tag group +example][code-sandbox-combobox-tag-group]. + +```jsx live +function ComboBoxExample() { + const books = [ + {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, + {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, + {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, + {id: 'book-5', author: 'George Orwell', title: '1984'}, + {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, + {id: 'book-7', author: 'Marcus Aurelius', title: 'Meditations'}, + { + id: 'book-8', + author: 'Fyodor Dostoevsky', + title: 'The Brothers Karamazov', + }, + {id: 'book-9', author: 'Lev Tolstoy', title: 'Anna Karenina'}, + {id: 'book-10', author: 'Fyodor Dostoevsky', title: 'Crime and Punishment'}, + ] + + function ComboBox() { + const initialItems = books.slice(0, 2) + const [inputValue, setInputValue] = React.useState('') + + const { + addItem, + getTagProps, + getTagRemoveProps, + getTagGroupProps, + items, + activeIndex, + } = useTagGroup({ + initialItems, + }) + const itemsToAdd = books.filter( + book => + !items.includes(book) && + (!inputValue || + book.title.toLowerCase().includes(inputValue.toLowerCase()) || + book.author.toLowerCase().includes(inputValue.toLowerCase())), + ) + const { + isOpen, + getToggleButtonProps, + getLabelProps, + getMenuProps, + getInputProps, + highlightedIndex, + getItemProps, + } = useCombobox({ + items: itemsToAdd, + inputValue, + onInputValueChange: ({inputValue}) => { + setInputValue(inputValue) + }, + onSelectedItemChange({selectedItem}) { + if (selectedItem) { + addItem(selectedItem) + } + }, + selectedItem: null, + itemToString(item) { + return item ? item.title : '' + }, + stateReducer(_state, actionAndChanges) { + const {changes, type} = actionAndChanges + + if ( + changes.selectedItem && + type !== useCombobox.stateChangeTypes.InputBlur + ) { + return {...changes, inputValue: '', highlightedIndex: 0, isOpen: true} + } + + console.log(changes) + + return changes + }, + }) + + return ( +
+
+ {items.map((item, index) => ( + + {item.title} + + ✕ + + + ))} +
+
+ +
+ + +
+
+ +
+ ) + } + + return +} +``` + ## Using action props Action props are functions returned by _useCombobox_ along with the state props @@ -922,7 +1091,7 @@ function ComboBoxExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -1200,6 +1369,8 @@ repository][examples-code-sandbox]. https://codesandbox.io/p/sandbox/github/kentcdodds/downshift-examples?file=%2Fsrc%2Fhooks%2FuseSelect%2Freact-virtual.js&moduleview=1 [examples-code-sandbox]: https://codesandbox.io/p/sandbox/github/kentcdodds/downshift-examples?file=%2Fsrc%2Findex.js&moduleview=1 +[code-sandbox-combobox-tag-group]: + https://codesandbox.io/p/sandbox/github/kentcdodds/downshift-examples?file=%2Fsrc%2Fhooks%2FuseCombobox%2Ftag-group-multiple-selection.js&moduleview=1 [react-virtual-github]: https://github.com/tannerlinsley/react-virtual [react-virtualized-github]: https://github.com/bvaughn/react-virtualized [react-window-github]: https://github.com/bvaughn/react-window @@ -1207,3 +1378,5 @@ repository][examples-code-sandbox]. https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V7.md#usecombobox [migration-guide-v8]: https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V8.md +[migration-guide-v9]: + https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V9.md diff --git a/docs/hooks/useMultipleSelection.mdx b/docs/hooks/useMultipleSelection.mdx index 32bf612..9fdef34 100644 --- a/docs/hooks/useMultipleSelection.mdx +++ b/docs/hooks/useMultipleSelection.mdx @@ -6,6 +6,14 @@ slug: /use-multiple-selection # useMultipleSelection +## DEPRECATED + +Please use the [useTagGroup](/use-tag-group) hook to create multiple selection +dropdowns with tag groups. Check out the examples for each: + +- [useCombobox](/use-combobox#multiple-selection-with-tag-group) +- [useSelect](/use-select#multiple-selection-with-tag-group) + ## The problem You have a custom **select** or a **combobox** in your applications which @@ -33,10 +41,11 @@ arrow navigation between dropdown and items, navigation between the items themselves, removing and adding items, and also a helpful _aria-live_ message when an item has been removed from the selection. -## Breaking Changes in v8 +## Breaking Changes in v8 and v9 -_useMultipleSelection_ has been affected by breaking changes in v8, so check out -the [migration page][migration-guide-v8]. +_useMultipleSelection_ has been affected by breaking changes in v8 and v9, so +check out the migration pages for [v8][migration-guide-v8] and +[v9][migration-guide-v9]. ## Props used in examples @@ -83,7 +92,7 @@ function MultipleComboBoxExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -287,7 +296,7 @@ function MultipleSelectExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -452,3 +461,5 @@ To see more cool stuff you can build with _useMultipleSelection_, explore the https://codesandbox.io/p/sandbox/github/kentcdodds/downshift-examples?file=%2Fsrc%2Findex.js%3A25%2C12&moduleview=1 [migration-guide-v8]: https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V8.md +[migration-guide-v9]: + https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V9.md diff --git a/docs/hooks/useSelect.mdx b/docs/hooks/useSelect.mdx index fdecd0e..838d1fd 100644 --- a/docs/hooks/useSelect.mdx +++ b/docs/hooks/useSelect.mdx @@ -33,8 +33,8 @@ between them, screen reader support, highlight by character keys etc. ## Breaking Changes in v8 -_useSelect_ has been affected by breaking changes in v8, so check out the -[migration page][migration-guide-v8]. +_useSelect_ has been affected by breaking changes in v8 and v9, so check out the +migration pages for [v8][migration-guide-v8] and [v9][migration-guide-v9]. ## Breaking Changes in v7 @@ -75,7 +75,7 @@ function SelectExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -188,7 +188,7 @@ function SelectExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -290,7 +290,7 @@ function SelectExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -397,7 +397,7 @@ function SelectExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -512,7 +512,7 @@ function SelectExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -619,7 +619,7 @@ function SelectExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -744,6 +744,163 @@ function SelectExample() { } ``` +## Multiple selection with Tag Group + +If your multiple selection scenario uses a tag group to display selected items, +you can use the hook in combination with [useTagGroup](/use-tag-group). + +In the example below, we use: + +- _null_ to control **selectedItem** as the hook should not care about + selection. +- **onSelectedItemChange** to be able to call **addItem** from _useTagGroup_. +- **stateReducer** to keep the menu open on selection. + +[CodeSandbox for combobox with tag group +example][code-sandbox-select-tag-group]. + +```jsx live +function TagGroupExample() { + const books = [ + {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, + {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, + {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, + {id: 'book-5', author: 'George Orwell', title: '1984'}, + {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, + {id: 'book-7', author: 'Marcus Aurelius', title: 'Meditations'}, + { + id: 'book-8', + author: 'Fyodor Dostoevsky', + title: 'The Brothers Karamazov', + }, + {id: 'book-9', author: 'Lev Tolstoy', title: 'Anna Karenina'}, + {id: 'book-10', author: 'Fyodor Dostoevsky', title: 'Crime and Punishment'}, + ] + + function itemToString(item) { + return item ? item.title : '' + } + + function TagGroup() { + const initialItems = books.slice(0, 2) + const [inputValue, setInputValue] = React.useState('') + + const { + addItem, + getTagProps, + getTagRemoveProps, + getTagGroupProps, + items, + activeIndex, + } = useTagGroup({ + initialItems, + }) + const itemsToAdd = books.filter( + book => + !items.includes(book) && + (!inputValue || + book.title.toLowerCase().includes(inputValue.toLowerCase()) || + book.author.toLowerCase().includes(inputValue.toLowerCase())), + ) + const { + isOpen, + selectedItem, + getToggleButtonProps, + getLabelProps, + getMenuProps, + highlightedIndex, + getItemProps, + } = useSelect({ + items: itemsToAdd, + itemToString, + onSelectedItemChange({selectedItem}) { + if (selectedItem) { + addItem(selectedItem) + } + }, + selectedItem: null, + itemToString(item) { + return item ? item.title : '' + }, + stateReducer(_state, actionAndChanges) { + const {changes, type} = actionAndChanges + + if ( + changes.selectedItem && + type !== useSelect.stateChangeTypes.ToggleButtonBlur + ) { + return {...changes, inputValue: '', highlightedIndex: 0, isOpen: true} + } + + return changes + }, + }) + + return ( +
+
+ {items.map((item, index) => ( + + {item.title} + + ✕ + + + ))} +
+
+ +
+ {selectedItem ? selectedItem.title : 'Best book ever'} + {isOpen ? <>↑ : <>↓} +
+
+ +
+ ) + } + + return +} +``` + ## Using action props Action props are functions returned by _useSelect_ along with the state props @@ -761,7 +918,7 @@ function SelectExample() { const books = [ {id: 'book-1', author: 'Harper Lee', title: 'To Kill a Mockingbird'}, {id: 'book-2', author: 'Lev Tolstoy', title: 'War and Peace'}, - {id: 'book-3', author: 'Fyodor Dostoyevsy', title: 'The Idiot'}, + {id: 'book-3', author: 'Fyodor Dostoevsky', title: 'The Idiot'}, {id: 'book-4', author: 'Oscar Wilde', title: 'A Picture of Dorian Gray'}, {id: 'book-5', author: 'George Orwell', title: '1984'}, {id: 'book-6', author: 'Jane Austen', title: 'Pride and Prejudice'}, @@ -1001,6 +1158,8 @@ repository][examples-code-sandbox]. https://codesandbox.io/p/sandbox/github/kentcdodds/downshift-examples?file=%2Fsrc%2Fhooks%2FuseCombobox%2Faction-props.js&moduleview=1 [code-sandbox-react-virtual]: https://codesandbox.io/p/sandbox/github/kentcdodds/downshift-examples?file=%2Fsrc%2Fhooks%2FuseCombobox%2Freact-virtual.js&moduleview=1 +[code-sandbox-select-tag-group]: + https://codesandbox.io/p/sandbox/github/kentcdodds/downshift-examples?file=%2Fsrc%2Fhooks%2FuseSelect%2Ftag-group-multiple-selection.js [examples-code-sandbox]: https://codesandbox.io/p/sandbox/github/kentcdodds/downshift-examples?file=%2Fsrc%2Findex.js&moduleview=1 [react-virtual-github]: https://github.com/tannerlinsley/react-virtual @@ -1010,3 +1169,5 @@ repository][examples-code-sandbox]. https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V7.md#useselect [migration-guide-v8]: https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V8.md +[migration-guide-v9]: + https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V9.md diff --git a/docs/hooks/useTagGroup.mdx b/docs/hooks/useTagGroup.mdx new file mode 100644 index 0000000..b0e1773 --- /dev/null +++ b/docs/hooks/useTagGroup.mdx @@ -0,0 +1,144 @@ +--- +title: useTagGroup +description: useTagGroup for building tag lists +slug: /use-tag-group +--- + +import {ThemedSnack} from '@site/src/components/ThemedSnack' + +# useTagGroup + +## The problem + +You want to build a tag group component in your app that's accessible and offers +a great user experience. There is no dedicated ARIA design pattern for this +component, but since it's widely used, we compiled the list of specifications +and implemented them through a React hook that's compliant with Downshift's +principles. + +## This solution + +**useTagGroup** is a React hook that manages all the stateful logic needed to +make the tag group functional and accessible. It returns a set of props that are +meant to be called, and their results destructured on the tag group's elements: +its container, tag item and tag remove button. These are similar to the props +provided by vanilla _Downshift_ to the children render prop. + +These props are called getter props, and their return values are destructured as +a set of ARIA attributes and event listeners. Together with the action props and +state props, they create all the stateful logic needed for the tag group to +implement the list of requirements. Every functionality needed should be +provided out-of-the-box: item removal and selection, and left/right arrow +movement between items, screen reader support etc. + +## Props used in examples + +In the examples below, we use the _useTagGroup_ hook and destructure the getter +props and state variables it returns. These are used in the following way: + +| Returned prop | Element | Comments | +| ------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------ | +| `getTagGroupProps` | `
` | Call and destructure its returned object on the container element. | +| `getTagProps` | `` | Call and destructure its returned object on the tag element. | +| `getTagRemoveProps` | ` + + ))} +
+
Add more items:
+ + + ) + } + + return +} +``` + +[use-tag-group-github]: + https://github.com/downshift-js/downshift/tree/master/src/hooks/useTagGroup +[code-sandbox-basic-usage]: + https://codesandbox.io/p/sandbox/github/kentcdodds/downshift-examples?file=%2Fsrc%2Fhooks%2FuseTagGroup%2Fbasic-usage.js%3A9%2C12&moduleview=1 diff --git a/package.json b/package.json index d451894..5859fa4 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "@mdx-js/mdx": "^1.6.22", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", - "downshift": "^8.3.2", + "downshift": "9.2.0", "mdx-embed": "^1.1.2", "my-loaders": "file:plugins/my-loaders", "prism-react-renderer": "^1.3.1", diff --git a/src/theme/ReactLiveScope/index.js b/src/theme/ReactLiveScope/index.js index f64ccf0..00f7d02 100644 --- a/src/theme/ReactLiveScope/index.js +++ b/src/theme/ReactLiveScope/index.js @@ -3,6 +3,7 @@ import Downshift, { useCombobox, useSelect, useMultipleSelection, + useTagGroup } from 'downshift' import cx from 'clsx' import ExpandMoreIcon from '@material-ui/icons/ExpandMore' @@ -27,6 +28,7 @@ const ReactLiveScope = { useCombobox, useMultipleSelection, useSelect, + useTagGroup, cx, Box, ExpandMoreIcon,