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:
parent
6cc5678449
commit
9540f05e42
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue