sprae 10.11.0 → 10.11.2

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.
@@ -16,7 +16,7 @@ directive.value = (el, [getValue, setValue], state) => {
16
16
  )
17
17
  : (el.type === "checkbox") ? (value) => (el.checked = value, attr(el, "checked", value))
18
18
  : (el.type === "select-one") ? (value) => {
19
- for (let option in el.options) option.removeAttribute("selected");
19
+ for (let option of el.options) option.removeAttribute("selected");
20
20
  el.value = value;
21
21
  el.selectedOptions[0]?.setAttribute("selected", "");
22
22
  }
package/dist/sprae.js CHANGED
@@ -7,11 +7,9 @@ var signal = (v, s, obs = /* @__PURE__ */ new Set()) => (s = {
7
7
  return v;
8
8
  },
9
9
  set value(val) {
10
- if (val === v)
11
- return;
10
+ if (val === v) return;
12
11
  v = val;
13
- for (let sub of obs)
14
- batched ? batched.add(sub) : sub();
12
+ for (let sub of obs) batched ? batched.add(sub) : sub();
15
13
  },
16
14
  peek() {
17
15
  return v;
@@ -27,8 +25,7 @@ var effect = (fn, teardown, fx, deps) => (fx = (prev) => {
27
25
  }
28
26
  }, deps = fx.deps = [], fx(), (dep) => {
29
27
  teardown?.call?.();
30
- while (dep = deps.pop())
31
- dep.delete(fx);
28
+ while (dep = deps.pop()) dep.delete(fx);
32
29
  });
33
30
  var computed = (fn, s = signal(), c, e) => (c = {
34
31
  get value() {
@@ -39,16 +36,14 @@ var computed = (fn, s = signal(), c, e) => (c = {
39
36
  }, c.toJSON = c.then = c.toString = c.valueOf = () => c.value, c);
40
37
  var batch = (fn) => {
41
38
  let fxs = batched;
42
- if (!fxs)
43
- batched = /* @__PURE__ */ new Set();
39
+ if (!fxs) batched = /* @__PURE__ */ new Set();
44
40
  try {
45
41
  fn();
46
42
  } finally {
47
43
  if (!fxs) {
48
44
  fxs = batched;
49
45
  batched = null;
50
- for (const fx of fxs)
51
- fx();
46
+ for (const fx of fxs) fx();
52
47
  }
53
48
  }
54
49
  };
@@ -65,18 +60,15 @@ function use(s) {
65
60
  var _signals = Symbol("signals");
66
61
  var _change = Symbol("length");
67
62
  function store(values, parent) {
68
- if (!values)
69
- return values;
70
- if (values[_signals])
71
- return values;
72
- if (Array.isArray(values))
73
- return list(values);
74
- if (values.constructor !== Object)
75
- return values;
63
+ if (!values) return values;
64
+ if (values[_signals]) return values;
65
+ if (Array.isArray(values)) return list(values);
66
+ if (values.constructor !== Object) return values;
76
67
  let signals = { ...parent?.[_signals] }, _len = signal(Object.values(values).length);
77
68
  const state = new Proxy(signals, {
78
69
  get: (_, key) => key === _change ? _len : key === _signals ? signals : signals[key]?.valueOf(),
79
70
  set: (_, key, v, s) => (s = signals[key], set(signals, key, v), s ?? ++_len.value, 1),
71
+ // bump length for new signal
80
72
  deleteProperty: (_, key) => (signals[key] && (del(signals, key), _len.value--), 1),
81
73
  ownKeys() {
82
74
  _len.value;
@@ -97,31 +89,24 @@ function store(values, parent) {
97
89
  var mut = { push: 1, pop: 1, shift: 1, unshift: 1, splice: 1 };
98
90
  function list(values) {
99
91
  let lastProp;
100
- if (values[_signals])
101
- return values;
92
+ if (values[_signals]) return values;
102
93
  let _len = signal(values.length), signals = Array(values.length).fill();
103
94
  const state = new Proxy(signals, {
104
95
  get(_, key) {
105
- if (typeof key === "symbol")
106
- return key === _change ? _len : key === _signals ? signals : signals[key];
107
- if (key === "length")
108
- return mut[lastProp] ? _len.peek() : _len.value;
96
+ if (typeof key === "symbol") return key === _change ? _len : key === _signals ? signals : signals[key];
97
+ if (key === "length") return mut[lastProp] ? _len.peek() : _len.value;
109
98
  lastProp = key;
110
- if (signals[key])
111
- return signals[key].valueOf();
112
- if (key < signals.length)
113
- return (signals[key] = signal(store(values[key]))).value;
99
+ if (signals[key]) return signals[key].valueOf();
100
+ if (key < signals.length) return (signals[key] = signal(store(values[key]))).value;
114
101
  },
115
102
  set(_, key, v) {
116
103
  if (key === "length") {
117
- for (let i = v, l = signals.length; i < l; i++)
118
- delete state[i];
104
+ for (let i = v, l = signals.length; i < l; i++) delete state[i];
119
105
  _len.value = signals.length = v;
120
106
  return true;
121
107
  }
122
108
  set(signals, key, v);
123
- if (key >= _len.peek())
124
- _len.value = signals.length = Number(key) + 1;
109
+ if (key >= _len.peek()) _len.value = signals.length = Number(key) + 1;
125
110
  return true;
126
111
  },
127
112
  deleteProperty: (_, key) => (signals[key] && del(signals, key), 1)
@@ -130,25 +115,20 @@ function list(values) {
130
115
  }
131
116
  function set(signals, key, v) {
132
117
  let s = signals[key];
133
- if (key[0] === "_")
134
- signals[key] = v;
118
+ if (key[0] === "_") signals[key] = v;
135
119
  else if (!s) {
136
120
  signals[key] = s = v?.peek ? v : signal(store(v));
137
- } else if (v === s.peek())
138
- ;
139
- else if (s._set)
140
- s._set(v);
121
+ } else if (v === s.peek()) ;
122
+ else if (s._set) s._set(v);
141
123
  else if (Array.isArray(v) && Array.isArray(s.peek())) {
142
124
  const cur = s.peek();
143
- if (cur[_change])
144
- untracked(() => {
145
- batch(() => {
146
- let i = 0, l = v.length;
147
- for (; i < l; i++)
148
- cur[i] = v[i];
149
- cur.length = l;
150
- });
125
+ if (cur[_change]) untracked(() => {
126
+ batch(() => {
127
+ let i = 0, l = v.length;
128
+ for (; i < l; i++) cur[i] = v[i];
129
+ cur.length = l;
151
130
  });
131
+ });
152
132
  else {
153
133
  s.value = v;
154
134
  }
@@ -158,8 +138,7 @@ function set(signals, key, v) {
158
138
  }
159
139
  function del(signals, key) {
160
140
  const s = signals[key], del2 = s[Symbol.dispose];
161
- if (del2)
162
- delete s[Symbol.dispose];
141
+ if (del2) delete s[Symbol.dispose];
163
142
  delete signals[key];
164
143
  del2?.();
165
144
  }
@@ -169,24 +148,20 @@ var _dispose = Symbol.dispose || (Symbol.dispose = Symbol("dispose"));
169
148
  var directive = {};
170
149
  var memo = /* @__PURE__ */ new WeakMap();
171
150
  function sprae(el, values) {
172
- if (!el?.childNodes)
173
- return;
151
+ if (!el?.childNodes) return;
174
152
  if (memo.has(el)) {
175
153
  return Object.assign(memo.get(el), values);
176
154
  }
177
155
  const state = store(values || {}), disposes = [];
178
156
  init(el);
179
- if (!memo.has(el))
180
- memo.set(el, state);
157
+ if (!memo.has(el)) memo.set(el, state);
181
158
  el[_dispose] = () => {
182
- while (disposes.length)
183
- disposes.pop()();
159
+ while (disposes.length) disposes.pop()();
184
160
  memo.delete(el);
185
161
  };
186
162
  return state;
187
163
  function init(el2, parent = el2.parentNode) {
188
- if (!el2.childNodes)
189
- return;
164
+ if (!el2.childNodes) return;
190
165
  for (let i = 0; i < el2.attributes?.length; ) {
191
166
  let attr2 = el2.attributes[i];
192
167
  if (attr2.name[0] === ":") {
@@ -196,25 +171,19 @@ function sprae(el, values) {
196
171
  let dir = directive[name] || directive.default;
197
172
  let evaluate = (dir.parse || parse)(attr2.value);
198
173
  let dispose = dir(el2, evaluate, state, name);
199
- if (dispose)
200
- disposes.push(dispose);
174
+ if (dispose) disposes.push(dispose);
201
175
  }
202
- if (memo.has(el2))
203
- return el2[_dispose] && disposes.push(el2[_dispose]);
204
- if (el2.parentNode !== parent)
205
- return;
206
- } else
207
- i++;
176
+ if (memo.has(el2)) return el2[_dispose] && disposes.push(el2[_dispose]);
177
+ if (el2.parentNode !== parent) return;
178
+ } else i++;
208
179
  }
209
- for (let child of [...el2.childNodes])
210
- init(child, el2);
180
+ for (let child of [...el2.childNodes]) init(child, el2);
211
181
  }
212
182
  ;
213
183
  }
214
184
  var evalMemo = {};
215
185
  var parse = (expr, dir, fn) => {
216
- if (fn = evalMemo[expr = expr.trim()])
217
- return fn;
186
+ if (fn = evalMemo[expr = expr.trim()]) return fn;
218
187
  try {
219
188
  fn = compile(expr);
220
189
  } catch (e) {
@@ -235,16 +204,14 @@ sprae.use = (s) => {
235
204
  s.compile && (compile = s.compile);
236
205
  };
237
206
  var frag = (tpl) => {
238
- if (!tpl.nodeType)
239
- return tpl;
207
+ if (!tpl.nodeType) return tpl;
240
208
  let content = tpl.content.cloneNode(true), attributes = [...tpl.attributes], ref = document.createTextNode(""), childNodes = (content.append(ref), [...content.childNodes]);
241
209
  return {
242
210
  childNodes,
243
211
  content,
244
212
  remove: () => content.append(...childNodes),
245
213
  replaceWith(el) {
246
- if (el === ref)
247
- return;
214
+ if (el === ref) return;
248
215
  ref.before(el);
249
216
  content.append(...childNodes);
250
217
  },
@@ -264,13 +231,11 @@ directive.if = (el, evaluate, state) => {
264
231
  memo.set(ifEl, null);
265
232
  if (next?.hasAttribute(":else")) {
266
233
  next.removeAttribute(":else");
267
- if (!next.hasAttribute(":if"))
268
- next.remove(), elseEl = next.content ? frag(next) : next, memo.set(elseEl, null);
234
+ if (!next.hasAttribute(":if")) next.remove(), elseEl = next.content ? frag(next) : next, memo.set(elseEl, null);
269
235
  }
270
236
  return effect(() => {
271
237
  const newEl = evaluate(state) ? ifEl : el[_prevIf] ? null : elseEl;
272
- if (next)
273
- next[_prevIf] = newEl === ifEl;
238
+ if (next) next[_prevIf] = newEl === ifEl;
274
239
  if (curEl != newEl) {
275
240
  curEl?.remove();
276
241
  if (curEl = newEl) {
@@ -290,10 +255,8 @@ directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
290
255
  const items = computed(() => {
291
256
  keys2 = null;
292
257
  let items2 = evaluate(state);
293
- if (typeof items2 === "number")
294
- items2 = Array.from({ length: items2 }, (_, i) => i + 1);
295
- if (items2?.constructor === Object)
296
- keys2 = Object.keys(items2), items2 = Object.values(items2);
258
+ if (typeof items2 === "number") items2 = Array.from({ length: items2 }, (_, i) => i + 1);
259
+ if (items2?.constructor === Object) keys2 = Object.keys(items2), items2 = Object.values(items2);
297
260
  return items2 || [];
298
261
  });
299
262
  const update = () => {
@@ -338,8 +301,7 @@ directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
338
301
  if (!planned) {
339
302
  update();
340
303
  queueMicrotask(() => (planned && update(), planned = 0));
341
- } else
342
- planned++;
304
+ } else planned++;
343
305
  });
344
306
  };
345
307
  directive.each.parse = (expr) => {
@@ -366,8 +328,7 @@ directive.with = (el, evaluate, rootState) => {
366
328
  // directive/html.js
367
329
  directive.html = (el, evaluate, state) => {
368
330
  let tpl = evaluate(state);
369
- if (!tpl)
370
- return;
331
+ if (!tpl) return;
371
332
  let content = (tpl.content || tpl).cloneNode(true);
372
333
  el.replaceChildren(content);
373
334
  sprae(el, state);
@@ -375,8 +336,7 @@ directive.html = (el, evaluate, state) => {
375
336
 
376
337
  // directive/text.js
377
338
  directive.text = (el, evaluate, state) => {
378
- if (el.content)
379
- el.replaceWith(el = frag(el).childNodes[0]);
339
+ if (el.content) el.replaceWith(el = frag(el).childNodes[0]);
380
340
  return effect(() => {
381
341
  let value = evaluate(state);
382
342
  el.textContent = value == null ? "" : value;
@@ -390,20 +350,13 @@ directive.class = (el, evaluate, state) => {
390
350
  let v = evaluate(state);
391
351
  let clsx = /* @__PURE__ */ new Set();
392
352
  if (v) {
393
- if (typeof v === "string")
394
- v.split(" ").map((cls) => clsx.add(cls));
395
- else if (Array.isArray(v))
396
- v.map((v2) => v2 && clsx.add(v2));
397
- else
398
- Object.entries(v).map(([k, v2]) => v2 && clsx.add(k));
353
+ if (typeof v === "string") v.split(" ").map((cls) => clsx.add(cls));
354
+ else if (Array.isArray(v)) v.map((v2) => v2 && clsx.add(v2));
355
+ else Object.entries(v).map(([k, v2]) => v2 && clsx.add(k));
399
356
  }
400
- for (let cls of cur)
401
- if (clsx.has(cls))
402
- clsx.delete(cls);
403
- else
404
- el.classList.remove(cls);
405
- for (let cls of cur = clsx)
406
- el.classList.add(cls);
357
+ for (let cls of cur) if (clsx.has(cls)) clsx.delete(cls);
358
+ else el.classList.remove(cls);
359
+ for (let cls of cur = clsx) el.classList.add(cls);
407
360
  });
408
361
  };
409
362
 
@@ -412,28 +365,21 @@ directive.style = (el, evaluate, state) => {
412
365
  let initStyle = el.getAttribute("style");
413
366
  return effect(() => {
414
367
  let v = evaluate(state);
415
- if (typeof v === "string")
416
- el.setAttribute("style", initStyle + (initStyle.endsWith(";") ? "" : "; ") + v);
368
+ if (typeof v === "string") el.setAttribute("style", initStyle + (initStyle.endsWith(";") ? "" : "; ") + v);
417
369
  else {
418
- if (initStyle)
419
- el.setAttribute("style", initStyle);
420
- for (let k in v)
421
- k[0] == "-" ? el.style.setProperty(k, v[k]) : el.style[k] = v[k];
370
+ if (initStyle) el.setAttribute("style", initStyle);
371
+ for (let k in v) k[0] == "-" ? el.style.setProperty(k, v[k]) : el.style[k] = v[k];
422
372
  }
423
373
  });
424
374
  };
425
375
 
426
376
  // directive/default.js
427
377
  directive.default = (target, evaluate, state, name) => {
428
- if (!name.startsWith("on"))
429
- return effect(() => {
430
- let value = evaluate(state);
431
- if (name)
432
- attr(target, name, value);
433
- else
434
- for (let key in value)
435
- attr(target, dashcase(key), value[key]);
436
- });
378
+ if (!name.startsWith("on")) return effect(() => {
379
+ let value = evaluate(state);
380
+ if (name) attr(target, name, value);
381
+ else for (let key in value) attr(target, dashcase(key), value[key]);
382
+ });
437
383
  const ctxs = name.split("..").map((e) => {
438
384
  let ctx = { evt: "", target, test: () => true };
439
385
  ctx.evt = (e.startsWith("on") ? e.slice(2) : e).replace(
@@ -442,16 +388,14 @@ directive.default = (target, evaluate, state, name) => {
442
388
  );
443
389
  return ctx;
444
390
  });
445
- if (ctxs.length == 1)
446
- return effect(() => addListener(evaluate(state), ctxs[0]));
391
+ if (ctxs.length == 1) return effect(() => addListener(evaluate(state), ctxs[0]));
447
392
  let startFn, nextFn, off, idx = 0;
448
393
  const nextListener = (fn) => {
449
394
  off = addListener((e) => (off(), nextFn = fn?.(e), (idx = ++idx % ctxs.length) ? nextListener(nextFn) : startFn && nextListener(startFn)), ctxs[idx]);
450
395
  };
451
396
  return effect(() => (startFn = evaluate(state), !off && nextListener(startFn), () => startFn = null));
452
397
  function addListener(fn, { evt, target: target2, test, defer, stop, prevent, immediate, ...opts }) {
453
- if (defer)
454
- fn = defer(fn);
398
+ if (defer) fn = defer(fn);
455
399
  const cb = (e) => {
456
400
  try {
457
401
  test(e) && (stop && (immediate ? e.stopImmediatePropagation() : e.stopPropagation()), prevent && e.preventDefault(), fn?.(e));
@@ -465,6 +409,7 @@ directive.default = (target, evaluate, state, name) => {
465
409
  ;
466
410
  };
467
411
  var mods = {
412
+ // actions
468
413
  prevent(ctx) {
469
414
  ctx.prevent = true;
470
415
  },
@@ -474,6 +419,7 @@ var mods = {
474
419
  immediate(ctx) {
475
420
  ctx.immediate = true;
476
421
  },
422
+ // options
477
423
  once(ctx) {
478
424
  ctx.once = true;
479
425
  },
@@ -483,6 +429,7 @@ var mods = {
483
429
  capture(ctx) {
484
430
  ctx.capture = true;
485
431
  },
432
+ // target
486
433
  window(ctx) {
487
434
  ctx.target = window;
488
435
  },
@@ -495,21 +442,21 @@ var mods = {
495
442
  debounce(ctx, wait) {
496
443
  ctx.defer = (fn) => debounce(fn, wait ? Number(wait) || 0 : 108);
497
444
  },
445
+ // test
498
446
  outside: (ctx) => (e) => {
499
447
  let target = ctx.target;
500
- if (target.contains(e.target))
501
- return false;
502
- if (e.target.isConnected === false)
503
- return false;
504
- if (target.offsetWidth < 1 && target.offsetHeight < 1)
505
- return false;
448
+ if (target.contains(e.target)) return false;
449
+ if (e.target.isConnected === false) return false;
450
+ if (target.offsetWidth < 1 && target.offsetHeight < 1) return false;
506
451
  return true;
507
452
  },
508
453
  self: (ctx) => (e) => e.target === ctx.target,
454
+ // keyboard
509
455
  ctrl: (_, ...param) => (e) => keys.ctrl(e) && param.every((p) => keys[p] ? keys[p](e) : e.key === p),
510
456
  shift: (_, ...param) => (e) => keys.shift(e) && param.every((p) => keys[p] ? keys[p](e) : e.key === p),
511
457
  alt: (_, ...param) => (e) => keys.alt(e) && param.every((p) => keys[p] ? keys[p](e) : e.key === p),
512
458
  meta: (_, ...param) => (e) => keys.meta(e) && param.every((p) => keys[p] ? keys[p](e) : e.key === p),
459
+ // NOTE: we don't expose up/left/right/down as too verbose: can and better be handled/differentiated at once
513
460
  arrow: () => keys.arrow,
514
461
  enter: () => keys.enter,
515
462
  esc: () => keys.esc,
@@ -536,23 +483,19 @@ var keys = {
536
483
  char: (e) => /^\S$/.test(e.key)
537
484
  };
538
485
  var attr = (el, name, v) => {
539
- if (v == null || v === false)
540
- el.removeAttribute(name);
541
- else
542
- el.setAttribute(name, v === true ? "" : typeof v === "number" || typeof v === "string" ? v : "");
486
+ if (v == null || v === false) el.removeAttribute(name);
487
+ else el.setAttribute(name, v === true ? "" : typeof v === "number" || typeof v === "string" ? v : "");
543
488
  };
544
489
  var throttle = (fn, limit) => {
545
490
  let pause, planned, block = (e) => {
546
491
  pause = true;
547
492
  setTimeout(() => {
548
493
  pause = false;
549
- if (planned)
550
- return planned = false, block(e), fn(e);
494
+ if (planned) return planned = false, block(e), fn(e);
551
495
  }, limit);
552
496
  };
553
497
  return (e) => {
554
- if (pause)
555
- return planned = true;
498
+ if (pause) return planned = true;
556
499
  block(e);
557
500
  return fn(e);
558
501
  };
@@ -573,9 +516,11 @@ var dashcase = (str) => {
573
516
 
574
517
  // directive/value.js
575
518
  directive.value = (el, [getValue, setValue], state) => {
576
- const update = el.type === "text" || el.type === "" ? (value) => el.setAttribute("value", el.value = value == null ? "" : value) : el.tagName === "TEXTAREA" || el.type === "text" || el.type === "" ? (value, from, to) => (from = el.selectionStart, to = el.selectionEnd, el.setAttribute("value", el.value = value == null ? "" : value), from && el.setSelectionRange(from, to)) : el.type === "checkbox" ? (value) => (el.checked = value, attr(el, "checked", value)) : el.type === "select-one" ? (value) => {
577
- for (let option in el.options)
578
- option.removeAttribute("selected");
519
+ const update = el.type === "text" || el.type === "" ? (value) => el.setAttribute("value", el.value = value == null ? "" : value) : el.tagName === "TEXTAREA" || el.type === "text" || el.type === "" ? (value, from, to) => (
520
+ // we retain selection in input
521
+ (from = el.selectionStart, to = el.selectionEnd, el.setAttribute("value", el.value = value == null ? "" : value), from && el.setSelectionRange(from, to))
522
+ ) : el.type === "checkbox" ? (value) => (el.checked = value, attr(el, "checked", value)) : el.type === "select-one" ? (value) => {
523
+ for (let option of el.options) option.removeAttribute("selected");
579
524
  el.value = value;
580
525
  el.selectedOptions[0]?.setAttribute("selected", "");
581
526
  } : (value) => el.value = value;