UNPKG

@wordpress/components

Version:
382 lines (380 loc) 14.9 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/components/src/popover/index.tsx var popover_exports = {}; __export(popover_exports, { Popover: () => Popover, PopoverSlot: () => PopoverSlot, SLOT_NAME: () => SLOT_NAME, default: () => popover_default }); module.exports = __toCommonJS(popover_exports); var import_clsx = __toESM(require("clsx")); var import_react_dom = require("@floating-ui/react-dom"); var import_framer_motion = require("framer-motion"); var import_element = require("@wordpress/element"); var import_compose = require("@wordpress/compose"); var import_icons = require("@wordpress/icons"); var import_deprecated = __toESM(require("@wordpress/deprecated")); var import_primitives = require("@wordpress/primitives"); var import_i18n = require("@wordpress/i18n"); var import_button = __toESM(require("../button")); var import_scroll_lock = __toESM(require("../scroll-lock")); var import_slot_fill = require("../slot-fill"); var import_utils = require("./utils"); var import_context = require("../context"); var import_overlay_middlewares = require("./overlay-middlewares"); var import_style_provider = require("../style-provider"); var import_jsx_runtime = require("react/jsx-runtime"); var SLOT_NAME = "Popover"; var OVERFLOW_PADDING = 8; var ArrowTriangle = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_primitives.SVG, { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 100 100", className: "components-popover__triangle", role: "presentation", children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_primitives.Path, { className: "components-popover__triangle-bg", d: "M 0 0 L 50 50 L 100 0" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_primitives.Path, { className: "components-popover__triangle-border", d: "M 0 0 L 50 50 L 100 0", vectorEffect: "non-scaling-stroke" })] }); var slotNameContext = (0, import_element.createContext)(void 0); slotNameContext.displayName = "__unstableSlotNameContext"; var fallbackContainerClassname = "components-popover__fallback-container"; var getPopoverFallbackContainer = () => { let container = document.body.querySelector("." + fallbackContainerClassname); if (!container) { container = document.createElement("div"); container.className = fallbackContainerClassname; document.body.append(container); } return container; }; var UnforwardedPopover = (props, forwardedRef) => { const { animate = true, headerTitle, constrainTabbing, onClose, children, className, noArrow = true, position, placement: placementProp = "bottom-start", offset: offsetProp = 0, focusOnMount = "firstElement", anchor, expandOnMobile, onFocusOutside, __unstableSlotName = SLOT_NAME, flip = true, resize = true, shift = false, inline = false, variant, style: contentStyle, // Deprecated props __unstableForcePosition, anchorRef, anchorRect, getAnchorRect, isAlternate, // Rest ...contentProps } = (0, import_context.useContextSystem)(props, "Popover"); let computedFlipProp = flip; let computedResizeProp = resize; if (__unstableForcePosition !== void 0) { (0, import_deprecated.default)("`__unstableForcePosition` prop in wp.components.Popover", { since: "6.1", version: "6.3", alternative: "`flip={ false }` and `resize={ false }`" }); computedFlipProp = !__unstableForcePosition; computedResizeProp = !__unstableForcePosition; } if (anchorRef !== void 0) { (0, import_deprecated.default)("`anchorRef` prop in wp.components.Popover", { since: "6.1", alternative: "`anchor` prop" }); } if (anchorRect !== void 0) { (0, import_deprecated.default)("`anchorRect` prop in wp.components.Popover", { since: "6.1", alternative: "`anchor` prop" }); } if (getAnchorRect !== void 0) { (0, import_deprecated.default)("`getAnchorRect` prop in wp.components.Popover", { since: "6.1", alternative: "`anchor` prop" }); } const computedVariant = isAlternate ? "toolbar" : variant; if (isAlternate !== void 0) { (0, import_deprecated.default)("`isAlternate` prop in wp.components.Popover", { since: "6.2", alternative: "`variant` prop with the `'toolbar'` value" }); } const arrowRef = (0, import_element.useRef)(null); const [fallbackReferenceElement, setFallbackReferenceElement] = (0, import_element.useState)(null); const anchorRefFallback = (0, import_element.useCallback)((node) => { setFallbackReferenceElement(node); }, []); const isMobileViewport = (0, import_compose.useViewportMatch)("medium", "<"); const isExpanded = expandOnMobile && isMobileViewport; const hasArrow = !isExpanded && !noArrow; const normalizedPlacementFromProps = position ? (0, import_utils.positionToPlacement)(position) : placementProp; const middleware = [...placementProp === "overlay" ? (0, import_overlay_middlewares.overlayMiddlewares)() : [], (0, import_react_dom.offset)(offsetProp), computedFlipProp && (0, import_react_dom.flip)(), computedResizeProp && (0, import_react_dom.size)({ padding: OVERFLOW_PADDING, apply(sizeProps) { var _refs$floating$curren; const { firstElementChild } = (_refs$floating$curren = refs.floating.current) !== null && _refs$floating$curren !== void 0 ? _refs$floating$curren : {}; if (!(firstElementChild instanceof HTMLElement)) { return; } Object.assign(firstElementChild.style, { maxHeight: `${Math.max(0, sizeProps.availableHeight)}px`, overflow: "auto" }); } }), shift && (0, import_react_dom.shift)({ crossAxis: true, limiter: (0, import_react_dom.limitShift)(), padding: 1 // Necessary to avoid flickering at the edge of the viewport. }), (0, import_react_dom.arrow)({ element: arrowRef })]; const slotName = (0, import_element.useContext)(slotNameContext) || __unstableSlotName; const slot = (0, import_slot_fill.useSlot)(slotName); let onDialogClose; if (onClose || onFocusOutside) { onDialogClose = (type, event) => { if (type === "focus-outside") { const blurTarget = event?.target; const referenceElement = refs.reference.current; const floatingElement = refs.floating.current; const isBlurFromThisPopover = referenceElement && "contains" in referenceElement && referenceElement.contains(blurTarget) || floatingElement?.contains(blurTarget); if (!isBlurFromThisPopover) { return; } if (onFocusOutside) { onFocusOutside(event); } else if (onClose) { onClose(); } } else if (onClose) { onClose(); } }; } const [dialogRef, dialogProps] = (0, import_compose.__experimentalUseDialog)({ constrainTabbing, focusOnMount, __unstableOnClose: onDialogClose, // @ts-expect-error The __unstableOnClose property needs to be deprecated first (see https://github.com/WordPress/gutenberg/pull/27675) onClose: onDialogClose }); const { // Positioning coordinates x, y, // Object with "regular" refs to both "reference" and "floating" refs, // Type of CSS position property to use (absolute or fixed) strategy, update, placement: computedPlacement, middlewareData: { arrow: arrowData } } = (0, import_react_dom.useFloating)({ placement: normalizedPlacementFromProps === "overlay" ? void 0 : normalizedPlacementFromProps, middleware, whileElementsMounted: (referenceParam, floatingParam, updateParam) => (0, import_react_dom.autoUpdate)(referenceParam, floatingParam, updateParam, { layoutShift: false, animationFrame: true }) }); const arrowCallbackRef = (0, import_element.useCallback)((node) => { arrowRef.current = node; update(); }, [update]); const anchorRefTop = anchorRef?.top; const anchorRefBottom = anchorRef?.bottom; const anchorRefStartContainer = anchorRef?.startContainer; const anchorRefCurrent = anchorRef?.current; (0, import_element.useLayoutEffect)(() => { const resultingReferenceElement = (0, import_utils.getReferenceElement)({ anchor, anchorRef, anchorRect, getAnchorRect, fallbackReferenceElement }); refs.setReference(resultingReferenceElement); }, [anchor, anchorRef, anchorRefTop, anchorRefBottom, anchorRefStartContainer, anchorRefCurrent, anchorRect, getAnchorRect, fallbackReferenceElement, refs]); const mergedFloatingRef = (0, import_compose.useMergeRefs)([refs.setFloating, dialogRef, forwardedRef]); const style = isExpanded ? void 0 : { position: strategy, top: 0, left: 0, // `x` and `y` are framer-motion specific props and are shorthands // for `translateX` and `translateY`. Currently it is not possible // to use `translateX` and `translateY` because those values would // be overridden by the return value of the // `placementToMotionAnimationProps` function. x: (0, import_utils.computePopoverPosition)(x), y: (0, import_utils.computePopoverPosition)(y) }; const shouldReduceMotion = (0, import_compose.useReducedMotion)(); const shouldAnimate = animate && !isExpanded && !shouldReduceMotion; const [animationFinished, setAnimationFinished] = (0, import_element.useState)(false); const { style: motionInlineStyles, ...otherMotionProps } = (0, import_element.useMemo)(() => (0, import_utils.placementToMotionAnimationProps)(computedPlacement), [computedPlacement]); const animationProps = shouldAnimate ? { style: { ...contentStyle, ...motionInlineStyles, ...style }, onAnimationComplete: () => setAnimationFinished(true), ...otherMotionProps } : { animate: false, style: { ...contentStyle, ...style } }; const isPositioned = (!shouldAnimate || animationFinished) && x !== null && y !== null; let content = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_framer_motion.motion.div, { className: (0, import_clsx.default)(className, { "is-expanded": isExpanded, "is-positioned": isPositioned, // Use the 'alternate' classname for 'toolbar' variant for back compat. [`is-${computedVariant === "toolbar" ? "alternate" : computedVariant}`]: computedVariant }), ...animationProps, ...contentProps, ref: mergedFloatingRef, ...dialogProps, tabIndex: -1, children: [isExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_scroll_lock.default, {}), isExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "components-popover__header", children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "components-popover__header-title", children: headerTitle }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_button.default, { className: "components-popover__close", size: "small", icon: import_icons.close, onClick: onClose, label: (0, import_i18n.__)("Close") })] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "components-popover__content", children }), hasArrow && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: arrowCallbackRef, className: ["components-popover__arrow", `is-${computedPlacement.split("-")[0]}`].join(" "), style: { left: typeof arrowData?.x !== "undefined" && Number.isFinite(arrowData.x) ? `${arrowData.x}px` : "", top: typeof arrowData?.y !== "undefined" && Number.isFinite(arrowData.y) ? `${arrowData.y}px` : "" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowTriangle, {}) })] }); const shouldRenderWithinSlot = slot.ref && !inline; const hasAnchor = anchorRef || anchorRect || anchor; if (shouldRenderWithinSlot) { content = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_slot_fill.Fill, { name: slotName, children: content }); } else if (!inline) { content = (0, import_element.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_style_provider.StyleProvider, { document, children: content }), getPopoverFallbackContainer()); } if (hasAnchor) { return content; } return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ref: anchorRefFallback }), content] }); }; var PopoverSlot = (0, import_element.forwardRef)(({ name = SLOT_NAME }, ref) => { return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_slot_fill.Slot, { bubblesVirtually: true, name, className: "popover-slot", ref }); }); var Popover = Object.assign((0, import_context.contextConnect)(UnforwardedPopover, "Popover"), { /** * Renders a slot that is used internally by Popover for rendering content. */ Slot: Object.assign(PopoverSlot, { displayName: "Popover.Slot" }), /** * Provides a context to manage popover slot names. * * This is marked as unstable and should not be used directly. */ __unstableSlotNameProvider: Object.assign(slotNameContext.Provider, { displayName: "Popover.__unstableSlotNameProvider" }) }); var popover_default = Popover; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Popover, PopoverSlot, SLOT_NAME }); //# sourceMappingURL=index.js.map