UNPKG

@workday/canvas-kit-react

Version:

The parent module that contains all Workday Canvas Kit React components

159 lines (158 loc) • 7.51 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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Popper = exports.defaultFallbackPlacements = void 0; const React = __importStar(require("react")); const ReactDOM = __importStar(require("react-dom")); const core_1 = require("@popperjs/core"); exports.defaultFallbackPlacements = ['top', 'right', 'bottom', 'left']; const hooks_1 = require("./hooks"); const common_1 = require("@workday/canvas-kit-react/common"); const fallbackPlacements_1 = require("./fallbackPlacements"); /** * A thin wrapper component around the Popper.js positioning engine. For reference: * https://popper.js.org/. `Popper` also automatically works with the {@link PopupStack} system. * `Popper` has no UI and will render any children to the `body` element and position around a * provided `anchorElement`. * * Prefer using {@link PopupPopper Popup.Popper} instead. Use this to make Popups that don't utilize * a PopupModel or any associate popup [hooks](#hooks). * * > **Note:** `Popper` renders any children to a `div` element created by the `PopupStack`. This * > element is not controlled by React, so any extra element props will _not_ be forwarded. The * > `ref` will point to the `div` element created by the `PopupStack`, however. In v4, an extra * > `div` element was rendered and that's where extra props were spread to. In v5+, you can provide * > your own element if you wish. */ exports.Popper = React.forwardRef(({ portal = true, open = true, ...elemProps }, ref) => { if (!open) { return null; } return React.createElement(OpenPopper, { ref: ref, portal: portal, ...elemProps }); }); const getElementFromRefOrElement = (input) => { if (input === null) { return undefined; } else if ('current' in input) { return input.current || undefined; } else { return input; } }; // prevent unnecessary renders if popperOptions are not passed const defaultPopperOptions = {}; // Popper bails early if `open` is false and React hooks cannot be called conditionally, // so we're breaking out the open version into another component. const OpenPopper = React.forwardRef(({ anchorElement, getAnchorClientRect, popperOptions = defaultPopperOptions, placement: popperPlacement = 'bottom', fallbackPlacements = exports.defaultFallbackPlacements, onPlacementChange, children, portal, popperInstanceRef, }, ref) => { const firstRender = React.useRef(true); const { localRef, elementRef } = (0, common_1.useLocalRef)(popperInstanceRef); const [placement, setPlacement] = React.useState(popperPlacement); const stackRef = (0, hooks_1.usePopupStack)(ref, anchorElement); const placementRef = React.useRef(popperPlacement); placementRef.current = placement; const placementModifier = React.useMemo(() => { return { name: 'setPlacement', enabled: true, phase: 'afterWrite', fn({ state }) { setPlacement(state.placement); onPlacementChange === null || onPlacementChange === void 0 ? void 0 : onPlacementChange(state.placement); }, }; }, [setPlacement, onPlacementChange]); // useLayoutEffect prevents flashing of the popup before position is determined React.useLayoutEffect(() => { const anchorEl = getAnchorClientRect ? { getBoundingClientRect: getAnchorClientRect } : getElementFromRefOrElement(anchorElement !== null && anchorElement !== void 0 ? anchorElement : null); if (!anchorEl) { console.warn(`Popper: neither anchorElement or getAnchorClientRect was defined. A valid anchorElement or getAnchorClientRect callback must be provided to render a Popper`); return undefined; } if (stackRef.current) { const instance = (0, core_1.createPopper)(anchorEl, stackRef.current, { placement: popperPlacement, ...popperOptions, modifiers: [ placementModifier, { ...fallbackPlacements_1.fallbackPlacementsModifier, options: { fallbackPlacements, }, }, ...(popperOptions.modifiers || []), ], }); elementRef(instance); // update the ref with the instance return () => { instance === null || instance === void 0 ? void 0 : instance.destroy(); }; } return undefined; // We will maintain our own list of dependencies. We need to separate "create" and "update" // prop dependencies. We do _not_ want to destroy the Popper instance if options or placement // change, only if anchor or target refs change // eslint-disable-next-line react-hooks/exhaustive-deps }, [anchorElement, getAnchorClientRect, stackRef]); React.useLayoutEffect(() => { var _a; // Only update options if this is _not_ the first render if (!firstRender.current) { (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.setOptions({ placement: popperPlacement, ...popperOptions, modifiers: [ placementModifier, { ...fallbackPlacements_1.fallbackPlacementsModifier, options: { fallbackPlacements, }, }, ...(popperOptions.modifiers || []), ], }); } firstRender.current = false; }, [popperOptions, popperPlacement, fallbackPlacements, placementModifier, localRef]); const contents = React.createElement(React.Fragment, null, isRenderProp(children) ? children({ placement }) : children); if (!portal) { return contents; } return ReactDOM.createPortal(contents, stackRef.current); }); // Typescript threw an error about non-callable signatures. Using typeof as a 'function' returns // a type of `Function` which isn't descriptive enough for Typescript. We don't do any detection // against the _type_ of function that gets passed, but we'll assume it is a render prop for now... function isRenderProp(children) { if (typeof children === 'function') { return true; } return false; }