├── .gitignore ├── .travis.yml ├── .npmignore ├── test ├── es5 │ ├── wc.html │ ├── index.html │ ├── ce.html │ ├── min.js │ └── index.js ├── index.html ├── my-button.js ├── nightmare.js └── table.html ├── LICENSE ├── package.json ├── min.js ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | test/coverage.json 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | git: 5 | depth: 1 6 | branches: 7 | only: 8 | - master 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | coverage/* 2 | node_modules/* 3 | test/* 4 | test/index.js 5 | .DS_Store 6 | .gitignore 7 | .travis.yml 8 | package-lock.json 9 | -------------------------------------------------------------------------------- /test/es5/wc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Custom Elements Built-in Extends + WebComponents 8 | 9 | 10 | 11 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /test/es5/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Custom Elements Built-in Extends - Transpiled 8 | 9 | 10 | 11 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /test/es5/ce.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Custom Elements Built-in Extends over 3rd parts polyfill 8 | 9 | 10 | 11 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Custom Elements Built-in Extends 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /test/my-button.js: -------------------------------------------------------------------------------- 1 | customElements.define( 2 | 'my-button', 3 | class MyButton extends HTMLButtonElement { 4 | static get observedAttributes() { return ['color']; } 5 | attributeChangedCallback(name, oldValue, newValue, nsValue) { 6 | this.style.color = newValue; 7 | } 8 | connectedCallback() { 9 | this.addEventListener('click', this); 10 | } 11 | disconnectedCallback() { 12 | this.removeEventListener('click', this); 13 | } 14 | handleEvent(event) { 15 | const next = this.nextElementSibling || 16 | this.parentNode.appendChild( 17 | document.createElement('div') 18 | ); 19 | next.textContent = `${event.type} @ ${new Date}`; 20 | } 21 | }, 22 | {'extends': 'button'} 23 | ); 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2018, Andrea Giammarchi, @WebReflection 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 10 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /test/nightmare.js: -------------------------------------------------------------------------------- 1 | const Nightmare = require('nightmare'); 2 | const nightmare = Nightmare({show: false}); 3 | 4 | nightmare 5 | .goto(`http://localhost:8080/`) 6 | .evaluate(() => { 7 | window.assert = (ok, message) => 8 | console.warn('nightmare', !!ok, message || 'unknown'); 9 | }) 10 | .on('console', (type, ...args) => { 11 | if (type === 'warn' && args[0] === 'nightmare') { 12 | type = 'assert'; 13 | args.shift(); 14 | } 15 | switch (type) { 16 | case 'assert': 17 | const [ok, message] = args; 18 | if (!ok) exit(new Error(message)); 19 | else console.log(` \x1B[0;32m✔\x1B[0;0m ${message}`); 20 | break; 21 | case 'error': 22 | exit(new Error(args[0])); 23 | default: 24 | console[type](...args); 25 | } 26 | }) 27 | .evaluate(() => { 28 | const constructor = customElements.get('my-button'); 29 | assert(typeof constructor === 'function', 'MyButton is registered'); 30 | const mybtn = document.querySelector('button[is="my-button"]'); 31 | assert(mybtn instanceof constructor, 'DOM node was upgraded'); 32 | assert(mybtn.style.color === 'blue', 'attribute change applied'); 33 | }) 34 | .end() 35 | .catch(exit); 36 | 37 | function exit(error) { 38 | console.error(error); 39 | process.exit(1); 40 | } 41 | -------------------------------------------------------------------------------- /test/table.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Custom Elements Built-in Extends 8 | 9 | 10 | 40 | 41 | 42 | 43 | 44 | 45 |
1
2
46 | 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "built-in-element", 3 | "version": "0.2.4", 4 | "description": "A polyfill for Custom Element built-in", 5 | "main": "index.js", 6 | "module": "index.js", 7 | "unpkg": "min.js", 8 | "scripts": { 9 | "build": "npm run min && npm run es5 && npm run size && npm run test", 10 | "es5": "cp index.js tmp.js && cat test/my-button.js >> tmp.js && cat tmp.js | babel --no-babelrc --presets=@babel/env > test/es5/index.js && rm tmp.js && npm run min5", 11 | "min": "uglifyjs index.js --comments=/^!/ -c -m -o min.js", 12 | "min5": "uglifyjs test/es5/index.js --comments=/^!/ -c -m -o test/es5/min.js", 13 | "size": "cat index.js | wc -c;cat min.js | wc -c;gzip -c9 min.js | wc -c;cat min.js | brotli | wc -c && rm -f min.js.br", 14 | "test": "npm run server & (sleep 1 && npm run nightmare && npm run kill)", 15 | "nightmare": "node test/nightmare.js || (npm run kill && exit 1)", 16 | "server": "node -e 'require(`fs`).writeFileSync(`pid`,require(`child_process`).spawn(`http-server`,[`test`,`-s`]).pid);'", 17 | "kill": "kill -9 $(cat pid) && rm -f pid" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/WebReflection/built-in-element.git" 22 | }, 23 | "keywords": [ 24 | "Custom", 25 | "Element", 26 | "built-in", 27 | "polyfill" 28 | ], 29 | "author": "Andrea Giammarchi", 30 | "license": "ISC", 31 | "bugs": { 32 | "url": "https://github.com/WebReflection/built-in-element/issues" 33 | }, 34 | "homepage": "https://github.com/WebReflection/built-in-element#readme", 35 | "devDependencies": { 36 | "@babel/cli": "^7.1.2", 37 | "@babel/core": "^7.1.2", 38 | "@babel/preset-env": "^7.1.0", 39 | "http-server": "^0.11.1", 40 | "nightmare": "^3.0.1", 41 | "uglify-es": "^3.3.9" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /min.js: -------------------------------------------------------------------------------- 1 | /*! (c) Andrea Giammarchi - ISC */ 2 | !function(e,t){"use strict";if(t.get("li-li"))return;try{class l extends HTMLLIElement{}if(t.define("li-li",l,{extends:"li"}),!/is="li-li"/.test((new l).outerHTML))throw{}}catch(l){const n="attributeChangedCallback",s="connectedCallback",r="disconnectedCallback",{assign:i,create:o,defineProperties:a,setPrototypeOf:u}=Object,{define:c,get:d,upgrade:f,whenDefined:b}=t,g=o(null),h=e=>{for(let t=0,{length:l}=e;t{let t=e.getAttribute("is");return t&&(t=t.toLowerCase())in g?g[t]:null},v=(e,t)=>{const{Class:l}=t,n=l.observedAttributes||[];if(u(e,l.prototype),n.length){new MutationObserver(h).observe(e,{attributes:!0,attributeFilter:n,attributeOldValue:!0});const t=[];for(let l=0,{length:s}=n;l{const l=e.querySelectorAll("[is]");for(let e=0,{length:n}=l;e{if(1!==e.nodeType)return;C(e,m);const t=p(e);t&&(e instanceof t.Class||v(e,t),s in e&&e[s]())},w=e=>{if(1!==e.nodeType)return;C(e,w);const t=p(e);t&&e instanceof t.Class&&r in e&&e[r]()};new MutationObserver(e=>{for(let t=0,{length:l}=e;te in g?g[e].Class:d.call(t,e)},upgrade:{value(e){const l=p(e);!l||e instanceof l.Class?f.call(t,e):v(e,l)}},whenDefined:{value:e=>e in g?Promise.resolve():b.call(t,e)}});const{createElement:y}=e;a(e,{createElement:{value(l,n){const s=y.call(e,l);return n&&"is"in n&&(s.setAttribute("is",n.is),t.upgrade(s)),s}}})}}(document,customElements); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # built-in-element 2 | 3 | [![Build Status](https://travis-ci.com/WebReflection/built-in-element.svg?branch=master)](https://travis-ci.com/WebReflection/built-in-element) ![WebReflection status](https://offline.report/status/webreflection.svg) 4 | 5 | ## Project moved to [@ungap/custom-elements-builtin](https://github.com/ungap/custom-elements-builtin) 6 | 7 | A polyfill for Custom Elements built-in that patches the native registry in Safari and WebKit and it's [compatible with the Custom Elements polyfill](https://github.com/WebReflection/document-register-element). 8 | 9 | It doesn't touch Chrome and Firefox 63+ with native support, and it weights less than 1K. 10 | 11 | ### Caveat 12 | 13 | You cannot use the `constructor` in any meaningful way if you want to ensure API consistency. 14 | 15 | Create new elements via `document.createElement('button', {is: 'my-button'})` but do not use `new MyButton` or incompatible browsers will throw right away because they made `HTMLButtonElement` and all others not usable as classes. 16 | 17 | If you need a reliable entry point to setup your custom builtins use the `connectedCallback` method instead of the `constructor` so you're also sure all attributes are eventually already known and you'll have full control. 18 | 19 | Alternatively, use a `WeakSet` to optionally invoke a setup. 20 | 21 | ```js 22 | const initialized = new WeakSet; 23 | const setup = node => { 24 | initialized.add(node); 25 | node.live = true; 26 | }; 27 | class MyButton extends HTMLButtonElement { 28 | connectedCallback() { 29 | if (!initialized.has(this)) 30 | setup(this); 31 | // anything else 32 | } 33 | } 34 | ``` 35 | 36 | You can do the same at the beginning of `attributeChangedCallback`. 37 | 38 | ### Compatible with ... 39 | 40 | Any engine that supports genuine ES2015 syntax and the following features: 41 | 42 | * global `MutationObserver`, `customElements`, and `Promise` 43 | * `assign`, `create`, `defineProperties`, and `setPrototypeOf` from the `Object` 44 | 45 | Alternatively, you can polyfill custom elements upfront and use Babel 7 to target older browsers. 46 | 47 | Feel free to live test the [native ES2015 version](https://webreflection.github.io/built-in-element/test/) or the [transpiled one](https://webreflection.github.io/built-in-element/test/es5/), which works down to IE9. 48 | -------------------------------------------------------------------------------- /test/es5/min.js: -------------------------------------------------------------------------------- 1 | "use strict";function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function _defineProperties(e,t){for(var n=0;n { 19 | for (let i = 0, {length} = changes; i < length; i++) { 20 | const {attributeName, oldValue, target} = changes[i]; 21 | const newValue = target.getAttribute(attributeName); 22 | if ( 23 | ATTRIBUTE_CHANGED_CALLBACK in target && 24 | !(oldValue == newValue && newValue == null) 25 | ) 26 | target[ATTRIBUTE_CHANGED_CALLBACK]( 27 | attributeName, 28 | oldValue, 29 | target.getAttribute(attributeName), 30 | // TODO: add getAttributeNS if the node is XML 31 | null 32 | ); 33 | } 34 | }; 35 | const getInfo = node => { 36 | let is = node.getAttribute('is'); 37 | if (is) { 38 | is = is.toLowerCase(); 39 | if (is in registry) 40 | return registry[is]; 41 | } 42 | return null; 43 | }; 44 | const setup = (node, info) => { 45 | const {Class} = info; 46 | const oa = Class.observedAttributes || []; 47 | setPrototypeOf(node, Class.prototype); 48 | if (oa.length) { 49 | new MutationObserver(attributeChanged).observe( 50 | node, 51 | { 52 | attributes: true, 53 | attributeFilter: oa, 54 | attributeOldValue: true 55 | } 56 | ); 57 | const changes = []; 58 | for (let i = 0, {length} = oa; i < length; i++) 59 | changes.push({attributeName: oa[i], oldValue: null, target: node}); 60 | attributeChanged(changes); 61 | } 62 | }; 63 | const setupSubNodes = (node, setup) => { 64 | const nodes = node.querySelectorAll('[is]'); 65 | for (let i = 0, {length} = nodes; i < length; i++) 66 | setup(nodes[i]); 67 | }; 68 | const setupIfNeeded = node => { 69 | if (node.nodeType !== 1) 70 | return; 71 | setupSubNodes(node, setupIfNeeded); 72 | const info = getInfo(node); 73 | if (info) { 74 | if (!(node instanceof info.Class)) 75 | setup(node, info); 76 | if (CONNECTED_CALLBACK in node) 77 | node[CONNECTED_CALLBACK](); 78 | } 79 | }; 80 | const disconnectIfNeeded = node => { 81 | if (node.nodeType !== 1) 82 | return; 83 | setupSubNodes(node, disconnectIfNeeded); 84 | const info = getInfo(node); 85 | if ( 86 | info && 87 | node instanceof info.Class && 88 | DISCONNECTED_CALLBACK in node 89 | ) 90 | node[DISCONNECTED_CALLBACK](); 91 | }; 92 | new MutationObserver(changes => { 93 | for (let i = 0, {length} = changes; i < length; i++) { 94 | const {addedNodes, removedNodes} = changes[i]; 95 | for (let j = 0, {length} = addedNodes; j < length; j++) 96 | setupIfNeeded(addedNodes[j]); 97 | for (let j = 0, {length} = removedNodes; j < length; j++) 98 | disconnectIfNeeded(removedNodes[j]); 99 | } 100 | }).observe( 101 | document, 102 | {childList: true, subtree: true} 103 | ); 104 | defineProperties( 105 | customElements, 106 | { 107 | define: { 108 | value(name, Class, options) { 109 | name = name.toLowerCase(); 110 | if (options && EXTENDS in options) { 111 | // currently options is not used but preserved for the future 112 | registry[name] = assign({}, options, {Class}); 113 | const query = options[EXTENDS] + '[is="' + name + '"]'; 114 | const changes = document.querySelectorAll(query); 115 | for (let i = 0, {length} = changes; i < length; i++) 116 | setupIfNeeded(changes[i]); 117 | } 118 | else 119 | define.apply(customElements, arguments); 120 | } 121 | }, 122 | get: { 123 | value(name) { 124 | return name in registry ? 125 | registry[name].Class : 126 | get.call(customElements, name); 127 | } 128 | }, 129 | upgrade: { 130 | value(node) { 131 | const info = getInfo(node); 132 | if (info && !(node instanceof info.Class)) 133 | setup(node, info); 134 | else 135 | upgrade.call(customElements, node); 136 | } 137 | }, 138 | whenDefined: { 139 | value(name) { 140 | return name in registry ? 141 | Promise.resolve() : 142 | whenDefined.call(customElements, name); 143 | } 144 | } 145 | } 146 | ); 147 | const {createElement} = document; 148 | defineProperties( 149 | document, 150 | { 151 | createElement: { 152 | value(name, options) { 153 | const node = createElement.call(document, name); 154 | if (options && 'is' in options) { 155 | node.setAttribute('is', options.is); 156 | customElements.upgrade(node); 157 | } 158 | return node; 159 | } 160 | } 161 | } 162 | ); 163 | } 164 | }(document, customElements)); 165 | -------------------------------------------------------------------------------- /test/es5/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 4 | 5 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 6 | 7 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 8 | 9 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 12 | 13 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 14 | 15 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 16 | 17 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 18 | 19 | function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); } 20 | 21 | function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } 22 | 23 | function _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } 24 | 25 | function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } 26 | 27 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 28 | 29 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 30 | 31 | /*! (c) Andrea Giammarchi - ISC */ 32 | (function (document, customElements) { 33 | 'use strict'; 34 | 35 | if (customElements.get('li-li')) return; 36 | var EXTENDS = 'extends'; 37 | 38 | try { 39 | var LI = 40 | /*#__PURE__*/ 41 | function (_HTMLLIElement) { 42 | _inherits(LI, _HTMLLIElement); 43 | 44 | function LI() { 45 | _classCallCheck(this, LI); 46 | 47 | return _possibleConstructorReturn(this, _getPrototypeOf(LI).apply(this, arguments)); 48 | } 49 | 50 | return LI; 51 | }(_wrapNativeSuper(HTMLLIElement)); 52 | 53 | customElements.define('li-li', LI, _defineProperty({}, EXTENDS, 'li')); 54 | if (!/is="li-li"/.test(new LI().outerHTML)) throw {}; 55 | } catch (o_O) { 56 | var ATTRIBUTE_CHANGED_CALLBACK = 'attributeChangedCallback'; 57 | var CONNECTED_CALLBACK = 'connectedCallback'; 58 | var DISCONNECTED_CALLBACK = 'disconnectedCallback'; 59 | var assign = Object.assign, 60 | create = Object.create, 61 | defineProperties = Object.defineProperties, 62 | setPrototypeOf = Object.setPrototypeOf; 63 | var define = customElements.define, 64 | get = customElements.get, 65 | upgrade = customElements.upgrade, 66 | whenDefined = customElements.whenDefined; 67 | var registry = create(null); 68 | 69 | var attributeChanged = function attributeChanged(changes) { 70 | for (var i = 0, length = changes.length; i < length; i++) { 71 | var _changes$i = changes[i], 72 | attributeName = _changes$i.attributeName, 73 | oldValue = _changes$i.oldValue, 74 | target = _changes$i.target; 75 | var newValue = target.getAttribute(attributeName); 76 | if (ATTRIBUTE_CHANGED_CALLBACK in target && !(oldValue == newValue && newValue == null)) target[ATTRIBUTE_CHANGED_CALLBACK](attributeName, oldValue, target.getAttribute(attributeName), // TODO: add getAttributeNS if the node is XML 77 | null); 78 | } 79 | }; 80 | 81 | var getInfo = function getInfo(node) { 82 | var is = node.getAttribute('is'); 83 | 84 | if (is) { 85 | is = is.toLowerCase(); 86 | if (is in registry) return registry[is]; 87 | } 88 | 89 | return null; 90 | }; 91 | 92 | var setup = function setup(node, info) { 93 | var Class = info.Class; 94 | var oa = Class.observedAttributes || []; 95 | setPrototypeOf(node, Class.prototype); 96 | 97 | if (oa.length) { 98 | new MutationObserver(attributeChanged).observe(node, { 99 | attributes: true, 100 | attributeFilter: oa, 101 | attributeOldValue: true 102 | }); 103 | var changes = []; 104 | 105 | for (var i = 0, length = oa.length; i < length; i++) { 106 | changes.push({ 107 | attributeName: oa[i], 108 | oldValue: null, 109 | target: node 110 | }); 111 | } 112 | 113 | attributeChanged(changes); 114 | } 115 | }; 116 | 117 | var setupSubNodes = function setupSubNodes(node, setup) { 118 | var nodes = node.querySelectorAll('[is]'); 119 | 120 | for (var i = 0, length = nodes.length; i < length; i++) { 121 | setup(nodes[i]); 122 | } 123 | }; 124 | 125 | var setupIfNeeded = function setupIfNeeded(node) { 126 | if (node.nodeType !== 1) return; 127 | setupSubNodes(node, setupIfNeeded); 128 | var info = getInfo(node); 129 | 130 | if (info) { 131 | if (!(node instanceof info.Class)) setup(node, info); 132 | if (CONNECTED_CALLBACK in node) node[CONNECTED_CALLBACK](); 133 | } 134 | }; 135 | 136 | var disconnectIfNeeded = function disconnectIfNeeded(node) { 137 | if (node.nodeType !== 1) return; 138 | setupSubNodes(node, disconnectIfNeeded); 139 | var info = getInfo(node); 140 | if (info && node instanceof info.Class && DISCONNECTED_CALLBACK in node) node[DISCONNECTED_CALLBACK](); 141 | }; 142 | 143 | new MutationObserver(function (changes) { 144 | for (var i = 0, length = changes.length; i < length; i++) { 145 | var _changes$i2 = changes[i], 146 | addedNodes = _changes$i2.addedNodes, 147 | removedNodes = _changes$i2.removedNodes; 148 | 149 | for (var j = 0, _length = addedNodes.length; j < _length; j++) { 150 | setupIfNeeded(addedNodes[j]); 151 | } 152 | 153 | for (var _j = 0, _length2 = removedNodes.length; _j < _length2; _j++) { 154 | disconnectIfNeeded(removedNodes[_j]); 155 | } 156 | } 157 | }).observe(document, { 158 | childList: true, 159 | subtree: true 160 | }); 161 | defineProperties(customElements, { 162 | define: { 163 | value: function value(name, Class, options) { 164 | name = name.toLowerCase(); 165 | 166 | if (options && EXTENDS in options) { 167 | // currently options is not used but preserved for the future 168 | registry[name] = assign({}, options, { 169 | Class: Class 170 | }); 171 | var query = options[EXTENDS] + '[is="' + name + '"]'; 172 | var changes = document.querySelectorAll(query); 173 | 174 | for (var i = 0, length = changes.length; i < length; i++) { 175 | setupIfNeeded(changes[i]); 176 | } 177 | } else define.apply(customElements, arguments); 178 | } 179 | }, 180 | get: { 181 | value: function value(name) { 182 | return name in registry ? registry[name].Class : get.call(customElements, name); 183 | } 184 | }, 185 | upgrade: { 186 | value: function value(node) { 187 | var info = getInfo(node); 188 | if (info && !(node instanceof info.Class)) setup(node, info);else upgrade.call(customElements, node); 189 | } 190 | }, 191 | whenDefined: { 192 | value: function value(name) { 193 | return name in registry ? Promise.resolve() : whenDefined.call(customElements, name); 194 | } 195 | } 196 | }); 197 | var createElement = document.createElement; 198 | defineProperties(document, { 199 | createElement: { 200 | value: function value(name, options) { 201 | var node = createElement.call(document, name); 202 | 203 | if (options && 'is' in options) { 204 | node.setAttribute('is', options.is); 205 | customElements.upgrade(node); 206 | } 207 | 208 | return node; 209 | } 210 | } 211 | }); 212 | } 213 | })(document, customElements); 214 | 215 | customElements.define('my-button', 216 | /*#__PURE__*/ 217 | function (_HTMLButtonElement) { 218 | _inherits(MyButton, _HTMLButtonElement); 219 | 220 | function MyButton() { 221 | _classCallCheck(this, MyButton); 222 | 223 | return _possibleConstructorReturn(this, _getPrototypeOf(MyButton).apply(this, arguments)); 224 | } 225 | 226 | _createClass(MyButton, [{ 227 | key: "attributeChangedCallback", 228 | value: function attributeChangedCallback(name, oldValue, newValue, nsValue) { 229 | this.style.color = newValue; 230 | } 231 | }, { 232 | key: "connectedCallback", 233 | value: function connectedCallback() { 234 | this.addEventListener('click', this); 235 | } 236 | }, { 237 | key: "disconnectedCallback", 238 | value: function disconnectedCallback() { 239 | this.removeEventListener('click', this); 240 | } 241 | }, { 242 | key: "handleEvent", 243 | value: function handleEvent(event) { 244 | var next = this.nextElementSibling || this.parentNode.appendChild(document.createElement('div')); 245 | next.textContent = "".concat(event.type, " @ ").concat(new Date()); 246 | } 247 | }], [{ 248 | key: "observedAttributes", 249 | get: function get() { 250 | return ['color']; 251 | } 252 | }]); 253 | 254 | return MyButton; 255 | }(_wrapNativeSuper(HTMLButtonElement)), { 256 | 'extends': 'button' 257 | }); 258 | 259 | --------------------------------------------------------------------------------