downshift 6.0.2 → 6.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -61
- package/dist/downshift.cjs.js +159 -167
- package/dist/downshift.esm.js +159 -167
- package/dist/downshift.native.cjs.js +159 -167
- package/dist/downshift.umd.js +160 -168
- package/dist/downshift.umd.js.map +1 -1
- package/dist/downshift.umd.min.js +2 -2
- package/dist/downshift.umd.min.js.map +1 -1
- package/package.json +33 -26
- package/preact/dist/downshift.cjs.js +159 -167
- package/preact/dist/downshift.esm.js +159 -167
- package/preact/dist/downshift.umd.js +160 -168
- package/preact/dist/downshift.umd.js.map +1 -1
- package/preact/dist/downshift.umd.min.js +2 -2
- package/preact/dist/downshift.umd.min.js.map +1 -1
- package/typings/index.d.ts +27 -8
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<h1 align="center">
|
|
2
2
|
downshift 🏎
|
|
3
3
|
<br>
|
|
4
|
-
<img src="https://downshift-js
|
|
4
|
+
<img src="https://github.com/downshift-js/downshift/blob/master/other/public/logo/downshift.svg" alt="downshift logo" title="downshift logo" width="300">
|
|
5
5
|
<br>
|
|
6
6
|
</h1>
|
|
7
7
|
<p align="center" style="font-size: 1.2rem;">Primitives to build simple, flexible, WAI-ARIA compliant React
|
|
@@ -38,29 +38,33 @@ use case.
|
|
|
38
38
|
|
|
39
39
|
## This solution
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
41
|
+
The library offers a couple of solutions. The first solution, which is the one
|
|
42
|
+
we recommend you to try first, is a set of React hooks. Each hook provides the
|
|
43
|
+
stateful logic needed to make the corresponding component functional and
|
|
44
|
+
accessible. Navigate to the documentation for each by using the links in the
|
|
45
|
+
list below.
|
|
46
|
+
|
|
47
|
+
- [useSelect][useselect-readme] for a custom select component.
|
|
48
|
+
- [useCombobox][combobox-readme] for a combobox/autocomplete input.
|
|
49
|
+
- [useMultipleSelection][multiple-selection-readme] for selecting multiple items
|
|
50
|
+
in a select or a combobox, as well as deleting items from selection or
|
|
51
|
+
navigating between the selected items.
|
|
52
|
+
|
|
53
|
+
The second solution is the `Downshift` component, which can also be used to
|
|
54
|
+
create accessible combobox and select components, providing the logic in the
|
|
55
|
+
form of a render prop. It served as inspiration for developing the hooks and it
|
|
56
|
+
has been around for a while. It established a successful pattern for making
|
|
57
|
+
components accessible and functional while giving developers complete freedom
|
|
58
|
+
when building the UI.
|
|
57
59
|
|
|
58
60
|
The `README` on this page convers only the component while each hook has its own
|
|
59
|
-
`README`
|
|
60
|
-
|
|
61
|
-
always switch between the documentation pages in order to find information.
|
|
61
|
+
`README` page. You can navigate to the [hooks page][hooks-readme] or go directly
|
|
62
|
+
to the hook you need by using the links in the list above.
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
For examples on how to use the hooks or the Downshift component, check out our
|
|
65
|
+
[docsite][docsite]!
|
|
66
|
+
|
|
67
|
+
### Downshift
|
|
64
68
|
|
|
65
69
|
This is a component that controls user interactions and state for you so you can
|
|
66
70
|
create autocomplete/combobox or select dropdown components. It uses a [render
|
|
@@ -76,33 +80,6 @@ harder to contribute to.
|
|
|
76
80
|
> NOTE: The original use case of this component is autocomplete, however the API
|
|
77
81
|
> is powerful and flexible enough to build things like dropdowns as well.
|
|
78
82
|
|
|
79
|
-
### The React Hooks API
|
|
80
|
-
|
|
81
|
-
`Downshift` proved to be a versatile component to create not only combobox
|
|
82
|
-
inputs, but also custom select elements and even multiple selection experiences.
|
|
83
|
-
However, additional code was needed to make these experiences fully accessible,
|
|
84
|
-
so we decided to create dedicated React hooks for them. Each hook handles a
|
|
85
|
-
specific dropdown variation and aims to make it fully accessible.
|
|
86
|
-
|
|
87
|
-
You can check the progress in the [hooks page][hooks-readme]. The hooks
|
|
88
|
-
published so far are:
|
|
89
|
-
|
|
90
|
-
- [useSelect][useselect-readme] for a custom select dropdown.
|
|
91
|
-
- [useCombobox][combobox-readme] for a combobox/autocomplete input.
|
|
92
|
-
- [useMultipleSelection][multiple-selection-readme] for allowing the selection
|
|
93
|
-
of multiple items in a select or a combobox.
|
|
94
|
-
|
|
95
|
-
For examples on how to use the hooks check out our [docsite][docsite]!
|
|
96
|
-
|
|
97
|
-
### Bundle size concerns
|
|
98
|
-
|
|
99
|
-
Adding the hooks into this repo increased the bundle size considerably. However,
|
|
100
|
-
since we create the bundle with `Rollup` and export both `<Downshift>` and the
|
|
101
|
-
hooks as modules, you should be able to have the library treeshaked (pruned) and
|
|
102
|
-
receive only the code you need. Since version `3.4.8`
|
|
103
|
-
[BundlePhobia][bundle-phobia-link] marked `Downshift` as both `tree-shakeable`
|
|
104
|
-
and `side-effect free`.
|
|
105
|
-
|
|
106
83
|
## Table of Contents
|
|
107
84
|
|
|
108
85
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
|
@@ -183,7 +160,7 @@ npm install --save downshift
|
|
|
183
160
|
|
|
184
161
|
## Usage
|
|
185
162
|
|
|
186
|
-
> [Try it out in the browser]
|
|
163
|
+
> [Try it out in the browser][code-sandbox-try-it-out]
|
|
187
164
|
|
|
188
165
|
```jsx
|
|
189
166
|
import * as React from 'react'
|
|
@@ -253,8 +230,7 @@ render(
|
|
|
253
230
|
)
|
|
254
231
|
```
|
|
255
232
|
|
|
256
|
-
|
|
257
|
-
[here](https://codesandbox.io/s/n9095).
|
|
233
|
+
There is also an [example without getRootProps][code-sandbox-no-get-root-props].
|
|
258
234
|
|
|
259
235
|
> Warning: The example without `getRootProps` is not fully accessible with
|
|
260
236
|
> screen readers as it's not possible to achieve the HTML structure suggested by
|
|
@@ -1090,14 +1066,21 @@ platforms:
|
|
|
1090
1066
|
## Examples
|
|
1091
1067
|
|
|
1092
1068
|
> 🚨 We're in the process of moving all examples to the
|
|
1093
|
-
> [downshift-examples](https://github.com/
|
|
1069
|
+
> [downshift-examples](https://github.com/downshift-js/downshift-examples) repo
|
|
1094
1070
|
> (which you can open, interact with, and contribute back to live on
|
|
1095
1071
|
> [codesandbox](https://codesandbox.io/s/github/kentcdodds/downshift-examples))
|
|
1096
1072
|
|
|
1073
|
+
> 🚨 We're also in the process of updating our examples from the
|
|
1074
|
+
> [downshift-docs](https://github.com/downshift-js/downshift-docs) repo which is
|
|
1075
|
+
> actually used to create our docsite at [downshit-js.com][docsite]). Make sure to
|
|
1076
|
+
> check it out for the most relevant Downshift examples or try out the new hooks
|
|
1077
|
+
> that aim to replace Downshift.
|
|
1078
|
+
|
|
1097
1079
|
**Ordered Examples:**
|
|
1098
1080
|
|
|
1099
1081
|
If you're just learning downshift, review these in order:
|
|
1100
1082
|
|
|
1083
|
+
0. [basic automplete with getRootProps](https://codesandbox.io/s/github/kentcdodds/downshift-examples?file=/src/downshift/ordered-examples/00-get-root-props-example.js) - the same as example #1 but using the correct HTML structure as suggested by ARIA-WCAG.
|
|
1101
1084
|
1. [basic autocomplete](https://codesandbox.io/s/github/kentcdodds/downshift-examples/tree/master/?module=%2Fsrc%2Fordered-examples%2F01-basic-autocomplete.js&moduleview=1) -
|
|
1102
1085
|
very bare bones, not styled at all. Good place to start.
|
|
1103
1086
|
2. [styled autocomplete](https://codesandbox.io/s/github/kentcdodds/downshift-examples/tree/master/?module=%2Fsrc%2Fordered-examples%2F02-complete-autocomplete.js&moduleview=1) -
|
|
@@ -1110,14 +1093,6 @@ If you're just learning downshift, review these in order:
|
|
|
1110
1093
|
Shows how to create a MultiDownshift component that allows for an array of
|
|
1111
1094
|
selectedItems for multiple selection using a state reducer
|
|
1112
1095
|
|
|
1113
|
-
**Hooks Examples:**
|
|
1114
|
-
|
|
1115
|
-
We are also in the process of updating our [docsite][docsite] and we aim to add
|
|
1116
|
-
the examples that illustrate the use of hooks there. This is a great opportunity
|
|
1117
|
-
to contribute, by converting existing `Downshift` examples to either `useSelect`
|
|
1118
|
-
or `useCombobox` or by adding any other scenarios that you feel are
|
|
1119
|
-
representative.
|
|
1120
|
-
|
|
1121
1096
|
**Other Examples:**
|
|
1122
1097
|
|
|
1123
1098
|
Check out these examples of more advanced use/edge cases:
|
|
@@ -1237,7 +1212,7 @@ You can implement these other solutions using `downshift`, but if you'd prefer
|
|
|
1237
1212
|
to use these out of the box solutions, then that's fine too:
|
|
1238
1213
|
|
|
1239
1214
|
- [`react-select`](https://github.com/JedWatson/react-select)
|
|
1240
|
-
- [`react-
|
|
1215
|
+
- [`react-autosuggest`](https://github.com/moroshko/react-autosuggest)
|
|
1241
1216
|
|
|
1242
1217
|
## Bindings for ReasonML
|
|
1243
1218
|
|
|
@@ -1422,6 +1397,10 @@ Thanks goes to these people ([emoji key][emojis]):
|
|
|
1422
1397
|
<td align="center"><a href="http://dataart.com"><img src="https://avatars1.githubusercontent.com/u/5685800?v=4" width="100px;" alt=""/><br /><sub><b>Sergey Skrynnikov</b></sub></a><br /><a href="https://github.com/downshift-js/downshift/commits?author=IwalkAlone" title="Code">💻</a> <a href="https://github.com/downshift-js/downshift/commits?author=IwalkAlone" title="Tests">⚠️</a></td>
|
|
1423
1398
|
<td align="center"><a href="https://www.linkedin.com/in/vvoyer"><img src="https://avatars0.githubusercontent.com/u/123822?v=4" width="100px;" alt=""/><br /><sub><b>Vincent Voyer</b></sub></a><br /><a href="https://github.com/downshift-js/downshift/commits?author=vvo" title="Documentation">📖</a></td>
|
|
1424
1399
|
<td align="center"><a href="https://github.com/limejoe"><img src="https://avatars2.githubusercontent.com/u/7977551?v=4" width="100px;" alt=""/><br /><sub><b>limejoe</b></sub></a><br /><a href="https://github.com/downshift-js/downshift/commits?author=limejoe" title="Code">💻</a> <a href="https://github.com/downshift-js/downshift/issues?q=author%3Alimejoe" title="Bug reports">🐛</a></td>
|
|
1400
|
+
<td align="center"><a href="https://github.com/k88manish"><img src="https://avatars2.githubusercontent.com/u/19614770?v=4" width="100px;" alt=""/><br /><sub><b>Manish Kumar</b></sub></a><br /><a href="https://github.com/downshift-js/downshift/commits?author=k88manish" title="Code">💻</a></td>
|
|
1401
|
+
</tr>
|
|
1402
|
+
<tr>
|
|
1403
|
+
<td align="center"><a href="https://github.com/fcrezza"><img src="https://avatars2.githubusercontent.com/u/48123020?v=4" width="100px;" alt=""/><br /><sub><b>Anang Fachreza</b></sub></a><br /><a href="https://github.com/downshift-js/downshift/commits?author=fcrezza" title="Documentation">📖</a> <a href="#example-fcrezza" title="Examples">💡</a></td>
|
|
1425
1404
|
</tr>
|
|
1426
1405
|
</table>
|
|
1427
1406
|
|
|
@@ -1503,3 +1482,7 @@ MIT
|
|
|
1503
1482
|
[select-aria]:
|
|
1504
1483
|
https://www.w3.org/TR/wai-aria-practices/examples/listbox/listbox-collapsible.html
|
|
1505
1484
|
[docsite]: https://downshift-js.com/
|
|
1485
|
+
[code-sandbox-try-it-out]:
|
|
1486
|
+
https://codesandbox.io/s/github/kentcdodds/downshift-examples?file=/src/downshift/ordered-examples/00-get-root-props-example.js
|
|
1487
|
+
[code-sandbox-no-get-root-props]:
|
|
1488
|
+
https://codesandbox.io/s/github/kentcdodds/downshift-examples?file=/src/downshift/ordered-examples/01-basic-autocomplete.js
|
package/dist/downshift.cjs.js
CHANGED
|
@@ -2088,6 +2088,69 @@ function useGetterPropsCalledChecker() {
|
|
|
2088
2088
|
}, []);
|
|
2089
2089
|
return setGetterPropCallInfo;
|
|
2090
2090
|
}
|
|
2091
|
+
function useA11yMessageSetter(getA11yMessage, dependencyArray, _ref2) {
|
|
2092
|
+
var isInitialMount = _ref2.isInitialMount,
|
|
2093
|
+
previousResultCount = _ref2.previousResultCount,
|
|
2094
|
+
highlightedIndex = _ref2.highlightedIndex,
|
|
2095
|
+
items = _ref2.items,
|
|
2096
|
+
environment = _ref2.environment,
|
|
2097
|
+
rest = _objectWithoutPropertiesLoose(_ref2, ["isInitialMount", "previousResultCount", "highlightedIndex", "items", "environment"]);
|
|
2098
|
+
|
|
2099
|
+
// Sets a11y status message on changes in state.
|
|
2100
|
+
react.useEffect(function () {
|
|
2101
|
+
if (isInitialMount) {
|
|
2102
|
+
return;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
updateA11yStatus(function () {
|
|
2106
|
+
return getA11yMessage(_extends({
|
|
2107
|
+
highlightedIndex: highlightedIndex,
|
|
2108
|
+
highlightedItem: items[highlightedIndex],
|
|
2109
|
+
resultCount: items.length,
|
|
2110
|
+
previousResultCount: previousResultCount
|
|
2111
|
+
}, rest));
|
|
2112
|
+
}, environment.document); // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2113
|
+
}, dependencyArray);
|
|
2114
|
+
}
|
|
2115
|
+
function useScrollIntoView(_ref3) {
|
|
2116
|
+
var highlightedIndex = _ref3.highlightedIndex,
|
|
2117
|
+
isOpen = _ref3.isOpen,
|
|
2118
|
+
itemRefs = _ref3.itemRefs,
|
|
2119
|
+
getItemNodeFromIndex = _ref3.getItemNodeFromIndex,
|
|
2120
|
+
menuElement = _ref3.menuElement,
|
|
2121
|
+
scrollIntoViewProp = _ref3.scrollIntoView;
|
|
2122
|
+
// used not to scroll on highlight by mouse.
|
|
2123
|
+
var shouldScrollRef = react.useRef(true); // Scroll on highlighted item if change comes from keyboard.
|
|
2124
|
+
|
|
2125
|
+
react.useEffect(function () {
|
|
2126
|
+
if (highlightedIndex < 0 || !isOpen || !Object.keys(itemRefs.current).length) {
|
|
2127
|
+
return;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
if (shouldScrollRef.current === false) {
|
|
2131
|
+
shouldScrollRef.current = true;
|
|
2132
|
+
} else {
|
|
2133
|
+
scrollIntoViewProp(getItemNodeFromIndex(highlightedIndex), menuElement);
|
|
2134
|
+
} // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2135
|
+
|
|
2136
|
+
}, [highlightedIndex]);
|
|
2137
|
+
return shouldScrollRef;
|
|
2138
|
+
}
|
|
2139
|
+
function useControlPropsValidator(_ref4) {
|
|
2140
|
+
var isInitialMount = _ref4.isInitialMount,
|
|
2141
|
+
props = _ref4.props,
|
|
2142
|
+
state = _ref4.state;
|
|
2143
|
+
// used for checking when props are moving from controlled to uncontrolled.
|
|
2144
|
+
var prevPropsRef = react.useRef(props);
|
|
2145
|
+
react.useEffect(function () {
|
|
2146
|
+
if (isInitialMount) {
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
validateControlledUnchanged(state, prevPropsRef.current, props);
|
|
2151
|
+
prevPropsRef.current = props;
|
|
2152
|
+
}, [state, props, isInitialMount]);
|
|
2153
|
+
}
|
|
2091
2154
|
|
|
2092
2155
|
function getItemIndexByCharacterKey(keysSoFar, highlightedIndex, items, itemToStringParam, getItemNodeFromIndex) {
|
|
2093
2156
|
var lowerCasedItemStrings = items.map(function (item) {
|
|
@@ -2454,9 +2517,7 @@ function useSelect(userProps) {
|
|
|
2454
2517
|
var toggleButtonRef = react.useRef(null);
|
|
2455
2518
|
var menuRef = react.useRef(null);
|
|
2456
2519
|
var itemRefs = react.useRef();
|
|
2457
|
-
itemRefs.current = {}; // used not to
|
|
2458
|
-
|
|
2459
|
-
var shouldScrollRef = react.useRef(true); // used not to trigger menu blur action in some scenarios.
|
|
2520
|
+
itemRefs.current = {}; // used not to trigger menu blur action in some scenarios.
|
|
2460
2521
|
|
|
2461
2522
|
var shouldBlurRef = react.useRef(true); // used to keep the inputValue clearTimeout object between renders.
|
|
2462
2523
|
|
|
@@ -2465,9 +2526,7 @@ function useSelect(userProps) {
|
|
|
2465
2526
|
var elementIdsRef = react.useRef(getElementIds(props)); // used to keep track of how many items we had on previous cycle.
|
|
2466
2527
|
|
|
2467
2528
|
var previousResultCountRef = react.useRef();
|
|
2468
|
-
var isInitialMountRef = react.useRef(true); //
|
|
2469
|
-
|
|
2470
|
-
var prevPropsRef = react.useRef(props); // utility callback to get item element.
|
|
2529
|
+
var isInitialMountRef = react.useRef(true); // utility callback to get item element.
|
|
2471
2530
|
|
|
2472
2531
|
var latest = useLatestRef({
|
|
2473
2532
|
state: state,
|
|
@@ -2480,45 +2539,30 @@ function useSelect(userProps) {
|
|
|
2480
2539
|
// Sets a11y status message on changes in state.
|
|
2481
2540
|
|
|
2482
2541
|
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
var previousResultCount = previousResultCountRef.current;
|
|
2509
|
-
updateA11yStatus(function () {
|
|
2510
|
-
return getA11ySelectionMessage({
|
|
2511
|
-
isOpen: isOpen,
|
|
2512
|
-
highlightedIndex: highlightedIndex,
|
|
2513
|
-
selectedItem: selectedItem,
|
|
2514
|
-
inputValue: inputValue,
|
|
2515
|
-
highlightedItem: items[highlightedIndex],
|
|
2516
|
-
resultCount: items.length,
|
|
2517
|
-
itemToString: itemToString,
|
|
2518
|
-
previousResultCount: previousResultCount
|
|
2519
|
-
});
|
|
2520
|
-
}, environment.document); // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2521
|
-
}, [selectedItem]); // Sets cleanup for the keysSoFar after 500ms.
|
|
2542
|
+
useA11yMessageSetter(getA11yStatusMessage, [isOpen, highlightedIndex, inputValue, items], _extends({
|
|
2543
|
+
isInitialMount: isInitialMountRef.current,
|
|
2544
|
+
previousResultCount: previousResultCountRef.current,
|
|
2545
|
+
items: items,
|
|
2546
|
+
environment: environment,
|
|
2547
|
+
itemToString: itemToString
|
|
2548
|
+
}, state)); // Sets a11y status message on changes in selectedItem.
|
|
2549
|
+
|
|
2550
|
+
useA11yMessageSetter(getA11ySelectionMessage, [selectedItem], _extends({
|
|
2551
|
+
isInitialMount: isInitialMountRef.current,
|
|
2552
|
+
previousResultCount: previousResultCountRef.current,
|
|
2553
|
+
items: items,
|
|
2554
|
+
environment: environment,
|
|
2555
|
+
itemToString: itemToString
|
|
2556
|
+
}, state)); // Scroll on highlighted item if change comes from keyboard.
|
|
2557
|
+
|
|
2558
|
+
var shouldScrollRef = useScrollIntoView({
|
|
2559
|
+
menuElement: menuRef.current,
|
|
2560
|
+
highlightedIndex: highlightedIndex,
|
|
2561
|
+
isOpen: isOpen,
|
|
2562
|
+
itemRefs: itemRefs,
|
|
2563
|
+
scrollIntoView: scrollIntoView,
|
|
2564
|
+
getItemNodeFromIndex: getItemNodeFromIndex
|
|
2565
|
+
}); // Sets cleanup for the keysSoFar after 500ms.
|
|
2522
2566
|
|
|
2523
2567
|
react.useEffect(function () {
|
|
2524
2568
|
// init the clean function here as we need access to dispatch.
|
|
@@ -2535,8 +2579,13 @@ function useSelect(userProps) {
|
|
|
2535
2579
|
return;
|
|
2536
2580
|
}
|
|
2537
2581
|
|
|
2538
|
-
clearTimeoutRef.current(dispatch);
|
|
2539
|
-
}, [inputValue]);
|
|
2582
|
+
clearTimeoutRef.current(dispatch);
|
|
2583
|
+
}, [dispatch, inputValue]);
|
|
2584
|
+
useControlPropsValidator({
|
|
2585
|
+
isInitialMount: isInitialMountRef.current,
|
|
2586
|
+
props: props,
|
|
2587
|
+
state: state
|
|
2588
|
+
});
|
|
2540
2589
|
/* Controls the focus on the menu or the toggle button. */
|
|
2541
2590
|
|
|
2542
2591
|
react.useEffect(function () {
|
|
@@ -2569,35 +2618,14 @@ function useSelect(userProps) {
|
|
|
2569
2618
|
}
|
|
2570
2619
|
} // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2571
2620
|
|
|
2572
|
-
}, [isOpen]);
|
|
2573
|
-
|
|
2574
|
-
react.useEffect(function () {
|
|
2575
|
-
if (highlightedIndex < 0 || !isOpen || !Object.keys(itemRefs.current).length) {
|
|
2576
|
-
return;
|
|
2577
|
-
}
|
|
2578
|
-
|
|
2579
|
-
if (shouldScrollRef.current === false) {
|
|
2580
|
-
shouldScrollRef.current = true;
|
|
2581
|
-
} else {
|
|
2582
|
-
scrollIntoView(getItemNodeFromIndex(highlightedIndex), menuRef.current);
|
|
2583
|
-
} // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2584
|
-
|
|
2585
|
-
}, [highlightedIndex]);
|
|
2621
|
+
}, [isOpen]);
|
|
2586
2622
|
react.useEffect(function () {
|
|
2587
2623
|
if (isInitialMountRef.current) {
|
|
2588
2624
|
return;
|
|
2589
2625
|
}
|
|
2590
2626
|
|
|
2591
2627
|
previousResultCountRef.current = items.length;
|
|
2592
|
-
});
|
|
2593
|
-
react.useEffect(function () {
|
|
2594
|
-
if (isInitialMountRef.current) {
|
|
2595
|
-
return;
|
|
2596
|
-
}
|
|
2597
|
-
|
|
2598
|
-
validateControlledUnchanged(state, prevPropsRef.current, props);
|
|
2599
|
-
prevPropsRef.current = props;
|
|
2600
|
-
}, [state, props]); // Add mouse/touch events to document.
|
|
2628
|
+
}); // Add mouse/touch events to document.
|
|
2601
2629
|
|
|
2602
2630
|
var mouseAndTouchTrackersRef = useMouseAndTouchTracker(isOpen, [menuRef, toggleButtonRef], environment, function () {
|
|
2603
2631
|
dispatch({
|
|
@@ -2891,7 +2919,7 @@ function useSelect(userProps) {
|
|
|
2891
2919
|
}
|
|
2892
2920
|
|
|
2893
2921
|
return itemProps;
|
|
2894
|
-
}, [dispatch, latest]);
|
|
2922
|
+
}, [dispatch, latest, shouldScrollRef]);
|
|
2895
2923
|
return {
|
|
2896
2924
|
// prop getters.
|
|
2897
2925
|
getToggleButtonProps: getToggleButtonProps,
|
|
@@ -3117,7 +3145,7 @@ function downshiftUseComboboxReducer(state, action) {
|
|
|
3117
3145
|
break;
|
|
3118
3146
|
|
|
3119
3147
|
case InputKeyDownEnter:
|
|
3120
|
-
changes = _extends({}, state.highlightedIndex >= 0 && {
|
|
3148
|
+
changes = _extends({}, state.isOpen && state.highlightedIndex >= 0 && {
|
|
3121
3149
|
selectedItem: props.items[state.highlightedIndex],
|
|
3122
3150
|
isOpen: getDefaultValue(props, 'isOpen'),
|
|
3123
3151
|
highlightedIndex: getDefaultValue(props, 'highlightedIndex'),
|
|
@@ -3136,25 +3164,28 @@ function downshiftUseComboboxReducer(state, action) {
|
|
|
3136
3164
|
break;
|
|
3137
3165
|
|
|
3138
3166
|
case InputKeyDownHome:
|
|
3139
|
-
changes = {
|
|
3167
|
+
changes = _extends({}, state.isOpen && {
|
|
3140
3168
|
highlightedIndex: getNextNonDisabledIndex(1, 0, props.items.length, action.getItemNodeFromIndex, false)
|
|
3141
|
-
};
|
|
3169
|
+
});
|
|
3142
3170
|
break;
|
|
3143
3171
|
|
|
3144
3172
|
case InputKeyDownEnd:
|
|
3145
|
-
changes = {
|
|
3173
|
+
changes = _extends({}, state.isOpen && {
|
|
3146
3174
|
highlightedIndex: getNextNonDisabledIndex(-1, props.items.length - 1, props.items.length, action.getItemNodeFromIndex, false)
|
|
3147
|
-
};
|
|
3175
|
+
});
|
|
3148
3176
|
break;
|
|
3149
3177
|
|
|
3150
3178
|
case InputBlur:
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3179
|
+
if (state.isOpen) {
|
|
3180
|
+
changes = _extends({
|
|
3181
|
+
isOpen: false,
|
|
3182
|
+
highlightedIndex: -1
|
|
3183
|
+
}, state.highlightedIndex >= 0 && action.selectItem && {
|
|
3184
|
+
selectedItem: props.items[state.highlightedIndex],
|
|
3185
|
+
inputValue: props.itemToString(props.items[state.highlightedIndex])
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3158
3189
|
break;
|
|
3159
3190
|
|
|
3160
3191
|
case InputChange:
|
|
@@ -3272,16 +3303,12 @@ function useCombobox(userProps) {
|
|
|
3272
3303
|
var inputRef = react.useRef(null);
|
|
3273
3304
|
var toggleButtonRef = react.useRef(null);
|
|
3274
3305
|
var comboboxRef = react.useRef(null);
|
|
3275
|
-
itemRefs.current = {};
|
|
3276
|
-
|
|
3277
|
-
var shouldScrollRef = react.useRef(true);
|
|
3306
|
+
itemRefs.current = {};
|
|
3278
3307
|
var isInitialMountRef = react.useRef(true); // prevent id re-generation between renders.
|
|
3279
3308
|
|
|
3280
3309
|
var elementIdsRef = react.useRef(getElementIds$1(props)); // used to keep track of how many items we had on previous cycle.
|
|
3281
3310
|
|
|
3282
|
-
var previousResultCountRef = react.useRef(); //
|
|
3283
|
-
|
|
3284
|
-
var prevPropsRef = react.useRef(props); // utility callback to get item element.
|
|
3311
|
+
var previousResultCountRef = react.useRef(); // utility callback to get item element.
|
|
3285
3312
|
|
|
3286
3313
|
var latest = useLatestRef({
|
|
3287
3314
|
state: state,
|
|
@@ -3294,58 +3321,35 @@ function useCombobox(userProps) {
|
|
|
3294
3321
|
// Sets a11y status message on changes in state.
|
|
3295
3322
|
|
|
3296
3323
|
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
highlightedIndex: highlightedIndex,
|
|
3327
|
-
selectedItem: selectedItem,
|
|
3328
|
-
inputValue: inputValue,
|
|
3329
|
-
highlightedItem: items[highlightedIndex],
|
|
3330
|
-
resultCount: items.length,
|
|
3331
|
-
itemToString: itemToString,
|
|
3332
|
-
previousResultCount: previousResultCount
|
|
3333
|
-
});
|
|
3334
|
-
}, environment.document); // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3335
|
-
}, [selectedItem]); // Scroll on highlighted item if change comes from keyboard.
|
|
3336
|
-
|
|
3337
|
-
react.useEffect(function () {
|
|
3338
|
-
if (highlightedIndex < 0 || !isOpen || !Object.keys(itemRefs.current).length) {
|
|
3339
|
-
return;
|
|
3340
|
-
}
|
|
3341
|
-
|
|
3342
|
-
if (shouldScrollRef.current === false) {
|
|
3343
|
-
shouldScrollRef.current = true;
|
|
3344
|
-
} else {
|
|
3345
|
-
scrollIntoView(getItemNodeFromIndex(highlightedIndex), menuRef.current);
|
|
3346
|
-
} // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3347
|
-
|
|
3348
|
-
}, [highlightedIndex]); // Controls the focus on the menu or the toggle button.
|
|
3324
|
+
useA11yMessageSetter(getA11yStatusMessage, [isOpen, highlightedIndex, inputValue, items], _extends({
|
|
3325
|
+
isInitialMount: isInitialMountRef.current,
|
|
3326
|
+
previousResultCount: previousResultCountRef.current,
|
|
3327
|
+
items: items,
|
|
3328
|
+
environment: environment,
|
|
3329
|
+
itemToString: itemToString
|
|
3330
|
+
}, state)); // Sets a11y status message on changes in selectedItem.
|
|
3331
|
+
|
|
3332
|
+
useA11yMessageSetter(getA11ySelectionMessage, [selectedItem], _extends({
|
|
3333
|
+
isInitialMount: isInitialMountRef.current,
|
|
3334
|
+
previousResultCount: previousResultCountRef.current,
|
|
3335
|
+
items: items,
|
|
3336
|
+
environment: environment,
|
|
3337
|
+
itemToString: itemToString
|
|
3338
|
+
}, state)); // Scroll on highlighted item if change comes from keyboard.
|
|
3339
|
+
|
|
3340
|
+
var shouldScrollRef = useScrollIntoView({
|
|
3341
|
+
menuElement: menuRef.current,
|
|
3342
|
+
highlightedIndex: highlightedIndex,
|
|
3343
|
+
isOpen: isOpen,
|
|
3344
|
+
itemRefs: itemRefs,
|
|
3345
|
+
scrollIntoView: scrollIntoView,
|
|
3346
|
+
getItemNodeFromIndex: getItemNodeFromIndex
|
|
3347
|
+
});
|
|
3348
|
+
useControlPropsValidator({
|
|
3349
|
+
isInitialMount: isInitialMountRef.current,
|
|
3350
|
+
props: props,
|
|
3351
|
+
state: state
|
|
3352
|
+
}); // Controls the focus on the input on open.
|
|
3349
3353
|
|
|
3350
3354
|
react.useEffect(function () {
|
|
3351
3355
|
// Don't focus menu on first render.
|
|
@@ -3365,15 +3369,7 @@ function useCombobox(userProps) {
|
|
|
3365
3369
|
}
|
|
3366
3370
|
|
|
3367
3371
|
previousResultCountRef.current = items.length;
|
|
3368
|
-
});
|
|
3369
|
-
react.useEffect(function () {
|
|
3370
|
-
if (isInitialMountRef.current) {
|
|
3371
|
-
return;
|
|
3372
|
-
}
|
|
3373
|
-
|
|
3374
|
-
validateControlledUnchanged(state, prevPropsRef.current, props);
|
|
3375
|
-
prevPropsRef.current = props;
|
|
3376
|
-
}, [state, props]); // Add mouse/touch events to document.
|
|
3372
|
+
}); // Add mouse/touch events to document.
|
|
3377
3373
|
|
|
3378
3374
|
var mouseAndTouchTrackersRef = useMouseAndTouchTracker(isOpen, [comboboxRef, menuRef, toggleButtonRef], environment, function () {
|
|
3379
3375
|
dispatch({
|
|
@@ -3433,13 +3429,14 @@ function useCombobox(userProps) {
|
|
|
3433
3429
|
|
|
3434
3430
|
var latestState = latest.current.state;
|
|
3435
3431
|
|
|
3436
|
-
if (latestState.isOpen
|
|
3432
|
+
if (latestState.isOpen) {
|
|
3437
3433
|
event.preventDefault();
|
|
3438
|
-
dispatch({
|
|
3439
|
-
type: InputKeyDownEnter,
|
|
3440
|
-
getItemNodeFromIndex: getItemNodeFromIndex
|
|
3441
|
-
});
|
|
3442
3434
|
}
|
|
3435
|
+
|
|
3436
|
+
dispatch({
|
|
3437
|
+
type: InputKeyDownEnter,
|
|
3438
|
+
getItemNodeFromIndex: getItemNodeFromIndex
|
|
3439
|
+
});
|
|
3443
3440
|
}
|
|
3444
3441
|
};
|
|
3445
3442
|
}, [dispatch, latest]); // Getter props.
|
|
@@ -3524,7 +3521,7 @@ function useCombobox(userProps) {
|
|
|
3524
3521
|
inputRef.current.focus();
|
|
3525
3522
|
}
|
|
3526
3523
|
}), _ref4), rest);
|
|
3527
|
-
}, [dispatch, latest]);
|
|
3524
|
+
}, [dispatch, latest, shouldScrollRef]);
|
|
3528
3525
|
var getToggleButtonProps = react.useCallback(function (_temp4) {
|
|
3529
3526
|
var _extends4;
|
|
3530
3527
|
|
|
@@ -4004,9 +4001,7 @@ function useMultipleSelection(userProps) {
|
|
|
4004
4001
|
var dropdownRef = react.useRef(null);
|
|
4005
4002
|
var previousSelectedItemsRef = react.useRef(selectedItems);
|
|
4006
4003
|
var selectedItemRefs = react.useRef();
|
|
4007
|
-
selectedItemRefs.current = [];
|
|
4008
|
-
|
|
4009
|
-
var prevPropsRef = react.useRef(props);
|
|
4004
|
+
selectedItemRefs.current = [];
|
|
4010
4005
|
var latest = useLatestRef({
|
|
4011
4006
|
state: state,
|
|
4012
4007
|
props: props
|
|
@@ -4046,14 +4041,11 @@ function useMultipleSelection(userProps) {
|
|
|
4046
4041
|
selectedItemRefs.current[activeIndex].focus();
|
|
4047
4042
|
}
|
|
4048
4043
|
}, [activeIndex]);
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
validateControlledUnchanged(state, prevPropsRef.current, props);
|
|
4055
|
-
prevPropsRef.current = props;
|
|
4056
|
-
}, [state, props]);
|
|
4044
|
+
useControlPropsValidator({
|
|
4045
|
+
isInitialMount: isInitialMountRef.current,
|
|
4046
|
+
props: props,
|
|
4047
|
+
state: state
|
|
4048
|
+
});
|
|
4057
4049
|
var setGetterPropCallInfo = useGetterPropsCalledChecker('getDropdownProps'); // Make initial ref false.
|
|
4058
4050
|
|
|
4059
4051
|
react.useEffect(function () {
|