UNPKG

@navikt/ds-react

Version:

React components from the Norwegian Labour and Welfare Administration.

61 lines (51 loc) 2.12 kB
import type { Middleware, Placement } from "@floating-ui/react-dom"; type Side = "top" | "right" | "bottom" | "left"; type Align = "start" | "center" | "end"; type Measurable = { getBoundingClientRect(): DOMRect }; /** * `transformOrigin` is a custom middleware for floating-ui that calculates the transform origin of the floating-element. */ function transformOrigin(options: { arrowWidth: number; arrowHeight: number; }): Middleware { return { name: "transformOrigin", options, fn(data) { const { placement, rects, middlewareData } = data; const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0; const isArrowHidden = cannotCenterArrow; const arrowWidth = isArrowHidden ? 0 : options.arrowWidth; const arrowHeight = isArrowHidden ? 0 : options.arrowHeight; const [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement); const noArrowAlign = { start: "0%", center: "50%", end: "100%" }[ placedAlign ]; const arrowXCenter = (middlewareData.arrow?.x ?? 0) + arrowWidth / 2; const arrowYCenter = (middlewareData.arrow?.y ?? 0) + arrowHeight / 2; let x = ""; let y = ""; if (placedSide === "bottom") { x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`; y = `${-arrowHeight}px`; } else if (placedSide === "top") { x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`; y = `${rects.floating.height + arrowHeight}px`; } else if (placedSide === "right") { x = `${-arrowHeight}px`; y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`; } else if (placedSide === "left") { x = `${rects.floating.width + arrowHeight}px`; y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`; } return { data: { x, y } }; }, }; } function getSideAndAlignFromPlacement(placement: Placement) { const [side, align = "center"] = placement.split("-"); return [side as Side, align as Align] as const; } export { getSideAndAlignFromPlacement, transformOrigin }; export type { Side, Align, Measurable };