sprae 10.0.1 → 10.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core.js CHANGED
@@ -1,90 +1,73 @@
1
- import { effect, untracked, use } from "./signal.js";
1
+ import { use } from "./signal.js";
2
2
  import store, { _signals } from './store.js';
3
3
 
4
4
  // polyfill
5
5
  const _dispose = (Symbol.dispose ||= Symbol("dispose"));
6
6
 
7
- // mark
8
- const SPRAE = `∴`
9
-
10
7
  // reserved directives - order matters!
11
8
  export const directive = {};
12
9
 
13
10
  // sprae element: apply directives
14
11
  const memo = new WeakMap();
15
12
 
16
- export default function sprae(els, values) {
17
- let state
13
+ export default function sprae(el, values) {
14
+ // text nodes, comments etc - but collections are fine
15
+ if (!el?.children) return
18
16
 
19
- // make multiple items
20
- if (!els?.[Symbol.iterator]) els = [els]
17
+ // repeated call can be caused by :each with new objects with old keys needs an update
18
+ if (memo.has(el)) {
19
+ // we rewrite signals instead of update, because user should have what he provided
20
+ return Object.assign(memo.get(el), values)
21
+ }
21
22
 
22
- for (let el of els) {
23
- // text nodes, comments etc - but collections are fine
24
- if (el?.children) {
25
- // repeated call can be caused by :each with new objects with old keys needs an update
26
- if (memo.has(el)) {
27
- // we rewrite signals instead of update, because user should have what he provided
28
- Object.assign(memo.get(el), values)
29
- }
30
- else {
31
- // take over existing state instead of creating clone
32
- state ||= store(values || {});
23
+ // take over existing state instead of creating clone
24
+ const state = store(values || {}), disposes = []
33
25
 
34
- init(el, state);
26
+ init(el);
35
27
 
36
- // if element was spraed by :with or :each instruction - skip, otherwise save
37
- if (!memo.has(el)) memo.set(el, state);
38
- }
39
- }
40
- };
28
+ // if element was spraed by :with or :each instruction - skip, otherwise save
29
+ if (!memo.has(el)) memo.set(el, state);
30
+
31
+ el[_dispose] = () => {
32
+ while (disposes.length) disposes.pop()();
33
+ memo.delete(el);
34
+ }
41
35
 
42
36
  return state;
43
- }
44
37
 
45
- // init directives on a single element
46
- function init(el, state, parent = el.parentNode, effects = []) {
47
- if (el.attributes) {
48
- // init generic-name attributes second
49
- for (let i = 0; i < el.attributes.length;) {
50
- let attr = el.attributes[i];
51
-
52
- if (attr.name[0] === ':') {
53
- el.removeAttribute(attr.name);
54
-
55
- // multiple attributes like :id:for=""
56
- let names = attr.name.slice(1).split(':')
57
-
58
- // NOTE: secondary directives don't stop flow nor extend state, so no need to check
59
- for (let name of names) {
60
- let dir = directive[name] || directive.default
61
- let evaluate = (dir.parse || parse)(attr.value, parse)
62
- let dispose = dir(el, evaluate, state, name);
63
- if (dispose) effects.push(dispose);
64
- }
65
-
66
- // stop if element was spraed by internal directive
67
- if (memo.has(el)) return;
68
-
69
- // stop if element is skipped (detached) like in case of :if or :each
70
- if (el.parentNode !== parent) return;
71
- } else i++;
38
+ function init(el, parent = el.parentNode) {
39
+ if (el.attributes) {
40
+ // init generic-name attributes second
41
+ for (let i = 0; i < el.attributes.length;) {
42
+ let attr = el.attributes[i];
43
+
44
+ if (attr.name[0] === ':') {
45
+ el.removeAttribute(attr.name);
46
+
47
+ // multiple attributes like :id:for=""
48
+ let names = attr.name.slice(1).split(':')
49
+
50
+ // NOTE: secondary directives don't stop flow nor extend state, so no need to check
51
+ for (let name of names) {
52
+ let dir = directive[name] || directive.default
53
+ let evaluate = (dir.parse || parse)(attr.value, parse)
54
+ let dispose = dir(el, evaluate, state, name);
55
+ if (dispose) disposes.push(dispose);
56
+ }
57
+
58
+ // stop if element was spraed by internal directive
59
+ if (memo.has(el)) return disposes.push(el[_dispose]);
60
+
61
+ // stop if element is skipped (detached) like in case of :if or :each
62
+ if (el.parentNode !== parent) return;
63
+ } else i++;
64
+ }
72
65
  }
73
- }
74
66
 
75
- for (let child of [...el.children]) init(child, state, el)
67
+ for (let child of [...el.children]) init(child, el)
68
+ };
69
+ }
76
70
 
77
- // mark spraed element
78
- el.classList?.add(SPRAE);
79
- el[_dispose] = () => {
80
- while (effects.length) effects.pop()();
81
- el.classList.remove(SPRAE);
82
- memo.delete(el);
83
- // NOTE: each child disposes own children etc.
84
- let els = el.getElementsByClassName(SPRAE);
85
- while (els.length) els[0][_dispose]?.()
86
- }
87
- };
88
71
 
89
72
  // compiler
90
73
  const evalMemo = {};
package/directive/each.js CHANGED
@@ -58,15 +58,18 @@ directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
58
58
  [itemVar]: { get() { return cur[idx] } },
59
59
  [idxVar]: { value: keys ? keys[idx] : idx },
60
60
  }),
61
- el = (tpl.content || tpl).cloneNode(true), // single element or fragment
62
- els = tpl.content ? [...el.childNodes] : [el] // total added elements
61
+ el = (tpl.content || tpl).cloneNode(true),
62
+ frag = tpl.content ?
63
+ // fake fragment to init sprae
64
+ { children: [...el.children], remove() { this.children.map(el => el.remove()) } } :
65
+ el;
63
66
 
64
67
  holder.before(el);
65
- sprae(els, scope);
68
+ sprae(frag, scope);
66
69
 
