From 00512bfaf0ae971b59d2e367bf220d35657a94d4 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 13 Oct 2017 23:22:07 +0700 Subject: [PATCH] Support arrow keys --- client/coral-ui/components/Dropdown.js | 42 ++++++++++++++++++-------- client/coral-ui/components/Option.js | 1 + 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/client/coral-ui/components/Dropdown.js b/client/coral-ui/components/Dropdown.js index 1b83ef2f5..e248cbab6 100644 --- a/client/coral-ui/components/Dropdown.js +++ b/client/coral-ui/components/Dropdown.js @@ -8,8 +8,7 @@ import ClickOutside from 'coral-framework/components/ClickOutside'; class Dropdown extends React.Component { toggleRef = null; - firstOptionRef = null; - lastOptionRef = null; + optionsRef = []; state = { isOpen: false @@ -23,13 +22,37 @@ class Dropdown extends React.Component { } } + goUp = () => { + const index = this.optionsRef.findIndex((ref) => ref.hasFocus()); + if (index > 0) { + this.optionsRef[index - 1].focus(); + } + } + + goDown = () => { + const index = this.optionsRef.findIndex((ref) => ref.hasFocus()); + if (index < this.optionsRef.length - 1) { + this.optionsRef[index + 1].focus(); + } + } + handleOptionKeyDown = (value, e) => { const code = e.which; - // 13 = Return, 32 = Space - if ((code === 13) || (code === 32)) { + switch (code) { + case 13: // 13 = Return + case 32: // 32 = Space e.preventDefault(); this.setValue(value); + break; + case 38: // 38 = Arrow Up + e.preventDefault(); + this.goUp(); + break; + case 40: // 40 = Arrow Down + e.preventDefault(); + this.goDown(); + break; } } @@ -76,12 +99,7 @@ class Dropdown extends React.Component { handleToggleRef = (ref) => this.toggleRef = ref; handleOptionsRef = (ref, index) => { - if (index === 0) { - this.firstOptionRef = ref; - } - if (index === this.props.children.length - 1) { - this.lastOptionRef = ref; - } + this.optionsRef[index] = ref; // Focus on current value when menu opens. if (ref) { @@ -93,8 +111,8 @@ class Dropdown extends React.Component { } // Trap keyboard focus inside the dropdown until a value has been chosen. - trapFocusBegin = () => this.lastOptionRef.focus(); - trapFocusEnd = () => this.firstOptionRef.focus(); + trapFocusBegin = () => this.optionsRef[this.optionsRef.length - 1].focus(); + trapFocusEnd = () => this.optionsRef[0].focus(); renderLabel() { const options = React.Children.toArray(this.props.children); diff --git a/client/coral-ui/components/Option.js b/client/coral-ui/components/Option.js index 542d9c36f..5b752eb48 100644 --- a/client/coral-ui/components/Option.js +++ b/client/coral-ui/components/Option.js @@ -12,6 +12,7 @@ class Option extends React.Component { }; focus = () => {this.ref.focus();} + hasFocus = () => document.activeElement === this.ref; render() { const {className, label = '', onClick, onKeyDown} = this.props;