UNPKG

@itwin/itwinui-react

Version:

A react component library for iTwinUI

354 lines (353 loc) 10.3 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true, }); function _export(target, all) { for (var name in all) Object.defineProperty(target, name, { enumerable: true, get: all[name], }); } _export(exports, { Popover: function () { return Popover; }, PopoverInitialFocusContext: function () { return PopoverInitialFocusContext; }, PopoverOpenContext: function () { return PopoverOpenContext; }, usePopover: function () { return usePopover; }, }); const _interop_require_default = require('@swc/helpers/_/_interop_require_default'); const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard'); const _react = /*#__PURE__*/ _interop_require_wildcard._(require('react')); const _classnames = /*#__PURE__*/ _interop_require_default._( require('classnames'), ); const _react1 = require('@floating-ui/react'); const _index = require('../../utils/index.js'); const _Portal = require('../../utils/components/Portal.js'); const _ThemeProvider = require('../ThemeProvider/ThemeProvider.js'); const PopoverOpenContext = _react.createContext(void 0); const PopoverInitialFocusContext = _react.createContext(void 0); const usePopover = (options) => { let { placement = 'bottom-start', visible, onVisibleChange, closeOnOutsideClick, autoUpdateOptions, matchWidth, interactions: interactionsProp, role, ...rest } = options; let mergedInteractions = _react.useMemo( () => ({ ...interactionsProp, ...{ click: interactionsProp?.click ?? true, dismiss: interactionsProp?.dismiss ?? true, hover: interactionsProp?.hover ?? false, focus: interactionsProp?.focus ?? false, }, }), [interactionsProp], ); let tree = (0, _react1.useFloatingTree)(); let middleware = _react.useMemo( () => ({ ...options.middleware, flip: options.middleware?.flip ?? true, shift: options.middleware?.shift ?? true, size: options.middleware?.size ?? true, hide: options.middleware?.hide || !_index.isUnitTest, }), [options.middleware], ); let maxHeight = 'boolean' == typeof middleware.size ? '400px' : middleware.size?.maxHeight; let [open, onOpenChange] = (0, _index.useControlledState)( false, visible, onVisibleChange, ); let floating = (0, _react1.useFloating)({ placement, open, onOpenChange, strategy: 'fixed', whileElementsMounted: _react.useMemo( () => open ? (...args) => (0, _react1.autoUpdate)(...args, autoUpdateOptions) : void 0, [autoUpdateOptions, open], ), ...rest, middleware: _react.useMemo( () => [ void 0 !== middleware.offset && (0, _react1.offset)(middleware.offset), middleware.flip && (0, _react1.flip)({ padding: 5, }), middleware.shift && (0, _react1.shift)({ padding: 4, }), (matchWidth || middleware.size) && (0, _react1.size)({ padding: 4, apply: ({ rects, availableHeight }) => { if (middleware.size) setAvailableHeight(Math.round(availableHeight)); if (matchWidth) setReferenceWidth(rects.reference.width); }, }), middleware.autoPlacement && (0, _react1.autoPlacement)({ padding: 4, }), middleware.inline && (0, _react1.inline)(), middleware.hide && (0, _react1.hide)({ padding: 4, }), ].filter(Boolean), [matchWidth, middleware], ), }); let interactions = (0, _react1.useInteractions)([ (0, _react1.useClick)(floating.context, { enabled: !!mergedInteractions.click, ...mergedInteractions.click, }), (0, _react1.useDismiss)(floating.context, { enabled: !!mergedInteractions.dismiss, outsidePress: closeOnOutsideClick, bubbles: null != tree, ...mergedInteractions.dismiss, }), (0, _react1.useHover)(floating.context, { enabled: !!mergedInteractions.hover, delay: 100, handleClose: (0, _react1.safePolygon)({ buffer: 1, blockPointerEvents: true, }), move: false, ...mergedInteractions.hover, }), (0, _react1.useFocus)(floating.context, { enabled: !!mergedInteractions.focus, ...mergedInteractions.focus, }), (0, _react1.useRole)(floating.context, { role: 'dialog', enabled: !!role, }), ]); let [referenceWidth, setReferenceWidth] = _react.useState(); let [availableHeight, setAvailableHeight] = _react.useState(); let getFloatingProps = _react.useCallback( (userProps) => interactions.getFloatingProps({ ...userProps, style: { ...floating.floatingStyles, ...(middleware.size && availableHeight && { maxBlockSize: `min(${availableHeight}px, ${maxHeight})`, }), zIndex: 999, ...(matchWidth && referenceWidth ? { minInlineSize: `${referenceWidth}px`, maxInlineSize: `min(${2 * referenceWidth}px, 90vw)`, } : {}), ...(middleware.hide && floating.middlewareData.hide?.referenceHidden && { visibility: 'hidden', }), ...userProps?.style, }, }), [ interactions, floating.floatingStyles, floating.middlewareData.hide?.referenceHidden, middleware.size, middleware.hide, availableHeight, maxHeight, matchWidth, referenceWidth, ], ); let getReferenceProps = _react.useCallback( (userProps) => interactions.getReferenceProps({ ...userProps, onClick: (0, _index.mergeEventHandlers)(userProps?.onClick, () => { if (!!mergedInteractions.click && visible) onOpenChange(false); }), }), [interactions, mergedInteractions.click, visible, onOpenChange], ); return _react.useMemo( () => ({ open, onOpenChange, getReferenceProps, getFloatingProps, ...floating, }), [open, onOpenChange, getFloatingProps, floating, getReferenceProps], ); }; const Popover = _react.forwardRef((props, forwardedRef) => { let { portal = true, visible, placement = 'bottom-start', onVisibleChange, closeOnOutsideClick = true, middleware, positionReference, className, children, content, applyBackground = false, ...rest } = props; let popover = usePopover({ visible, placement, onVisibleChange, closeOnOutsideClick, role: 'dialog', middleware, transform: false, }); let [popoverElement, setPopoverElement] = _react.useState(null); let popoverRef = (0, _index.useMergedRefs)( popover.refs.setFloating, forwardedRef, setPopoverElement, ); let triggerId = `${(0, _index.useId)()}-trigger`; let hasAriaLabel = !!props['aria-labelledby'] || !!props['aria-label']; (0, _index.useLayoutEffect)(() => { if (!positionReference) return; popover.refs.setPositionReference(positionReference); return () => void popover.refs.setPositionReference(null); }, [popover.refs, positionReference]); let [initialFocus, setInitialFocus] = _react.useState(); let initialFocusContextValue = _react.useMemo( () => ({ setInitialFocus, }), [], ); return _react.createElement( _react.Fragment, null, _react.createElement( PopoverOpenContext.Provider, { value: popover.open, }, (0, _index.cloneElementWithRef)(children, (children) => ({ id: children.props.id || triggerId, ...popover.getReferenceProps(children.props), ref: popover.refs.setReference, })), ), popover.open ? _react.createElement( PopoverInitialFocusContext.Provider, { value: initialFocusContextValue, }, _react.createElement( PopoverPortal, { portal: portal, }, _react.createElement( _ThemeProvider.ThemeProvider, null, _react.createElement( _Portal.PortalContainerContext.Provider, { value: popoverElement, }, _react.createElement(DisplayContents, null), _react.createElement( _react1.FloatingFocusManager, { context: popover.context, modal: false, initialFocus: initialFocus, }, _react.createElement( _index.Box, { className: (0, _classnames.default)( 'iui-popover', { 'iui-popover-surface': applyBackground, }, className, ), 'aria-labelledby': hasAriaLabel ? void 0 : popover.refs.domReference.current?.id, ...popover.getFloatingProps(rest), ref: popoverRef, }, content, ), ), ), ), ), ) : null, ); }); if ('development' === process.env.NODE_ENV) Popover.displayName = 'Popover'; const PopoverPortal = ({ children, portal = true }) => { let portalTo = (0, _Portal.usePortalTo)(portal); return _react.createElement( _react1.FloatingPortal, { key: portalTo?.id, root: portalTo ?? void 0, }, _react.createElement(DisplayContents, null), children, ); }; const DisplayContents = _react.memo(() => _react.createElement( _index.ShadowRoot, { css: ` :host { display: contents; } `, }, _react.createElement('slot', null), ), );