UNPKG

@grafana/ui

Version:
80 lines (77 loc) 3.1 kB
import { autoPlacement, size, useFloating, autoUpdate } from '@floating-ui/react'; import { useRef, useState, useMemo } from 'react'; import { measureText } from '../../utils/measureText.mjs'; import { MENU_ITEM_FONT_WEIGHT, MENU_ITEM_FONT_SIZE, MENU_ITEM_PADDING, MENU_OPTION_HEIGHT, POPOVER_MAX_HEIGHT } from './getComboboxStyles.mjs'; const WIDTH_CALCULATION_LIMIT_ITEMS = 1e5; const POPOVER_PADDING = 16; const SCROLL_CONTAINER_PADDING = 8; const useComboboxFloat = (items, isOpen) => { var _a; const inputRef = useRef(null); const floatingRef = useRef(null); const scrollRef = useRef(null); const [popoverMaxSize, setPopoverMaxSize] = useState({ width: 0, height: 0 }); const scrollbarWidth = useMemo(() => getScrollbarWidth(), []); const middleware = [ autoPlacement({ // see https://floating-ui.com/docs/autoplacement allowedPlacements: ["bottom-start", "bottom-end", "top-start", "top-end"], boundary: document.body, crossAxis: true }), size({ apply({ availableWidth, availableHeight }) { const preferredMaxWidth = availableWidth - POPOVER_PADDING; const preferredMaxHeight = availableHeight - POPOVER_PADDING; const width = Math.max(preferredMaxWidth, 0); const height = Math.min(Math.max(preferredMaxHeight, MENU_OPTION_HEIGHT * 6), POPOVER_MAX_HEIGHT); setPopoverMaxSize({ width, height }); } }) ]; const elements = { reference: inputRef.current, floating: floatingRef.current }; const { floatingStyles } = useFloating({ strategy: "fixed", open: isOpen, placement: "bottom-start", middleware, elements, whileElementsMounted: autoUpdate }); const longestItemWidth = useMemo(() => { var _a2; let longestItem = ""; const itemsToLookAt = Math.min(items.length, WIDTH_CALCULATION_LIMIT_ITEMS); for (let i = 0; i < itemsToLookAt; i++) { const itemLabel = (_a2 = items[i].label) != null ? _a2 : items[i].value.toString(); longestItem = itemLabel.length > longestItem.length ? itemLabel : longestItem; } const size2 = measureText(longestItem, MENU_ITEM_FONT_SIZE, MENU_ITEM_FONT_WEIGHT).width; return size2 + SCROLL_CONTAINER_PADDING + MENU_ITEM_PADDING * 2 + scrollbarWidth; }, [items, scrollbarWidth]); const floatStyles = { ...floatingStyles, width: longestItemWidth, maxWidth: popoverMaxSize.width, minWidth: (_a = inputRef.current) == null ? void 0 : _a.offsetWidth, maxHeight: popoverMaxSize.height }; return { inputRef, floatingRef, scrollRef, floatStyles }; }; function getScrollbarWidth() { var _a; const outer = document.createElement("div"); outer.style.visibility = "hidden"; outer.style.overflow = "scroll"; document.body.appendChild(outer); const inner = document.createElement("div"); outer.appendChild(inner); const scrollbarWidth = outer.offsetWidth - inner.offsetWidth; (_a = outer.parentNode) == null ? void 0 : _a.removeChild(outer); return scrollbarWidth; } export { useComboboxFloat }; //# sourceMappingURL=useComboboxFloat.mjs.map