|
- // Mixins
- import Delayable from '../delayable';
- import Toggleable from '../toggleable'; // Utilities
-
- import mixins from '../../util/mixins';
- import { getSlot, getSlotType } from '../../util/helpers';
- import { consoleError } from '../../util/console';
- const baseMixins = mixins(Delayable, Toggleable);
- /* @vue/component */
-
- export default baseMixins.extend({
- name: 'activatable',
- props: {
- activator: {
- default: null,
- validator: val => {
- return ['string', 'object'].includes(typeof val);
- }
- },
- disabled: Boolean,
- internalActivator: Boolean,
- openOnHover: Boolean
- },
- data: () => ({
- // Do not use this directly, call getActivator() instead
- activatorElement: null,
- activatorNode: [],
- events: ['click', 'mouseenter', 'mouseleave'],
- listeners: {}
- }),
- watch: {
- activator: 'resetActivator',
- openOnHover: 'resetActivator'
- },
-
- mounted() {
- const slotType = getSlotType(this, 'activator', true);
-
- if (slotType && ['v-slot', 'normal'].includes(slotType)) {
- consoleError(`The activator slot must be bound, try '<template v-slot:activator="{ on }"><v-btn v-on="on">'`, this);
- }
-
- this.addActivatorEvents();
- },
-
- beforeDestroy() {
- this.removeActivatorEvents();
- },
-
- methods: {
- addActivatorEvents() {
- if (!this.activator || this.disabled || !this.getActivator()) return;
- this.listeners = this.genActivatorListeners();
- const keys = Object.keys(this.listeners);
-
- for (const key of keys) {
- this.getActivator().addEventListener(key, this.listeners[key]);
- }
- },
-
- genActivator() {
- const node = getSlot(this, 'activator', Object.assign(this.getValueProxy(), {
- on: this.genActivatorListeners(),
- attrs: this.genActivatorAttributes()
- })) || [];
- this.activatorNode = node;
- return node;
- },
-
- genActivatorAttributes() {
- return {
- role: 'button',
- 'aria-haspopup': true,
- 'aria-expanded': String(this.isActive)
- };
- },
-
- genActivatorListeners() {
- if (this.disabled) return {};
- const listeners = {};
-
- if (this.openOnHover) {
- listeners.mouseenter = e => {
- this.getActivator(e);
- this.runDelay('open');
- };
-
- listeners.mouseleave = e => {
- this.getActivator(e);
- this.runDelay('close');
- };
- } else {
- listeners.click = e => {
- const activator = this.getActivator(e);
- if (activator) activator.focus();
- e.stopPropagation();
- this.isActive = !this.isActive;
- };
- }
-
- return listeners;
- },
-
- getActivator(e) {
- // If we've already fetched the activator, re-use
- if (this.activatorElement) return this.activatorElement;
- let activator = null;
-
- if (this.activator) {
- const target = this.internalActivator ? this.$el : document;
-
- if (typeof this.activator === 'string') {
- // Selector
- activator = target.querySelector(this.activator);
- } else if (this.activator.$el) {
- // Component (ref)
- activator = this.activator.$el;
- } else {
- // HTMLElement | Element
- activator = this.activator;
- }
- } else if (this.activatorNode.length === 1 || this.activatorNode.length && !e) {
- // Use the contents of the activator slot
- // There's either only one element in it or we
- // don't have a click event to use as a last resort
- const vm = this.activatorNode[0].componentInstance;
-
- if (vm && vm.$options.mixins && // Activatable is indirectly used via Menuable
- vm.$options.mixins.some(m => m.options && ['activatable', 'menuable'].includes(m.options.name))) {
- // Activator is actually another activatible component, use its activator (#8846)
- activator = vm.getActivator();
- } else {
- activator = this.activatorNode[0].elm;
- }
- } else if (e) {
- // Activated by a click event
- activator = e.currentTarget || e.target;
- }
-
- this.activatorElement = activator;
- return this.activatorElement;
- },
-
- getContentSlot() {
- return getSlot(this, 'default', this.getValueProxy(), true);
- },
-
- getValueProxy() {
- const self = this;
- return {
- get value() {
- return self.isActive;
- },
-
- set value(isActive) {
- self.isActive = isActive;
- }
-
- };
- },
-
- removeActivatorEvents() {
- if (!this.activator || !this.activatorElement) return;
- const keys = Object.keys(this.listeners);
-
- for (const key of keys) {
- this.activatorElement.removeEventListener(key, this.listeners[key]);
- }
-
- this.listeners = {};
- },
-
- resetActivator() {
- this.removeActivatorEvents();
- this.activatorElement = null;
- this.getActivator();
- this.addActivatorEvents();
- }
-
- }
- });
- //# sourceMappingURL=index.js.map
|