355 lines
10 KiB
JavaScript
355 lines
10 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = void 0;
|
||
|
|
||
|
var _positionable = _interopRequireDefault(require("../positionable"));
|
||
|
|
||
|
var _stackable = _interopRequireDefault(require("../stackable"));
|
||
|
|
||
|
var _activatable = _interopRequireDefault(require("../activatable"));
|
||
|
|
||
|
var _mixins = _interopRequireDefault(require("../../util/mixins"));
|
||
|
|
||
|
var _helpers = require("../../util/helpers");
|
||
|
|
||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
|
||
|
// Mixins
|
||
|
// Utilities
|
||
|
var baseMixins = (0, _mixins.default)(_stackable.default, _positionable.default, _activatable.default);
|
||
|
/* @vue/component */
|
||
|
|
||
|
var _default = baseMixins.extend().extend({
|
||
|
name: 'menuable',
|
||
|
props: {
|
||
|
allowOverflow: Boolean,
|
||
|
light: Boolean,
|
||
|
dark: Boolean,
|
||
|
maxWidth: {
|
||
|
type: [Number, String],
|
||
|
default: 'auto'
|
||
|
},
|
||
|
minWidth: [Number, String],
|
||
|
nudgeBottom: {
|
||
|
type: [Number, String],
|
||
|
default: 0
|
||
|
},
|
||
|
nudgeLeft: {
|
||
|
type: [Number, String],
|
||
|
default: 0
|
||
|
},
|
||
|
nudgeRight: {
|
||
|
type: [Number, String],
|
||
|
default: 0
|
||
|
},
|
||
|
nudgeTop: {
|
||
|
type: [Number, String],
|
||
|
default: 0
|
||
|
},
|
||
|
nudgeWidth: {
|
||
|
type: [Number, String],
|
||
|
default: 0
|
||
|
},
|
||
|
offsetOverflow: Boolean,
|
||
|
openOnClick: Boolean,
|
||
|
positionX: {
|
||
|
type: Number,
|
||
|
default: null
|
||
|
},
|
||
|
positionY: {
|
||
|
type: Number,
|
||
|
default: null
|
||
|
},
|
||
|
zIndex: {
|
||
|
type: [Number, String],
|
||
|
default: null
|
||
|
}
|
||
|
},
|
||
|
data: function data() {
|
||
|
return {
|
||
|
absoluteX: 0,
|
||
|
absoluteY: 0,
|
||
|
activatedBy: null,
|
||
|
activatorFixed: false,
|
||
|
activatorNode: null,
|
||
|
dimensions: {
|
||
|
activator: {
|
||
|
top: 0,
|
||
|
left: 0,
|
||
|
bottom: 0,
|
||
|
right: 0,
|
||
|
width: 0,
|
||
|
height: 0,
|
||
|
offsetTop: 0,
|
||
|
scrollHeight: 0,
|
||
|
offsetLeft: 0
|
||
|
},
|
||
|
content: {
|
||
|
top: 0,
|
||
|
left: 0,
|
||
|
bottom: 0,
|
||
|
right: 0,
|
||
|
width: 0,
|
||
|
height: 0,
|
||
|
offsetTop: 0,
|
||
|
scrollHeight: 0
|
||
|
}
|
||
|
},
|
||
|
hasJustFocused: false,
|
||
|
hasWindow: false,
|
||
|
inputActivator: false,
|
||
|
isContentActive: false,
|
||
|
pageWidth: 0,
|
||
|
pageYOffset: 0,
|
||
|
stackClass: 'v-menu__content--active',
|
||
|
stackMinZIndex: 6
|
||
|
};
|
||
|
},
|
||
|
computed: {
|
||
|
computedLeft: function computedLeft() {
|
||
|
var a = this.dimensions.activator;
|
||
|
var c = this.dimensions.content;
|
||
|
var activatorLeft = (this.attach !== false ? a.offsetLeft : a.left) || 0;
|
||
|
var minWidth = Math.max(a.width, c.width);
|
||
|
var left = 0;
|
||
|
left += this.left ? activatorLeft - (minWidth - a.width) : activatorLeft;
|
||
|
|
||
|
if (this.offsetX) {
|
||
|
var maxWidth = isNaN(Number(this.maxWidth)) ? a.width : Math.min(a.width, Number(this.maxWidth));
|
||
|
left += this.left ? -maxWidth : a.width;
|
||
|
}
|
||
|
|
||
|
if (this.nudgeLeft) left -= parseInt(this.nudgeLeft);
|
||
|
if (this.nudgeRight) left += parseInt(this.nudgeRight);
|
||
|
return left;
|
||
|
},
|
||
|
computedTop: function computedTop() {
|
||
|
var a = this.dimensions.activator;
|
||
|
var c = this.dimensions.content;
|
||
|
var top = 0;
|
||
|
if (this.top) top += a.height - c.height;
|
||
|
if (this.attach !== false) top += a.offsetTop;else top += a.top + this.pageYOffset;
|
||
|
if (this.offsetY) top += this.top ? -a.height : a.height;
|
||
|
if (this.nudgeTop) top -= parseInt(this.nudgeTop);
|
||
|
if (this.nudgeBottom) top += parseInt(this.nudgeBottom);
|
||
|
return top;
|
||
|
},
|
||
|
hasActivator: function hasActivator() {
|
||
|
return !!this.$slots.activator || !!this.$scopedSlots.activator || !!this.activator || !!this.inputActivator;
|
||
|
}
|
||
|
},
|
||
|
watch: {
|
||
|
disabled: function disabled(val) {
|
||
|
val && this.callDeactivate();
|
||
|
},
|
||
|
isActive: function isActive(val) {
|
||
|
if (this.disabled) return;
|
||
|
val ? this.callActivate() : this.callDeactivate();
|
||
|
},
|
||
|
positionX: 'updateDimensions',
|
||
|
positionY: 'updateDimensions'
|
||
|
},
|
||
|
beforeMount: function beforeMount() {
|
||
|
this.hasWindow = typeof window !== 'undefined';
|
||
|
},
|
||
|
methods: {
|
||
|
absolutePosition: function absolutePosition() {
|
||
|
return {
|
||
|
offsetTop: 0,
|
||
|
offsetLeft: 0,
|
||
|
scrollHeight: 0,
|
||
|
top: this.positionY || this.absoluteY,
|
||
|
bottom: this.positionY || this.absoluteY,
|
||
|
left: this.positionX || this.absoluteX,
|
||
|
right: this.positionX || this.absoluteX,
|
||
|
height: 0,
|
||
|
width: 0
|
||
|
};
|
||
|
},
|
||
|
activate: function activate() {},
|
||
|
calcLeft: function calcLeft(menuWidth) {
|
||
|
return (0, _helpers.convertToUnit)(this.attach !== false ? this.computedLeft : this.calcXOverflow(this.computedLeft, menuWidth));
|
||
|
},
|
||
|
calcTop: function calcTop() {
|
||
|
return (0, _helpers.convertToUnit)(this.attach !== false ? this.computedTop : this.calcYOverflow(this.computedTop));
|
||
|
},
|
||
|
calcXOverflow: function calcXOverflow(left, menuWidth) {
|
||
|
var xOverflow = left + menuWidth - this.pageWidth + 12;
|
||
|
|
||
|
if ((!this.left || this.right) && xOverflow > 0) {
|
||
|
left = Math.max(left - xOverflow, 0);
|
||
|
} else {
|
||
|
left = Math.max(left, 12);
|
||
|
}
|
||
|
|
||
|
return left + this.getOffsetLeft();
|
||
|
},
|
||
|
calcYOverflow: function calcYOverflow(top) {
|
||
|
var documentHeight = this.getInnerHeight();
|
||
|
var toTop = this.pageYOffset + documentHeight;
|
||
|
var activator = this.dimensions.activator;
|
||
|
var contentHeight = this.dimensions.content.height;
|
||
|
var totalHeight = top + contentHeight;
|
||
|
var isOverflowing = toTop < totalHeight; // If overflowing bottom and offset
|
||
|
// TODO: set 'bottom' position instead of 'top'
|
||
|
|
||
|
if (isOverflowing && this.offsetOverflow && // If we don't have enough room to offset
|
||
|
// the overflow, don't offset
|
||
|
activator.top > contentHeight) {
|
||
|
top = this.pageYOffset + (activator.top - contentHeight); // If overflowing bottom
|
||
|
} else if (isOverflowing && !this.allowOverflow) {
|
||
|
top = toTop - contentHeight - 12; // If overflowing top
|
||
|
} else if (top < this.pageYOffset && !this.allowOverflow) {
|
||
|
top = this.pageYOffset + 12;
|
||
|
}
|
||
|
|
||
|
return top < 12 ? 12 : top;
|
||
|
},
|
||
|
callActivate: function callActivate() {
|
||
|
if (!this.hasWindow) return;
|
||
|
this.activate();
|
||
|
},
|
||
|
callDeactivate: function callDeactivate() {
|
||
|
this.isContentActive = false;
|
||
|
this.deactivate();
|
||
|
},
|
||
|
checkForPageYOffset: function checkForPageYOffset() {
|
||
|
if (this.hasWindow) {
|
||
|
this.pageYOffset = this.activatorFixed ? 0 : this.getOffsetTop();
|
||
|
}
|
||
|
},
|
||
|
checkActivatorFixed: function checkActivatorFixed() {
|
||
|
if (this.attach !== false) return;
|
||
|
var el = this.getActivator();
|
||
|
|
||
|
while (el) {
|
||
|
if (window.getComputedStyle(el).position === 'fixed') {
|
||
|
this.activatorFixed = true;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
el = el.offsetParent;
|
||
|
}
|
||
|
|
||
|
this.activatorFixed = false;
|
||
|
},
|
||
|
deactivate: function deactivate() {},
|
||
|
genActivatorListeners: function genActivatorListeners() {
|
||
|
var _this = this;
|
||
|
|
||
|
var listeners = _activatable.default.options.methods.genActivatorListeners.call(this);
|
||
|
|
||
|
var onClick = listeners.click;
|
||
|
|
||
|
listeners.click = function (e) {
|
||
|
if (_this.openOnClick) {
|
||
|
onClick && onClick(e);
|
||
|
}
|
||
|
|
||
|
_this.absoluteX = e.clientX;
|
||
|
_this.absoluteY = e.clientY;
|
||
|
};
|
||
|
|
||
|
return listeners;
|
||
|
},
|
||
|
getInnerHeight: function getInnerHeight() {
|
||
|
if (!this.hasWindow) return 0;
|
||
|
return window.innerHeight || document.documentElement.clientHeight;
|
||
|
},
|
||
|
getOffsetLeft: function getOffsetLeft() {
|
||
|
if (!this.hasWindow) return 0;
|
||
|
return window.pageXOffset || document.documentElement.scrollLeft;
|
||
|
},
|
||
|
getOffsetTop: function getOffsetTop() {
|
||
|
if (!this.hasWindow) return 0;
|
||
|
return window.pageYOffset || document.documentElement.scrollTop;
|
||
|
},
|
||
|
getRoundedBoundedClientRect: function getRoundedBoundedClientRect(el) {
|
||
|
var rect = el.getBoundingClientRect();
|
||
|
return {
|
||
|
top: Math.round(rect.top),
|
||
|
left: Math.round(rect.left),
|
||
|
bottom: Math.round(rect.bottom),
|
||
|
right: Math.round(rect.right),
|
||
|
width: Math.round(rect.width),
|
||
|
height: Math.round(rect.height)
|
||
|
};
|
||
|
},
|
||
|
measure: function measure(el) {
|
||
|
if (!el || !this.hasWindow) return null;
|
||
|
var rect = this.getRoundedBoundedClientRect(el); // Account for activator margin
|
||
|
|
||
|
if (this.attach !== false) {
|
||
|
var style = window.getComputedStyle(el);
|
||
|
rect.left = parseInt(style.marginLeft);
|
||
|
rect.top = parseInt(style.marginTop);
|
||
|
}
|
||
|
|
||
|
return rect;
|
||
|
},
|
||
|
sneakPeek: function sneakPeek(cb) {
|
||
|
var _this2 = this;
|
||
|
|
||
|
requestAnimationFrame(function () {
|
||
|
var el = _this2.$refs.content;
|
||
|
|
||
|
if (!el || el.style.display !== 'none') {
|
||
|
cb();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
el.style.display = 'inline-block';
|
||
|
cb();
|
||
|
el.style.display = 'none';
|
||
|
});
|
||
|
},
|
||
|
startTransition: function startTransition() {
|
||
|
var _this3 = this;
|
||
|
|
||
|
return new Promise(function (resolve) {
|
||
|
return requestAnimationFrame(function () {
|
||
|
_this3.isContentActive = _this3.hasJustFocused = _this3.isActive;
|
||
|
resolve();
|
||
|
});
|
||
|
});
|
||
|
},
|
||
|
updateDimensions: function updateDimensions() {
|
||
|
var _this4 = this;
|
||
|
|
||
|
this.hasWindow = typeof window !== 'undefined';
|
||
|
this.checkActivatorFixed();
|
||
|
this.checkForPageYOffset();
|
||
|
this.pageWidth = document.documentElement.clientWidth;
|
||
|
var dimensions = {}; // Activator should already be shown
|
||
|
|
||
|
if (!this.hasActivator || this.absolute) {
|
||
|
dimensions.activator = this.absolutePosition();
|
||
|
} else {
|
||
|
var activator = this.getActivator();
|
||
|
if (!activator) return;
|
||
|
dimensions.activator = this.measure(activator);
|
||
|
dimensions.activator.offsetLeft = activator.offsetLeft;
|
||
|
|
||
|
if (this.attach !== false) {
|
||
|
// account for css padding causing things to not line up
|
||
|
// this is mostly for v-autocomplete, hopefully it won't break anything
|
||
|
dimensions.activator.offsetTop = activator.offsetTop;
|
||
|
} else {
|
||
|
dimensions.activator.offsetTop = 0;
|
||
|
}
|
||
|
} // Display and hide to get dimensions
|
||
|
|
||
|
|
||
|
this.sneakPeek(function () {
|
||
|
dimensions.content = _this4.measure(_this4.$refs.content);
|
||
|
_this4.dimensions = dimensions;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
exports.default = _default;
|
||
|
//# sourceMappingURL=index.js.map
|