UNPKG

vue-custom-element

Version:
95 lines (81 loc) 3.86 kB
import registerCustomElement from './utils/registerCustomElement'; import createVueInstance from './utils/createVueInstance'; import { getProps, convertAttributeValue } from './utils/props'; import { camelize } from './utils/helpers'; function install(Vue) { Vue.customElement = function vueCustomElement(tag, componentDefinition, options = {}) { const isAsyncComponent = typeof componentDefinition === 'function'; const optionsProps = isAsyncComponent && { props: options.props || [] }; const props = getProps(isAsyncComponent ? optionsProps : componentDefinition); // register Custom Element const CustomElement = registerCustomElement(tag, { constructorCallback() { typeof options.constructorCallback === 'function' && options.constructorCallback.call(this); }, connectedCallback() { const asyncComponentPromise = isAsyncComponent && componentDefinition(); const isAsyncComponentPromise = asyncComponentPromise && asyncComponentPromise.then && typeof asyncComponentPromise.then === 'function'; typeof options.connectedCallback === 'function' && options.connectedCallback.call(this); if (isAsyncComponent && !isAsyncComponentPromise) { throw new Error(`Async component ${tag} do not returns Promise`); } if (!this.__detached__) { if (isAsyncComponentPromise) { asyncComponentPromise.then((lazyComponent) => { const lazyProps = getProps(lazyComponent); createVueInstance(this, Vue, lazyComponent, lazyProps, options).then(() => { typeof options.vueInstanceCreatedCallback === 'function' && options.vueInstanceCreatedCallback.call(this); }); }); } else { createVueInstance(this, Vue, componentDefinition, props, options).then(() => { typeof options.vueInstanceCreatedCallback === 'function' && options.vueInstanceCreatedCallback.call(this); }); } } this.__detached__ = false; }, /** * When using element in e.g. modal, it's detached and then attached back to document. * It will be unfortunate if we will destroy Vue instance when it happens. * That's why we detect if it's permament using setTimeout */ disconnectedCallback() { this.__detached__ = true; typeof options.disconnectedCallback === 'function' && options.disconnectedCallback.call(this); options.destroyTimeout !== null && setTimeout(() => { if (this.__detached__ && this.__vue_custom_element__) { this.__detached__ = false; this.__vue_custom_element__.$destroy(true); delete this.__vue_custom_element__; delete this.__vue_custom_element_props__; } }, options.destroyTimeout || 3000); }, /** * When attribute changes we should update Vue instance * @param name * @param oldVal * @param value */ attributeChangedCallback(name, oldValue, value) { if (this.__vue_custom_element__ && typeof value !== 'undefined') { const nameCamelCase = camelize(name); typeof options.attributeChangedCallback === 'function' && options.attributeChangedCallback.call(this, name, oldValue, value); const type = this.__vue_custom_element_props__.types[nameCamelCase]; this.__vue_custom_element__[nameCamelCase] = convertAttributeValue(value, type); } }, observedAttributes: props.hyphenate, shadow: !!options.shadow && !!HTMLElement.prototype.attachShadow }); return CustomElement; }; } export default install; if (typeof window !== 'undefined' && window.Vue) { window.Vue.use(install); if (install.installed) { install.installed = false; } }