react-bootstrap-typeahead
Version:
React typeahead with Bootstrap styling
71 lines (70 loc) • 2.13 kB
JavaScript
import PropTypes from 'prop-types';
import { useEffect, useState, } from 'react';
import { usePopper } from 'react-popper';
import { noop } from '../../utils';
const alignValues = ['justify', 'left', 'right'];
const SafeElement = typeof Element === 'undefined' ? noop : Element;
const propTypes = {
align: PropTypes.oneOf(alignValues),
children: PropTypes.func.isRequired,
dropup: PropTypes.bool,
flip: PropTypes.bool,
isMenuShown: PropTypes.bool,
positionFixed: PropTypes.bool,
referenceElement: PropTypes.instanceOf(SafeElement),
};
const defaultProps = {
align: 'justify',
dropup: false,
flip: false,
isMenuShown: false,
positionFixed: false,
};
const setPopperWidth = {
enabled: true,
fn: (data) => {
data.state.styles.popper.width = `${data.state.rects.reference.width}px`;
},
name: 'setPopperWidth',
phase: 'write',
};
export function getModifiers(props) {
const modifiers = [
{
enabled: !!props.flip,
name: 'flip',
},
];
if (props.align !== 'right' && props.align !== 'left') {
modifiers.push(setPopperWidth);
}
return modifiers;
}
export function getPlacement(props) {
const x = props.align === 'right' ? 'end' : 'start';
const y = props.dropup ? 'top' : 'bottom';
return `${y}-${x}`;
}
const Overlay = ({ referenceElement, ...props }) => {
const [popperElement, attachRef] = useState(null);
const { attributes, styles, forceUpdate } = usePopper(referenceElement, popperElement, {
modifiers: getModifiers(props),
placement: getPlacement(props),
strategy: props.positionFixed ? 'fixed' : 'absolute',
});
const refElementHeight = referenceElement?.offsetHeight;
useEffect(() => {
forceUpdate && forceUpdate();
}, [refElementHeight]);
if (!props.isMenuShown) {
return null;
}
return props.children({
...attributes.popper,
innerRef: attachRef,
style: styles.popper,
});
};
Overlay.propTypes = propTypes;
Overlay.defaultProps = defaultProps;
export default Overlay;