UNPKG

svelte-ux

Version:

- Increment version in `package.json` and commit as `Version bump to x.y.z` - `npm run publish`

62 lines (61 loc) 3.4 kB
import { computePosition, autoUpdate, flip, offset, shift, autoPlacement, size, } from '@floating-ui/dom'; import portal from './portal'; export function popover(node, options) { var _a; const popoverEl = node; const anchorEl = (_a = options === null || options === void 0 ? void 0 : options.anchorEl) !== null && _a !== void 0 ? _a : node.parentElement; const cleanup = autoUpdate(anchorEl, popoverEl, () => { // Only allow autoPlacement to swap sides (ex. top/bottom) and not also axises (ex. left/right). Mathces flip behavor const allowedPlacements = (options === null || options === void 0 ? void 0 : options.autoPlacement) && (options === null || options === void 0 ? void 0 : options.placement) ? [options === null || options === void 0 ? void 0 : options.placement, getOppositePlacement(options === null || options === void 0 ? void 0 : options.placement)] : undefined; const positionOptions = { placement: options === null || options === void 0 ? void 0 : options.placement, middleware: [ offset(options === null || options === void 0 ? void 0 : options.offset), (options === null || options === void 0 ? void 0 : options.autoPlacement) ? autoPlacement({ allowedPlacements }) : flip(), (options === null || options === void 0 ? void 0 : options.resize) && size({ padding: options === null || options === void 0 ? void 0 : options.padding, apply({ availableWidth, availableHeight, elements }) { Object.assign(elements.floating.style, { maxWidth: `${availableWidth}px`, maxHeight: `${availableHeight}px`, }); }, }), shift({ padding: options === null || options === void 0 ? void 0 : options.padding }), ], }; computePosition(anchorEl, popoverEl, positionOptions).then(({ x, y }) => { Object.assign(popoverEl.style, { left: `${x}px`, top: `${y}px`, ...((options === null || options === void 0 ? void 0 : options.matchWidth) && { width: `${anchorEl.offsetWidth}px`, }), }); }); }); function onClickOutside(e) { if (!anchorEl.contains(e.target) && !popoverEl.contains(e.target)) { node.dispatchEvent(new CustomEvent('clickOutside', node)); } } document.addEventListener('click', onClickOutside); const portalResult = portal(node); return { ...portalResult, destroy() { var _a; cleanup(); (_a = portalResult === null || portalResult === void 0 ? void 0 : portalResult.destroy) === null || _a === void 0 ? void 0 : _a.call(portalResult); document.removeEventListener('click', onClickOutside); }, }; } // See: https://github.com/floating-ui/floating-ui/blob/master/packages/core/src/utils/getOppositePlacement.ts (not exported) const hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' }; export function getOppositePlacement(placement) { return placement.replace(/left|right|bottom|top/g, (matched) => hash[matched]); }