@atlaskit/popup
Version:
A popup displays brief content in an overlay.
147 lines (144 loc) • 4.93 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';
const defaultLayer = 400;
const 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({
xcss,
appearance: inAppearance = 'default',
children,
boundary,
offset,
strategy,
onClose,
testId,
rootBoundary = 'viewport',
shouldFlip = true,
placement = 'auto',
fallbackPlacements,
popupComponent,
autoFocus = true,
zIndex = defaultLayer,
shouldUseCaptureOnOutsideClick = false,
shouldIgnoreCloseEvent,
shouldRenderToParent: inShouldRenderToParent,
shouldDisableFocusLock = false,
shouldFitContainer,
shouldFitViewport,
shouldDisableGpuAcceleration = false,
role,
titleId,
isOpen,
id
}) {
const triggerRef = useContext(TriggerRefContext);
const {
appearance,
shouldRenderToParent
} = usePopupAppearance({
appearance: inAppearance,
shouldRenderToParent: inShouldRenderToParent
});
const handleOpenLayerObserverCloseSignal = useCallback(() => {
onClose === null || onClose === void 0 ? void 0 : onClose(null);
}, [onClose]);
useNotifyOpenLayerObserver({
isOpen,
onClose: handleOpenLayerObserverCloseSignal,
type: 'popup'
});
if (!isOpen) {
return null;
}
const 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();
const isOpen = useContext(IsOpenContext);
const 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
}));
}