UNPKG

@navikt/ds-react

Version:

React components from the Norwegian Labour and Welfare Administration.

248 lines 13.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.Floating = exports.useFloatingContext = exports.FloatingProvider = void 0; const react_dom_1 = require("@floating-ui/react-dom"); const react_1 = __importStar(require("react")); const Modal_context_1 = require("../../modal/Modal.context"); const Slot_1 = require("../../slot/Slot"); const create_context_1 = require("../../util/create-context"); const hooks_1 = require("../../util/hooks"); const useOpenChangeAnimationComplete_1 = require("../overlay/hooks/useOpenChangeAnimationComplete"); const Floating_utils_1 = require("./Floating.utils"); _a = (0, create_context_1.createContext)({ name: "FloatingContext", hookName: "useFloating", providerName: "FloatingProvider", }), exports.FloatingProvider = _a[0], exports.useFloatingContext = _a[1]; const Floating = ({ children }) => { const [anchor, setAnchor] = (0, react_1.useState)(null); return (react_1.default.createElement(exports.FloatingProvider, { anchor: anchor, onAnchorChange: setAnchor }, children)); }; exports.Floating = Floating; /** * `FloatingAnchor` provides an anchor for a Floating instance. * Allows anchoring to non-DOM nodes like a cursor position when used with `virtualRef`. */ const FloatingAnchor = (0, react_1.forwardRef)((_a, forwardedRef) => { var { virtualRef, asChild } = _a, rest = __rest(_a, ["virtualRef", "asChild"]); const context = (0, exports.useFloatingContext)(); const ref = (0, react_1.useRef)(null); const mergedRef = (0, hooks_1.useMergeRefs)(forwardedRef, ref); (0, react_1.useEffect)(() => { // Allows anchoring the floating to non-DOM nodes like a cursor position. // We replace `anchorRef` with a virtual ref in such cases. context.onAnchorChange((virtualRef === null || virtualRef === void 0 ? void 0 : virtualRef.current) || ref.current); }); const Comp = asChild ? Slot_1.Slot : "div"; return virtualRef ? null : react_1.default.createElement(Comp, Object.assign({ ref: mergedRef }, rest)); }); /** * Floating Arrow */ const OPPOSITE_SIDE = { top: "bottom", right: "left", bottom: "top", left: "right", }; const FloatingArrow = ({ width, height, className }) => { const context = useFloatingContentContext(); const side = OPPOSITE_SIDE[context.placedSide]; return (react_1.default.createElement("span", { ref: context.onArrowChange, style: { position: "absolute", left: context.arrowX, top: context.arrowY, [side]: 0, transformOrigin: { top: "", right: "0 0", bottom: "center 0", left: "100% 0", }[context.placedSide], transform: { top: "translateY(100%)", right: "translateY(50%) rotate(90deg) translateX(-50%)", bottom: `rotate(180deg)`, left: "translateY(50%) rotate(-90deg) translateX(50%)", }[context.placedSide], visibility: context.hideArrow ? "hidden" : undefined, }, "aria-hidden": true }, react_1.default.createElement("svg", { className: className, width: width, height: height, viewBox: "0 0 30 10", preserveAspectRatio: "none", style: { display: "block" } }, react_1.default.createElement("polygon", { points: "0,0 30,0 15,10" })))); }; const [FloatingContentProvider, useFloatingContentContext] = (0, create_context_1.createContext)({ name: "FloatingContentContext", hookName: "useFloatingContentContext", providerName: "FloatingContentProvider", }); const FloatingContent = (0, react_1.forwardRef)((_a, forwardedRef) => { var _b, _c, _d, _e, _f, _g; var { children, side = "bottom", sideOffset = 0, align = "center", alignOffset = 0, avoidCollisions = true, collisionBoundary = [], collisionPadding: collisionPaddingProp = 0, hideWhenDetached = false, updatePositionStrategy = "optimized", onPlaced, arrow: _arrow, fallbackPlacements, enabled = true, autoUpdateWhileMounted = true } = _a, contentProps = __rest(_a, ["children", "side", "sideOffset", "align", "alignOffset", "avoidCollisions", "collisionBoundary", "collisionPadding", "hideWhenDetached", "updatePositionStrategy", "onPlaced", "arrow", "fallbackPlacements", "enabled", "autoUpdateWhileMounted"]); const context = (0, exports.useFloatingContext)(); const modalContext = (0, Modal_context_1.useModalContext)(false); const arrowDefaults = Object.assign({ padding: 5, width: 0, height: 0 }, _arrow); const [arrow, setArrow] = (0, react_1.useState)(null); const arrowWidth = arrowDefaults.width; const arrowHeight = arrowDefaults.height; const desiredPlacement = (side + (align !== "center" ? "-" + align : "")); const collisionPadding = typeof collisionPaddingProp === "number" ? collisionPaddingProp : Object.assign({ top: 0, right: 0, bottom: 0, left: 0 }, collisionPaddingProp); const boundary = Array.isArray(collisionBoundary) ? collisionBoundary : [collisionBoundary]; const hasExplicitBoundaries = boundary.length > 0; /** * .filter(x => x !== null) does not narrow the type of the array enough. */ function isNotNull(value) { return value !== null; } const detectOverflowOptions = { padding: collisionPadding, boundary: boundary.filter(isNotNull), // with `strategy: 'fixed'`, this is the only way to get it to respect boundaries altBoundary: hasExplicitBoundaries, /* https://floating-ui.com/docs/flip#fallbackaxissidedirection */ fallbackAxisSideDirection: "end", fallbackPlacements, }; const { refs, floatingStyles, placement, isPositioned, middlewareData, elements: floatingElements, update, } = (0, react_dom_1.useFloating)({ open: enabled, // default to `fixed` strategy so users don't have to pick and we also avoid focus scroll issues strategy: "fixed", placement: desiredPlacement, whileElementsMounted: autoUpdateWhileMounted ? (...args) => { const cleanup = (0, react_dom_1.autoUpdate)(...args, { animationFrame: updatePositionStrategy === "always", }); return cleanup; } : undefined, elements: { reference: context.anchor, }, middleware: [ (0, react_dom_1.offset)({ mainAxis: sideOffset + arrowHeight, alignmentAxis: alignOffset, }), avoidCollisions && (0, react_dom_1.shift)({ mainAxis: true, crossAxis: false, limiter: (0, react_dom_1.limitShift)(), }), avoidCollisions && (0, react_dom_1.flip)(Object.assign({}, detectOverflowOptions)), (0, react_dom_1.size)(Object.assign(Object.assign({}, detectOverflowOptions), { apply: ({ elements, rects, availableWidth, availableHeight }) => { const { width: anchorWidth, height: anchorHeight } = rects.reference; const contentStyle = elements.floating.style; /** * Allows styling and animations based on the available space. */ contentStyle.setProperty("--ac-floating-available-width", `${availableWidth}px`); contentStyle.setProperty("--ac-floating-available-height", `${availableHeight}px`); contentStyle.setProperty("--ac-floating-anchor-width", `${anchorWidth}px`); contentStyle.setProperty("--ac-floating-anchor-height", `${anchorHeight}px`); } })), arrow && (0, react_dom_1.arrow)({ element: arrow, padding: arrowDefaults.padding }), (0, Floating_utils_1.transformOrigin)({ arrowWidth, arrowHeight }), hideWhenDetached && (0, react_dom_1.hide)(Object.assign({ strategy: "referenceHidden" }, detectOverflowOptions)), ], }); (0, react_1.useEffect)(() => { if (autoUpdateWhileMounted || !enabled) { return; } if (floatingElements.reference && floatingElements.floating) { const cleanup = (0, react_dom_1.autoUpdate)(floatingElements.reference, floatingElements.floating, update); return () => { cleanup(); }; } }, [autoUpdateWhileMounted, enabled, floatingElements, update]); (0, useOpenChangeAnimationComplete_1.useOpenChangeAnimationComplete)({ enabled: !!(modalContext === null || modalContext === void 0 ? void 0 : modalContext.ref), open: enabled, ref: modalContext === null || modalContext === void 0 ? void 0 : modalContext.ref, onComplete: update, }); const [placedSide, placedAlign] = (0, Floating_utils_1.getSideAndAlignFromPlacement)(placement); const handlePlaced = (0, hooks_1.useCallbackRef)(onPlaced); (0, hooks_1.useClientLayoutEffect)(() => { isPositioned && (handlePlaced === null || handlePlaced === void 0 ? void 0 : handlePlaced()); }, [isPositioned, handlePlaced]); const arrowX = (_b = middlewareData.arrow) === null || _b === void 0 ? void 0 : _b.x; const arrowY = (_c = middlewareData.arrow) === null || _c === void 0 ? void 0 : _c.y; const cannotCenterArrow = ((_d = middlewareData.arrow) === null || _d === void 0 ? void 0 : _d.centerOffset) !== 0; return (react_1.default.createElement("div", { ref: refs.setFloating, "data-aksel-floating-content-wrapper": "", style: Object.assign(Object.assign({}, floatingStyles), { transform: isPositioned ? floatingStyles.transform : "translate(0, -200%)", minWidth: "max-content", zIndex: "9999999", ["--ac-floating-transform-origin"]: [ (_e = middlewareData.transformOrigin) === null || _e === void 0 ? void 0 : _e.x, (_f = middlewareData.transformOrigin) === null || _f === void 0 ? void 0 : _f.y, ].join(" ") }), // Floating UI uses the `dir` attribute on the reference/floating node for logical alignment. // This attribute is necessary for both portalled and inline calculations. dir: "ltr" }, react_1.default.createElement(FloatingContentProvider, { placedSide: placedSide, onArrowChange: setArrow, arrowX: arrowX, arrowY: arrowY, hideArrow: cannotCenterArrow }, react_1.default.createElement("div", Object.assign({ ref: forwardedRef, "data-side": placedSide, "data-align": placedAlign }, contentProps, { style: Object.assign(Object.assign({}, contentProps.style), { // if the FloatingContent hasn't been placed yet (not all measurements done) // we prevent animations so that users's animation don't kick in too early referring wrong sides animation: !isPositioned ? "none" : undefined, // hide the content if using the hide middleware and should be hidden opacity: ((_g = middlewareData.hide) === null || _g === void 0 ? void 0 : _g.referenceHidden) ? 0 : undefined }) }), children, (_arrow === null || _arrow === void 0 ? void 0 : _arrow.height) && (_arrow === null || _arrow === void 0 ? void 0 : _arrow.width) && (react_1.default.createElement(FloatingArrow, { width: _arrow.width, height: _arrow.height, className: _arrow.className })))))); }); Floating.Anchor = FloatingAnchor; Floating.Content = FloatingContent; //# sourceMappingURL=Floating.js.map