@atlaskit/popup
Version:
A popup displays brief content in an overlay.
154 lines (151 loc) • 6.21 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import React, { useCallback, useContext } from 'react';
import { Layering } from '@atlaskit/layering/layering';
import { useNotifyOpenLayerObserver } from '@atlaskit/layering/use-notify-open-layer-observer';
import { fg } from '@atlaskit/platform-feature-flags/fg';
import Portal from '@atlaskit/portal/portal';
import PopperWrapper from '../popper-wrapper';
import { usePopupAppearance } from '../use-appearance';
import { IdContext } from './id-context';
import { IsOpenContext } from './is-open-context';
import { PopupContentTopLayer } from './popup-content-top-layer';
import { TriggerRefContext } from './trigger-ref-context';
import { useEnsureIsInsidePopup } from './use-ensure-is-inside-popup';
var defaultLayer = 400;
var shouldDisableGpuAccelerationModifiers = [{
name: 'computeStyles',
options: {
gpuAcceleration: false
}
}];
/**
* Legacy (Popper + Portal) implementation of the compositional PopupContent.
*
* Renders when the `platform-dst-top-layer` flag is off. This component owns
* the open layer observer registration, which on the top-layer path is handled
* by the `Popover` primitive inside `PopupContentTopLayer` instead.
*/
function PopupContentLegacy(_ref) {
var xcss = _ref.xcss,
_ref$appearance = _ref.appearance,
inAppearance = _ref$appearance === void 0 ? 'default' : _ref$appearance,
children = _ref.children,
boundary = _ref.boundary,
offset = _ref.offset,
strategy = _ref.strategy,
onClose = _ref.onClose,
testId = _ref.testId,
_ref$rootBoundary = _ref.rootBoundary,
rootBoundary = _ref$rootBoundary === void 0 ? 'viewport' : _ref$rootBoundary,
_ref$shouldFlip = _ref.shouldFlip,
shouldFlip = _ref$shouldFlip === void 0 ? true : _ref$shouldFlip,
_ref$placement = _ref.placement,
placement = _ref$placement === void 0 ? 'auto' : _ref$placement,
fallbackPlacements = _ref.fallbackPlacements,
popupComponent = _ref.popupComponent,
_ref$autoFocus = _ref.autoFocus,
autoFocus = _ref$autoFocus === void 0 ? true : _ref$autoFocus,
_ref$zIndex = _ref.zIndex,
zIndex = _ref$zIndex === void 0 ? defaultLayer : _ref$zIndex,
_ref$shouldUseCapture = _ref.shouldUseCaptureOnOutsideClick,
shouldUseCaptureOnOutsideClick = _ref$shouldUseCapture === void 0 ? false : _ref$shouldUseCapture,
shouldIgnoreCloseEvent = _ref.shouldIgnoreCloseEvent,
inShouldRenderToParent = _ref.shouldRenderToParent,
_ref$shouldDisableFoc = _ref.shouldDisableFocusLock,
shouldDisableFocusLock = _ref$shouldDisableFoc === void 0 ? false : _ref$shouldDisableFoc,
shouldFitContainer = _ref.shouldFitContainer,
shouldFitViewport = _ref.shouldFitViewport,
_ref$shouldDisableGpu = _ref.shouldDisableGpuAcceleration,
shouldDisableGpuAcceleration = _ref$shouldDisableGpu === void 0 ? false : _ref$shouldDisableGpu,
role = _ref.role,
titleId = _ref.titleId,
isOpen = _ref.isOpen,
id = _ref.id;
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,
type: 'popup'
});
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,
shouldIgnoreCloseEvent: shouldIgnoreCloseEvent,
shouldRenderToParent: shouldRenderToParent,
shouldDisableFocusLock: shouldDisableFocusLock,
triggerRef: triggerRef,
strategy: strategy,
shouldFitViewport: shouldFitViewport,
modifiers: shouldDisableGpuAcceleration ? shouldDisableGpuAccelerationModifiers : undefined,
role: role,
titleId: titleId
}));
if (shouldRenderToParent) {
return popperWrapper;
}
return /*#__PURE__*/React.createElement(Portal, {
zIndex: zIndex
}, popperWrapper);
}
/**
* __Popup content__
*
* Popup content is the component that renders the content of the popup.
*
* It must be a child of the Popup component.
*/
export function PopupContent(props) {
useEnsureIsInsidePopup();
var isOpen = useContext(IsOpenContext);
var id = useContext(IdContext);
// Select the rendering implementation at the component boundary rather than
// gating hooks inside a single component. Each implementation owns its own
// hooks, so a runtime feature-flag change swaps component types (a clean
// remount) instead of changing the hook order of a mounted component.
//
// Forwarding the full props onto the chosen implementation is intentional:
// both implementations declare explicit prop types, so the forward is type
// checked rather than an unbounded API.
if (fg('platform-dst-top-layer')) {
// The top-layer Popover registers with the open layer observer itself.
// eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props -- intentional forward to a typed implementation
return /*#__PURE__*/React.createElement(PopupContentTopLayer, _extends({}, props, {
isOpen: isOpen,
id: id
}));
}
// eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props -- intentional forward to a typed implementation
return /*#__PURE__*/React.createElement(PopupContentLegacy, _extends({}, props, {
isOpen: isOpen,
id: id
}));
}