@opensig/opendesign
Version:
<p align="center"><img src="../docs/public/opendesign-logo-light.png"/></p> <h1 align="center">opendesign</h1> <p align="center">一个 Vue 3 组件库</p> <p align="center"><b>皮肤可定制,使用 TypeScript</b></p>
427 lines (426 loc) • 14.6 kB
JavaScript
;
const vue = require("vue");
const types = require("./types.js");
const dom = require("../_utils/dom.js");
const helper = require("../_utils/helper.js");
const is = require("../_utils/is.js");
const popup = require("./popup.js");
const useResizeObserver = require("../hooks/use-resize-observer.js");
const resizeObserver = require("../resize-observer/resize-observer.js");
const useIntersectionObserver = require("../hooks/use-intersection-observer.js");
const useScreen = require("../hooks/use-screen.js");
const childOnly = require("../child-only/child-only.js");
const clientOnly = require("../_components/client-only.js");
const vueUtils = require("../_utils/vue-utils.js");
const zIndex = require("../_utils/z-index.js");
const __default__ = {
inheritAttrs: false
};
const _sfc_main = /* @__PURE__ */ vue.defineComponent({
...__default__,
__name: "OPopup",
props: types.popupProps,
emits: ["update:visible", "change"],
setup(__props, { emit: __emit }) {
const props = __props;
const emits = __emit;
const { isPhonePad } = useScreen.useScreen();
const triggers = vue.computed(() => {
const triggers2 = is.isArray(props.trigger) ? props.trigger : [props.trigger];
if (isPhonePad.value) {
const r = triggers2.filter((item) => ["none", "click-outclick", "click"].includes(item));
return r.length > 0 ? r : ["click"];
}
return triggers2;
});
const visible = vue.ref(false);
const targetElRef = vue.ref(null);
let targetEl = null;
const isTargetInViewport = vue.ref(true);
let wrapperEl = vue.ref(null);
const popupRef = vue.ref(null);
const popStyle = vue.reactive({
"--popup-edge-offset": `${props.edgeOffset}px`
});
const popPosition = vue.ref(props.position);
const wrapOrigin = vue.ref({ left: "0px", top: "0px" });
const wrapStyle = vue.computed(() => ({
transformOrigin: `${wrapOrigin.value.left} ${wrapOrigin.value.top}`
}));
const anchorStyle = vue.reactive({});
const toMount = vue.ref(false);
const isAnimating = vue.ref(false);
let ro = null;
let io = null;
const updateZIndex = (show) => {
if (show) {
popStyle["--popup-z-index"] = zIndex.createTopZIndex();
} else {
zIndex.removeZIndex(popStyle["--popup-z-index"]);
}
};
vue.onMounted(() => {
ro = useResizeObserver.useResizeObserver();
io = useIntersectionObserver.useIntersectionObserver();
visible.value = props.visible;
if (props.visible) {
updateZIndex(props.visible);
}
const { target, wrapper } = vue.toRefs(props);
vueUtils.resolveHtmlElement(target).then((el) => {
if (el) {
bindTargetEvent(el);
}
});
vueUtils.resolveHtmlElement(wrapper).then((el) => {
if (el) {
wrapperEl.value = el;
}
});
});
let triggerListener = [];
const bindTargetEvent = (el) => {
if (!el) {
return;
}
targetEl = el;
if (props.adjustMinWidth) {
popStyle.minWidth = `${targetEl.offsetWidth}px`;
} else if (props.adjustWidth) {
popStyle.width = `${targetEl.offsetWidth}px`;
}
triggerListener = popup.bindTrigger(el, popupRef, triggers.value, {
updateFn: updateVisible,
hoverDelay: props.hoverDelay,
autoHide: props.autoHide
});
if (props.hideWhenTargetInvisible) {
io == null ? void 0 : io.observe(targetEl, onTargetInterscting);
}
};
vue.onUnmounted(() => {
triggerListener.forEach((fn) => {
fn();
});
if (wrapperEl.value) {
ro == null ? void 0 : ro.unobserve(wrapperEl.value, onResize);
}
if (targetEl) {
ro == null ? void 0 : ro.unobserve(targetEl, onResize);
}
});
const updatePopupStyle = () => {
if (props.hideWhenTargetInvisible && !isTargetInViewport.value) {
return;
}
if (!targetEl || !popupRef.value || !wrapperEl.value) {
return;
}
const {
popupStyle: pStyle,
position,
anchorStyle: aStyle
} = popup.calcPopupStyle(popupRef.value, targetEl, props.position, {
adaptive: props.adaptive,
offset: props.offset,
edgeOffset: props.edgeOffset,
anchor: props.anchor
});
wrapOrigin.value = popup.getTransformOrigin(position);
if (pStyle) {
popStyle.top = `${Math.floor(pStyle.top)}px`;
popStyle.left = `${Math.floor(pStyle.left)}px`;
popPosition.value = position;
}
if (aStyle) {
Object.keys(aStyle).forEach((k) => {
const val = aStyle[k];
anchorStyle[k] = `${Math.floor(val)}px`;
});
}
};
let oldIntersecting = null;
const onTargetInterscting = (entry) => {
isTargetInViewport.value = entry.isIntersecting;
if (oldIntersecting !== null && entry.isIntersecting) {
if (visible.value) {
vue.nextTick(() => {
updatePopupStyle();
});
}
}
oldIntersecting = isTargetInViewport.value;
};
const beforeToggle = async (show) => {
let goon = true;
if (show) {
if (is.isFunction(props.beforeShow)) {
goon = await props.beforeShow();
}
} else {
if (is.isFunction(props.beforeHide)) {
goon = await props.beforeHide();
}
}
return goon !== false;
};
vue.watch(
() => props.visible,
async (val) => {
if (visible.value === val) {
return;
}
const goon = await beforeToggle(val);
if (!goon) {
emits("update:visible", visible.value);
return;
}
updateVisible(val);
updateZIndex(val);
if (val) {
vue.nextTick(() => {
updatePopupStyle();
});
}
}
);
let visibleTimer = 0;
const clearVisibleTimer = () => {
if (visibleTimer) {
window.clearTimeout(visibleTimer);
visibleTimer = 0;
}
};
const updateVisible = async (isVisible, delay) => {
if (props.disabled) {
return;
}
const v = isVisible === void 0 ? !visible.value : isVisible;
if (v === visible.value && visibleTimer === 0) {
return;
}
const update = () => {
if (visible.value === v) {
return;
}
visible.value = v;
updateZIndex(v);
emits("update:visible", v);
emits("change", v);
if (v) {
toMount.value = true;
if (props.hideWhenTargetInvisible && targetEl) {
io == null ? void 0 : io.observe(targetEl, onTargetInterscting);
}
}
};
const goon = await beforeToggle(v);
if (!goon) {
return;
}
if (delay) {
clearVisibleTimer();
visibleTimer = window.setTimeout(update, delay);
} else {
update();
}
};
vue.watch(targetElRef, (elRef) => {
if (dom.isHtmlElement(elRef == null ? void 0 : elRef.$el)) {
bindTargetEvent(elRef == null ? void 0 : elRef.$el);
}
});
const onResize = (_en, isFirst) => {
if (visible.value && !isFirst) {
updatePopupStyle();
}
};
const onPopupResize = helper.debounce((en) => {
onResize(en, false);
}, 100);
const handleTransitionStart = () => {
isAnimating.value = true;
};
const handleTransitionEnd = () => {
isAnimating.value = false;
if (!visible.value && props.unmountOnHide) {
toMount.value = false;
}
};
const scrollListener = helper.throttleRAF(() => {
if (visible.value) {
updatePopupStyle();
}
});
const listenScroll = (el) => {
el.addEventListener("scroll", scrollListener, { passive: true });
return () => {
el.removeEventListener("scroll", scrollListener);
};
};
vue.watch(popupRef, (popEl) => {
let handles = [];
if (popEl) {
if (targetEl) {
const scrollers = dom.getScrollParents(targetEl);
handles = scrollers.map((el) => {
return listenScroll(el);
});
ro == null ? void 0 : ro.observe(targetEl, (en, isFirst) => {
if (props.adjustMinWidth) {
popStyle.minWidth = `${targetEl == null ? void 0 : targetEl.offsetWidth}px`;
} else if (props.adjustWidth) {
popStyle.width = `${targetEl == null ? void 0 : targetEl.offsetWidth}px`;
}
onResize(en, isFirst);
});
}
if (wrapperEl.value) {
ro == null ? void 0 : ro.observe(wrapperEl.value, onResize);
}
} else {
handles.forEach((hl) => hl());
if (wrapperEl.value) {
ro == null ? void 0 : ro.unobserve(wrapperEl.value, onResize);
}
if (targetEl) {
ro == null ? void 0 : ro.unobserve(targetEl, onResize);
io == null ? void 0 : io.unobserve(targetEl, onTargetInterscting);
isTargetInViewport.value = true;
}
}
});
const onPopupHoverIn = () => {
if (triggers.value.includes("hover")) {
updateVisible(true, props.hoverDelay);
}
};
const onPopupHoverOut = () => {
if (triggers.value.includes("hover") && props.autoHide) {
updateVisible(false, props.hoverDelay);
}
};
const sholdUmMount = vue.computed(() => {
return toMount.value || visible.value || !props.unmountOnHide;
});
return (_ctx, _cache) => {
return vue.openBlock(), vue.createElementBlock(
vue.Fragment,
null,
[
_ctx.$slots.target ? (vue.openBlock(), vue.createBlock(
vue.unref(childOnly),
{
key: 0,
ref_key: "targetElRef",
ref: targetElRef
},
{
default: vue.withCtx(() => [
vue.renderSlot(_ctx.$slots, "target")
]),
_: 3
/* FORWARDED */
},
512
/* NEED_PATCH */
)) : vue.createCommentVNode("v-if", true),
!props.disabled ? (vue.openBlock(), vue.createBlock(vue.unref(clientOnly), { key: 1 }, {
default: vue.withCtx(() => [
(vue.openBlock(), vue.createBlock(vue.Teleport, {
to: props.wrapper,
disabled: !props.wrapper
}, [
vue.createVNode(vue.unref(resizeObserver), { onResize: vue.unref(onPopupResize) }, {
default: vue.withCtx(() => [
sholdUmMount.value ? (vue.openBlock(), vue.createElementBlock(
"div",
vue.mergeProps({
key: 0,
ref_key: "popupRef",
ref: popupRef,
class: ["o-popup", [
`o-popup-pos-${popPosition.value}`,
{
"out-view": props.hideWhenTargetInvisible && !isTargetInViewport.value,
animating: isAnimating.value
}
]],
style: popStyle
}, _ctx.$attrs, {
onMouseenter: onPopupHoverIn,
onMouseleave: onPopupHoverOut
}),
[
vue.createVNode(vue.Transition, {
name: props.transition,
appear: true,
onBeforeEnter: handleTransitionStart,
onAfterEnter: handleTransitionEnd,
onBeforeLeave: handleTransitionStart,
onAfterLeave: handleTransitionEnd,
persisted: ""
}, {
default: vue.withCtx(() => [
vue.withDirectives(vue.createElementVNode(
"div",
{
class: vue.normalizeClass(["o-popup-wrap", props.wrapClass]),
style: vue.normalizeStyle(wrapStyle.value)
},
[
vue.createElementVNode(
"div",
{
class: vue.normalizeClass(["o-popup-body", props.bodyClass])
},
[
vue.renderSlot(_ctx.$slots, "default")
],
2
/* CLASS */
),
props.anchor ? (vue.openBlock(), vue.createElementBlock(
"div",
{
key: 0,
class: vue.normalizeClass(["o-popup-anchor", props.anchorClass]),
style: vue.normalizeStyle(anchorStyle)
},
[
vue.renderSlot(_ctx.$slots, "anchor")
],
6
/* CLASS, STYLE */
)) : vue.createCommentVNode("v-if", true)
],
6
/* CLASS, STYLE */
), [
[vue.vShow, visible.value]
])
]),
_: 3
/* FORWARDED */
}, 8, ["name"])
],
16
/* FULL_PROPS */
)) : vue.createCommentVNode("v-if", true)
]),
_: 3
/* FORWARDED */
}, 8, ["onResize"])
], 8, ["to", "disabled"]))
]),
_: 3
/* FORWARDED */
})) : vue.createCommentVNode("v-if", true)
],
64
/* STABLE_FRAGMENT */
);
};
}
});
module.exports = _sfc_main;