sprae 11.0.7 → 11.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/dist/sprae.js CHANGED
@@ -1,6 +1,5 @@
1
1
  // signal.js
2
2
  var current;
3
- var batched;
4
3
  var signal = (v, s, obs = /* @__PURE__ */ new Set()) => (s = {
5
4
  get value() {
6
5
  current?.deps.push(obs.add(current));
@@ -9,7 +8,7 @@ var signal = (v, s, obs = /* @__PURE__ */ new Set()) => (s = {
9
8
  set value(val) {
10
9
  if (val === v) return;
11
10
  v = val;
12
- for (let sub of obs) batched ? batched.add(sub) : sub();
11
+ for (let sub of obs) sub();
13
12
  },
14
13
  peek() {
15
14
  return v;
@@ -34,31 +33,19 @@ var computed = (fn, s = signal(), c, e) => (c = {
34
33
  },
35
34
  peek: s.peek
36
35
  }, c.toJSON = c.then = c.toString = c.valueOf = () => c.value, c);
37
- var batch = (fn) => {
38
- let fxs = batched;
39
- if (!fxs) batched = /* @__PURE__ */ new Set();
40
- try {
41
- fn();
42
- } finally {
43
- if (!fxs) {
44
- fxs = batched;
45
- batched = null;
46
- for (const fx of fxs) fx();
47
- }
48
- }
49
- };
50
- var untracked = (fn, prev, v) => (prev = current, current = null, v = fn(), current = prev, v);
36
+ var batch = (fn) => fn();
37
+ var untracked = batch;
51
38
  function use(s) {
52
39
  signal = s.signal;
53
40
  effect = s.effect;
54
41
  computed = s.computed;
55
- batch = s.batch || ((fn) => fn());
42
+ batch = s.batch || batch;
56
43
  untracked = s.untracked || batch;
57
44
  }
58
45
 
59
46
  // store.js
60
47
  var _signals = Symbol("signals");
61
- var _change = Symbol("length");
48
+ var _change = Symbol("change");
62
49
  function store(values, parent) {
63
50
  if (!values) return values;
64
51
  if (values[_signals]) return values;
@@ -122,14 +109,13 @@ function set(signals, key, v) {
122
109
  else if (s._set) s._set(v);
123
110
  else if (Array.isArray(v) && Array.isArray(s.peek())) {
124
111
  const cur = s.peek();
125
- if (cur[_change]) untracked(() => {
112
+ if (cur[_change]) {
126
113
  batch(() => {
127
114
  let i = 0, l = v.length;
128
115
  for (; i < l; i++) cur[i] = v[i];
129
116
  cur.length = l;
130
117
  });
131
- });
132
- else {
118
+ } else {
133
119
  s.value = v;
134
120
  }
135
121
  } else {
@@ -149,6 +135,7 @@ var _state = Symbol("state");
149
135
  var _on = Symbol("on");
150
136
  var _off = Symbol("off");
151
137
  var directive = {};
138
+ var dir = (name, create, p = parse) => directive[name] = (el, expr, state, name2, update, evaluate) => (evaluate = p(expr), update = create(el, state, expr, name2, evaluate), () => update(evaluate(state)));
152
139
  function sprae(el, values) {
153
140
  if (!el?.childNodes) return;
154
141
  if (_state in el) {
@@ -168,13 +155,12 @@ function sprae(el, values) {
168
155
  function init(el2) {
169
156
  if (!el2.childNodes) return;
170
157
  for (let i = 0; i < el2.attributes?.length; ) {
171
- let attr2 = el2.attributes[i];
158
+ let attr2 = el2.attributes[i], update;
172
159
  if (attr2.name[0] === ":") {
173
160
  el2.removeAttribute(attr2.name);
174
161
  for (let name of attr2.name.slice(1).split(":")) {
175
- let dir = directive[name] || directive.default, update = dir(el2, (dir.parse || parse)(attr2.value), state, name);
176
- fx.push(update);
177
- offs.push(effect(update));
162
+ update = (directive[name] || directive.default)(el2, attr2.value, state, name);
163
+ fx.push(update), offs.push(effect(update));
178
164
  if (_state in el2) return;
179
165
  }
180
166
  } else i++;
@@ -184,19 +170,20 @@ function sprae(el, values) {
184
170
  ;
185
171
  }
186
172
  var memo = {};
187
- var parse = (expr, dir, fn) => {
173
+ var parse = (expr, dir2) => {
174
+ let fn;
188
175
  if (fn = memo[expr = expr.trim()]) return fn;
189
176
  try {
190
177
  fn = compile(expr);
191
178
  } catch (e) {
192
- err(e, dir, expr);
179
+ err(e, dir2, expr);
193
180
  }
194
181
  return memo[expr] = fn;
195
182
  };
196
- var err = (e, dir, expr = "") => {
183
+ var err = (e, dir2, expr = "") => {
197
184
  throw Object.assign(e, { message: `\u2234 ${e.message}
198
185
 
199
- ${dir}${expr ? `="${expr}"
186
+ ${dir2 || ""}${expr ? `="${expr}"
200
187
 
201
188
  ` : ""}`, expr });
202
189
  };
@@ -229,8 +216,9 @@ var frag = (tpl) => {
229
216
 
230
217
  // directive/if.js
231
218
  var _prevIf = Symbol("if");
232
- directive.if = (el, evaluate, state) => {
233
- let next = el.nextElementSibling, holder = document.createTextNode(""), curEl, ifEl, elseEl;
219
+ dir("if", (el, state) => {
220
+ const holder = document.createTextNode("");
221
+ let next = el.nextElementSibling, curEl, ifEl, elseEl;
234
222
  el.replaceWith(holder);
235
223
  ifEl = el.content ? frag(el) : el;
236
224
  ifEl[_state] = null;
@@ -238,8 +226,8 @@ directive.if = (el, evaluate, state) => {
238
226
  next.removeAttribute(":else");
239
227
  if (!next.hasAttribute(":if")) next.remove(), elseEl = next.content ? frag(next) : next, elseEl[_state] = null;
240
228
  }
241
- return () => {
242
- const newEl = evaluate(state) ? ifEl : el[_prevIf] ? null : elseEl;
229
+ return (value) => {
230
+ const newEl = value ? ifEl : el[_prevIf] ? null : elseEl;
243
231
  if (next) next[_prevIf] = newEl === ifEl;
244
232
  if (curEl != newEl) {
245
233
  if (curEl) curEl.remove(), curEl[_off]?.();
@@ -250,41 +238,28 @@ directive.if = (el, evaluate, state) => {
250
238
  }
251
239
  }
252
240
  };
253
- };
241
+ });
254
242
 
255
243
  // directive/each.js
256
- directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
257
- const holder = document.createTextNode("");
258
- tpl.replaceWith(holder);
259
- tpl[_state] = null;
260
- let cur, keys2, prevl = 0;
261
- const items = computed(() => {
262
- keys2 = null;
263
- let items2 = evaluate(state);
264
- if (typeof items2 === "number") items2 = Array.from({ length: items2 }, (_, i) => i + 1);
265
- if (items2?.constructor === Object) keys2 = Object.keys(items2), items2 = Object.values(items2);
266
- return items2 || [];
267
- });
268
- const update = () => {
269
- untracked(() => {
244
+ dir(
245
+ "each",
246
+ (tpl, state, expr) => {
247
+ const [itemVar, idxVar = "$"] = expr.split(/\s+in\s+/)[0].split(/\s*,\s*/);
248
+ const holder = document.createTextNode("");
249
+ tpl.replaceWith(holder);
250
+ tpl[_state] = null;
251
+ let cur, keys2, items, prevl = 0;
252
+ const update = () => {
270
253
  var _a, _b;
271
- let i = 0, newItems = items.value, newl = newItems.length;
254
+ let i = 0, newItems = items, newl = newItems.length;
272
255
  if (cur && !cur[_change]) {
273
- for (let s of cur[_signals] || []) {
274
- s[Symbol.dispose]();
275
- }
256
+ for (let s of cur[_signals] || []) s[Symbol.dispose]();
276
257
  cur = null, prevl = 0;
277
258
  }
278
- if (newl < prevl) {
279
- cur.length = newl;
280
- } else {
281
- if (!cur) {
282
- cur = newItems;
283
- } else {
284
- for (; i < prevl; i++) {
285
- cur[i] = newItems[i];
286
- }
287
- }
259
+ if (newl < prevl) cur.length = newl;
260
+ else {
261
+ if (!cur) cur = newItems;
262
+ else while (i < prevl) cur[i] = newItems[i++];
288
263
  for (; i < newl; i++) {
289
264
  cur[i] = newItems[i];
290
265
  let idx = i, scope = store({
@@ -299,95 +274,38 @@ directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
299
274
  }
300
275
  }
301
276
  prevl = newl;
302
- });
303
- };
304
- let planned = 0;
305
- return () => {
306
- items.value[_change]?.value;
307
- if (!planned++) update(), queueMicrotask(() => (planned > 1 && update(), planned = 0));
308
- };
309
- };
310
- directive.each.parse = (expr) => {
311
- let [leftSide, itemsExpr] = expr.split(/\s+in\s+/);
312
- let [itemVar, idxVar = "$"] = leftSide.split(/\s*,\s*/);
313
- return [itemVar, idxVar, parse(itemsExpr)];
314
- };
315
-
316
- // directive/ref.js
317
- directive.ref = (el, evaluate, state) => {
318
- return () => evaluate(state)?.call?.(null, el);
319
- };
320
-
321
- // directive/with.js
322
- directive.with = (el, evaluate, rootState) => {
323
- let state;
324
- return () => {
325
- let values = evaluate(rootState);
326
- sprae(el, state ? values : state = store(values, rootState));
327
- };
328
- };
329
-
330
- // directive/text.js
331
- directive.text = (el, evaluate, state) => {
332
- if (el.content) el.replaceWith(el = frag(el).childNodes[0]);
333
- return () => {
334
- let value = evaluate(state);
335
- el.textContent = value == null ? "" : value;
336
- };
337
- };
338
-
339
- // directive/class.js
340
- directive.class = (el, evaluate, state) => {
341
- let cur = /* @__PURE__ */ new Set();
342
- return () => {
343
- let v = evaluate(state);
344
- let clsx = /* @__PURE__ */ new Set();
345
- if (v) {
346
- if (typeof v === "string") v.split(" ").map((cls) => clsx.add(cls));
347
- else if (Array.isArray(v)) v.map((v2) => v2 && clsx.add(v2));
348
- else Object.entries(v).map(([k, v2]) => v2 && clsx.add(k));
349
- }
350
- for (let cls of cur) if (clsx.has(cls)) clsx.delete(cls);
351
- else el.classList.remove(cls);
352
- for (let cls of cur = clsx) el.classList.add(cls);
353
- };
354
- };
355
-
356
- // directive/style.js
357
- directive.style = (el, evaluate, state) => {
358
- let initStyle = el.getAttribute("style");
359
- return () => {
360
- let v = evaluate(state);
361
- if (typeof v === "string") el.setAttribute("style", initStyle + (initStyle.endsWith(";") ? "" : "; ") + v);
362
- else {
363
- if (initStyle) el.setAttribute("style", initStyle);
364
- for (let k in v) k[0] == "-" ? el.style.setProperty(k, v[k]) : el.style[k] = v[k];
365
- }
366
- };
367
- };
277
+ };
278
+ return (value) => {
279
+ keys2 = null;
280
+ if (typeof value === "number") items = Array.from({ length: value }, (_, i) => i + 1);
281
+ else if (value?.constructor === Object) keys2 = Object.keys(value), items = Object.values(value);
282
+ else items = value || [];
283
+ let planned = 0;
284
+ return effect(() => {
285
+ items[_change]?.value;
286
+ if (!planned++) update(), queueMicrotask(() => (planned > 1 && update(), planned = 0));
287
+ });
288
+ };
289
+ },
290
+ // redefine evaluator to take second part of expression
291
+ (expr) => parse(expr.split(/\s+in\s+/)[1])
292
+ );
368
293
 
369
294
  // directive/default.js
370
- directive.default = (target, evaluate, state, name) => {
371
- if (!name.startsWith("on")) return () => {
372
- let value = evaluate(state);
373
- if (name) attr(target, name, value);
374
- else for (let key in value) attr(target, dashcase(key), value[key]);
375
- };
295
+ dir("default", (target, state, expr, name) => {
296
+ if (!name.startsWith("on"))
297
+ return name ? (value) => attr(target, name, value) : (value) => {
298
+ for (let key in value) attr(target, dashcase(key), value[key]);
299
+ };
376
300
  const ctxs = name.split("..").map((e) => {
377
301
  let ctx = { evt: "", target, test: () => true };
378
302
  ctx.evt = (e.startsWith("on") ? e.slice(2) : e).replace(
379
303
  /\.(\w+)?-?([-\w]+)?/g,
380
- (match, mod, param = "") => (ctx.test = mods[mod]?.(ctx, ...param.split("-")) || ctx.test, "")
304
+ (_, mod, param = "") => (ctx.test = mods[mod]?.(ctx, ...param.split("-")) || ctx.test, "")
381
305
  );
382
306
  return ctx;
383
307
  });
384
- if (ctxs.length == 1) return () => addListener(evaluate(state), ctxs[0]);
385
- let startFn, nextFn, off, idx = 0;
386
- const nextListener = (fn) => {
387
- off = addListener((e) => (off(), nextFn = fn?.(e), (idx = ++idx % ctxs.length) ? nextListener(nextFn) : startFn && nextListener(startFn)), ctxs[idx]);
388
- };
389
- return () => (startFn = evaluate(state), !off && nextListener(startFn), () => startFn = null);
390
- function addListener(fn, { evt, target: target2, test, defer, stop, prevent, immediate, ...opts }) {
308
+ const addListener = (fn, { evt, target: target2, test, defer, stop, prevent, immediate, ...opts }) => {
391
309
  if (defer) fn = defer(fn);
392
310
  const cb = (e) => {
393
311
  try {
@@ -398,9 +316,14 @@ directive.default = (target, evaluate, state, name) => {
398
316
  };
399
317
  target2.addEventListener(evt, cb, opts);
400
318
  return () => target2.removeEventListener(evt, cb, opts);
401
- }
402
- ;
403
- };
319
+ };
320
+ if (ctxs.length == 1) return (v) => addListener(v, ctxs[0]);
321
+ let startFn, nextFn, off, idx = 0;
322
+ const nextListener = (fn) => {
323
+ off = addListener((e) => (off(), nextFn = fn?.(e), (idx = ++idx % ctxs.length) ? nextListener(nextFn) : startFn && nextListener(startFn)), ctxs[idx]);
324
+ };
325
+ return (value) => (startFn = value, !off && nextListener(startFn), () => startFn = null);
326
+ });
404
327
  var mods = {
405
328
  // actions
406
329
  prevent(ctx) {
@@ -478,10 +401,6 @@ var keys = {
478
401
  letter: (e) => /^\p{L}$/gu.test(e.key),
479
402
  char: (e) => /^\S$/.test(e.key)
480
403
  };
481
- var attr = (el, name, v) => {
482
- if (v == null || v === false) el.removeAttribute(name);
483
- else el.setAttribute(name, v === true ? "" : typeof v === "number" || typeof v === "string" ? v : "");
484
- };
485
404
  var throttle = (fn, limit) => {
486
405
  let pause, planned, block = (e) => {
487
406
  pause = true;
@@ -506,12 +425,16 @@ var debounce = (fn, wait) => {
506
425
  }, wait);
507
426
  };
508
427
  };
428
+ var attr = (el, name, v) => {
429
+ if (v == null || v === false) el.removeAttribute(name);
430
+ else el.setAttribute(name, v === true ? "" : typeof v === "number" || typeof v === "string" ? v : "");
431
+ };
509
432
  var dashcase = (str) => {
510
433
  return str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match, i) => (i ? "-" : "") + match.toLowerCase());
511
434
  };
512
435
 
513
436
  // directive/value.js
514
- directive.value = (el, [getValue, setValue], state) => {
437
+ dir("value", (el, state, expr) => {
515
438
  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) => (
516
439
  // we retain selection in input
517
440
  (from = el.selectionStart, to = el.selectionEnd, el.setAttribute("value", el.value = value == null ? "" : value), from && el.setSelectionRange(from, to))
@@ -523,50 +446,80 @@ directive.value = (el, [getValue, setValue], state) => {
523
446
  for (let o of el.options) o.removeAttribute("selected");
524
447
  for (let v of value) el.querySelector(`[value="${v}"]`).setAttribute("selected", "");
525
448
  } : (value) => el.value = value;
526
- const handleChange = el.type === "checkbox" ? () => setValue(state, el.checked) : el.type === "select-multiple" ? () => setValue(state, [...el.selectedOptions].map((o) => o.value)) : (e) => setValue(state, el.selectedIndex < 0 ? null : el.value);
527
- el.oninput = el.onchange = handleChange;
528
- if (el.type?.startsWith("select")) {
529
- new MutationObserver(handleChange).observe(el, { childList: true, subtree: true, attributes: true });
530
- sprae(el, state);
531
- }
532
- return () => {
533
- update(getValue(state));
534
- };
535
- };
536
- directive.value.parse = (expr) => {
537
- let evaluate = [parse(expr)];
449
+ ensure(state, expr);
538
450
  try {
539
- const set2 = parse(`${expr}=__`);
540
- evaluate.push((state, value) => {
541
- state.__ = value;
542
- set2(state, value);
543
- delete state.__;
544
- });
545
- } catch (e) {
451
+ const set2 = setter(expr);
452
+ const handleChange = el.type === "checkbox" ? () => set2(state, el.checked) : el.type === "select-multiple" ? () => set2(state, [...el.selectedOptions].map((o) => o.value)) : () => set2(state, el.selectedIndex < 0 ? null : el.value);
453
+ el.oninput = el.onchange = handleChange;
454
+ if (el.type?.startsWith("select")) {
455
+ new MutationObserver(handleChange).observe(el, { childList: true, subtree: true, attributes: true });
456
+ sprae(el, state);
457
+ }
458
+ } catch {
546
459
  }
547
- return evaluate;
460
+ return update;
461
+ });
462
+ var setter = (expr, set2 = parse(`${expr}=__`)) => (
463
+ // FIXME: if there's a simpler way to set value in justin?
464
+ (state, value) => (state.__ = value, set2(state, value), delete state.__)
465
+ );
466
+ var ensure = (state, expr, name = expr.match(/^\w+(?=\s*(?:\.|\[|$))/)) => {
467
+ var _a;
468
+ return name && (state[_a = name[0]] || (state[_a] = null));
548
469
  };
549
470
 
471
+ // directive/ref.js
472
+ dir("ref", (el, state, expr, _, ev) => (ensure(state, expr), ev(state) == null ? (setter(expr)(state, el), (_2) => _2) : (v) => v.call(null, el)));
473
+
474
+ // directive/with.js
475
+ dir("with", (el, rootState, state) => (state = null, (values) => sprae(el, state ? values : state = store(values, rootState))));
476
+
477
+ // directive/text.js
478
+ dir("text", (el) => (
479
+ // <template :text="a"/> or previously initialized template
480
+ (el.content && el.replaceWith(el = frag(el).childNodes[0]), (value) => el.textContent = value == null ? "" : value)
481
+ ));
482
+
483
+ // directive/class.js
484
+ dir(
485
+ "class",
486
+ (el, cur) => (cur = /* @__PURE__ */ new Set(), (v) => {
487
+ let clsx = /* @__PURE__ */ new Set();
488
+ if (v) {
489
+ if (typeof v === "string") v.split(" ").map((cls) => clsx.add(cls));
490
+ else if (Array.isArray(v)) v.map((v2) => v2 && clsx.add(v2));
491
+ else Object.entries(v).map(([k, v2]) => v2 && clsx.add(k));
492
+ }
493
+ for (let cls of cur) if (clsx.has(cls)) clsx.delete(cls);
494
+ else el.classList.remove(cls);
495
+ for (let cls of cur = clsx) el.classList.add(cls);
496
+ })
497
+ );
498
+
499
+ // directive/style.js
500
+ dir(
501
+ "style",
502
+ (el, initStyle) => (initStyle = el.getAttribute("style"), (v) => {
503
+ if (typeof v === "string") el.setAttribute("style", initStyle + (initStyle.endsWith(";") ? "" : "; ") + v);
504
+ else {
505
+ if (initStyle) el.setAttribute("style", initStyle);
506
+ for (let k in v) k[0] == "-" ? el.style.setProperty(k, v[k]) : el.style[k] = v[k];
507
+ }
508
+ })
509
+ );
510
+
550
511
  // directive/fx.js
551
- directive.fx = (el, evaluate, state) => {
552
- return () => evaluate(state);
553
- };
512
+ dir("fx", (_) => (_2) => _2);
554
513
 
555
514
  // directive/aria.js
556
- directive["aria"] = (el, evaluate, state) => {
557
- const update = (value) => {
558
- for (let key in value) attr(el, "aria-" + dashcase(key), value[key] == null ? null : value[key] + "");
559
- };
560
- return () => update(evaluate(state));
561
- };
515
+ dir("aria", (el) => (value) => {
516
+ for (let key in value) attr(el, "aria-" + dashcase(key), value[key] == null ? null : value[key] + "");
517
+ });
562
518
 
563
519
  // directive/data.js
564
- directive["data"] = (el, evaluate, state) => {
565
- return () => {
566
- let value = evaluate(state);
567
- for (let key in value) el.dataset[key] = value[key];
568
- };
569
- };
520
+ dir("data", (el) => (value) => {
521
+ for (let key in value) el.dataset[key] = value[key];
522
+ });
570
523
 
571
524
  // sprae.js
572
525
  sprae.use({ compile: (expr) => sprae.constructor(`with (arguments[0]) { return ${expr} };`) });