Comparing version 0.7.2 to 0.8.0
## Pre-v1.0.0 changes | ||
[v0.8.0] | ||
- Significant performance improvements for MutationObserver support | ||
[v0.8.0]: https://github.com/rstacruz/remount/compare/v0.7.1...v0.8.0 | ||
[v0.7.1] | ||
@@ -4,0 +10,0 @@ |
@@ -146,3 +146,3 @@ (function (global, factory) { | ||
if (shadow) { | ||
if (shadow && element.attachShadow) { | ||
var mountPoint = document.createElement('span'); | ||
@@ -171,2 +171,18 @@ element.attachShadow({ mode: 'open' }).appendChild(mountPoint); | ||
/** | ||
* Defines a custom element. | ||
* | ||
* @example | ||
* defineElement( | ||
* { component: MyComponent }, | ||
* 'my-div', | ||
* { | ||
* onUpdate: () => {}, | ||
* onUnmount: () => {}, | ||
* } | ||
* ) | ||
* | ||
* @private | ||
*/ | ||
function defineElement$1(elSpec, name, _ref) { | ||
@@ -178,2 +194,3 @@ var onUpdate = _ref.onUpdate, | ||
// Maintain parity with what would happen in Custom Elements mode | ||
if (!isValidName(name)) { | ||
@@ -192,16 +209,4 @@ if (elSpec.quiet) return; | ||
each(mutation.addedNodes, function (node) { | ||
if (node.nodeName.toLowerCase() !== name) return; | ||
onUpdate(node, node); | ||
checkForMount(node, name, onUpdate, onUnmount); | ||
}); | ||
each(mutation.removedNodes, function (node) { | ||
if (node.nodeName.toLowerCase() !== name) return; | ||
onUnmount(node, node); | ||
}); | ||
if (mutation.type === 'attributes') { | ||
var node = mutation.target; | ||
if (node.nodeName.toLowerCase() !== name) return; | ||
onUpdate(node, node); | ||
} | ||
}); | ||
@@ -211,3 +216,2 @@ }); | ||
observer.observe(document.body, { | ||
attributes: true, | ||
childList: true, | ||
@@ -217,6 +221,55 @@ subtree: true | ||
observers[name] = observer; | ||
observers[name] = true; | ||
} | ||
function checkForMount(node, name, onUpdate, onUnmount) { | ||
if (node.nodeName.toLowerCase() === name) { | ||
// It's a match! | ||
onUpdate(node, node); | ||
observeForUpdates(node, onUpdate); | ||
observeForRemoval(node, onUnmount); | ||
} else if (node.children && node.children.length) { | ||
// Recurse down into the other additions | ||
each(node.children, function (subnode) { | ||
checkForMount(subnode, name, onUpdate, onUnmount); | ||
}); | ||
} | ||
} | ||
/** | ||
* Observes for any changes in attributes | ||
*/ | ||
function observeForUpdates(node /*: Element */, onUpdate) { | ||
var observer = new window.MutationObserver(function (mutations) { | ||
each(mutations, function (mutation) { | ||
var node = mutation.target; | ||
onUpdate(node, node); | ||
}); | ||
}); | ||
observer.observe(node, { attributes: true }); | ||
} | ||
/** | ||
* Observes a node's parent to wait until the node is removed | ||
*/ | ||
function observeForRemoval(node /*: Element */, onUnmount) { | ||
var parent = node.parentNode; | ||
var observer = new window.MutationObserver(function (mutations) { | ||
each(mutations, function (mutation) { | ||
each(mutation.removedNodes, function (subnode) { | ||
if (node !== subnode) return; | ||
observer.disconnect(parent); | ||
onUnmount(node, node); | ||
}); | ||
}); | ||
}); | ||
observer.observe(parent, { childList: true, subtree: true }); | ||
} | ||
/** | ||
* Some implementations of MutationObserver don't have .forEach, | ||
@@ -235,3 +288,19 @@ * so we need our own `forEach` shim. This is usually the case with | ||
function isValidName(name) { | ||
/** | ||
* Validate a custom tag. | ||
* | ||
* Since Remount can work with either Custom Elements or MutationObserver API's, | ||
* it'd be wise if we rejected element names that won't work in Custom Elements | ||
* mode (even if we're using MutationObserver mode). | ||
* | ||
* @example | ||
* isValidName('div') // => false | ||
* isValidName('my-div') // => true | ||
* isValidName('123-456') // => false | ||
* isValidName('my-123') // => true | ||
* | ||
* @private | ||
*/ | ||
function isValidName(name /*: string */) /*: boolean */{ | ||
return name.indexOf('-') !== -1 && name.match(/^[a-z][a-z0-9-]*$/); | ||
@@ -273,3 +342,3 @@ } | ||
function unmount(_ /*: any */, mountPoint /*: Element */) { | ||
function unmount(_ /*: ElementSpec */, mountPoint /*: Element */) { | ||
ReactDOM.unmountComponentAtNode(mountPoint); | ||
@@ -290,8 +359,10 @@ } | ||
/* | ||
* Detect what API can be used; die otherwise. | ||
*/ | ||
var Adapter = isSupported() ? ElementsAdapter : isSupported$1() ? MutationAdapter : null; | ||
if (!Adapter) { | ||
throw new Error('Unsupported platform'); | ||
} else { | ||
console.log('Remount: using adapter', Adapter.name); | ||
console.warn("Remount: This browser doesn't support the " + 'MutationObserver API or the Custom Elements API. Including ' + 'polyfills might fix this. Remount elements will not work. ' + 'https://github.com/rstacruz/remount'); | ||
} | ||
@@ -301,8 +372,21 @@ | ||
* Inspect `Remount.adapterName` to see what adapter's being used. | ||
* | ||
* @example | ||
* import * as Remount from 'remount' | ||
* console.log(Remount.adapterName) | ||
*/ | ||
var adapterName = Adapter.name; | ||
var adapterName = Adapter && Adapter.name; | ||
/** | ||
* Registers elements. | ||
* Registers custom elements and links them to React components. | ||
* | ||
* @example | ||
* define({ 'x-tooltip': Tooltip }) | ||
* | ||
* @example | ||
* define( | ||
* { 'x-tooltip': Tooltip }, | ||
* { attributes: ['title', 'body'] } | ||
* ) | ||
*/ | ||
@@ -313,2 +397,4 @@ | ||
) { | ||
if (!Adapter) return; | ||
Object.keys(components).forEach(function (name$$1 /*: string */) { | ||
@@ -315,0 +401,0 @@ // Construct the specs for the element. |
@@ -1,1 +0,1 @@ | ||
(function(a,b){'object'==typeof exports&&'undefined'!=typeof module?b(exports,require('react'),require('react-dom')):'function'==typeof define&&define.amd?define(['exports','react','react-dom'],b):b(a.Remount={},a.React,a.ReactDOM)})(this,function(a,b,c){'use strict';function d(){if(!(r||void 0===window.Reflect||void 0===window.customElements||window.customElements.hasOwnProperty('polyfillWrapFlushCallback'))){var b=HTMLElement;window.HTMLElement=function(){return Reflect.construct(b,[],this.constructor)},HTMLElement.prototype=b.prototype,HTMLElement.prototype.constructor=HTMLElement,Object.setPrototypeOf(HTMLElement,b),r=!0}}function e(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);b<a.length;b++)c[b]=a[b];return c}return Array.from(a)}function f(a,b){if(!(a instanceof b))throw new TypeError('Cannot call a class as a function')}function g(a,b){if(!a)throw new ReferenceError('this hasn\'t been initialised - super() hasn\'t been called');return b&&('object'==typeof b||'function'==typeof b)?b:a}function h(a,b){if('function'!=typeof b&&null!==b)throw new TypeError('Super expression must either be null or a function, not '+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}}),b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b)}function i(){return window.customElements&&window.customElements.define}function j(a,b){var c=b.shadow;if(c){var d=document.createElement('span');return a.attachShadow({mode:'open'}).appendChild(d),d}return a}function k(){return!!window.MutationObserver}function l(a,b){for(var c=0,d=a.length;c<d;c++)b(a[c])}function m(a){return-1!==a.indexOf('-')&&a.match(/^[a-z][a-z0-9-]*$/)}function n(a,d,e){var f=a.component,g=a.attributes,h=b.createElement(f,e);c.render(h,d)}function o(a,b){c.unmountComponentAtNode(b)}function p(a){return'object'===('undefined'==typeof a?'undefined':w(a))&&a.component?a:{component:a}}function q(a,b){var c=a.getAttribute('props-json');if(c)return JSON.parse(c);return(b||[]).reduce(function(b,c){return b[c]=a.getAttribute(c),b},{})}c=c&&c.hasOwnProperty('default')?c['default']:c;var r=void 0,s=function(){function a(a,b){for(var c,d=0;d<b.length;d++)c=b[d],c.enumerable=c.enumerable||!1,c.configurable=!0,'value'in c&&(c.writable=!0),Object.defineProperty(a,c.key,c)}return function(b,c,d){return c&&a(b.prototype,c),d&&a(b,d),b}}(),t=Object.freeze({defineElement:function(a,b,c){var i=c.onUpdate,k=c.onUnmount;d();var l=a.attributes||[],m=function(b){function c(){return f(this,c),g(this,(c.__proto__||Object.getPrototypeOf(c)).apply(this,arguments))}return h(c,b),s(c,[{key:'connectedCallback',value:function(){this._mountPoint=j(this,a),i(this,this._mountPoint)}},{key:'disconnectedCallback',value:function(){this._mountPoint&&k(this,this._mountPoint)}},{key:'attributeChangedCallback',value:function(){this._mountPoint&&i(this,this._mountPoint)}}],[{key:'observedAttributes',get:function(){return['props-json'].concat(e(l))}}]),c}(window.HTMLElement);a.quiet&&window.customElements.get(b)||window.customElements.define(b,m)},isSupported:i,name:'CustomElements'}),u={},v=Object.freeze({isSupported:k,defineElement:function(a,b,c){var d=c.onUpdate,e=c.onUnmount;if(b=b.toLowerCase(),!m(b)){if(a.quiet)return;throw new Error('Remount: "'+b+'" is not a valid custom element name')}if(u[b]){if(a.quiet)return;throw new Error('Remount: "'+b+'" is already registered')}var f=new window.MutationObserver(function(a){l(a,function(a){if(l(a.addedNodes,function(a){a.nodeName.toLowerCase()!==b||d(a,a)}),l(a.removedNodes,function(a){a.nodeName.toLowerCase()!==b||e(a,a)}),'attributes'===a.type){var c=a.target;if(c.nodeName.toLowerCase()!==b)return;d(c,c)}})});f.observe(document.body,{attributes:!0,childList:!0,subtree:!0}),u[b]=f},name:'MutationObserver'}),w='function'==typeof Symbol&&'symbol'==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&'function'==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?'symbol':typeof a},x=i()?t:k()?v:null;if(!x)throw new Error('Unsupported platform');else console.log('Remount: using adapter',x.name);var y=x.name;a.adapterName=y,a.define=function(a,b){Object.keys(a).forEach(function(c){var d=Object.assign({},b,p(a[c]));x.defineElement(d,c,{onUpdate:function(a,b){var c=q(a,d.attributes);n(d,b,c)},onUnmount:function(a,b){o(d,b)}})})},Object.defineProperty(a,'__esModule',{value:!0})}); | ||
(function(a,b){'object'==typeof exports&&'undefined'!=typeof module?b(exports,require('react'),require('react-dom')):'function'==typeof define&&define.amd?define(['exports','react','react-dom'],b):b(a.Remount={},a.React,a.ReactDOM)})(this,function(a,b,c){'use strict';function d(){if(!(u||void 0===window.Reflect||void 0===window.customElements||window.customElements.hasOwnProperty('polyfillWrapFlushCallback'))){var b=HTMLElement;window.HTMLElement=function(){return Reflect.construct(b,[],this.constructor)},HTMLElement.prototype=b.prototype,HTMLElement.prototype.constructor=HTMLElement,Object.setPrototypeOf(HTMLElement,b),u=!0}}function e(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);b<a.length;b++)c[b]=a[b];return c}return Array.from(a)}function f(a,b){if(!(a instanceof b))throw new TypeError('Cannot call a class as a function')}function g(a,b){if(!a)throw new ReferenceError('this hasn\'t been initialised - super() hasn\'t been called');return b&&('object'==typeof b||'function'==typeof b)?b:a}function h(a,b){if('function'!=typeof b&&null!==b)throw new TypeError('Super expression must either be null or a function, not '+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}}),b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b)}function i(){return window.customElements&&window.customElements.define}function j(a,b){var c=b.shadow;if(c&&a.attachShadow){var d=document.createElement('span');return a.attachShadow({mode:'open'}).appendChild(d),d}return a}function k(){return!!window.MutationObserver}function l(a,b,c,d){a.nodeName.toLowerCase()===b?(c(a,a),m(a,c),n(a,d)):a.children&&a.children.length&&o(a.children,function(a){l(a,b,c,d)})}function m(a,b){var c=new window.MutationObserver(function(a){o(a,function(a){var c=a.target;b(c,c)})});c.observe(a,{attributes:!0})}function n(a,b){var c=a.parentNode,d=new window.MutationObserver(function(e){o(e,function(e){o(e.removedNodes,function(e){a!==e||(d.disconnect(c),b(a,a))})})});d.observe(c,{childList:!0,subtree:!0})}function o(a,b){for(var c=0,d=a.length;c<d;c++)b(a[c])}function p(a){return-1!==a.indexOf('-')&&a.match(/^[a-z][a-z0-9-]*$/)}function q(a,d,e){var f=a.component,g=a.attributes,h=b.createElement(f,e);c.render(h,d)}function r(a,b){c.unmountComponentAtNode(b)}function s(a){return'object'===('undefined'==typeof a?'undefined':z(a))&&a.component?a:{component:a}}function t(a,b){var c=a.getAttribute('props-json');if(c)return JSON.parse(c);return(b||[]).reduce(function(b,c){return b[c]=a.getAttribute(c),b},{})}c=c&&c.hasOwnProperty('default')?c['default']:c;var u=void 0,v=function(){function a(a,b){for(var c,d=0;d<b.length;d++)c=b[d],c.enumerable=c.enumerable||!1,c.configurable=!0,'value'in c&&(c.writable=!0),Object.defineProperty(a,c.key,c)}return function(b,c,d){return c&&a(b.prototype,c),d&&a(b,d),b}}(),w=Object.freeze({defineElement:function(a,b,c){var i=c.onUpdate,k=c.onUnmount;d();var l=a.attributes||[],m=function(b){function c(){return f(this,c),g(this,(c.__proto__||Object.getPrototypeOf(c)).apply(this,arguments))}return h(c,b),v(c,[{key:'connectedCallback',value:function(){this._mountPoint=j(this,a),i(this,this._mountPoint)}},{key:'disconnectedCallback',value:function(){this._mountPoint&&k(this,this._mountPoint)}},{key:'attributeChangedCallback',value:function(){this._mountPoint&&i(this,this._mountPoint)}}],[{key:'observedAttributes',get:function(){return['props-json'].concat(e(l))}}]),c}(window.HTMLElement);a.quiet&&window.customElements.get(b)||window.customElements.define(b,m)},isSupported:i,name:'CustomElements'}),x={},y=Object.freeze({isSupported:k,defineElement:function(a,b,c){var d=c.onUpdate,e=c.onUnmount;if(b=b.toLowerCase(),!p(b)){if(a.quiet)return;throw new Error('Remount: "'+b+'" is not a valid custom element name')}if(x[b]){if(a.quiet)return;throw new Error('Remount: "'+b+'" is already registered')}var f=new window.MutationObserver(function(a){o(a,function(a){o(a.addedNodes,function(a){l(a,b,d,e)})})});f.observe(document.body,{childList:!0,subtree:!0}),x[b]=!0},name:'MutationObserver'}),z='function'==typeof Symbol&&'symbol'==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&'function'==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?'symbol':typeof a},A=i()?w:k()?y:null;A||console.warn('Remount: This browser doesn\'t support the MutationObserver API or the Custom Elements API. Including polyfills might fix this. Remount elements will not work. https://github.com/rstacruz/remount');var B=A&&A.name;a.adapterName=B,a.define=function(a,b){A&&Object.keys(a).forEach(function(c){var d=Object.assign({},b,s(a[c]));A.defineElement(d,c,{onUpdate:function(a,b){var c=t(a,d.attributes);q(d,b,c)},onUnmount:function(a,b){r(d,b)}})})},Object.defineProperty(a,'__esModule',{value:!0})}); |
@@ -122,3 +122,3 @@ (function (global, factory) { | ||
) { | ||
if (shadow) { | ||
if (shadow && element.attachShadow) { | ||
const mountPoint = document.createElement('span'); | ||
@@ -147,5 +147,22 @@ element.attachShadow({ mode: 'open' }).appendChild(mountPoint); | ||
/** | ||
* Defines a custom element. | ||
* | ||
* @example | ||
* defineElement( | ||
* { component: MyComponent }, | ||
* 'my-div', | ||
* { | ||
* onUpdate: () => {}, | ||
* onUnmount: () => {}, | ||
* } | ||
* ) | ||
* | ||
* @private | ||
*/ | ||
function defineElement$1 (elSpec, name, { onUpdate, onUnmount }) { | ||
name = name.toLowerCase(); | ||
// Maintain parity with what would happen in Custom Elements mode | ||
if (!isValidName(name)) { | ||
@@ -164,16 +181,4 @@ if (elSpec.quiet) return | ||
each(mutation.addedNodes, node => { | ||
if (node.nodeName.toLowerCase() !== name) return | ||
onUpdate(node, node); | ||
checkForMount(node, name, onUpdate, onUnmount); | ||
}); | ||
each(mutation.removedNodes, node => { | ||
if (node.nodeName.toLowerCase() !== name) return | ||
onUnmount(node, node); | ||
}); | ||
if (mutation.type === 'attributes') { | ||
const node = mutation.target; | ||
if (node.nodeName.toLowerCase() !== name) return | ||
onUpdate(node, node); | ||
} | ||
}); | ||
@@ -183,3 +188,2 @@ }); | ||
observer.observe(document.body, { | ||
attributes: true, | ||
childList: true, | ||
@@ -189,6 +193,55 @@ subtree: true | ||
observers[name] = observer; | ||
observers[name] = true; | ||
} | ||
function checkForMount (node, name, onUpdate, onUnmount) { | ||
if (node.nodeName.toLowerCase() === name) { | ||
// It's a match! | ||
onUpdate(node, node); | ||
observeForUpdates(node, onUpdate); | ||
observeForRemoval(node, onUnmount); | ||
} else if (node.children && node.children.length) { | ||
// Recurse down into the other additions | ||
each(node.children, subnode => { | ||
checkForMount(subnode, name, onUpdate, onUnmount); | ||
}); | ||
} | ||
} | ||
/** | ||
* Observes for any changes in attributes | ||
*/ | ||
function observeForUpdates (node /*: Element */, onUpdate) { | ||
const observer = new window.MutationObserver(mutations => { | ||
each(mutations, mutation => { | ||
const node = mutation.target; | ||
onUpdate(node, node); | ||
}); | ||
}); | ||
observer.observe(node, { attributes: true }); | ||
} | ||
/** | ||
* Observes a node's parent to wait until the node is removed | ||
*/ | ||
function observeForRemoval (node /*: Element */, onUnmount) { | ||
const parent = node.parentNode; | ||
const observer = new window.MutationObserver(mutations => { | ||
each(mutations, mutation => { | ||
each(mutation.removedNodes, subnode => { | ||
if (node !== subnode) return | ||
observer.disconnect(parent); | ||
onUnmount(node, node); | ||
}); | ||
}); | ||
}); | ||
observer.observe(parent, { childList: true, subtree: true }); | ||
} | ||
/** | ||
* Some implementations of MutationObserver don't have .forEach, | ||
@@ -207,6 +260,20 @@ * so we need our own `forEach` shim. This is usually the case with | ||
function isValidName (name) { | ||
return ( | ||
name.indexOf('-') !== -1 && name.match(/^[a-z][a-z0-9-]*$/) | ||
) | ||
/** | ||
* Validate a custom tag. | ||
* | ||
* Since Remount can work with either Custom Elements or MutationObserver API's, | ||
* it'd be wise if we rejected element names that won't work in Custom Elements | ||
* mode (even if we're using MutationObserver mode). | ||
* | ||
* @example | ||
* isValidName('div') // => false | ||
* isValidName('my-div') // => true | ||
* isValidName('123-456') // => false | ||
* isValidName('my-123') // => true | ||
* | ||
* @private | ||
*/ | ||
function isValidName (name /*: string */) /*: boolean */ { | ||
return name.indexOf('-') !== -1 && name.match(/^[a-z][a-z0-9-]*$/) | ||
} | ||
@@ -247,3 +314,3 @@ | ||
function unmount (_ /*: any */, mountPoint /*: Element */) { | ||
function unmount (_ /*: ElementSpec */, mountPoint /*: Element */) { | ||
ReactDOM.unmountComponentAtNode(mountPoint); | ||
@@ -264,2 +331,6 @@ } | ||
/* | ||
* Detect what API can be used; die otherwise. | ||
*/ | ||
const Adapter = isSupported() | ||
@@ -272,5 +343,8 @@ ? ElementsAdapter | ||
if (!Adapter) { | ||
throw new Error('Unsupported platform') | ||
} else { | ||
console.log('Remount: using adapter', Adapter.name); | ||
console.warn( | ||
"Remount: This browser doesn't support the " + | ||
'MutationObserver API or the Custom Elements API. Including ' + | ||
'polyfills might fix this. Remount elements will not work. ' + | ||
'https://github.com/rstacruz/remount' | ||
); | ||
} | ||
@@ -280,8 +354,21 @@ | ||
* Inspect `Remount.adapterName` to see what adapter's being used. | ||
* | ||
* @example | ||
* import * as Remount from 'remount' | ||
* console.log(Remount.adapterName) | ||
*/ | ||
const adapterName = Adapter.name; | ||
const adapterName = Adapter && Adapter.name; | ||
/** | ||
* Registers elements. | ||
* Registers custom elements and links them to React components. | ||
* | ||
* @example | ||
* define({ 'x-tooltip': Tooltip }) | ||
* | ||
* @example | ||
* define( | ||
* { 'x-tooltip': Tooltip }, | ||
* { attributes: ['title', 'body'] } | ||
* ) | ||
*/ | ||
@@ -293,2 +380,4 @@ | ||
) { | ||
if (!Adapter) return | ||
Object.keys(components).forEach((name$$1 /*: string */) => { | ||
@@ -295,0 +384,0 @@ // Construct the specs for the element. |
@@ -1,1 +0,1 @@ | ||
(function(a,b){'object'==typeof exports&&'undefined'!=typeof module?b(exports,require('react'),require('react-dom')):'function'==typeof define&&define.amd?define(['exports','react','react-dom'],b):b(a.Remount={},a.React,a.ReactDOM)})(this,function(a,b,c){'use strict';function d(){if(n||void 0===window.Reflect||void 0===window.customElements||window.customElements.hasOwnProperty('polyfillWrapFlushCallback'))return;const b=HTMLElement;window.HTMLElement=function(){return Reflect.construct(b,[],this.constructor)},HTMLElement.prototype=b.prototype,HTMLElement.prototype.constructor=HTMLElement,Object.setPrototypeOf(HTMLElement,b),n=!0}function e(){return window.customElements&&window.customElements.define}function f(a,{shadow:b}){if(b){const b=document.createElement('span');return a.attachShadow({mode:'open'}).appendChild(b),b}return a}function g(){return!!window.MutationObserver}function h(a,b){for(let c=0,d=a.length;c<d;c++)b(a[c])}function i(a){return-1!==a.indexOf('-')&&a.match(/^[a-z][a-z0-9-]*$/)}function j({component:a,attributes:d},e,f){const g=b.createElement(a,f);c.render(g,e)}function k(a,b){c.unmountComponentAtNode(b)}function l(a){return'object'==typeof a&&a.component?a:{component:a}}function m(a,b){const c=a.getAttribute('props-json');if(c)return JSON.parse(c);return(b||[]).reduce((b,c)=>(b[c]=a.getAttribute(c),b),{})}c=c&&c.hasOwnProperty('default')?c['default']:c;let n;var o=Object.freeze({defineElement:function(a,b,{onUpdate:c,onUnmount:e}){d();const g=a.attributes||[];class h extends window.HTMLElement{static get observedAttributes(){return['props-json',...g]}connectedCallback(){this._mountPoint=f(this,a),c(this,this._mountPoint)}disconnectedCallback(){this._mountPoint&&e(this,this._mountPoint)}attributeChangedCallback(){this._mountPoint&&c(this,this._mountPoint)}}a.quiet&&window.customElements.get(b)||window.customElements.define(b,h)},isSupported:e,name:'CustomElements'});let p={};var q=Object.freeze({isSupported:g,defineElement:function(a,b,{onUpdate:c,onUnmount:d}){if(b=b.toLowerCase(),!i(b)){if(a.quiet)return;throw new Error(`Remount: "${b}" is not a valid custom element name`)}if(p[b]){if(a.quiet)return;throw new Error(`Remount: "${b}" is already registered`)}const e=new window.MutationObserver(a=>{h(a,a=>{if(h(a.addedNodes,a=>{a.nodeName.toLowerCase()!==b||c(a,a)}),h(a.removedNodes,a=>{a.nodeName.toLowerCase()!==b||d(a,a)}),'attributes'===a.type){const d=a.target;if(d.nodeName.toLowerCase()!==b)return;c(d,d)}})});e.observe(document.body,{attributes:!0,childList:!0,subtree:!0}),p[b]=e},name:'MutationObserver'});const r=e()?o:g()?q:null;if(!r)throw new Error('Unsupported platform');else console.log('Remount: using adapter',r.name);const s=r.name;a.adapterName=s,a.define=function(a,b){Object.keys(a).forEach((c)=>{const d=Object.assign({},b,l(a[c]));r.defineElement(d,c,{onUpdate(a,b){const c=m(a,d.attributes);j(d,b,c)},onUnmount(a,b){k(d,b)}})})},Object.defineProperty(a,'__esModule',{value:!0})}); | ||
(function(a,b){'object'==typeof exports&&'undefined'!=typeof module?b(exports,require('react'),require('react-dom')):'function'==typeof define&&define.amd?define(['exports','react','react-dom'],b):b(a.Remount={},a.React,a.ReactDOM)})(this,function(a,b,c){'use strict';function d(){if(q||void 0===window.Reflect||void 0===window.customElements||window.customElements.hasOwnProperty('polyfillWrapFlushCallback'))return;const b=HTMLElement;window.HTMLElement=function(){return Reflect.construct(b,[],this.constructor)},HTMLElement.prototype=b.prototype,HTMLElement.prototype.constructor=HTMLElement,Object.setPrototypeOf(HTMLElement,b),q=!0}function e(){return window.customElements&&window.customElements.define}function f(a,{shadow:b}){if(b&&a.attachShadow){const b=document.createElement('span');return a.attachShadow({mode:'open'}).appendChild(b),b}return a}function g(){return!!window.MutationObserver}function h(a,b,c,d){a.nodeName.toLowerCase()===b?(c(a,a),i(a,c),j(a,d)):a.children&&a.children.length&&k(a.children,a=>{h(a,b,c,d)})}function i(a,b){const c=new window.MutationObserver(a=>{k(a,a=>{const c=a.target;b(c,c)})});c.observe(a,{attributes:!0})}function j(a,b){const c=a.parentNode,d=new window.MutationObserver(e=>{k(e,e=>{k(e.removedNodes,e=>{a!==e||(d.disconnect(c),b(a,a))})})});d.observe(c,{childList:!0,subtree:!0})}function k(a,b){for(let c=0,d=a.length;c<d;c++)b(a[c])}function l(a){return-1!==a.indexOf('-')&&a.match(/^[a-z][a-z0-9-]*$/)}function m({component:a,attributes:d},e,f){const g=b.createElement(a,f);c.render(g,e)}function n(a,b){c.unmountComponentAtNode(b)}function o(a){return'object'==typeof a&&a.component?a:{component:a}}function p(a,b){const c=a.getAttribute('props-json');if(c)return JSON.parse(c);return(b||[]).reduce((b,c)=>(b[c]=a.getAttribute(c),b),{})}c=c&&c.hasOwnProperty('default')?c['default']:c;let q;var r=Object.freeze({defineElement:function(a,b,{onUpdate:c,onUnmount:e}){d();const g=a.attributes||[];class h extends window.HTMLElement{static get observedAttributes(){return['props-json',...g]}connectedCallback(){this._mountPoint=f(this,a),c(this,this._mountPoint)}disconnectedCallback(){this._mountPoint&&e(this,this._mountPoint)}attributeChangedCallback(){this._mountPoint&&c(this,this._mountPoint)}}a.quiet&&window.customElements.get(b)||window.customElements.define(b,h)},isSupported:e,name:'CustomElements'});let s={};var t=Object.freeze({isSupported:g,defineElement:function(a,b,{onUpdate:c,onUnmount:d}){if(b=b.toLowerCase(),!l(b)){if(a.quiet)return;throw new Error(`Remount: "${b}" is not a valid custom element name`)}if(s[b]){if(a.quiet)return;throw new Error(`Remount: "${b}" is already registered`)}const e=new window.MutationObserver(a=>{k(a,a=>{k(a.addedNodes,a=>{h(a,b,c,d)})})});e.observe(document.body,{childList:!0,subtree:!0}),s[b]=!0},name:'MutationObserver'});const u=e()?r:g()?t:null;u||console.warn('Remount: This browser doesn\'t support the MutationObserver API or the Custom Elements API. Including polyfills might fix this. Remount elements will not work. https://github.com/rstacruz/remount');const v=u&&u.name;a.adapterName=v,a.define=function(a,b){u&&Object.keys(a).forEach((c)=>{const d=Object.assign({},b,o(a[c]));u.defineElement(d,c,{onUpdate(a,b){const c=p(a,d.attributes);m(d,b,c)},onUnmount(a,b){n(d,b)}})})},Object.defineProperty(a,'__esModule',{value:!0})}); |
32
index.js
@@ -16,2 +16,6 @@ // @flow | ||
/* | ||
* Detect what API can be used; die otherwise. | ||
*/ | ||
const Adapter = ElementsAdapter.isSupported() | ||
@@ -24,5 +28,8 @@ ? ElementsAdapter | ||
if (!Adapter) { | ||
throw new Error('Unsupported platform') | ||
} else { | ||
console.log('Remount: using adapter', Adapter.name) | ||
console.warn( | ||
"Remount: This browser doesn't support the " + | ||
'MutationObserver API or the Custom Elements API. Including ' + | ||
'polyfills might fix this. Remount elements will not work. ' + | ||
'https://github.com/rstacruz/remount' | ||
) | ||
} | ||
@@ -32,8 +39,21 @@ | ||
* Inspect `Remount.adapterName` to see what adapter's being used. | ||
* | ||
* @example | ||
* import * as Remount from 'remount' | ||
* console.log(Remount.adapterName) | ||
*/ | ||
export const adapterName = Adapter.name | ||
export const adapterName = Adapter && Adapter.name | ||
/** | ||
* Registers elements. | ||
* Registers custom elements and links them to React components. | ||
* | ||
* @example | ||
* define({ 'x-tooltip': Tooltip }) | ||
* | ||
* @example | ||
* define( | ||
* { 'x-tooltip': Tooltip }, | ||
* { attributes: ['title', 'body'] } | ||
* ) | ||
*/ | ||
@@ -45,2 +65,4 @@ | ||
) { | ||
if (!Adapter) return | ||
Object.keys(components).forEach((name /*: string */) => { | ||
@@ -47,0 +69,0 @@ // Construct the specs for the element. |
{ | ||
"name": "remount", | ||
"description": "Mount React components to the DOM using custom elements", | ||
"version": "0.7.2", | ||
"version": "0.8.0", | ||
"author": "Rico Sta. Cruz <rstacruz@users.noreply.github.com>", | ||
@@ -6,0 +6,0 @@ "bugs": { |
@@ -18,3 +18,3 @@ <br> | ||
<br> | ||
<em>1kb gzip'd · No dependencies · IE support</em> | ||
<em>2kb gzip'd · No dependencies · IE support</em> | ||
</p> | ||
@@ -33,4 +33,2 @@ | ||
Be sure to use the recommended polyfills below as well. [#](#polyfills) | ||
## Usage | ||
@@ -76,13 +74,15 @@ | ||
- Named attributes (eg, `<x-greeter name="John">`) ([docs](./docs/api.md)) | ||
- Shadow DOM ([docs](./docs/api.md)) | ||
- Uses Custom Elements API (when available) | ||
- Fallback to compatible API for other browers | ||
- Shadow DOM mode (when available) | ||
## Browser support | ||
Remount supports all modern browsers, including IE11 (Internet Explorer's oldest supported version as of 2016). Remember to use the polyfills below to ensure the best compatibility. | ||
Remount supports all browsers that React support, which includes IE11. Legacy IE support (IE9) is available using polyfills. | ||
⚡ [Browser support docs →](./docs/polyfills.md) | ||
Custom Elements API<sup>[#][custom-elements]</sup> ("Web Components") will be used if it's available (Chrome/67+), and will fallback to a compatible API otherwise. | ||
## Polyfills | ||
⚡ [Browser support docs →](./docs/browser_support.md) | ||
More info on this on the [Polyfill docs](./docs/polyfills.md). | ||
[custom-elements]: https://caniuse.com/#search=custom%20elements | ||
@@ -95,3 +95,3 @@ ## Documentation | ||
- [Comparison with alternatives](./docs/comparison.md) | ||
- [Polyfills](./docs/polyfills.md) | ||
- [Browser support](./docs/browser_support.md) | ||
@@ -98,0 +98,0 @@ ## Thanks |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
58383
1262