From b31d9325ab3d661ffeae5772d3e3207751b5a9ea Mon Sep 17 00:00:00 2001 From: Richard Schreiber Date: Tue, 31 May 2022 22:39:38 +0200 Subject: [PATCH 1/3] Proxy VueComponent methods on CustomElement --- dist/vue-wc-wrapper.global.js | 477 +++++++++++++++++----------------- dist/vue-wc-wrapper.js | 13 +- src/index.js | 9 + 3 files changed, 265 insertions(+), 234 deletions(-) diff --git a/dist/vue-wc-wrapper.global.js b/dist/vue-wc-wrapper.global.js index 889a242..940ab06 100644 --- a/dist/vue-wc-wrapper.global.js +++ b/dist/vue-wc-wrapper.global.js @@ -1,272 +1,283 @@ var wrapVueWebComponent = (function () { -'use strict'; - -const camelizeRE = /-(\w)/g; -const camelize = str => { - return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '') -}; - -const hyphenateRE = /\B([A-Z])/g; -const hyphenate = str => { - return str.replace(hyphenateRE, '-$1').toLowerCase() -}; - -function getInitialProps (propsList) { - const res = {}; - propsList.forEach(key => { - res[key] = undefined; - }); - return res -} - -function injectHook (options, key, hook) { - options[key] = [].concat(options[key] || []); - options[key].unshift(hook); -} - -function callHooks (vm, hook) { - if (vm) { - const hooks = vm.$options[hook] || []; - hooks.forEach(hook => { - hook.call(vm); + 'use strict'; + + const camelizeRE = /-(\w)/g; + const camelize = str => { + return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '') + }; + + const hyphenateRE = /\B([A-Z])/g; + const hyphenate = str => { + return str.replace(hyphenateRE, '-$1').toLowerCase() + }; + + function getInitialProps (propsList) { + const res = {}; + propsList.forEach(key => { + res[key] = undefined; }); + return res } -} - -function createCustomEvent (name, args) { - return new CustomEvent(name, { - bubbles: false, - cancelable: false, - detail: args - }) -} - -const isBoolean = val => /function Boolean/.test(String(val)); -const isNumber = val => /function Number/.test(String(val)); - -function convertAttributeValue (value, name, { type } = {}) { - if (isBoolean(type)) { - if (value === 'true' || value === 'false') { - return value === 'true' - } - if (value === '' || value === name || value != null) { - return true + + function injectHook (options, key, hook) { + options[key] = [].concat(options[key] || []); + options[key].unshift(hook); + } + + function callHooks (vm, hook) { + if (vm) { + const hooks = vm.$options[hook] || []; + hooks.forEach(hook => { + hook.call(vm); + }); } - return value - } else if (isNumber(type)) { - const parsed = parseFloat(value, 10); - return isNaN(parsed) ? value : parsed - } else { - return value } -} -function toVNodes (h, children) { - const res = []; - for (let i = 0, l = children.length; i < l; i++) { - res.push(toVNode(h, children[i])); + function createCustomEvent (name, args) { + return new CustomEvent(name, { + bubbles: false, + cancelable: false, + detail: args + }) } - return res -} - -function toVNode (h, node) { - if (node.nodeType === 3) { - return node.data.trim() ? node.data : null - } else if (node.nodeType === 1) { - const data = { - attrs: getAttributes(node), - domProps: { - innerHTML: node.innerHTML + + const isBoolean = val => /function Boolean/.test(String(val)); + const isNumber = val => /function Number/.test(String(val)); + + function convertAttributeValue (value, name, { type } = {}) { + if (isBoolean(type)) { + if (value === 'true' || value === 'false') { + return value === 'true' } - }; - if (data.attrs.slot) { - data.slot = data.attrs.slot; - delete data.attrs.slot; + if (value === '' || value === name || value != null) { + return true + } + return value + } else if (isNumber(type)) { + const parsed = parseFloat(value, 10); + return isNaN(parsed) ? value : parsed + } else { + return value } - return h(node.tagName, data) - } else { - return null } -} -function getAttributes (node) { - const res = {}; - for (let i = 0, l = node.attributes.length; i < l; i++) { - const attr = node.attributes[i]; - res[attr.nodeName] = attr.nodeValue; + function toVNodes (h, children) { + const res = []; + for (let i = 0, l = children.length; i < l; i++) { + res.push(toVNode(h, children[i])); + } + return res } - return res -} - -function wrap (Vue, Component) { - const isAsync = typeof Component === 'function' && !Component.cid; - let isInitialized = false; - let hyphenatedPropsList; - let camelizedPropsList; - let camelizedPropsMap; - - function initialize (Component) { - if (isInitialized) return - - const options = typeof Component === 'function' - ? Component.options - : Component; - - // extract props info - const propsList = Array.isArray(options.props) - ? options.props - : Object.keys(options.props || {}); - hyphenatedPropsList = propsList.map(hyphenate); - camelizedPropsList = propsList.map(camelize); - const originalPropsAsObject = Array.isArray(options.props) ? {} : options.props || {}; - camelizedPropsMap = camelizedPropsList.reduce((map, key, i) => { - map[key] = originalPropsAsObject[propsList[i]]; - return map - }, {}); - - // proxy $emit to native DOM events - injectHook(options, 'beforeCreate', function () { - const emit = this.$emit; - this.$emit = (name, ...args) => { - this.$root.$options.customElement.dispatchEvent(createCustomEvent(name, args)); - return emit.call(this, name, ...args) + + function toVNode (h, node) { + if (node.nodeType === 3) { + return node.data.trim() ? node.data : null + } else if (node.nodeType === 1) { + const data = { + attrs: getAttributes(node), + domProps: { + innerHTML: node.innerHTML + } }; - }); + if (data.attrs.slot) { + data.slot = data.attrs.slot; + delete data.attrs.slot; + } + return h(node.tagName, data) + } else { + return null + } + } - injectHook(options, 'created', function () { - // sync default props values to wrapper on created - camelizedPropsList.forEach(key => { - this.$root.props[key] = this[key]; - }); - }); + function getAttributes (node) { + const res = {}; + for (let i = 0, l = node.attributes.length; i < l; i++) { + const attr = node.attributes[i]; + res[attr.nodeName] = attr.nodeValue; + } + return res + } - // proxy props as Element properties - camelizedPropsList.forEach(key => { - Object.defineProperty(CustomElement.prototype, key, { - get () { - return this._wrapper.props[key] - }, - set (newVal) { - this._wrapper.props[key] = newVal; - }, - enumerable: false, - configurable: true - }); - }); + function wrap (Vue, Component) { + const isAsync = typeof Component === 'function' && !Component.cid; + let isInitialized = false; + let hyphenatedPropsList; + let camelizedPropsList; + let camelizedPropsMap; - isInitialized = true; - } + function initialize (Component) { + if (isInitialized) return - function syncAttribute (el, key) { - const camelized = camelize(key); - const value = el.hasAttribute(key) ? el.getAttribute(key) : undefined; - el._wrapper.props[camelized] = convertAttributeValue( - value, - key, - camelizedPropsMap[camelized] - ); - } + const options = typeof Component === 'function' + ? Component.options + : Component; - class CustomElement extends HTMLElement { - constructor () { - const self = super(); - self.attachShadow({ mode: 'open' }); - - const wrapper = self._wrapper = new Vue({ - name: 'shadow-root', - customElement: self, - shadowRoot: self.shadowRoot, - data () { - return { - props: {}, - slotChildren: [] - } - }, - render (h) { - return h(Component, { - ref: 'inner', - props: this.props - }, this.slotChildren) - } + // extract props info + const propsList = Array.isArray(options.props) + ? options.props + : Object.keys(options.props || {}); + hyphenatedPropsList = propsList.map(hyphenate); + camelizedPropsList = propsList.map(camelize); + const originalPropsAsObject = Array.isArray(options.props) ? {} : options.props || {}; + camelizedPropsMap = camelizedPropsList.reduce((map, key, i) => { + map[key] = originalPropsAsObject[propsList[i]]; + return map + }, {}); + + // proxy $emit to native DOM events + injectHook(options, 'beforeCreate', function () { + const emit = this.$emit; + this.$emit = (name, ...args) => { + this.$root.$options.customElement.dispatchEvent(createCustomEvent(name, args)); + return emit.call(this, name, ...args) + }; }); - // Use MutationObserver to react to future attribute & slot content change - const observer = new MutationObserver(mutations => { - let hasChildrenChange = false; - for (let i = 0; i < mutations.length; i++) { - const m = mutations[i]; - if (isInitialized && m.type === 'attributes' && m.target === self) { - syncAttribute(self, m.attributeName); - } else { - hasChildrenChange = true; + injectHook(options, 'created', function () { + // sync default props values to wrapper on created + camelizedPropsList.forEach(key => { + this.$root.props[key] = this[key]; + }); + }); + + // proxy methods as Element methods + Object.keys(options.methods || {}).forEach(key => { + Object.defineProperty(CustomElement.prototype, key, { + value (...args) { + // _wrapper.$refs.inner + return options.methods[key].call(this.vueComponent, ...args) + //return this.vueComponent[key](...args) } - } - if (hasChildrenChange) { - wrapper.slotChildren = Object.freeze(toVNodes( - wrapper.$createElement, - self.childNodes - )); - } + }); }); - observer.observe(self, { - childList: true, - subtree: true, - characterData: true, - attributes: true + + // proxy props as Element properties + camelizedPropsList.forEach(key => { + Object.defineProperty(CustomElement.prototype, key, { + get () { + return this._wrapper.props[key] + }, + set (newVal) { + this._wrapper.props[key] = newVal; + }, + enumerable: false, + configurable: true + }); }); + + isInitialized = true; } - get vueComponent () { - return this._wrapper.$refs.inner + function syncAttribute (el, key) { + const camelized = camelize(key); + const value = el.hasAttribute(key) ? el.getAttribute(key) : undefined; + el._wrapper.props[camelized] = convertAttributeValue( + value, + key, + camelizedPropsMap[camelized] + ); } - connectedCallback () { - const wrapper = this._wrapper; - if (!wrapper._isMounted) { - // initialize attributes - const syncInitialAttributes = () => { - wrapper.props = getInitialProps(camelizedPropsList); - hyphenatedPropsList.forEach(key => { - syncAttribute(this, key); - }); - }; + class CustomElement extends HTMLElement { + constructor () { + const self = super(); + self.attachShadow({ mode: 'open' }); - if (isInitialized) { - syncInitialAttributes(); - } else { - // async & unresolved - Component().then(resolved => { - if (resolved.__esModule || resolved[Symbol.toStringTag] === 'Module') { - resolved = resolved.default; + const wrapper = self._wrapper = new Vue({ + name: 'shadow-root', + customElement: self, + shadowRoot: self.shadowRoot, + data () { + return { + props: {}, + slotChildren: [] } - initialize(resolved); + }, + render (h) { + return h(Component, { + ref: 'inner', + props: this.props + }, this.slotChildren) + } + }); + + // Use MutationObserver to react to future attribute & slot content change + const observer = new MutationObserver(mutations => { + let hasChildrenChange = false; + for (let i = 0; i < mutations.length; i++) { + const m = mutations[i]; + if (isInitialized && m.type === 'attributes' && m.target === self) { + syncAttribute(self, m.attributeName); + } else { + hasChildrenChange = true; + } + } + if (hasChildrenChange) { + wrapper.slotChildren = Object.freeze(toVNodes( + wrapper.$createElement, + self.childNodes + )); + } + }); + observer.observe(self, { + childList: true, + subtree: true, + characterData: true, + attributes: true + }); + } + + get vueComponent () { + return this._wrapper.$refs.inner + } + + connectedCallback () { + const wrapper = this._wrapper; + if (!wrapper._isMounted) { + // initialize attributes + const syncInitialAttributes = () => { + wrapper.props = getInitialProps(camelizedPropsList); + hyphenatedPropsList.forEach(key => { + syncAttribute(this, key); + }); + }; + + if (isInitialized) { syncInitialAttributes(); - }); + } else { + // async & unresolved + Component().then(resolved => { + if (resolved.__esModule || resolved[Symbol.toStringTag] === 'Module') { + resolved = resolved.default; + } + initialize(resolved); + syncInitialAttributes(); + }); + } + // initialize children + wrapper.slotChildren = Object.freeze(toVNodes( + wrapper.$createElement, + this.childNodes + )); + wrapper.$mount(); + this.shadowRoot.appendChild(wrapper.$el); + } else { + callHooks(this.vueComponent, 'activated'); } - // initialize children - wrapper.slotChildren = Object.freeze(toVNodes( - wrapper.$createElement, - this.childNodes - )); - wrapper.$mount(); - this.shadowRoot.appendChild(wrapper.$el); - } else { - callHooks(this.vueComponent, 'activated'); + } + + disconnectedCallback () { + callHooks(this.vueComponent, 'deactivated'); } } - disconnectedCallback () { - callHooks(this.vueComponent, 'deactivated'); + if (!isAsync) { + initialize(Component); } - } - if (!isAsync) { - initialize(Component); + return CustomElement } - return CustomElement -} - -return wrap; + return wrap; -}()); +})(); diff --git a/dist/vue-wc-wrapper.js b/dist/vue-wc-wrapper.js index 721bf1f..668b52c 100644 --- a/dist/vue-wc-wrapper.js +++ b/dist/vue-wc-wrapper.js @@ -137,6 +137,17 @@ function wrap (Vue, Component) { }); }); + // proxy methods as Element methods + Object.keys(options.methods || {}).forEach(key => { + Object.defineProperty(CustomElement.prototype, key, { + value (...args) { + // _wrapper.$refs.inner + return options.methods[key].call(this.vueComponent, ...args) + //return this.vueComponent[key](...args) + } + }); + }); + // proxy props as Element properties camelizedPropsList.forEach(key => { Object.defineProperty(CustomElement.prototype, key, { @@ -264,4 +275,4 @@ function wrap (Vue, Component) { return CustomElement } -export default wrap; +export { wrap as default }; diff --git a/src/index.js b/src/index.js index 4409bd7..80453c3 100644 --- a/src/index.js +++ b/src/index.js @@ -51,6 +51,15 @@ export default function wrap (Vue, Component) { }) }) + // proxy methods as Element methods + Object.keys(options.methods || {}).forEach(key => { + Object.defineProperty(CustomElement.prototype, key, { + value (...args) { + return options.methods[key].call(this.vueComponent, ...args) + } + }) + }) + // proxy props as Element properties camelizedPropsList.forEach(key => { Object.defineProperty(CustomElement.prototype, key, { From b504d53d631e2da2875abaabc94fe31edb89f672 Mon Sep 17 00:00:00 2001 From: Richard Schreiber Date: Tue, 31 May 2022 22:58:41 +0200 Subject: [PATCH 2/3] remove indentation in dist-files --- dist/vue-wc-wrapper.global.js | 484 +++++++++++++++++----------------- dist/vue-wc-wrapper.js | 2 - 2 files changed, 241 insertions(+), 245 deletions(-) diff --git a/dist/vue-wc-wrapper.global.js b/dist/vue-wc-wrapper.global.js index 940ab06..0bf944c 100644 --- a/dist/vue-wc-wrapper.global.js +++ b/dist/vue-wc-wrapper.global.js @@ -1,283 +1,281 @@ var wrapVueWebComponent = (function () { - 'use strict'; - - const camelizeRE = /-(\w)/g; - const camelize = str => { - return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '') - }; - - const hyphenateRE = /\B([A-Z])/g; - const hyphenate = str => { - return str.replace(hyphenateRE, '-$1').toLowerCase() - }; - - function getInitialProps (propsList) { - const res = {}; - propsList.forEach(key => { - res[key] = undefined; +'use strict'; + +const camelizeRE = /-(\w)/g; +const camelize = str => { + return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '') +}; + +const hyphenateRE = /\B([A-Z])/g; +const hyphenate = str => { + return str.replace(hyphenateRE, '-$1').toLowerCase() +}; + +function getInitialProps (propsList) { + const res = {}; + propsList.forEach(key => { + res[key] = undefined; + }); + return res +} + +function injectHook (options, key, hook) { + options[key] = [].concat(options[key] || []); + options[key].unshift(hook); +} + +function callHooks (vm, hook) { + if (vm) { + const hooks = vm.$options[hook] || []; + hooks.forEach(hook => { + hook.call(vm); }); - return res } - - function injectHook (options, key, hook) { - options[key] = [].concat(options[key] || []); - options[key].unshift(hook); - } - - function callHooks (vm, hook) { - if (vm) { - const hooks = vm.$options[hook] || []; - hooks.forEach(hook => { - hook.call(vm); - }); +} + +function createCustomEvent (name, args) { + return new CustomEvent(name, { + bubbles: false, + cancelable: false, + detail: args + }) +} + +const isBoolean = val => /function Boolean/.test(String(val)); +const isNumber = val => /function Number/.test(String(val)); + +function convertAttributeValue (value, name, { type } = {}) { + if (isBoolean(type)) { + if (value === 'true' || value === 'false') { + return value === 'true' } - } - - function createCustomEvent (name, args) { - return new CustomEvent(name, { - bubbles: false, - cancelable: false, - detail: args - }) - } - - const isBoolean = val => /function Boolean/.test(String(val)); - const isNumber = val => /function Number/.test(String(val)); - - function convertAttributeValue (value, name, { type } = {}) { - if (isBoolean(type)) { - if (value === 'true' || value === 'false') { - return value === 'true' - } - if (value === '' || value === name || value != null) { - return true - } - return value - } else if (isNumber(type)) { - const parsed = parseFloat(value, 10); - return isNaN(parsed) ? value : parsed - } else { - return value + if (value === '' || value === name || value != null) { + return true } + return value + } else if (isNumber(type)) { + const parsed = parseFloat(value, 10); + return isNaN(parsed) ? value : parsed + } else { + return value } +} - function toVNodes (h, children) { - const res = []; - for (let i = 0, l = children.length; i < l; i++) { - res.push(toVNode(h, children[i])); - } - return res +function toVNodes (h, children) { + const res = []; + for (let i = 0, l = children.length; i < l; i++) { + res.push(toVNode(h, children[i])); } - - function toVNode (h, node) { - if (node.nodeType === 3) { - return node.data.trim() ? node.data : null - } else if (node.nodeType === 1) { - const data = { - attrs: getAttributes(node), - domProps: { - innerHTML: node.innerHTML - } - }; - if (data.attrs.slot) { - data.slot = data.attrs.slot; - delete data.attrs.slot; + return res +} + +function toVNode (h, node) { + if (node.nodeType === 3) { + return node.data.trim() ? node.data : null + } else if (node.nodeType === 1) { + const data = { + attrs: getAttributes(node), + domProps: { + innerHTML: node.innerHTML } - return h(node.tagName, data) - } else { - return null + }; + if (data.attrs.slot) { + data.slot = data.attrs.slot; + delete data.attrs.slot; } + return h(node.tagName, data) + } else { + return null } +} - function getAttributes (node) { - const res = {}; - for (let i = 0, l = node.attributes.length; i < l; i++) { - const attr = node.attributes[i]; - res[attr.nodeName] = attr.nodeValue; - } - return res +function getAttributes (node) { + const res = {}; + for (let i = 0, l = node.attributes.length; i < l; i++) { + const attr = node.attributes[i]; + res[attr.nodeName] = attr.nodeValue; } + return res +} + +function wrap (Vue, Component) { + const isAsync = typeof Component === 'function' && !Component.cid; + let isInitialized = false; + let hyphenatedPropsList; + let camelizedPropsList; + let camelizedPropsMap; + + function initialize (Component) { + if (isInitialized) return + + const options = typeof Component === 'function' + ? Component.options + : Component; + + // extract props info + const propsList = Array.isArray(options.props) + ? options.props + : Object.keys(options.props || {}); + hyphenatedPropsList = propsList.map(hyphenate); + camelizedPropsList = propsList.map(camelize); + const originalPropsAsObject = Array.isArray(options.props) ? {} : options.props || {}; + camelizedPropsMap = camelizedPropsList.reduce((map, key, i) => { + map[key] = originalPropsAsObject[propsList[i]]; + return map + }, {}); + + // proxy $emit to native DOM events + injectHook(options, 'beforeCreate', function () { + const emit = this.$emit; + this.$emit = (name, ...args) => { + this.$root.$options.customElement.dispatchEvent(createCustomEvent(name, args)); + return emit.call(this, name, ...args) + }; + }); - function wrap (Vue, Component) { - const isAsync = typeof Component === 'function' && !Component.cid; - let isInitialized = false; - let hyphenatedPropsList; - let camelizedPropsList; - let camelizedPropsMap; - - function initialize (Component) { - if (isInitialized) return - - const options = typeof Component === 'function' - ? Component.options - : Component; - - // extract props info - const propsList = Array.isArray(options.props) - ? options.props - : Object.keys(options.props || {}); - hyphenatedPropsList = propsList.map(hyphenate); - camelizedPropsList = propsList.map(camelize); - const originalPropsAsObject = Array.isArray(options.props) ? {} : options.props || {}; - camelizedPropsMap = camelizedPropsList.reduce((map, key, i) => { - map[key] = originalPropsAsObject[propsList[i]]; - return map - }, {}); - - // proxy $emit to native DOM events - injectHook(options, 'beforeCreate', function () { - const emit = this.$emit; - this.$emit = (name, ...args) => { - this.$root.$options.customElement.dispatchEvent(createCustomEvent(name, args)); - return emit.call(this, name, ...args) - }; - }); - - injectHook(options, 'created', function () { - // sync default props values to wrapper on created - camelizedPropsList.forEach(key => { - this.$root.props[key] = this[key]; - }); + injectHook(options, 'created', function () { + // sync default props values to wrapper on created + camelizedPropsList.forEach(key => { + this.$root.props[key] = this[key]; }); + }); - // proxy methods as Element methods - Object.keys(options.methods || {}).forEach(key => { - Object.defineProperty(CustomElement.prototype, key, { - value (...args) { - // _wrapper.$refs.inner - return options.methods[key].call(this.vueComponent, ...args) - //return this.vueComponent[key](...args) - } - }); + // proxy methods as Element methods + Object.keys(options.methods || {}).forEach(key => { + Object.defineProperty(CustomElement.prototype, key, { + value (...args) { + return options.methods[key].call(this.vueComponent, ...args) + } }); + }); - // proxy props as Element properties - camelizedPropsList.forEach(key => { - Object.defineProperty(CustomElement.prototype, key, { - get () { - return this._wrapper.props[key] - }, - set (newVal) { - this._wrapper.props[key] = newVal; - }, - enumerable: false, - configurable: true - }); + // proxy props as Element properties + camelizedPropsList.forEach(key => { + Object.defineProperty(CustomElement.prototype, key, { + get () { + return this._wrapper.props[key] + }, + set (newVal) { + this._wrapper.props[key] = newVal; + }, + enumerable: false, + configurable: true }); + }); - isInitialized = true; - } + isInitialized = true; + } - function syncAttribute (el, key) { - const camelized = camelize(key); - const value = el.hasAttribute(key) ? el.getAttribute(key) : undefined; - el._wrapper.props[camelized] = convertAttributeValue( - value, - key, - camelizedPropsMap[camelized] - ); - } + function syncAttribute (el, key) { + const camelized = camelize(key); + const value = el.hasAttribute(key) ? el.getAttribute(key) : undefined; + el._wrapper.props[camelized] = convertAttributeValue( + value, + key, + camelizedPropsMap[camelized] + ); + } - class CustomElement extends HTMLElement { - constructor () { - const self = super(); - self.attachShadow({ mode: 'open' }); - - const wrapper = self._wrapper = new Vue({ - name: 'shadow-root', - customElement: self, - shadowRoot: self.shadowRoot, - data () { - return { - props: {}, - slotChildren: [] - } - }, - render (h) { - return h(Component, { - ref: 'inner', - props: this.props - }, this.slotChildren) + class CustomElement extends HTMLElement { + constructor () { + const self = super(); + self.attachShadow({ mode: 'open' }); + + const wrapper = self._wrapper = new Vue({ + name: 'shadow-root', + customElement: self, + shadowRoot: self.shadowRoot, + data () { + return { + props: {}, + slotChildren: [] } - }); - - // Use MutationObserver to react to future attribute & slot content change - const observer = new MutationObserver(mutations => { - let hasChildrenChange = false; - for (let i = 0; i < mutations.length; i++) { - const m = mutations[i]; - if (isInitialized && m.type === 'attributes' && m.target === self) { - syncAttribute(self, m.attributeName); - } else { - hasChildrenChange = true; - } - } - if (hasChildrenChange) { - wrapper.slotChildren = Object.freeze(toVNodes( - wrapper.$createElement, - self.childNodes - )); - } - }); - observer.observe(self, { - childList: true, - subtree: true, - characterData: true, - attributes: true - }); - } - - get vueComponent () { - return this._wrapper.$refs.inner - } + }, + render (h) { + return h(Component, { + ref: 'inner', + props: this.props + }, this.slotChildren) + } + }); - connectedCallback () { - const wrapper = this._wrapper; - if (!wrapper._isMounted) { - // initialize attributes - const syncInitialAttributes = () => { - wrapper.props = getInitialProps(camelizedPropsList); - hyphenatedPropsList.forEach(key => { - syncAttribute(this, key); - }); - }; - - if (isInitialized) { - syncInitialAttributes(); + // Use MutationObserver to react to future attribute & slot content change + const observer = new MutationObserver(mutations => { + let hasChildrenChange = false; + for (let i = 0; i < mutations.length; i++) { + const m = mutations[i]; + if (isInitialized && m.type === 'attributes' && m.target === self) { + syncAttribute(self, m.attributeName); } else { - // async & unresolved - Component().then(resolved => { - if (resolved.__esModule || resolved[Symbol.toStringTag] === 'Module') { - resolved = resolved.default; - } - initialize(resolved); - syncInitialAttributes(); - }); + hasChildrenChange = true; } - // initialize children + } + if (hasChildrenChange) { wrapper.slotChildren = Object.freeze(toVNodes( wrapper.$createElement, - this.childNodes + self.childNodes )); - wrapper.$mount(); - this.shadowRoot.appendChild(wrapper.$el); - } else { - callHooks(this.vueComponent, 'activated'); } - } + }); + observer.observe(self, { + childList: true, + subtree: true, + characterData: true, + attributes: true + }); + } + + get vueComponent () { + return this._wrapper.$refs.inner + } + + connectedCallback () { + const wrapper = this._wrapper; + if (!wrapper._isMounted) { + // initialize attributes + const syncInitialAttributes = () => { + wrapper.props = getInitialProps(camelizedPropsList); + hyphenatedPropsList.forEach(key => { + syncAttribute(this, key); + }); + }; - disconnectedCallback () { - callHooks(this.vueComponent, 'deactivated'); + if (isInitialized) { + syncInitialAttributes(); + } else { + // async & unresolved + Component().then(resolved => { + if (resolved.__esModule || resolved[Symbol.toStringTag] === 'Module') { + resolved = resolved.default; + } + initialize(resolved); + syncInitialAttributes(); + }); + } + // initialize children + wrapper.slotChildren = Object.freeze(toVNodes( + wrapper.$createElement, + this.childNodes + )); + wrapper.$mount(); + this.shadowRoot.appendChild(wrapper.$el); + } else { + callHooks(this.vueComponent, 'activated'); } } - if (!isAsync) { - initialize(Component); + disconnectedCallback () { + callHooks(this.vueComponent, 'deactivated'); } + } - return CustomElement + if (!isAsync) { + initialize(Component); } - return wrap; + return CustomElement +} + +return wrap; })(); diff --git a/dist/vue-wc-wrapper.js b/dist/vue-wc-wrapper.js index 668b52c..153b228 100644 --- a/dist/vue-wc-wrapper.js +++ b/dist/vue-wc-wrapper.js @@ -141,9 +141,7 @@ function wrap (Vue, Component) { Object.keys(options.methods || {}).forEach(key => { Object.defineProperty(CustomElement.prototype, key, { value (...args) { - // _wrapper.$refs.inner return options.methods[key].call(this.vueComponent, ...args) - //return this.vueComponent[key](...args) } }); }); From 6decefe3176dc66b6f280f1ceee1322967e525ec Mon Sep 17 00:00:00 2001 From: Richard Schreiber Date: Tue, 31 May 2022 23:00:41 +0200 Subject: [PATCH 3/3] undo unneeded dist-changes --- dist/vue-wc-wrapper.global.js | 2 +- dist/vue-wc-wrapper.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/vue-wc-wrapper.global.js b/dist/vue-wc-wrapper.global.js index 0bf944c..1cb08a2 100644 --- a/dist/vue-wc-wrapper.global.js +++ b/dist/vue-wc-wrapper.global.js @@ -278,4 +278,4 @@ function wrap (Vue, Component) { return wrap; -})(); +}()); diff --git a/dist/vue-wc-wrapper.js b/dist/vue-wc-wrapper.js index 153b228..f2dc229 100644 --- a/dist/vue-wc-wrapper.js +++ b/dist/vue-wc-wrapper.js @@ -273,4 +273,4 @@ function wrap (Vue, Component) { return CustomElement } -export { wrap as default }; +export default wrap; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy