stream-chat-react
Version:
React components to create chat conversations or livestream style chat
55 lines (54 loc) • 2.45 kB
JavaScript
import { autoPlacement, autoUpdate, flip as flipMw, offset as offsetMw, shift as shiftMw, size as sizeMw, useFloating, } from '@floating-ui/react';
const hasResizeObserver = typeof window !== 'undefined' && 'ResizeObserver' in window;
function autoMiddlewareFor(p) {
if (!String(p).startsWith('auto'))
return null;
const alignment = p === 'auto-start' ? 'start' : p === 'auto-end' ? 'end' : undefined;
return autoPlacement({ alignment });
}
function toOffsetMw(opt) {
if (opt == null)
return null;
if (Array.isArray(opt)) {
const [crossAxis, mainAxis] = opt;
return offsetMw({ crossAxis, mainAxis });
}
if (typeof opt === 'number')
return offsetMw(opt);
return offsetMw(opt);
}
export function usePopoverPosition({ allowFlip = true, allowShift = true, autoUpdateOptions, fitAvailableSpace = false, freeze = false, offset, placement = 'bottom-start', }) {
const autoMw = autoMiddlewareFor(placement);
const offsetMiddleware = toOffsetMw(offset);
const isSidePlacement = placement.startsWith('left') || placement.startsWith('right');
const middleware = [
// offset first (mirrors common Popper setups)
...(offsetMiddleware ? [offsetMiddleware] : []),
// choose between autoPlacement (Popper's "auto*") OR flip()
// only allow flip when not explicitly 'left*' or 'right*'
...(autoMw ? [autoMw] : allowFlip && !isSidePlacement ? [flipMw()] : []),
// viewport collision adjustments
...(allowShift ? [shiftMw({ padding: 8 })] : []),
// optional size constraining
// eslint-disable-next-line @typescript-eslint/no-empty-function
...(fitAvailableSpace ? [sizeMw({ apply: () => { } })] : []),
];
// if placement is 'auto*', seed with any static placement; autoPlacement will pick the final one
const seedPlacement = String(placement).startsWith('auto')
? 'bottom'
: placement;
return useFloating({
middleware,
placement: seedPlacement,
strategy: 'fixed',
whileElementsMounted: freeze
? undefined
: (reference, floating, update) => autoUpdate(reference, floating, update, {
ancestorResize: true,
ancestorScroll: true,
animationFrame: false,
elementResize: hasResizeObserver,
...autoUpdateOptions,
}),
});
}