@razorpay/blade
Version:
The Design System that powers Razorpay
199 lines (193 loc) • 9.15 kB
JavaScript
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
import { useFloating, shift, flip, offset, arrow, autoUpdate, useTransitionStyles, useClick, useDismiss, useRole, useInteractions, FloatingPortal, FloatingFocusManager } from '@floating-ui/react';
import React__default from 'react';
import { PopoverContent } from './PopoverContent.js';
import { ARROW_HEIGHT, ARROW_WIDTH } from './constants.js';
import { PopoverContext } from './PopoverContext.js';
import '../BladeProvider/index.js';
import '../Box/BaseBox/index.js';
import '../../utils/metaAttribute/index.js';
import '../../tokens/global/index.js';
import { useControllableState } from '../../utils/useControllable.js';
import { mergeProps } from '../../utils/mergeProps.js';
import '../PopupArrow/index.js';
import { useMergeRefs } from '../../utils/useMergeRefs.js';
import '../../utils/makeAccessible/index.js';
import { useId } from '../../utils/useId.js';
import { getFloatingPlacementParts } from '../../utils/getFloatingPlacementParts.js';
import { componentZIndices } from '../../utils/componentZIndices.js';
import '../../utils/makeAnalyticsAttribute/index.js';
import { jsxs, jsx } from 'react/jsx-runtime';
import useTheme from '../BladeProvider/useTheme.js';
import { size } from '../../tokens/global/size.js';
import { BaseBox } from '../Box/BaseBox/BaseBox.web.js';
import { metaAttribute } from '../../utils/metaAttribute/metaAttribute.web.js';
import { MetaConstants } from '../../utils/metaAttribute/metaConstants.js';
import { makeAccessible } from '../../utils/makeAccessible/makeAccessible.web.js';
import { makeAnalyticsAttribute } from '../../utils/makeAnalyticsAttribute/makeAnalyticsAttribute.js';
import { PopupArrow } from '../PopupArrow/PopupArrow.web.js';
var _excluded = ["content", "title", "titleLeading", "footer", "children", "placement", "onOpenChange", "zIndex", "isOpen", "defaultIsOpen", "initialFocusRef"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var Popover = function Popover(_ref) {
var content = _ref.content,
title = _ref.title,
titleLeading = _ref.titleLeading,
footer = _ref.footer,
children = _ref.children,
_ref$placement = _ref.placement,
placement = _ref$placement === void 0 ? 'top' : _ref$placement,
onOpenChange = _ref.onOpenChange,
_ref$zIndex = _ref.zIndex,
zIndex = _ref$zIndex === void 0 ? componentZIndices.popover : _ref$zIndex,
isOpen = _ref.isOpen,
defaultIsOpen = _ref.defaultIsOpen,
initialFocusRef = _ref.initialFocusRef,
rest = _objectWithoutProperties(_ref, _excluded);
var _useTheme = useTheme(),
theme = _useTheme.theme;
var defaultInitialFocusRef = React__default.useRef(null);
var arrowRef = React__default.useRef(null);
var titleId = useId('popover-title');
var GAP = theme.spacing[2];
var _getFloatingPlacement = getFloatingPlacementParts(placement),
_getFloatingPlacement2 = _slicedToArray(_getFloatingPlacement, 1),
side = _getFloatingPlacement2[0];
var isHorizontal = side === 'left' || side === 'right';
var isOppositeAxis = side === 'right' || side === 'bottom';
var _useControllableState = useControllableState({
value: isOpen,
defaultValue: defaultIsOpen,
onChange: function onChange(isOpen) {
return onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
isOpen: isOpen
});
}
}),
_useControllableState2 = _slicedToArray(_useControllableState, 2),
controllableIsOpen = _useControllableState2[0],
controllableSetIsOpen = _useControllableState2[1];
var _useFloating = useFloating({
open: controllableIsOpen,
onOpenChange: function onOpenChange(isOpen) {
return controllableSetIsOpen(function () {
return isOpen;
});
},
placement: placement,
strategy: 'fixed',
middleware: [shift({
crossAxis: false,
padding: GAP
}), flip({
padding: GAP,
fallbackAxisSideDirection: 'end'
}), offset(GAP + ARROW_HEIGHT), arrow({
element: arrowRef,
padding: isHorizontal ? GAP + ARROW_HEIGHT : ARROW_WIDTH
})],
whileElementsMounted: autoUpdate
}),
refs = _useFloating.refs,
floatingStyles = _useFloating.floatingStyles,
context = _useFloating.context,
computedPlacement = _useFloating.placement;
var close = React__default.useCallback(function () {
controllableSetIsOpen(function () {
return false;
});
}, [controllableSetIsOpen]);
// we need to animate from the offset of the computed placement
// because placement can change dynamically based on available space
var _getFloatingPlacement3 = getFloatingPlacementParts(computedPlacement),
_getFloatingPlacement4 = _slicedToArray(_getFloatingPlacement3, 1),
computedSide = _getFloatingPlacement4[0];
var computedIsHorizontal = computedSide === 'left' || computedSide === 'right';
var animationOffset = isOppositeAxis ? -size[4] : size[4];
var _useTransitionStyles = useTransitionStyles(context, {
duration: theme.motion.duration.quick,
initial: {
opacity: 0,
transform: "translate".concat(computedIsHorizontal ? 'X' : 'Y', "(").concat(animationOffset, "px)")
}
}),
isMounted = _useTransitionStyles.isMounted,
styles = _useTransitionStyles.styles;
// remove click handler if popover is controlled
var isControlled = isOpen !== undefined;
var click = useClick(context, {
enabled: !isControlled
});
var dismiss = useDismiss(context);
var role = useRole(context);
var _useInteractions = useInteractions([click, dismiss, role]),
getReferenceProps = _useInteractions.getReferenceProps,
getFloatingProps = _useInteractions.getFloatingProps;
var triggerRef = React__default.useRef(null);
var mergedRef = useMergeRefs(refs.setReference, triggerRef);
var contextValue = React__default.useMemo(function () {
return {
close: close,
defaultInitialFocusRef: defaultInitialFocusRef,
titleId: titleId
};
}, [close, titleId]);
// Inject aria attributes to trigger
// Doing it this way instead of makeAccessible()
// because with makeAccessible we will need to make sure aria-controls, aria-expanded etc
// are exposed from the trigger component prop, which we cannot ensure
React__default.useLayoutEffect(function () {
if (!triggerRef.current) return;
var props = getReferenceProps();
for (var _i = 0, _Object$keys = Object.keys(props); _i < _Object$keys.length; _i++) {
var key = _Object$keys[_i];
if (key.startsWith('aria-')) {
triggerRef.current.setAttribute(key, props[key]);
}
}
}, [getReferenceProps, triggerRef]);
return /*#__PURE__*/jsxs(PopoverContext.Provider, {
value: contextValue,
children: [/*#__PURE__*/React__default.cloneElement(children, _objectSpread({
ref: mergedRef
}, mergeProps(children.props, getReferenceProps()))), isMounted && /*#__PURE__*/jsx(FloatingPortal, {
children: /*#__PURE__*/jsx(FloatingFocusManager, {
initialFocus: initialFocusRef !== null && initialFocusRef !== void 0 ? initialFocusRef : defaultInitialFocusRef,
context: context,
modal: true,
guards: true,
children: /*#__PURE__*/jsx(BaseBox, _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
ref: refs.setFloating,
style: floatingStyles
// TODO: Tokenize zIndex values
,
zIndex: zIndex
}, getFloatingProps()), metaAttribute({
name: MetaConstants.Popover
})), makeAccessible({
labelledBy: titleId
})), makeAnalyticsAttribute(rest)), {}, {
children: /*#__PURE__*/jsx(PopoverContent, {
title: title,
titleLeading: titleLeading,
footer: footer,
style: styles,
arrow: /*#__PURE__*/jsx(PopupArrow, {
ref: arrowRef,
context: context,
width: ARROW_WIDTH,
height: ARROW_HEIGHT,
fillColor: theme.colors.popup.background.subtle,
strokeColor: theme.colors.popup.border.subtle
}),
children: content
})
}))
})
})]
});
};
export { Popover };
//# sourceMappingURL=Popover.web.js.map