67
70
  // signal/holder disposal removes element
68
71
  ((cur[_signals] ||= [])[i] ||= {})[Symbol.dispose] = () => {
69
- for (let el of els) el[Symbol.dispose](), el.remove()
72
+ frag[Symbol.dispose](), frag.remove()
70
73
  };
71
74
  }
72
75
  }
package/directive/with.js CHANGED
@@ -1,16 +1,24 @@
1
1
  import sprae, { directive } from "../core.js";
2
2
  import store, { _signals } from '../store.js';
3
3
  import { effect } from "../signal.js";
4
+ import { signal } from "ulive";
4
5
 
5
6
  directive.with = (el, evaluate, rootState) => {
6
- let state, values
7
+ let state
7
8
  return effect(() => {
8
- values = evaluate(rootState);
9
- Object.assign(state ||= sprae(el,
10
- store(
11
- values,
12
- Object.create(rootState[_signals])
13
- )
14
- ), values)
9
+ let values = evaluate(rootState);
10
+
11
+ if (!state) {
12
+ state = store({});
13
+ // inherit root signals
14
+ Object.assign(state[_signals], rootState[_signals]);
15
+ // create local scope signals
16
+ for (let key in values) state[_signals][key] = null, state[key] = values[key]
17
+
18
+ sprae(el, state)
19
+ }
20
+ else {
21
+ Object.assign(state, values)
22
+ }
15
23
  })
16
24
  };
