UNPKG

@varlet/ui

Version:

A Vue3 component library based on Material Design 2 and 3, supporting mobile and desktop.

399 lines (398 loc) • 11 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; import { onMounted, onUnmounted, ref, watch } from "vue"; import computeStyles from "@popperjs/core/lib/modifiers/computeStyles.js"; import flip from "@popperjs/core/lib/modifiers/flip.js"; import offset from "@popperjs/core/lib/modifiers/offset.js"; import { createPopper } from "@popperjs/core/lib/popper-lite.js"; import { call, doubleRaf, getStyle, isString, preventDefault } from "@varlet/shared"; import { onWindowResize, useEventListener, useVModel } from "@varlet/use"; import { useStack } from "../context/stack.mjs"; import { useZIndex } from "../context/zIndex.mjs"; import { toPxNum } from "../utils/elements.mjs"; function usePopover(options) { const host = ref(null); const popover = ref(null); const referenceSize = ref({ width: 0, height: 0 }); const show = useVModel(options, "show", { passive: true, defaultValue: false, emit(_event, value) { if (value) { call(options.onOpen); } else { call(options.onClose); } } }); const { zIndex } = useZIndex(() => show.value, 1); useStack(() => show.value, zIndex); let popoverInstance = null; let reference = void 0; let enterPopover = false; let enterReference = false; let allowClose = true; useEventListener(() => window, "keydown", handleKeydown); watch(() => [options.offsetX, options.offsetY, options.placement, options.strategy], resize); watch(() => options.disabled, close); watch( () => show.value, (newValue) => { if (newValue) { resize(); } } ); onWindowResize(resize); onMounted(createPopperInstance); onUnmounted(destroyPopperInstance); function createPopperInstance() { const reference2 = getReference(); popoverInstance = createPopper(reference2, popover.value, getPopperOptions()); reference2.addEventListener("mouseenter", handleReferenceMouseenter); reference2.addEventListener("mouseleave", handleReferenceMouseleave); reference2.addEventListener("click", handleReferenceClick); document.addEventListener("click", handleClickOutside); } function destroyPopperInstance() { const reference2 = getReference(); if (reference2) { reference2.removeEventListener("mouseenter", handleReferenceMouseenter); reference2.removeEventListener("mouseleave", handleReferenceMouseleave); reference2.removeEventListener("click", handleReferenceClick); } popoverInstance.destroy(); document.removeEventListener("click", handleClickOutside); } function computeReferenceSize() { const reference2 = getReference(); if (!reference2) { return; } const { width, height } = getStyle(reference2); referenceSize.value = { width: toPxNum(width), height: toPxNum(height) }; } function getTransformOrigin() { switch (options.placement) { case "top": case "cover-bottom": return "bottom"; case "top-start": case "right-end": case "cover-bottom-start": return "bottom left"; case "top-end": case "left-end": case "cover-bottom-end": return "bottom right"; case "bottom": case "cover-top": return "top"; case "bottom-start": case "right-start": case "cover-top-start": return "top left"; case "bottom-end": case "left-start": case "cover-top-end": return "top right"; case "left": case "cover-right": return "right"; case "right": case "cover-left": return "left"; } } function handleReferenceMouseenter() { if (options.trigger !== "hover") { return; } enterReference = true; open(); } function handleReferenceMouseleave() { return __async(this, null, function* () { if (options.trigger !== "hover") { return; } enterReference = false; yield doubleRaf(); if (enterPopover) { return; } close(); }); } function handlePopoverMouseenter() { if (options.trigger !== "hover") { return; } enterPopover = true; if (options.cascadeOptimization) { allowClose = false; } } function handlePopoverMouseleave() { return __async(this, null, function* () { if (options.trigger !== "hover") { return; } enterPopover = false; yield doubleRaf(); if (enterReference) { return; } close(); }); } function handleReferenceClick() { if (options.trigger !== "click") { return; } if (options.closeOnClickReference && show.value) { close(); return; } open(); } function handleClickOutside(e) { const reference2 = getReference(); if (reference2 && !reference2.contains(e.target)) { if (options.trigger !== "click") { return; } handlePopoverClose(); call(options.onClickOutside, e); } } function handlePopoverClose() { close(); } function handleClosed() { resize(); call(options.onClosed); } function getPosition() { const { offsetX, offsetY, placement } = options; computeReferenceSize(); const offset2 = { x: toPxNum(offsetX), y: toPxNum(offsetY) }; switch (placement) { case "cover-top": return { placement: "bottom", skidding: offset2.x, distance: offset2.y - referenceSize.value.height }; case "cover-top-start": return { placement: "bottom-start", skidding: offset2.x, distance: offset2.y - referenceSize.value.height }; case "cover-top-end": return { placement: "bottom-end", skidding: offset2.x, distance: offset2.y - referenceSize.value.height }; case "cover-bottom": return { placement: "top", skidding: offset2.x, distance: -offset2.y - referenceSize.value.height }; case "cover-bottom-start": return { placement: "top-start", skidding: offset2.x, distance: -offset2.y - referenceSize.value.height }; case "cover-bottom-end": return { placement: "top-end", skidding: offset2.x, distance: -offset2.y - referenceSize.value.height }; case "cover-left": return { placement: "right", skidding: offset2.y, distance: offset2.x - referenceSize.value.width }; case "cover-right": return { placement: "left", skidding: offset2.y, distance: -offset2.x - referenceSize.value.width }; case "left": case "left-start": case "left-end": return { placement, skidding: offset2.y, distance: -offset2.x }; case "top": case "top-start": case "top-end": return { placement, skidding: offset2.x, distance: -offset2.y }; case "bottom": case "bottom-start": case "bottom-end": return { placement, skidding: offset2.x, distance: offset2.y }; case "right": case "right-start": case "right-end": return { placement, skidding: offset2.y, distance: offset2.x }; } } function getPopperOptions() { const { placement, skidding, distance } = getPosition(); const modifiers = [ __spreadProps(__spreadValues({}, flip), { enabled: show.value }), __spreadProps(__spreadValues({}, offset), { options: { offset: [skidding, distance] } }), __spreadProps(__spreadValues({}, computeStyles), { options: { adaptive: false, gpuAcceleration: false }, enabled: show.value }), { name: "applyTransformOrigin", enabled: show.value, phase: "beforeWrite", fn({ state }) { state.styles.popper.transformOrigin = getTransformOrigin(); } } ]; return { placement, modifiers, strategy: options.strategy }; } function getReference() { var _a, _b; const targetReference = (_a = reference != null ? reference : options.reference) != null ? _a : host.value; if (isString(targetReference)) { return (_b = host.value) == null ? void 0 : _b.querySelector(targetReference); } return targetReference; } function setAllowClose(value) { allowClose = value; } function setReference(newReference) { destroyPopperInstance(); reference = newReference; createPopperInstance(); } function handleKeydown(event) { const { closeOnKeyEscape = false } = options; if (event.key === "Escape" && closeOnKeyEscape && show.value) { preventDefault(event); close(); } } function resize() { popoverInstance.setOptions(getPopperOptions()); } function open() { if (options.disabled) { return; } show.value = true; call(options["onUpdate:show"], true); } function close() { if (!allowClose) { return; } show.value = false; call(options["onUpdate:show"], false); } return { show, popover, zIndex, host, referenceSize, handlePopoverClose, handlePopoverMouseenter, handlePopoverMouseleave, handleClosed, setReference, setAllowClose, resize, open, close }; } export { usePopover };