element-plus
Version:
A Component Library for Vue3.0
559 lines (546 loc) • 16.9 kB
JavaScript
import { computed, ref, reactive, watch, createVNode, Transition, withCtx, withDirectives, vShow, cloneVNode, openBlock, createBlock, Comment, defineComponent, onMounted, onBeforeUnmount, onActivated, onDeactivated, renderSlot, toDisplayString, Fragment, Teleport } from 'vue';
import throwError from '../utils/error';
import { PatchFlags, getFirstValidNode, renderBlock } from '../utils/vnode';
import { createPopper } from '@popperjs/core';
import { generateId, isBool, isArray, isString, $, isHTMLElement } from '../utils/util';
import PopupManager from '../utils/popup-manager';
import { stop } from '../utils/dom';
import { ClickOutside } from '../directives';
function buildModifier(props, externalModifiers = []) {
const { arrow, arrowOffset, offset, gpuAcceleration, } = props;
const modifiers = [
{
name: 'offset',
options: {
offset: [0, offset !== null && offset !== void 0 ? offset : 12],
},
},
{
name: 'preventOverflow',
options: {
padding: {
top: 2,
bottom: 2,
left: 5,
right: 5,
},
},
},
{
name: 'flip',
options: {
padding: 5,
},
},
{
name: 'computeStyles',
options: {
gpuAcceleration,
adaptive: gpuAcceleration,
},
},
];
if (arrow) {
modifiers.push({
name: 'arrow',
options: {
element: arrow,
padding: arrowOffset !== null && arrowOffset !== void 0 ? arrowOffset : 5,
},
});
}
modifiers.push(...(externalModifiers));
return modifiers;
}
function usePopperOptions(props, state) {
return computed(() => {
var _a;
return Object.assign(Object.assign({ placement: props.placement }, props.popperOptions), { modifiers: buildModifier({
arrow: state.arrow.value,
arrowOffset: props.arrowOffset,
offset: props.offset,
gpuAcceleration: props.gpuAcceleration,
}, (_a = props.popperOptions) === null || _a === void 0 ? void 0 : _a.modifiers) });
});
}
var Effect;
(function (Effect) {
Effect["DARK"] = "dark";
Effect["LIGHT"] = "light";
})(Effect || (Effect = {}));
const DEFAULT_TRIGGER = 'hover';
var defaultProps = {
arrowOffset: {
type: Number,
default: 5,
},
appendToBody: {
type: Boolean,
default: true,
},
autoClose: {
type: Number,
default: 0,
},
boundariesPadding: {
type: Number,
default: 0,
},
content: {
type: String,
default: '',
},
class: {
type: String,
default: '',
},
style: Object,
hideAfter: {
type: Number,
default: 200,
},
cutoff: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
effect: {
type: String,
default: Effect.DARK,
},
enterable: {
type: Boolean,
default: true,
},
manualMode: {
type: Boolean,
default: false,
},
showAfter: {
type: Number,
default: 0,
},
offset: {
type: Number,
default: 12,
},
placement: {
type: String,
default: 'bottom',
},
popperClass: {
type: String,
default: '',
},
pure: {
type: Boolean,
default: false,
},
popperOptions: {
type: Object,
default: () => null,
},
showArrow: {
type: Boolean,
default: true,
},
strategy: {
type: String,
default: 'fixed',
},
transition: {
type: String,
default: 'el-fade-in-linear',
},
trigger: {
type: [String, Array],
default: DEFAULT_TRIGGER,
},
visible: {
type: Boolean,
default: undefined,
},
stopPopperMouseEvent: {
type: Boolean,
default: true,
},
gpuAcceleration: {
type: Boolean,
default: true,
},
};
const UPDATE_VISIBLE_EVENT = 'update:visible';
function usePopper (props, { emit }) {
const arrowRef = ref(null);
const triggerRef = ref(null);
const popperRef = ref(null);
const popperId = `el-popper-${generateId()}`;
let popperInstance = null;
let showTimer = null;
let hideTimer = null;
let triggerFocused = false;
const isManualMode = () => props.manualMode || props.trigger === 'manual';
const popperStyle = ref({ zIndex: PopupManager.nextZIndex() });
const popperOptions = usePopperOptions(props, {
arrow: arrowRef,
});
const state = reactive({
visible: !!props.visible,
});
const visibility = computed({
get() {
if (props.disabled) {
return false;
}
else {
return isBool(props.visible) ? props.visible : state.visible;
}
},
set(val) {
if (isManualMode())
return;
isBool(props.visible)
? emit(UPDATE_VISIBLE_EVENT, val)
: (state.visible = val);
},
});
function _show() {
if (props.autoClose > 0) {
hideTimer = window.setTimeout(() => {
_hide();
}, props.autoClose);
}
visibility.value = true;
}
function _hide() {
visibility.value = false;
}
function clearTimers() {
clearTimeout(showTimer);
clearTimeout(hideTimer);
}
const show = () => {
if (isManualMode() || props.disabled)
return;
clearTimers();
if (props.showAfter === 0) {
_show();
}
else {
showTimer = window.setTimeout(() => {
_show();
}, props.showAfter);
}
};
const hide = () => {
if (isManualMode())
return;
clearTimers();
if (props.hideAfter > 0) {
hideTimer = window.setTimeout(() => {
close();
}, props.hideAfter);
}
else {
close();
}
};
const close = () => {
_hide();
if (props.disabled) {
doDestroy(true);
}
};
function onPopperMouseEnter() {
if (props.enterable && props.trigger !== 'click') {
clearTimeout(hideTimer);
}
}
function onPopperMouseLeave() {
const { trigger } = props;
const shouldPrevent = (isString(trigger) && (trigger === 'click' || trigger === 'focus')) ||
(trigger.length === 1 &&
(trigger[0] === 'click' || trigger[0] === 'focus'));
if (shouldPrevent)
return;
hide();
}
function initializePopper() {
if (!$(visibility)) {
return;
}
const unwrappedTrigger = $(triggerRef);
const _trigger = isHTMLElement(unwrappedTrigger)
? unwrappedTrigger
: unwrappedTrigger.$el;
popperInstance = createPopper(_trigger, $(popperRef), $(popperOptions));
popperInstance.update();
}
function doDestroy(forceDestroy) {
if (!popperInstance || ($(visibility) && !forceDestroy))
return;
detachPopper();
}
function detachPopper() {
var _a;
(_a = popperInstance === null || popperInstance === void 0 ? void 0 : popperInstance.destroy) === null || _a === void 0 ? void 0 : _a.call(popperInstance);
popperInstance = null;
}
const events = {};
function update() {
if (!$(visibility)) {
return;
}
if (popperInstance) {
popperInstance.update();
}
else {
initializePopper();
}
}
function onVisibilityChange(toState) {
if (toState) {
popperStyle.value.zIndex = PopupManager.nextZIndex();
initializePopper();
}
}
if (!isManualMode()) {
const toggleState = () => {
if ($(visibility)) {
hide();
}
else {
show();
}
};
const popperEventsHandler = (e) => {
e.stopPropagation();
switch (e.type) {
case 'click': {
if (triggerFocused) {
triggerFocused = false;
}
else {
toggleState();
}
break;
}
case 'mouseenter': {
show();
break;
}
case 'mouseleave': {
hide();
break;
}
case 'focus': {
triggerFocused = true;
show();
break;
}
case 'blur': {
triggerFocused = false;
hide();
break;
}
}
};
const mapEvents = (t) => {
switch (t) {
case 'click': {
events.onClick = popperEventsHandler;
break;
}
case 'hover': {
events.onMouseEnter = popperEventsHandler;
events.onMouseLeave = popperEventsHandler;
break;
}
case 'focus': {
events.onFocus = popperEventsHandler;
events.onBlur = popperEventsHandler;
break;
}
}
};
if (isArray(props.trigger)) {
Object.values(props.trigger).map(mapEvents);
}
else {
mapEvents(props.trigger);
}
}
watch(popperOptions, val => {
if (!popperInstance)
return;
popperInstance.setOptions(val);
popperInstance.update();
});
watch(visibility, onVisibilityChange);
return {
update,
doDestroy,
show,
hide,
onPopperMouseEnter,
onPopperMouseLeave,
onAfterEnter: () => {
emit('after-enter');
},
onAfterLeave: () => {
detachPopper();
emit('after-leave');
},
onBeforeEnter: () => {
emit('before-enter');
},
onBeforeLeave: () => {
emit('before-leave');
},
initializePopper,
isManualMode,
arrowRef,
events,
popperId,
popperInstance,
popperRef,
popperStyle,
triggerRef,
visibility,
};
}
/**
* Make a map and return a function for checking if a key
* is in that map.
* IMPORTANT: all calls of this function must be prefixed with
* \/\*#\_\_PURE\_\_\*\/
* So that rollup can tree-shake them if necessary.
*/
const EMPTY_OBJ = (process.env.NODE_ENV !== 'production')
? Object.freeze({})
: {};
const EMPTY_ARR = (process.env.NODE_ENV !== 'production') ? Object.freeze([]) : [];
const NOOP = () => { };
function renderPopper(props, children) {
const { effect, name, stopPopperMouseEvent, popperClass, popperStyle, popperRef, pure, popperId, visibility, onMouseEnter, onMouseLeave, onAfterEnter, onAfterLeave, onBeforeEnter, onBeforeLeave, } = props;
const kls = [
popperClass,
'el-popper',
'is-' + effect,
pure ? 'is-pure' : '',
];
const mouseUpAndDown = stopPopperMouseEvent ? stop : NOOP;
return createVNode(Transition, {
name,
'onAfterEnter': onAfterEnter,
'onAfterLeave': onAfterLeave,
'onBeforeEnter': onBeforeEnter,
'onBeforeLeave': onBeforeLeave,
}, {
default: withCtx(() => [withDirectives(createVNode('div', {
'aria-hidden': String(!visibility),
class: kls,
style: popperStyle !== null && popperStyle !== void 0 ? popperStyle : {},
id: popperId,
ref: popperRef !== null && popperRef !== void 0 ? popperRef : 'popperRef',
role: 'tooltip',
onMouseEnter,
onMouseLeave,
onClick: stop,
onMouseDown: mouseUpAndDown,
onMouseUp: mouseUpAndDown,
}, children, PatchFlags.CLASS | PatchFlags.STYLE | PatchFlags.PROPS | PatchFlags.HYDRATE_EVENTS, [
'aria-hidden',
'onMouseenter',
'onMouseleave',
'onMouseDown',
'onMouseUp',
'onClick',
'id',
]), [[vShow, visibility]])]),
}, PatchFlags.PROPS, ['name', 'onAfterEnter', 'onAfterLeave', 'onBeforeEnter', 'onBeforeLeave']);
}
function renderTrigger(trigger, extraProps) {
const firstElement = getFirstValidNode(trigger, 1);
if (!firstElement)
throwError('renderTrigger', 'trigger expects single rooted node');
return cloneVNode(firstElement, extraProps);
}
function renderArrow(showArrow) {
return showArrow
? (openBlock(),
createBlock('div', {
ref: 'arrowRef',
class: 'el-popper__arrow',
'data-popper-arrow': '',
}, null, PatchFlags.NEED_PATCH))
: (openBlock(), createBlock(Comment, null, ''));
}
const compName = 'ElPopper';
const UPDATE_VISIBLE_EVENT$1 = 'update:visible';
var script = defineComponent({
name: compName,
props: defaultProps,
emits: [UPDATE_VISIBLE_EVENT$1, 'after-enter', 'after-leave', 'before-enter', 'before-leave'],
setup(props, ctx) {
if (!ctx.slots.trigger) {
throwError(compName, 'Trigger must be provided');
}
const popperStates = usePopper(props, ctx);
const forceDestroy = () => popperStates.doDestroy(true);
onMounted(popperStates.initializePopper);
onBeforeUnmount(forceDestroy);
onActivated(popperStates.initializePopper);
onDeactivated(forceDestroy);
return popperStates;
},
render() {
var _a;
const { $slots, appendToBody, class: kls, style, effect, hide, onPopperMouseEnter, onPopperMouseLeave, onAfterEnter, onAfterLeave, onBeforeEnter, onBeforeLeave, popperClass, popperId, popperStyle, pure, showArrow, transition, visibility, stopPopperMouseEvent, } = this;
const isManual = this.isManualMode();
const arrow = renderArrow(showArrow);
const popper = renderPopper({
effect,
name: transition,
popperClass,
popperId,
popperStyle,
pure,
stopPopperMouseEvent,
onMouseEnter: onPopperMouseEnter,
onMouseLeave: onPopperMouseLeave,
onAfterEnter,
onAfterLeave,
onBeforeEnter,
onBeforeLeave,
visibility,
}, [
renderSlot($slots, 'default', {}, () => {
return [toDisplayString(this.content)];
}),
arrow,
]);
const _t = (_a = $slots.trigger) === null || _a === void 0 ? void 0 : _a.call($slots);
const triggerProps = Object.assign({ ariaDescribedby: popperId, class: kls, style, ref: 'triggerRef' }, this.events);
const trigger = isManual
? renderTrigger(_t, triggerProps)
: withDirectives(renderTrigger(_t, triggerProps), [[ClickOutside, hide]]);
return renderBlock(Fragment, null, [
trigger,
createVNode(Teleport, {
to: 'body',
disabled: !appendToBody,
}, [popper], PatchFlags.PROPS, ['disabled']),
]);
},
});
script.__file = "packages/popper/src/index.vue";
script.install = (app) => {
app.component(script.name, script);
};
const _Popper = script;
export default _Popper;
export { Effect, defaultProps, renderArrow, renderPopper, renderTrigger, usePopper };