sprae 10.0.1 → 10.1.0

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) {
@@ -131,62 +126,50 @@ function del(signals, key) {
131
126
 
132
127
  // core.js
133
128
  var _dispose = Symbol.dispose ||= Symbol("dispose");
134
- var SPRAE = `\u2234`;
135
129
  var directive = {};
136
130
  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
- }
131
+ function sprae(el, values) {
132
+ if (!el?.children)
133
+ return;
134
+ if (memo.has(el)) {
135
+ return Object.assign(memo.get(el), values);
177
136
  }
178
- for (let child of [...el.children])
179
- init(child, state, el);
180
- el.classList?.add(SPRAE);
137
+ const state = store(values || {}), disposes = [];
138
+ init(el);
139
+ if (!memo.has(el))
140
+ memo.set(el, state);
181
141
  el[_dispose] = () => {
182
- while (effects.length)
183
- effects.pop()();
184
- el.classList.remove(SPRAE);
142
+ while (disposes.length)
143
+ disposes.pop()();
185
144
  memo.delete(el);
186
- let els = el.getElementsByClassName(SPRAE);
187
- while (els.length)
188
- els[0][_dispose]?.();
189
145
  };
146
+ return state;
147
+ function init(el2, parent = el2.parentNode) {
148
+ if (el2.attributes) {
149
+ for (let i = 0; i < el2.attributes.length; ) {
150
+ let attr2 = el2.attributes[i];
151
+ if (attr2.name[0] === ":") {
152
+ el2.removeAttribute(attr2.name);
153
+ let names = attr2.name.slice(1).split(":");
154
+ for (let name of names) {
155
+ let dir = directive[name] || directive.default;
156
+ let evaluate = (dir.parse || parse)(attr2.value, parse);
157
+ let dispose = dir(el2, evaluate, state, name);
158
+ if (dispose)
159
+ disposes.push(dispose);
160
+ }
161
+ if (memo.has(el2))
162
+ return disposes.push(el2[_dispose]);
163
+ if (el2.parentNode !== parent)
164
+ return;
165
+ } else
166
+ i++;
167
+ }
168
+ }
169
+ for (let child of [...el2.children])
170
+ init(child, el2);
171
+ }
172
+ ;
190
173
  }
191
174
  var evalMemo = {};
192
175
  var parse = (expr, dir, fn) => {
@@ -273,28 +256,6 @@ var batch2 = (fn) => {
273
256
  };
274
257
  var untracked2 = (fn, prev, v) => (prev = current, current = null, v = fn(), current = prev, v);
275
258
 
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
259
  // directive/each.js
299
260
  var _each = Symbol(":each");
300
261
  directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
@@ -336,12 +297,13 @@ directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
336
297
  return cur[idx];
337
298
  } },
338
299
  [idxVar]: { value: keys2 ? keys2[idx] : idx }
339
- }), el = (tpl.content || tpl).cloneNode(true), els = tpl.content ? [...el.childNodes] : [el];
300
+ }), el = (tpl.content || tpl).cloneNode(true), frag = tpl.content ? { children: [...el.children], remove() {
301
+ this.children.map((el2) => el2.remove());
302
+ } } : el;
340
303
  holder.before(el);
341
- sprae(els, scope);
304
+ sprae(frag, scope);
342
305
  ((cur[_signals] ||= [])[i] ||= {})[Symbol.dispose] = () => {
343
- for (let el2 of els)
344
- el2[Symbol.dispose](), el2.remove();
306
+ frag[Symbol.dispose](), frag.remove();
345
307
  };
346
308
  }
347
309
  }
@@ -543,16 +505,18 @@ directive.ref.parse = (expr) => expr;
543
505
 
544
506
  // directive/with.js
545
507
  directive.with = (el, evaluate, rootState) => {
546
- let state, values;
508
+ let state;
547
509
  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);
510
+ let values = evaluate(rootState);
511
+ if (!state) {
512
+ state = store({});
513
+ Object.assign(state[_signals], rootState[_signals]);
514
+ for (let key in values)
515
+ state[_signals][key] = null, state[key] = values[key];
516
+ sprae(el, state);
517
+ } else {
518
+ Object.assign(state, values);
519
+ }
556
520
  });
557
521
  };
558
522
 
@@ -637,7 +601,6 @@ directive.fx = (el, evaluate, state) => {
637
601
  // sprae.js
638
602
  sprae.use(ulive_es_exports);
639
603
  sprae.use({ compile: (expr) => sprae.constructor(`__scope`, `with (__scope) { return ${expr} };`) });
640
- sprae.use({ swap: deflate_default });
641
604
  var sprae_default = sprae;
642
605
  export {
643
606
  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)=>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 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||g)(s.value,g),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={},g=(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 b,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 b?.deps.push(r.add(b)),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=b,b=r;try{t=e()}finally{b=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=b,b=null,r=e(),b=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 g=0;return t((()=>{f||v.value[o]?.value,g?g++:(h(),queueMicrotask((()=>(g&&h(),g=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.0",
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 |
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