@arco-design/web-vue
Version:
Arco Design Vue 2.0: A Vue.js 3 UI Library
408 lines (407 loc) • 13.4 kB
JavaScript
import { defineComponent, toRefs, ref, computed, onMounted, onBeforeUnmount, watch, resolveComponent, openBlock, createBlock, withCtx, Teleport, withDirectives, createElementBlock, mergeProps, createVNode, Transition, normalizeClass, vShow, createCommentVNode, createElementVNode, normalizeStyle, renderSlot, createTextVNode, toDisplayString } from "vue";
import { getPrefixCls } from "../_utils/global-config.js";
import ClientOnly from "../_components/client-only.js";
import Button from "../button/index.js";
import IconHover from "../_components/icon-hover.js";
import IconClose from "../icon/icon-close/index.js";
import { useI18n } from "../locale/index.js";
import { useOverflow } from "../_hooks/use-overflow.js";
import { on, off } from "../_utils/dom.js";
import usePopupManager from "../_hooks/use-popup-manager.js";
import { isNumber, isFunction, isPromise, isBoolean } from "../_utils/is.js";
import { KEYBOARD_KEY } from "../_utils/keyboard.js";
import { useTeleportContainer } from "../_hooks/use-teleport-container.js";
import _export_sfc from "../_virtual/plugin-vue_export-helper.js";
const DRAWER_PLACEMENTS = ["top", "right", "bottom", "left"];
const _sfc_main = defineComponent({
name: "Drawer",
components: {
ClientOnly,
ArcoButton: Button,
IconHover,
IconClose
},
inheritAttrs: false,
props: {
visible: {
type: Boolean,
default: false
},
defaultVisible: {
type: Boolean,
default: false
},
placement: {
type: String,
default: "right",
validator: (value) => DRAWER_PLACEMENTS.includes(value)
},
title: String,
mask: {
type: Boolean,
default: true
},
maskClosable: {
type: Boolean,
default: true
},
closable: {
type: Boolean,
default: true
},
okText: String,
cancelText: String,
okLoading: {
type: Boolean,
default: false
},
okButtonProps: {
type: Object
},
cancelButtonProps: {
type: Object
},
unmountOnClose: Boolean,
width: {
type: [Number, String],
default: 250
},
height: {
type: [Number, String],
default: 250
},
popupContainer: {
type: [String, Object],
default: "body"
},
drawerStyle: {
type: Object
},
bodyClass: {
type: [String, Array]
},
bodyStyle: {
type: [String, Object, Array]
},
onBeforeOk: {
type: Function
},
onBeforeCancel: {
type: Function
},
escToClose: {
type: Boolean,
default: true
},
renderToBody: {
type: Boolean,
default: true
},
header: {
type: Boolean,
default: true
},
footer: {
type: Boolean,
default: true
},
hideCancel: {
type: Boolean,
default: false
}
},
emits: {
"update:visible": (visible) => true,
"ok": (e) => true,
"cancel": (e) => true,
"open": () => true,
"close": () => true,
"beforeOpen": () => true,
"beforeClose": () => true
},
setup(props, { emit }) {
const { popupContainer } = toRefs(props);
const prefixCls = getPrefixCls("drawer");
const { t } = useI18n();
const _visible = ref(props.defaultVisible);
const computedVisible = computed(() => {
var _a;
return (_a = props.visible) != null ? _a : _visible.value;
});
const _okLoading = ref(false);
const mergedOkLoading = computed(() => props.okLoading || _okLoading.value);
const { teleportContainer, containerRef } = useTeleportContainer({
popupContainer,
visible: computedVisible
});
const mounted = ref(computedVisible.value);
let globalKeyDownListener = false;
const handleGlobalKeyDown = (ev) => {
if (props.escToClose && ev.key === KEYBOARD_KEY.ESC && isLastDialog()) {
handleCancel(ev);
}
};
const addGlobalKeyDownListener = () => {
if (props.escToClose && !globalKeyDownListener) {
globalKeyDownListener = true;
on(document.documentElement, "keydown", handleGlobalKeyDown);
}
};
const removeGlobalKeyDownListener = () => {
if (globalKeyDownListener) {
globalKeyDownListener = false;
off(document.documentElement, "keydown", handleGlobalKeyDown);
}
};
const { zIndex, isLastDialog } = usePopupManager("dialog", {
visible: computedVisible
});
const isFixed = computed(() => {
return (containerRef == null ? void 0 : containerRef.value) === document.body;
});
let promiseNumber = 0;
const close = () => {
promiseNumber++;
if (_okLoading.value) {
_okLoading.value = false;
}
_visible.value = false;
emit("update:visible", false);
};
const handleOk = async (e) => {
const currentPromiseNumber = promiseNumber;
const closed = await new Promise(
async (resolve) => {
var _a;
if (isFunction(props.onBeforeOk)) {
let result = props.onBeforeOk((closed2 = true) => resolve(closed2));
if (isPromise(result) || !isBoolean(result)) {
_okLoading.value = true;
}
if (isPromise(result)) {
try {
result = (_a = await result) != null ? _a : true;
} catch (error) {
result = false;
throw error;
}
}
if (isBoolean(result)) {
resolve(result);
}
} else {
resolve(true);
}
}
);
if (currentPromiseNumber === promiseNumber) {
if (closed) {
emit("ok", e);
close();
} else if (_okLoading.value) {
_okLoading.value = false;
}
}
};
const handleCancel = (e) => {
var _a;
let result = true;
if (isFunction(props.onBeforeCancel)) {
result = (_a = props.onBeforeCancel()) != null ? _a : false;
}
if (result) {
emit("cancel", e);
close();
}
};
const handleMask = (e) => {
if (props.maskClosable) {
handleCancel(e);
}
};
const handleOpen = () => {
if (computedVisible.value) {
emit("open");
}
};
const handleClose = () => {
if (!computedVisible.value) {
mounted.value = false;
resetOverflow();
emit("close");
}
};
const { setOverflowHidden, resetOverflow } = useOverflow(containerRef);
onMounted(() => {
if (computedVisible.value) {
mounted.value = true;
setOverflowHidden();
addGlobalKeyDownListener();
}
});
onBeforeUnmount(() => {
resetOverflow();
removeGlobalKeyDownListener();
});
watch(computedVisible, (visible) => {
if (_visible.value !== visible) {
_visible.value = visible;
}
if (visible) {
emit("beforeOpen");
mounted.value = true;
setOverflowHidden();
addGlobalKeyDownListener();
} else {
emit("beforeClose");
removeGlobalKeyDownListener();
}
});
const style = computed(() => {
var _a;
const style2 = {
[props.placement]: 0,
...(_a = props.drawerStyle) != null ? _a : {}
};
if (["right", "left"].includes(props.placement)) {
style2.width = isNumber(props.width) ? `${props.width}px` : props.width;
} else {
style2.height = isNumber(props.height) ? `${props.height}px` : props.height;
}
return style2;
});
return {
prefixCls,
style,
t,
mounted,
computedVisible,
mergedOkLoading,
zIndex,
handleOk,
handleCancel,
handleOpen,
handleClose,
handleMask,
isFixed,
teleportContainer
};
}
});
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_icon_close = resolveComponent("icon-close");
const _component_icon_hover = resolveComponent("icon-hover");
const _component_arco_button = resolveComponent("arco-button");
const _component_client_only = resolveComponent("client-only");
return openBlock(), createBlock(_component_client_only, null, {
default: withCtx(() => [
(openBlock(), createBlock(Teleport, {
to: _ctx.teleportContainer,
disabled: !_ctx.renderToBody
}, [
!_ctx.unmountOnClose || _ctx.computedVisible || _ctx.mounted ? withDirectives((openBlock(), createElementBlock("div", mergeProps({
key: 0,
class: `${_ctx.prefixCls}-container`,
style: _ctx.isFixed ? { zIndex: _ctx.zIndex } : { zIndex: "inherit", position: "absolute" }
}, _ctx.$attrs), [
createVNode(Transition, {
name: "fade-drawer",
appear: ""
}, {
default: withCtx(() => [
_ctx.mask ? withDirectives((openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(`${_ctx.prefixCls}-mask`),
onClick: _cache[0] || (_cache[0] = (...args) => _ctx.handleMask && _ctx.handleMask(...args))
}, null, 2)), [
[vShow, _ctx.computedVisible]
]) : createCommentVNode("v-if", true)
]),
_: 1
}),
createVNode(Transition, {
name: `slide-${_ctx.placement}-drawer`,
appear: "",
onAfterEnter: _ctx.handleOpen,
onAfterLeave: _ctx.handleClose,
persisted: ""
}, {
default: withCtx(() => [
withDirectives(createElementVNode("div", {
class: normalizeClass(_ctx.prefixCls),
style: normalizeStyle(_ctx.style)
}, [
_ctx.header ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(`${_ctx.prefixCls}-header`)
}, [
renderSlot(_ctx.$slots, "header", {}, () => [
_ctx.$slots.title || _ctx.title ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(`${_ctx.prefixCls}-title`)
}, [
renderSlot(_ctx.$slots, "title", {}, () => [
createTextVNode(toDisplayString(_ctx.title), 1)
])
], 2)) : createCommentVNode("v-if", true),
_ctx.closable ? (openBlock(), createElementBlock("div", {
key: 1,
tabindex: "-1",
role: "button",
"aria-label": "Close",
class: normalizeClass(`${_ctx.prefixCls}-close-btn`),
onClick: _cache[1] || (_cache[1] = (...args) => _ctx.handleCancel && _ctx.handleCancel(...args))
}, [
createVNode(_component_icon_hover, null, {
default: withCtx(() => [
createVNode(_component_icon_close)
]),
_: 1
})
], 2)) : createCommentVNode("v-if", true)
])
], 2)) : createCommentVNode("v-if", true),
createElementVNode("div", {
class: normalizeClass([`${_ctx.prefixCls}-body`, _ctx.bodyClass]),
style: normalizeStyle(_ctx.bodyStyle)
}, [
renderSlot(_ctx.$slots, "default")
], 6),
_ctx.footer ? (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass(`${_ctx.prefixCls}-footer`)
}, [
renderSlot(_ctx.$slots, "footer", {}, () => [
!_ctx.hideCancel ? (openBlock(), createBlock(_component_arco_button, mergeProps({ key: 0 }, _ctx.cancelButtonProps, { onClick: _ctx.handleCancel }), {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.cancelText || _ctx.t("drawer.cancelText")), 1)
]),
_: 1
}, 16, ["onClick"])) : createCommentVNode("v-if", true),
createVNode(_component_arco_button, mergeProps({
type: "primary",
loading: _ctx.mergedOkLoading
}, _ctx.okButtonProps, { onClick: _ctx.handleOk }), {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.okText || _ctx.t("drawer.okText")), 1)
]),
_: 1
}, 16, ["loading", "onClick"])
])
], 2)) : createCommentVNode("v-if", true)
], 6), [
[vShow, _ctx.computedVisible]
])
]),
_: 3
}, 8, ["name", "onAfterEnter", "onAfterLeave"])
], 16)), [
[vShow, _ctx.computedVisible || _ctx.mounted]
]) : createCommentVNode("v-if", true)
], 8, ["to", "disabled"]))
]),
_: 3
});
}
var _Drawer = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export { _Drawer as default };