UNPKG

@atlaskit/popup

Version:

A popup displays brief content in an overlay.

196 lines (194 loc) 7.37 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import React, { createContext, useCallback, useContext, useState } from 'react'; import invariant from 'tiny-invariant'; import noop from '@atlaskit/ds-lib/noop'; import { useId } from '@atlaskit/ds-lib/use-id'; import { Layering } from '@atlaskit/layering'; import { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer'; import { Manager, Reference } from '@atlaskit/popper'; import Portal from '@atlaskit/portal'; import PopperWrapper from '../popper-wrapper'; import { usePopupAppearance } from '../use-appearance'; import { useGetMemoizedMergedTriggerRef } from '../use-get-memoized-merged-trigger-ref'; var IsOpenContext = /*#__PURE__*/createContext(false); var IdContext = /*#__PURE__*/createContext(undefined); var TriggerRefContext = /*#__PURE__*/createContext(null); var SetTriggerRefContext = /*#__PURE__*/createContext(noop); var EnsureIsInsidePopupContext = /*#__PURE__*/createContext(false); // Used to ensure popup sub-components are used within a Popup // and provide a useful error message if not. var useEnsureIsInsidePopup = function useEnsureIsInsidePopup() { var context = useContext(EnsureIsInsidePopupContext); invariant(context, 'PopupTrigger and PopupContent components must be used within a Popup'); }; /** * __Popup__ * * Popup is a composable component that provides the context for the trigger and content components. * * Usage example: * ```jsx * <Popup> * <PopupTrigger> * {(props) => ( * <button type="button" {...props}>Click me</button> * )} * </PopupTrigger> * <PopupContent> * {(props) => <div>Hello world</div>} * </PopupContent> * </Popup> * ``` */ export var Popup = function Popup(_ref) { var children = _ref.children, providedId = _ref.id, _ref$isOpen = _ref.isOpen, isOpen = _ref$isOpen === void 0 ? false : _ref$isOpen; var _useState = useState(null), _useState2 = _slicedToArray(_useState, 2), triggerRef = _useState2[0], setTriggerRef = _useState2[1]; var generatedId = useId(); var id = providedId || generatedId; return /*#__PURE__*/React.createElement(EnsureIsInsidePopupContext.Provider, { value: true }, /*#__PURE__*/React.createElement(IdContext.Provider, { value: id }, /*#__PURE__*/React.createElement(TriggerRefContext.Provider, { value: triggerRef }, /*#__PURE__*/React.createElement(SetTriggerRefContext.Provider, { value: setTriggerRef }, /*#__PURE__*/React.createElement(IsOpenContext.Provider, { value: isOpen }, /*#__PURE__*/React.createElement(Manager, null, children)))))); }; /** * __Popup trigger__ * * Popup trigger is the component that renders the trigger for the popup. * * It must be a child of the Popup component. */ export var PopupTrigger = function PopupTrigger(_ref2) { var children = _ref2.children; useEnsureIsInsidePopup(); var isOpen = useContext(IsOpenContext); var id = useContext(IdContext); var setTriggerRef = useContext(SetTriggerRefContext); var getMergedTriggerRef = useGetMemoizedMergedTriggerRef(); return /*#__PURE__*/React.createElement(Reference, null, function (_ref3) { var ref = _ref3.ref; return children({ ref: getMergedTriggerRef(ref, setTriggerRef, isOpen), 'aria-controls': id, 'aria-expanded': isOpen, 'aria-haspopup': true }); }); }; var defaultLayer = 400; /** * Disables popper.js GPU acceleration for this popup. * This means only positioning will be used, without any transforms. * * Performance will be degraded if the popup is expected to move. */ var shouldDisableGpuAccelerationModifiers = [{ name: 'computeStyles', options: { gpuAcceleration: false } }]; /** * __Popup content__ * * Popup content is the component that renders the content of the popup. * * It must be a child of the Popup component. */ export var PopupContent = function PopupContent(_ref4) { var xcss = _ref4.xcss, _ref4$appearance = _ref4.appearance, inAppearance = _ref4$appearance === void 0 ? 'default' : _ref4$appearance, children = _ref4.children, boundary = _ref4.boundary, offset = _ref4.offset, strategy = _ref4.strategy, onClose = _ref4.onClose, testId = _ref4.testId, _ref4$rootBoundary = _ref4.rootBoundary, rootBoundary = _ref4$rootBoundary === void 0 ? 'viewport' : _ref4$rootBoundary, _ref4$shouldFlip = _ref4.shouldFlip, shouldFlip = _ref4$shouldFlip === void 0 ? true : _ref4$shouldFlip, _ref4$placement = _ref4.placement, placement = _ref4$placement === void 0 ? 'auto' : _ref4$placement, fallbackPlacements = _ref4.fallbackPlacements, popupComponent = _ref4.popupComponent, _ref4$autoFocus = _ref4.autoFocus, autoFocus = _ref4$autoFocus === void 0 ? true : _ref4$autoFocus, _ref4$zIndex = _ref4.zIndex, zIndex = _ref4$zIndex === void 0 ? defaultLayer : _ref4$zIndex, _ref4$shouldUseCaptur = _ref4.shouldUseCaptureOnOutsideClick, shouldUseCaptureOnOutsideClick = _ref4$shouldUseCaptur === void 0 ? false : _ref4$shouldUseCaptur, inShouldRenderToParent = _ref4.shouldRenderToParent, _ref4$shouldDisableFo = _ref4.shouldDisableFocusLock, shouldDisableFocusLock = _ref4$shouldDisableFo === void 0 ? false : _ref4$shouldDisableFo, shouldFitContainer = _ref4.shouldFitContainer, shouldFitViewport = _ref4.shouldFitViewport, _ref4$shouldDisableGp = _ref4.shouldDisableGpuAcceleration, shouldDisableGpuAcceleration = _ref4$shouldDisableGp === void 0 ? false : _ref4$shouldDisableGp; useEnsureIsInsidePopup(); var isOpen = useContext(IsOpenContext); var id = useContext(IdContext); var triggerRef = useContext(TriggerRefContext); var _usePopupAppearance = usePopupAppearance({ appearance: inAppearance, shouldRenderToParent: inShouldRenderToParent }), appearance = _usePopupAppearance.appearance, shouldRenderToParent = _usePopupAppearance.shouldRenderToParent; var handleOpenLayerObserverCloseSignal = useCallback(function () { onClose === null || onClose === void 0 || onClose(null); }, [onClose]); useNotifyOpenLayerObserver({ isOpen: isOpen, onClose: handleOpenLayerObserverCloseSignal }); if (!isOpen) { return null; } var popperWrapper = /*#__PURE__*/React.createElement(Layering, { isDisabled: false }, /*#__PURE__*/React.createElement(PopperWrapper, { xcss: xcss, appearance: appearance, content: children, isOpen: isOpen, placement: placement, fallbackPlacements: fallbackPlacements, boundary: boundary, rootBoundary: rootBoundary, shouldFlip: shouldFlip, offset: offset, popupComponent: popupComponent, id: id, testId: testId, onClose: onClose, autoFocus: autoFocus, shouldFitContainer: shouldFitContainer, shouldUseCaptureOnOutsideClick: shouldUseCaptureOnOutsideClick, shouldRenderToParent: shouldRenderToParent, shouldDisableFocusLock: shouldDisableFocusLock, triggerRef: triggerRef, strategy: strategy, shouldFitViewport: shouldFitViewport, modifiers: shouldDisableGpuAcceleration ? shouldDisableGpuAccelerationModifiers : undefined })); if (shouldRenderToParent) { return popperWrapper; } return /*#__PURE__*/React.createElement(Portal, { zIndex: zIndex }, popperWrapper); };