tutuca 0.9.15 → 0.9.16

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.
@@ -112,9 +112,8 @@ class Path {
112
112
  let curVal = v;
113
113
  for (const step of this.steps) {
114
114
  curVal = step.lookup(curVal, NONE);
115
- if (curVal === NONE) {
115
+ if (curVal === NONE)
116
116
  return dval;
117
- }
118
117
  }
119
118
  return curVal;
120
119
  }
@@ -124,9 +123,8 @@ class Path {
124
123
  for (let i = 0;i < this.steps.length; i++) {
125
124
  intermediates[i] = curVal;
126
125
  curVal = this.steps[i].lookup(curVal, NONE);
127
- if (curVal === NONE) {
126
+ if (curVal === NONE)
128
127
  return root;
129
- }
130
128
  }
131
129
  let newVal = v;
132
130
  for (let i = this.steps.length - 1;i >= 0; i--) {
@@ -144,7 +142,7 @@ class Path {
144
142
  console.warn(`bad PathItem`, { root, curVal, step, path: this });
145
143
  return null;
146
144
  }
147
- step.updateBindings(curVal, stack.binds.head.bindings);
145
+ step.updateBindings(curVal, stack.binds[0].bindings);
148
146
  stack = stack.enter(curVal, {}, step.isFrame);
149
147
  }
150
148
  return stack;
@@ -193,9 +191,8 @@ var EMPTY_META = {};
193
191
  function parseMetaComment(n) {
194
192
  if (n?.nodeType === 8 && n.textContent[0] === "§") {
195
193
  const m = parseMetaComment(n.previousSibling);
196
- if (m !== EMPTY_META) {
194
+ if (m !== EMPTY_META)
197
195
  return m;
198
- }
199
196
  try {
200
197
  return JSON.parse(n.textContent.slice(1, -1));
201
198
  } catch (err) {
@@ -218,9 +215,8 @@ function resolvePathStep(comp, nodeIds, vid) {
218
215
  const j = node.pathInNext ? i + 1 : i;
219
216
  const { si, sk, nid: nodeId } = nodeIds[j];
220
217
  const pi = node.pathInNext ? comp.getNodeForId(+nodeId, vid).val.toPathItem() : node.toPathItem();
221
- if (pi !== null) {
218
+ if (pi !== null)
222
219
  return si !== undefined ? pi.withIndex(+si) : sk ? pi.withKey(sk) : pi;
223
- }
224
220
  }
225
221
  return null;
226
222
  }
@@ -270,20 +266,12 @@ class ValParser {
270
266
  }
271
267
  allowFieldOnly() {
272
268
  this.okField = true;
273
- this.okBind = false;
274
- this.okComputed = false;
275
- this.okDyn = false;
276
- this.okType = false;
277
- this.okRequest = false;
278
- this.okName = false;
279
- this.okConst = false;
280
- this.okStrTpl = false;
281
- this.okSeqAccess = false;
269
+ this.okBind = this.okComputed = this.okDyn = this.okType = this.okRequest = false;
270
+ this.okName = this.okConst = this.okStrTpl = this.okSeqAccess = false;
282
271
  }
283
272
  _parseSeqAccess(s, px) {
284
- if (!this.okSeqAccess) {
273
+ if (!this.okSeqAccess)
285
274
  return null;
286
- }
287
275
  const openSquareBracketIndex = s.indexOf("[");
288
276
  this.allowFieldOnly();
289
277
  const left = this.parse(s.slice(0, openSquareBracketIndex), px);
@@ -326,15 +314,14 @@ class ValParser {
326
314
  return this.okRequest ? parseReq(s.slice(1), px) : null;
327
315
  }
328
316
  const num = VALID_FLOAT_RE.test(s) ? parseFloat(s) : null;
329
- if (Number.isFinite(num)) {
317
+ if (Number.isFinite(num))
330
318
  return this.okConst ? parseConst(num, px) : null;
331
- } else if (s === "true" || s === "false") {
319
+ else if (s === "true" || s === "false")
332
320
  return this.okConst ? parseConst(s === "true", px) : null;
333
- } else if (charCode >= 97 && charCode <= 122) {
321
+ else if (charCode >= 97 && charCode <= 122)
334
322
  return this.okName ? parseName(s, px) : null;
335
- } else if (charCode >= 65 && charCode <= 90) {
323
+ else if (charCode >= 65 && charCode <= 90)
336
324
  return this.okType ? parseType(s, px) : null;
337
- }
338
325
  return null;
339
326
  }
340
327
  parseDynamic(s, px) {
@@ -344,19 +331,13 @@ class ValParser {
344
331
  }
345
332
  parseEach(s, px) {
346
333
  this.allowFieldOnly();
347
- this.okComputed = true;
348
- this.okDyn = true;
334
+ this.okComputed = this.okDyn = true;
349
335
  return this.parse(s, px);
350
336
  }
351
337
  allowHandlerArg() {
352
338
  this.allowFieldOnly();
353
- this.okBind = true;
354
- this.okComputed = true;
355
- this.okDyn = true;
356
- this.okType = true;
357
- this.okRequest = true;
358
- this.okName = true;
359
- this.okConst = true;
339
+ this.okBind = this.okComputed = this.okDyn = this.okType = this.okRequest = true;
340
+ this.okName = this.okConst = true;
360
341
  }
361
342
  parseHandlerArg(s, px) {
362
343
  this.allowHandlerArg();
@@ -379,25 +360,17 @@ class ValParser {
379
360
  }
380
361
  parseAll(s, px) {
381
362
  this.allowHandlerArg();
382
- this.okStrTpl = true;
383
- this.okSeqAccess = true;
363
+ this.okStrTpl = this.okSeqAccess = true;
384
364
  return this.parse(s, px);
385
365
  }
386
366
  parseCondValue(s, px) {
387
367
  this.allowFieldOnly();
388
- this.okBind = true;
389
- this.okComputed = true;
390
- this.okDyn = true;
391
- this.okConst = true;
368
+ this.okBind = this.okComputed = this.okDyn = this.okConst = true;
392
369
  return this.parse(s, px);
393
370
  }
394
371
  parseText(s, px) {
395
372
  this.allowFieldOnly();
396
- this.okBind = true;
397
- this.okComputed = true;
398
- this.okDyn = true;
399
- this.okConst = true;
400
- this.okStrTpl = true;
373
+ this.okBind = this.okComputed = this.okDyn = this.okConst = this.okStrTpl = true;
401
374
  return this.parse(s, px);
402
375
  }
403
376
  parseRender(s, px) {
@@ -445,9 +418,8 @@ class StrTplVal extends VarVal {
445
418
  }
446
419
  eval(stack) {
447
420
  const strs = new Array(this.vals.length);
448
- for (let i = 0;i < this.vals.length; i++) {
421
+ for (let i = 0;i < this.vals.length; i++)
449
422
  strs[i] = this.vals[i]?.eval(stack, "");
450
- }
451
423
  return strs.join("");
452
424
  }
453
425
  static parse(s, px) {
@@ -603,15 +575,13 @@ function getValSubType(s) {
603
575
  for (let i = 0;i < s.length; i++) {
604
576
  switch (s.charCodeAt(i)) {
605
577
  case 91:
606
- if (open > 0) {
578
+ if (open > 0)
607
579
  return VAL_SUB_TYPE_INVALID;
608
- }
609
580
  open += 1;
610
581
  break;
611
582
  case 93:
612
- if (close > 0 || open === 0) {
583
+ if (close > 0 || open === 0)
613
584
  return VAL_SUB_TYPE_INVALID;
614
- }
615
585
  close += 1;
616
586
  break;
617
587
  case 123:
@@ -620,9 +590,8 @@ function getValSubType(s) {
620
590
  return VAL_SUB_TYPE_CONST_STRING;
621
591
  }
622
592
  }
623
- if (open > 0 || close > 0) {
593
+ if (open > 0 || close > 0)
624
594
  return open === 1 && close === 1 ? VAL_SUB_TYPE_SEQ_ACCESS : VAL_SUB_TYPE_INVALID;
625
- }
626
595
  return -1;
627
596
  }
628
597
  var vp = new ValParser;
@@ -683,14 +652,12 @@ class AttrParser {
683
652
  }
684
653
  }
685
654
  parseThen(s) {
686
- if (this.ifAttr) {
655
+ if (this.ifAttr)
687
656
  this.ifAttr.thenVal = vp.parseAttr(s, this.px) ?? NOT_SET_VAL;
688
- }
689
657
  }
690
658
  parseElse(value) {
691
- if (this.ifAttr) {
659
+ if (this.ifAttr)
692
660
  this.ifAttr.elseVal = vp.parseAttr(value, this.px) ?? NOT_SET_VAL;
693
- }
694
661
  }
695
662
  parseEvent(directiveName, value) {
696
663
  const [eventName, ...modifiers] = directiveName.slice(3).split("+");
@@ -749,25 +716,22 @@ class AttrParser {
749
716
  this.parseElse(s);
750
717
  return;
751
718
  }
752
- if (directiveName.startsWith("on.")) {
719
+ if (directiveName.startsWith("on."))
753
720
  this.parseEvent(directiveName, s);
754
- } else if (directiveName.startsWith("if.")) {
721
+ else if (directiveName.startsWith("if."))
755
722
  this.parseIf(directiveName, s);
756
- } else if (directiveName.startsWith("then.")) {
723
+ else if (directiveName.startsWith("then."))
757
724
  this.parseThen(s);
758
- } else if (directiveName.startsWith("else.")) {
725
+ else if (directiveName.startsWith("else."))
759
726
  this.parseElse(s);
760
- }
761
727
  }
762
728
  _parseWhen(s) {
763
- if (this.eachAttr !== null) {
729
+ if (this.eachAttr !== null)
764
730
  this.eachAttr.whenVal = vp.parseAlter(s, this.px);
765
- }
766
731
  }
767
732
  _parseLoopWith(s) {
768
- if (this.eachAttr !== null) {
733
+ if (this.eachAttr !== null)
769
734
  this.eachAttr.loopWithVal = vp.parseAlter(s, this.px);
770
- }
771
735
  }
772
736
  parse(attributes, parseAll = false) {
773
737
  for (const { name, value } of attributes) {
@@ -794,9 +758,8 @@ class ConstAttrs extends Attributes {
794
758
  }
795
759
  static fromAttrs(attrs) {
796
760
  const attrsObj = {};
797
- for (const attr of attrs) {
761
+ for (const attr of attrs)
798
762
  attrsObj[attr.name] = attr.val.eval(null);
799
- }
800
763
  return new ConstAttrs(attrsObj);
801
764
  }
802
765
  setDataAttr(key, val) {
@@ -804,9 +767,8 @@ class ConstAttrs extends Attributes {
804
767
  }
805
768
  toMacroVars() {
806
769
  const r = {};
807
- for (const name in this.items) {
770
+ for (const name in this.items)
808
771
  r[name] = `'${this.items[name]}'`;
809
- }
810
772
  return r;
811
773
  }
812
774
  isConstant() {
@@ -817,7 +779,8 @@ class ConstAttrs extends Attributes {
817
779
  class DynAttrs extends Attributes {
818
780
  eval(stack) {
819
781
  const attrs = {};
820
- for (const attr of this.items) {
782
+ for (let i = 0;i < this.items.length; i++) {
783
+ const attr = this.items[i];
821
784
  attrs[attr.name] = attr.eval(stack);
822
785
  }
823
786
  return attrs;
@@ -827,9 +790,8 @@ class DynAttrs extends Attributes {
827
790
  }
828
791
  toMacroVars() {
829
792
  const r = {};
830
- for (const attr of this.items) {
793
+ for (const attr of this.items)
831
794
  r[attr.name] = attr.val.toString();
832
- }
833
795
  return r;
834
796
  }
835
797
  }
@@ -889,17 +851,15 @@ class EventHandler {
889
851
  }
890
852
  getHandlerAndArgs(stack, _event) {
891
853
  const argValues = new Array(this.args.length);
892
- for (let i = 0;i < argValues.length; i++) {
854
+ for (let i = 0;i < argValues.length; i++)
893
855
  argValues[i] = this.args[i].eval(stack);
894
- }
895
856
  return [this.handlerVal.eval(stack), argValues];
896
857
  }
897
858
  static parse(s, px) {
898
859
  const [handlerName, ...rawArgs] = s.trim().split(/\s+/);
899
860
  const handlerVal = vp.parseHandlerName(handlerName, px);
900
- if (handlerVal === null) {
861
+ if (handlerVal === null)
901
862
  return null;
902
- }
903
863
  const args = new Array(rawArgs.length);
904
864
  vp.allowHandlerArg();
905
865
  for (let i = 0;i < rawArgs.length; i++) {
@@ -1451,7 +1411,7 @@ function condenseChildsWhites(childs) {
1451
1411
  }
1452
1412
 
1453
1413
  class View {
1454
- constructor(name, rawView, style = "", anode = null, ctx = null) {
1414
+ constructor(name, rawView = "No View Defined", style = "", anode = null, ctx = null) {
1455
1415
  this.name = name;
1456
1416
  this.anode = anode;
1457
1417
  this.style = style;
@@ -1546,6 +1506,63 @@ function compileModifiers(eventName, names) {
1546
1506
  };
1547
1507
  }
1548
1508
 
1509
+ // src/util/parsectx.js
1510
+ class ParseCtxClassSetCollector extends ParseContext {
1511
+ constructor(...args) {
1512
+ super(...args);
1513
+ this.classes = new Set;
1514
+ }
1515
+ _addClasses(s) {
1516
+ for (const v of s.split(/\s+/)) {
1517
+ this.classes.add(v);
1518
+ }
1519
+ }
1520
+ enterMacro(macroName, macroVars, macroSlots) {
1521
+ const { DOMParser: DP, Text, Comment, nodes, events, macroNodes } = this;
1522
+ const frame = { macroName, macroVars, macroSlots };
1523
+ const v = new ParseCtxClassSetCollector(DP, Text, Comment, nodes, events, macroNodes, frame, this);
1524
+ v.classes = this.classes;
1525
+ return v;
1526
+ }
1527
+ onAttributes(attrs, _wrapperAttrs, _textChild) {
1528
+ if (Array.isArray(attrs.items)) {
1529
+ for (const attr of attrs.items) {
1530
+ if (attr.name !== "class") {
1531
+ continue;
1532
+ }
1533
+ const { val, thenVal, elseVal } = attr;
1534
+ if (thenVal !== undefined) {
1535
+ this._maybeAddVal(thenVal);
1536
+ this._maybeAddVal(elseVal);
1537
+ } else {
1538
+ this._maybeAddVal(val);
1539
+ }
1540
+ }
1541
+ } else {
1542
+ const attr = attrs.items.class;
1543
+ if (attr) {
1544
+ this._addClasses(attr);
1545
+ }
1546
+ }
1547
+ }
1548
+ _maybeAddVal(value) {
1549
+ if (!this._maybeAddStrTpl(value) && typeof value?.val === "string") {
1550
+ this._addClasses(value.val);
1551
+ }
1552
+ }
1553
+ _maybeAddStrTpl(value) {
1554
+ if (value?.vals !== undefined) {
1555
+ for (const val of value.vals) {
1556
+ if (val instanceof ConstVal && val.val !== "") {
1557
+ this._addClasses(val.val);
1558
+ }
1559
+ }
1560
+ return true;
1561
+ }
1562
+ return false;
1563
+ }
1564
+ }
1565
+
1549
1566
  // src/cache.js
1550
1567
  class NullDomCache {
1551
1568
  get(_k, _cacheKey) {}
@@ -1563,11 +1580,10 @@ class WeakMapDomCache {
1563
1580
  this.map = new WeakMap;
1564
1581
  }
1565
1582
  _returnValue(r) {
1566
- if (r === undefined) {
1583
+ if (r === undefined)
1567
1584
  this.miss += 1;
1568
- } else {
1585
+ else
1569
1586
  this.hit += 1;
1570
- }
1571
1587
  return r;
1572
1588
  }
1573
1589
  get(k, cacheKey) {
@@ -1575,13 +1591,12 @@ class WeakMapDomCache {
1575
1591
  }
1576
1592
  set(k, cacheKey, v) {
1577
1593
  const cur = this.map.get(k);
1578
- if (cur) {
1594
+ if (cur)
1579
1595
  cur[cacheKey] = v;
1580
- } else if (typeof k === "object") {
1596
+ else if (typeof k === "object")
1581
1597
  this.map.set(k, { [cacheKey]: v });
1582
- } else {
1598
+ else
1583
1599
  this.badKey += 1;
1584
- }
1585
1600
  }
1586
1601
  get2(k1, k2, cacheKey) {
1587
1602
  return this._returnValue(this.map.get(k1)?.get?.(k2)?.[cacheKey]);
@@ -1590,11 +1605,10 @@ class WeakMapDomCache {
1590
1605
  const cur1 = this.map.get(k1);
1591
1606
  if (cur1) {
1592
1607
  const cur = cur1.get(k2);
1593
- if (cur) {
1608
+ if (cur)
1594
1609
  cur[cacheKey] = v;
1595
- } else {
1610
+ else
1596
1611
  cur1.set(k2, { [cacheKey]: v });
1597
- }
1598
1612
  } else if (typeof k1 === "object" && typeof k2 === "object") {
1599
1613
  const cur = new WeakMap;
1600
1614
  cur.set(k2, { [cacheKey]: v });
@@ -1625,9 +1639,8 @@ class WeakMapComputedCache {
1625
1639
  const cur = this.map.get(v);
1626
1640
  if (cur) {
1627
1641
  const curValue = cur[key];
1628
- if (curValue !== undefined) {
1642
+ if (curValue !== undefined)
1629
1643
  return curValue;
1630
- }
1631
1644
  const newValue2 = fn.call(v) ?? null;
1632
1645
  cur[key] = newValue2;
1633
1646
  return newValue2;
@@ -1675,9 +1688,8 @@ class Components {
1675
1688
  }
1676
1689
  compileStyles() {
1677
1690
  const styles = [];
1678
- for (const comp of this.byId.values()) {
1691
+ for (const comp of this.byId.values())
1679
1692
  styles.push(comp.compileStyle());
1680
- }
1681
1693
  return styles.join(`
1682
1694
  `);
1683
1695
  }
@@ -1701,9 +1713,8 @@ class ComponentStack {
1701
1713
  this.comps.registerComponent(comp);
1702
1714
  this.byName[comp.name] = comp;
1703
1715
  const alias = aliases[comp.name];
1704
- if (alias) {
1716
+ if (alias)
1705
1717
  this.byName[alias] = comp;
1706
- }
1707
1718
  }
1708
1719
  }
1709
1720
  registerMacros(macros) {
@@ -1713,9 +1724,8 @@ class ComponentStack {
1713
1724
  return this.comps.getCompFor(v);
1714
1725
  }
1715
1726
  registerRequestHandlers(handlers) {
1716
- for (const name in handlers) {
1727
+ for (const name in handlers)
1717
1728
  this.reqsByName[name] = new RequestHandler(name, handlers[name]);
1718
- }
1719
1729
  }
1720
1730
  lookupRequest(name) {
1721
1731
  return this.reqsByName[name] ?? this.parent?.lookupRequest(name) ?? null;
@@ -1761,26 +1771,26 @@ var isString = (v) => typeof v === "string";
1761
1771
  var _compId = 0;
1762
1772
 
1763
1773
  class Component {
1764
- constructor(name, Class, view, views = {}, style = "", commonStyle = "", globalStyle = "", computed = {}, input = {}, logic = {}, bubble = {}, response = {}, alter = {}, dynamic = {}, on = {}) {
1774
+ constructor(Class, o) {
1765
1775
  this.id = _compId++;
1766
- this.name = name;
1776
+ this.name = o.name ?? "UnkComp";
1767
1777
  this.Class = Class;
1768
- this.views = { main: new View("main", view, style) };
1769
- this.commonStyle = commonStyle;
1770
- this.globalStyle = globalStyle;
1771
- this.computed = computed;
1772
- this.input = input;
1773
- this.logic = logic;
1774
- this.bubble = bubble;
1775
- this.response = response;
1776
- this.alter = alter;
1777
- this.on = { stackEnter: on?.stackEnter ?? defaultOnStackEnter };
1778
- for (const name2 in views) {
1779
- const v = views[name2];
1780
- const { view: view2, style: style2 } = isString(v) ? { view: v } : v;
1781
- this.views[name2] = new View(name2, view2, style2);
1782
- }
1783
- this._rawDynamic = dynamic;
1778
+ this.views = { main: new View("main", o.view, o.style) };
1779
+ this.commonStyle = o.commonStyle ?? "";
1780
+ this.globalStyle = o.globalStyle ?? "";
1781
+ this.computed = o.computed ?? {};
1782
+ this.input = o.input ?? {};
1783
+ this.logic = o.logic ?? {};
1784
+ this.bubble = o.bubble ?? {};
1785
+ this.response = o.response ?? {};
1786
+ this.alter = o.alter ?? {};
1787
+ this.on = { stackEnter: o.on?.stackEnter ?? defaultOnStackEnter };
1788
+ for (const name in o.views ?? {}) {
1789
+ const v = o.views[name];
1790
+ const { view, style } = isString(v) ? { view: v } : v;
1791
+ this.views[name] = new View(name, view, style);
1792
+ }
1793
+ this._rawDynamic = o.dynamic ?? {};
1784
1794
  this.dynamic = {};
1785
1795
  this.scope = null;
1786
1796
  }
@@ -1798,9 +1808,8 @@ class Component {
1798
1808
  }
1799
1809
  }
1800
1810
  }
1801
- for (const name in this.views) {
1811
+ for (const name in this.views)
1802
1812
  this.views[name].compile(new ParseContext2, this.scope, this.id);
1803
- }
1804
1813
  }
1805
1814
  make(args, opts) {
1806
1815
  return this.Class.make(args, opts);
@@ -1817,14 +1826,12 @@ class Component {
1817
1826
  compileStyle() {
1818
1827
  const { id, commonStyle, globalStyle, views } = this;
1819
1828
  const styles = commonStyle ? [`[data-cid="${id}"]{${commonStyle}}`] : [];
1820
- if (globalStyle !== "") {
1829
+ if (globalStyle !== "")
1821
1830
  styles.push(globalStyle);
1822
- }
1823
1831
  for (const name in views) {
1824
1832
  const { style } = views[name];
1825
- if (style !== "") {
1833
+ if (style !== "")
1826
1834
  styles.push(`[data-cid="${id}"][data-vid="${name}"]{${style}}`);
1827
- }
1828
1835
  }
1829
1836
  return styles.join(`
1830
1837
  `);
@@ -1837,27 +1844,17 @@ function defaultOnStackEnter(stack) {
1837
1844
  // src/stack.js
1838
1845
  var STOP = Symbol("STOP");
1839
1846
  var NEXT = Symbol("NEXT");
1840
-
1841
- class Pair {
1842
- constructor(head, tail) {
1843
- this.head = head;
1844
- this.tail = tail;
1845
- }
1846
- push(v) {
1847
- return new Pair(v, this);
1848
- }
1849
- lookup(v, dv = null) {
1850
- const { tail } = this;
1851
- const r = this.head.lookup(v);
1852
- return r === STOP ? dv : r === NEXT ? tail !== null ? tail.lookup(v, dv) : dv : r;
1853
- }
1854
- *[Symbol.iterator]() {
1855
- let v = this;
1856
- while (v !== null) {
1857
- yield v.head;
1858
- v = v.tail;
1859
- }
1847
+ function lookup(chain, name, dv = null) {
1848
+ let n = chain;
1849
+ while (n !== null) {
1850
+ const r = n[0].lookup(name);
1851
+ if (r === STOP)
1852
+ return dv;
1853
+ if (r !== NEXT)
1854
+ return r;
1855
+ n = n[1];
1860
1856
  }
1857
+ return dv;
1861
1858
  }
1862
1859
 
1863
1860
  class BindFrame {
@@ -1881,56 +1878,64 @@ class ObjectFrame {
1881
1878
  return v === undefined ? NEXT : v;
1882
1879
  }
1883
1880
  }
1881
+ function computeViewsId(views) {
1882
+ let s = "";
1883
+ let n = views;
1884
+ while (n !== null) {
1885
+ s += n[0];
1886
+ n = n[1];
1887
+ }
1888
+ return s === "main" ? "" : s;
1889
+ }
1884
1890
 
1885
1891
  class Stack {
1886
- constructor(comps, it, binds, dynBinds, views, ctx = null) {
1892
+ constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
1887
1893
  this.comps = comps;
1888
1894
  this.it = it;
1889
1895
  this.binds = binds;
1890
1896
  this.dynBinds = dynBinds;
1891
1897
  this.views = views;
1898
+ this.viewsId = viewsId;
1892
1899
  this.ctx = ctx;
1893
- const viewsId = [...views].join("");
1894
- this.viewsId = viewsId === "main" ? "" : viewsId;
1895
1900
  }
1896
1901
  _enrichOnEnter() {
1897
1902
  return this.comps.getOnEnterFor(this.it).call(this.it, this) ?? this;
1898
1903
  }
1899
1904
  upToFrameBinds() {
1900
- const { comps, binds, dynBinds, views, ctx } = this;
1901
- return binds.head.isFrame ? this : new Stack(comps, binds.tail.head.it, binds.tail, dynBinds, views, ctx);
1905
+ const { comps, binds, dynBinds, views, viewsId, ctx } = this;
1906
+ return binds[0].isFrame ? this : new Stack(comps, binds[1][0].it, binds[1], dynBinds, views, viewsId, ctx);
1902
1907
  }
1903
1908
  static root(comps, it, ctx) {
1904
- const binds = new Pair(new BindFrame(it, { it }, true), null);
1905
- const dynBinds = new Pair(new ObjectFrame({}), null);
1906
- const views = new Pair("main", null);
1907
- return new Stack(comps, it, binds, dynBinds, views, ctx)._enrichOnEnter();
1909
+ const binds = [new BindFrame(it, { it }, true), null];
1910
+ const dynBinds = [new ObjectFrame({}), null];
1911
+ const views = ["main", null];
1912
+ return new Stack(comps, it, binds, dynBinds, views, "", ctx)._enrichOnEnter();
1908
1913
  }
1909
1914
  enter(it, bindings = {}, isFrame = true) {
1910
- const { comps, binds, dynBinds, views, ctx } = this;
1911
- const newBinds = binds.push(new BindFrame(it, bindings, isFrame));
1912
- return new Stack(comps, it, newBinds, dynBinds, views, ctx)._enrichOnEnter();
1915
+ const { comps, binds, dynBinds, views, viewsId, ctx } = this;
1916
+ const newBinds = [new BindFrame(it, bindings, isFrame), binds];
1917
+ return new Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx)._enrichOnEnter();
1913
1918
  }
1914
1919
  pushViewName(name) {
1915
1920
  const { comps, it, binds, dynBinds, views, ctx } = this;
1916
- return new Stack(comps, it, binds, dynBinds, views.push(name), ctx);
1921
+ const newViews = [name, views];
1922
+ return new Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
1917
1923
  }
1918
1924
  withDynamicBindings(dynamics) {
1919
1925
  const dynObj = {};
1920
1926
  const comp = this.comps.getCompFor(this.it);
1921
- for (const dynName of dynamics) {
1927
+ for (const dynName of dynamics)
1922
1928
  comp.dynamic[dynName].evalAndBind(this, dynObj);
1923
- }
1924
- const { comps, it, binds, views, ctx } = this;
1925
- const newDynBinds = this.dynBinds.push(new ObjectFrame(dynObj));
1926
- return new Stack(comps, it, binds, newDynBinds, views, ctx);
1929
+ const { comps, it, binds, views, viewsId, ctx } = this;
1930
+ const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
1931
+ return new Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
1927
1932
  }
1928
1933
  lookupDynamic(name) {
1929
1934
  const d = this.comps.getCompFor(this.it)?.dynamic[name];
1930
- return d ? this.dynBinds.lookup(d.getSymbol(this)) ?? d.val.eval(this) : null;
1935
+ return d ? lookup(this.dynBinds, d.getSymbol(this)) ?? d.val.eval(this) : null;
1931
1936
  }
1932
1937
  lookupBind(name) {
1933
- return this.binds.lookup(name);
1938
+ return lookup(this.binds, name);
1934
1939
  }
1935
1940
  lookupType(name) {
1936
1941
  return this.comps.getCompFor(this.it).scope.lookupComponent(name);
@@ -1946,7 +1951,7 @@ class Stack {
1946
1951
  return this.ctx.lookupName(name);
1947
1952
  }
1948
1953
  lookupComputed(name) {
1949
- const node = this.binds.head.isFrame ? this.binds.head : this.binds.tail.head;
1954
+ const node = this.binds[0].isFrame ? this.binds[0] : this.binds[1][0];
1950
1955
  return this.comps.lookupComputed(node.it, name);
1951
1956
  }
1952
1957
  getHandlerFor(name, key) {
@@ -1956,11 +1961,12 @@ class Stack {
1956
1961
  return this.comps.getRequestFor(this.it, name);
1957
1962
  }
1958
1963
  lookupBestView(views, defaultViewName) {
1959
- for (const viewName of this.views) {
1960
- const view = views[viewName];
1961
- if (view !== undefined) {
1964
+ let n = this.views;
1965
+ while (n !== null) {
1966
+ const view = views[n[0]];
1967
+ if (view !== undefined)
1962
1968
  return view;
1963
- }
1969
+ n = n[1];
1964
1970
  }
1965
1971
  return views[defaultViewName];
1966
1972
  }
@@ -1978,9 +1984,8 @@ class State {
1978
1984
  set(val, info) {
1979
1985
  const old = this.val;
1980
1986
  this.val = val;
1981
- for (const sub of this.changeSubs) {
1987
+ for (const sub of this.changeSubs)
1982
1988
  sub({ val, old, info, timestamp: Date.now() });
1983
- }
1984
1989
  }
1985
1990
  update(fn, info) {
1986
1991
  return this.set(fn(this.val), info);
@@ -2027,14 +2032,8 @@ class Transactor {
2027
2032
  return this.transactions.length > 0;
2028
2033
  }
2029
2034
  transactNext() {
2030
- if (this.hasPendingTransactions) {
2035
+ if (this.hasPendingTransactions)
2031
2036
  this.transact(this.transactions.shift());
2032
- }
2033
- }
2034
- transactAll() {
2035
- while (this.hasPendingTransactions) {
2036
- this.transact(this.transactions.shift());
2037
- }
2038
2037
  }
2039
2038
  transact(transaction) {
2040
2039
  const curState = this.state.val;
@@ -2042,9 +2041,8 @@ class Transactor {
2042
2041
  if (newState !== undefined) {
2043
2042
  this.state.set(newState, { transaction });
2044
2043
  transaction.afterTransaction();
2045
- } else {
2044
+ } else
2046
2045
  console.warn("undefined new state", { curState, transaction });
2047
- }
2048
2046
  }
2049
2047
  transactInputNow(path, event, eventHandler, dragInfo) {
2050
2048
  this.transact(new InputEvent(path, event, eventHandler, this, dragInfo));
@@ -2204,9 +2202,8 @@ class LogicEvent extends NameArgsTransaction {
2204
2202
  }
2205
2203
  afterTransaction() {
2206
2204
  const { path, name, args, opts } = this;
2207
- if (opts.bubbles && path.steps.length > 0) {
2205
+ if (opts.bubbles && path.steps.length > 0)
2208
2206
  this.transactor.pushBubble(path.popStep(), name, args, opts, this);
2209
- }
2210
2207
  }
2211
2208
  }
2212
2209
 
@@ -2246,7 +2243,7 @@ class Task {
2246
2243
  }
2247
2244
 
2248
2245
  class Dispatcher {
2249
- constructor(path, transactor, parentTransaction = null) {
2246
+ constructor(path, transactor, parentTransaction) {
2250
2247
  this.path = path;
2251
2248
  this.transactor = transactor;
2252
2249
  this.parent = parentTransaction;
@@ -2303,34 +2300,32 @@ var prototypesDiffer = (a, b) => Object.getPrototypeOf(a) !== Object.getPrototyp
2303
2300
  function applyProperties(node, props, previous) {
2304
2301
  for (const propName in props) {
2305
2302
  const propValue = props[propName];
2306
- if (propValue === undefined) {
2303
+ if (propValue === undefined)
2307
2304
  removeProperty(node, propName, previous);
2308
- } else if (isHtmlAttribute(propName)) {
2305
+ else if (isHtmlAttribute(propName))
2309
2306
  node.setAttribute(propName, propValue);
2310
- } else if (propName === "dangerouslySetInnerHTML") {
2307
+ else if (propName === "dangerouslySetInnerHTML")
2311
2308
  node.innerHTML = propValue.__html ?? "";
2312
- } else if (isObject(propValue)) {
2309
+ else if (isObject(propValue))
2313
2310
  patchObject(node, previous, propName, propValue);
2314
- } else if (propName === "className") {
2311
+ else if (propName === "className")
2315
2312
  node.setAttribute("class", propValue);
2316
- } else {
2313
+ else
2317
2314
  node[propName] = propValue;
2318
- }
2319
2315
  }
2320
2316
  }
2321
2317
  function removeProperty(node, propName, previous) {
2322
2318
  const previousValue = previous[propName];
2323
- if (propName === "dangerouslySetInnerHTML") {
2319
+ if (propName === "dangerouslySetInnerHTML")
2324
2320
  node.replaceChildren();
2325
- } else if (propName === "className") {
2321
+ else if (propName === "className")
2326
2322
  node.removeAttribute("class");
2327
- } else if (propName === "htmlFor") {
2323
+ else if (propName === "htmlFor")
2328
2324
  node.removeAttribute("for");
2329
- } else if (typeof previousValue === "string" || isHtmlAttribute(propName)) {
2325
+ else if (typeof previousValue === "string" || isHtmlAttribute(propName))
2330
2326
  node.removeAttribute(propName);
2331
- } else {
2327
+ else
2332
2328
  node[propName] = null;
2333
- }
2334
2329
  }
2335
2330
  function patchObject(node, previous, propName, propValue) {
2336
2331
  const previousValue = previous?.[propName];
@@ -2338,13 +2333,11 @@ function patchObject(node, previous, propName, propValue) {
2338
2333
  node[propName] = propValue;
2339
2334
  return;
2340
2335
  }
2341
- if (!isObject(node[propName])) {
2336
+ if (!isObject(node[propName]))
2342
2337
  node[propName] = {};
2343
- }
2344
2338
  const target = node[propName];
2345
- for (const k in propValue) {
2339
+ for (const k in propValue)
2346
2340
  target[k] = propValue[k];
2347
- }
2348
2341
  }
2349
2342
 
2350
2343
  class VBase {
@@ -2352,33 +2345,30 @@ class VBase {
2352
2345
  var getKey = (child) => child instanceof VNode ? child.key : undefined;
2353
2346
  var isIterable = (obj) => obj != null && typeof obj !== "string" && typeof obj[Symbol.iterator] === "function";
2354
2347
  function childsEqual(a, b) {
2355
- for (let i = 0;i < a.length; i++) {
2348
+ if (a === b)
2349
+ return true;
2350
+ for (let i = 0;i < a.length; i++)
2356
2351
  if (!a[i].isEqualTo(b[i]))
2357
2352
  return false;
2358
- }
2359
2353
  return true;
2360
2354
  }
2361
2355
  function appendChildNodes(parent, childs, opts) {
2362
- for (const child of childs) {
2356
+ for (const child of childs)
2363
2357
  parent.appendChild(child.toDom(opts));
2364
- }
2365
2358
  }
2366
2359
  function addChild(normalizedChildren, child) {
2367
2360
  if (child == null)
2368
2361
  return;
2369
2362
  if (isIterable(child)) {
2370
- for (const c of child) {
2363
+ for (const c of child)
2371
2364
  addChild(normalizedChildren, c);
2372
- }
2373
2365
  } else if (child instanceof VBase) {
2374
- if (child instanceof VFragment) {
2366
+ if (child instanceof VFragment)
2375
2367
  normalizedChildren.push(...child.childs);
2376
- } else {
2368
+ else
2377
2369
  normalizedChildren.push(child);
2378
- }
2379
- } else {
2370
+ } else
2380
2371
  normalizedChildren.push(new VText(child));
2381
- }
2382
2372
  }
2383
2373
 
2384
2374
  class VText extends VBase {
@@ -2423,9 +2413,8 @@ class VFragment extends VBase {
2423
2413
  return 11;
2424
2414
  }
2425
2415
  isEqualTo(other) {
2426
- if (!(other instanceof VFragment) || this.childs.length !== other.childs.length) {
2416
+ if (!(other instanceof VFragment) || this.childs.length !== other.childs.length)
2427
2417
  return false;
2428
- }
2429
2418
  return childsEqual(this.childs, other.childs);
2430
2419
  }
2431
2420
  toDom(opts) {
@@ -2448,18 +2437,18 @@ class VNode extends VBase {
2448
2437
  return 1;
2449
2438
  }
2450
2439
  isEqualTo(other) {
2440
+ if (this === other)
2441
+ return true;
2451
2442
  if (!(other instanceof VNode) || this.tag !== other.tag || this.key !== other.key || this.namespace !== other.namespace || this.childs.length !== other.childs.length) {
2452
2443
  return false;
2453
2444
  }
2454
- for (const key in this.attrs) {
2455
- if (this.attrs[key] !== other.attrs[key]) {
2456
- return false;
2457
- }
2458
- }
2459
- for (const key in other.attrs) {
2460
- if (!Object.hasOwn(this.attrs, key)) {
2461
- return false;
2462
- }
2445
+ if (this.attrs !== other.attrs) {
2446
+ for (const key in this.attrs)
2447
+ if (this.attrs[key] !== other.attrs[key])
2448
+ return false;
2449
+ for (const key in other.attrs)
2450
+ if (!Object.hasOwn(this.attrs, key))
2451
+ return false;
2463
2452
  }
2464
2453
  return childsEqual(this.childs, other.childs);
2465
2454
  }
@@ -2472,6 +2461,8 @@ class VNode extends VBase {
2472
2461
  }
2473
2462
  }
2474
2463
  function diffProps(a, b) {
2464
+ if (a === b)
2465
+ return null;
2475
2466
  let diff = null;
2476
2467
  for (const aKey in a) {
2477
2468
  if (!Object.hasOwn(b, aKey)) {
@@ -2543,6 +2534,24 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
2543
2534
  parentDom.replaceChildren();
2544
2535
  return;
2545
2536
  }
2537
+ if (oldChilds.length === newChilds.length) {
2538
+ let hasKey = false;
2539
+ for (let i = 0;i < oldChilds.length; i++) {
2540
+ if (getKey(oldChilds[i]) != null || getKey(newChilds[i]) != null) {
2541
+ hasKey = true;
2542
+ break;
2543
+ }
2544
+ }
2545
+ if (!hasKey) {
2546
+ let dom = parentDom.firstChild;
2547
+ for (let i = 0;i < oldChilds.length; i++) {
2548
+ const next = dom.nextSibling;
2549
+ morphNode(dom, oldChilds[i], newChilds[i], opts);
2550
+ dom = next;
2551
+ }
2552
+ return;
2553
+ }
2554
+ }
2546
2555
  const domNodes = Array.from(parentDom.childNodes);
2547
2556
  const oldKeyMap = Object.create(null);
2548
2557
  for (let i = 0;i < oldChilds.length; i++) {
@@ -2557,9 +2566,8 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
2557
2566
  const newKey = getKey(newChild);
2558
2567
  let oldIdx = -1;
2559
2568
  if (newKey != null) {
2560
- if (newKey in oldKeyMap && !used[oldKeyMap[newKey]]) {
2569
+ if (newKey in oldKeyMap && !used[oldKeyMap[newKey]])
2561
2570
  oldIdx = oldKeyMap[newKey];
2562
- }
2563
2571
  } else {
2564
2572
  while (unkeyedCursor < oldChilds.length) {
2565
2573
  if (!used[unkeyedCursor] && getKey(oldChilds[unkeyedCursor]) == null) {
@@ -2580,11 +2588,9 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
2580
2588
  parentDom.insertBefore(newChild.toDom(opts), ref);
2581
2589
  }
2582
2590
  }
2583
- for (let i = oldChilds.length - 1;i >= 0; i--) {
2584
- if (!used[i] && domNodes[i].parentNode === parentDom) {
2591
+ for (let i = oldChilds.length - 1;i >= 0; i--)
2592
+ if (!used[i] && domNodes[i].parentNode === parentDom)
2585
2593
  parentDom.removeChild(domNodes[i]);
2586
- }
2587
- }
2588
2594
  }
2589
2595
  var renderCache = new WeakMap;
2590
2596
  function render(vnode, container, options) {
@@ -2633,6 +2639,8 @@ function h(tagName, properties, children) {
2633
2639
  }
2634
2640
 
2635
2641
  // src/app.js
2642
+ var _evs = "dragstart dragover dragend touchstart touchmove touchend touchcancel".split(" ");
2643
+
2636
2644
  class App {
2637
2645
  constructor(rootNode, comps, renderer, ParseContext2) {
2638
2646
  this.rootNode = rootNode;
@@ -2643,12 +2651,12 @@ class App {
2643
2651
  this.renderer = renderer;
2644
2652
  this.maxEventNodeDepth = Infinity;
2645
2653
  this._transactNextBatchId = this._evictCacheId = null;
2646
- this._eventNames = new Set(["dragstart", "dragover", "dragend"]);
2654
+ this._eventNames = new Set(_evs);
2647
2655
  this.dragInfo = this.curDragOver = null;
2656
+ this._touch = null;
2648
2657
  this.transactor.onTransactionPushed = (_transaction) => {
2649
- if (this._transactNextBatchId === null) {
2658
+ if (this._transactNextBatchId === null)
2650
2659
  this._scheduleNextTransactionBatchExecution();
2651
- }
2652
2660
  };
2653
2661
  this._compiled = false;
2654
2662
  this._renderOpts = { document: rootNode.ownerDocument };
@@ -2657,36 +2665,95 @@ class App {
2657
2665
  return this.transactor.state;
2658
2666
  }
2659
2667
  handleEvent(e) {
2660
- const isDragStart = e.type === "dragstart";
2661
- const isDragOver = e.type === "dragover";
2662
- const isDragEnd = e.type === "dragend";
2668
+ const { type } = e;
2669
+ if (type[0] === "t" && type.startsWith("touch")) {
2670
+ this._handleTouchEvent(e);
2671
+ return;
2672
+ }
2673
+ this._dispatchEvent(e);
2674
+ }
2675
+ _dispatchEvent(e) {
2676
+ const { type } = e;
2677
+ const isDrag = type === "dragover" || type === "dragstart" || type === "dragend";
2663
2678
  const { rootNode: root, maxEventNodeDepth: maxDepth, comps } = this;
2664
- const stopOnNoEvent = !(isDragOver || isDragStart || isDragEnd);
2665
- const [path, handlers] = Path.fromEvent(e, root, maxDepth, comps, stopOnNoEvent);
2666
- if (isDragOver) {
2679
+ const [path, handlers] = Path.fromEvent(e, root, maxDepth, comps, !isDrag);
2680
+ if (isDrag)
2681
+ this._handleDragEvent(e, type, path);
2682
+ if (path !== null && handlers !== null) {
2683
+ for (const handler of handlers) {
2684
+ this.transactor.transactInputNow(path, e, handler, this.dragInfo);
2685
+ }
2686
+ }
2687
+ }
2688
+ _handleTouchEvent(e) {
2689
+ const { type } = e;
2690
+ if (type === "touchstart") {
2691
+ if (this._touch !== null || e.touches.length !== 1)
2692
+ return;
2693
+ const t = e.touches[0];
2694
+ const draggable = t.target?.closest?.('[draggable="true"]');
2695
+ if (!draggable)
2696
+ return;
2697
+ this._touch = makeTouchInfo(t.identifier, t.clientX, t.clientY, draggable, false);
2698
+ return;
2699
+ }
2700
+ if (this._touch === null)
2701
+ return;
2702
+ const touch = findTouch(e, this._touch.id);
2703
+ if (touch === null)
2704
+ return;
2705
+ const { rootNode, _touch } = this;
2706
+ const { clientX, clientY } = touch;
2707
+ const fire = (type2, target) => {
2708
+ const e2 = { type: type2, target, clientX, clientY, preventDefault: NOOP };
2709
+ this._dispatchEvent(e2);
2710
+ };
2711
+ if (type === "touchmove") {
2712
+ if (!_touch.active) {
2713
+ const dx = clientX - _touch.startX;
2714
+ const dy = clientY - _touch.startY;
2715
+ if (dx * dx + dy * dy < TOUCH_DRAG_THRESHOLD_SQ)
2716
+ return;
2717
+ _touch.active = true;
2718
+ e.preventDefault();
2719
+ fire("dragstart", _touch.target);
2720
+ } else {
2721
+ e.preventDefault();
2722
+ fire("dragover", hitTest(rootNode, clientX, clientY));
2723
+ }
2724
+ return;
2725
+ }
2726
+ if (type === "touchend" || type === "touchcancel") {
2727
+ if (_touch.active) {
2728
+ if (type === "touchend")
2729
+ fire("drop", hitTest(rootNode, clientX, clientY));
2730
+ fire("dragend", _touch.target);
2731
+ }
2732
+ this._touch = null;
2733
+ }
2734
+ }
2735
+ _handleDragEvent(e, type, path) {
2736
+ if (type === "dragover") {
2667
2737
  const dropTarget = getClosestDropTarget(e.target, this.rootNode, 50);
2668
2738
  if (dropTarget !== null) {
2669
2739
  e.preventDefault();
2670
2740
  this._cleanDragOverAttrs();
2671
2741
  this.curDragOver = dropTarget;
2672
- dropTarget.dataset.draggingover = this.dragInfo.type;
2742
+ dropTarget.dataset.draggingover = this.dragInfo?.type ?? "_external";
2673
2743
  }
2674
- } else if (isDragStart) {
2744
+ } else if (type === "dragstart") {
2675
2745
  e.target.dataset.dragging = 1;
2676
2746
  const rootValue = this.state.val;
2677
2747
  const value = path.lookup(rootValue);
2678
- const type = e.target.dataset.dragtype ?? "?";
2748
+ const dragType = e.target.dataset.dragtype ?? "?";
2679
2749
  const stack = path.buildStack(this.makeStack(rootValue));
2680
- this.dragInfo = new DragInfo(path, stack, e, value, type, e.target);
2681
- } else if (isDragEnd) {
2682
- delete this.dragInfo.node.dataset.dragging;
2683
- this.dragInfo = null;
2684
- this._cleanDragOverAttrs();
2685
- }
2686
- if (path !== null && handlers !== null) {
2687
- for (const handler of handlers) {
2688
- this.transactor.transactInputNow(path, e, handler, this.dragInfo);
2750
+ this.dragInfo = new DragInfo(path, stack, e, value, dragType, e.target);
2751
+ } else {
2752
+ if (this.dragInfo !== null) {
2753
+ delete this.dragInfo.node.dataset.dragging;
2754
+ this.dragInfo = null;
2689
2755
  }
2756
+ this._cleanDragOverAttrs();
2690
2757
  }
2691
2758
  }
2692
2759
  makeStack(rootValue) {
@@ -2709,25 +2776,20 @@ class App {
2709
2776
  compile() {
2710
2777
  for (const Comp of this.comps.byId.values()) {
2711
2778
  Comp.compile(this.ParseContext);
2712
- for (const key in Comp.views) {
2713
- for (const name of Comp.views[key].ctx.genEventNames()) {
2779
+ for (const key in Comp.views)
2780
+ for (const name of Comp.views[key].ctx.genEventNames())
2714
2781
  this._eventNames.add(name);
2715
- }
2716
- }
2717
2782
  }
2718
2783
  this._compiled = true;
2719
2784
  }
2720
2785
  start(opts) {
2721
- if (!this._compiled) {
2786
+ if (!this._compiled)
2722
2787
  this.compile();
2723
- }
2724
- for (const name of this._eventNames) {
2725
- this.rootNode.addEventListener(name, this);
2726
- }
2788
+ for (const name of this._eventNames)
2789
+ this.rootNode.addEventListener(name, this, listenerOpts(name));
2727
2790
  this.onChange((info) => {
2728
- if (info.val !== info.old) {
2791
+ if (info.val !== info.old)
2729
2792
  this.render();
2730
- }
2731
2793
  });
2732
2794
  injectCss("tutuca-app", this.comps.compileStyles(), opts?.head ?? document.head);
2733
2795
  if (opts?.noCache) {
@@ -2740,9 +2802,8 @@ class App {
2740
2802
  }
2741
2803
  stop() {
2742
2804
  this.stopCacheEvictionInterval();
2743
- for (const name of this._eventNames) {
2744
- this.rootNode.removeEventListener(name, this);
2745
- }
2805
+ for (const name of this._eventNames)
2806
+ this.rootNode.removeEventListener(name, this, listenerOpts(name));
2746
2807
  }
2747
2808
  dispatchLogicAtRoot(name, args, opts) {
2748
2809
  return this.transactor.pushLogic(new Path([]), name, args, opts);
@@ -2756,12 +2817,10 @@ class App {
2756
2817
  this._transactNextBatchId = null;
2757
2818
  const startTs = Date.now();
2758
2819
  const t = this.transactor;
2759
- while (t.hasPendingTransactions && Date.now() - startTs < maxRunTimeMs) {
2820
+ while (t.hasPendingTransactions && Date.now() - startTs < maxRunTimeMs)
2760
2821
  t.transactNext();
2761
- }
2762
- if (t.hasPendingTransactions) {
2822
+ if (t.hasPendingTransactions)
2763
2823
  this._scheduleNextTransactionBatchExecution();
2764
- }
2765
2824
  }
2766
2825
  _scheduleNextTransactionBatchExecution() {
2767
2826
  this._transactNextBatchId = setTimeout(() => this._transactNextBatch(), 0);
@@ -2777,19 +2836,44 @@ class App {
2777
2836
  function injectCss(nodeId, style, styleTarget = document.head) {
2778
2837
  const styleNode = document.createElement("style");
2779
2838
  const currentNodeWithId = styleTarget.querySelector(`#${nodeId}`);
2780
- if (currentNodeWithId) {
2839
+ if (currentNodeWithId)
2781
2840
  styleTarget.removeChild(currentNodeWithId);
2782
- }
2783
2841
  styleNode.id = nodeId;
2784
2842
  styleNode.innerHTML = style;
2785
2843
  styleTarget.appendChild(styleNode);
2786
2844
  }
2845
+ var TOUCH_DRAG_THRESHOLD_PX = 10;
2846
+ var TOUCH_DRAG_THRESHOLD_SQ = TOUCH_DRAG_THRESHOLD_PX * TOUCH_DRAG_THRESHOLD_PX;
2847
+ var NOOP = () => {};
2848
+ function findTouch(e, id) {
2849
+ for (const t of e.changedTouches)
2850
+ if (t.identifier === id)
2851
+ return t;
2852
+ for (const t of e.touches)
2853
+ if (t.identifier === id)
2854
+ return t;
2855
+ return null;
2856
+ }
2857
+ var listenerOpts = (name) => name === "touchmove" ? { passive: false } : undefined;
2858
+ function makeTouchInfo(id, startX, startY, target, active) {
2859
+ return { id, startX, startY, target, active };
2860
+ }
2861
+ function hitTest(rootNode, x, y) {
2862
+ const root = rootNode.getRootNode();
2863
+ let el = root.elementFromPoint?.(x, y) ?? null;
2864
+ while (el?.shadowRoot) {
2865
+ const next = el.shadowRoot.elementFromPoint(x, y);
2866
+ if (next === null || next === el)
2867
+ break;
2868
+ el = next;
2869
+ }
2870
+ return el ?? rootNode;
2871
+ }
2787
2872
  function getClosestDropTarget(target, rootNode, count) {
2788
2873
  let node = target;
2789
2874
  while (count-- > 0 && node !== rootNode) {
2790
- if (node.dataset?.droptarget !== undefined) {
2875
+ if (node.dataset?.droptarget !== undefined)
2791
2876
  return node;
2792
- }
2793
2877
  node = node.parentNode;
2794
2878
  }
2795
2879
  return null;
@@ -2809,63 +2893,6 @@ class DragInfo {
2809
2893
  }
2810
2894
  }
2811
2895
 
2812
- // src/util/parsectx.js
2813
- class ParseCtxClassSetCollector extends ParseContext {
2814
- constructor(...args) {
2815
- super(...args);
2816
- this.classes = new Set;
2817
- }
2818
- _addClasses(s) {
2819
- for (const v of s.split(/\s+/)) {
2820
- this.classes.add(v);
2821
- }
2822
- }
2823
- enterMacro(macroName, macroVars, macroSlots) {
2824
- const { DOMParser: DP, Text, Comment, nodes, events, macroNodes } = this;
2825
- const frame = { macroName, macroVars, macroSlots };
2826
- const v = new ParseCtxClassSetCollector(DP, Text, Comment, nodes, events, macroNodes, frame, this);
2827
- v.classes = this.classes;
2828
- return v;
2829
- }
2830
- onAttributes(attrs, _wrapperAttrs, _textChild) {
2831
- if (Array.isArray(attrs.items)) {
2832
- for (const attr of attrs.items) {
2833
- if (attr.name !== "class") {
2834
- continue;
2835
- }
2836
- const { val, thenVal, elseVal } = attr;
2837
- if (thenVal !== undefined) {
2838
- this._maybeAddVal(thenVal);
2839
- this._maybeAddVal(elseVal);
2840
- } else {
2841
- this._maybeAddVal(val);
2842
- }
2843
- }
2844
- } else {
2845
- const attr = attrs.items.class;
2846
- if (attr) {
2847
- this._addClasses(attr);
2848
- }
2849
- }
2850
- }
2851
- _maybeAddVal(value) {
2852
- if (!this._maybeAddStrTpl(value) && typeof value?.val === "string") {
2853
- this._addClasses(value.val);
2854
- }
2855
- }
2856
- _maybeAddStrTpl(value) {
2857
- if (value?.vals !== undefined) {
2858
- for (const val of value.vals) {
2859
- if (val instanceof ConstVal && val.val !== "") {
2860
- this._addClasses(val.val);
2861
- }
2862
- }
2863
- return true;
2864
- }
2865
- return false;
2866
- }
2867
- }
2868
-
2869
2896
  // deps/immutable.js
2870
2897
  function invariant(condition, error) {
2871
2898
  if (!condition)
@@ -7260,14 +7287,11 @@ class Field {
7260
7287
  return { type, defaultValue: dv?.toJS ? dv.toJS() : dv };
7261
7288
  }
7262
7289
  getFirstFailingCheck(v) {
7263
- if (!this.typeCheck.isValid(v)) {
7290
+ if (!this.typeCheck.isValid(v))
7264
7291
  return this.typeCheck;
7265
- }
7266
- for (const check of this.checks) {
7267
- if (!check.isValid(v)) {
7292
+ for (const check of this.checks)
7293
+ if (!check.isValid(v))
7268
7294
  return check;
7269
- }
7270
- }
7271
7295
  return null;
7272
7296
  }
7273
7297
  isValid(v) {
@@ -7278,9 +7302,8 @@ class Field {
7278
7302
  return this;
7279
7303
  }
7280
7304
  coerceOr(v, defaultValue = null) {
7281
- if (this.isValid(v)) {
7305
+ if (this.isValid(v))
7282
7306
  return v;
7283
- }
7284
7307
  const v1 = this.coercer(v);
7285
7308
  return this.isValid(v1) ? v1 : defaultValue;
7286
7309
  }
@@ -7438,9 +7461,8 @@ function extendProtoForKeyed(proto, name, uname) {
7438
7461
  proto[`updateIn${uname}At`] = function(i, fn) {
7439
7462
  const col = this.get(name);
7440
7463
  const v = col.get(i, NONE2);
7441
- if (v !== NONE2) {
7464
+ if (v !== NONE2)
7442
7465
  return this.set(name, col.set(i, fn(v)));
7443
- }
7444
7466
  console.warn("key", i, "not found in", name, col);
7445
7467
  return this;
7446
7468
  };
@@ -7540,19 +7562,17 @@ class ClassBuilder {
7540
7562
  const args = {};
7541
7563
  for (const key in inArgs) {
7542
7564
  const field = fields[key];
7543
- if (compFields.has(key)) {
7565
+ if (compFields.has(key))
7544
7566
  args[key] = mkCompField(field, opts.scope, inArgs[key]);
7545
- } else if (field === undefined) {
7567
+ else if (field === undefined) {
7546
7568
  console.warn("extra argument to constructor:", name, key, inArgs);
7547
7569
  continue;
7548
7570
  }
7549
7571
  args[key] = field.coerceOrDefault(inArgs[key]);
7550
7572
  }
7551
- for (const key of compFields) {
7552
- if (args[key] === undefined) {
7573
+ for (const key of compFields)
7574
+ if (args[key] === undefined)
7553
7575
  args[key] = mkCompField(fields[key], opts.scope, inArgs[key]);
7554
- }
7555
- }
7556
7576
  return this(args);
7557
7577
  }
7558
7578
  };
@@ -7579,9 +7599,8 @@ class ClassBuilder {
7579
7599
  return this._mergeProto(this._statics, proto, "static");
7580
7600
  }
7581
7601
  _mergeProto(target, proto, _name) {
7582
- for (const k in proto) {
7602
+ for (const k in proto)
7583
7603
  target[k] = proto[k];
7584
- }
7585
7604
  return this;
7586
7605
  }
7587
7606
  addField(name, dval, FieldCls) {
@@ -7613,48 +7632,48 @@ function classFromData(name, { fields = {}, methods, statics }) {
7613
7632
  for (const field in fields) {
7614
7633
  const value = fields[field];
7615
7634
  const type = typeof value;
7616
- if (type === "string") {
7635
+ if (type === "string")
7617
7636
  b.addField(field, value, FieldString);
7618
- } else if (type === "number") {
7637
+ else if (type === "number")
7619
7638
  b.addField(field, value, FieldFloat);
7620
- } else if (type === "boolean") {
7639
+ else if (type === "boolean")
7621
7640
  b.addField(field, value, FieldBool);
7622
- } else if (List.isList(value) || Array.isArray(value)) {
7641
+ else if (List.isList(value) || Array.isArray(value))
7623
7642
  b.addField(field, List(value), FieldList);
7624
- } else if (Set2.isSet(value) || value instanceof Set) {
7643
+ else if (Set2.isSet(value) || value instanceof Set)
7625
7644
  b.addField(field, Set2(value), FieldSet);
7626
- } else if (OrderedMap.isOrderedMap(value)) {
7645
+ else if (OrderedMap.isOrderedMap(value))
7627
7646
  b.addField(field, value, FieldOMap);
7628
- } else if (value?.type && value?.defaultValue !== undefined) {
7647
+ else if (value?.type && value?.defaultValue !== undefined) {
7629
7648
  const Field2 = fieldsByTypeName[value.type] ?? FieldAny;
7630
7649
  b.addField(field, new Field2().coerceOr(value.defaultValue), Field2);
7631
- } else if (value?.component && value?.args !== undefined) {
7650
+ } else if (value?.component && value?.args !== undefined)
7632
7651
  b.addCompField(field, value.component, value.args);
7633
- } else if (Map2.isMap(value) || value?.constructor === Object) {
7652
+ else if (Map2.isMap(value) || value?.constructor === Object)
7634
7653
  b.addField(field, Map2(value), FieldMap);
7635
- } else {
7654
+ else {
7636
7655
  const Field2 = fieldsByClass.get(value?.constructor) ?? FieldAny;
7637
7656
  b.addField(field, value, Field2);
7638
7657
  }
7639
7658
  }
7640
- if (methods) {
7659
+ if (methods)
7641
7660
  b.methods(methods);
7642
- }
7643
- if (statics) {
7661
+ if (statics)
7644
7662
  b.statics(statics);
7645
- }
7646
7663
  return b.build();
7647
7664
  }
7648
- var component = (opts) => new Component(opts.name ?? "Comp", classFromData(opts.name, opts), opts.view ?? "Not Defined", opts.views, opts.style, opts.commonStyle ?? "", opts.globalStyle ?? "", opts.computed, opts.input, opts.logic, opts.bubble, opts.response, opts.alter, opts.dynamic, opts.on);
7665
+ var component = (opts) => new Component(classFromData(opts.name, opts), opts);
7649
7666
 
7650
7667
  // src/renderer.js
7651
7668
  var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
7652
7669
 
7653
7670
  class Renderer {
7654
- constructor(comps, getSeqInfo, cache) {
7671
+ constructor(comps) {
7655
7672
  this.comps = comps;
7656
- this.getSeqInfo = getSeqInfo ?? basicGetSeqInfo;
7657
- this.cache = cache ?? new WeakMapDomCache;
7673
+ this.cache = new WeakMapDomCache;
7674
+ }
7675
+ getSeqInfo(seq) {
7676
+ return isIndexed(seq) ? imIndexedIter : isKeyed(seq) ? imKeyedIter : seqInfoByClass.get(seq?.constructor) ?? unkIter;
7658
7677
  }
7659
7678
  renderTag(tag, attrs, childs) {
7660
7679
  return h(tag, attrs, childs);
@@ -7670,18 +7689,17 @@ class Renderer {
7670
7689
  }
7671
7690
  renderToDOM(stack, val) {
7672
7691
  const rootNode = document.createElement("div");
7673
- render(h("div", null, [this.renderRoot(stack, val)]), rootNode, { document });
7692
+ const rOpts = { document };
7693
+ render(h("div", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
7674
7694
  return rootNode.childNodes[0];
7675
7695
  }
7676
7696
  renderToString(stack, val, cleanAttrs = true) {
7677
7697
  const dom = this.renderToDOM(stack, val);
7678
7698
  if (cleanAttrs) {
7679
7699
  const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
7680
- for (const { dataset } of nodes) {
7681
- for (const name of DATASET_ATTRS) {
7700
+ for (const { dataset } of nodes)
7701
+ for (const name of DATASET_ATTRS)
7682
7702
  delete dataset[name];
7683
- }
7684
- }
7685
7703
  }
7686
7704
  return dom.innerHTML;
7687
7705
  }
@@ -7697,9 +7715,8 @@ class Renderer {
7697
7715
  _rValComp(stack, val, comp, nid, key, viewName) {
7698
7716
  const cacheKey = `${viewName ?? stack.viewsId ?? ""}${nid}-${key}`;
7699
7717
  const cachedNode = this.cache.get(val, cacheKey);
7700
- if (cachedNode) {
7718
+ if (cachedNode)
7701
7719
  return cachedNode;
7702
- }
7703
7720
  const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
7704
7721
  const meta = this._renderMetadata({ $: "Comp", nid });
7705
7722
  const dom = new VFragment([meta, this.renderView(view, stack)]);
@@ -7711,60 +7728,58 @@ class Renderer {
7711
7728
  }
7712
7729
  renderEach(stack, iterInfo, nodeId, viewName) {
7713
7730
  const { seq, filter, loopWith } = iterInfo.eval(stack);
7714
- const [attrName, gen] = this.getSeqInfo(seq);
7715
7731
  const r = [];
7716
7732
  const iterData = loopWith.call(stack.it, seq);
7717
- for (const [key, value] of gen(seq)) {
7733
+ this.getSeqInfo(seq)(seq, (key, value, attrName) => {
7718
7734
  if (filter.call(stack.it, key, value, iterData)) {
7719
7735
  const newStack = stack.enter(value, { key }, true);
7720
7736
  const dom = this.renderIt(newStack, nodeId, key, viewName);
7721
7737
  this.pushEachEntry(r, nodeId, attrName, key, dom);
7722
7738
  }
7723
- }
7739
+ });
7724
7740
  return r;
7725
7741
  }
7726
7742
  renderEachWhen(stack, iterInfo, view, nid) {
7727
7743
  const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
7728
- const [attrName, gen] = this.getSeqInfo(seq);
7729
7744
  const r = [];
7730
7745
  const iterData = loopWith.call(stack.it, seq);
7731
- for (const [key, value] of gen(seq)) {
7732
- if (filter.call(stack.it, key, value, iterData)) {
7746
+ const it = stack.it;
7747
+ this.getSeqInfo(seq)(seq, (key, value, attrName) => {
7748
+ if (filter.call(it, key, value, iterData)) {
7733
7749
  const bindings = { key, value };
7734
7750
  const cacheKey = `${nid}-${key}`;
7735
7751
  let cachedNode;
7736
7752
  if (enricher) {
7737
- enricher.call(stack.it, bindings, key, value, iterData);
7738
- cachedNode = this.cache.get2(stack.it, value, cacheKey);
7739
- } else {
7753
+ enricher.call(it, bindings, key, value, iterData);
7754
+ cachedNode = this.cache.get2(it, value, cacheKey);
7755
+ } else
7740
7756
  cachedNode = this.cache.get(value, cacheKey);
7741
- }
7742
7757
  if (cachedNode) {
7743
7758
  this.pushEachEntry(r, nid, attrName, key, cachedNode);
7744
- continue;
7759
+ return;
7745
7760
  }
7746
7761
  const newStack = stack.enter(value, bindings, false);
7747
7762
  const dom = this.renderView(view, newStack);
7748
7763
  this.pushEachEntry(r, nid, attrName, key, dom);
7749
- if (enricher) {
7750
- this.cache.set2(stack.it, value, cacheKey, dom);
7751
- } else {
7764
+ if (enricher)
7765
+ this.cache.set2(it, value, cacheKey, dom);
7766
+ else
7752
7767
  this.cache.set(value, cacheKey, dom);
7753
- }
7754
7768
  }
7755
- }
7769
+ });
7756
7770
  return r;
7757
7771
  }
7758
7772
  renderView(view, stack) {
7759
- if (stack.binds.tail !== null) {
7760
- for (const binds of stack.binds.tail) {
7761
- if (!binds.isFrame)
7762
- continue;
7763
- if (stack.it !== binds.it)
7773
+ let n = stack.binds[1];
7774
+ while (n !== null) {
7775
+ const b = n[0];
7776
+ if (b.isFrame) {
7777
+ if (stack.it !== b.it)
7764
7778
  break;
7765
- console.error("recursion detected", stack.it, binds.it);
7779
+ console.error("recursion detected", stack.it, b.it);
7766
7780
  return new VComment("RECURSION AVOIDED");
7767
7781
  }
7782
+ n = n[1];
7768
7783
  }
7769
7784
  return view.render(stack, this);
7770
7785
  }
@@ -7772,22 +7787,17 @@ class Renderer {
7772
7787
  return new VComment(`§${JSON.stringify(info)}§`);
7773
7788
  }
7774
7789
  }
7775
- function* imIndexedEntries(seq) {
7790
+ var imIndexedIter = (seq, visit) => {
7776
7791
  let i = 0;
7777
7792
  for (const v of seq)
7778
- yield [i++, v];
7779
- }
7780
- function* imKeyedEntries(obj) {
7781
- for (const [key, value] of obj.toSeq().entries())
7782
- yield [key, value];
7783
- }
7793
+ visit(i++, v, "si");
7794
+ };
7795
+ var imKeyedIter = (seq, visit) => {
7796
+ for (const [k, v] of seq.toSeq().entries())
7797
+ visit(k, v, "sk");
7798
+ };
7799
+ var unkIter = () => {};
7784
7800
  var seqInfoByClass = new Map;
7785
- var idxInfo = ["si", imIndexedEntries];
7786
- var keyInfo = ["sk", imKeyedEntries];
7787
- var unkInfo = ["si", function* nullEntries(_obj) {}];
7788
- function basicGetSeqInfo(seq) {
7789
- return isIndexed(seq) ? idxInfo : isKeyed(seq) ? keyInfo : seqInfoByClass.get(seq?.constructor) ?? unkInfo;
7790
- }
7791
7801
 
7792
7802
  // extra/klist.js
7793
7803
  class KList {
@@ -7880,21 +7890,16 @@ class FieldKList extends Field {
7880
7890
  }
7881
7891
  }
7882
7892
  fieldsByClass.set(KList, FieldKList);
7883
- function* klistEntries(seq) {
7884
- for (const k of seq.order) {
7885
- yield [k, seq.items.get(k)];
7886
- }
7887
- }
7888
- seqInfoByClass.set(KList, ["data-sk", klistEntries]);
7893
+ seqInfoByClass.set(KList, (seq, visit) => {
7894
+ for (const k of seq.order)
7895
+ visit(k, seq.items.get(k), "data-sk");
7896
+ });
7889
7897
  // index.js
7890
7898
  var css = String.raw;
7891
7899
  var html = String.raw;
7892
- function macro(defaults, rawView) {
7893
- return new Macro(defaults, rawView);
7894
- }
7895
- var toNode = (nodeOrSelector) => typeof nodeOrSelector === "string" ? document.querySelector(nodeOrSelector) : nodeOrSelector;
7900
+ var macro = (defaults, rawView) => new Macro(defaults, rawView);
7896
7901
  function tutuca(nodeOrSelector) {
7897
- const rootNode = toNode(nodeOrSelector);
7902
+ const rootNode = typeof nodeOrSelector === "string" ? document.querySelector(nodeOrSelector) : nodeOrSelector;
7898
7903
  const comps = new Components;
7899
7904
  const renderer = new Renderer(comps);
7900
7905
  return new App(rootNode, comps, renderer, ParseContext);
@@ -7915,9 +7920,8 @@ async function compileClassesToStyleText(app, compileClasses, extraCSSClasses, C
7915
7920
  for (const Comp of app.comps.byId.values()) {
7916
7921
  for (const key in Comp.views) {
7917
7922
  const view = Comp.views[key];
7918
- for (const name of view.ctx.classes) {
7923
+ for (const name of view.ctx.classes)
7919
7924
  classes.add(name);
7920
- }
7921
7925
  }
7922
7926
  }
7923
7927
  return await compileClasses(Array.from(classes));
@@ -8143,6 +8147,7 @@ class LintParseContext extends ParseContext {
8143
8147
  this.attrs.push({ attrs, wrapperAttrs, textChild });
8144
8148
  }
8145
8149
  }
8150
+
8146
8151
  // dev.js
8147
8152
  class LintClassCollectorCtx extends ParseCtxClassSetCollector {
8148
8153
  constructor(...args) {