@navikt/ds-react
Version:
React components from the Norwegian Labour and Welfare Administration.
248 lines • 13.6 kB
JavaScript
"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