react-bootstrap-typeahead
Version:
React typeahead with Bootstrap styling
56 lines (55 loc) • 2.12 kB
JavaScript
import PropTypes from 'prop-types';
import React, { useCallback, useEffect, useRef, } from 'react';
import scrollIntoView from 'scroll-into-view-if-needed';
import { useTypeaheadContext } from '../core/Context';
import { getDisplayName, getMenuItemId, preventInputBlur, warn, } from '../utils';
import { optionType } from '../propTypes';
const propTypes = {
option: optionType.isRequired,
position: PropTypes.number,
};
export function useItem({ label, onClick, option, position, ...props }) {
const { activeIndex, id, isOnlyResult, onActiveItemChange, onInitialItemChange, onMenuItemClick, setItem, } = useTypeaheadContext();
const itemRef = useRef(null);
useEffect(() => {
if (position === 0) {
onInitialItemChange(option);
}
});
useEffect(() => {
if (position === activeIndex) {
onActiveItemChange(option);
const node = itemRef.current;
node &&
scrollIntoView(node, {
boundary: node.parentNode,
scrollMode: 'if-needed',
});
}
}, [activeIndex, onActiveItemChange, option, position]);
const handleClick = useCallback((e) => {
onMenuItemClick(option, e);
onClick && onClick(e);
}, [onClick, onMenuItemClick, option]);
const active = isOnlyResult || activeIndex === position;
setItem(option, position);
return {
...props,
active,
'aria-label': label,
'aria-selected': active,
id: getMenuItemId(id, position),
onClick: handleClick,
onMouseDown: preventInputBlur,
ref: itemRef,
role: 'option',
};
}
export function withItem(Component) {
warn(false, 'Warning: `withItem` is deprecated and will be removed in the next ' +
'major version. Use `useItem` instead.');
const WrappedMenuItem = (props) => (React.createElement(Component, { ...props, ...useItem(props) }));
WrappedMenuItem.displayName = `withItem(${getDisplayName(Component)})`;
WrappedMenuItem.propTypes = propTypes;
return WrappedMenuItem;
}