Update Address Book Component for better interaction

refs VICE-2186

Test Plan
1. Open storybook
2. Shrink window so items scroll
3. When navigating with keyboard, the menu should scroll up and down

Change-Id: I32985d5f43e7dc4bbf844e99ee6c0f59e39038cd
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/278817
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Matthew Lemon <mlemon@instructure.com>
QA-Review: Matthew Lemon <mlemon@instructure.com>
Product-Review: Matthew Lemon <mlemon@instructure.com>
This commit is contained in:
Jeffrey Johnson 2021-11-18 12:23:51 -08:00
parent 6cc5678449
commit 9540f05e42
2 changed files with 49 additions and 12 deletions

View File

@ -16,9 +16,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// TODO:
// Need to fix No results text
import PropTypes from 'prop-types'
import {Popover} from '@instructure/ui-popover'
import {View} from '@instructure/ui-view'
@ -72,6 +69,7 @@ export const AddressBook = ({
const [isLimitReached, setLimitReached] = useState(false)
const [popoverWidth, setPopoverWidth] = useState('200px')
const [inputValue, setInputValue] = useState('')
const menuRef = useRef(null)
const [focusType, setFocusType] = useState(KEYBOARD_FOCUS_TYPE) // Options are 'keyboard' and 'mouse'
const backButtonArray = isSubMenu ? [{id: 'backButton', name: I18n.t('Back')}] : []
const headerArray = headerText ? [{id: 'headerText', name: headerText, focusSkip: true}] : []
@ -134,6 +132,8 @@ export const AddressBook = ({
}
setSelectedItem(user)
}}
menuRef={menuRef}
isKeyboardFocus={focusType === KEYBOARD_FOCUS_TYPE}
>
{user.name}
</AddressBookItem>
@ -309,7 +309,7 @@ export const AddressBook = ({
addTag(user)
onSelect(user.id)
} else {
onSelect(user.id)
onSelect(user.id, isCourse, isBackButton)
}
}
@ -355,7 +355,11 @@ export const AddressBook = ({
setIsMenuOpen(true)
}
}}
onBlur={() => setIsMenuOpen(false)}
onBlur={() => {
if (focusType === KEYBOARD_FOCUS_TYPE) {
setIsMenuOpen(false)
}
}}
onKeyDown={inputKeyHandler}
aria-expanded={isMenuOpen}
aria-activedescendant={`address-book-menu-item-${selectedItem?.id}`}
@ -375,7 +379,15 @@ export const AddressBook = ({
/>
}
>
<View as="div" width={popoverWidth} maxHeight="80vh" overflowY="auto">
<View
elementRef={el => {
menuRef.current = el
}}
as="div"
width={popoverWidth}
maxHeight="80vh"
overflowY="auto"
>
{isLoading && renderLoading()}
{!isLoading && (
<ul

View File

@ -17,7 +17,7 @@
*/
import PropTypes from 'prop-types'
import React, {useState} from 'react'
import React, {useEffect, useRef} from 'react'
import {View} from '@instructure/ui-view'
import {Flex} from '@instructure/ui-flex'
import {TruncateText} from '@instructure/ui-truncate-text'
@ -28,11 +28,25 @@ export const AddressBookItem = ({
id,
iconBefore,
iconAfter,
isKeyboardFocus,
isSelected,
hasPopup,
onSelect,
onHover
onHover,
menuRef
}) => {
const itemRef = useRef()
// Scroll individual item into view when its selected or navigated towards
useEffect(() => {
if (isSelected && itemRef.current && menuRef && isKeyboardFocus) {
const menuItemOffsetTop = itemRef.current?.offsetTop
const menuHeight = menuRef.current?.clientHeight
const itemHeight = itemRef.current?.clientHeight
menuRef.current.scrollTop = menuItemOffsetTop - (menuHeight - itemHeight) / 2
}
}, [isKeyboardFocus, isSelected, menuRef])
return (
<View
as="div"
@ -44,15 +58,18 @@ export const AddressBookItem = ({
onMouseLeave={() => {
onHover(false)
}}
onMouseDown={() => {
onSelect()
}}
elementRef={el => {
itemRef.current = el
}}
>
<li
role="menuitem"
id={id}
style={{listStyle: 'none'}}
aria-haspopup={hasPopup}
onMouseDown={() => {
onSelect()
}}
data-selected={isSelected}
>
<Flex as="div" width="100%" margin="xxx-small none xxx-small xxx-small">
@ -109,7 +126,15 @@ AddressBookItem.propTypes = {
/**
* Function to execute on item hover
*/
onHover: PropTypes.func
onHover: PropTypes.func,
/**
* Menu Ref is needed to scroll menu correctly
*/
menuRef: PropTypes.object,
/**
* Boolean to determine if keyboard or mouse navigation is occuring
*/
isKeyboardFocus: PropTypes.bool
}
export default AddressBookItem