sprae 10.6.3 → 10.8.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
@@ -12,8 +12,8 @@ export const memo = new WeakMap();
12
12
 
13
13
  // sprae element: apply directives
14
14
  export default function sprae(el, values) {
15
- // text nodes, comments etc - but collections are fine
16
- if (!el?.children) return
15
+ // text nodes, comments etc
16
+ if (!el?.childNodes) return
17
17
 
18
18
  // repeated call can be caused by :each with new objects with old keys needs an update
19
19
  if (memo.has(el)) {
@@ -38,35 +38,35 @@ export default function sprae(el, values) {
38
38
  return state;
39
39
 
40
40
  function init(el, parent = el.parentNode) {
41
- if (el.attributes) {
42
- // init generic-name attributes second
43
- for (let i = 0; i < el.attributes.length;) {
44
- let attr = el.attributes[i];
45
-
46
- if (attr.name[0] === ':') {
47
- el.removeAttribute(attr.name);
48
-
49
- // multiple attributes like :id:for=""
50
- let names = attr.name.slice(1).split(':')
51
-
52
- // NOTE: secondary directives don't stop flow nor extend state, so no need to check
53
- for (let name of names) {
54
- let dir = directive[name] || directive.default
55
- let evaluate = (dir.parse || parse)(attr.value, parse)
56
- let dispose = dir(el, evaluate, state, name);
57
- if (dispose) disposes.push(dispose);
58
- }
59
-
60
- // stop if element was spraed by internal directive
61
- if (memo.has(el)) return el[_dispose] && disposes.push(el[_dispose])
62
-
63
- // stop if element is skipped (detached) like in case of :if or :each
64
- if (el.parentNode !== parent) return
65
- } else i++;
66
- }
41
+ if (!el.childNodes) return // ignore text nodes, comments etc
42
+
43
+ // init generic-name attributes second
44
+ for (let i = 0; i < el.attributes?.length;) {
45
+ let attr = el.attributes[i];
46
+
47
+ if (attr.name[0] === ':') {
48
+ el.removeAttribute(attr.name);
49
+
50
+ // multiple attributes like :id:for=""
51
+ let names = attr.name.slice(1).split(':')
52
+
53
+ // NOTE: secondary directives don't stop flow nor extend state, so no need to check
54
+ for (let name of names) {
55
+ let dir = directive[name] || directive.default
56
+ let evaluate = (dir.parse || parse)(attr.value, parse)
57
+ let dispose = dir(el, evaluate, state, name);
58
+ if (dispose) disposes.push(dispose);
59
+ }
60
+
61
+ // stop if element was spraed by internal directive
62
+ if (memo.has(el)) return el[_dispose] && disposes.push(el[_dispose])
63
+
64
+ // stop if element is skipped (detached) like in case of :if or :each
65
+ if (el.parentNode !== parent) return
66
+ } else i++;
67
67
  }
68
68
 
69
- for (let child of [...el.children]) init(child, el);
69
+ for (let child of [...el.childNodes]) init(child, el);
70
70
  };
71
71
  }
72
72
 
@@ -97,3 +97,28 @@ sprae.use = s => {
97
97
  s.signal && use(s);
98
98
  s.compile && (compile = s.compile);
99
99
  }
100
+
101
+
102
+ // instantiated <template> fragment holder, like persisting fragment but with minimal API surface
103
+ export const frag = (tpl) => {
104
+ if (!tpl.nodeType) return tpl // existing tpl
105
+
106
+ // ensure at least one node
107
+ tpl.content.appendChild(document.createTextNode(''))
108
+
109
+ let content = tpl.content.cloneNode(true),
110
+ attributes = [...tpl.attributes],
111
+ childNodes = [...content.childNodes]
112
+
113
+ return {
114
+ childNodes,
115
+ content,
116
+ remove: () => content.append(...childNodes),
117
+ replaceWith(el) {
118
+ childNodes[0].before(el)
119
+ content.append(...childNodes)
120
+ },
121
+ attributes,
122
+ removeAttribute(name) { attributes.splice(attributes.findIndex(a => a.name === name), 1) }
123
+ }
124
+ }
@@ -1,5 +1,4 @@
1
1
  import { directive } from "../core.js";
2
- import { ipol } from './default.js';
3
2
  import { effect } from "../signal.js";
4
3
 
5
4
  directive.class = (el, evaluate, state) => {
@@ -8,8 +7,8 @@ directive.class = (el, evaluate, state) => {
8
7
  let v = evaluate(state);
9
8
  let clsx = new Set;
10
9
  if (v) {
11
- if (typeof v === "string") ipol(v, state).split(' ').map(cls => clsx.add(cls));
12
- else if (Array.isArray(v)) v.map(v => (v = ipol(v, state)) && clsx.add(v));
10
+ if (typeof v === "string") v.split(' ').map(cls => clsx.add(cls));
11
+ else if (Array.isArray(v)) v.map(v => v && clsx.add(v));
13
12
  else Object.entries(v).map(([k, v]) => v && clsx.add(k));
14
13
  }
15
14
  for (let cls of cur) if (clsx.has(cls)) clsx.delete(cls); else el.classList.remove(cls);
@@ -6,8 +6,8 @@ directive.default = (target, evaluate, state, name) => {
6
6
  // simple prop
7
7
  if (!name.startsWith('on')) return effect(() => {
8
8
  let value = evaluate(state);
9
- if (name) attr(target, name, ipol(value, state))
10
- else for (let key in value) attr(target, dashcase(key), ipol(value[key], state));
9
+ if (name) attr(target, name, value)
10
+ else for (let key in value) attr(target, dashcase(key), value[key]);
11
11
  });
12
12
 
13
13
  // bind event to a target
@@ -155,8 +155,3 @@ const debounce = (fn, wait) => {
155
155
  export const dashcase = (str) => {
156
156
  return str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => "-" + match.toLowerCase());
157
157
  }
158
-
159
- // interpolate a$<b> fields from context
160
- export const ipol = (v, state) => {
161
- return v?.replace ? v.replace(/\$<([^>]+)>/g, (match, field) => state[field] ?? '') : v
162
- };
package/directive/each.js CHANGED
@@ -1,13 +1,11 @@
1
- import sprae, { directive } from "../core.js";
1
+ import sprae, { directive, frag } from "../core.js";
2
2
  import store, { _change, _signals } from "../store.js";
3
3
  import { effect, untracked, computed } from '../signal.js';
4
4
 
5
5
 
6
- export const _each = Symbol(":each");
7
-
8
6
  directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
9
7
  // we need :if to be able to replace holder instead of tpl for :if :each case
10
- const holder = (tpl[_each] = document.createTextNode(""));
8
+ const holder = (document.createTextNode(""));
11
9
  tpl.replaceWith(holder);
12
10
 
13
11
  // we re-create items any time new items are produced
@@ -58,18 +56,14 @@ directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
58
56
  [itemVar]: cur[_signals]?.[idx] || cur[idx],
59
57
  [idxVar]: keys ? keys[idx] : idx
60
58
  }, state),
61
- el = (tpl.content || tpl).cloneNode(true),
62
- frag = tpl.content ?
63
- // fake fragment to allow sprae multiple elements
64
- { children: [...el.children], remove() { this.children.map(el => el.remove()) } } :
65
- el;
59
+ el = tpl.content ? frag(tpl) : tpl.cloneNode(true);
66
60
 
67
- holder.before(el);
68
- sprae(frag, scope);
61
+ holder.before(el.content || el);
62
+ sprae(el, scope);
69
63
 
70
64
  // signal/holder disposal removes element
71
65
  ((cur[_signals] ||= [])[i] ||= {})[Symbol.dispose] = () => {
72
- frag[Symbol.dispose](), frag.remove()
66
+ el[Symbol.dispose](), el.remove()
73
67
  };
74
68
  }
75
69
  }
package/directive/if.js CHANGED
@@ -1,5 +1,4 @@
1
- import sprae, { directive, memo } from "../core.js";
2
- import { _each } from './each.js';
1
+ import sprae, { directive, memo, frag } from "../core.js";
3
2
  import { effect } from "../signal.js";
4
3
 
5
4
  // :if is interchangeable with :each depending on order, :if :each or :each :if have different meanings
@@ -7,24 +6,21 @@ import { effect } from "../signal.js";
7
6
  // we consider :with={x} :if={x} case insignificant
8
7
  const _prevIf = Symbol("if");
9
8
  directive.if = (ifEl, evaluate, state) => {
10
- let parent = ifEl.parentNode,
11
- next = ifEl.nextElementSibling,
9
+ let next = ifEl.nextElementSibling,
12
10
  holder = document.createTextNode(''),
13
11
 
14
12
  // actual replaceable els (takes <template>)
15
- cur, ifs, elses, none = [];
13
+ none = [], cur = none, ifs, elses;
16
14
 
17
- ifEl.after(holder) // mark end of modifying section
15
+ ifEl.replaceWith(holder)
18
16
 
19
- ifEl.remove(), cur = none
20
-
21
- ifs = ifEl.content ? [...ifEl.content.childNodes] : [ifEl]
17
+ ifs = ifEl.content ? [frag(ifEl)] : [ifEl]
22
18
 
23
19
  if (next?.hasAttribute(":else")) {
24
20
  next.removeAttribute(":else");
25
21
  // if next is :else :if - leave it for its own :if handler
26
22
  if (next.hasAttribute(":if")) elses = none;
27
- else next.remove(), elses = next.content ? [...next.content.childNodes] : [next];
23
+ else next.remove(), elses = next.content ? [frag(next)] : [next];
28
24
  } else elses = none;
29
25
 
30
26
  // we mark all els as fake-spraed, because we have to sprae for real on insert
@@ -34,13 +30,10 @@ directive.if = (ifEl, evaluate, state) => {
34
30
  const newEls = evaluate(state) ? ifs : ifEl[_prevIf] ? none : elses;
35
31
  if (next) next[_prevIf] = newEls === ifs
36
32
  if (cur != newEls) {
37
- // :if :each
38
- if (cur[0]?.[_each]) cur = [cur[0][_each]]
39
-
40
33
  for (let el of cur) el.remove();
41
34
  cur = newEls;
42
35
  for (let el of cur) {
43
- parent.insertBefore(el, holder)
36
+ holder.before(el.content || el)
44
37
  memo.get(el) === null && memo.delete(el) // remove fake memo to sprae as new
45
38
  sprae(el, state)
46
39
  }
package/directive/ref.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import { directive } from "../core.js";
2
2
  import { _change, _signals } from "../store.js";
3
- import { ipol } from './default.js';
4
3
 
5
4
  // ref must be last within primaries, since that must be skipped by :each, but before secondaries
6
5
  directive.ref = (el, expr, state) => {
7
- state[ipol(expr, state)] = el
6
+ state[expr] = el
8
7
  }
9
8
 
10
9
  directive.ref.parse = expr => expr
@@ -1,5 +1,4 @@
1
1
  import { directive } from "../core.js";
2
- import { ipol } from './default.js';
3
2
  import { effect } from "../signal.js";
4
3
 
5
4
  directive.style = (el, evaluate, state) => {
@@ -8,10 +7,10 @@ directive.style = (el, evaluate, state) => {
8
7
 
9
8
  return effect(() => {
10
9
  let v = evaluate(state);
11
- if (typeof v === "string") el.setAttribute("style", initStyle + ipol(v, state));
10
+ if (typeof v === "string") el.setAttribute("style", initStyle + v);
12
11
  else {
13
12
  el.setAttribute("style", initStyle);
14
- for (let k in v) el.style.setProperty(k, ipol(v[k], state));
13
+ for (let k in v) el.style.setProperty(k, v[k]);
15
14
  }
16
15
  });
17
16
  };
package/directive/text.js CHANGED
@@ -1,9 +1,14 @@
1
- import { directive } from "../core.js";
1
+ import { directive, frag } from "../core.js";
2
2
  import { effect } from "../signal.js";
3
3
 
4
4
  // set text content
5
5
  directive.text = (el, evaluate, state) => {
6
- if (el.content) el.replaceWith(el = document.createTextNode('')) // <template :text="abc"/>
6
+ // <template :text="a"/> or previously initialized template
7
+ if (el.content) {
8
+ let tplfrag = frag(el)
9
+ if (el !== tplfrag) el.replaceWith(tplfrag.content);
10
+ el = tplfrag.childNodes[0];
11
+ }
7
12
 
8
13
  return effect(() => {
9
14
  let value = evaluate(state);
package/dist/sprae.js CHANGED
@@ -126,7 +126,7 @@ var _dispose = Symbol.dispose ||= Symbol("dispose");
126
126
  var directive = {};
127
127
  var memo = /* @__PURE__ */ new WeakMap();
128
128
  function sprae(el, values) {
129
- if (!el?.children)
129
+ if (!el?.childNodes)
130
130
  return;
131
131
  if (memo.has(el)) {
132
132
  return Object.assign(memo.get(el), values);
@@ -142,28 +142,28 @@ function sprae(el, values) {
142
142
  };
143
143
  return state;
144
144
  function init(el2, parent = el2.parentNode) {
145
- if (el2.attributes) {
146
- for (let i = 0; i < el2.attributes.length; ) {
147
- let attr2 = el2.attributes[i];
148
- if (attr2.name[0] === ":") {
149
- el2.removeAttribute(attr2.name);
150
- let names = attr2.name.slice(1).split(":");
151
- for (let name of names) {
152
- let dir = directive[name] || directive.default;
153
- let evaluate = (dir.parse || parse)(attr2.value, parse);
154
- let dispose = dir(el2, evaluate, state, name);
155
- if (dispose)
156
- disposes.push(dispose);
157
- }
158
- if (memo.has(el2))
159
- return el2[_dispose] && disposes.push(el2[_dispose]);
160
- if (el2.parentNode !== parent)
161
- return;
162
- } else
163
- i++;
164
- }
145
+ if (!el2.childNodes)
146
+ return;
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 el2[_dispose] && disposes.push(el2[_dispose]);
161
+ if (el2.parentNode !== parent)
162
+ return;
163
+ } else
164
+ i++;
165
165
  }
166
- for (let child of [...el2.children])
166
+ for (let child of [...el2.childNodes])
167
167
  init(child, el2);
168
168
  }
169
169
  ;
@@ -191,6 +191,25 @@ sprae.use = (s) => {
191
191
  s.signal && use(s);
192
192
  s.compile && (compile = s.compile);
193
193
  };
194
+ var frag = (tpl) => {
195
+ if (!tpl.nodeType)
196
+ return tpl;
197
+ tpl.content.appendChild(document.createTextNode(""));
198
+ let content = tpl.content.cloneNode(true), attributes = [...tpl.attributes], childNodes = [...content.childNodes];
199
+ return {
200
+ childNodes,
201
+ content,
202
+ remove: () => content.append(...childNodes),
203
+ replaceWith(el) {
204
+ childNodes[0].before(el);
205
+ content.append(...childNodes);
206
+ },
207
+ attributes,
208
+ removeAttribute(name) {
209
+ attributes.splice(attributes.findIndex((a) => a.name === name), 1);
210
+ }
211
+ };
212
+ };
194
213
 
195
214
  // node_modules/ulive/dist/ulive.es.js
196
215
  var ulive_es_exports = {};
@@ -256,10 +275,42 @@ var batch2 = (fn) => {
256
275
  };
257
276
  var untracked2 = (fn, prev, v) => (prev = current, current = null, v = fn(), current = prev, v);
258
277
 
278
+ // directive/if.js
279
+ var _prevIf = Symbol("if");
280
+ directive.if = (ifEl, evaluate, state) => {
281
+ let next = ifEl.nextElementSibling, holder = document.createTextNode(""), none = [], cur = none, ifs, elses;
282
+ ifEl.replaceWith(holder);
283
+ ifs = ifEl.content ? [frag(ifEl)] : [ifEl];
284
+ if (next?.hasAttribute(":else")) {
285
+ next.removeAttribute(":else");
286
+ if (next.hasAttribute(":if"))
287
+ elses = none;
288
+ else
289
+ next.remove(), elses = next.content ? [frag(next)] : [next];
290
+ } else
291
+ elses = none;
292
+ for (let el of [...ifs, ...elses])
293
+ memo.set(el, null);
294
+ return effect(() => {
295
+ const newEls = evaluate(state) ? ifs : ifEl[_prevIf] ? none : elses;
296
+ if (next)
297
+ next[_prevIf] = newEls === ifs;
298
+ if (cur != newEls) {
299
+ for (let el of cur)
300
+ el.remove();
301
+ cur = newEls;
302
+ for (let el of cur) {
303
+ holder.before(el.content || el);
304
+ memo.get(el) === null && memo.delete(el);
305
+ sprae(el, state);
306
+ }
307
+ }
308
+ });
309
+ };
310
+
259
311
  // directive/each.js
260
- var _each = Symbol(":each");
261
312
  directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
262
- const holder = tpl[_each] = document.createTextNode("");
313
+ const holder = document.createTextNode("");
263
314
  tpl.replaceWith(holder);
264
315
  let cur, keys2, prevl = 0;
265
316
  const items = computed(() => {
@@ -295,13 +346,11 @@ directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
295
346
  let idx = i, scope = store({
296
347
  [itemVar]: cur[_signals]?.[idx] || cur[idx],
297
348
  [idxVar]: keys2 ? keys2[idx] : idx
298
- }, state), el = (tpl.content || tpl).cloneNode(true), frag = tpl.content ? { children: [...el.children], remove() {
299
- this.children.map((el2) => el2.remove());
300
- } } : el;
301
- holder.before(el);
302
- sprae(frag, scope);
349
+ }, state), el = tpl.content ? frag(tpl) : tpl.cloneNode(true);
350
+ holder.before(el.content || el);
351
+ sprae(el, scope);
303
352
  ((cur[_signals] ||= [])[i] ||= {})[Symbol.dispose] = () => {
304
- frag[Symbol.dispose](), frag.remove();
353
+ el[Symbol.dispose](), el.remove();
305
354
  };
306
355
  }
307
356
  }
@@ -324,38 +373,82 @@ directive.each.parse = (expr, parse2) => {
324
373
  return [itemVar, idxVar, parse2(itemsExpr)];
325
374
  };
326
375
 
327
- // directive/if.js
328
- var _prevIf = Symbol("if");
329
- directive.if = (ifEl, evaluate, state) => {
330
- let parent = ifEl.parentNode, next = ifEl.nextElementSibling, holder = document.createTextNode(""), cur, ifs, elses, none = [];
331
- ifEl.after(holder);
332
- ifEl.remove(), cur = none;
333
- ifs = ifEl.content ? [...ifEl.content.childNodes] : [ifEl];
334
- if (next?.hasAttribute(":else")) {
335
- next.removeAttribute(":else");
336
- if (next.hasAttribute(":if"))
337
- elses = none;
338
- else
339
- next.remove(), elses = next.content ? [...next.content.childNodes] : [next];
340
- } else
341
- elses = none;
342
- for (let el of [...ifs, ...elses])
343
- memo.set(el, null);
376
+ // directive/ref.js
377
+ directive.ref = (el, expr, state) => {
378
+ state[expr] = el;
379
+ };
380
+ directive.ref.parse = (expr) => expr;
381
+
382
+ // directive/with.js
383
+ directive.with = (el, evaluate, rootState) => {
384
+ let state;
344
385
  return effect(() => {
345
- const newEls = evaluate(state) ? ifs : ifEl[_prevIf] ? none : elses;
346
- if (next)
347
- next[_prevIf] = newEls === ifs;
348
- if (cur != newEls) {
349
- if (cur[0]?.[_each])
350
- cur = [cur[0][_each]];
351
- for (let el of cur)
352
- el.remove();
353
- cur = newEls;
354
- for (let el of cur) {
355
- parent.insertBefore(el, holder);
356
- memo.get(el) === null && memo.delete(el);
357
- sprae(el, state);
358
- }
386
+ let values = evaluate(rootState);
387
+ sprae(el, state ? values : state = store(values, rootState));
388
+ });
389
+ };
390
+
391
+ // directive/html.js
392
+ directive.html = (el, evaluate, state) => {
393
+ let tpl = evaluate(state);
394
+ if (!tpl)
395
+ return;
396
+ let content = (tpl.content || tpl).cloneNode(true);
397
+ el.replaceChildren(content);
398
+ sprae(el, state);
399
+ };
400
+
401
+ // directive/text.js
402
+ directive.text = (el, evaluate, state) => {
403
+ if (el.content) {
404
+ let tplfrag = frag(el);
405
+ if (el !== tplfrag)
406
+ el.replaceWith(tplfrag.content);
407
+ el = tplfrag.childNodes[0];
408
+ }
409
+ return effect(() => {
410
+ let value = evaluate(state);
411
+ el.textContent = value == null ? "" : value;
412
+ });
413
+ };
414
+
415
+ // directive/class.js
416
+ directive.class = (el, evaluate, state) => {
417
+ let cur = /* @__PURE__ */ new Set();
418
+ return effect(() => {
419
+ let v = evaluate(state);
420
+ let clsx = /* @__PURE__ */ new Set();
421
+ if (v) {
422
+ if (typeof v === "string")
423
+ v.split(" ").map((cls) => clsx.add(cls));
424
+ else if (Array.isArray(v))
425
+ v.map((v2) => v2 && clsx.add(v2));
426
+ else
427
+ Object.entries(v).map(([k, v2]) => v2 && clsx.add(k));
428
+ }
429
+ for (let cls of cur)
430
+ if (clsx.has(cls))
431
+ clsx.delete(cls);
432
+ else
433
+ el.classList.remove(cls);
434
+ for (let cls of cur = clsx)
435
+ el.classList.add(cls);
436
+ });
437
+ };
438
+
439
+ // directive/style.js
440
+ directive.style = (el, evaluate, state) => {
441
+ let initStyle = el.getAttribute("style") || "";
442
+ if (!initStyle.endsWith(";"))
443
+ initStyle += "; ";
444
+ return effect(() => {
445
+ let v = evaluate(state);
446
+ if (typeof v === "string")
447
+ el.setAttribute("style", initStyle + v);
448
+ else {
449
+ el.setAttribute("style", initStyle);
450
+ for (let k in v)
451
+ el.style.setProperty(k, v[k]);
359
452
  }
360
453
  });
361
454
  };
@@ -366,10 +459,10 @@ directive.default = (target, evaluate, state, name) => {
366
459
  return effect(() => {
367
460
  let value = evaluate(state);
368
461
  if (name)
369
- attr(target, name, ipol(value, state));
462
+ attr(target, name, value);
370
463
  else
371
464
  for (let key in value)
372
- attr(target, dashcase(key), ipol(value[key], state));
465
+ attr(target, dashcase(key), value[key]);
373
466
  });
374
467
  const ctxs = name.split("..").map((e) => {
375
468
  let ctx = { evt: "", target, test: () => true };
@@ -507,85 +600,6 @@ var debounce = (fn, wait) => {
507
600
  var dashcase = (str) => {
508
601
  return str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => "-" + match.toLowerCase());
509
602
  };
510
- var ipol = (v, state) => {
511
- return v?.replace ? v.replace(/\$<([^>]+)>/g, (match, field) => state[field] ?? "") : v;
512
- };
513
-
514
- // directive/ref.js
515
- directive.ref = (el, expr, state) => {
516
- state[ipol(expr, state)] = el;
517
- };
518
- directive.ref.parse = (expr) => expr;
519
-
520
- // directive/with.js
521
- directive.with = (el, evaluate, rootState) => {
522
- let state;
523
- return effect(() => {
524
- let values = evaluate(rootState);
525
- sprae(el, state ? values : state = store(values, rootState));
526
- });
527
- };
528
-
529
- // directive/html.js
530
- directive.html = (el, evaluate, state) => {
531
- let tpl = evaluate(state);
532
- if (!tpl)
533
- return;
534
- let content = (tpl.content || tpl).cloneNode(true);
535
- el.replaceChildren(content);
536
- sprae(el, state);
537
- };
538
-
539
- // directive/text.js
540
- directive.text = (el, evaluate, state) => {
541
- if (el.content)
542
- el.replaceWith(el = document.createTextNode(""));
543
- return effect(() => {
544
- let value = evaluate(state);
545
- el.textContent = value == null ? "" : value;
546
- });
547
- };
548
-
549
- // directive/class.js
550
- directive.class = (el, evaluate, state) => {
551
- let cur = /* @__PURE__ */ new Set();
552
- return effect(() => {
553
- let v = evaluate(state);
554
- let clsx = /* @__PURE__ */ new Set();
555
- if (v) {
556
- if (typeof v === "string")
557
- ipol(v, state).split(" ").map((cls) => clsx.add(cls));
558
- else if (Array.isArray(v))
559
- v.map((v2) => (v2 = ipol(v2, state)) && clsx.add(v2));
560
- else
561
- Object.entries(v).map(([k, v2]) => v2 && clsx.add(k));
562
- }
563
- for (let cls of cur)
564
- if (clsx.has(cls))
565
- clsx.delete(cls);
566
- else
567
- el.classList.remove(cls);
568
- for (let cls of cur = clsx)
569
- el.classList.add(cls);
570
- });
571
- };
572
-
573
- // directive/style.js
574
- directive.style = (el, evaluate, state) => {
575
- let initStyle = el.getAttribute("style") || "";
576
- if (!initStyle.endsWith(";"))
577
- initStyle += "; ";
578
- return effect(() => {
579
- let v = evaluate(state);
580
- if (typeof v === "string")
581
- el.setAttribute("style", initStyle + ipol(v, state));
582
- else {
583
- el.setAttribute("style", initStyle);
584
- for (let k in v)
585
- el.style.setProperty(k, ipol(v[k], state));
586
- }
587
- });
588
- };
589
603
 
590
604
  // directive/value.js
591
605
  directive.value = (el, evaluate, state) => {
package/dist/sprae.min.js CHANGED
@@ -1 +1 @@
1
- var e,t,r,l,n,s=Object.defineProperty,o=Symbol("signals"),a=Symbol("length");function i(t,r){if(!t)return t;if(t[o])return t;if(Array.isArray(t))return function(t){let r;if(t[o])return t;let l=e(t.length),n=Array(t.length).fill();const s=new Proxy(n,{get:(s,c)=>"symbol"==typeof c?c===a?l:c===o?n:n[c]:"length"===c?u[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)=>(n[t]&&f(n,t),1)});return s}(t);if(t.constructor!==Object)return t;let l={...r?.[o]},s=e(Object.values(t).length);const p=new Proxy(l,{get:(e,t)=>t===a?s:t===o?l:l[t]?.valueOf(),set:(e,t,r,n)=>(n=l[t],c(l,t,r),n??++s.value,1),deleteProperty:(e,t)=>(l[t]&&(f(l,t),s.value--),1),ownKeys:()=>(s.value,Reflect.ownKeys(l))});for(let e in t){const r=Object.getOwnPropertyDescriptor(t,e);r?.get?(l[e]=n(r.get.bind(p)))._set=r.set?.bind(p):(l[e]=void 0,c(l,e,t[e]))}return p}var u={push:1,pop:1,shift:1,unshift:1,splice:1};function c(t,n,s){let o=t[n];if("_"===n[0])t[n]=s;else if(o)if(s===o.peek());else if(o._set)o._set(s);else if(Array.isArray(s)&&Array.isArray(o.peek())){const e=o.peek();e[a]?r((()=>{l((()=>{let t=0,r=s.length;for(;t<r;t++)e[t]=s[t];e.length=r}))})):o.value=s}else o.value=i(s);else t[n]=o=s?.peek?s:e(i(s))}function f(e,t){const r=e[t],l=r[Symbol.dispose];l&&delete r[Symbol.dispose],delete e[t],l?.()}var p=Symbol.dispose||=Symbol("dispose"),d={},y=new WeakMap;function h(e,t){if(!e?.children)return;if(y.has(e))return Object.assign(y.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=d[n]||d.default,o=e(t,(e.parse||g)(s.value,g),r,n);o&&l.push(o)}if(y.has(t))return t[p]&&l.push(t[p]);if(t.parentNode!==n)return}else e++}for(let r of[...t.children])e(r,t)}(e),y.has(e)||y.set(e,r),e[p]=()=>{for(;l.length;)l.pop()();y.delete(e)},r}var m,v={},g=(e,t,r)=>{if(r=v[e=e.trim()])return r;try{r=m(e)}catch(r){b(r,t,e)}return v[e]=r},b=(e,t,r="")=>{throw Object.assign(e,{message:`∴ ${e.message}\n\n${t}${r?`="${r}"\n\n`:""}`,expr:r})};h.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&&(m=s.compile)};var k,A,S={};((e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})})(S,{batch:()=>x,computed:()=>N,effect:()=>O,signal:()=>w,untracked:()=>$});var w=(e,t,r=new Set)=>((t={get value(){return k?.deps.push(r.add(k)),e},set value(t){if(t!==e){e=t;for(let e of r)A?A.add(e):e()}},peek:()=>e}).toJSON=t.then=t.toString=t.valueOf=()=>t.value,t),O=(e,t,r,l)=>(l=(r=l=>{t?.call?.(),l=k,k=r;try{t=e()}finally{k=l}}).deps=[],r(),e=>{for(t?.call?.();e=l.pop();)e.delete(r)}),N=(e,t=w(),r,l)=>((r={get value(){return l||=O((()=>t.value=e())),t.value},peek:t.peek}).toJSON=r.then=r.toString=r.valueOf=()=>r.value,r),x=e=>{let t=A;t||(A=new Set);try{e()}finally{if(!t){t=A,A=null;for(const e of t)e()}}},$=(e,t,r)=>(t=k,k=null,r=e(),k=t,r),j=Symbol(":each");d.each=(e,[l,s,u],c)=>{const f=e[j]=document.createTextNode("");e.replaceWith(f);let p,d,y=0;const m=n((()=>{d=null;let e=u(c);return"number"==typeof e&&(e=Array.from({length:e},((e,t)=>t+1))),e?.constructor===Object&&(d=Object.keys(e),e=Object.values(e)),e||[]})),v=()=>{r((()=>{let t=0,r=m.value,n=r.length;if(p&&!p[a]){for(let e of p[o]||[])e[Symbol.dispose]();p=null,y=0}if(n<y)p.length=n;else{if(p)for(;t<y;t++)p[t]=r[t];else p=r;for(;t<n;t++){p[t]=r[t];let n=t,a=i({[l]:p[o]?.[n]||p[n],[s]:d?d[n]:n},c),u=(e.content||e).cloneNode(!0),y=e.content?{children:[...u.children],remove(){this.children.map((e=>e.remove()))}}:u;f.before(u),h(y,a),((p[o]||=[])[t]||={})[Symbol.dispose]=()=>{y[Symbol.dispose](),y.remove()}}}y=n}))};let g=0;return t((()=>{m.value[a]?.value,g?g++:(v(),queueMicrotask((()=>(g&&v(),g=0))))}))},d.each.parse=(e,t)=>{let[r,l]=e.split(/\s+in\s+/),[n,s="$"]=r.split(/\s*,\s*/);return[n,s,t(l)]};var E=Symbol("if");d.if=(e,r,l)=>{let n,s,o,a=e.parentNode,i=e.nextElementSibling,u=document.createTextNode(""),c=[];e.after(u),e.remove(),n=c,s=e.content?[...e.content.childNodes]:[e],i?.hasAttribute(":else")?(i.removeAttribute(":else"),i.hasAttribute(":if")?o=c:(i.remove(),o=i.content?[...i.content.childNodes]:[i])):o=c;for(let e of[...s,...o])y.set(e,null);return t((()=>{const t=r(l)?s:e[E]?c:o;if(i&&(i[E]=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)a.insertBefore(e,u),null===y.get(e)&&y.delete(e),h(e,l)}}))},d.default=(e,r,l,n)=>{if(!n.startsWith("on"))return t((()=>{let t=r(l);if(n)W(e,n,K(t,l));else for(let r in t)W(e,D(r),K(t[r],l))}));const s=n.split("..").map((t=>{let r={evt:"",target:e,test:()=>!0};return r.evt=(t.startsWith("on")?t.slice(2):t).replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,l="")=>(r.test=P[t]?.(r,...l.split("-"))||r.test,""))),r}));if(1==s.length)return t((()=>f(r(l),s[0])));let o,a,i,u=0;const c=e=>{i=f((t=>(i(),a=e?.(t),(u=++u%s.length)?c(a):o&&c(o))),s[u])};return t((()=>(o=r(l),!i&&c(o),()=>o=null)));function f(e,{evt:t,target:r,test:l,defer:n,stop:s,prevent:o,immediate:a,...i}){n&&(e=n(e));const u=r=>{try{l(r)&&(s&&(a?r.stopImmediatePropagation():r.stopPropagation()),o&&r.preventDefault(),e?.(r))}catch(r){b(r,`:on${t}`,e)}};return r.addEventListener(t,u,i),()=>r.removeEventListener(t,u,i)}};var P={prevent(e){e.prevent=!0},stop(e){e.stop=!0},immediate(e){e.immediate=!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=>_(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=>T.ctrl(e)&&t.every((t=>T[t]?T[t](e):e.key===t)),shift:(e,...t)=>e=>T.shift(e)&&t.every((t=>T[t]?T[t](e):e.key===t)),alt:(e,...t)=>e=>T.alt(e)&&t.every((t=>T[t]?T[t](e):e.key===t)),meta:(e,...t)=>e=>T.meta(e)&&t.every((t=>T[t]?T[t](e):e.key===t)),arrow:()=>T.arrow,enter:()=>T.enter,esc:()=>T.esc,tab:()=>T.tab,space:()=>T.space,delete:()=>T.delete,digit:()=>T.digit,letter:()=>T.letter,char:()=>T.char},T={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,esc:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,delete:e=>"Delete"===e.key||"Backspace"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^\p{L}$/gu.test(e.key),char:e=>/^\S$/.test(e.key)},W=(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))},_=(e,t)=>{let r;return l=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(l)}),t)}},D=e=>e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),K=(e,t)=>e?.replace?e.replace(/\$<([^>]+)>/g,((e,r)=>t[r]??"")):e;d.ref=(e,t,r)=>{r[K(t,r)]=e},d.ref.parse=e=>e,d.with=(e,r,l)=>{let n;return t((()=>{let t=r(l);h(e,n?t:n=i(t,l))}))},d.html=(e,t,r)=>{let l=t(r);if(!l)return;let n=(l.content||l).cloneNode(!0);e.replaceChildren(n),h(e,r)},d.text=(e,r,l)=>(e.content&&e.replaceWith(e=document.createTextNode("")),t((()=>{let t=r(l);e.textContent=null==t?"":t}))),d.class=(e,r,l)=>{let n=new Set;return t((()=>{let t=r(l),s=new Set;t&&("string"==typeof t?K(t,l).split(" ").map((e=>s.add(e))):Array.isArray(t)?t.map((e=>(e=K(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)}))},d.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+K(t,l));else{e.setAttribute("style",n);for(let r in t)e.style.setProperty(r,K(t[r],l))}}))},d.value=(e,r,l)=>{let n,s,o="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,W(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((()=>o(r(l))))},d.fx=(e,r,l)=>t((()=>r(l))),h.use(S),h.use({compile:e=>h.constructor("__scope",`with (__scope) { return ${e} };`)});var L=h;export{L as default};
1
+ var e,t,r,l,n,o=Object.defineProperty,s=Symbol("signals"),a=Symbol("length");function i(t,r){if(!t)return t;if(t[s])return t;if(Array.isArray(t))return function(t){let r;if(t[s])return t;let l=e(t.length),n=Array(t.length).fill();const o=new Proxy(n,{get:(o,c)=>"symbol"==typeof c?c===a?l:c===s?n:n[c]:"length"===c?u[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 o[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)=>(n[t]&&f(n,t),1)});return o}(t);if(t.constructor!==Object)return t;let l={...r?.[s]},o=e(Object.values(t).length);const p=new Proxy(l,{get:(e,t)=>t===a?o:t===s?l:l[t]?.valueOf(),set:(e,t,r,n)=>(n=l[t],c(l,t,r),n??++o.value,1),deleteProperty:(e,t)=>(l[t]&&(f(l,t),o.value--),1),ownKeys:()=>(o.value,Reflect.ownKeys(l))});for(let e in t){const r=Object.getOwnPropertyDescriptor(t,e);r?.get?(l[e]=n(r.get.bind(p)))._set=r.set?.bind(p):(l[e]=void 0,c(l,e,t[e]))}return p}var u={push:1,pop:1,shift:1,unshift:1,splice:1};function c(t,n,o){let s=t[n];if("_"===n[0])t[n]=o;else if(s)if(o===s.peek());else if(s._set)s._set(o);else if(Array.isArray(o)&&Array.isArray(s.peek())){const e=s.peek();e[a]?r((()=>{l((()=>{let t=0,r=o.length;for(;t<r;t++)e[t]=o[t];e.length=r}))})):s.value=o}else s.value=i(o);else t[n]=s=o?.peek?o:e(i(o))}function f(e,t){const r=e[t],l=r[Symbol.dispose];l&&delete r[Symbol.dispose],delete e[t],l?.()}var p=Symbol.dispose||=Symbol("dispose"),d={},y=new WeakMap;function h(e,t){if(!e?.childNodes)return;if(y.has(e))return Object.assign(y.get(e),t);const r=i(t||{}),l=[];return function e(t,n=t.parentNode){if(t.childNodes){for(let e=0;e<t.attributes?.length;){let o=t.attributes[e];if(":"===o.name[0]){t.removeAttribute(o.name);let e=o.name.slice(1).split(":");for(let n of e){let e=d[n]||d.default,s=e(t,(e.parse||g)(o.value,g),r,n);s&&l.push(s)}if(y.has(t))return t[p]&&l.push(t[p]);if(t.parentNode!==n)return}else e++}for(let r of[...t.childNodes])e(r,t)}}(e),y.has(e)||y.set(e,r),e[p]=()=>{for(;l.length;)l.pop()();y.delete(e)},r}var m,v={},g=(e,t,r)=>{if(r=v[e=e.trim()])return r;try{r=m(e)}catch(r){b(r,t,e)}return v[e]=r},b=(e,t,r="")=>{throw Object.assign(e,{message:`∴ ${e.message}\n\n${t}${r?`="${r}"\n\n`:""}`,expr:r})};h.use=o=>{o.signal&&function(o){e=o.signal,t=o.effect,n=o.computed,l=o.batch||(e=>e()),r=o.untracked||l}(o),o.compile&&(m=o.compile)};var k,A,w=e=>{if(!e.nodeType)return e;e.content.appendChild(document.createTextNode(""));let t=e.content.cloneNode(!0),r=[...e.attributes],l=[...t.childNodes];return{childNodes:l,content:t,remove:()=>t.append(...l),replaceWith(e){l[0].before(e),t.append(...l)},attributes:r,removeAttribute(e){r.splice(r.findIndex((t=>t.name===e)),1)}}},S={};((e,t)=>{for(var r in t)o(e,r,{get:t[r],enumerable:!0})})(S,{batch:()=>W,computed:()=>x,effect:()=>O,signal:()=>N,untracked:()=>j});var N=(e,t,r=new Set)=>((t={get value(){return k?.deps.push(r.add(k)),e},set value(t){if(t!==e){e=t;for(let e of r)A?A.add(e):e()}},peek:()=>e}).toJSON=t.then=t.toString=t.valueOf=()=>t.value,t),O=(e,t,r,l)=>(l=(r=l=>{t?.call?.(),l=k,k=r;try{t=e()}finally{k=l}}).deps=[],r(),e=>{for(t?.call?.();e=l.pop();)e.delete(r)}),x=(e,t=N(),r,l)=>((r={get value(){return l||=O((()=>t.value=e())),t.value},peek:t.peek}).toJSON=r.then=r.toString=r.valueOf=()=>r.value,r),W=e=>{let t=A;t||(A=new Set);try{e()}finally{if(!t){t=A,A=null;for(const e of t)e()}}},j=(e,t,r)=>(t=k,k=null,r=e(),k=t,r),T=Symbol("if");d.if=(e,r,l)=>{let n,o,s=e.nextElementSibling,a=document.createTextNode(""),i=[],u=i;e.replaceWith(a),n=e.content?[w(e)]:[e],s?.hasAttribute(":else")?(s.removeAttribute(":else"),s.hasAttribute(":if")?o=i:(s.remove(),o=s.content?[w(s)]:[s])):o=i;for(let e of[...n,...o])y.set(e,null);return t((()=>{const t=r(l)?n:e[T]?i:o;if(s&&(s[T]=t===n),u!=t){for(let e of u)e.remove();u=t;for(let e of u)a.before(e.content||e),null===y.get(e)&&y.delete(e),h(e,l)}}))},d.each=(e,[l,o,u],c)=>{const f=document.createTextNode("");e.replaceWith(f);let p,d,y=0;const m=n((()=>{d=null;let e=u(c);return"number"==typeof e&&(e=Array.from({length:e},((e,t)=>t+1))),e?.constructor===Object&&(d=Object.keys(e),e=Object.values(e)),e||[]})),v=()=>{r((()=>{let t=0,r=m.value,n=r.length;if(p&&!p[a]){for(let e of p[s]||[])e[Symbol.dispose]();p=null,y=0}if(n<y)p.length=n;else{if(p)for(;t<y;t++)p[t]=r[t];else p=r;for(;t<n;t++){p[t]=r[t];let n=t,a=i({[l]:p[s]?.[n]||p[n],[o]:d?d[n]:n},c),u=e.content?w(e):e.cloneNode(!0);f.before(u.content||u),h(u,a),((p[s]||=[])[t]||={})[Symbol.dispose]=()=>{u[Symbol.dispose](),u.remove()}}}y=n}))};let g=0;return t((()=>{m.value[a]?.value,g?g++:(v(),queueMicrotask((()=>(g&&v(),g=0))))}))},d.each.parse=(e,t)=>{let[r,l]=e.split(/\s+in\s+/),[n,o="$"]=r.split(/\s*,\s*/);return[n,o,t(l)]},d.ref=(e,t,r)=>{r[t]=e},d.ref.parse=e=>e,d.with=(e,r,l)=>{let n;return t((()=>{let t=r(l);h(e,n?t:n=i(t,l))}))},d.html=(e,t,r)=>{let l=t(r);if(!l)return;let n=(l.content||l).cloneNode(!0);e.replaceChildren(n),h(e,r)},d.text=(e,r,l)=>{if(e.content){let t=w(e);e!==t&&e.replaceWith(t.content),e=t.childNodes[0]}return t((()=>{let t=r(l);e.textContent=null==t?"":t}))},d.class=(e,r,l)=>{let n=new Set;return t((()=>{let t=r(l),o=new Set;t&&("string"==typeof t?t.split(" ").map((e=>o.add(e))):Array.isArray(t)?t.map((e=>e&&o.add(e))):Object.entries(t).map((([e,t])=>t&&o.add(e))));for(let t of n)o.has(t)?o.delete(t):e.classList.remove(t);for(let t of n=o)e.classList.add(t)}))},d.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+t);else{e.setAttribute("style",n);for(let r in t)e.style.setProperty(r,t[r])}}))},d.default=(e,r,l,n)=>{if(!n.startsWith("on"))return t((()=>{let t=r(l);if(n)E(e,n,t);else for(let r in t)E(e,D(r),t[r])}));const o=n.split("..").map((t=>{let r={evt:"",target:e,test:()=>!0};return r.evt=(t.startsWith("on")?t.slice(2):t).replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,l="")=>(r.test=$[t]?.(r,...l.split("-"))||r.test,""))),r}));if(1==o.length)return t((()=>f(r(l),o[0])));let s,a,i,u=0;const c=e=>{i=f((t=>(i(),a=e?.(t),(u=++u%o.length)?c(a):s&&c(s))),o[u])};return t((()=>(s=r(l),!i&&c(s),()=>s=null)));function f(e,{evt:t,target:r,test:l,defer:n,stop:o,prevent:s,immediate:a,...i}){n&&(e=n(e));const u=r=>{try{l(r)&&(o&&(a?r.stopImmediatePropagation():r.stopPropagation()),s&&r.preventDefault(),e?.(r))}catch(r){b(r,`:on${t}`,e)}};return r.addEventListener(t,u,i),()=>r.removeEventListener(t,u,i)}};var $={prevent(e){e.prevent=!0},stop(e){e.stop=!0},immediate(e){e.immediate=!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=>P(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>_(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=>C.ctrl(e)&&t.every((t=>C[t]?C[t](e):e.key===t)),shift:(e,...t)=>e=>C.shift(e)&&t.every((t=>C[t]?C[t](e):e.key===t)),alt:(e,...t)=>e=>C.alt(e)&&t.every((t=>C[t]?C[t](e):e.key===t)),meta:(e,...t)=>e=>C.meta(e)&&t.every((t=>C[t]?C[t](e):e.key===t)),arrow:()=>C.arrow,enter:()=>C.enter,esc:()=>C.esc,tab:()=>C.tab,space:()=>C.space,delete:()=>C.delete,digit:()=>C.digit,letter:()=>C.letter,char:()=>C.char},C={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,esc:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,delete:e=>"Delete"===e.key||"Backspace"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^\p{L}$/gu.test(e.key),char:e=>/^\S$/.test(e.key)},E=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},P=(e,t)=>{let r,l,n=o=>{r=!0,setTimeout((()=>{if(r=!1,l)return l=!1,n(o),e(o)}),t)};return t=>r?l=!0:(n(t),e(t))},_=(e,t)=>{let r;return l=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(l)}),t)}},D=e=>e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase()));d.value=(e,r,l)=>{let n,o,s="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,o=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),n&&e.setSelectionRange(n,o)):"checkbox"===e.type?t=>(e.checked=t,E(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((()=>s(r(l))))},d.fx=(e,r,l)=>t((()=>r(l))),h.use(S),h.use({compile:e=>h.constructor("__scope",`with (__scope) { return ${e} };`)});var K=h;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.6.3",
4
+ "version": "10.8.0",
5
5
  "main": "./sprae.js",
6
6
  "module": "./sprae.js",
7
7
  "type": "module",
package/readme.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  _Sprae_ is open & minimalistic progressive enhancement framework.<br/>
6
6
  Perfect for small-scale websites, static pages, landings, prototypes, or lightweight UI.<br/>
7
-
7
+ A light, fast and sweet alternative to alpine, petit-vue etc.
8
8
 
9
9
  ## Usage
10
10
 
@@ -24,7 +24,7 @@ Perfect for small-scale websites, static pages, landings, prototypes, or lightwe
24
24
  </script>
25
25
  ```
26
26
 
27
- Sprae evaluates `:`-directives and evaporates them, returning reactive state.
27
+ Sprae evaluates `:`-directives and evaporates them, returning reactive state for updates.
28
28
 
29
29
  ## Directives
30
30
 
@@ -59,9 +59,6 @@ Multiply element.
59
59
  <dt :text="item.term"/>
60
60
  <dd :text="item.definition"/>
61
61
  </template>
62
-
63
- <!-- prevent FOUC -->
64
- <style>[:each] {visibility: hidden}</style>
65
62
  ```
66
63
 
67
64
  #### `:text="value"`
@@ -83,9 +80,6 @@ Set class value.
83
80
  <!-- appends class -->
84
81
  <div class="foo" :class="bar"></div>
85
82
 
86
- <!-- interpolation -->
87
- <div :class="'foo $<bar>'"></div>
88
-
89
83
  <!-- array/object, a-la clsx -->
90
84
  <div :class="[foo && 'foo', {bar: bar}]"></div>
91
85
  ```
@@ -98,9 +92,6 @@ Set style value.
98
92
  <!-- extends style -->
99
93
  <div style="foo: bar" :style="'baz: qux'">
100
94
 
101
- <!-- interpolation -->
102
- <div :style="'foo: $<bar>'"></div>
103
-
104
95
  <!-- object -->
105
96
  <div :style="{foo: 'bar'}"></div>
106
97
 
@@ -277,7 +268,8 @@ Trigger when element is connected / disconnected from DOM.
277
268
 
278
269
  ## Signals
279
270
 
280
- Sprae can take signal values. Signals provider can be switched to any preact-flavored implementation:
271
+ Sprae uses signals for reactivity and can take signal values as inputs.
272
+ Signals provider can be switched to any preact-flavored implementation:
281
273
 
282
274
  ```js
283
275
  import sprae from 'sprae';
@@ -352,6 +344,7 @@ import * as signals from '@preact/signals'
352
344
  import compile from 'subscript'
353
345
 
354
346
  // standard directives
347
+ import 'sprae/directive/default.js'
355
348
  import 'sprae/directive/if.js'
356
349
  import 'sprae/directive/text.js'
357
350
 
@@ -367,20 +360,25 @@ sprae.use(signals)
367
360
  sprae.use({ compile })
368
361
  ```
369
362
 
370
- <!-- ## Dispose
371
-
372
- To destroy state and detach sprae handlers, call `element[Symbol.dispose]()`. -->
363
+ ## Hints
373
364
 
365
+ * To prevent [FOUC](https://en.wikipedia.org/wiki/Flash_of_unstyled_content) add `<style>[:each],[:if],[:else],[:text] {visibility: hidden}</style>`
366
+ * Attributes order matters, eg. `<li :each="value in values" :text="value.name"></li>` is not the same as `<li :text="value.name" :each="value in values"></li>`
367
+ * To destroy state and detach sprae handlers, call `element[Symbol.dispose]()`.
368
+ * State getters/setters work as computed effects, eg. `sprae(el, { x:1, get x2(){ return this.x * 2} })`.
369
+ * `this` keyword is not used, to get access to current element use `ref` as `<input :ref="el" :text="el.value"/>`
370
+ * Async/await is not supported in attributes, it's a strong signal you need to put these methods into state.
374
371
 
375
372
  ## Justification
376
373
 
377
374
  * [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).
378
375
  * [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-`, `{}`, `@`, `$`), tend to [self-encapsulate](https://github.com/alpinejs/alpine/discussions/3223) and not care about size/performance.
379
376
 
380
- _Sprae_ holds open & minimalistic philosophy:
377
+ _Sprae_ holds open, sweet & minimalistic philosophy:
381
378
  * Slim `:` API and _signals_ reactivity.
382
379
  * Pluggable directives & configurable internals.
383
380
  * Small, safe & performant.
381
+ * Bits of organic sugar.
384
382
  * Aims at making developers happy 🫰
385
383
 
386
384
  <!--