UNPKG

2 kBJavaScriptView Raw
1import PropTypes from 'prop-types';
2import React, { useCallback, useEffect, useRef, } from 'react';
3import scrollIntoView from 'scroll-into-view-if-needed';
4import { useTypeaheadContext } from '../core/Context';
5import { getDisplayName, getMenuItemId, preventInputBlur } from '../utils';
6import { optionType } from '../propTypes';
7const propTypes = {
8 option: optionType.isRequired,
9 position: PropTypes.number,
10};
11export function useItem({ label, onClick, option, position, ...props }) {
12 const { activeIndex, id, isOnlyResult, onActiveItemChange, onInitialItemChange, onMenuItemClick, setItem, } = useTypeaheadContext();
13 const itemRef = useRef(null);
14 useEffect(() => {
15 if (position === 0) {
16 onInitialItemChange(option);
17 }
18 });
19 useEffect(() => {
20 if (position === activeIndex) {
21 onActiveItemChange(option);
22 const node = itemRef.current;
23 node &&
24 scrollIntoView(node, {
25 block: 'nearest',
26 boundary: node.parentNode,
27 inline: 'nearest',
28 scrollMode: 'if-needed',
29 });
30 }
31 });
32 const handleClick = useCallback((e) => {
33 onMenuItemClick(option, e);
34 onClick && onClick(e);
35 }, [onClick, onMenuItemClick, option]);
36 const active = isOnlyResult || activeIndex === position;
37 setItem(option, position);
38 return {
39 ...props,
40 active,
41 'aria-label': label,
42 'aria-selected': active,
43 id: getMenuItemId(id, position),
44 onClick: handleClick,
45 onMouseDown: preventInputBlur,
46 ref: itemRef,
47 role: 'option',
48 };
49}
50export function withItem(Component) {
51 const WrappedMenuItem = (props) => (React.createElement(Component, { ...props, ...useItem(props) }));
52 WrappedMenuItem.displayName = `withItem(${getDisplayName(Component)})`;
53 WrappedMenuItem.propTypes = propTypes;
54 return WrappedMenuItem;
55}