package/dist/sprae.js CHANGED
@@ -21,17 +21,16 @@ function use(s) {
21
21
  // store.js
22
22
  var _signals = Symbol("signals");
23
23
  var _change = Symbol("length");
24
- function store(values, signals) {
24
+ function store(values) {
25
25
  if (!values)
26
26
  return values;
27
- if (values[_signals] && !signals)
27
+ if (values[_signals])
28
28
  return values;
29
29
  if (Array.isArray(values))
30
30
  return list(values);
31
31
  if (values.constructor !== Object)
32
32
  return values;
33
- let _len = signal(Object.values(values).length);
34
- signals ||= {};
33
+ let signals = {}, _len = signal(Object.values(values).length);
35
34
  const state = new Proxy(signals, {
36
35
  get: (_, key) => key === _change ? _len : key === _signals ? signals : signals[key]?.valueOf(),
37
36
  set: (_, key, v, s) => (s = signals[key], set(signals, key, v), s || ++_len.value),
@@ -41,19 +40,15 @@ function store(values, signals) {
41
40
  return Reflect.ownKeys(signals);
42
41
  }
43
42
  });
44
- if (values[_signals])
45
- for (let key in values)
46
- signals[key] = values[_signals][key];
47
- else
48
- for (let key in values) {
49
- const desc = Object.getOwnPropertyDescriptor(values, key);
50
- if (desc?.get) {
51
- (signals[key] = computed(desc.get.bind(state)))._set = desc.set?.bind(state);
52
- } else {
53
- signals[key] = null;
54
- set(signals, key, values[key]);
55
- }
43
+ for (let key in values) {
44
+ const desc = Object.getOwnPropertyDescriptor(values, key);
45
+ if (desc?.get) {
46
+ (signals[key] = computed(desc.get.bind(state)))._set = desc.set?.bind(state);
47
+ } else {
48
+ signals[key] = null;
49
+ set(signals, key, values[key]);
56
50
  }
51
+ }
57
52
  return state;
58
53
  }
59
54
  function list(values) {
@@ -63,10 +58,8 @@ function list(values) {
63
58
  let _len = signal(values.length), signals = Array(values.length).fill(null);
64
59
  const state = new Proxy(signals, {
65
60
  get(_, key) {
66
- if (key === _change)
67
- return _len;
68
- if (key === _signals)
69
- return signals;
61
+ if (typeof key === "symbol")
62
+ return key === _change ? _len : key === _signals ? signals : signals[key];
70
63
  if (key === "length")
71
64
  return Array.prototype[lastProp] ? _len.peek() : _len.value;
72
65
  lastProp = key;
@@ -131,62 +124,50 @@ function del(signals, key) {
131
124
 
132
125
  // core.js
133
126
  var _dispose = Symbol.dispose ||= Symbol("dispose");
134
- var SPRAE = `\u2234`;
135
127
  var directive = {};
136
128
  var memo = /* @__PURE__ */ new WeakMap();
137
- function sprae(els, values) {
138
- let state;
139
- if (!els?.[Symbol.iterator])
140
- els = [els];
141
- for (let el of els) {
142
- if (el?.children) {
143
- if (memo.has(el)) {
144
- Object.assign(memo.get(el), values);
145
- } else {
146
- state ||= store(values || {});
147
- init(el, state);
148
- if (!memo.has(el))
149
- memo.set(el, state);
150
- }
151
- }
152
- }
153
- ;
154
- return state;
155
- }
156
- function init(el, state, parent = el.parentNode, effects = []) {
157
- if (el.attributes) {
158
- for (let i = 0; i < el.attributes.length; ) {
159
- let attr2 = el.attributes[i];
160
- if (attr2.name[0] === ":") {
161
- el.removeAttribute(attr2.name);
162
- let names = attr2.name.slice(1).split(":");
163
- for (let name of names) {
164
- let dir = directive[name] || directive.default;
165
- let evaluate = (dir.parse || parse)(attr2.value, parse);
166
- let dispose = dir(el, evaluate, state, name);
167
- if (dispose)
168
- effects.push(dispose);
169
- }
170
- if (memo.has(el))
171
- return;
172
- if (el.parentNode !== parent)
173
- return;
174
- } else
175
- i++;
176
- }
129
+ function sprae(el, values) {
130
+ if (!el?.children)
131
+ return;
132
+ if (memo.has(el)) {
133
+ return Object.assign(memo.get(el), values);
177
134
  }
178
- for (let child of [...el.children])
179
- init(child, state, el);
180
- el.classList?.add(SPRAE);
135
+ const state = store(values || {}), disposes = [];
136
+ init(el);
137
+ if (!memo.has(el))
138
+ memo.set(el, state);
181
139
  el[_dispose] = () => {
182
- while (effects.length)
183
- effects.pop()();
184
- el.classList.remove(SPRAE);
140
+ while (disposes.length)
141
+ disposes.pop()();
185
142
  memo.delete(el);
186
- let els = el.getElementsByClassName(SPRAE);
187
- while (els.length)
188
- els[0][_dispose]?.();
189
143
  };
144
+ return state;
145
+ function init(el2, parent = el2.parentNode) {
146
+ if (el2.attributes) {
147
+ for (let i = 0; i < el2.attributes.length; ) {
148
+ let attr2 = el2.attributes[i];
149
+ if (attr2.name[0] === ":") {
150
+ el2.removeAttribute(attr2.name);
151
+ let names = attr2.name.slice(1).split(":");
152
+ for (let name of names) {
153
+ let dir = directive[name] || directive.default;
154
+ let evaluate = (dir.parse || parse)(attr2.value, parse);
155
+ let dispose = dir(el2, evaluate, state, name);
156
+ if (dispose)
157
+ disposes.push(dispose);
158
+ }
159
+ if (memo.has(el2))
160
+ return disposes.push(el2[_dispose]);
161
+ if (el2.parentNode !== parent)
162
+ return;
163
+ } else
164
+ i++;
165
+ }
166
+ }
167
+ for (let child of [...el2.children])
168
+ init(child, el2);
169
+ }
170
+ ;
190
171
  }
191
172
  var evalMemo = {};
192
173
  var parse = (expr, dir, fn) => {
@@ -273,28 +254,6 @@ var batch2 = (fn) => {
273
254
  };
274
255
  var untracked2 = (fn, prev, v) => (prev = current, current = null, v = fn(), current = prev, v);
275
256
 
276
- // node_modules/swapdom/deflate.js
277
- var swap = (parent, a, b, end = null, { remove, insert } = swap) => {
278
- let i = 0, cur, next, bi, bidx = new Set(b);
279
- while (bi = a[i++])
280
- !bidx.has(bi) ? remove(bi, parent) : cur = cur || bi;
281
- cur = cur || end, i = 0;
282
- while (bi = b[i++]) {
283
- next = cur ? cur.nextSibling : end;
284
- if (cur === bi)
285
- cur = next;
286
- else {
287
- if (b[i] === next)
288
- cur = next;
289
- insert(bi, cur, parent);
290
- }
291
- }
292
- return b;
293
- };
294
- swap.insert = (a, b, parent) => parent.insertBefore(a, b);
295
- swap.remove = (a, parent) => parent.removeChild(a);
296
- var deflate_default = swap;
297
-
298
257
  // directive/each.js
299
258
  var _each = Symbol(":each");
300
259
  directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
@@ -336,12 +295,13 @@ directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
336
295
  return cur[idx];
337
296
  } },
338
297
  [idxVar]: { value: keys2 ? keys2[idx] : idx }
339
- }), el = (tpl.content || tpl).cloneNode(true), els = tpl.content ? [...el.childNodes] : [el];
298
+ }), el = (tpl.content || tpl).cloneNode(true), frag = tpl.content ? { children: [...el.children], remove() {
299
+ this.children.map((el2) => el2.remove());
300
+ } } : el;
340
301
  holder.before(el);
341
- sprae(els, scope);
302
+ sprae(frag, scope);
342
303
  ((cur[_signals] ||= [])[i] ||= {})[Symbol.dispose] = () => {
343
- for (let el2 of els)
344
- el2[Symbol.dispose](), el2.remove();
304
+ frag[Symbol.dispose](), frag.remove();
345
305
  };
346
306
  }
347
307
  }
@@ -543,16 +503,18 @@ directive.ref.parse = (expr) => expr;
543
503
 
544
504
  // directive/with.js
545
505
  directive.with = (el, evaluate, rootState) => {
546
- let state, values;
506
+ let state;
547
507
  return effect(() => {
548
- values = evaluate(rootState);
549
- Object.assign(state ||= sprae(
550
- el,
551
- store(
552
- values,
553
- Object.create(rootState[_signals])
554
- )
555
- ), values);
508
+ let values = evaluate(rootState);
509
+ if (!state) {
510
+ state = store({});
511
+ Object.assign(state[_signals], rootState[_signals]);
512
+ for (let key in values)
513
+ state[_signals][key] = null, state[key] = values[key];
514
+ sprae(el, state);
515
+ } else {
516
+ Object.assign(state, values);
517
+ }
556
518
  });
557
519
  };
558
520
 
@@ -637,7 +599,6 @@ directive.fx = (el, evaluate, state) => {
637
599
  // sprae.js
638
600
  sprae.use(ulive_es_exports);
639
601
  sprae.use({ compile: (expr) => sprae.constructor(`__scope`, `with (__scope) { return ${expr} };`) });
640
- sprae.use({ swap: deflate_default });
641
602
  var sprae_default = sprae;
642
603
  export {
643
604
  sprae_default as default
package/dist/sprae.min.js CHANGED
@@ -1 +1 @@
1
- var e,t,r,l,n,s=Object.defineProperty,a=Symbol("signals"),o=Symbol("length");function i(t,r){if(!t)return t;if(t[a]&&!r)return t;if(Array.isArray(t))return function(t){let r;if(t[a])return t;let l=e(t.length),n=Array(t.length).fill(null);const s=new Proxy(n,{get:(s,c)=>c===o?l:c===a?n:"length"===c?Array.prototype[r]?l.peek():l.value:(r=c,n[c]?n[c].valueOf():c<n.length?(n[c]=e(i(t[c]))).value:void 0),set(e,t,r){if("length"===t){for(let e=r,t=n.length;e<t;e++)delete s[e];return l.value=n.length=r,!0}return c(n,t,r),t>=l.peek()&&(l.value=n.length=Number(t)+1),!0},deleteProperty:(e,t)=>(u(n,t),!0)});return s}(t);if(t.constructor!==Object)return t;let l=e(Object.values(t).length);r||={};const s=new Proxy(r,{get:(e,t)=>t===o?l:t===a?r:r[t]?.valueOf(),set:(e,t,n,s)=>(s=r[t],c(r,t,n),s||++l.value),deleteProperty:(e,t)=>u(r,t)&&l.value--,ownKeys:()=>(l.value,Reflect.ownKeys(r))});if(t[a])for(let e in t)r[e]=t[a][e];else for(let e in t){const l=Object.getOwnPropertyDescriptor(t,e);l?.get?(r[e]=n(l.get.bind(s)))._set=l.set?.bind(s):(r[e]=null,c(r,e,t[e]))}return s}function c(t,n,s){let a=t[n];if(a)if(s===a.peek());else if(a._set)a._set(s);else if(Array.isArray(s)&&Array.isArray(a.peek())){const e=a.peek();e[o]?r((()=>{l((()=>{let t=0,r=s.length;for(;t<r;t++)e[t]=s[t];e.length=r}))})):a.value=s}else a.value=i(s);else t[n]=a=s?.peek?s:e(i(s))}function u(e,t){const r=e[t];if(r){const l=r[Symbol.dispose];return l&&delete r[Symbol.dispose],delete e[t],l?.(),!0}}var f=Symbol.dispose||=Symbol("dispose"),p={},d=new WeakMap;function y(e,t){let r;e?.[Symbol.iterator]||(e=[e]);for(let l of e)l?.children&&(d.has(l)?Object.assign(d.get(l),t):(r||=i(t||{}),v(l,r),d.has(l)||d.set(l,r)));return r}function v(e,t,r=e.parentNode,l=[]){if(e.attributes)for(let n=0;n<e.attributes.length;){let s=e.attributes[n];if(":"===s.name[0]){e.removeAttribute(s.name);let n=s.name.slice(1).split(":");for(let r of n){let n=p[r]||p.default,a=(n.parse||g)(s.value,g),o=n(e,a,t,r);o&&l.push(o)}if(d.has(e))return;if(e.parentNode!==r)return}else n++}for(let r of[...e.children])v(r,t,e);e.classList?.add("∴"),e[f]=()=>{for(;l.length;)l.pop()();e.classList.remove("∴"),d.delete(e);let t=e.getElementsByClassName("∴");for(;t.length;)t[0][f]?.()}}var h,m={},g=(e,t,r)=>{if(r=m[e=e.trim()])return r;try{r=h(e)}catch(r){throw Object.assign(r,{message:`∴ ${r.message}\n\n${t}${e?`="${e}"\n\n`:""}`,expr:e})}return m[e]=r};y.use=s=>{s.signal&&function(s){e=s.signal,t=s.effect,n=s.computed,l=s.batch||(e=>e()),r=s.untracked||l}(s),s.compile&&(h=s.compile)};var b,k,A={};((e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})})(A,{batch:()=>N,computed:()=>O,effect:()=>w,signal:()=>S,untracked:()=>x});var S=(e,t,r=new Set)=>((t={get value(){return b?.deps.push(r.add(b)),e},set value(t){if(t!==e){e=t;for(let e of r)k?k.add(e):e()}},peek:()=>e}).toJSON=t.then=t.toString=t.valueOf=()=>t.value,t),w=(e,t,r,l)=>(l=(r=l=>{t?.call?.(),l=b,b=r;try{t=e()}finally{b=l}}).deps=[],r(),e=>{for(t?.call?.();e=l.pop();)e.delete(r)}),O=(e,t=S(),r,l)=>((r={get value(){return l||=w((()=>t.value=e())),t.value},peek:t.peek}).toJSON=r.then=r.toString=r.valueOf=()=>r.value,r),N=e=>{let t=k;t||(k=new Set);try{e()}finally{if(!t){t=k,k=null;for(const e of t)e()}}},x=(e,t,r)=>(t=b,b=null,r=e(),b=t,r),j=(e,t,r,l=null,{remove:n,insert:s}=j)=>{let a,o,i,c=0,u=new Set(r);for(;i=t[c++];)u.has(i)?a=a||i:n(i,e);for(a=a||l,c=0;i=r[c++];)o=a?a.nextSibling:l,a===i?a=o:(r[c]===o&&(a=o),s(i,a,e));return r};j.insert=(e,t,r)=>r.insertBefore(e,t),j.remove=(e,t)=>t.removeChild(e);var C=j,E=Symbol(":each");p.each=(e,[l,s,i],c)=>{const u=e[E]=document.createTextNode("");e.replaceWith(u);let f,p,d=0;const v=n((()=>{p=null;let e=i(c);return"number"==typeof e&&(e=Array.from({length:e},((e,t)=>t+1))),e?.constructor===Object&&(p=Object.keys(e),e=Object.values(e)),e||[]})),h=()=>{r((()=>{let t=0,r=v.value,n=r.length;if(f&&!f[o]){for(let e of f[a]||[])e[Symbol.dispose]();f=null,d=0}if(n<d)f.length=n;else{if(f)for(;t<d;t++)f[t]=r[t];else f=r;for(;t<n;t++){f[t]=r[t];let n=t,o=Object.create(c,{[l]:{get:()=>f[n]},[s]:{value:p?p[n]:n}}),i=(e.content||e).cloneNode(!0),d=e.content?[...i.childNodes]:[i];u.before(i),y(d,o),((f[a]||=[])[t]||={})[Symbol.dispose]=()=>{for(let e of d)e[Symbol.dispose](),e.remove()}}}d=n}))};let m=0;return t((()=>{f||v.value[o]?.value,m?m++:(h(),queueMicrotask((()=>(m&&h(),m=0))))}))},p.each.parse=(e,t)=>{let[r,l]=e.split(/\s+in\s+/),[n,s="$"]=r.split(/\s*,\s*/);return[n,s,t(l)]};var $=Symbol("if");p.if=(e,r,l)=>{let n,s,a,o=e.parentNode,i=e.nextElementSibling,c=document.createTextNode(""),u=[];return e.after(c),e.content?(n=u,e.remove(),s=[...e.content.childNodes]):s=n=[e],i?.hasAttribute(":else")?(i.removeAttribute(":else"),i.hasAttribute(":if")?a=u:(i.remove(),a=i.content?[...i.content.childNodes]:[i])):a=u,t((()=>{const t=r(l)?s:e[$]?u:a;if(i&&(i[$]=t===s),n!=t){n[0]?.[E]&&(n=[n[0][E]]);for(let e of n)e.remove();n=t;for(let e of n)o.insertBefore(e,c),y(e,l)}}))},p.default=(e,r,l,n)=>{let s,a=n.startsWith("on")&&n.slice(2);return t(a?()=>(s?.(),s=P(e,a,r(l))):()=>{let t=r(l);if(n)L(e,n,B(t,l));else for(let r in t)L(e,K(r),B(t[r],l))})};var P=(e,t,r=(()=>{}))=>{const l={evt:"",target:e,test:()=>!0};l.evt=t.replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,r="")=>(l.test=T[t]?.(l,...r.split("-"))||l.test,"")));const{evt:n,target:s,test:a,defer:o,stop:i,prevent:c,...u}=l;o&&(r=o(r));const f=e=>a(e)&&(i&&e.stopPropagation(),c&&e.preventDefault(),r.call(s,e));return s.addEventListener(n,f,u),()=>s.removeEventListener(n,f,u)},T={prevent(e){e.prevent=!0},stop(e){e.stop=!0},once(e){e.once=!0},passive(e){e.passive=!0},capture(e){e.capture=!0},window(e){e.target=window},document(e){e.target=document},throttle(e,t){e.defer=e=>_(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>D(e,t?Number(t)||0:108)},outside:e=>t=>{let r=e.target;return!(r.contains(t.target)||!1===t.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:e=>t=>t.target===e.target,ctrl:(e,...t)=>e=>W.ctrl(e)&&t.every((t=>W[t]?W[t](e):e.key===t)),shift:(e,...t)=>e=>W.shift(e)&&t.every((t=>W[t]?W[t](e):e.key===t)),alt:(e,...t)=>e=>W.alt(e)&&t.every((t=>W[t]?W[t](e):e.key===t)),meta:(e,...t)=>e=>W.meta(e)&&t.every((t=>W[t]?W[t](e):e.key===t)),arrow:()=>W.arrow,enter:()=>W.enter,escape:()=>W.escape,tab:()=>W.tab,space:()=>W.space,backspace:()=>W.backspace,delete:()=>W.delete,digit:()=>W.digit,letter:()=>W.letter,character:()=>W.character},W={ctrl:e=>e.ctrlKey||"Control"===e.key||"Ctrl"===e.key,shift:e=>e.shiftKey||"Shift"===e.key,alt:e=>e.altKey||"Alt"===e.key,meta:e=>e.metaKey||"Meta"===e.key||"Command"===e.key,arrow:e=>e.key.startsWith("Arrow"),enter:e=>"Enter"===e.key,escape:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,backspace:e=>"Backspace"===e.key,delete:e=>"Delete"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^[a-zA-Z]$/.test(e.key),character:e=>/^\S$/.test(e.key)},L=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},_=(e,t)=>{let r,l,n=s=>{r=!0,setTimeout((()=>{if(r=!1,l)return l=!1,n(s),e(s)}),t)};return t=>r?l=!0:(n(t),e(t))},D=(e,t)=>{let r;return l=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(l)}),t)}},K=e=>e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),B=(e,t)=>e?.replace?e.replace(/\$<([^>]+)>/g,((e,r)=>t[r]??"")):e;p.ref=(e,t,r)=>{Object.defineProperty(r,B(t,r),{value:e})},p.ref.parse=e=>e,p.with=(e,r,l)=>{let n,s;return t((()=>{s=r(l),Object.assign(n||=y(e,i(s,Object.create(l[a]))),s)}))},p.html=(e,t,r)=>{let l=t(r);if(!l)return;let n=(l.content||l).cloneNode(!0);e.replaceChildren(n),y(e,r)},p.text=(e,r,l)=>(e.content&&e.replaceWith(e=document.createTextNode("")),t((()=>{let t=r(l);e.textContent=null==t?"":t}))),p.class=(e,r,l)=>{let n=new Set;return t((()=>{let t=r(l),s=new Set;t&&("string"==typeof t?B(t,l).split(" ").map((e=>s.add(e))):Array.isArray(t)?t.map((e=>(e=B(e,l))&&s.add(e))):Object.entries(t).map((([e,t])=>t&&s.add(e))));for(let t of n)s.has(t)?s.delete(t):e.classList.remove(t);for(let t of n=s)e.classList.add(t)}))},p.style=(e,r,l)=>{let n=e.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),t((()=>{let t=r(l);if("string"==typeof t)e.setAttribute("style",n+B(t,l));else{e.setAttribute("style",n);for(let r in t)e.style.setProperty(r,B(t[r],l))}}))},p.value=(e,r,l)=>{let n,s,a="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(n=e.selectionStart,s=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),n&&e.setSelectionRange(n,s)):"checkbox"===e.type?t=>(e.checked=t,L(e,"checked",t)):"select-one"===e.type?t=>{for(let t in e.options)t.removeAttribute("selected");e.value=t,e.selectedOptions[0]?.setAttribute("selected","")}:t=>e.value=t;return t((()=>a(r(l))))},p.fx=(e,r,l)=>t((()=>r(l))),y.use(A),y.use({compile:e=>y.constructor("__scope",`with (__scope) { return ${e} };`)}),y.use({swap:C});var M=y;export{M as default};
1
+ var e,t,r,l,n,s=Object.defineProperty,a=Symbol("signals"),o=Symbol("length");function i(t){if(!t)return t;if(t[a])return t;if(Array.isArray(t))return function(t){let r;if(t[a])return t;let l=e(t.length),n=Array(t.length).fill(null);const s=new Proxy(n,{get:(s,c)=>"symbol"==typeof c?c===o?l:c===a?n:n[c]:"length"===c?Array.prototype[r]?l.peek():l.value:(r=c,n[c]?n[c].valueOf():c<n.length?(n[c]=e(i(t[c]))).value:void 0),set(e,t,r){if("length"===t){for(let e=r,t=n.length;e<t;e++)delete s[e];return l.value=n.length=r,!0}return c(n,t,r),t>=l.peek()&&(l.value=n.length=Number(t)+1),!0},deleteProperty:(e,t)=>(u(n,t),!0)});return s}(t);if(t.constructor!==Object)return t;let r={},l=e(Object.values(t).length);const s=new Proxy(r,{get:(e,t)=>t===o?l:t===a?r:r[t]?.valueOf(),set:(e,t,n,s)=>(s=r[t],c(r,t,n),s||++l.value),deleteProperty:(e,t)=>u(r,t)&&l.value--,ownKeys:()=>(l.value,Reflect.ownKeys(r))});for(let e in t){const l=Object.getOwnPropertyDescriptor(t,e);l?.get?(r[e]=n(l.get.bind(s)))._set=l.set?.bind(s):(r[e]=null,c(r,e,t[e]))}return s}function c(t,n,s){let a=t[n];if(a)if(s===a.peek());else if(a._set)a._set(s);else if(Array.isArray(s)&&Array.isArray(a.peek())){const e=a.peek();e[o]?r((()=>{l((()=>{let t=0,r=s.length;for(;t<r;t++)e[t]=s[t];e.length=r}))})):a.value=s}else a.value=i(s);else t[n]=a=s?.peek?s:e(i(s))}function u(e,t){const r=e[t];if(r){const l=r[Symbol.dispose];return l&&delete r[Symbol.dispose],delete e[t],l?.(),!0}}var f=Symbol.dispose||=Symbol("dispose"),p={},d=new WeakMap;function y(e,t){if(!e?.children)return;if(d.has(e))return Object.assign(d.get(e),t);const r=i(t||{}),l=[];return function e(t,n=t.parentNode){if(t.attributes)for(let e=0;e<t.attributes.length;){let s=t.attributes[e];if(":"===s.name[0]){t.removeAttribute(s.name);let e=s.name.slice(1).split(":");for(let n of e){let e=p[n]||p.default,a=e(t,(e.parse||b)(s.value,b),r,n);a&&l.push(a)}if(d.has(t))return l.push(t[f]);if(t.parentNode!==n)return}else e++}for(let r of[...t.children])e(r,t)}(e),d.has(e)||d.set(e,r),e[f]=()=>{for(;l.length;)l.pop()();d.delete(e)},r}var v,h={},b=(e,t,r)=>{if(r=h[e=e.trim()])return r;try{r=v(e)}catch(r){throw Object.assign(r,{message:`∴ ${r.message}\n\n${t}${e?`="${e}"\n\n`:""}`,expr:e})}return h[e]=r};y.use=s=>{s.signal&&function(s){e=s.signal,t=s.effect,n=s.computed,l=s.batch||(e=>e()),r=s.untracked||l}(s),s.compile&&(v=s.compile)};var g,m,k={};((e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})})(k,{batch:()=>O,computed:()=>w,effect:()=>S,signal:()=>A,untracked:()=>N});var A=(e,t,r=new Set)=>((t={get value(){return g?.deps.push(r.add(g)),e},set value(t){if(t!==e){e=t;for(let e of r)m?m.add(e):e()}},peek:()=>e}).toJSON=t.then=t.toString=t.valueOf=()=>t.value,t),S=(e,t,r,l)=>(l=(r=l=>{t?.call?.(),l=g,g=r;try{t=e()}finally{g=l}}).deps=[],r(),e=>{for(t?.call?.();e=l.pop();)e.delete(r)}),w=(e,t=A(),r,l)=>((r={get value(){return l||=S((()=>t.value=e())),t.value},peek:t.peek}).toJSON=r.then=r.toString=r.valueOf=()=>r.value,r),O=e=>{let t=m;t||(m=new Set);try{e()}finally{if(!t){t=m,m=null;for(const e of t)e()}}},N=(e,t,r)=>(t=g,g=null,r=e(),g=t,r),j=Symbol(":each");p.each=(e,[l,s,i],c)=>{const u=e[j]=document.createTextNode("");e.replaceWith(u);let f,p,d=0;const v=n((()=>{p=null;let e=i(c);return"number"==typeof e&&(e=Array.from({length:e},((e,t)=>t+1))),e?.constructor===Object&&(p=Object.keys(e),e=Object.values(e)),e||[]})),h=()=>{r((()=>{let t=0,r=v.value,n=r.length;if(f&&!f[o]){for(let e of f[a]||[])e[Symbol.dispose]();f=null,d=0}if(n<d)f.length=n;else{if(f)for(;t<d;t++)f[t]=r[t];else f=r;for(;t<n;t++){f[t]=r[t];let n=t,o=Object.create(c,{[l]:{get:()=>f[n]},[s]:{value:p?p[n]:n}}),i=(e.content||e).cloneNode(!0),d=e.content?{children:[...i.children],remove(){this.children.map((e=>e.remove()))}}:i;u.before(i),y(d,o),((f[a]||=[])[t]||={})[Symbol.dispose]=()=>{d[Symbol.dispose](),d.remove()}}}d=n}))};let b=0;return t((()=>{f||v.value[o]?.value,b?b++:(h(),queueMicrotask((()=>(b&&h(),b=0))))}))},p.each.parse=(e,t)=>{let[r,l]=e.split(/\s+in\s+/),[n,s="$"]=r.split(/\s*,\s*/);return[n,s,t(l)]};var x=Symbol("if");p.if=(e,r,l)=>{let n,s,a,o=e.parentNode,i=e.nextElementSibling,c=document.createTextNode(""),u=[];return e.after(c),e.content?(n=u,e.remove(),s=[...e.content.childNodes]):s=n=[e],i?.hasAttribute(":else")?(i.removeAttribute(":else"),i.hasAttribute(":if")?a=u:(i.remove(),a=i.content?[...i.content.childNodes]:[i])):a=u,t((()=>{const t=r(l)?s:e[x]?u:a;if(i&&(i[x]=t===s),n!=t){n[0]?.[j]&&(n=[n[0][j]]);for(let e of n)e.remove();n=t;for(let e of n)o.insertBefore(e,c),y(e,l)}}))},p.default=(e,r,l,n)=>{let s,a=n.startsWith("on")&&n.slice(2);return t(a?()=>(s?.(),s=$(e,a,r(l))):()=>{let t=r(l);if(n)T(e,n,D(t,l));else for(let r in t)T(e,_(r),D(t[r],l))})};var $=(e,t,r=(()=>{}))=>{const l={evt:"",target:e,test:()=>!0};l.evt=t.replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,r="")=>(l.test=E[t]?.(l,...r.split("-"))||l.test,"")));const{evt:n,target:s,test:a,defer:o,stop:i,prevent:c,...u}=l;o&&(r=o(r));const f=e=>a(e)&&(i&&e.stopPropagation(),c&&e.preventDefault(),r.call(s,e));return s.addEventListener(n,f,u),()=>s.removeEventListener(n,f,u)},E={prevent(e){e.prevent=!0},stop(e){e.stop=!0},once(e){e.once=!0},passive(e){e.passive=!0},capture(e){e.capture=!0},window(e){e.target=window},document(e){e.target=document},throttle(e,t){e.defer=e=>C(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>W(e,t?Number(t)||0:108)},outside:e=>t=>{let r=e.target;return!(r.contains(t.target)||!1===t.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:e=>t=>t.target===e.target,ctrl:(e,...t)=>e=>P.ctrl(e)&&t.every((t=>P[t]?P[t](e):e.key===t)),shift:(e,...t)=>e=>P.shift(e)&&t.every((t=>P[t]?P[t](e):e.key===t)),alt:(e,...t)=>e=>P.alt(e)&&t.every((t=>P[t]?P[t](e):e.key===t)),meta:(e,...t)=>e=>P.meta(e)&&t.every((t=>P[t]?P[t](e):e.key===t)),arrow:()=>P.arrow,enter:()=>P.enter,escape:()=>P.escape,tab:()=>P.tab,space:()=>P.space,backspace:()=>P.backspace,delete:()=>P.delete,digit:()=>P.digit,letter:()=>P.letter,character:()=>P.character},P={ctrl:e=>e.ctrlKey||"Control"===e.key||"Ctrl"===e.key,shift:e=>e.shiftKey||"Shift"===e.key,alt:e=>e.altKey||"Alt"===e.key,meta:e=>e.metaKey||"Meta"===e.key||"Command"===e.key,arrow:e=>e.key.startsWith("Arrow"),enter:e=>"Enter"===e.key,escape:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,backspace:e=>"Backspace"===e.key,delete:e=>"Delete"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^[a-zA-Z]$/.test(e.key),character:e=>/^\S$/.test(e.key)},T=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},C=(e,t)=>{let r,l,n=s=>{r=!0,setTimeout((()=>{if(r=!1,l)return l=!1,n(s),e(s)}),t)};return t=>r?l=!0:(n(t),e(t))},W=(e,t)=>{let r;return l=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(l)}),t)}},_=e=>e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),D=(e,t)=>e?.replace?e.replace(/\$<([^>]+)>/g,((e,r)=>t[r]??"")):e;p.ref=(e,t,r)=>{Object.defineProperty(r,D(t,r),{value:e})},p.ref.parse=e=>e,p.with=(e,r,l)=>{let n;return t((()=>{let t=r(l);if(n)Object.assign(n,t);else{n=i({}),Object.assign(n[a],l[a]);for(let e in t)n[a][e]=null,n[e]=t[e];y(e,n)}}))},p.html=(e,t,r)=>{let l=t(r);if(!l)return;let n=(l.content||l).cloneNode(!0);e.replaceChildren(n),y(e,r)},p.text=(e,r,l)=>(e.content&&e.replaceWith(e=document.createTextNode("")),t((()=>{let t=r(l);e.textContent=null==t?"":t}))),p.class=(e,r,l)=>{let n=new Set;return t((()=>{let t=r(l),s=new Set;t&&("string"==typeof t?D(t,l).split(" ").map((e=>s.add(e))):Array.isArray(t)?t.map((e=>(e=D(e,l))&&s.add(e))):Object.entries(t).map((([e,t])=>t&&s.add(e))));for(let t of n)s.has(t)?s.delete(t):e.classList.remove(t);for(let t of n=s)e.classList.add(t)}))},p.style=(e,r,l)=>{let n=e.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),t((()=>{let t=r(l);if("string"==typeof t)e.setAttribute("style",n+D(t,l));else{e.setAttribute("style",n);for(let r in t)e.style.setProperty(r,D(t[r],l))}}))},p.value=(e,r,l)=>{let n,s,a="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(n=e.selectionStart,s=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),n&&e.setSelectionRange(n,s)):"checkbox"===e.type?t=>(e.checked=t,T(e,"checked",t)):"select-one"===e.type?t=>{for(let t in e.options)t.removeAttribute("selected");e.value=t,e.selectedOptions[0]?.setAttribute("selected","")}:t=>e.value=t;return t((()=>a(r(l))))},p.fx=(e,r,l)=>t((()=>r(l))),y.use(k),y.use({compile:e=>y.constructor("__scope",`with (__scope) { return ${e} };`)});var K=y;export{K as default};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sprae",
3
3
  "description": "DOM microhydration.",
4
- "version": "10.0.1",
4
+ "version": "10.1.1",
5
5
  "main": "./sprae.js",
6
6
  "module": "./sprae.js",
7
7
  "type": "module",
package/readme.md CHANGED
@@ -144,7 +144,7 @@ Set any attribute(s).
144
144
  Define values for a subtree.
145
145
 
146
146
  ```html
147
- <x :with="{ foo: signal('bar') }">
147
+ <x :with="{ foo: 'bar' }">
148
148
  <y :with="{ baz: 'qux' }" :text="foo + baz"></y>
149
149
  </x>
150
150
  ```
@@ -335,7 +335,7 @@ import { effect } from 'sprae/signal'
335
335
  import * as signals from '@preact/signals'
336
336
  import compile from 'subscript'
337
337
 
338
- // include directives
338
+ // standard directives
339
339
  import 'sprae/directive/if.js'
340
340
  import 'sprae/directive/text.js'
341
341
 
@@ -358,9 +358,10 @@ To destroy state and detach sprae handlers, call `element[Symbol.dispose]()`. --
358
358
 
359
359
  ## Justification
360
360
 
361
- [Template-parts](https://github.com/dy/template-parts) is stuck with native HTML quirks ([parsing table](https://github.com/github/template-parts/issues/24), [SVG attributes](https://github.com/github/template-parts/issues/25), [liquid syntax](https://shopify.github.io/liquid/tags/template/#raw) conflict etc). [Alpine](https://github.com/alpinejs/alpine) / [petite-vue](https://github.com/vuejs/petite-vue) / [lucia](https://github.com/aidenyabi/lucia) escape native HTML quirks, but have excessive API (`:`, `x-`, `{}`, `@`, `$`) and tend to [self-encapsulate](https://github.com/alpinejs/alpine/discussions/3223).
361
+ [Template-parts](https://github.com/dy/template-parts) is stuck with native HTML quirks ([parsing table](https://github.com/github/template-parts/issues/24), [SVG attributes](https://github.com/github/template-parts/issues/25), [liquid syntax](https://shopify.github.io/liquid/tags/template/#raw) conflict etc).<br/>
362
+ [Alpine](https://github.com/alpinejs/alpine) / [petite-vue](https://github.com/vuejs/petite-vue) / [lucia](https://github.com/aidenyabi/lucia) escape native HTML quirks, but have excessive API (`:`, `x-`, `{}`, `@`, `$`) and tend to [self-encapsulate](https://github.com/alpinejs/alpine/discussions/3223).
362
363
 
363
- _Sprae_ holds open & minimalistic philosophy, combining _`:`-directives_ with emerging _signals_.
364
+ _Sprae_ holds open & minimalistic philosophy, combining _`:`-directives_ with _signals_.
364
365
 
365
366
  <!--
366
367
  | | [AlpineJS](https://github.com/alpinejs/alpine) | [Petite-Vue](https://github.com/vuejs/petite-vue) | Sprae |
@@ -406,14 +407,14 @@ npm ci
406
407
  npm run build-prod
407
408
 
408
409
  # bench
409
- cd ../../../webdriver-ts
410
+ [cd ../../../webdriver-ts
410
411
  npm ci
411
- npm run compile
412
+ npm run compile]
412
413
  npm run bench keyed/sprae
413
414
 
414
415
  # show results
415
- cd ../webdriver-ts-results
416
- npm ci
416
+ [cd ../webdriver-ts-results
417
+ npm ci]
417
418
  cd ../webdriver-ts
418
419
  npm run results
419
420
  ```
package/sprae.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import sprae from './core.js'
2
2
 
3
3
  import * as signals from 'ulive'
4
- import swap from 'swapdom/deflate'
5
4
 
6
5
  // default directives
7
6
  import './directive/if.js'
@@ -22,7 +21,4 @@ sprae.use(signals)
22
21
  // default compiler (indirect new Function to avoid detector)
23
22
  sprae.use({ compile: expr => sprae.constructor(`__scope`, `with (__scope) { return ${expr} };`) })
24
23
 
25
- // defaul dom swapper
26
- sprae.use({ swap })
27
-
28
24
  export default sprae
package/store.js CHANGED
@@ -4,11 +4,11 @@ import { signal, computed, effect, batch, untracked } from './signal.js'
4
4
  export const _signals = Symbol('signals'), _change = Symbol('length');
5
5
 
6
6
  // object store is not lazy
7
- export default function store(values, signals) {
7
+ export default function store(values) {
8
8
  if (!values) return values
9
9
 
10
10
  // ignore existing state as argument
11
- if (values[_signals] && !signals) return values;
11
+ if (values[_signals]) return values;
12
12
 
13
13
  // redirect for optimized array store
14
14
  if (Array.isArray(values)) return list(values)
@@ -17,9 +17,8 @@ export default function store(values, signals) {
17
17
  if (values.constructor !== Object) return values;
18
18
 
19
19
  // NOTE: if you decide to unlazy values, think about large arrays - init upfront can be costly
20
- let _len = signal(Object.values(values).length)
20
+ let signals = {}, _len = signal(Object.values(values).length)
21
21
 
22
- signals ||= {}
23
22
  // proxy conducts prop access to signals
24
23
  const state = new Proxy(signals, {
25
24
  get: (_, key) => key === _change ? _len : key === _signals ? signals : signals[key]?.valueOf(),
@@ -32,9 +31,8 @@ export default function store(values, signals) {
32
31
  },
33
32
  })
34
33
 
35
- // take over existing store signals instead of creating new ones
36
- if (values[_signals]) for (let key in values) signals[key] = values[_signals][key];
37
- else for (let key in values) {
34
+ // init signals for values
35
+ for (let key in values) {
38
36
  const desc = Object.getOwnPropertyDescriptor(values, key)
39
37
 
40
38
  // getter turns into computed
@@ -69,8 +67,8 @@ export function list(values) {
69
67
  // proxy conducts prop access to signals
70
68
  const state = new Proxy(signals, {
71
69
  get(_, key) {
72
- if (key === _change) return _len
73
- if (key === _signals) return signals
70
+ // covers Symbol.isConcatSpreadable etc.
71
+ if (typeof key === 'symbol') return key === _change ? _len : key === _signals ? signals : signals[key]
74
72
 
75
73
  // console.log('get', key)
76
74
  // if .length is read within .push/etc - peek signal to avoid recursive subscription