├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── cjs ├── index.js ├── package.json └── utils.js ├── esm ├── index.js └── utils.js ├── index.js ├── min.js ├── package.json ├── rollup.config.js └── test └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | .DS_Store 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test/ 3 | _config.yml 4 | .DS_Store 5 | .gitignore 6 | .travis.yml 7 | package-lock.json 8 | rollup.config.js 9 | es.config.js 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2019, 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hypersimple 2 | 3 | The easiest way to use [hyperHTML](https://github.com/WebReflection/hyperHTML#readme) 🦄 4 | 5 | * `hooks` like simplicity implemented through the model 6 | * component implemented as callbacks 7 | * an entire model/props driven development 8 | 9 | - - - 10 | **Social Media Photo by [Juliana Malta](https://unsplash.com/@julianamalta) on [Unsplash](https://unsplash.com/)** 11 | 12 | ![WebReflection status](https://offline.report/status/webreflection.svg) [![License: ISC](https://img.shields.io/badge/License-ISC-yellow.svg)](https://opensource.org/licenses/ISC) 13 | 14 | 15 | #### Example 16 | 17 | [Live on Code Pen](https://codepen.io/WebReflection/pen/RXaWyR?editors=0010). 18 | 19 | ```js 20 | import {comp, html, render} from 'hypersimple'; 21 | 22 | // components 23 | const Button = comp(model => html` 24 | 27 | `); 28 | 29 | // main App: just like any component 30 | const App = comp(model => html` 31 | Lorem ipsum: ${model.count} 32 |
33 | ${Button(model.button)} 34 | `); 35 | 36 | // model: it will be mutated to trigger updates on changes 37 | const model = { 38 | count: 0, 39 | button: { 40 | text: 'increment', 41 | onclick() { 42 | // will update the view right away 43 | model.count += 1; 44 | } 45 | } 46 | }; 47 | 48 | // render 49 | render(document.body, () => App(model)); 50 | ``` 51 | 52 | ## API in a nutshell 53 | 54 | * `comp(fn)` returns a component based on some `props` or `model` object. The `fn` _must_ return the result of `html` or `svg` 55 | * `html` and `svg` are a template literal tag that accept everything _hyperHTML_ can produce 56 | * `render(where, what)` will populate the content of a generic node with whatever a component returns 57 | * `update(model[, {...changes}])` to update all components based on the same model and, eventually, batch all updates at once through changes 58 | * `define(...)` to enrich _hyperHTML_ potentials [as described in the documentation](https://viperhtml.js.org/hyperhtml/documentation/#api-3) 59 | 60 | The `model` _will be modified_ to reflect any change of any of its properties in the UI, and every method will be automatically bound to the related context. 61 | 62 | A `model` _can be used with multiple components_ without needing to nest a sub model/object per each component related to the same model. 63 | 64 | If you use immutable structures, you'll trash the whole layout each time so ... to **keep it simple**, as the project suggests, but also to keep it memory safe, just pass mutable models and update those directly instead of duplicating references. 65 | 66 | The whole idea is indeed to abstract away everything that's more complicated than setting, or updating, a generic property. 67 | -------------------------------------------------------------------------------- /cjs/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const WeakMap = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/weakmap')); 3 | const Map = (m => m.__esModule ? /* istanbul ignore next */ m.default : /* istanbul ignore next */ m)(require('@ungap/essential-map')); 4 | const { 5 | define, html, svg, augment, merge, refresh, same, slice 6 | } = require('./utils.js'); 7 | 8 | var comps = new WeakMap; 9 | var param = new WeakMap; 10 | var store = new WeakMap; 11 | 12 | var ids = 0; 13 | var sync = true; 14 | 15 | (m => { 16 | exports.escape = m.escape; 17 | exports.unescape = m.unescape; 18 | })(require('html-escaper')); 19 | exports.define = define; 20 | exports.html = html; 21 | exports.svg = svg; 22 | 23 | function comp(Component) { 24 | var id = ++ids; 25 | comps.set(component, id); 26 | return component; 27 | function component(model) { 28 | var mod = model || {}; 29 | var map = store.get(mod) || setMap(mod); 30 | return updateComponent.call( 31 | mod, 32 | map.get(component) || 33 | setInfo(map, component, Component, id, slice.call(arguments, 0)) 34 | ); 35 | }; 36 | } 37 | exports.comp = comp; 38 | 39 | function render(where, comp) { 40 | var content = comps.has(comp) ? 41 | comp(param.get(where) || setParam(where)) : 42 | comp(); 43 | var isElement = content.nodeType === 1; 44 | if (!( 45 | (isElement && where.firstChild === content) || 46 | (!isElement && content.childNodes.every(same, where.childNodes)) 47 | )) { 48 | where.textContent = ''; 49 | where.appendChild(content.valueOf(true)); 50 | } 51 | return where; 52 | } 53 | exports.render = render; 54 | 55 | function update(model, changes) { 56 | var map = store.get(model); 57 | if (!map) 58 | throw new Error('unknown model'); 59 | sync = false; 60 | try { 61 | merge(model, changes || {}); 62 | } 63 | finally { 64 | sync = true; 65 | map.forEach(updateComponent, model); 66 | } 67 | } 68 | exports.update = update; 69 | 70 | function setInfo(map, comp, Component, id, args) { 71 | var info = {Component: Component, id: id, args: args}; 72 | map.set(comp, info); 73 | return info; 74 | } 75 | 76 | function setMap(model) { 77 | var map = new Map; 78 | store.set(model, map); 79 | augment(model, updateAll); 80 | return map; 81 | } 82 | 83 | function setParam(where) { 84 | var model = {}; 85 | param.set(where, model); 86 | return model; 87 | } 88 | 89 | function updateAll(model) { 90 | if (sync) 91 | store.get(model).forEach(updateComponent, model); 92 | } 93 | 94 | function updateComponent(info) { 95 | return refresh(this, info.Component, info.id, info.args); 96 | } 97 | -------------------------------------------------------------------------------- /cjs/package.json: -------------------------------------------------------------------------------- 1 | {"type":"commonjs"} -------------------------------------------------------------------------------- /cjs/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const {define, wire} = require('hyperhtml'); 3 | 4 | var defineProperty = Object.defineProperty; 5 | var gOPD = Object.getOwnPropertyDescriptor; 6 | var keys = Object.keys; 7 | 8 | var hOP = {}.hasOwnProperty; 9 | var slice = [].slice; 10 | var wired = {id: 0, model: null}; 11 | 12 | // hyper utilities 13 | exports.define = define; 14 | 15 | function html() { 16 | return wire(wired.model, 'html:' + wired.id).apply(null, arguments); 17 | } 18 | exports.html = html; 19 | 20 | function svg() { 21 | return wire(wired.model, 'svg:' + wired.id).apply(null, arguments); 22 | } 23 | exports.svg = svg; 24 | 25 | // extra utilities 26 | function augment(model, update) { 27 | keys(model).forEach(function (key) { 28 | var value, desc = gOPD(model, key); 29 | if (desc.configurable) { 30 | if ('value' in desc) { 31 | value = bound(desc.value, model); 32 | defineProperty(model, key, { 33 | configurable: true, 34 | enumerable: true, 35 | get: function () { 36 | return value; 37 | }, 38 | set: function ($) { 39 | value = bound($, model); 40 | update(model); 41 | } 42 | }); 43 | } else if ('set' in desc) { 44 | value = desc.set; 45 | desc.set = function ($) { 46 | value.call(model, $); 47 | update(model); 48 | }; 49 | defineProperty(model, key, desc); 50 | } 51 | } 52 | }); 53 | } 54 | exports.augment = augment; 55 | 56 | function merge(model, changes) { 57 | for (var key in changes) { 58 | if (hOP.call(changes, key)) { 59 | var has = hOP.call(model, key); 60 | var curr = changes[key]; 61 | var prev = has ? model[key] : null; 62 | if (has && curr !== null && typeof curr === "object") 63 | merge(prev, curr); 64 | else if (!has || curr !== prev) 65 | model[key] = curr; 66 | } 67 | } 68 | } 69 | exports.merge = merge; 70 | 71 | function refresh(model, Component, id, args) { 72 | var wid = wired.id; 73 | var wmodel = wired.model; 74 | wired.id = id; 75 | wired.model = model; 76 | try { 77 | return Component.apply(null, args); 78 | } 79 | finally { 80 | wired.id = wid; 81 | wired.model = wmodel; 82 | } 83 | } 84 | exports.refresh = refresh; 85 | 86 | function same(node, i) { 87 | return this[i] === node[i]; 88 | } 89 | exports.same = same; 90 | 91 | exports.slice = slice; 92 | 93 | function bound(value, model) { 94 | return typeof value === 'function' ? value.bind(model) : value; 95 | } 96 | -------------------------------------------------------------------------------- /esm/index.js: -------------------------------------------------------------------------------- 1 | import WeakMap from '@ungap/weakmap'; 2 | import Map from '@ungap/essential-map'; 3 | import { 4 | define, html, svg, 5 | augment, merge, refresh, same, slice 6 | } from './utils.js'; 7 | 8 | var comps = new WeakMap; 9 | var param = new WeakMap; 10 | var store = new WeakMap; 11 | 12 | var ids = 0; 13 | var sync = true; 14 | 15 | export {escape, unescape} from 'html-escaper'; 16 | export {define, html, svg}; 17 | 18 | export function comp(Component) { 19 | var id = ++ids; 20 | comps.set(component, id); 21 | return component; 22 | function component(model) { 23 | var mod = model || {}; 24 | var map = store.get(mod) || setMap(mod); 25 | return updateComponent.call( 26 | mod, 27 | map.get(component) || 28 | setInfo(map, component, Component, id, slice.call(arguments, 0)) 29 | ); 30 | }; 31 | }; 32 | 33 | export function render(where, comp) { 34 | var content = comps.has(comp) ? 35 | comp(param.get(where) || setParam(where)) : 36 | comp(); 37 | var isElement = content.nodeType === 1; 38 | if (!( 39 | (isElement && where.firstChild === content) || 40 | (!isElement && content.childNodes.every(same, where.childNodes)) 41 | )) { 42 | where.textContent = ''; 43 | where.appendChild(content.valueOf(true)); 44 | } 45 | return where; 46 | }; 47 | 48 | export function update(model, changes) { 49 | var map = store.get(model); 50 | if (!map) 51 | throw new Error('unknown model'); 52 | sync = false; 53 | try { 54 | merge(model, changes || {}); 55 | } 56 | finally { 57 | sync = true; 58 | map.forEach(updateComponent, model); 59 | } 60 | }; 61 | 62 | function setInfo(map, comp, Component, id, args) { 63 | var info = {Component: Component, id: id, args: args}; 64 | map.set(comp, info); 65 | return info; 66 | } 67 | 68 | function setMap(model) { 69 | var map = new Map; 70 | store.set(model, map); 71 | augment(model, updateAll); 72 | return map; 73 | } 74 | 75 | function setParam(where) { 76 | var model = {}; 77 | param.set(where, model); 78 | return model; 79 | } 80 | 81 | function updateAll(model) { 82 | if (sync) 83 | store.get(model).forEach(updateComponent, model); 84 | } 85 | 86 | function updateComponent(info) { 87 | return refresh(this, info.Component, info.id, info.args); 88 | } 89 | -------------------------------------------------------------------------------- /esm/utils.js: -------------------------------------------------------------------------------- 1 | import {define, wire} from 'hyperhtml'; 2 | 3 | var defineProperty = Object.defineProperty; 4 | var gOPD = Object.getOwnPropertyDescriptor; 5 | var keys = Object.keys; 6 | 7 | var hOP = {}.hasOwnProperty; 8 | var slice = [].slice; 9 | var wired = {id: 0, model: null}; 10 | 11 | // hyper utilities 12 | export {define}; 13 | 14 | export function html() { 15 | return wire(wired.model, 'html:' + wired.id).apply(null, arguments); 16 | }; 17 | 18 | export function svg() { 19 | return wire(wired.model, 'svg:' + wired.id).apply(null, arguments); 20 | }; 21 | 22 | // extra utilities 23 | export function augment(model, update) { 24 | keys(model).forEach(function (key) { 25 | var value, desc = gOPD(model, key); 26 | if (desc.configurable) { 27 | if ('value' in desc) { 28 | value = bound(desc.value, model); 29 | defineProperty(model, key, { 30 | configurable: true, 31 | enumerable: true, 32 | get: function () { 33 | return value; 34 | }, 35 | set: function ($) { 36 | value = bound($, model); 37 | update(model); 38 | } 39 | }); 40 | } else if ('set' in desc) { 41 | value = desc.set; 42 | desc.set = function ($) { 43 | value.call(model, $); 44 | update(model); 45 | }; 46 | defineProperty(model, key, desc); 47 | } 48 | } 49 | }); 50 | }; 51 | 52 | export function merge(model, changes) { 53 | for (var key in changes) { 54 | if (hOP.call(changes, key)) { 55 | var has = hOP.call(model, key); 56 | var curr = changes[key]; 57 | var prev = has ? model[key] : null; 58 | if (has && curr !== null && typeof curr === "object") 59 | merge(prev, curr); 60 | else if (!has || curr !== prev) 61 | model[key] = curr; 62 | } 63 | } 64 | }; 65 | 66 | export function refresh(model, Component, id, args) { 67 | var wid = wired.id; 68 | var wmodel = wired.model; 69 | wired.id = id; 70 | wired.model = model; 71 | try { 72 | return Component.apply(null, args); 73 | } 74 | finally { 75 | wired.id = wid; 76 | wired.model = wmodel; 77 | } 78 | }; 79 | 80 | export function same(node, i) { 81 | return this[i] === node[i]; 82 | }; 83 | 84 | export {slice}; 85 | 86 | function bound(value, model) { 87 | return typeof value === 'function' ? value.bind(model) : value; 88 | } 89 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var hypersimple = (function (exports) { 2 | 'use strict'; 3 | 4 | /*! (c) Andrea Giammarchi - ISC */ 5 | var self = null || 6 | /* istanbul ignore next */ 7 | {}; 8 | 9 | try { 10 | self.WeakMap = WeakMap; 11 | } catch (WeakMap) { 12 | // this could be better but 90% of the time 13 | // it's everything developers need as fallback 14 | self.WeakMap = function (id, Object) { 15 | 16 | var dP = Object.defineProperty; 17 | var hOP = Object.hasOwnProperty; 18 | var proto = WeakMap.prototype; 19 | 20 | proto["delete"] = function (key) { 21 | return this.has(key) && delete key[this._]; 22 | }; 23 | 24 | proto.get = function (key) { 25 | return this.has(key) ? key[this._] : void 0; 26 | }; 27 | 28 | proto.has = function (key) { 29 | return hOP.call(key, this._); 30 | }; 31 | 32 | proto.set = function (key, value) { 33 | dP(key, this._, { 34 | configurable: true, 35 | value: value 36 | }); 37 | return this; 38 | }; 39 | 40 | return WeakMap; 41 | 42 | function WeakMap(iterable) { 43 | dP(this, '_', { 44 | value: '_@ungap/weakmap' + id++ 45 | }); 46 | if (iterable) iterable.forEach(add, this); 47 | } 48 | 49 | function add(pair) { 50 | this.set(pair[0], pair[1]); 51 | } 52 | }(Math.random(), Object); 53 | } 54 | 55 | var WeakMap$1 = self.WeakMap; 56 | 57 | /*! (c) Andrea Giammarchi - ISC */ 58 | var self$1 = null || 59 | /* istanbul ignore next */ 60 | {}; 61 | 62 | try { 63 | self$1.Map = Map; 64 | } catch (Map) { 65 | self$1.Map = function Map() { 66 | var i = 0; 67 | var k = []; 68 | var v = []; 69 | return { 70 | "delete": function _delete(key) { 71 | var had = contains(key); 72 | 73 | if (had) { 74 | k.splice(i, 1); 75 | v.splice(i, 1); 76 | } 77 | 78 | return had; 79 | }, 80 | forEach: function forEach(callback, context) { 81 | k.forEach(function (key, i) { 82 | callback.call(context, v[i], key, this); 83 | }, this); 84 | }, 85 | get: function get(key) { 86 | return contains(key) ? v[i] : void 0; 87 | }, 88 | has: function has(key) { 89 | return contains(key); 90 | }, 91 | set: function set(key, value) { 92 | v[contains(key) ? i : k.push(key) - 1] = value; 93 | return this; 94 | } 95 | }; 96 | 97 | function contains(v) { 98 | i = k.indexOf(v); 99 | return -1 < i; 100 | } 101 | }; 102 | } 103 | 104 | var Map$1 = self$1.Map; 105 | 106 | 107 | 108 | /*! (c) Andrea Giammarchi - ISC */ 109 | var self$2 = null || 110 | /* istanbul ignore next */ 111 | {}; 112 | 113 | try { 114 | self$2.WeakSet = WeakSet; 115 | } catch (WeakSet) { 116 | (function (id, dP) { 117 | var proto = WeakSet.prototype; 118 | 119 | proto.add = function (object) { 120 | if (!this.has(object)) dP(object, this._, { 121 | value: true, 122 | configurable: true 123 | }); 124 | return this; 125 | }; 126 | 127 | proto.has = function (object) { 128 | return this.hasOwnProperty.call(object, this._); 129 | }; 130 | 131 | proto["delete"] = function (object) { 132 | return this.has(object) && delete object[this._]; 133 | }; 134 | 135 | self$2.WeakSet = WeakSet; 136 | 137 | function WeakSet() { 138 | 139 | dP(this, '_', { 140 | value: '_@ungap/weakmap' + id++ 141 | }); 142 | } 143 | })(Math.random(), Object.defineProperty); 144 | } 145 | 146 | var WeakSet$1 = self$2.WeakSet; 147 | 148 | var _ref = [], 149 | indexOf = _ref.indexOf; 150 | 151 | var append = function append(get, parent, children, start, end, before) { 152 | var isSelect = ('selectedIndex' in parent); 153 | var noSelection = isSelect; 154 | 155 | while (start < end) { 156 | var child = get(children[start], 1); 157 | parent.insertBefore(child, before); 158 | 159 | if (isSelect && noSelection && child.selected) { 160 | noSelection = !noSelection; 161 | var selectedIndex = parent.selectedIndex; 162 | parent.selectedIndex = selectedIndex < 0 ? start : indexOf.call(parent.querySelectorAll('option'), child); 163 | } 164 | 165 | start++; 166 | } 167 | }; 168 | var eqeq = function eqeq(a, b) { 169 | return a == b; 170 | }; 171 | var identity = function identity(O) { 172 | return O; 173 | }; 174 | var indexOf$1 = function indexOf(moreNodes, moreStart, moreEnd, lessNodes, lessStart, lessEnd, compare) { 175 | var length = lessEnd - lessStart; 176 | /* istanbul ignore if */ 177 | 178 | if (length < 1) return -1; 179 | 180 | while (moreEnd - moreStart >= length) { 181 | var m = moreStart; 182 | var l = lessStart; 183 | 184 | while (m < moreEnd && l < lessEnd && compare(moreNodes[m], lessNodes[l])) { 185 | m++; 186 | l++; 187 | } 188 | 189 | if (l === lessEnd) return moreStart; 190 | moreStart = m + 1; 191 | } 192 | 193 | return -1; 194 | }; 195 | var isReversed = function isReversed(futureNodes, futureEnd, currentNodes, currentStart, currentEnd, compare) { 196 | while (currentStart < currentEnd && compare(currentNodes[currentStart], futureNodes[futureEnd - 1])) { 197 | currentStart++; 198 | futureEnd--; 199 | } 200 | return futureEnd === 0; 201 | }; 202 | var next = function next(get, list, i, length, before) { 203 | return i < length ? get(list[i], 0) : 0 < i ? get(list[i - 1], -0).nextSibling : before; 204 | }; 205 | var remove = function remove(get, children, start, end) { 206 | while (start < end) { 207 | drop(get(children[start++], -1)); 208 | } 209 | }; // - - - - - - - - - - - - - - - - - - - 210 | // diff related constants and utilities 211 | // - - - - - - - - - - - - - - - - - - - 212 | 213 | var DELETION = -1; 214 | var INSERTION = 1; 215 | var SKIP = 0; 216 | var SKIP_OND = 50; 217 | 218 | var HS = function HS(futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges) { 219 | var k = 0; 220 | /* istanbul ignore next */ 221 | 222 | var minLen = futureChanges < currentChanges ? futureChanges : currentChanges; 223 | var link = Array(minLen++); 224 | var tresh = Array(minLen); 225 | tresh[0] = -1; 226 | 227 | for (var i = 1; i < minLen; i++) { 228 | tresh[i] = currentEnd; 229 | } 230 | 231 | var nodes = currentNodes.slice(currentStart, currentEnd); 232 | 233 | for (var _i = futureStart; _i < futureEnd; _i++) { 234 | var index = nodes.indexOf(futureNodes[_i]); 235 | 236 | if (-1 < index) { 237 | var idxInOld = index + currentStart; 238 | k = findK(tresh, minLen, idxInOld); 239 | /* istanbul ignore else */ 240 | 241 | if (-1 < k) { 242 | tresh[k] = idxInOld; 243 | link[k] = { 244 | newi: _i, 245 | oldi: idxInOld, 246 | prev: link[k - 1] 247 | }; 248 | } 249 | } 250 | } 251 | 252 | k = --minLen; 253 | --currentEnd; 254 | 255 | while (tresh[k] > currentEnd) { 256 | --k; 257 | } 258 | 259 | minLen = currentChanges + futureChanges - k; 260 | var diff = Array(minLen); 261 | var ptr = link[k]; 262 | --futureEnd; 263 | 264 | while (ptr) { 265 | var _ptr = ptr, 266 | newi = _ptr.newi, 267 | oldi = _ptr.oldi; 268 | 269 | while (futureEnd > newi) { 270 | diff[--minLen] = INSERTION; 271 | --futureEnd; 272 | } 273 | 274 | while (currentEnd > oldi) { 275 | diff[--minLen] = DELETION; 276 | --currentEnd; 277 | } 278 | 279 | diff[--minLen] = SKIP; 280 | --futureEnd; 281 | --currentEnd; 282 | ptr = ptr.prev; 283 | } 284 | 285 | while (futureEnd >= futureStart) { 286 | diff[--minLen] = INSERTION; 287 | --futureEnd; 288 | } 289 | 290 | while (currentEnd >= currentStart) { 291 | diff[--minLen] = DELETION; 292 | --currentEnd; 293 | } 294 | 295 | return diff; 296 | }; // this is pretty much the same petit-dom code without the delete map part 297 | // https://github.com/yelouafi/petit-dom/blob/bd6f5c919b5ae5297be01612c524c40be45f14a7/src/vdom.js#L556-L561 298 | 299 | 300 | var OND = function OND(futureNodes, futureStart, rows, currentNodes, currentStart, cols, compare) { 301 | var length = rows + cols; 302 | var v = []; 303 | var d, k, r, c, pv, cv, pd; 304 | 305 | outer: for (d = 0; d <= length; d++) { 306 | /* istanbul ignore if */ 307 | if (d > SKIP_OND) return null; 308 | pd = d - 1; 309 | /* istanbul ignore next */ 310 | 311 | pv = d ? v[d - 1] : [0, 0]; 312 | cv = v[d] = []; 313 | 314 | for (k = -d; k <= d; k += 2) { 315 | if (k === -d || k !== d && pv[pd + k - 1] < pv[pd + k + 1]) { 316 | c = pv[pd + k + 1]; 317 | } else { 318 | c = pv[pd + k - 1] + 1; 319 | } 320 | 321 | r = c - k; 322 | 323 | while (c < cols && r < rows && compare(currentNodes[currentStart + c], futureNodes[futureStart + r])) { 324 | c++; 325 | r++; 326 | } 327 | 328 | if (c === cols && r === rows) { 329 | break outer; 330 | } 331 | 332 | cv[d + k] = c; 333 | } 334 | } 335 | 336 | var diff = Array(d / 2 + length / 2); 337 | var diffIdx = diff.length - 1; 338 | 339 | for (d = v.length - 1; d >= 0; d--) { 340 | while (c > 0 && r > 0 && compare(currentNodes[currentStart + c - 1], futureNodes[futureStart + r - 1])) { 341 | // diagonal edge = equality 342 | diff[diffIdx--] = SKIP; 343 | c--; 344 | r--; 345 | } 346 | 347 | if (!d) break; 348 | pd = d - 1; 349 | /* istanbul ignore next */ 350 | 351 | pv = d ? v[d - 1] : [0, 0]; 352 | k = c - r; 353 | 354 | if (k === -d || k !== d && pv[pd + k - 1] < pv[pd + k + 1]) { 355 | // vertical edge = insertion 356 | r--; 357 | diff[diffIdx--] = INSERTION; 358 | } else { 359 | // horizontal edge = deletion 360 | c--; 361 | diff[diffIdx--] = DELETION; 362 | } 363 | } 364 | 365 | return diff; 366 | }; 367 | 368 | var applyDiff = function applyDiff(diff, get, parentNode, futureNodes, futureStart, currentNodes, currentStart, currentLength, before) { 369 | var live = []; 370 | var length = diff.length; 371 | var currentIndex = currentStart; 372 | var i = 0; 373 | 374 | while (i < length) { 375 | switch (diff[i++]) { 376 | case SKIP: 377 | futureStart++; 378 | currentIndex++; 379 | break; 380 | 381 | case INSERTION: 382 | // TODO: bulk appends for sequential nodes 383 | live.push(futureNodes[futureStart]); 384 | append(get, parentNode, futureNodes, futureStart++, futureStart, currentIndex < currentLength ? get(currentNodes[currentIndex], 0) : before); 385 | break; 386 | 387 | case DELETION: 388 | currentIndex++; 389 | break; 390 | } 391 | } 392 | 393 | i = 0; 394 | 395 | while (i < length) { 396 | switch (diff[i++]) { 397 | case SKIP: 398 | currentStart++; 399 | break; 400 | 401 | case DELETION: 402 | // TODO: bulk removes for sequential nodes 403 | if (-1 < live.indexOf(currentNodes[currentStart])) currentStart++;else remove(get, currentNodes, currentStart++, currentStart); 404 | break; 405 | } 406 | } 407 | }; 408 | 409 | var findK = function findK(ktr, length, j) { 410 | var lo = 1; 411 | var hi = length; 412 | 413 | while (lo < hi) { 414 | var mid = (lo + hi) / 2 >>> 0; 415 | if (j < ktr[mid]) hi = mid;else lo = mid + 1; 416 | } 417 | 418 | return lo; 419 | }; 420 | 421 | var smartDiff = function smartDiff(get, parentNode, futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges, currentLength, compare, before) { 422 | applyDiff(OND(futureNodes, futureStart, futureChanges, currentNodes, currentStart, currentChanges, compare) || HS(futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges), get, parentNode, futureNodes, futureStart, currentNodes, currentStart, currentLength, before); 423 | }; 424 | 425 | var drop = function drop(node) { 426 | return (node.remove || dropChild).call(node); 427 | }; 428 | 429 | function dropChild() { 430 | var parentNode = this.parentNode; 431 | /* istanbul ignore else */ 432 | 433 | if (parentNode) parentNode.removeChild(this); 434 | } 435 | 436 | /*! (c) 2018 Andrea Giammarchi (ISC) */ 437 | 438 | var domdiff = function domdiff(parentNode, // where changes happen 439 | currentNodes, // Array of current items/nodes 440 | futureNodes, // Array of future items/nodes 441 | options // optional object with one of the following properties 442 | // before: domNode 443 | // compare(generic, generic) => true if same generic 444 | // node(generic) => Node 445 | ) { 446 | if (!options) options = {}; 447 | var compare = options.compare || eqeq; 448 | var get = options.node || identity; 449 | var before = options.before == null ? null : get(options.before, 0); 450 | var currentLength = currentNodes.length; 451 | var currentEnd = currentLength; 452 | var currentStart = 0; 453 | var futureEnd = futureNodes.length; 454 | var futureStart = 0; // common prefix 455 | 456 | while (currentStart < currentEnd && futureStart < futureEnd && compare(currentNodes[currentStart], futureNodes[futureStart])) { 457 | currentStart++; 458 | futureStart++; 459 | } // common suffix 460 | 461 | 462 | while (currentStart < currentEnd && futureStart < futureEnd && compare(currentNodes[currentEnd - 1], futureNodes[futureEnd - 1])) { 463 | currentEnd--; 464 | futureEnd--; 465 | } 466 | 467 | var currentSame = currentStart === currentEnd; 468 | var futureSame = futureStart === futureEnd; // same list 469 | 470 | if (currentSame && futureSame) return futureNodes; // only stuff to add 471 | 472 | if (currentSame && futureStart < futureEnd) { 473 | append(get, parentNode, futureNodes, futureStart, futureEnd, next(get, currentNodes, currentStart, currentLength, before)); 474 | return futureNodes; 475 | } // only stuff to remove 476 | 477 | 478 | if (futureSame && currentStart < currentEnd) { 479 | remove(get, currentNodes, currentStart, currentEnd); 480 | return futureNodes; 481 | } 482 | 483 | var currentChanges = currentEnd - currentStart; 484 | var futureChanges = futureEnd - futureStart; 485 | var i = -1; // 2 simple indels: the shortest sequence is a subsequence of the longest 486 | 487 | if (currentChanges < futureChanges) { 488 | i = indexOf$1(futureNodes, futureStart, futureEnd, currentNodes, currentStart, currentEnd, compare); // inner diff 489 | 490 | if (-1 < i) { 491 | append(get, parentNode, futureNodes, futureStart, i, get(currentNodes[currentStart], 0)); 492 | append(get, parentNode, futureNodes, i + currentChanges, futureEnd, next(get, currentNodes, currentEnd, currentLength, before)); 493 | return futureNodes; 494 | } 495 | } 496 | /* istanbul ignore else */ 497 | else if (futureChanges < currentChanges) { 498 | i = indexOf$1(currentNodes, currentStart, currentEnd, futureNodes, futureStart, futureEnd, compare); // outer diff 499 | 500 | if (-1 < i) { 501 | remove(get, currentNodes, currentStart, i); 502 | remove(get, currentNodes, i + futureChanges, currentEnd); 503 | return futureNodes; 504 | } 505 | } // common case with one replacement for many nodes 506 | // or many nodes replaced for a single one 507 | 508 | /* istanbul ignore else */ 509 | 510 | 511 | if (currentChanges < 2 || futureChanges < 2) { 512 | append(get, parentNode, futureNodes, futureStart, futureEnd, get(currentNodes[currentStart], 0)); 513 | remove(get, currentNodes, currentStart, currentEnd); 514 | return futureNodes; 515 | } // the half match diff part has been skipped in petit-dom 516 | // https://github.com/yelouafi/petit-dom/blob/bd6f5c919b5ae5297be01612c524c40be45f14a7/src/vdom.js#L391-L397 517 | // accordingly, I think it's safe to skip in here too 518 | // if one day it'll come out like the speediest thing ever to do 519 | // then I might add it in here too 520 | // Extra: before going too fancy, what about reversed lists ? 521 | // This should bail out pretty quickly if that's not the case. 522 | 523 | 524 | if (currentChanges === futureChanges && isReversed(futureNodes, futureEnd, currentNodes, currentStart, currentEnd, compare)) { 525 | append(get, parentNode, futureNodes, futureStart, futureEnd, next(get, currentNodes, currentEnd, currentLength, before)); 526 | return futureNodes; 527 | } // last resort through a smart diff 528 | 529 | 530 | smartDiff(get, parentNode, futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges, currentLength, compare, before); 531 | return futureNodes; 532 | }; 533 | 534 | /*! (c) Andrea Giammarchi - ISC */ 535 | var self$3 = null || 536 | /* istanbul ignore next */ 537 | {}; 538 | self$3.CustomEvent = typeof CustomEvent === 'function' ? CustomEvent : function (__p__) { 539 | CustomEvent[__p__] = new CustomEvent('').constructor[__p__]; 540 | return CustomEvent; 541 | 542 | function CustomEvent(type, init) { 543 | if (!init) init = {}; 544 | var e = document.createEvent('CustomEvent'); 545 | e.initCustomEvent(type, !!init.bubbles, !!init.cancelable, init.detail); 546 | return e; 547 | } 548 | }('prototype'); 549 | var CustomEvent$1 = self$3.CustomEvent; 550 | 551 | // able to create Custom Elements like components 552 | // including the ability to listen to connect/disconnect 553 | // events via onconnect/ondisconnect attributes 554 | // Components can be created imperatively or declaratively. 555 | // The main difference is that declared components 556 | // will not automatically render on setState(...) 557 | // to simplify state handling on render. 558 | 559 | function Component() { 560 | return this; // this is needed in Edge !!! 561 | } // Component is lazily setup because it needs 562 | // wire mechanism as lazy content 563 | 564 | function setup(content) { 565 | // there are various weakly referenced variables in here 566 | // and mostly are to use Component.for(...) static method. 567 | var children = new WeakMap$1(); 568 | var create = Object.create; 569 | 570 | var createEntry = function createEntry(wm, id, component) { 571 | wm.set(id, component); 572 | return component; 573 | }; 574 | 575 | var get = function get(Class, info, context, id) { 576 | var relation = info.get(Class) || relate(Class, info); 577 | 578 | switch (typeof(id)) { 579 | case 'object': 580 | case 'function': 581 | var wm = relation.w || (relation.w = new WeakMap$1()); 582 | return wm.get(id) || createEntry(wm, id, new Class(context)); 583 | 584 | default: 585 | var sm = relation.p || (relation.p = create(null)); 586 | return sm[id] || (sm[id] = new Class(context)); 587 | } 588 | }; 589 | 590 | var relate = function relate(Class, info) { 591 | var relation = { 592 | w: null, 593 | p: null 594 | }; 595 | info.set(Class, relation); 596 | return relation; 597 | }; 598 | 599 | var set = function set(context) { 600 | var info = new Map$1(); 601 | children.set(context, info); 602 | return info; 603 | }; // The Component Class 604 | 605 | 606 | Object.defineProperties(Component, { 607 | // Component.for(context[, id]) is a convenient way 608 | // to automatically relate data/context to children components 609 | // If not created yet, the new Component(context) is weakly stored 610 | // and after that same instance would always be returned. 611 | "for": { 612 | configurable: true, 613 | value: function value(context, id) { 614 | return get(this, children.get(context) || set(context), context, id == null ? 'default' : id); 615 | } 616 | } 617 | }); 618 | Object.defineProperties(Component.prototype, { 619 | // all events are handled with the component as context 620 | handleEvent: { 621 | value: function value(e) { 622 | var ct = e.currentTarget; 623 | this['getAttribute' in ct && ct.getAttribute('data-call') || 'on' + e.type](e); 624 | } 625 | }, 626 | // components will lazily define html or svg properties 627 | // as soon as these are invoked within the .render() method 628 | // Such render() method is not provided by the base class 629 | // but it must be available through the Component extend. 630 | // Declared components could implement a 631 | // render(props) method too and use props as needed. 632 | html: lazyGetter('html', content), 633 | svg: lazyGetter('svg', content), 634 | // the state is a very basic/simple mechanism inspired by Preact 635 | state: lazyGetter('state', function () { 636 | return this.defaultState; 637 | }), 638 | // it is possible to define a default state that'd be always an object otherwise 639 | defaultState: { 640 | get: function get() { 641 | return {}; 642 | } 643 | }, 644 | // dispatch a bubbling, cancelable, custom event 645 | // through the first known/available node 646 | dispatch: { 647 | value: function value(type, detail) { 648 | var _wire$ = this._wire$; 649 | 650 | if (_wire$) { 651 | var event = new CustomEvent$1(type, { 652 | bubbles: true, 653 | cancelable: true, 654 | detail: detail 655 | }); 656 | event.component = this; 657 | return (_wire$.dispatchEvent ? _wire$ : _wire$.firstChild).dispatchEvent(event); 658 | } 659 | 660 | return false; 661 | } 662 | }, 663 | // setting some property state through a new object 664 | // or a callback, triggers also automatically a render 665 | // unless explicitly specified to not do so (render === false) 666 | setState: { 667 | value: function value(state, render) { 668 | var target = this.state; 669 | var source = typeof state === 'function' ? state.call(this, target) : state; 670 | 671 | for (var key in source) { 672 | target[key] = source[key]; 673 | } 674 | 675 | if (render !== false) this.render(); 676 | return this; 677 | } 678 | } 679 | }); 680 | } // instead of a secret key I could've used a WeakMap 681 | // However, attaching a property directly will result 682 | // into better performance with thousands of components 683 | // hanging around, and less memory pressure caused by the WeakMap 684 | 685 | var lazyGetter = function lazyGetter(type, fn) { 686 | var secret = '_' + type + '$'; 687 | return { 688 | get: function get() { 689 | return this[secret] || setValue(this, secret, fn.call(this, type)); 690 | }, 691 | set: function set(value) { 692 | setValue(this, secret, value); 693 | } 694 | }; 695 | }; // shortcut to set value on get or set(value) 696 | 697 | 698 | var setValue = function setValue(self, secret, value) { 699 | return Object.defineProperty(self, secret, { 700 | configurable: true, 701 | value: typeof value === 'function' ? function () { 702 | return self._wire$ = value.apply(this, arguments); 703 | } : value 704 | })[secret]; 705 | }; 706 | 707 | Object.defineProperties(Component.prototype, { 708 | // used to distinguish better than instanceof 709 | ELEMENT_NODE: { 710 | value: 1 711 | }, 712 | nodeType: { 713 | value: -1 714 | } 715 | }); 716 | 717 | var attributes = {}; 718 | var intents = {}; 719 | var keys = []; 720 | var hasOwnProperty = intents.hasOwnProperty; 721 | var length = 0; 722 | var Intent = { 723 | // used to invoke right away hyper:attributes 724 | attributes: attributes, 725 | // hyperHTML.define('intent', (object, update) => {...}) 726 | // can be used to define a third parts update mechanism 727 | // when every other known mechanism failed. 728 | // hyper.define('user', info => info.name); 729 | // hyper(node)`

${{user}}

`; 730 | define: function define(intent, callback) { 731 | if (intent.indexOf('-') < 0) { 732 | if (!(intent in intents)) { 733 | length = keys.push(intent); 734 | } 735 | 736 | intents[intent] = callback; 737 | } else { 738 | attributes[intent] = callback; 739 | } 740 | }, 741 | // this method is used internally as last resort 742 | // to retrieve a value out of an object 743 | invoke: function invoke(object, callback) { 744 | for (var i = 0; i < length; i++) { 745 | var key = keys[i]; 746 | 747 | if (hasOwnProperty.call(object, key)) { 748 | return intents[key](object[key], callback); 749 | } 750 | } 751 | } 752 | }; 753 | 754 | var isArray = Array.isArray || function (toString) { 755 | var $ = toString.call([]); 756 | return function isArray(object) { 757 | return toString.call(object) === $; 758 | }; 759 | }({}.toString); 760 | 761 | /*! (c) Andrea Giammarchi - ISC */ 762 | var createContent = function (document) { 763 | 764 | var FRAGMENT = 'fragment'; 765 | var TEMPLATE = 'template'; 766 | var HAS_CONTENT = ('content' in create(TEMPLATE)); 767 | var createHTML = HAS_CONTENT ? function (html) { 768 | var template = create(TEMPLATE); 769 | template.innerHTML = html; 770 | return template.content; 771 | } : function (html) { 772 | var content = create(FRAGMENT); 773 | var template = create(TEMPLATE); 774 | var childNodes = null; 775 | 776 | if (/^[^\S]*?<(col(?:group)?|t(?:head|body|foot|r|d|h))/i.test(html)) { 777 | var selector = RegExp.$1; 778 | template.innerHTML = '' + html + '
'; 779 | childNodes = template.querySelectorAll(selector); 780 | } else { 781 | template.innerHTML = html; 782 | childNodes = template.childNodes; 783 | } 784 | 785 | append(content, childNodes); 786 | return content; 787 | }; 788 | return function createContent(markup, type) { 789 | return (type === 'svg' ? createSVG : createHTML)(markup); 790 | }; 791 | 792 | function append(root, childNodes) { 793 | var length = childNodes.length; 794 | 795 | while (length--) { 796 | root.appendChild(childNodes[0]); 797 | } 798 | } 799 | 800 | function create(element) { 801 | return element === FRAGMENT ? document.createDocumentFragment() : document.createElementNS('http://www.w3.org/1999/xhtml', element); 802 | } // it could use createElementNS when hasNode is there 803 | // but this fallback is equally fast and easier to maintain 804 | // it is also battle tested already in all IE 805 | 806 | 807 | function createSVG(svg) { 808 | var content = create(FRAGMENT); 809 | var template = create('div'); 810 | template.innerHTML = '' + svg + ''; 811 | append(content, template.firstChild.childNodes); 812 | return content; 813 | } 814 | }(document); 815 | 816 | /*! (c) Andrea Giammarchi */ 817 | function disconnected(poly) { 818 | 819 | var Event = poly.Event; 820 | var WeakSet = poly.WeakSet; 821 | var notObserving = true; 822 | var observer = null; 823 | return function observe(node) { 824 | if (notObserving) { 825 | notObserving = !notObserving; 826 | observer = new WeakSet(); 827 | startObserving(node.ownerDocument); 828 | } 829 | 830 | observer.add(node); 831 | return node; 832 | }; 833 | 834 | function startObserving(document) { 835 | var connected = new WeakSet(); 836 | var disconnected = new WeakSet(); 837 | 838 | try { 839 | new MutationObserver(changes).observe(document, { 840 | subtree: true, 841 | childList: true 842 | }); 843 | } catch (o_O) { 844 | var timer = 0; 845 | var records = []; 846 | 847 | var reschedule = function reschedule(record) { 848 | records.push(record); 849 | clearTimeout(timer); 850 | timer = setTimeout(function () { 851 | changes(records.splice(timer = 0, records.length)); 852 | }, 0); 853 | }; 854 | 855 | document.addEventListener('DOMNodeRemoved', function (event) { 856 | reschedule({ 857 | addedNodes: [], 858 | removedNodes: [event.target] 859 | }); 860 | }, true); 861 | document.addEventListener('DOMNodeInserted', function (event) { 862 | reschedule({ 863 | addedNodes: [event.target], 864 | removedNodes: [] 865 | }); 866 | }, true); 867 | } 868 | 869 | function changes(records) { 870 | for (var record, length = records.length, i = 0; i < length; i++) { 871 | record = records[i]; 872 | dispatchAll(record.removedNodes, 'disconnected', disconnected, connected); 873 | dispatchAll(record.addedNodes, 'connected', connected, disconnected); 874 | } 875 | } 876 | 877 | function dispatchAll(nodes, type, wsin, wsout) { 878 | for (var node, event = new Event(type), length = nodes.length, i = 0; i < length; (node = nodes[i++]).nodeType === 1 && dispatchTarget(node, event, type, wsin, wsout)) { 879 | } 880 | } 881 | 882 | function dispatchTarget(node, event, type, wsin, wsout) { 883 | if (observer.has(node) && !wsin.has(node)) { 884 | wsout["delete"](node); 885 | wsin.add(node); 886 | node.dispatchEvent(event); 887 | /* 888 | // The event is not bubbling (perf reason: should it?), 889 | // hence there's no way to know if 890 | // stop/Immediate/Propagation() was called. 891 | // Should DOM Level 0 work at all? 892 | // I say it's a YAGNI case for the time being, 893 | // and easy to implement in user-land. 894 | if (!event.cancelBubble) { 895 | var fn = node['on' + type]; 896 | if (fn) 897 | fn.call(node, event); 898 | } 899 | */ 900 | } 901 | 902 | for (var // apparently is node.children || IE11 ... ^_^;; 903 | // https://github.com/WebReflection/disconnected/issues/1 904 | children = node.children || [], length = children.length, i = 0; i < length; dispatchTarget(children[i++], event, type, wsin, wsout)) { 905 | } 906 | } 907 | } 908 | } 909 | 910 | /*! (c) Andrea Giammarchi - ISC */ 911 | var importNode = function (document, appendChild, cloneNode, createTextNode, importNode) { 912 | var _native = (importNode in document); // IE 11 has problems with cloning templates: 913 | // it "forgets" empty childNodes. This feature-detects that. 914 | 915 | 916 | var fragment = document.createDocumentFragment(); 917 | fragment[appendChild](document[createTextNode]('g')); 918 | fragment[appendChild](document[createTextNode]('')); 919 | var content = _native ? document[importNode](fragment, true) : fragment[cloneNode](true); 920 | return content.childNodes.length < 2 ? function importNode(node, deep) { 921 | var clone = node[cloneNode](); 922 | 923 | for (var childNodes = node.childNodes || [], length = childNodes.length, i = 0; deep && i < length; i++) { 924 | clone[appendChild](importNode(childNodes[i], deep)); 925 | } 926 | 927 | return clone; 928 | } : _native ? document[importNode] : function (node, deep) { 929 | return node[cloneNode](!!deep); 930 | }; 931 | }(document, 'appendChild', 'cloneNode', 'createTextNode', 'importNode'); 932 | 933 | var trim = ''.trim || function () { 934 | return String(this).replace(/^\s+|\s+/g, ''); 935 | }; 936 | 937 | /*! (c) Andrea Giammarchi - ISC */ 938 | // Custom 939 | var UID = '-' + Math.random().toFixed(6) + '%'; // Edge issue! 940 | 941 | var UID_IE = false; 942 | 943 | try { 944 | if (!function (template, content, tabindex) { 945 | return content in template && (template.innerHTML = '

', template[content].childNodes[0].getAttribute(tabindex) == UID); 946 | }(document.createElement('template'), 'content', 'tabindex')) { 947 | UID = '_dt: ' + UID.slice(1, -1) + ';'; 948 | UID_IE = true; 949 | } 950 | } catch (meh) {} 951 | 952 | var UIDC = ''; // DOM 953 | 954 | var COMMENT_NODE = 8; 955 | var ELEMENT_NODE = 1; 956 | var TEXT_NODE = 3; 957 | var SHOULD_USE_TEXT_CONTENT = /^(?:style|textarea)$/i; 958 | var VOID_ELEMENTS = /^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i; 959 | 960 | /*! (c) Andrea Giammarchi - ISC */ 961 | function sanitize (template) { 962 | return template.join(UIDC).replace(selfClosing, fullClosing).replace(attrSeeker, attrReplacer); 963 | } 964 | var spaces = ' \\f\\n\\r\\t'; 965 | var almostEverything = '[^' + spaces + '\\/>"\'=]+'; 966 | var attrName = '[' + spaces + ']+' + almostEverything; 967 | var tagName = '<([A-Za-z]+[A-Za-z0-9:._-]*)((?:'; 968 | var attrPartials = '(?:\\s*=\\s*(?:\'[^\']*?\'|"[^"]*?"|<[^>]*?>|' + almostEverything.replace('\\/', '') + '))?)'; 969 | var attrSeeker = new RegExp(tagName + attrName + attrPartials + '+)([' + spaces + ']*/?>)', 'g'); 970 | var selfClosing = new RegExp(tagName + attrName + attrPartials + '*)([' + spaces + ']*/>)', 'g'); 971 | var findAttributes = new RegExp('(' + attrName + '\\s*=\\s*)([\'"]?)' + UIDC + '\\2', 'gi'); 972 | 973 | function attrReplacer($0, $1, $2, $3) { 974 | return '<' + $1 + $2.replace(findAttributes, replaceAttributes) + $3; 975 | } 976 | 977 | function replaceAttributes($0, $1, $2) { 978 | return $1 + ($2 || '"') + UID + ($2 || '"'); 979 | } 980 | 981 | function fullClosing($0, $1, $2) { 982 | return VOID_ELEMENTS.test($1) ? $0 : '<' + $1 + $2 + '>'; 983 | } 984 | 985 | var umap = (function (_) { 986 | return { 987 | // About: get: _.get.bind(_) 988 | // It looks like WebKit/Safari didn't optimize bind at all, 989 | // so that using bind slows it down by 60%. 990 | // Firefox and Chrome are just fine in both cases, 991 | // so let's use the approach that works fast everywhere 👍 992 | get: function get(key) { 993 | return _.get(key); 994 | }, 995 | set: function set(key, value) { 996 | return _.set(key, value), value; 997 | } 998 | }; 999 | }); 1000 | 1001 | /* istanbul ignore next */ 1002 | 1003 | var normalizeAttributes = UID_IE ? function (attributes, parts) { 1004 | var html = parts.join(' '); 1005 | return parts.slice.call(attributes, 0).sort(function (left, right) { 1006 | return html.indexOf(left.name) <= html.indexOf(right.name) ? -1 : 1; 1007 | }); 1008 | } : function (attributes, parts) { 1009 | return parts.slice.call(attributes, 0); 1010 | }; 1011 | 1012 | function find(node, path) { 1013 | var length = path.length; 1014 | var i = 0; 1015 | 1016 | while (i < length) { 1017 | node = node.childNodes[path[i++]]; 1018 | } 1019 | 1020 | return node; 1021 | } 1022 | 1023 | function parse(node, holes, parts, path) { 1024 | var childNodes = node.childNodes; 1025 | var length = childNodes.length; 1026 | var i = 0; 1027 | 1028 | while (i < length) { 1029 | var child = childNodes[i]; 1030 | 1031 | switch (child.nodeType) { 1032 | case ELEMENT_NODE: 1033 | var childPath = path.concat(i); 1034 | parseAttributes(child, holes, parts, childPath); 1035 | parse(child, holes, parts, childPath); 1036 | break; 1037 | 1038 | case COMMENT_NODE: 1039 | var textContent = child.textContent; 1040 | 1041 | if (textContent === UID) { 1042 | parts.shift(); 1043 | holes.push( // basicHTML or other non standard engines 1044 | // might end up having comments in nodes 1045 | // where they shouldn't, hence this check. 1046 | SHOULD_USE_TEXT_CONTENT.test(node.nodeName) ? Text(node, path) : Any(child, path.concat(i))); 1047 | } else { 1048 | switch (textContent.slice(0, 2)) { 1049 | case '/*': 1050 | if (textContent.slice(-2) !== '*/') break; 1051 | 1052 | case "\uD83D\uDC7B": 1053 | // ghost 1054 | node.removeChild(child); 1055 | i--; 1056 | length--; 1057 | } 1058 | } 1059 | 1060 | break; 1061 | 1062 | case TEXT_NODE: 1063 | // the following ignore is actually covered by browsers 1064 | // only basicHTML ends up on previous COMMENT_NODE case 1065 | // instead of TEXT_NODE because it knows nothing about 1066 | // special style or textarea behavior 1067 | 1068 | /* istanbul ignore if */ 1069 | if (SHOULD_USE_TEXT_CONTENT.test(node.nodeName) && trim.call(child.textContent) === UIDC) { 1070 | parts.shift(); 1071 | holes.push(Text(node, path)); 1072 | } 1073 | 1074 | break; 1075 | } 1076 | 1077 | i++; 1078 | } 1079 | } 1080 | 1081 | function parseAttributes(node, holes, parts, path) { 1082 | var attributes = node.attributes; 1083 | var cache = []; 1084 | var remove = []; 1085 | var array = normalizeAttributes(attributes, parts); 1086 | var length = array.length; 1087 | var i = 0; 1088 | 1089 | while (i < length) { 1090 | var attribute = array[i++]; 1091 | var direct = attribute.value === UID; 1092 | var sparse; 1093 | 1094 | if (direct || 1 < (sparse = attribute.value.split(UIDC)).length) { 1095 | var name = attribute.name; // the following ignore is covered by IE 1096 | // and the IE9 double viewBox test 1097 | 1098 | /* istanbul ignore else */ 1099 | 1100 | if (cache.indexOf(name) < 0) { 1101 | cache.push(name); 1102 | var realName = parts.shift().replace(direct ? /^(?:|[\S\s]*?\s)(\S+?)\s*=\s*('|")?$/ : new RegExp('^(?:|[\\S\\s]*?\\s)(' + name + ')\\s*=\\s*(\'|")[\\S\\s]*', 'i'), '$1'); 1103 | var value = attributes[realName] || // the following ignore is covered by browsers 1104 | // while basicHTML is already case-sensitive 1105 | 1106 | /* istanbul ignore next */ 1107 | attributes[realName.toLowerCase()]; 1108 | if (direct) holes.push(Attr(value, path, realName, null));else { 1109 | var skip = sparse.length - 2; 1110 | 1111 | while (skip--) { 1112 | parts.shift(); 1113 | } 1114 | 1115 | holes.push(Attr(value, path, realName, sparse)); 1116 | } 1117 | } 1118 | 1119 | remove.push(attribute); 1120 | } 1121 | } 1122 | 1123 | length = remove.length; 1124 | i = 0; 1125 | /* istanbul ignore next */ 1126 | 1127 | var cleanValue = 0 < length && UID_IE && !('ownerSVGElement' in node); 1128 | 1129 | while (i < length) { 1130 | // Edge HTML bug #16878726 1131 | var attr = remove[i++]; // IE/Edge bug lighterhtml#63 - clean the value or it'll persist 1132 | 1133 | /* istanbul ignore next */ 1134 | 1135 | if (cleanValue) attr.value = ''; // IE/Edge bug lighterhtml#64 - don't use removeAttributeNode 1136 | 1137 | node.removeAttribute(attr.name); 1138 | } // This is a very specific Firefox/Safari issue 1139 | // but since it should be a not so common pattern, 1140 | // it's probably worth patching regardless. 1141 | // Basically, scripts created through strings are death. 1142 | // You need to create fresh new scripts instead. 1143 | // TODO: is there any other node that needs such nonsense? 1144 | 1145 | 1146 | var nodeName = node.nodeName; 1147 | 1148 | if (/^script$/i.test(nodeName)) { 1149 | // this used to be like that 1150 | // var script = createElement(node, nodeName); 1151 | // then Edge arrived and decided that scripts created 1152 | // through template documents aren't worth executing 1153 | // so it became this ... hopefully it won't hurt in the wild 1154 | var script = document.createElement(nodeName); 1155 | length = attributes.length; 1156 | i = 0; 1157 | 1158 | while (i < length) { 1159 | script.setAttributeNode(attributes[i++].cloneNode(true)); 1160 | } 1161 | 1162 | script.textContent = node.textContent; 1163 | node.parentNode.replaceChild(script, node); 1164 | } 1165 | } 1166 | 1167 | function Any(node, path) { 1168 | return { 1169 | type: 'any', 1170 | node: node, 1171 | path: path 1172 | }; 1173 | } 1174 | 1175 | function Attr(node, path, name, sparse) { 1176 | return { 1177 | type: 'attr', 1178 | node: node, 1179 | path: path, 1180 | name: name, 1181 | sparse: sparse 1182 | }; 1183 | } 1184 | 1185 | function Text(node, path) { 1186 | return { 1187 | type: 'text', 1188 | node: node, 1189 | path: path 1190 | }; 1191 | } 1192 | 1193 | // globals 1194 | var parsed = umap(new WeakMap$1()); 1195 | 1196 | function createInfo(options, template) { 1197 | var markup = (options.convert || sanitize)(template); 1198 | var transform = options.transform; 1199 | if (transform) markup = transform(markup); 1200 | var content = createContent(markup, options.type); 1201 | cleanContent(content); 1202 | var holes = []; 1203 | parse(content, holes, template.slice(0), []); 1204 | return { 1205 | content: content, 1206 | updates: function updates(content) { 1207 | var updates = []; 1208 | var len = holes.length; 1209 | var i = 0; 1210 | var off = 0; 1211 | 1212 | while (i < len) { 1213 | var info = holes[i++]; 1214 | var node = find(content, info.path); 1215 | 1216 | switch (info.type) { 1217 | case 'any': 1218 | updates.push({ 1219 | fn: options.any(node, []), 1220 | sparse: false 1221 | }); 1222 | break; 1223 | 1224 | case 'attr': 1225 | var sparse = info.sparse; 1226 | var fn = options.attribute(node, info.name, info.node); 1227 | if (sparse === null) updates.push({ 1228 | fn: fn, 1229 | sparse: false 1230 | });else { 1231 | off += sparse.length - 2; 1232 | updates.push({ 1233 | fn: fn, 1234 | sparse: true, 1235 | values: sparse 1236 | }); 1237 | } 1238 | break; 1239 | 1240 | case 'text': 1241 | updates.push({ 1242 | fn: options.text(node), 1243 | sparse: false 1244 | }); 1245 | node.textContent = ''; 1246 | break; 1247 | } 1248 | } 1249 | 1250 | len += off; 1251 | return function () { 1252 | var length = arguments.length; 1253 | 1254 | if (len !== length - 1) { 1255 | throw new Error(length - 1 + ' values instead of ' + len + '\n' + template.join('${value}')); 1256 | } 1257 | 1258 | var i = 1; 1259 | var off = 1; 1260 | 1261 | while (i < length) { 1262 | var update = updates[i - off]; 1263 | 1264 | if (update.sparse) { 1265 | var values = update.values; 1266 | var value = values[0]; 1267 | var j = 1; 1268 | var l = values.length; 1269 | off += l - 2; 1270 | 1271 | while (j < l) { 1272 | value += arguments[i++] + values[j++]; 1273 | } 1274 | 1275 | update.fn(value); 1276 | } else update.fn(arguments[i++]); 1277 | } 1278 | 1279 | return content; 1280 | }; 1281 | } 1282 | }; 1283 | } 1284 | 1285 | function createDetails(options, template) { 1286 | var info = parsed.get(template) || parsed.set(template, createInfo(options, template)); 1287 | return info.updates(importNode.call(document, info.content, true)); 1288 | } 1289 | 1290 | var empty = []; 1291 | 1292 | function domtagger(options) { 1293 | var previous = empty; 1294 | var updates = cleanContent; 1295 | return function (template) { 1296 | if (previous !== template) updates = createDetails(options, previous = template); 1297 | return updates.apply(null, arguments); 1298 | }; 1299 | } 1300 | 1301 | function cleanContent(fragment) { 1302 | var childNodes = fragment.childNodes; 1303 | var i = childNodes.length; 1304 | 1305 | while (i--) { 1306 | var child = childNodes[i]; 1307 | 1308 | if (child.nodeType !== 1 && trim.call(child.textContent).length === 0) { 1309 | fragment.removeChild(child); 1310 | } 1311 | } 1312 | } 1313 | 1314 | /*! (c) Andrea Giammarchi - ISC */ 1315 | var hyperStyle = function () { 1316 | 1317 | var IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i; 1318 | var hyphen = /([^A-Z])([A-Z]+)/g; 1319 | return function hyperStyle(node, original) { 1320 | return 'ownerSVGElement' in node ? svg(node, original) : update(node.style, false); 1321 | }; 1322 | 1323 | function ized($0, $1, $2) { 1324 | return $1 + '-' + $2.toLowerCase(); 1325 | } 1326 | 1327 | function svg(node, original) { 1328 | var style; 1329 | if (original) style = original.cloneNode(true);else { 1330 | node.setAttribute('style', '--hyper:style;'); 1331 | style = node.getAttributeNode('style'); 1332 | } 1333 | style.value = ''; 1334 | node.setAttributeNode(style); 1335 | return update(style, true); 1336 | } 1337 | 1338 | function toStyle(object) { 1339 | var key, 1340 | css = []; 1341 | 1342 | for (key in object) { 1343 | css.push(key.replace(hyphen, ized), ':', object[key], ';'); 1344 | } 1345 | 1346 | return css.join(''); 1347 | } 1348 | 1349 | function update(style, isSVG) { 1350 | var oldType, oldValue; 1351 | return function (newValue) { 1352 | var info, key, styleValue, value; 1353 | 1354 | switch (typeof(newValue)) { 1355 | case 'object': 1356 | if (newValue) { 1357 | if (oldType === 'object') { 1358 | if (!isSVG) { 1359 | if (oldValue !== newValue) { 1360 | for (key in oldValue) { 1361 | if (!(key in newValue)) { 1362 | style[key] = ''; 1363 | } 1364 | } 1365 | } 1366 | } 1367 | } else { 1368 | if (isSVG) style.value = '';else style.cssText = ''; 1369 | } 1370 | 1371 | info = isSVG ? {} : style; 1372 | 1373 | for (key in newValue) { 1374 | value = newValue[key]; 1375 | styleValue = typeof value === 'number' && !IS_NON_DIMENSIONAL.test(key) ? value + 'px' : value; 1376 | if (!isSVG && /^--/.test(key)) info.setProperty(key, styleValue);else info[key] = styleValue; 1377 | } 1378 | 1379 | oldType = 'object'; 1380 | if (isSVG) style.value = toStyle(oldValue = info);else oldValue = newValue; 1381 | break; 1382 | } 1383 | 1384 | default: 1385 | if (oldValue != newValue) { 1386 | oldType = 'string'; 1387 | oldValue = newValue; 1388 | if (isSVG) style.value = newValue || '';else style.cssText = newValue || ''; 1389 | } 1390 | 1391 | break; 1392 | } 1393 | }; 1394 | } 1395 | }(); 1396 | 1397 | /*! (c) Andrea Giammarchi - ISC */ 1398 | var Wire = function (slice, proto) { 1399 | proto = Wire.prototype; 1400 | proto.ELEMENT_NODE = 1; 1401 | proto.nodeType = 111; 1402 | 1403 | proto.remove = function (keepFirst) { 1404 | var childNodes = this.childNodes; 1405 | var first = this.firstChild; 1406 | var last = this.lastChild; 1407 | this._ = null; 1408 | 1409 | if (keepFirst && childNodes.length === 2) { 1410 | last.parentNode.removeChild(last); 1411 | } else { 1412 | var range = this.ownerDocument.createRange(); 1413 | range.setStartBefore(keepFirst ? childNodes[1] : first); 1414 | range.setEndAfter(last); 1415 | range.deleteContents(); 1416 | } 1417 | 1418 | return first; 1419 | }; 1420 | 1421 | proto.valueOf = function (forceAppend) { 1422 | var fragment = this._; 1423 | var noFragment = fragment == null; 1424 | if (noFragment) fragment = this._ = this.ownerDocument.createDocumentFragment(); 1425 | 1426 | if (noFragment || forceAppend) { 1427 | for (var n = this.childNodes, i = 0, l = n.length; i < l; i++) { 1428 | fragment.appendChild(n[i]); 1429 | } 1430 | } 1431 | 1432 | return fragment; 1433 | }; 1434 | 1435 | return Wire; 1436 | 1437 | function Wire(childNodes) { 1438 | var nodes = this.childNodes = slice.call(childNodes, 0); 1439 | this.firstChild = nodes[0]; 1440 | this.lastChild = nodes[nodes.length - 1]; 1441 | this.ownerDocument = nodes[0].ownerDocument; 1442 | this._ = null; 1443 | } 1444 | }([].slice); 1445 | 1446 | // Node.CONSTANTS 1447 | var DOCUMENT_FRAGMENT_NODE = 11; // SVG related constants 1448 | 1449 | var OWNER_SVG_ELEMENT = 'ownerSVGElement'; // Custom Elements / MutationObserver constants 1450 | 1451 | var CONNECTED = 'connected'; 1452 | var DISCONNECTED = 'dis' + CONNECTED; 1453 | 1454 | var componentType = Component.prototype.nodeType; 1455 | var wireType = Wire.prototype.nodeType; 1456 | var observe = disconnected({ 1457 | Event: CustomEvent$1, 1458 | WeakSet: WeakSet$1 1459 | }); 1460 | 1461 | var asHTML = function asHTML(html) { 1462 | return { 1463 | html: html 1464 | }; 1465 | }; // returns nodes from wires and components 1466 | 1467 | 1468 | var asNode = function asNode(item, i) { 1469 | switch (item.nodeType) { 1470 | case wireType: 1471 | // in the Wire case, the content can be 1472 | // removed, post-pended, inserted, or pre-pended and 1473 | // all these cases are handled by domdiff already 1474 | 1475 | /* istanbul ignore next */ 1476 | return 1 / i < 0 ? i ? item.remove(true) : item.lastChild : i ? item.valueOf(true) : item.firstChild; 1477 | 1478 | case componentType: 1479 | return asNode(item.render(), i); 1480 | 1481 | default: 1482 | return item; 1483 | } 1484 | }; // returns true if domdiff can handle the value 1485 | 1486 | 1487 | var canDiff = function canDiff(value) { 1488 | return 'ELEMENT_NODE' in value; 1489 | }; 1490 | 1491 | var hyperSetter = function hyperSetter(node, name, svg) { 1492 | return svg ? function (value) { 1493 | try { 1494 | node[name] = value; 1495 | } catch (nope) { 1496 | node.setAttribute(name, value); 1497 | } 1498 | } : function (value) { 1499 | node[name] = value; 1500 | }; 1501 | }; // when a Promise is used as interpolation value 1502 | // its result must be parsed once resolved. 1503 | // This callback is in charge of understanding what to do 1504 | // with a returned value once the promise is resolved. 1505 | 1506 | 1507 | var invokeAtDistance = function invokeAtDistance(value, callback) { 1508 | callback(value.placeholder); 1509 | 1510 | if ('text' in value) { 1511 | Promise.resolve(value.text).then(String).then(callback); 1512 | } else if ('any' in value) { 1513 | Promise.resolve(value.any).then(callback); 1514 | } else if ('html' in value) { 1515 | Promise.resolve(value.html).then(asHTML).then(callback); 1516 | } else { 1517 | Promise.resolve(Intent.invoke(value, callback)).then(callback); 1518 | } 1519 | }; // quick and dirty way to check for Promise/ish values 1520 | 1521 | 1522 | var isPromise_ish = function isPromise_ish(value) { 1523 | return value != null && 'then' in value; 1524 | }; // list of attributes that should not be directly assigned 1525 | 1526 | 1527 | var readOnly = /^(?:form|list)$/i; // reused every slice time 1528 | 1529 | var slice = [].slice; // simplifies text node creation 1530 | 1531 | var text = function text(node, _text) { 1532 | return node.ownerDocument.createTextNode(_text); 1533 | }; 1534 | 1535 | function Tagger(type) { 1536 | this.type = type; 1537 | return domtagger(this); 1538 | } 1539 | 1540 | Tagger.prototype = { 1541 | // there are four kind of attributes, and related behavior: 1542 | // * events, with a name starting with `on`, to add/remove event listeners 1543 | // * special, with a name present in their inherited prototype, accessed directly 1544 | // * regular, accessed through get/setAttribute standard DOM methods 1545 | // * style, the only regular attribute that also accepts an object as value 1546 | // so that you can style=${{width: 120}}. In this case, the behavior has been 1547 | // fully inspired by Preact library and its simplicity. 1548 | attribute: function attribute(node, name, original) { 1549 | var isSVG = (OWNER_SVG_ELEMENT in node); 1550 | var oldValue; // if the attribute is the style one 1551 | // handle it differently from others 1552 | 1553 | if (name === 'style') return hyperStyle(node, original, isSVG); // direct accessors for and friends 1554 | else if (name.slice(0, 1) === '.') return hyperSetter(node, name.slice(1), isSVG); // the name is an event one, 1555 | // add/remove event listeners accordingly 1556 | else if (/^on/.test(name)) { 1557 | var type = name.slice(2); 1558 | 1559 | if (type === CONNECTED || type === DISCONNECTED) { 1560 | observe(node); 1561 | } else if (name.toLowerCase() in node) { 1562 | type = type.toLowerCase(); 1563 | } 1564 | 1565 | return function (newValue) { 1566 | if (oldValue !== newValue) { 1567 | if (oldValue) node.removeEventListener(type, oldValue, false); 1568 | oldValue = newValue; 1569 | if (newValue) node.addEventListener(type, newValue, false); 1570 | } 1571 | }; 1572 | } // the attribute is special ('value' in input) 1573 | // and it's not SVG *or* the name is exactly data, 1574 | // in this case assign the value directly 1575 | else if (name === 'data' || !isSVG && name in node && !readOnly.test(name)) { 1576 | return function (newValue) { 1577 | if (oldValue !== newValue) { 1578 | oldValue = newValue; 1579 | 1580 | if (node[name] !== newValue && newValue == null) { 1581 | // cleanup on null to avoid silly IE/Edge bug 1582 | node[name] = ''; 1583 | node.removeAttribute(name); 1584 | } else node[name] = newValue; 1585 | } 1586 | }; 1587 | } else if (name in Intent.attributes) { 1588 | return function (any) { 1589 | var newValue = Intent.attributes[name](node, any); 1590 | 1591 | if (oldValue !== newValue) { 1592 | oldValue = newValue; 1593 | if (newValue == null) node.removeAttribute(name);else node.setAttribute(name, newValue); 1594 | } 1595 | }; 1596 | } // in every other case, use the attribute node as it is 1597 | // update only the value, set it as node only when/if needed 1598 | else { 1599 | var owner = false; 1600 | var attribute = original.cloneNode(true); 1601 | return function (newValue) { 1602 | if (oldValue !== newValue) { 1603 | oldValue = newValue; 1604 | 1605 | if (attribute.value !== newValue) { 1606 | if (newValue == null) { 1607 | if (owner) { 1608 | owner = false; 1609 | node.removeAttributeNode(attribute); 1610 | } 1611 | 1612 | attribute.value = newValue; 1613 | } else { 1614 | attribute.value = newValue; 1615 | 1616 | if (!owner) { 1617 | owner = true; 1618 | node.setAttributeNode(attribute); 1619 | } 1620 | } 1621 | } 1622 | } 1623 | }; 1624 | } 1625 | }, 1626 | // in a hyper(node)`
${content}
` case 1627 | // everything could happen: 1628 | // * it's a JS primitive, stored as text 1629 | // * it's null or undefined, the node should be cleaned 1630 | // * it's a component, update the content by rendering it 1631 | // * it's a promise, update the content once resolved 1632 | // * it's an explicit intent, perform the desired operation 1633 | // * it's an Array, resolve all values if Promises and/or 1634 | // update the node with the resulting list of content 1635 | any: function any(node, childNodes) { 1636 | var diffOptions = { 1637 | node: asNode, 1638 | before: node 1639 | }; 1640 | var nodeType = OWNER_SVG_ELEMENT in node ? 1641 | /* istanbul ignore next */ 1642 | 'svg' : 'html'; 1643 | var fastPath = false; 1644 | var oldValue; 1645 | 1646 | var anyContent = function anyContent(value) { 1647 | switch (typeof(value)) { 1648 | case 'string': 1649 | case 'number': 1650 | case 'boolean': 1651 | if (fastPath) { 1652 | if (oldValue !== value) { 1653 | oldValue = value; 1654 | childNodes[0].textContent = value; 1655 | } 1656 | } else { 1657 | fastPath = true; 1658 | oldValue = value; 1659 | childNodes = domdiff(node.parentNode, childNodes, [text(node, value)], diffOptions); 1660 | } 1661 | 1662 | break; 1663 | 1664 | case 'function': 1665 | anyContent(value(node)); 1666 | break; 1667 | 1668 | case 'object': 1669 | case 'undefined': 1670 | if (value == null) { 1671 | fastPath = false; 1672 | childNodes = domdiff(node.parentNode, childNodes, [], diffOptions); 1673 | break; 1674 | } 1675 | 1676 | default: 1677 | fastPath = false; 1678 | oldValue = value; 1679 | 1680 | if (isArray(value)) { 1681 | if (value.length === 0) { 1682 | if (childNodes.length) { 1683 | childNodes = domdiff(node.parentNode, childNodes, [], diffOptions); 1684 | } 1685 | } else { 1686 | switch (typeof(value[0])) { 1687 | case 'string': 1688 | case 'number': 1689 | case 'boolean': 1690 | anyContent({ 1691 | html: value 1692 | }); 1693 | break; 1694 | 1695 | case 'object': 1696 | if (isArray(value[0])) { 1697 | value = value.concat.apply([], value); 1698 | } 1699 | 1700 | if (isPromise_ish(value[0])) { 1701 | Promise.all(value).then(anyContent); 1702 | break; 1703 | } 1704 | 1705 | default: 1706 | childNodes = domdiff(node.parentNode, childNodes, value, diffOptions); 1707 | break; 1708 | } 1709 | } 1710 | } else if (canDiff(value)) { 1711 | childNodes = domdiff(node.parentNode, childNodes, value.nodeType === DOCUMENT_FRAGMENT_NODE ? slice.call(value.childNodes) : [value], diffOptions); 1712 | } else if (isPromise_ish(value)) { 1713 | value.then(anyContent); 1714 | } else if ('placeholder' in value) { 1715 | invokeAtDistance(value, anyContent); 1716 | } else if ('text' in value) { 1717 | anyContent(String(value.text)); 1718 | } else if ('any' in value) { 1719 | anyContent(value.any); 1720 | } else if ('html' in value) { 1721 | childNodes = domdiff(node.parentNode, childNodes, slice.call(createContent([].concat(value.html).join(''), nodeType).childNodes), diffOptions); 1722 | } else if ('length' in value) { 1723 | anyContent(slice.call(value)); 1724 | } else { 1725 | anyContent(Intent.invoke(value, anyContent)); 1726 | } 1727 | 1728 | break; 1729 | } 1730 | }; 1731 | 1732 | return anyContent; 1733 | }, 1734 | // style or textareas don't accept HTML as content 1735 | // it's pointless to transform or analyze anything 1736 | // different from text there but it's worth checking 1737 | // for possible defined intents. 1738 | text: function text(node) { 1739 | var oldValue; 1740 | 1741 | var textContent = function textContent(value) { 1742 | if (oldValue !== value) { 1743 | oldValue = value; 1744 | 1745 | var type = typeof(value); 1746 | 1747 | if (type === 'object' && value) { 1748 | if (isPromise_ish(value)) { 1749 | value.then(textContent); 1750 | } else if ('placeholder' in value) { 1751 | invokeAtDistance(value, textContent); 1752 | } else if ('text' in value) { 1753 | textContent(String(value.text)); 1754 | } else if ('any' in value) { 1755 | textContent(value.any); 1756 | } else if ('html' in value) { 1757 | textContent([].concat(value.html).join('')); 1758 | } else if ('length' in value) { 1759 | textContent(slice.call(value).join('')); 1760 | } else { 1761 | textContent(Intent.invoke(value, textContent)); 1762 | } 1763 | } else if (type === 'function') { 1764 | textContent(value(node)); 1765 | } else { 1766 | node.textContent = value == null ? '' : value; 1767 | } 1768 | } 1769 | }; 1770 | 1771 | return textContent; 1772 | } 1773 | }; 1774 | 1775 | var isNoOp = (typeof document === "undefined" ? "undefined" : typeof(document)) !== 'object'; 1776 | 1777 | var _templateLiteral = function templateLiteral(tl) { 1778 | var RAW = 'raw'; 1779 | 1780 | var isBroken = function isBroken(UA) { 1781 | return /(Firefox|Safari)\/(\d+)/.test(UA) && !/(Chrom[eium]+|Android)\/(\d+)/.test(UA); 1782 | }; 1783 | 1784 | var broken = isBroken((document.defaultView.navigator || {}).userAgent); 1785 | var FTS = !(RAW in tl) || tl.propertyIsEnumerable(RAW) || !Object.isFrozen(tl[RAW]); 1786 | 1787 | if (broken || FTS) { 1788 | var forever = {}; 1789 | 1790 | var foreverCache = function foreverCache(tl) { 1791 | for (var key = '.', i = 0; i < tl.length; i++) { 1792 | key += tl[i].length + '.' + tl[i]; 1793 | } 1794 | 1795 | return forever[key] || (forever[key] = tl); 1796 | }; // Fallback TypeScript shenanigans 1797 | 1798 | 1799 | if (FTS) _templateLiteral = foreverCache; // try fast path for other browsers: 1800 | // store the template as WeakMap key 1801 | // and forever cache it only when it's not there. 1802 | // this way performance is still optimal, 1803 | // penalized only when there are GC issues 1804 | else { 1805 | var wm = new WeakMap$1(); 1806 | 1807 | var set = function set(tl, unique) { 1808 | wm.set(tl, unique); 1809 | return unique; 1810 | }; 1811 | 1812 | _templateLiteral = function templateLiteral(tl) { 1813 | return wm.get(tl) || set(tl, foreverCache(tl)); 1814 | }; 1815 | } 1816 | } else { 1817 | isNoOp = true; 1818 | } 1819 | 1820 | return TL(tl); 1821 | }; 1822 | 1823 | function TL(tl) { 1824 | return isNoOp ? tl : _templateLiteral(tl); 1825 | } 1826 | 1827 | function tta (template) { 1828 | var length = arguments.length; 1829 | var args = [TL(template)]; 1830 | var i = 1; 1831 | 1832 | while (i < length) { 1833 | args.push(arguments[i++]); 1834 | } 1835 | 1836 | return args; 1837 | } 1838 | 1839 | var wires = new WeakMap$1(); // A wire is a callback used as tag function 1840 | // to lazily relate a generic object to a template literal. 1841 | // hyper.wire(user)`
${user.name}
`; => the div#user 1842 | // This provides the ability to have a unique DOM structure 1843 | // related to a unique JS object through a reusable template literal. 1844 | // A wire can specify a type, as svg or html, and also an id 1845 | // via html:id or :id convention. Such :id allows same JS objects 1846 | // to be associated to different DOM structures accordingly with 1847 | // the used template literal without losing previously rendered parts. 1848 | 1849 | var wire = function wire(obj, type) { 1850 | return obj == null ? content(type || 'html') : weakly(obj, type || 'html'); 1851 | }; // A wire content is a virtual reference to one or more nodes. 1852 | // It's represented by either a DOM node, or an Array. 1853 | // In both cases, the wire content role is to simply update 1854 | // all nodes through the list of related callbacks. 1855 | // In few words, a wire content is like an invisible parent node 1856 | // in charge of updating its content like a bound element would do. 1857 | 1858 | 1859 | var content = function content(type) { 1860 | var wire, tagger, template; 1861 | return function () { 1862 | var args = tta.apply(null, arguments); 1863 | 1864 | if (template !== args[0]) { 1865 | template = args[0]; 1866 | tagger = new Tagger(type); 1867 | wire = wireContent(tagger.apply(tagger, args)); 1868 | } else { 1869 | tagger.apply(tagger, args); 1870 | } 1871 | 1872 | return wire; 1873 | }; 1874 | }; // wires are weakly created through objects. 1875 | // Each object can have multiple wires associated 1876 | // and this is thanks to the type + :id feature. 1877 | 1878 | 1879 | var weakly = function weakly(obj, type) { 1880 | var i = type.indexOf(':'); 1881 | var wire = wires.get(obj); 1882 | var id = type; 1883 | 1884 | if (-1 < i) { 1885 | id = type.slice(i + 1); 1886 | type = type.slice(0, i) || 'html'; 1887 | } 1888 | 1889 | if (!wire) wires.set(obj, wire = {}); 1890 | return wire[id] || (wire[id] = content(type)); 1891 | }; // A document fragment loses its nodes 1892 | // as soon as it is appended into another node. 1893 | // This has the undesired effect of losing wired content 1894 | // on a second render call, because (by then) the fragment would be empty: 1895 | // no longer providing access to those sub-nodes that ultimately need to 1896 | // stay associated with the original interpolation. 1897 | // To prevent hyperHTML from forgetting about a fragment's sub-nodes, 1898 | // fragments are instead returned as an Array of nodes or, if there's only one entry, 1899 | // as a single referenced node which, unlike fragments, will indeed persist 1900 | // wire content throughout multiple renderings. 1901 | // The initial fragment, at this point, would be used as unique reference to this 1902 | // array of nodes or to this single referenced node. 1903 | 1904 | 1905 | var wireContent = function wireContent(node) { 1906 | var childNodes = node.childNodes; 1907 | var length = childNodes.length; 1908 | return length === 1 ? childNodes[0] : length ? new Wire(childNodes) : node; 1909 | }; 1910 | 1911 | // are already known to hyperHTML 1912 | 1913 | var bewitched = new WeakMap$1(); // better known as hyper.bind(node), the render is 1914 | 1915 | /*! (c) Andrea Giammarchi (ISC) */ 1916 | 1917 | var define = Intent.define; 1918 | // html or svg property of each hyper.Component 1919 | 1920 | setup(content); // everything is exported directly or through the 1921 | 1922 | var defineProperty = Object.defineProperty; 1923 | var gOPD = Object.getOwnPropertyDescriptor; 1924 | var keys$1 = Object.keys; 1925 | var hOP = {}.hasOwnProperty; 1926 | var slice$1 = [].slice; 1927 | var wired = { 1928 | id: 0, 1929 | model: null 1930 | }; // hyper utilities 1931 | function html() { 1932 | return wire(wired.model, 'html:' + wired.id).apply(null, arguments); 1933 | } 1934 | function svg() { 1935 | return wire(wired.model, 'svg:' + wired.id).apply(null, arguments); 1936 | } 1937 | 1938 | function augment(model, update) { 1939 | keys$1(model).forEach(function (key) { 1940 | var value, 1941 | desc = gOPD(model, key); 1942 | 1943 | if (desc.configurable) { 1944 | if ('value' in desc) { 1945 | value = bound(desc.value, model); 1946 | defineProperty(model, key, { 1947 | configurable: true, 1948 | enumerable: true, 1949 | get: function get() { 1950 | return value; 1951 | }, 1952 | set: function set($) { 1953 | value = bound($, model); 1954 | update(model); 1955 | } 1956 | }); 1957 | } else if ('set' in desc) { 1958 | value = desc.set; 1959 | 1960 | desc.set = function ($) { 1961 | value.call(model, $); 1962 | update(model); 1963 | }; 1964 | 1965 | defineProperty(model, key, desc); 1966 | } 1967 | } 1968 | }); 1969 | } 1970 | function merge(model, changes) { 1971 | for (var key in changes) { 1972 | if (hOP.call(changes, key)) { 1973 | var has = hOP.call(model, key); 1974 | var curr = changes[key]; 1975 | var prev = has ? model[key] : null; 1976 | if (has && curr !== null && typeof(curr) === "object") merge(prev, curr);else if (!has || curr !== prev) model[key] = curr; 1977 | } 1978 | } 1979 | } 1980 | function refresh(model, Component, id, args) { 1981 | var wid = wired.id; 1982 | var wmodel = wired.model; 1983 | wired.id = id; 1984 | wired.model = model; 1985 | 1986 | try { 1987 | return Component.apply(null, args); 1988 | } finally { 1989 | wired.id = wid; 1990 | wired.model = wmodel; 1991 | } 1992 | } 1993 | function same(node, i) { 1994 | return this[i] === node[i]; 1995 | } 1996 | 1997 | function bound(value, model) { 1998 | return typeof value === 'function' ? value.bind(model) : value; 1999 | } 2000 | 2001 | /** 2002 | * Copyright (C) 2017-present by Andrea Giammarchi - @WebReflection 2003 | * 2004 | * Permission is hereby granted, free of charge, to any person obtaining a copy 2005 | * of this software and associated documentation files (the "Software"), to deal 2006 | * in the Software without restriction, including without limitation the rights 2007 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2008 | * copies of the Software, and to permit persons to whom the Software is 2009 | * furnished to do so, subject to the following conditions: 2010 | * 2011 | * The above copyright notice and this permission notice shall be included in 2012 | * all copies or substantial portions of the Software. 2013 | * 2014 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2015 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2016 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2017 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2018 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2019 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2020 | * THE SOFTWARE. 2021 | */ 2022 | var replace = ''.replace; 2023 | var ca = /[&<>'"]/g; 2024 | var es = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g; 2025 | var esca = { 2026 | '&': '&', 2027 | '<': '<', 2028 | '>': '>', 2029 | "'": ''', 2030 | '"': '"' 2031 | }; 2032 | var unes = { 2033 | '&': '&', 2034 | '&': '&', 2035 | '<': '<', 2036 | '<': '<', 2037 | '>': '>', 2038 | '>': '>', 2039 | ''': "'", 2040 | ''': "'", 2041 | '"': '"', 2042 | '"': '"' 2043 | }; 2044 | function escape(es) { 2045 | return replace.call(es, ca, pe); 2046 | } 2047 | function unescape(un) { 2048 | return replace.call(un, es, cape); 2049 | } 2050 | 2051 | function pe(m) { 2052 | return esca[m]; 2053 | } 2054 | 2055 | function cape(m) { 2056 | return unes[m]; 2057 | } 2058 | 2059 | var comps = new WeakMap$1(); 2060 | var param = new WeakMap$1(); 2061 | var store = new WeakMap$1(); 2062 | var ids = 0; 2063 | var sync = true; 2064 | function comp(Component) { 2065 | var id = ++ids; 2066 | comps.set(component, id); 2067 | return component; 2068 | 2069 | function component(model) { 2070 | var mod = model || {}; 2071 | var map = store.get(mod) || setMap(mod); 2072 | return updateComponent.call(mod, map.get(component) || setInfo(map, component, Component, id, slice$1.call(arguments, 0))); 2073 | } 2074 | } 2075 | function render(where, comp) { 2076 | var content = comps.has(comp) ? comp(param.get(where) || setParam(where)) : comp(); 2077 | var isElement = content.nodeType === 1; 2078 | 2079 | if (!(isElement && where.firstChild === content || !isElement && content.childNodes.every(same, where.childNodes))) { 2080 | where.textContent = ''; 2081 | where.appendChild(content.valueOf(true)); 2082 | } 2083 | 2084 | return where; 2085 | } 2086 | function update(model, changes) { 2087 | var map = store.get(model); 2088 | if (!map) throw new Error('unknown model'); 2089 | sync = false; 2090 | 2091 | try { 2092 | merge(model, changes || {}); 2093 | } finally { 2094 | sync = true; 2095 | map.forEach(updateComponent, model); 2096 | } 2097 | } 2098 | 2099 | function setInfo(map, comp, Component, id, args) { 2100 | var info = { 2101 | Component: Component, 2102 | id: id, 2103 | args: args 2104 | }; 2105 | map.set(comp, info); 2106 | return info; 2107 | } 2108 | 2109 | function setMap(model) { 2110 | var map = new Map$1(); 2111 | store.set(model, map); 2112 | augment(model, updateAll); 2113 | return map; 2114 | } 2115 | 2116 | function setParam(where) { 2117 | var model = {}; 2118 | param.set(where, model); 2119 | return model; 2120 | } 2121 | 2122 | function updateAll(model) { 2123 | if (sync) store.get(model).forEach(updateComponent, model); 2124 | } 2125 | 2126 | function updateComponent(info) { 2127 | return refresh(this, info.Component, info.id, info.args); 2128 | } 2129 | 2130 | exports.comp = comp; 2131 | exports.define = define; 2132 | exports.escape = escape; 2133 | exports.html = html; 2134 | exports.render = render; 2135 | exports.svg = svg; 2136 | exports.unescape = unescape; 2137 | exports.update = update; 2138 | 2139 | return exports; 2140 | 2141 | }({})); 2142 | -------------------------------------------------------------------------------- /min.js: -------------------------------------------------------------------------------- 1 | /*! (c) Andrea Giammarchi - ISC */ 2 | var hypersimple=function(e){"use strict";var t={};try{t.WeakMap=WeakMap}catch(e){t.WeakMap=function(t,e){var n=e.defineProperty,r=e.hasOwnProperty,i=o.prototype;return i.delete=function(e){return this.has(e)&&delete e[this._]},i.get=function(e){return this.has(e)?e[this._]:void 0},i.has=function(e){return r.call(e,this._)},i.set=function(e,t){return n(e,this._,{configurable:!0,value:t}),this},o;function o(e){n(this,"_",{value:"_@ungap/weakmap"+t++}),e&&e.forEach(a,this)}function a(e){this.set(e[0],e[1])}}(Math.random(),Object)}var s=t.WeakMap,n={};try{n.Map=Map}catch(e){n.Map=function(){var n=0,i=[],o=[];return{delete:function(e){var t=r(e);return t&&(i.splice(n,1),o.splice(n,1)),t},forEach:function(n,r){i.forEach(function(e,t){n.call(r,o[t],e,this)},this)},get:function(e){return r(e)?o[n]:void 0},has:function(e){return r(e)},set:function(e,t){return o[r(e)?n:i.push(e)-1]=t,this}};function r(e){return-1<(n=i.indexOf(e))}}}var v=n.Map,i={};try{i.WeakSet=WeakSet}catch(e){!function(e,t){var n=r.prototype;function r(){t(this,"_",{value:"_@ungap/weakmap"+e++})}n.add=function(e){return this.has(e)||t(e,this._,{value:!0,configurable:!0}),this},n.has=function(e){return this.hasOwnProperty.call(e,this._)},n.delete=function(e){return this.has(e)&&delete e[this._]},i.WeakSet=r}(Math.random(),Object.defineProperty)}function g(e,t,n,r,i,o){for(var a=("selectedIndex"in t),u=a;ra;)--c;l=u+r-c;var g=Array(l),y=s[c];for(--n;y;){for(var b=y.newi,w=y.oldi;b>>0;n"+e+"",r=n.querySelectorAll(i)}else n.innerHTML=e,r=n.childNodes;return F(t,r),t},function(e,t){return("svg"===t?function(e){var t=q(S),n=q("div");return n.innerHTML=''+e+"",F(t,n.firstChild.childNodes),t}:T)(e)});function F(e,t){for(var n=t.length;n--;)e.appendChild(t[0])}function q(e){return e===S?A.createDocumentFragment():A.createElementNS("http://www.w3.org/1999/xhtml",e)}var H,I,z,V,Z,G,B,J,K,Q,U=(H=document,I="appendChild",z="cloneNode",V="createTextNode",G=(Z="importNode")in H,(B=H.createDocumentFragment())[I](H[V]("g")),B[I](H[V]("")),(G?H[Z](B,!0):B[z](!0)).childNodes.length<2?function e(t,n){for(var r=t[z](),i=t.childNodes||[],o=i.length,a=0;n&&a

',J[K].childNodes[0].getAttribute(Q)==Y)||(Y="_dt: "+Y.slice(1,-1)+";",ee=!0)}catch(e){}var te="\x3c!--"+Y+"--\x3e",ne=8,re=1,ie=3,oe=/^(?:style|textarea)$/i,ae=/^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i;var ue=" \\f\\n\\r\\t",ce="[^"+ue+"\\/>\"'=]+",le="["+ue+"]+"+ce,se="<([A-Za-z]+[A-Za-z0-9:._-]*)((?:",fe="(?:\\s*=\\s*(?:'[^']*?'|\"[^\"]*?\"|<[^>]*?>|"+ce.replace("\\/","")+"))?)",de=new RegExp(se+le+fe+"+)(["+ue+"]*/?>)","g"),he=new RegExp(se+le+fe+"*)(["+ue+"]*/>)","g"),ve=new RegExp("("+le+"\\s*=\\s*)(['\"]?)"+te+"\\2","gi");function pe(e,t,n,r){return"<"+t+n.replace(ve,me)+r}function me(e,t,n){return t+(n||'"')+Y+(n||'"')}function ge(e,t,n){return ae.test(t)?e:"<"+t+n+">"}var ye=ee?function(e,t){var n=t.join(" ");return t.slice.call(e,0).sort(function(e,t){return n.indexOf(e.name)<=n.indexOf(t.name)?-1:1})}:function(e,t){return t.slice.call(e,0)};function be(e,t){for(var n=t.length,r=0;r'"]/g,Ct=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g,kt={"&":"&","<":"<",">":">","'":"'",'"':"""},Ot={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'};function At(e){return kt[e]}function St(e){return Ot[e]}var jt=new s,Tt=new s,_t=new s,Mt=0,Pt=!0;function Lt(e){Pt&&_t.get(e).forEach(Dt,e)}function Dt(e){return function(e,t,n,r){var i=bt.id,o=bt.model;bt.id=n,bt.model=e;try{return t.apply(null,r)}finally{bt.id=i,bt.model=o}}(this,e.Component,e.id,e.args)}return e.comp=function(f){var d=++Mt;return jt.set(h,d),h;function h(e){var t,n,r,i,o,a,u,c,l=e||{},s=_t.get(l)||(t=l,n=new v,_t.set(t,n),function(r,i){mt(r).forEach(function(e){var t,n=pt(r,e);n.configurable&&("value"in n?(t=Nt(n.value,r),vt(r,e,{configurable:!0,enumerable:!0,get:function(){return t},set:function(e){t=Nt(e,r),i(r)}})):"set"in n&&(t=n.set,n.set=function(e){t.call(r,e),i(r)},vt(r,e,n)))})}(t,Lt),n);return Dt.call(l,s.get(h)||(r=s,i=h,o=f,a=d,u=yt.call(arguments,0),c={Component:o,id:a,args:u},r.set(i,c),c))}},e.define=ht,e.escape=function(e){return xt.call(e,Et,At)},e.html=function(){return it(bt.model,"html:"+bt.id).apply(null,arguments)},e.render=function(e,t){var n,r,i=jt.has(t)?t(Tt.get(e)||(n=e,r={},Tt.set(n,r),r)):t(),o=1===i.nodeType;return o&&e.firstChild===i||!o&&i.childNodes.every(wt,e.childNodes)||(e.textContent="",e.appendChild(i.valueOf(!0))),e},e.svg=function(){return it(bt.model,"svg:"+bt.id).apply(null,arguments)},e.unescape=function(e){return xt.call(e,Ct,St)},e.update=function(e,t){var n=_t.get(e);if(!n)throw new Error("unknown model");Pt=!1;try{!function e(t,n){for(var r in n)if(gt.call(n,r)){var i=gt.call(t,r),o=n[r],a=i?t[r]:null;i&&null!==o&&"object"==typeof o?e(a,o):i&&o===a||(t[r]=o)}}(e,t||{})}finally{Pt=!0,n.forEach(Dt,e)}},e}({}); 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hypersimple", 3 | "version": "0.4.1", 4 | "description": "The easiest way to use hyperHTML", 5 | "main": "cjs/index.js", 6 | "module": "esm/index.js", 7 | "unpkg": "min.js", 8 | "scripts": { 9 | "build": "npm run cjs && npm run rollup && npm run min && npm run size", 10 | "cjs": "ascjs esm cjs", 11 | "min": "echo '/*! (c) Andrea Giammarchi - ISC */' > min.js && uglifyjs index.js -c -m >> min.js", 12 | "rollup": "rollup --config rollup.config.js && drop-babel-typeof index.js", 13 | "size": "cat index.js | wc -c;cat min.js | wc -c;gzip -c9 min.js | wc -c" 14 | }, 15 | "keywords": [ 16 | "hyperHTML", 17 | "component", 18 | "hooks", 19 | "store" 20 | ], 21 | "author": "Andrea Giammarchi", 22 | "license": "ISC", 23 | "dependencies": { 24 | "@ungap/essential-map": "^0.2.0", 25 | "@ungap/weakmap": "^0.1.4", 26 | "html-escaper": "^2.0.1", 27 | "hyperhtml": "^2.32.2" 28 | }, 29 | "devDependencies": { 30 | "@babel/core": "^7.9.0", 31 | "@babel/preset-env": "^7.9.0", 32 | "ascjs": "^3.1.2", 33 | "drop-babel-typeof": "^1.0.3", 34 | "rollup": "^2.1.0", 35 | "rollup-plugin-babel": "^4.4.0", 36 | "rollup-plugin-node-resolve": "^5.2.0", 37 | "uglify-js": "^3.8.0" 38 | }, 39 | "repository": { 40 | "type": "git", 41 | "url": "git+https://github.com/WebReflection/hypersimple.git" 42 | }, 43 | "bugs": { 44 | "url": "https://github.com/WebReflection/hypersimple/issues" 45 | }, 46 | "homepage": "https://github.com/WebReflection/hypersimple#readme" 47 | } 48 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import resolve from 'rollup-plugin-node-resolve'; 3 | export default { 4 | input: 'esm/index.js', 5 | plugins: [ 6 | resolve({module: true}), 7 | babel({ 8 | runtimeHelpers: true, 9 | presets: ['@babel/preset-env'] 10 | }) 11 | ], 12 | context: 'null', 13 | moduleContext: 'null', 14 | output: { 15 | exports: 'named', 16 | file: 'index.js', 17 | format: 'iife', 18 | name: 'hypersimple' 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | hypersimple 7 | 8 | 59 | 60 | 61 | --------------------------------------------------------------------------------