diff --git a/.changeset/openMenuOnArrows.md b/.changeset/openMenuOnArrows.md new file mode 100644 index 0000000000..c25482062e --- /dev/null +++ b/.changeset/openMenuOnArrows.md @@ -0,0 +1,5 @@ +--- +'react-select': minor +--- + +Add `openMenuOnArrows` option, to disable opening menu on arrow up/down keys diff --git a/package.json b/package.json index c186787df8..f65f95ebd9 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@testing-library/dom": "8.19.0", "@testing-library/jest-dom": "5.1.1", "@testing-library/react": "12.1.4", - "@testing-library/user-event": "^10.0.0", + "@testing-library/user-event": "^13.0.0", "@types/copy-webpack-plugin": "^5.0.2", "@types/html-webpack-plugin": "^3.2.4", "@types/jest-in-case": "^1.0.6", diff --git a/packages/react-select/src/Select.tsx b/packages/react-select/src/Select.tsx index fc37056c0b..c9e4453387 100644 --- a/packages/react-select/src/Select.tsx +++ b/packages/react-select/src/Select.tsx @@ -248,6 +248,8 @@ export interface Props< openMenuOnFocus: boolean; /** Allows control of whether the menu is opened when the Select is clicked */ openMenuOnClick: boolean; + /** Allows control of whether the menu is opened on up and down arrows */ + openMenuOnArrows: boolean; /** Array of options that populate the select menu */ options: OptionsOrGroups; /** Number of options to jump in menu when page{up|down} keys are used */ @@ -310,6 +312,7 @@ export const defaultProps = { noOptionsMessage: () => 'No options', openMenuOnFocus: false, openMenuOnClick: true, + openMenuOnArrows: true, options: [], pageSize: 5, placeholder: 'Select...', @@ -1565,6 +1568,7 @@ export default class Select< onKeyDown, tabSelectsValue, openMenuOnFocus, + openMenuOnArrows, } = this.props; const { focusedOption, focusedValue, selectValue } = this.state; @@ -1659,6 +1663,8 @@ export default class Select< case 'ArrowUp': if (menuIsOpen) { this.focusOption('up'); + } else if (!openMenuOnArrows) { + return; } else { this.openMenu('last'); } @@ -1666,6 +1672,8 @@ export default class Select< case 'ArrowDown': if (menuIsOpen) { this.focusOption('down'); + } else if (!openMenuOnArrows) { + return; } else { this.openMenu('first'); } diff --git a/packages/react-select/src/__tests__/Select.test.tsx b/packages/react-select/src/__tests__/Select.test.tsx index 0313149095..ed24420af7 100644 --- a/packages/react-select/src/__tests__/Select.test.tsx +++ b/packages/react-select/src/__tests__/Select.test.tsx @@ -969,6 +969,46 @@ test('clicking when focused does not open select when openMenuOnClick=false', () expect(spy).not.toHaveBeenCalled(); }); +test('arrow keys does not open select when openMenuOnArrows=false', () => { + let spy = jest.fn(); + let { container } = render( + + ); + + // this will get updated on input click, though click on input is not bubbling up to control component + userEvent.click(container.querySelector('input.react-select__input')!); + expect(spy).not.toHaveBeenCalled(); + + userEvent.keyboard('[ArrowUp]'); + expect(spy).toHaveBeenCalled(); +}); + cases( 'focus on options > keyboard interaction with Menu', ({ props, selectedOption, nextFocusOption, keyEvent = [] }) => { diff --git a/yarn.lock b/yarn.lock index 7bc6a7d6e7..dc283a9a98 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1266,7 +1266,7 @@ pirates "^4.0.5" source-map-support "^0.5.16" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.2.0", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.7.7", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.2.0", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.7.7", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.19.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78" integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA== @@ -3315,12 +3315,12 @@ "@testing-library/dom" "^8.0.0" "@types/react-dom" "*" -"@testing-library/user-event@^10.0.0": - version "10.4.1" - resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-10.4.1.tgz#f62adeae45681484dc24e6ca4f0b8f8a09321429" - integrity sha512-3sdJAfjT0i4aNvo0Gqod5MvZXutMXarVsLtb+r1t65AaRJY7BgMIzWgOtfM5dxRvZsc7IdXnCt9+gcWhiXk1xg== +"@testing-library/user-event@^13.0.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-13.5.0.tgz#69d77007f1e124d55314a2b73fd204b333b13295" + integrity sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg== dependencies: - "@babel/runtime" "^7.10.2" + "@babel/runtime" "^7.12.5" "@ts-morph/common@~0.5.2": version "0.5.2"