@varlet/ui
Version:
A Vue3 component library based on Material Design 2 and 3, supporting mobile and desktop.
399 lines (398 loc) • 11 kB
JavaScript
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
};