├── .gitignore
├── .npmignore
├── .npmrc
├── LICENSE
├── README.md
├── async.js
├── cjs
├── async.js
├── index.js
├── package.json
└── x.js
├── es.js
├── esm.js
├── esm
├── async.js
├── index.js
└── x.js
├── index.d.ts
├── index.js
├── min.js
├── min.js.br
├── package.json
├── rollup
├── async.config.js
├── es.config.js
├── esm.config.js
└── index.config.js
├── test
├── async.html
├── button.html
├── children.html
├── click.html
├── collapsible.html
├── counter.mjs
├── effect.html
├── effect2.html
├── index.js
├── indirect.html
├── indirect.mjs
├── issue-10.html
├── issue-37.html
├── lfx.html
├── mixed.html
├── multi-return.html
├── package.json
├── registry.mjs
├── state-counter.html
├── swr.html
├── timer.html
└── use-mo.html
└── uland-head.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .nyc_output
3 | node_modules/
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .nyc_output
3 | .travis.yml
4 | node_modules/
5 | rollup/
6 | test/
7 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) 2020, 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 | # 🦄 µland
2 |
3 | [](https://webreflection.github.io/csp/#-csp-strict)
4 |
5 | 
6 |
7 | **Social Media Photo by [Ben Klea](https://unsplash.com/@benkleaphoto) on [Unsplash](https://unsplash.com/)**
8 |
9 | *micro* land, or *unicorn* land, is a [µhtml](https://github.com/WebReflection/uhtml#readme) take at [neverland](https://github.com/WebReflection/neverland/#readme).
10 |
11 |
12 | ### 📣 Community Announcement
13 |
14 | Please ask questions in the [dedicated discussions repository](https://github.com/WebReflection/discussions), to help the community around this project grow ♥
15 |
16 | ---
17 |
18 | Same API, except the exports are `{Component, render, html, svg}`, where `Component` is a function you can use either as `new Component(...)` or just `Component(...)` which is the equivalent of _neverland_ default export.
19 |
20 | This module exports same utilities via `uland/async`, which is based on `uhooks-dom/async` for asynchronous hooks.
21 |
22 |
23 | ### Announcement
24 |
25 | Are you looking for something even more similar to *React*? Then don't miss [🐪 kaboobie](https://github.com/WebReflection/kaboobie/#readme) out!
26 |
27 | Are you looking for *SSR* components? Then check [🦄 µland-ssr](https://github.com/WebReflection/uland-ssr#readme) out!
28 |
29 |
30 | ## API
31 |
32 | The concept is exactly the same as the _neverland_ one, the `render(...)` accepts a node to render, and either a *component* or a *callback* that returns some content.
33 |
34 | [Live demo](https://codepen.io/WebReflection/pen/dyGvNdg?editors=0010).
35 |
36 | ```js
37 | import {Component, render, html, useState} from 'uland';
38 |
39 | const Counter = Component((initialState) => {
40 | const [count, setCount] = useState(initialState);
41 | return html`
42 | `;
45 | });
46 |
47 | // basic example, show two independent counters
48 | render(document.body, () => html`
49 |
50 | A bounce of counters.
51 | ${Counter(0)} ${Counter(1)}
52 |
53 | `);
54 | ```
55 |
56 | Please [check neverland](https://github.com/WebReflection/neverland/#concept) to know more about this module usage.
57 |
--------------------------------------------------------------------------------
/async.js:
--------------------------------------------------------------------------------
1 | self.uland=function(e){"use strict";function t(e){this.observe(e,{subtree:!0,childList:!0})}function n(e){e.type in this&&this[e.type](e)}let s=null,r=new Set;const a=e=>{const{$:t,r:n,h:s}=e;h(n)&&(l.get(s).delete(e),n()),h(e.r=t())&&l.get(s).add(e)},o=()=>{const e=r;r=new Set,e.forEach((({h:e,c:t,a:n,e:s})=>{s&&e.apply(t,n)}))},l=new WeakMap,c=[],i=[];function u(e,t){return e!==this[t]}const d=()=>s,h=e=>"function"==typeof e,p=e=>{const t={h:n,c:null,a:null,e:0,i:0,s:[]};return n;function n(){const n=s;s=t,t.e=t.i=0;try{return e.apply(t.c=this,t.a=arguments)}finally{s=n,c.length&&f.then(c.forEach.bind(c.splice(0),a)),i.length&&i.splice(0).forEach(a)}}},f=Promise.resolve();function w(e){const{_:t,value:n}=this;n!==e&&(this._=new Set,this.value=e,t.forEach((({h:e,c:t,a:n})=>{e.apply(t,n)})))}const y=(e,t)=>{const n=d(),{i:s,s:r}=n;return s!==r.length&&t&&!t.some(u,r[s]._)||(r[s]={$:e(),_:t}),r[n.i++].$},g=e=>(t,n)=>{const s=d(),{i:r,s:a,h:o}=s,c=r===a.length;s.i++,c&&(l.has(o)||l.set(o,new Set),a[r]={$:t,_:n,r:null,d:!1,h:o}),(c||!n||a[r].d||n.some(u,a[r]._))&&e.push(a[r]),a[r].$=t,a[r]._=n,a[r].d=!1},m=g(c),v=g(i),b=(e,t)=>h(t)?t(e):t,E=(e,t,n)=>{const s=d(),{i:a,s:l}=s;a===l.length&&l.push({$:h(n)?n(t):b(void 0,t),set:t=>{l[a].$=e(l[a].$,t),(e=>{r.has(e)||(e.e=1,r.add(e),f.then(o))})(s)}});const{$:c,set:i}=l[s.i++];return[c,i]},k=new WeakMap,x=e=>(e=>{const t=l.get(e);t&&f.then((()=>{t.forEach((e=>{e.r(),e.r=null,e.d=!0})),t.clear()}))})(k.get(e)),C=e=>(e=>l.has(e))(k.get(e)),N=e=>{const t=p(e);return k.set(n,t),n;async function n(){return await t.apply(this,arguments)}};
2 | /*! (c) Andrea Giammarchi - ISC */
3 | let $=null,M=null,A=null;const S=new WeakMap,T=new WeakMap,_=(e,t,n,s)=>{const r=r=>{S.has(e)||(S.set(e,0),f.then((()=>{S.delete(e),e.apply(t,n)}))),s(r)};return T.set(s,r),r},L=(e,t,n,s)=>e?[s[0],T.get(s[1])||_(e,t,n,s[1])]:s,O=(e,t)=>{const n=N(t?async function(){const[t,s,r]=[$,M,A];[$,M,A]=[n,this,arguments];try{return await e.apply(M,A)}finally{[$,M,A]=[t,s,r]}}:e);return n},W=((e,s,r,a)=>{const o=new WeakMap,l=new WeakMap,c=new WeakMap,i=e=>o.has(e),u=e=>{i(e)&&(d(e,e.removeEventListener,o.get(e)),o.delete(e))},d=(e,t,n)=>{t.call(e,"disconnected",n),t.call(e,"connected",n)},h=(e,t,n,s)=>{for(let{length:r}=e,a=0;a{i(e)&&!n.has(e)&&(a.delete(e),n.set(e,0),e.dispatchEvent(new(r||CustomEvent)(t))),h(e[s||"children"]||[],t,n,a)},f=new(a||MutationObserver)((e=>{for(let{length:t}=e,n=0;n{u(e),(t||(t={})).handleEvent||(t.handleEvent=n),d(e,e.addEventListener,t),o.set(e,t)},disconnect:u,kill(){f.disconnect()}}})(document,"children",CustomEvent),j=({firstChild:e})=>{if(e&&1!==e.nodeType&&!(e=e.nextElementSibling))throw"unobservable";return e},B=e=>{const{nodeType:t}=e;if(t)return 1===t?e:j(e);{const t=e.valueOf();return t!==e?B(t):j(t)}},R=(e,t)=>{const n=O(e,t);return async function(){const e=await n.apply(this,arguments);if(C(n)){const t=B(e);W.has(t)||W.connect(t,{disconnected(){x(n)}})}return e}};var D=e=>({get:t=>e.get(t),set:(t,n)=>(e.set(t,n),n)});const{isArray:z}=Array;class H extends Map{set(e,t){return super.set(e,t),t}}class P extends WeakMap{set(e,t){return super.set(e,t),t}}
4 | /*! (c) Andrea Giammarchi - ISC */const F=/^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i,q=/<([a-z]+[a-z0-9:._-]*)([^>]*?)(\/?)>/g,G=/([^\s\\>"'=]+)\s*=\s*(['"]?)\x01/g,I=/[\x01\x02]/g;const J=(e,t)=>111===e.nodeType?1/t<0?t?(({firstChild:e,lastChild:t})=>{const n=document.createRange();return n.setStartAfter(e),n.setEndAfter(t),n.deleteContents(),e})(e):e.lastChild:t?e.valueOf():e.firstChild:e,K=(e,t)=>{let n,s,r=t.slice(2);return!(t in e)&&(s=t.toLowerCase())in e&&(r=s.slice(2)),t=>{const s=z(t)?t:[t,!1];n!==s[0]&&(n&&e.removeEventListener(r,n,s[1]),(n=s[0])&&e.addEventListener(r,n,s[1]))}};const{isArray:Q,prototype:U}=Array,{indexOf:V}=U,{createDocumentFragment:X,createElement:Y,createElementNS:Z,createTextNode:ee,createTreeWalker:te,importNode:ne}=new Proxy(document,{get:(e,t)=>e[t].bind(e)});let se;const re=(e,t)=>t?(e=>{se||(se=Z("http://www.w3.org/2000/svg","svg")),se.innerHTML=e;const t=X();return t.append(...se.childNodes),t})(e):(e=>{const t=Y("template");return t.innerHTML=e,t.content})(e),ae=({childNodes:e},t)=>e[t],oe=(e,t,n)=>((e,t,n,s,r)=>{const a=n.length;let o=t.length,l=a,c=0,i=0,u=null;for(;cr-i){const a=s(t[c],0);for(;i{switch(t[0]){case"?":return((e,t,n)=>s=>{n!==!!s&&((n=!!s)?e.setAttribute(t,""):e.removeAttribute(t))})(e,t.slice(1),!1);case".":return((e,t)=>"dataset"===t?(({dataset:e})=>t=>{for(const n in t){const s=t[n];null==s?delete e[n]:e[n]=s}})(e):n=>{e[t]=n})(e,t.slice(1));case"@":return K(e,"on"+t.slice(1));case"o":if("n"===t[1])return K(e,t)}switch(t){case"ref":return(e=>{let t;return n=>{t!==n&&(t=n,"function"==typeof n?n(e):n.current=e)}})(e);case"aria":return(e=>t=>{for(const n in t){const s="role"===n?n:`aria-${n}`,r=t[n];null==r?e.removeAttribute(s):e.setAttribute(s,r)}})(e)}return((e,t)=>{let n,s=!0;const r=document.createAttributeNS(null,t);return t=>{if(n!==t)if(n=t,null==n)s||(e.removeAttributeNode(r),s=!0);else{const n=t;null==n?(s||e.removeAttributeNode(r),s=!0):(r.value=n,s&&(e.setAttributeNodeNS(r),s=!1))}}})(e,t)};function ce(e){const{type:t,path:n}=e,s=n.reduceRight(ae,this);return"node"===t?(e=>{let t,n,s=[];const r=a=>{switch(typeof a){case"string":case"number":case"boolean":t!==a&&(t=a,n||(n=ee("")),n.data=a,s=oe(e,s,[n]));break;case"object":case"undefined":if(null==a){t!=a&&(t=a,s=oe(e,s,[]));break}if(Q(a)){t=a,0===a.length?s=oe(e,s,[]):"object"==typeof a[0]?s=oe(e,s,a):r(String(a));break}t!==a&&"ELEMENT_NODE"in a&&(t=a,s=oe(e,s,11===a.nodeType?[...a.childNodes]:[a]));break;case"function":r(a(e))}};return r})(s):"attr"===t?le(s,e.name):(e=>{let t;return n=>{t!=n&&(t=n,e.textContent=null==n?"":n)}})(s)}const ie=e=>{const t=[];let{parentNode:n}=e;for(;n;)t.push(V.call(n.childNodes,e)),e=n,({parentNode:n}=e);return t},ue="isµ",de=new P,he=/^(?:textarea|script|style|title|plaintext|xmp)$/,pe=(e,t)=>{const n="svg"===e,s=((e,t,n)=>{let s=0;return e.join("").trim().replace(q,((e,t,s,r)=>{let a=t+s.replace(G,"=$2$1").trimEnd();return r.length&&(a+=n||F.test(t)?" /":">"+t),"<"+a+">"})).replace(I,(e=>""===e?"\x3c!--"+t+s+++"--\x3e":t+s++))})(t,ue,n),r=re(s,n),a=te(r,129),o=[],l=t.length-1;let c=0,i=`isµ${c}`;for(;c{const{content:n,nodes:s}=de.get(t)||de.set(t,pe(e,t)),r=ne(n,!0);return{content:r,updates:s.map(ce,r)}},we=(e,{type:t,template:n,values:s})=>{const r=ye(e,s);let{entry:a}=e;a&&a.template===n&&a.type===t||(e.entry=a=((e,t)=>{const{content:n,updates:s}=fe(e,t);return{type:e,template:t,content:n,updates:s,wire:null}})(t,n));const{content:o,updates:l,wire:c}=a;for(let e=0;e{const{firstChild:t,lastChild:n}=e;if(t===n)return n||e;const{childNodes:s}=e,r=[...s];return{ELEMENT_NODE:1,nodeType:111,firstChild:t,lastChild:n,valueOf:()=>(s.length!==r.length&&e.append(...r),e)}})(o))},ye=({stack:e},t)=>{const{length:n}=t;for(let s=0;s{const t=new P;return Object.assign(((t,...n)=>new ge(e,t,n)),{for(n,s){const r=t.get(n)||t.set(n,new H);return r.get(s)||r.set(s,(t=>(n,...s)=>we(t,{type:e,template:n,values:s}))({stack:[],entry:null,wire:null}))},node:(t,...n)=>we({stack:[],entry:null,wire:null},new ge(e,t,n)).valueOf()})},ve=new P,be=me("html"),Ee=me("svg"),{create:ke}=Object,xe=(e,...t)=>new ge("html",e,t);xe.for=Oe(be);const Ce=(e,...t)=>new ge("svg",e,t);Ce.for=Oe(Ee);const Ne=D(new WeakMap),$e=(e,t)=>R((async function(){const n=await t.f.apply(this,arguments);return n instanceof ge?(await Se(e,n),t.$=_e(t,n)):t.$=n,t.$})),Me=()=>({s:[],e:null}),Ae=(e,{f:t,c:n,a:s})=>{let{e:r}=e;return r&&r.f===t||(e.e=r={f:t,h:null,$:null},r.h=$e(Me(),r)),r.h.apply(n,s)},Se=async(e,{values:t})=>{await Te(e,t)},Te=async(e,t)=>{const{s:n}=e,{length:s}=t;for(let e=0;e("svg"===t?Ee:be).for(e,t)(n,...s);function Le(e,t,n){this.f=e,this.c=t,this.a=n}function Oe(e){const t=D(new WeakMap);return(n,s)=>{const r=t.get(n)||t.set(n,ke(null)),a=r[s]||(r[s]=Me());return async(t,...r)=>(await Te(a,r),e.for(n,s)(t,...r))}}return e.Component=function(e){return function(){return new Le(e,this,arguments)}},e.createContext=e=>({_:new Set,provide:w,value:e}),e.html=xe,e.render=(e,t)=>(Ne.get(e)||Ne.set(e,{c:Me(),h:R((async function(t){const n=await("function"==typeof t?t():t);return((e,t)=>{const n="function"==typeof t?t():t,s=ve.get(e)||ve.set(e,{stack:[],entry:null,wire:null}),r=n instanceof ge?we(s,n):n;return r!==s.wire&&(s.wire=r,e.replaceChildren(r.valueOf())),e})(e,n instanceof Le?await Ae(this.c,n):(await Se(this.c,n),n))}),e)})).h(t),e.svg=Ce,e.useCallback=(e,t)=>y((()=>e),t),e.useContext=({_:e,value:t})=>(e.add(d()),t),e.useEffect=m,e.useLayoutEffect=v,e.useMemo=y,e.useReducer=(e,t,n)=>L($,M,A,E(e,t,n)),e.useRef=e=>{const t=d(),{i:n,s:s}=t;return n===s.length&&s.push({current:e}),s[t.i++]},e.useState=e=>L($,M,A,(e=>E(b,e))(e))
5 | /*! (c) Andrea Giammarchi - ISC */,e}({});
6 |
--------------------------------------------------------------------------------
/cjs/async.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {hooked} = require('uhooks-dom/async');
3 | const umap = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require('umap'));
4 | const {isArray} = require('uarray');
5 |
6 | const {
7 | Hole,
8 | html: $html,
9 | svg: $svg,
10 | render: $render
11 | } = require('uhtml');
12 |
13 | const {create} = Object;
14 |
15 | const html = (template, ...values) => new Hole('html', template, values);
16 | html.for = createFor($html);
17 |
18 | const svg = (template, ...values) => new Hole('svg', template, values);
19 | svg.for = createFor($svg);
20 |
21 | const cache = umap(new WeakMap);
22 |
23 | const render = (where, what) => (
24 | cache.get(where) || cache.set(where, {
25 | c: createCache(),
26 | h: hooked(
27 | async function (what) {
28 | const value = await (typeof what === 'function' ? what() : what);
29 | return $render(
30 | where,
31 | value instanceof Hook ?
32 | await unroll(this.c, value) :
33 | (await unrollHole(this.c, value), value)
34 | );
35 | },
36 | where
37 | )
38 | })
39 | ).h(what);
40 |
41 | exports.Component = Component;
42 | exports.render = render;
43 | exports.html = html;
44 | exports.svg = svg;
45 |
46 | (m => {
47 | exports.createContext = m.createContext;
48 | exports.useContext = m.useContext;
49 | exports.useCallback = m.useCallback;
50 | exports.useMemo = m.useMemo;
51 | exports.useEffect = m.useEffect;
52 | exports.useLayoutEffect = m.useLayoutEffect;
53 | exports.useReducer = m.useReducer;
54 | exports.useState = m.useState;
55 | exports.useRef = m.useRef;
56 | })(require('uhooks-dom/async'));
57 |
58 | const createHook = (info, entry) => hooked(async function () {
59 | const hole = await entry.f.apply(this, arguments);
60 | if (hole instanceof Hole) {
61 | await unrollHole(info, hole);
62 | entry.$ = view(entry, hole);
63 | }
64 | else
65 | entry.$ = hole;
66 | return entry.$;
67 | });
68 |
69 | const createCache = () => ({s: [], e: null});
70 |
71 | const unroll = (info, {f, c, a}) => {
72 | let {e} = info;
73 | if (!e || e.f !== f) {
74 | info.e = (e = {f, h: null, $: null});
75 | e.h = createHook(createCache(), e);
76 | }
77 | return e.h.apply(c, a);
78 | };
79 |
80 | const unrollHole = async (info, {values}) => {
81 | await unrollValues(info, values);
82 | };
83 |
84 | const unrollValues = async (info, values) => {
85 | const {s} = info, {length} = values;
86 | for (let i = 0; i < length; i++) {
87 | const hook = await values[i];
88 | if (hook instanceof Hook)
89 | values[i] = await unroll(s[i] || (s[i] = createCache()), hook);
90 | else if (hook instanceof Hole)
91 | await unrollHole(s[i] || (s[i] = createCache()), hook);
92 | else if (isArray(hook))
93 | await unrollValues(s[i] || (s[i] = createCache()), hook);
94 | else
95 | s[i] = null;
96 | }
97 | if (length < s.length)
98 | s.splice(length);
99 | };
100 |
101 | const view = (e, {type, template, values}) =>
102 | (type === 'svg' ? $svg : $html)
103 | .for(e, type)(template, ...values);
104 |
105 | function Component(f) {
106 | return function () {
107 | return new Hook(f, this, arguments);
108 | };
109 | }
110 |
111 | function Hook(f, c, a) {
112 | this.f = f;
113 | this.c = c;
114 | this.a = a;
115 | }
116 |
117 | function createFor(uhtml) {
118 | const cache = umap(new WeakMap);
119 | return (
120 | (e, id) => {
121 | const store = cache.get(e) || cache.set(e, create(null));
122 | const info = store[id] || (store[id] = createCache());
123 | return async (template, ...values) => {
124 | await unrollValues(info, values);
125 | return uhtml.for(e, id)(template, ...values);
126 | };
127 | }
128 | );
129 | }
130 |
--------------------------------------------------------------------------------
/cjs/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {hooked} = require('uhooks-dom');
3 | const umap = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require('umap'));
4 | const {isArray} = require('uarray');
5 |
6 | const {
7 | Hole,
8 | html: $html,
9 | svg: $svg,
10 | render: $render
11 | } = require('uhtml');
12 |
13 | const {create} = Object;
14 |
15 | const html = (template, ...values) => new Hole('html', template, values);
16 | html.for = createFor($html);
17 |
18 | const svg = (template, ...values) => new Hole('svg', template, values);
19 | svg.for = createFor($svg);
20 |
21 | const cache = umap(new WeakMap);
22 |
23 | const render = (where, what) => (
24 | cache.get(where) || cache.set(where, {
25 | c: createCache(),
26 | h: hooked(
27 | /*async*/ function (what) {
28 | const value = /*await*/ (typeof what === 'function' ? what() : what);
29 | return $render(
30 | where,
31 | value instanceof Hook ?
32 | /*await*/ unroll(this.c, value) :
33 | (/*await*/ unrollHole(this.c, value), value)
34 | );
35 | },
36 | where
37 | )
38 | })
39 | ).h(what);
40 |
41 | exports.Component = Component;
42 | exports.render = render;
43 | exports.html = html;
44 | exports.svg = svg;
45 |
46 | (m => {
47 | exports.createContext = m.createContext;
48 | exports.useContext = m.useContext;
49 | exports.useCallback = m.useCallback;
50 | exports.useMemo = m.useMemo;
51 | exports.useEffect = m.useEffect;
52 | exports.useLayoutEffect = m.useLayoutEffect;
53 | exports.useReducer = m.useReducer;
54 | exports.useState = m.useState;
55 | exports.useRef = m.useRef;
56 | })(require('uhooks-dom'));
57 |
58 | const createHook = (info, entry) => hooked(/*async*/ function () {
59 | const hole = /*await*/ entry.f.apply(this, arguments);
60 | if (hole instanceof Hole) {
61 | /*await*/ unrollHole(info, hole);
62 | entry.$ = view(entry, hole);
63 | }
64 | else
65 | entry.$ = hole;
66 | return entry.$;
67 | });
68 |
69 | const createCache = () => ({s: [], e: null});
70 |
71 | const unroll = (info, {f, c, a}) => {
72 | let {e} = info;
73 | if (!e || e.f !== f) {
74 | info.e = (e = {f, h: null, $: null});
75 | e.h = createHook(createCache(), e);
76 | }
77 | return e.h.apply(c, a);
78 | };
79 |
80 | const unrollHole = /*async*/ (info, {values}) => {
81 | /*await*/ unrollValues(info, values);
82 | };
83 |
84 | const unrollValues = /*async*/ (info, values) => {
85 | const {s} = info, {length} = values;
86 | for (let i = 0; i < length; i++) {
87 | const hook = /*await*/ values[i];
88 | if (hook instanceof Hook)
89 | values[i] = /*await*/ unroll(s[i] || (s[i] = createCache()), hook);
90 | else if (hook instanceof Hole)
91 | /*await*/ unrollHole(s[i] || (s[i] = createCache()), hook);
92 | else if (isArray(hook))
93 | /*await*/ unrollValues(s[i] || (s[i] = createCache()), hook);
94 | else
95 | s[i] = null;
96 | }
97 | if (length < s.length)
98 | s.splice(length);
99 | };
100 |
101 | const view = (e, {type, template, values}) =>
102 | (type === 'svg' ? $svg : $html)
103 | .for(e, type)(template, ...values);
104 |
105 | function Component(f) {
106 | return function () {
107 | return new Hook(f, this, arguments);
108 | };
109 | }
110 |
111 | function Hook(f, c, a) {
112 | this.f = f;
113 | this.c = c;
114 | this.a = a;
115 | }
116 |
117 | function createFor(uhtml) {
118 | const cache = umap(new WeakMap);
119 | return (
120 | (e, id) => {
121 | const store = cache.get(e) || cache.set(e, create(null));
122 | const info = store[id] || (store[id] = createCache());
123 | return /*async*/ (template, ...values) => {
124 | /*await*/ unrollValues(info, values);
125 | return uhtml.for(e, id)(template, ...values);
126 | };
127 | }
128 | );
129 | }
130 |
--------------------------------------------------------------------------------
/cjs/package.json:
--------------------------------------------------------------------------------
1 | {"type":"commonjs"}
--------------------------------------------------------------------------------
/cjs/x.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {createPragma} = require('jsx2tag');
3 | const {html} = require('./index.js');
4 |
5 | const createElement = createPragma(html);
6 | self.React = {
7 | createElement,
8 | Fragment: createElement
9 | };
10 |
11 | (m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
12 | (require('jsx2tag'));
13 | (m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
14 | (require('./index.js'));
15 |
--------------------------------------------------------------------------------
/es.js:
--------------------------------------------------------------------------------
1 | self.uland=function(e){"use strict";function t(e){this.observe(e,{subtree:!0,childList:!0})}function n(e){e.type in this&&this[e.type](e)}let r=null,s=new Set;const o=e=>{const{$:t,r:n,h:r}=e;p(n)&&(c.get(r).delete(e),n()),p(e.r=t())&&c.get(r).add(e)},l=()=>{const e=s;s=new Set,e.forEach((({h:e,c:t,a:n,e:r})=>{r&&e.apply(t,n)}))},c=new WeakMap,a=[],i=[];function u(e,t){return e!==this[t]}const d=e=>{const t=c.get(e);t&&m.then((()=>{t.forEach((e=>{e.r(),e.r=null,e.d=!0})),t.clear()}))},h=()=>r,f=e=>c.has(e),p=e=>"function"==typeof e,g=e=>{const t={h:n,c:null,a:null,e:0,i:0,s:[]};return n;function n(){const n=r;r=t,t.e=t.i=0;try{return e.apply(t.c=this,t.a=arguments)}finally{r=n,a.length&&m.then(a.forEach.bind(a.splice(0),o)),i.length&&i.splice(0).forEach(o)}}},m=Promise.resolve();function y(e){const{_:t,value:n}=this;n!==e&&(this._=new Set,this.value=e,t.forEach((({h:e,c:t,a:n})=>{e.apply(t,n)})))}const v=(e,t)=>{const n=h(),{i:r,s:s}=n;return r!==s.length&&t&&!t.some(u,s[r]._)||(s[r]={$:e(),_:t}),s[n.i++].$},w=e=>(t,n)=>{const r=h(),{i:s,s:o,h:l}=r,a=s===o.length;r.i++,a&&(c.has(l)||c.set(l,new Set),o[s]={$:t,_:n,r:null,d:!1,h:l}),(a||!n||o[s].d||n.some(u,o[s]._))&&e.push(o[s]),o[s].$=t,o[s]._=n,o[s].d=!1},b=w(a),E=w(i),x=(e,t)=>p(t)?t(e):t,k=(e,t,n)=>{const r=h(),{i:o,s:c}=r;o===c.length&&c.push({$:p(n)?n(t):x(void 0,t),set:t=>{c[o].$=e(c[o].$,t),(e=>{s.has(e)||(e.e=1,s.add(e),m.then(l))})(r)}});const{$:a,set:i}=c[r.i++];return[a,i]};
2 | /*! (c) Andrea Giammarchi - ISC */
3 | let C=null,N=null,$=null;const A=new WeakMap,M=new WeakMap,S=(e,t,n,r)=>{const s=s=>{A.has(e)||(A.set(e,0),m.then((()=>{A.delete(e),e.apply(t,n)}))),r(s)};return M.set(r,s),s},T=(e,t,n,r)=>e?[r[0],M.get(r[1])||S(e,t,n,r[1])]:r,_=(e,t)=>{const n=g(t?function(){const[t,r,s]=[C,N,$];[C,N,$]=[n,this,arguments];try{return e.apply(N,$)}finally{[C,N,$]=[t,r,s]}}:e);return n},L=((e,r,s,o)=>{const l=new WeakMap,c=new WeakMap,a=new WeakMap,i=e=>l.has(e),u=e=>{i(e)&&(d(e,e.removeEventListener,l.get(e)),l.delete(e))},d=(e,t,n)=>{t.call(e,"disconnected",n),t.call(e,"connected",n)},h=(e,t,n,r)=>{for(let{length:s}=e,o=0;o{i(e)&&!n.has(e)&&(o.delete(e),n.set(e,0),e.dispatchEvent(new(s||CustomEvent)(t))),h(e[r||"children"]||[],t,n,o)},p=new(o||MutationObserver)((e=>{for(let{length:t}=e,n=0;n{u(e),(t||(t={})).handleEvent||(t.handleEvent=n),d(e,e.addEventListener,t),l.set(e,t)},disconnect:u,kill(){p.disconnect()}}})(document,"children",CustomEvent),O=({firstChild:e})=>{if(e&&1!==e.nodeType&&!(e=e.nextElementSibling))throw"unobservable";return e},W=e=>{const{nodeType:t}=e;if(t)return 1===t?e:O(e);{const t=e.valueOf();return t!==e?W(t):O(t)}},j=(e,t)=>{const n=_(e,t);return function(){const e=n.apply(this,arguments);if(f(n)){const t=W(e);L.has(t)||L.connect(t,{disconnected(){d(n)}})}return e}};var B=e=>({get:t=>e.get(t),set:(t,n)=>(e.set(t,n),n)});const{isArray:R}=Array;class D extends Map{set(e,t){return super.set(e,t),t}}class z extends WeakMap{set(e,t){return super.set(e,t),t}}
4 | /*! (c) Andrea Giammarchi - ISC */const H=/^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i,P=/<([a-z]+[a-z0-9:._-]*)([^>]*?)(\/?)>/g,F=/([^\s\\>"'=]+)\s*=\s*(['"]?)\x01/g,q=/[\x01\x02]/g;const G=(e,t)=>111===e.nodeType?1/t<0?t?(({firstChild:e,lastChild:t})=>{const n=document.createRange();return n.setStartAfter(e),n.setEndAfter(t),n.deleteContents(),e})(e):e.lastChild:t?e.valueOf():e.firstChild:e,I=(e,t)=>{let n,r,s=t.slice(2);return!(t in e)&&(r=t.toLowerCase())in e&&(s=r.slice(2)),t=>{const r=R(t)?t:[t,!1];n!==r[0]&&(n&&e.removeEventListener(s,n,r[1]),(n=r[0])&&e.addEventListener(s,n,r[1]))}};const{isArray:J,prototype:K}=Array,{indexOf:Q}=K,{createDocumentFragment:U,createElement:V,createElementNS:X,createTextNode:Y,createTreeWalker:Z,importNode:ee}=new Proxy(document,{get:(e,t)=>e[t].bind(e)});let te;const ne=(e,t)=>t?(e=>{te||(te=X("http://www.w3.org/2000/svg","svg")),te.innerHTML=e;const t=U();return t.append(...te.childNodes),t})(e):(e=>{const t=V("template");return t.innerHTML=e,t.content})(e),re=({childNodes:e},t)=>e[t],se=(e,t,n)=>((e,t,n,r,s)=>{const o=n.length;let l=t.length,c=o,a=0,i=0,u=null;for(;as-i){const o=r(t[a],0);for(;i{switch(t[0]){case"?":return((e,t,n)=>r=>{n!==!!r&&((n=!!r)?e.setAttribute(t,""):e.removeAttribute(t))})(e,t.slice(1),!1);case".":return((e,t)=>"dataset"===t?(({dataset:e})=>t=>{for(const n in t){const r=t[n];null==r?delete e[n]:e[n]=r}})(e):n=>{e[t]=n})(e,t.slice(1));case"@":return I(e,"on"+t.slice(1));case"o":if("n"===t[1])return I(e,t)}switch(t){case"ref":return(e=>{let t;return n=>{t!==n&&(t=n,"function"==typeof n?n(e):n.current=e)}})(e);case"aria":return(e=>t=>{for(const n in t){const r="role"===n?n:`aria-${n}`,s=t[n];null==s?e.removeAttribute(r):e.setAttribute(r,s)}})(e)}return((e,t)=>{let n,r=!0;const s=document.createAttributeNS(null,t);return t=>{if(n!==t)if(n=t,null==n)r||(e.removeAttributeNode(s),r=!0);else{const n=t;null==n?(r||e.removeAttributeNode(s),r=!0):(s.value=n,r&&(e.setAttributeNodeNS(s),r=!1))}}})(e,t)};function le(e){const{type:t,path:n}=e,r=n.reduceRight(re,this);return"node"===t?(e=>{let t,n,r=[];const s=o=>{switch(typeof o){case"string":case"number":case"boolean":t!==o&&(t=o,n||(n=Y("")),n.data=o,r=se(e,r,[n]));break;case"object":case"undefined":if(null==o){t!=o&&(t=o,r=se(e,r,[]));break}if(J(o)){t=o,0===o.length?r=se(e,r,[]):"object"==typeof o[0]?r=se(e,r,o):s(String(o));break}t!==o&&"ELEMENT_NODE"in o&&(t=o,r=se(e,r,11===o.nodeType?[...o.childNodes]:[o]));break;case"function":s(o(e))}};return s})(r):"attr"===t?oe(r,e.name):(e=>{let t;return n=>{t!=n&&(t=n,e.textContent=null==n?"":n)}})(r)}const ce=e=>{const t=[];let{parentNode:n}=e;for(;n;)t.push(Q.call(n.childNodes,e)),e=n,({parentNode:n}=e);return t},ae="isµ",ie=new z,ue=/^(?:textarea|script|style|title|plaintext|xmp)$/,de=(e,t)=>{const n="svg"===e,r=((e,t,n)=>{let r=0;return e.join("").trim().replace(P,((e,t,r,s)=>{let o=t+r.replace(F,"=$2$1").trimEnd();return s.length&&(o+=n||H.test(t)?" /":">"+t),"<"+o+">"})).replace(q,(e=>""===e?"\x3c!--"+t+r+++"--\x3e":t+r++))})(t,ae,n),s=ne(r,n),o=Z(s,129),l=[],c=t.length-1;let a=0,i=`isµ${a}`;for(;a{const{content:n,nodes:r}=ie.get(t)||ie.set(t,de(e,t)),s=ee(n,!0);return{content:s,updates:r.map(le,s)}},fe=(e,{type:t,template:n,values:r})=>{const s=pe(e,r);let{entry:o}=e;o&&o.template===n&&o.type===t||(e.entry=o=((e,t)=>{const{content:n,updates:r}=he(e,t);return{type:e,template:t,content:n,updates:r,wire:null}})(t,n));const{content:l,updates:c,wire:a}=o;for(let e=0;e{const{firstChild:t,lastChild:n}=e;if(t===n)return n||e;const{childNodes:r}=e,s=[...r];return{ELEMENT_NODE:1,nodeType:111,firstChild:t,lastChild:n,valueOf:()=>(r.length!==s.length&&e.append(...s),e)}})(l))},pe=({stack:e},t)=>{const{length:n}=t;for(let r=0;r{const t=new z;return Object.assign(((t,...n)=>new ge(e,t,n)),{for(n,r){const s=t.get(n)||t.set(n,new D);return s.get(r)||s.set(r,(t=>(n,...r)=>fe(t,{type:e,template:n,values:r}))({stack:[],entry:null,wire:null}))},node:(t,...n)=>fe({stack:[],entry:null,wire:null},new ge(e,t,n)).valueOf()})},ye=new z,ve=me("html"),we=me("svg"),{create:be}=Object,Ee=(e,...t)=>new ge("html",e,t);Ee.for=_e(ve);const xe=(e,...t)=>new ge("svg",e,t);xe.for=_e(we);const ke=B(new WeakMap),Ce=(e,t)=>j((function(){const n=t.f.apply(this,arguments);return n instanceof ge?(Ae(e,n),t.$=Se(t,n)):t.$=n,t.$})),Ne=()=>({s:[],e:null}),$e=(e,{f:t,c:n,a:r})=>{let{e:s}=e;return s&&s.f===t||(e.e=s={f:t,h:null,$:null},s.h=Ce(Ne(),s)),s.h.apply(n,r)},Ae=(e,{values:t})=>{Me(e,t)},Me=(e,t)=>{const{s:n}=e,{length:r}=t;for(let e=0;e("svg"===t?we:ve).for(e,t)(n,...r);function Te(e,t,n){this.f=e,this.c=t,this.a=n}function _e(e){const t=B(new WeakMap);return(n,r)=>{const s=t.get(n)||t.set(n,be(null)),o=s[r]||(s[r]=Ne());return(t,...s)=>(Me(o,s),e.for(n,r)(t,...s))}}return e.Component=function(e){return function(){return new Te(e,this,arguments)}},e.createContext=e=>({_:new Set,provide:y,value:e}),e.html=Ee,e.render=(e,t)=>(ke.get(e)||ke.set(e,{c:Ne(),h:j((function(t){const n="function"==typeof t?t():t;return((e,t)=>{const n="function"==typeof t?t():t,r=ye.get(e)||ye.set(e,{stack:[],entry:null,wire:null}),s=n instanceof ge?fe(r,n):n;return s!==r.wire&&(r.wire=s,e.replaceChildren(s.valueOf())),e})(e,n instanceof Te?$e(this.c,n):(Ae(this.c,n),n))}),e)})).h(t),e.svg=xe,e.useCallback=(e,t)=>v((()=>e),t),e.useContext=({_:e,value:t})=>(e.add(h()),t),e.useEffect=b,e.useLayoutEffect=E,e.useMemo=v,e.useReducer=(e,t,n)=>T(C,N,$,k(e,t,n)),e.useRef=e=>{const t=h(),{i:n,s:r}=t;return n===r.length&&r.push({current:e}),r[t.i++]},e.useState=e=>T(C,N,$,(e=>k(x,e))(e))
5 | /*! (c) Andrea Giammarchi - ISC */,e}({});
6 |
--------------------------------------------------------------------------------
/esm.js:
--------------------------------------------------------------------------------
1 | function e(e){this.observe(e,{subtree:!0,childList:!0})}function t(e){e.type in this&&this[e.type](e)}let n=null,r=new Set;const s=e=>{const{$:t,r:n,h:r}=e;p(n)&&(l.get(r).delete(e),n()),p(e.r=t())&&l.get(r).add(e)},o=()=>{const e=r;r=new Set,e.forEach((({h:e,c:t,a:n,e:r})=>{r&&e.apply(t,n)}))},l=new WeakMap,c=[],a=[];function i(e,t){return e!==this[t]}const u=e=>{const t=l.get(e);t&&g.then((()=>{t.forEach((e=>{e.r(),e.r=null,e.d=!0})),t.clear()}))},d=()=>n,h=e=>l.has(e),p=e=>"function"==typeof e,f=e=>{const t={h:r,c:null,a:null,e:0,i:0,s:[]};return r;function r(){const r=n;n=t,t.e=t.i=0;try{return e.apply(t.c=this,t.a=arguments)}finally{n=r,c.length&&g.then(c.forEach.bind(c.splice(0),s)),a.length&&a.splice(0).forEach(s)}}},g=Promise.resolve(),m=e=>({_:new Set,provide:w,value:e}),y=({_:e,value:t})=>(e.add(d()),t);function w(e){const{_:t,value:n}=this;n!==e&&(this._=new Set,this.value=e,t.forEach((({h:e,c:t,a:n})=>{e.apply(t,n)})))}const v=(e,t)=>b((()=>e),t),b=(e,t)=>{const n=d(),{i:r,s:s}=n;return r!==s.length&&t&&!t.some(i,s[r]._)||(s[r]={$:e(),_:t}),s[n.i++].$},E=e=>(t,n)=>{const r=d(),{i:s,s:o,h:c}=r,a=s===o.length;r.i++,a&&(l.has(c)||l.set(c,new Set),o[s]={$:t,_:n,r:null,d:!1,h:c}),(a||!n||o[s].d||n.some(i,o[s]._))&&e.push(o[s]),o[s].$=t,o[s]._=n,o[s].d=!1},x=E(c),k=E(a),N=(e,t)=>p(t)?t(e):t,$=(e,t,n)=>{const s=d(),{i:l,s:c}=s;l===c.length&&c.push({$:p(n)?n(t):N(void 0,t),set:t=>{c[l].$=e(c[l].$,t),(e=>{r.has(e)||(e.e=1,r.add(e),g.then(o))})(s)}});const{$:a,set:i}=c[s.i++];return[a,i]},C=e=>{const t=d(),{i:n,s:r}=t;return n===r.length&&r.push({current:e}),r[t.i++]};
2 | /*! (c) Andrea Giammarchi - ISC */
3 | let A=null,M=null,S=null;const T=new WeakMap,_=new WeakMap,O=(e,t,n,r)=>{const s=s=>{T.has(e)||(T.set(e,0),g.then((()=>{T.delete(e),e.apply(t,n)}))),r(s)};return _.set(r,s),s},L=(e,t,n,r)=>e?[r[0],_.get(r[1])||O(e,t,n,r[1])]:r,W=(e,t)=>{const n=f(t?function(){const[t,r,s]=[A,M,S];[A,M,S]=[n,this,arguments];try{return e.apply(M,S)}finally{[A,M,S]=[t,r,s]}}:e);return n},j=(e,t,n)=>L(A,M,S,$(e,t,n)),B=e=>L(A,M,S,(e=>$(N,e))(e))
4 | /*! (c) Andrea Giammarchi - ISC */,D=((n,r,s,o)=>{const l=new WeakMap,c=new WeakMap,a=new WeakMap,i=e=>l.has(e),u=e=>{i(e)&&(d(e,e.removeEventListener,l.get(e)),l.delete(e))},d=(e,t,n)=>{t.call(e,"disconnected",n),t.call(e,"connected",n)},h=(e,t,n,r)=>{for(let{length:s}=e,o=0;o{i(e)&&!n.has(e)&&(o.delete(e),n.set(e,0),e.dispatchEvent(new(s||CustomEvent)(t))),h(e[r||"children"]||[],t,n,o)},f=new(o||MutationObserver)((e=>{for(let{length:t}=e,n=0;n{u(e),(n||(n={})).handleEvent||(n.handleEvent=t),d(e,e.addEventListener,n),l.set(e,n)},disconnect:u,kill(){f.disconnect()}}})(document,"children",CustomEvent),z=({firstChild:e})=>{if(e&&1!==e.nodeType&&!(e=e.nextElementSibling))throw"unobservable";return e},H=e=>{const{nodeType:t}=e;if(t)return 1===t?e:z(e);{const t=e.valueOf();return t!==e?H(t):z(t)}},P=(e,t)=>{const n=W(e,t);return function(){const e=n.apply(this,arguments);if(h(n)){const t=H(e);D.has(t)||D.connect(t,{disconnected(){u(n)}})}return e}};var R=e=>({get:t=>e.get(t),set:(t,n)=>(e.set(t,n),n)});const{isArray:F}=Array;class q extends Map{set(e,t){return super.set(e,t),t}}class G extends WeakMap{set(e,t){return super.set(e,t),t}}
5 | /*! (c) Andrea Giammarchi - ISC */const I=/^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i,J=/<([a-z]+[a-z0-9:._-]*)([^>]*?)(\/?)>/g,K=/([^\s\\>"'=]+)\s*=\s*(['"]?)\x01/g,Q=/[\x01\x02]/g;const U=(e,t)=>111===e.nodeType?1/t<0?t?(({firstChild:e,lastChild:t})=>{const n=document.createRange();return n.setStartAfter(e),n.setEndAfter(t),n.deleteContents(),e})(e):e.lastChild:t?e.valueOf():e.firstChild:e,V=(e,t)=>{let n,r,s=t.slice(2);return!(t in e)&&(r=t.toLowerCase())in e&&(s=r.slice(2)),t=>{const r=F(t)?t:[t,!1];n!==r[0]&&(n&&e.removeEventListener(s,n,r[1]),(n=r[0])&&e.addEventListener(s,n,r[1]))}};const{isArray:X,prototype:Y}=Array,{indexOf:Z}=Y,{createDocumentFragment:ee,createElement:te,createElementNS:ne,createTextNode:re,createTreeWalker:se,importNode:oe}=new Proxy(document,{get:(e,t)=>e[t].bind(e)});let le;const ce=(e,t)=>t?(e=>{le||(le=ne("http://www.w3.org/2000/svg","svg")),le.innerHTML=e;const t=ee();return t.append(...le.childNodes),t})(e):(e=>{const t=te("template");return t.innerHTML=e,t.content})(e),ae=({childNodes:e},t)=>e[t],ie=(e,t,n)=>((e,t,n,r,s)=>{const o=n.length;let l=t.length,c=o,a=0,i=0,u=null;for(;as-i){const o=r(t[a],0);for(;i{switch(t[0]){case"?":return((e,t,n)=>r=>{n!==!!r&&((n=!!r)?e.setAttribute(t,""):e.removeAttribute(t))})(e,t.slice(1),!1);case".":return((e,t)=>"dataset"===t?(({dataset:e})=>t=>{for(const n in t){const r=t[n];null==r?delete e[n]:e[n]=r}})(e):n=>{e[t]=n})(e,t.slice(1));case"@":return V(e,"on"+t.slice(1));case"o":if("n"===t[1])return V(e,t)}switch(t){case"ref":return(e=>{let t;return n=>{t!==n&&(t=n,"function"==typeof n?n(e):n.current=e)}})(e);case"aria":return(e=>t=>{for(const n in t){const r="role"===n?n:`aria-${n}`,s=t[n];null==s?e.removeAttribute(r):e.setAttribute(r,s)}})(e)}return((e,t)=>{let n,r=!0;const s=document.createAttributeNS(null,t);return t=>{if(n!==t)if(n=t,null==n)r||(e.removeAttributeNode(s),r=!0);else{const n=t;null==n?(r||e.removeAttributeNode(s),r=!0):(s.value=n,r&&(e.setAttributeNodeNS(s),r=!1))}}})(e,t)};function de(e){const{type:t,path:n}=e,r=n.reduceRight(ae,this);return"node"===t?(e=>{let t,n,r=[];const s=o=>{switch(typeof o){case"string":case"number":case"boolean":t!==o&&(t=o,n||(n=re("")),n.data=o,r=ie(e,r,[n]));break;case"object":case"undefined":if(null==o){t!=o&&(t=o,r=ie(e,r,[]));break}if(X(o)){t=o,0===o.length?r=ie(e,r,[]):"object"==typeof o[0]?r=ie(e,r,o):s(String(o));break}t!==o&&"ELEMENT_NODE"in o&&(t=o,r=ie(e,r,11===o.nodeType?[...o.childNodes]:[o]));break;case"function":s(o(e))}};return s})(r):"attr"===t?ue(r,e.name):(e=>{let t;return n=>{t!=n&&(t=n,e.textContent=null==n?"":n)}})(r)}const he=e=>{const t=[];let{parentNode:n}=e;for(;n;)t.push(Z.call(n.childNodes,e)),e=n,({parentNode:n}=e);return t},pe=new G,fe=/^(?:textarea|script|style|title|plaintext|xmp)$/,ge=(e,t)=>{const n="svg"===e,r=((e,t,n)=>{let r=0;return e.join("").trim().replace(J,((e,t,r,s)=>{let o=t+r.replace(K,"=$2$1").trimEnd();return s.length&&(o+=n||I.test(t)?" /":">"+t),"<"+o+">"})).replace(Q,(e=>""===e?"\x3c!--"+t+r+++"--\x3e":t+r++))})(t,"isµ",n),s=ce(r,n),o=se(s,129),l=[],c=t.length-1;let a=0,i=`isµ${a}`;for(;a{const{content:n,nodes:r}=pe.get(t)||pe.set(t,ge(e,t)),s=oe(n,!0);return{content:s,updates:r.map(de,s)}},ye=(e,{type:t,template:n,values:r})=>{const s=we(e,r);let{entry:o}=e;o&&o.template===n&&o.type===t||(e.entry=o=((e,t)=>{const{content:n,updates:r}=me(e,t);return{type:e,template:t,content:n,updates:r,wire:null}})(t,n));const{content:l,updates:c,wire:a}=o;for(let e=0;e{const{firstChild:t,lastChild:n}=e;if(t===n)return n||e;const{childNodes:r}=e,s=[...r];return{ELEMENT_NODE:1,nodeType:111,firstChild:t,lastChild:n,valueOf:()=>(r.length!==s.length&&e.append(...s),e)}})(l))},we=({stack:e},t)=>{const{length:n}=t;for(let r=0;r{const t=new G;return Object.assign(((t,...n)=>new ve(e,t,n)),{for(n,r){const s=t.get(n)||t.set(n,new q);return s.get(r)||s.set(r,(t=>(n,...r)=>ye(t,{type:e,template:n,values:r}))({stack:[],entry:null,wire:null}))},node:(t,...n)=>ye({stack:[],entry:null,wire:null},new ve(e,t,n)).valueOf()})},Ee=new G,xe=be("html"),ke=be("svg"),{create:Ne}=Object,$e=(e,...t)=>new ve("html",e,t);$e.for=De(xe);const Ce=(e,...t)=>new ve("svg",e,t);Ce.for=De(ke);const Ae=R(new WeakMap),Me=(e,t)=>(Ae.get(e)||Ae.set(e,{c:Te(),h:P((function(t){const n="function"==typeof t?t():t;return((e,t)=>{const n="function"==typeof t?t():t,r=Ee.get(e)||Ee.set(e,{stack:[],entry:null,wire:null}),s=n instanceof ve?ye(r,n):n;return s!==r.wire&&(r.wire=s,e.replaceChildren(s.valueOf())),e})(e,n instanceof Be?_e(this.c,n):(Oe(this.c,n),n))}),e)})).h(t),Se=(e,t)=>P((function(){const n=t.f.apply(this,arguments);return n instanceof ve?(Oe(e,n),t.$=We(t,n)):t.$=n,t.$})),Te=()=>({s:[],e:null}),_e=(e,{f:t,c:n,a:r})=>{let{e:s}=e;return s&&s.f===t||(e.e=s={f:t,h:null,$:null},s.h=Se(Te(),s)),s.h.apply(n,r)},Oe=(e,{values:t})=>{Le(e,t)},Le=(e,t)=>{const{s:n}=e,{length:r}=t;for(let e=0;e("svg"===t?ke:xe).for(e,t)(n,...r);function je(e){return function(){return new Be(e,this,arguments)}}function Be(e,t,n){this.f=e,this.c=t,this.a=n}function De(e){const t=R(new WeakMap);return(n,r)=>{const s=t.get(n)||t.set(n,Ne(null)),o=s[r]||(s[r]=Te());return(t,...s)=>(Le(o,s),e.for(n,r)(t,...s))}}export{je as Component,m as createContext,$e as html,Me as render,Ce as svg,v as useCallback,y as useContext,x as useEffect,k as useLayoutEffect,b as useMemo,j as useReducer,C as useRef,B as useState};
6 |
--------------------------------------------------------------------------------
/esm/async.js:
--------------------------------------------------------------------------------
1 | import {hooked} from 'uhooks-dom/async';
2 | import umap from 'umap';
3 | import {isArray} from 'uarray';
4 |
5 | import {
6 | Hole,
7 | html as $html,
8 | svg as $svg,
9 | render as $render
10 | } from 'uhtml';
11 |
12 | const {create} = Object;
13 |
14 | const html = (template, ...values) => new Hole('html', template, values);
15 | html.for = createFor($html);
16 |
17 | const svg = (template, ...values) => new Hole('svg', template, values);
18 | svg.for = createFor($svg);
19 |
20 | const cache = umap(new WeakMap);
21 |
22 | const render = (where, what) => (
23 | cache.get(where) || cache.set(where, {
24 | c: createCache(),
25 | h: hooked(
26 | async function (what) {
27 | const value = await (typeof what === 'function' ? what() : what);
28 | return $render(
29 | where,
30 | value instanceof Hook ?
31 | await unroll(this.c, value) :
32 | (await unrollHole(this.c, value), value)
33 | );
34 | },
35 | where
36 | )
37 | })
38 | ).h(what);
39 |
40 | export {Component, render, html, svg};
41 |
42 | export {
43 | createContext, useContext,
44 | useCallback, useMemo,
45 | useEffect, useLayoutEffect,
46 | useReducer, useState, useRef
47 | } from 'uhooks-dom/async';
48 |
49 | const createHook = (info, entry) => hooked(async function () {
50 | const hole = await entry.f.apply(this, arguments);
51 | if (hole instanceof Hole) {
52 | await unrollHole(info, hole);
53 | entry.$ = view(entry, hole);
54 | }
55 | else
56 | entry.$ = hole;
57 | return entry.$;
58 | });
59 |
60 | const createCache = () => ({s: [], e: null});
61 |
62 | const unroll = (info, {f, c, a}) => {
63 | let {e} = info;
64 | if (!e || e.f !== f) {
65 | info.e = (e = {f, h: null, $: null});
66 | e.h = createHook(createCache(), e);
67 | }
68 | return e.h.apply(c, a);
69 | };
70 |
71 | const unrollHole = async (info, {values}) => {
72 | await unrollValues(info, values);
73 | };
74 |
75 | const unrollValues = async (info, values) => {
76 | const {s} = info, {length} = values;
77 | for (let i = 0; i < length; i++) {
78 | const hook = await values[i];
79 | if (hook instanceof Hook)
80 | values[i] = await unroll(s[i] || (s[i] = createCache()), hook);
81 | else if (hook instanceof Hole)
82 | await unrollHole(s[i] || (s[i] = createCache()), hook);
83 | else if (isArray(hook))
84 | await unrollValues(s[i] || (s[i] = createCache()), hook);
85 | else
86 | s[i] = null;
87 | }
88 | if (length < s.length)
89 | s.splice(length);
90 | };
91 |
92 | const view = (e, {type, template, values}) =>
93 | (type === 'svg' ? $svg : $html)
94 | .for(e, type)(template, ...values);
95 |
96 | function Component(f) {
97 | return function () {
98 | return new Hook(f, this, arguments);
99 | };
100 | }
101 |
102 | function Hook(f, c, a) {
103 | this.f = f;
104 | this.c = c;
105 | this.a = a;
106 | }
107 |
108 | function createFor(uhtml) {
109 | const cache = umap(new WeakMap);
110 | return (
111 | (e, id) => {
112 | const store = cache.get(e) || cache.set(e, create(null));
113 | const info = store[id] || (store[id] = createCache());
114 | return async (template, ...values) => {
115 | await unrollValues(info, values);
116 | return uhtml.for(e, id)(template, ...values);
117 | };
118 | }
119 | );
120 | }
121 |
--------------------------------------------------------------------------------
/esm/index.js:
--------------------------------------------------------------------------------
1 | import {hooked} from 'uhooks-dom';
2 | import umap from 'umap';
3 | import {isArray} from 'uarray';
4 |
5 | import {
6 | Hole,
7 | html as $html,
8 | svg as $svg,
9 | render as $render
10 | } from 'uhtml';
11 |
12 | const {create} = Object;
13 |
14 | const html = (template, ...values) => new Hole('html', template, values);
15 | html.for = createFor($html);
16 |
17 | const svg = (template, ...values) => new Hole('svg', template, values);
18 | svg.for = createFor($svg);
19 |
20 | const cache = umap(new WeakMap);
21 |
22 | const render = (where, what) => (
23 | cache.get(where) || cache.set(where, {
24 | c: createCache(),
25 | h: hooked(
26 | /*async*/ function (what) {
27 | const value = /*await*/ (typeof what === 'function' ? what() : what);
28 | return $render(
29 | where,
30 | value instanceof Hook ?
31 | /*await*/ unroll(this.c, value) :
32 | (/*await*/ unrollHole(this.c, value), value)
33 | );
34 | },
35 | where
36 | )
37 | })
38 | ).h(what);
39 |
40 | export {Component, render, html, svg};
41 |
42 | export {
43 | createContext, useContext,
44 | useCallback, useMemo,
45 | useEffect, useLayoutEffect,
46 | useReducer, useState, useRef
47 | } from 'uhooks-dom';
48 |
49 | const createHook = (info, entry) => hooked(/*async*/ function () {
50 | const hole = /*await*/ entry.f.apply(this, arguments);
51 | if (hole instanceof Hole) {
52 | /*await*/ unrollHole(info, hole);
53 | entry.$ = view(entry, hole);
54 | }
55 | else
56 | entry.$ = hole;
57 | return entry.$;
58 | });
59 |
60 | const createCache = () => ({s: [], e: null});
61 |
62 | const unroll = (info, {f, c, a}) => {
63 | let {e} = info;
64 | if (!e || e.f !== f) {
65 | info.e = (e = {f, h: null, $: null});
66 | e.h = createHook(createCache(), e);
67 | }
68 | return e.h.apply(c, a);
69 | };
70 |
71 | const unrollHole = /*async*/ (info, {values}) => {
72 | /*await*/ unrollValues(info, values);
73 | };
74 |
75 | const unrollValues = /*async*/ (info, values) => {
76 | const {s} = info, {length} = values;
77 | for (let i = 0; i < length; i++) {
78 | const hook = /*await*/ values[i];
79 | if (hook instanceof Hook)
80 | values[i] = /*await*/ unroll(s[i] || (s[i] = createCache()), hook);
81 | else if (hook instanceof Hole)
82 | /*await*/ unrollHole(s[i] || (s[i] = createCache()), hook);
83 | else if (isArray(hook))
84 | /*await*/ unrollValues(s[i] || (s[i] = createCache()), hook);
85 | else
86 | s[i] = null;
87 | }
88 | if (length < s.length)
89 | s.splice(length);
90 | };
91 |
92 | const view = (e, {type, template, values}) =>
93 | (type === 'svg' ? $svg : $html)
94 | .for(e, type)(template, ...values);
95 |
96 | function Component(f) {
97 | return function () {
98 | return new Hook(f, this, arguments);
99 | };
100 | }
101 |
102 | function Hook(f, c, a) {
103 | this.f = f;
104 | this.c = c;
105 | this.a = a;
106 | }
107 |
108 | function createFor(uhtml) {
109 | const cache = umap(new WeakMap);
110 | return (
111 | (e, id) => {
112 | const store = cache.get(e) || cache.set(e, create(null));
113 | const info = store[id] || (store[id] = createCache());
114 | return /*async*/ (template, ...values) => {
115 | /*await*/ unrollValues(info, values);
116 | return uhtml.for(e, id)(template, ...values);
117 | };
118 | }
119 | );
120 | }
121 |
--------------------------------------------------------------------------------
/esm/x.js:
--------------------------------------------------------------------------------
1 | import {createPragma} from 'jsx2tag';
2 | import {html} from './index.js';
3 |
4 | const createElement = createPragma(html);
5 | self.React = {
6 | createElement,
7 | Fragment: createElement
8 | };
9 |
10 | export * from 'jsx2tag';
11 | export * from './index.js';
12 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {{
3 | * (...args: any[]): Hole;
4 | * for: (entry: IEntry, id?: string) => (...args: any[]) => any
5 | * }} IRenderer
6 | */
7 | /**
8 | * @type {IRenderer}
9 | */
10 | export function html(...args: any[]): Hole;
11 | export namespace html { }
12 | /**
13 | * @type {IRenderer}
14 | */
15 | export function svg(...args: any[]): Hole;
16 | export namespace svg { }
17 | export function Component(fn: (...args: Args[]) => unknown): (...args: Args[]) => Hook;
18 | export function render(where: Node, what: any): Node;
19 | export type IRenderer = {
20 | (...args: any[]): Hole;
21 | for: (entry: IEntry, id?: string) => (...args: any[]) => any;
22 | };
23 | export type ITagFunction = (template: TemplateStringsArray, ...values: any[]) => K;
24 | /**
25 | * An interface describing hooks counter
26 | */
27 | export type ICounter = {
28 | a: number;
29 | aLength: number;
30 | i: number;
31 | iLength: number;
32 | };
33 | /**
34 | * An interface describing hooks info
35 | */
36 | export type IInfo = {
37 | sub?: IInfo[];
38 | stack: IEntry[];
39 | };
40 | export type IEntry = {
41 | hook: any;
42 | fn: any;
43 | };
44 | export type CacheFn = (wm: any, key: any, value: T) => T;
45 | import { Hole } from "lighterhtml";
46 | /**
47 | * @class
48 | * @param {Function} fn
49 | * @param {any[]} args
50 | */
51 | declare function Hook(fn: Function, args: any[]): void;
52 | declare class Hook {
53 | /**
54 | * @class
55 | * @param {Function} fn
56 | * @param {any[]} args
57 | */
58 | constructor(fn: Function, args: any[]);
59 | fn: Function;
60 | args: any[];
61 | }
62 | export { useState, useEffect, useContext, createContext, useRef, useReducer, useCallback, useMemo, useLayoutEffect } from "uhooks-dom";
63 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | self.uland = (function (exports) {
2 | 'use strict';
3 |
4 | /**
5 | * @typedef {Object} Handler an object that handle events.
6 | * @property {(event: Event) => void} connected an optional method triggered when node is connected.
7 | * @property {(event: Event) => void} disconnected an optional method triggered when node is disconnected.
8 | */
9 |
10 | /**
11 | * @typedef {Object} UConnect an utility to connect or disconnect nodes to observe.
12 | * @property {(node: Node, handler?: Handler) => void} connect a method to start observing a generic Node.
13 | * @property {(node: Node) => void} disconnect a method to stop observing a generic Node.
14 | * @property {() => void} kill a method to kill/disconnect the MutationObserver.
15 | */
16 |
17 | /**
18 | * Attach a MutationObserver to a generic node and returns a UConnect instance.
19 | * @param {Node} root a DOM node to observe for mutations.
20 | * @param {string} parse the kind of nodes to parse: children, by default, or childNodes.
21 | * @param {Event} CE an Event/CustomEvent constructor (polyfilled in SSR).
22 | * @param {MutationObserver} MO a MutationObserver constructor (polyfilled in SSR).
23 | * @returns {UConnect} an utility to connect or disconnect nodes to observe.
24 | */
25 | const observe = (root, parse, CE, MO) => {
26 | const observed = new WeakMap;
27 |
28 | // these two should be WeakSet but IE11 happens
29 | const wmin = new WeakMap;
30 | const wmout = new WeakMap;
31 |
32 | const has = node => observed.has(node);
33 | const disconnect = node => {
34 | if (has(node)) {
35 | listener(node, node.removeEventListener, observed.get(node));
36 | observed.delete(node);
37 | }
38 | };
39 | const connect = (node, handler) => {
40 | disconnect(node);
41 | if (!(handler || (handler = {})).handleEvent)
42 | handler.handleEvent = handleEvent;
43 | listener(node, node.addEventListener, handler);
44 | observed.set(node, handler);
45 | };
46 |
47 | const listener = (node, method, handler) => {
48 | method.call(node, 'disconnected', handler);
49 | method.call(node, 'connected', handler);
50 | };
51 |
52 | const notifyObserved = (nodes, type, wmin, wmout) => {
53 | for (let {length} = nodes, i = 0; i < length; i++)
54 | notifyTarget(nodes[i], type, wmin, wmout);
55 | };
56 |
57 | const notifyTarget = (node, type, wmin, wmout) => {
58 | if (has(node) && !wmin.has(node)) {
59 | wmout.delete(node);
60 | wmin.set(node, 0);
61 | node.dispatchEvent(new (CE || CustomEvent)(type));
62 | }
63 | notifyObserved(node[parse || 'children'] || [], type, wmin, wmout);
64 | };
65 |
66 | const mo = new (MO || MutationObserver)(nodes => {
67 | for (let {length} = nodes, i = 0; i < length; i++) {
68 | const {removedNodes, addedNodes} = nodes[i];
69 | notifyObserved(removedNodes, 'disconnected', wmout, wmin);
70 | notifyObserved(addedNodes, 'connected', wmin, wmout);
71 | }
72 | });
73 |
74 | mo.add = add;
75 | mo.add(root || document);
76 |
77 | const {attachShadow} = Element.prototype;
78 | if (attachShadow)
79 | Element.prototype.attachShadow = function (init) {
80 | const sd = attachShadow.call(this, init);
81 | mo.add(sd);
82 | return sd;
83 | };
84 |
85 | return {has, connect, disconnect, kill() { mo.disconnect(); }};
86 | };
87 |
88 | function add(node) {
89 | this.observe(node, {subtree: true, childList: true});
90 | }
91 |
92 | function handleEvent(event) {
93 | if (event.type in this)
94 | this[event.type](event);
95 | }
96 |
97 | let info = null, schedule = new Set;
98 |
99 | const invoke = effect => {
100 | const {$, r, h} = effect;
101 | if (isFunction(r)) {
102 | fx$1.get(h).delete(effect);
103 | r();
104 | }
105 | if (isFunction(effect.r = $()))
106 | fx$1.get(h).add(effect);
107 | };
108 |
109 | const runSchedule = () => {
110 | const previous = schedule;
111 | schedule = new Set;
112 | previous.forEach(({h, c, a, e}) => {
113 | // avoid running schedules when the hook is
114 | // re-executed before such schedule happens
115 | if (e)
116 | h.apply(c, a);
117 | });
118 | };
119 |
120 | const fx$1 = new WeakMap;
121 | const effects = [];
122 | const layoutEffects = [];
123 |
124 | function different(value, i) {
125 | return value !== this[i];
126 | }
127 | const dropEffect = hook => {
128 | const effects = fx$1.get(hook);
129 | if (effects)
130 | wait.then(() => {
131 | effects.forEach(effect => {
132 | effect.r();
133 | effect.r = null;
134 | effect.d = true;
135 | });
136 | effects.clear();
137 | });
138 | };
139 |
140 | const getInfo = () => info;
141 |
142 | const hasEffect = hook => fx$1.has(hook);
143 |
144 | const isFunction = f => typeof f === 'function';
145 |
146 | const hooked$2 = callback => {
147 | const current = {h: hook, c: null, a: null, e: 0, i: 0, s: []};
148 | return hook;
149 | function hook() {
150 | const prev = info;
151 | info = current;
152 | current.e = current.i = 0;
153 | try {
154 | return callback.apply(current.c = this, current.a = arguments);
155 | }
156 | finally {
157 | info = prev;
158 | if (effects.length)
159 | wait.then(effects.forEach.bind(effects.splice(0), invoke));
160 | if (layoutEffects.length)
161 | layoutEffects.splice(0).forEach(invoke);
162 | }
163 | }
164 | };
165 |
166 | const reschedule = info => {
167 | if (!schedule.has(info)) {
168 | info.e = 1;
169 | schedule.add(info);
170 | wait.then(runSchedule);
171 | }
172 | };
173 |
174 | const wait = Promise.resolve();
175 |
176 | const createContext = value => ({
177 | _: new Set,
178 | provide,
179 | value
180 | });
181 |
182 | const useContext = ({_, value}) => {
183 | _.add(getInfo());
184 | return value;
185 | };
186 |
187 | function provide(newValue) {
188 | const {_, value} = this;
189 | if (value !== newValue) {
190 | this._ = new Set;
191 | this.value = newValue;
192 | _.forEach(({h, c, a}) => {
193 | h.apply(c, a);
194 | });
195 | }
196 | }
197 |
198 | const useCallback = (fn, guards) => useMemo(() => fn, guards);
199 |
200 | const useMemo = (memo, guards) => {
201 | const info = getInfo();
202 | const {i, s} = info;
203 | if (i === s.length || !guards || guards.some(different, s[i]._))
204 | s[i] = {$: memo(), _: guards};
205 | return s[info.i++].$;
206 | };
207 |
208 | const createEffect = stack => (callback, guards) => {
209 | const info = getInfo();
210 | const {i, s, h} = info;
211 | const call = i === s.length;
212 | info.i++;
213 | if (call) {
214 | if (!fx$1.has(h))
215 | fx$1.set(h, new Set);
216 | s[i] = {$: callback, _: guards, r: null, d: false, h};
217 | }
218 | if (call || !guards || s[i].d || guards.some(different, s[i]._))
219 | stack.push(s[i]);
220 | s[i].$ = callback;
221 | s[i]._ = guards;
222 | s[i].d = false;
223 | };
224 |
225 | const useEffect = createEffect(effects);
226 |
227 | const useLayoutEffect = createEffect(layoutEffects);
228 |
229 | const getValue = (value, f) => isFunction(f) ? f(value) : f;
230 |
231 | const useReducer$1 = (reducer, value, init) => {
232 | const info = getInfo();
233 | const {i, s} = info;
234 | if (i === s.length)
235 | s.push({
236 | $: isFunction(init) ?
237 | init(value) : getValue(void 0, value),
238 | set: value => {
239 | s[i].$ = reducer(s[i].$, value);
240 | reschedule(info);
241 | }
242 | });
243 | const {$, set} = s[info.i++];
244 | return [$, set];
245 | };
246 |
247 | const useState$1 = value => useReducer$1(getValue, value);
248 |
249 | const useRef = current => {
250 | const info = getInfo();
251 | const {i, s} = info;
252 | if (i === s.length)
253 | s.push({current});
254 | return s[info.i++];
255 | };
256 |
257 | /*! (c) Andrea Giammarchi - ISC */
258 |
259 | let h = null, c = null, a = null;
260 |
261 | const fx = new WeakMap;
262 | const states = new WeakMap;
263 |
264 | const set = (h, c, a, update) => {
265 | const wrap = value => {
266 | if (!fx.has(h)) {
267 | fx.set(h, 0);
268 | wait.then(() => {
269 | fx.delete(h);
270 | h.apply(c, a);
271 | });
272 | }
273 | update(value);
274 | };
275 | states.set(update, wrap);
276 | return wrap;
277 | };
278 |
279 | const wrap = (h, c, a, state) => (
280 | h ? [
281 | state[0],
282 | states.get(state[1]) || set(h, c, a, state[1])
283 | ] :
284 | state
285 | );
286 |
287 | const hooked$1 = (callback, outer) => {
288 | const hook = hooked$2(
289 | outer ?
290 | /*async*/ function () {
291 | const [ph, pc, pa] = [h, c, a];
292 | [h, c, a] = [hook, this, arguments];
293 | try {
294 | return /*await*/ callback.apply(c, a);
295 | }
296 | finally {
297 | [h, c, a] = [ph, pc, pa];
298 | }
299 | } :
300 | callback
301 | );
302 | return hook;
303 | };
304 |
305 | const useReducer = (reducer, value, init) =>
306 | wrap(h, c, a, useReducer$1(reducer, value, init));
307 |
308 | const useState = value => wrap(h, c, a, useState$1(value));
309 |
310 | /*! (c) Andrea Giammarchi - ISC */
311 | const observer = observe(document, 'children', CustomEvent);
312 |
313 | const find = ({firstChild}) => {
314 | if (
315 | firstChild &&
316 | firstChild.nodeType !== 1 &&
317 | !(firstChild = firstChild.nextElementSibling)
318 | )
319 | throw 'unobservable';
320 | return firstChild;
321 | };
322 |
323 | const get = node => {
324 | const {nodeType} = node;
325 | if (nodeType)
326 | return nodeType === 1 ? node : find(node);
327 | else {
328 | // give a chance to facades to return a reasonable value
329 | const value = node.valueOf();
330 | return value !== node ? get(value) : find(value);
331 | }
332 | };
333 |
334 | const hooked = (fn, outer) => {
335 | const hook = hooked$1(fn, outer);
336 | return /*async*/ function () {
337 | const node = /*await*/ hook.apply(this, arguments);
338 | if (hasEffect(hook)) {
339 | const element = get(node);
340 | if (!observer.has(element))
341 | observer.connect(element, {
342 | disconnected() {
343 | dropEffect(hook);
344 | }
345 | });
346 | }
347 | return node;
348 | };
349 | };
350 |
351 | var umap = _ => ({
352 | // About: get: _.get.bind(_)
353 | // It looks like WebKit/Safari didn't optimize bind at all,
354 | // so that using bind slows it down by 60%.
355 | // Firefox and Chrome are just fine in both cases,
356 | // so let's use the approach that works fast everywhere 👍
357 | get: key => _.get(key),
358 | set: (key, value) => (_.set(key, value), value)
359 | });
360 |
361 | const {isArray: isArray$1} = Array;
362 |
363 | class MapSet extends Map {
364 | set(key, value) {
365 | super.set(key, value);
366 | return value;
367 | }
368 | }
369 |
370 | class WeakMapSet extends WeakMap {
371 | set(key, value) {
372 | super.set(key, value);
373 | return value;
374 | }
375 | }
376 |
377 | /*! (c) Andrea Giammarchi - ISC */
378 | const empty = /^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i;
379 | const elements = /<([a-z]+[a-z0-9:._-]*)([^>]*?)(\/?)>/g;
380 | const attributes = /([^\s\\>"'=]+)\s*=\s*(['"]?)\x01/g;
381 | const holes = /[\x01\x02]/g;
382 |
383 | // \x01 Node.ELEMENT_NODE
384 | // \x02 Node.ATTRIBUTE_NODE
385 |
386 | /**
387 | * Given a template, find holes as both nodes and attributes and
388 | * return a string with holes as either comment nodes or named attributes.
389 | * @param {string[]} template a template literal tag array
390 | * @param {string} prefix prefix to use per each comment/attribute
391 | * @param {boolean} svg enforces self-closing tags
392 | * @returns {string} X/HTML with prefixed comments or attributes
393 | */
394 | var instrument = (template, prefix, svg) => {
395 | let i = 0;
396 | return template
397 | .join('\x01')
398 | .trim()
399 | .replace(
400 | elements,
401 | (_, name, attrs, selfClosing) => {
402 | let ml = name + attrs.replace(attributes, '\x02=$2$1').trimEnd();
403 | if (selfClosing.length)
404 | ml += (svg || empty.test(name)) ? ' /' : ('>' + name);
405 | return '<' + ml + '>';
406 | }
407 | )
408 | .replace(
409 | holes,
410 | hole => hole === '\x01' ?
411 | ('') :
412 | (prefix + i++)
413 | );
414 | };
415 |
416 | const ELEMENT_NODE = 1;
417 | const nodeType = 111;
418 |
419 | const remove = ({firstChild, lastChild}) => {
420 | const range = document.createRange();
421 | range.setStartAfter(firstChild);
422 | range.setEndAfter(lastChild);
423 | range.deleteContents();
424 | return firstChild;
425 | };
426 |
427 | const diffable = (node, operation) => node.nodeType === nodeType ?
428 | ((1 / operation) < 0 ?
429 | (operation ? remove(node) : node.lastChild) :
430 | (operation ? node.valueOf() : node.firstChild)) :
431 | node
432 | ;
433 |
434 | const persistent = fragment => {
435 | const {firstChild, lastChild} = fragment;
436 | if (firstChild === lastChild)
437 | return lastChild || fragment;
438 | const {childNodes} = fragment;
439 | const nodes = [...childNodes];
440 | return {
441 | ELEMENT_NODE,
442 | nodeType,
443 | firstChild,
444 | lastChild,
445 | valueOf() {
446 | if (childNodes.length !== nodes.length)
447 | fragment.append(...nodes);
448 | return fragment;
449 | }
450 | };
451 | };
452 |
453 | const aria = node => values => {
454 | for (const key in values) {
455 | const name = key === 'role' ? key : `aria-${key}`;
456 | const value = values[key];
457 | if (value == null)
458 | node.removeAttribute(name);
459 | else
460 | node.setAttribute(name, value);
461 | }
462 | };
463 |
464 | const attribute = (node, name) => {
465 | let oldValue, orphan = true;
466 | const attributeNode = document.createAttributeNS(null, name);
467 | return newValue => {
468 | if (oldValue !== newValue) {
469 | oldValue = newValue;
470 | if (oldValue == null) {
471 | if (!orphan) {
472 | node.removeAttributeNode(attributeNode);
473 | orphan = true;
474 | }
475 | }
476 | else {
477 | const value = newValue;
478 | if (value == null) {
479 | if (!orphan)
480 | node.removeAttributeNode(attributeNode);
481 | orphan = true;
482 | }
483 | else {
484 | attributeNode.value = value;
485 | if (orphan) {
486 | node.setAttributeNodeNS(attributeNode);
487 | orphan = false;
488 | }
489 | }
490 | }
491 | }
492 | };
493 | };
494 |
495 | const boolean = (node, key, oldValue) => newValue => {
496 | if (oldValue !== !!newValue) {
497 | // when IE won't be around anymore ...
498 | // node.toggleAttribute(key, oldValue = !!newValue);
499 | if ((oldValue = !!newValue))
500 | node.setAttribute(key, '');
501 | else
502 | node.removeAttribute(key);
503 | }
504 | };
505 |
506 | const data = ({dataset}) => values => {
507 | for (const key in values) {
508 | const value = values[key];
509 | if (value == null)
510 | delete dataset[key];
511 | else
512 | dataset[key] = value;
513 | }
514 | };
515 |
516 | const event = (node, name) => {
517 | let oldValue, lower, type = name.slice(2);
518 | if (!(name in node) && (lower = name.toLowerCase()) in node)
519 | type = lower.slice(2);
520 | return newValue => {
521 | const info = isArray$1(newValue) ? newValue : [newValue, false];
522 | if (oldValue !== info[0]) {
523 | if (oldValue)
524 | node.removeEventListener(type, oldValue, info[1]);
525 | if (oldValue = info[0])
526 | node.addEventListener(type, oldValue, info[1]);
527 | }
528 | };
529 | };
530 |
531 | const ref = node => {
532 | let oldValue;
533 | return value => {
534 | if (oldValue !== value) {
535 | oldValue = value;
536 | if (typeof value === 'function')
537 | value(node);
538 | else
539 | value.current = node;
540 | }
541 | };
542 | };
543 |
544 | const setter = (node, key) => key === 'dataset' ?
545 | data(node) :
546 | value => {
547 | node[key] = value;
548 | };
549 |
550 | const text = node => {
551 | let oldValue;
552 | return newValue => {
553 | if (oldValue != newValue) {
554 | oldValue = newValue;
555 | node.textContent = newValue == null ? '' : newValue;
556 | }
557 | };
558 | };
559 |
560 | /**
561 | * ISC License
562 | *
563 | * Copyright (c) 2020, Andrea Giammarchi, @WebReflection
564 | *
565 | * Permission to use, copy, modify, and/or distribute this software for any
566 | * purpose with or without fee is hereby granted, provided that the above
567 | * copyright notice and this permission notice appear in all copies.
568 | *
569 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
570 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
571 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
572 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
573 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
574 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
575 | * PERFORMANCE OF THIS SOFTWARE.
576 | */
577 |
578 | /**
579 | * @param {Node} parentNode The container where children live
580 | * @param {Node[]} a The list of current/live children
581 | * @param {Node[]} b The list of future children
582 | * @param {(entry: Node, action: number) => Node} get
583 | * The callback invoked per each entry related DOM operation.
584 | * @param {Node} [before] The optional node used as anchor to insert before.
585 | * @returns {Node[]} The same list of future children.
586 | */
587 | var udomdiff = (parentNode, a, b, get, before) => {
588 | const bLength = b.length;
589 | let aEnd = a.length;
590 | let bEnd = bLength;
591 | let aStart = 0;
592 | let bStart = 0;
593 | let map = null;
594 | while (aStart < aEnd || bStart < bEnd) {
595 | // append head, tail, or nodes in between: fast path
596 | if (aEnd === aStart) {
597 | // we could be in a situation where the rest of nodes that
598 | // need to be added are not at the end, and in such case
599 | // the node to `insertBefore`, if the index is more than 0
600 | // must be retrieved, otherwise it's gonna be the first item.
601 | const node = bEnd < bLength ?
602 | (bStart ?
603 | (get(b[bStart - 1], -0).nextSibling) :
604 | get(b[bEnd - bStart], 0)) :
605 | before;
606 | while (bStart < bEnd)
607 | parentNode.insertBefore(get(b[bStart++], 1), node);
608 | }
609 | // remove head or tail: fast path
610 | else if (bEnd === bStart) {
611 | while (aStart < aEnd) {
612 | // remove the node only if it's unknown or not live
613 | if (!map || !map.has(a[aStart]))
614 | parentNode.removeChild(get(a[aStart], -1));
615 | aStart++;
616 | }
617 | }
618 | // same node: fast path
619 | else if (a[aStart] === b[bStart]) {
620 | aStart++;
621 | bStart++;
622 | }
623 | // same tail: fast path
624 | else if (a[aEnd - 1] === b[bEnd - 1]) {
625 | aEnd--;
626 | bEnd--;
627 | }
628 | // The once here single last swap "fast path" has been removed in v1.1.0
629 | // https://github.com/WebReflection/udomdiff/blob/single-final-swap/esm/index.js#L69-L85
630 | // reverse swap: also fast path
631 | else if (
632 | a[aStart] === b[bEnd - 1] &&
633 | b[bStart] === a[aEnd - 1]
634 | ) {
635 | // this is a "shrink" operation that could happen in these cases:
636 | // [1, 2, 3, 4, 5]
637 | // [1, 4, 3, 2, 5]
638 | // or asymmetric too
639 | // [1, 2, 3, 4, 5]
640 | // [1, 2, 3, 5, 6, 4]
641 | const node = get(a[--aEnd], -1).nextSibling;
642 | parentNode.insertBefore(
643 | get(b[bStart++], 1),
644 | get(a[aStart++], -1).nextSibling
645 | );
646 | parentNode.insertBefore(get(b[--bEnd], 1), node);
647 | // mark the future index as identical (yeah, it's dirty, but cheap 👍)
648 | // The main reason to do this, is that when a[aEnd] will be reached,
649 | // the loop will likely be on the fast path, as identical to b[bEnd].
650 | // In the best case scenario, the next loop will skip the tail,
651 | // but in the worst one, this node will be considered as already
652 | // processed, bailing out pretty quickly from the map index check
653 | a[aEnd] = b[bEnd];
654 | }
655 | // map based fallback, "slow" path
656 | else {
657 | // the map requires an O(bEnd - bStart) operation once
658 | // to store all future nodes indexes for later purposes.
659 | // In the worst case scenario, this is a full O(N) cost,
660 | // and such scenario happens at least when all nodes are different,
661 | // but also if both first and last items of the lists are different
662 | if (!map) {
663 | map = new Map;
664 | let i = bStart;
665 | while (i < bEnd)
666 | map.set(b[i], i++);
667 | }
668 | // if it's a future node, hence it needs some handling
669 | if (map.has(a[aStart])) {
670 | // grab the index of such node, 'cause it might have been processed
671 | const index = map.get(a[aStart]);
672 | // if it's not already processed, look on demand for the next LCS
673 | if (bStart < index && index < bEnd) {
674 | let i = aStart;
675 | // counts the amount of nodes that are the same in the future
676 | let sequence = 1;
677 | while (++i < aEnd && i < bEnd && map.get(a[i]) === (index + sequence))
678 | sequence++;
679 | // effort decision here: if the sequence is longer than replaces
680 | // needed to reach such sequence, which would brings again this loop
681 | // to the fast path, prepend the difference before a sequence,
682 | // and move only the future list index forward, so that aStart
683 | // and bStart will be aligned again, hence on the fast path.
684 | // An example considering aStart and bStart are both 0:
685 | // a: [1, 2, 3, 4]
686 | // b: [7, 1, 2, 3, 6]
687 | // this would place 7 before 1 and, from that time on, 1, 2, and 3
688 | // will be processed at zero cost
689 | if (sequence > (index - bStart)) {
690 | const node = get(a[aStart], 0);
691 | while (bStart < index)
692 | parentNode.insertBefore(get(b[bStart++], 1), node);
693 | }
694 | // if the effort wasn't good enough, fallback to a replace,
695 | // moving both source and target indexes forward, hoping that some
696 | // similar node will be found later on, to go back to the fast path
697 | else {
698 | parentNode.replaceChild(
699 | get(b[bStart++], 1),
700 | get(a[aStart++], -1)
701 | );
702 | }
703 | }
704 | // otherwise move the source forward, 'cause there's nothing to do
705 | else
706 | aStart++;
707 | }
708 | // this node has no meaning in the future list, so it's more than safe
709 | // to remove it, and check the next live node out instead, meaning
710 | // that only the live list index should be forwarded
711 | else
712 | parentNode.removeChild(get(a[aStart++], -1));
713 | }
714 | }
715 | return b;
716 | };
717 |
718 | const {isArray, prototype} = Array;
719 | const {indexOf} = prototype;
720 |
721 | const {
722 | createDocumentFragment,
723 | createElement,
724 | createElementNS,
725 | createTextNode,
726 | createTreeWalker,
727 | importNode
728 | } = new Proxy(document, {
729 | get: (target, method) => target[method].bind(target)
730 | });
731 |
732 | const createHTML = html => {
733 | const template = createElement('template');
734 | template.innerHTML = html;
735 | return template.content;
736 | };
737 |
738 | let xml;
739 | const createSVG = svg => {
740 | if (!xml) xml = createElementNS('http://www.w3.org/2000/svg', 'svg');
741 | xml.innerHTML = svg;
742 | const content = createDocumentFragment();
743 | content.append(...xml.childNodes);
744 | return content;
745 | };
746 |
747 | const createContent = (text, svg) => svg ?
748 | createSVG(text) : createHTML(text);
749 |
750 | // from a generic path, retrieves the exact targeted node
751 | const reducePath = ({childNodes}, i) => childNodes[i];
752 |
753 | // this helper avoid code bloat around handleAnything() callback
754 | const diff = (comment, oldNodes, newNodes) => udomdiff(
755 | comment.parentNode,
756 | // TODO: there is a possible edge case where a node has been
757 | // removed manually, or it was a keyed one, attached
758 | // to a shared reference between renders.
759 | // In this case udomdiff might fail at removing such node
760 | // as its parent won't be the expected one.
761 | // The best way to avoid this issue is to filter oldNodes
762 | // in search of those not live, or not in the current parent
763 | // anymore, but this would require both a change to uwire,
764 | // exposing a parentNode from the firstChild, as example,
765 | // but also a filter per each diff that should exclude nodes
766 | // that are not in there, penalizing performance quite a lot.
767 | // As this has been also a potential issue with domdiff,
768 | // and both lighterhtml and hyperHTML might fail with this
769 | // very specific edge case, I might as well document this possible
770 | // "diffing shenanigan" and call it a day.
771 | oldNodes,
772 | newNodes,
773 | diffable,
774 | comment
775 | );
776 |
777 | // if an interpolation represents a comment, the whole
778 | // diffing will be related to such comment.
779 | // This helper is in charge of understanding how the new
780 | // content for such interpolation/hole should be updated
781 | const handleAnything = comment => {
782 | let oldValue, text, nodes = [];
783 | const anyContent = newValue => {
784 | switch (typeof newValue) {
785 | // primitives are handled as text content
786 | case 'string':
787 | case 'number':
788 | case 'boolean':
789 | if (oldValue !== newValue) {
790 | oldValue = newValue;
791 | if (!text)
792 | text = createTextNode('');
793 | text.data = newValue;
794 | nodes = diff(comment, nodes, [text]);
795 | }
796 | break;
797 | // null, and undefined are used to cleanup previous content
798 | case 'object':
799 | case 'undefined':
800 | if (newValue == null) {
801 | if (oldValue != newValue) {
802 | oldValue = newValue;
803 | nodes = diff(comment, nodes, []);
804 | }
805 | break;
806 | }
807 | // arrays and nodes have a special treatment
808 | if (isArray(newValue)) {
809 | oldValue = newValue;
810 | // arrays can be used to cleanup, if empty
811 | if (newValue.length === 0)
812 | nodes = diff(comment, nodes, []);
813 | // or diffed, if these contains nodes or "wires"
814 | else if (typeof newValue[0] === 'object')
815 | nodes = diff(comment, nodes, newValue);
816 | // in all other cases the content is stringified as is
817 | else
818 | anyContent(String(newValue));
819 | break;
820 | }
821 | // if the new value is a DOM node, or a wire, and it's
822 | // different from the one already live, then it's diffed.
823 | // if the node is a fragment, it's appended once via its childNodes
824 | // There is no `else` here, meaning if the content
825 | // is not expected one, nothing happens, as easy as that.
826 | if (oldValue !== newValue && 'ELEMENT_NODE' in newValue) {
827 | oldValue = newValue;
828 | nodes = diff(
829 | comment,
830 | nodes,
831 | newValue.nodeType === 11 ?
832 | [...newValue.childNodes] :
833 | [newValue]
834 | );
835 | }
836 | break;
837 | case 'function':
838 | anyContent(newValue(comment));
839 | break;
840 | }
841 | };
842 | return anyContent;
843 | };
844 |
845 | // attributes can be:
846 | // * ref=${...} for hooks and other purposes
847 | // * aria=${...} for aria attributes
848 | // * ?boolean=${...} for boolean attributes
849 | // * .dataset=${...} for dataset related attributes
850 | // * .setter=${...} for Custom Elements setters or nodes with setters
851 | // such as buttons, details, options, select, etc
852 | // * @event=${...} to explicitly handle event listeners
853 | // * onevent=${...} to automatically handle event listeners
854 | // * generic=${...} to handle an attribute just like an attribute
855 | const handleAttribute = (node, name/*, svg*/) => {
856 | switch (name[0]) {
857 | case '?': return boolean(node, name.slice(1), false);
858 | case '.': return setter(node, name.slice(1));
859 | case '@': return event(node, 'on' + name.slice(1));
860 | case 'o': if (name[1] === 'n') return event(node, name);
861 | }
862 |
863 | switch (name) {
864 | case 'ref': return ref(node);
865 | case 'aria': return aria(node);
866 | }
867 |
868 | return attribute(node, name/*, svg*/);
869 | };
870 |
871 | // each mapped update carries the update type and its path
872 | // the type is either node, attribute, or text, while
873 | // the path is how to retrieve the related node to update.
874 | // In the attribute case, the attribute name is also carried along.
875 | function handlers(options) {
876 | const {type, path} = options;
877 | const node = path.reduceRight(reducePath, this);
878 | return type === 'node' ?
879 | handleAnything(node) :
880 | (type === 'attr' ?
881 | handleAttribute(node, options.name/*, options.svg*/) :
882 | text(node));
883 | }
884 |
885 | // from a fragment container, create an array of indexes
886 | // related to its child nodes, so that it's possible
887 | // to retrieve later on exact node via reducePath
888 | const createPath = node => {
889 | const path = [];
890 | let {parentNode} = node;
891 | while (parentNode) {
892 | path.push(indexOf.call(parentNode.childNodes, node));
893 | node = parentNode;
894 | ({parentNode} = node);
895 | }
896 | return path;
897 | };
898 |
899 | // the prefix is used to identify either comments, attributes, or nodes
900 | // that contain the related unique id. In the attribute cases
901 | // isµX="attribute-name" will be used to map current X update to that
902 | // attribute name, while comments will be like , to map
903 | // the update to that specific comment node, hence its parent.
904 | // style and textarea will have text content, and are handled
905 | // directly through text-only updates.
906 | const prefix = 'isµ';
907 |
908 | // Template Literals are unique per scope and static, meaning a template
909 | // should be parsed once, and once only, as it will always represent the same
910 | // content, within the exact same amount of updates each time.
911 | // This cache relates each template to its unique content and updates.
912 | const cache$2 = new WeakMapSet;
913 |
914 | // a RegExp that helps checking nodes that cannot contain comments
915 | const textOnly = /^(?:textarea|script|style|title|plaintext|xmp)$/;
916 |
917 | const createCache$1 = () => ({
918 | stack: [], // each template gets a stack for each interpolation "hole"
919 |
920 | entry: null, // each entry contains details, such as:
921 | // * the template that is representing
922 | // * the type of node it represents (html or svg)
923 | // * the content fragment with all nodes
924 | // * the list of updates per each node (template holes)
925 | // * the "wired" node or fragment that will get updates
926 | // if the template or type are different from the previous one
927 | // the entry gets re-created each time
928 |
929 | wire: null // each rendered node represent some wired content and
930 | // this reference to the latest one. If different, the node
931 | // will be cleaned up and the new "wire" will be appended
932 | });
933 |
934 | // the entry stored in the rendered node cache, and per each "hole"
935 | const createEntry = (type, template) => {
936 | const {content, updates} = mapUpdates(type, template);
937 | return {type, template, content, updates, wire: null};
938 | };
939 |
940 | // a template is instrumented to be able to retrieve where updates are needed.
941 | // Each unique template becomes a fragment, cloned once per each other
942 | // operation based on the same template, i.e. data => html`
${data}
`
943 | const mapTemplate = (type, template) => {
944 | const svg = type === 'svg';
945 | const text = instrument(template, prefix, svg);
946 | const content = createContent(text, svg);
947 | // once instrumented and reproduced as fragment, it's crawled
948 | // to find out where each update is in the fragment tree
949 | const tw = createTreeWalker(content, 1 | 128);
950 | const nodes = [];
951 | const length = template.length - 1;
952 | let i = 0;
953 | // updates are searched via unique names, linearly increased across the tree
954 | //
955 | let search = `${prefix}${i}`;
956 | while (i < length) {
957 | const node = tw.nextNode();
958 | // if not all updates are bound but there's nothing else to crawl
959 | // it means that there is something wrong with the template.
960 | if (!node)
961 | throw `bad template: ${text}`;
962 | // if the current node is a comment, and it contains isµX
963 | // it means the update should take care of any content
964 | if (node.nodeType === 8) {
965 | // The only comments to be considered are those
966 | // which content is exactly the same as the searched one.
967 | if (node.data === search) {
968 | nodes.push({type: 'node', path: createPath(node)});
969 | search = `${prefix}${++i}`;
970 | }
971 | }
972 | else {
973 | // if the node is not a comment, loop through all its attributes
974 | // named isµX and relate attribute updates to this node and the
975 | // attribute name, retrieved through node.getAttribute("isµX")
976 | // the isµX attribute will be removed as irrelevant for the layout
977 | // let svg = -1;
978 | while (node.hasAttribute(search)) {
979 | nodes.push({
980 | type: 'attr',
981 | path: createPath(node),
982 | name: node.getAttribute(search)
983 | });
984 | node.removeAttribute(search);
985 | search = `${prefix}${++i}`;
986 | }
987 | // if the node was a style, textarea, or others, check its content
988 | // and if it is then update tex-only this node
989 | if (
990 | textOnly.test(node.localName) &&
991 | node.textContent.trim() === ``
992 | ){
993 | node.textContent = '';
994 | nodes.push({type: 'text', path: createPath(node)});
995 | search = `${prefix}${++i}`;
996 | }
997 | }
998 | }
999 | // once all nodes to update, or their attributes, are known, the content
1000 | // will be cloned in the future to represent the template, and all updates
1001 | // related to such content retrieved right away without needing to re-crawl
1002 | // the exact same template, and its content, more than once.
1003 | return {content, nodes};
1004 | };
1005 |
1006 | // if a template is unknown, perform the previous mapping, otherwise grab
1007 | // its details such as the fragment with all nodes, and updates info.
1008 | const mapUpdates = (type, template) => {
1009 | const {content, nodes} = (
1010 | cache$2.get(template) ||
1011 | cache$2.set(template, mapTemplate(type, template))
1012 | );
1013 | // clone deeply the fragment
1014 | const fragment = importNode(content, true);
1015 | // and relate an update handler per each node that needs one
1016 | const updates = nodes.map(handlers, fragment);
1017 | // return the fragment and all updates to use within its nodes
1018 | return {content: fragment, updates};
1019 | };
1020 |
1021 | // as html and svg can be nested calls, but no parent node is known
1022 | // until rendered somewhere, the unroll operation is needed to
1023 | // discover what to do with each interpolation, which will result
1024 | // into an update operation.
1025 | const unroll$1 = (info, {type, template, values}) => {
1026 | // interpolations can contain holes and arrays, so these need
1027 | // to be recursively discovered
1028 | const length = unrollValues$1(info, values);
1029 | let {entry} = info;
1030 | // if the cache entry is either null or different from the template
1031 | // and the type this unroll should resolve, create a new entry
1032 | // assigning a new content fragment and the list of updates.
1033 | if (!entry || (entry.template !== template || entry.type !== type))
1034 | info.entry = (entry = createEntry(type, template));
1035 | const {content, updates, wire} = entry;
1036 | // even if the fragment and its nodes is not live yet,
1037 | // it is already possible to update via interpolations values.
1038 | for (let i = 0; i < length; i++)
1039 | updates[i](values[i]);
1040 | // if the entry was new, or representing a different template or type,
1041 | // create a new persistent entity to use during diffing.
1042 | // This is simply a DOM node, when the template has a single container,
1043 | // as in ``, or a "wire" in `` and similar cases.
1044 | return wire || (entry.wire = persistent(content));
1045 | };
1046 |
1047 | // the stack retains, per each interpolation value, the cache
1048 | // related to each interpolation value, or null, if the render
1049 | // was conditional and the value is not special (Array or Hole)
1050 | const unrollValues$1 = ({stack}, values) => {
1051 | const {length} = values;
1052 | for (let i = 0; i < length; i++) {
1053 | const hole = values[i];
1054 | // each Hole gets unrolled and re-assigned as value
1055 | // so that domdiff will deal with a node/wire, not with a hole
1056 | if (hole instanceof Hole)
1057 | values[i] = unroll$1(
1058 | stack[i] || (stack[i] = createCache$1()),
1059 | hole
1060 | );
1061 | // arrays are recursively resolved so that each entry will contain
1062 | // also a DOM node or a wire, hence it can be diffed if/when needed
1063 | else if (isArray(hole))
1064 | unrollValues$1(stack[i] || (stack[i] = createCache$1()), hole);
1065 | // if the value is nothing special, the stack doesn't need to retain data
1066 | // this is useful also to cleanup previously retained data, if the value
1067 | // was a Hole, or an Array, but not anymore, i.e.:
1068 | // const update = content => html`