creo 0.2.5 → 0.2.7

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/index.js CHANGED
@@ -23,9 +23,6 @@ function hasScStructuralChange(prev, next) {
23
23
  return false;
24
24
  }
25
25
 
26
- // src/public/primitive.ts
27
- var $primitive = Symbol("primitive");
28
-
29
26
  // src/internal/orchestrator.ts
30
27
  class Orchestrator {
31
28
  #currentEngine;
@@ -39,6 +36,14 @@ class Orchestrator {
39
36
  var orchestrator = new Orchestrator;
40
37
 
41
38
  // src/public/view.ts
39
+ function applyRef(ref, value) {
40
+ if (!ref)
41
+ return;
42
+ if (typeof ref === "function")
43
+ ref(value);
44
+ else
45
+ ref.current = value;
46
+ }
42
47
  function view(body) {
43
48
  return (props, slot) => {
44
49
  orchestrator.currentEngine().view(body, props, slot, maybeGetUserKey(props));
@@ -50,6 +55,9 @@ function maybeGetUserKey(params) {
50
55
  }
51
56
  }
52
57
 
58
+ // src/public/primitive.ts
59
+ var $primitive = Symbol("primitive");
60
+
53
61
  // src/public/primitives/primitives.ts
54
62
  function html(tag) {
55
63
  const fn = ({
@@ -177,6 +185,7 @@ var area = html("area");
177
185
  class State {
178
186
  #current;
179
187
  #schedule;
188
+ #pending;
180
189
  constructor(initial, schedule) {
181
190
  this.#current = initial;
182
191
  this.#schedule = schedule;
@@ -185,30 +194,49 @@ class State {
185
194
  return this.#current;
186
195
  }
187
196
  set(value) {
197
+ this.#pending = null;
188
198
  this.#current = value;
189
199
  this.#schedule();
190
200
  }
191
201
  update(fn) {
192
- const result = fn(this.#current);
193
- if (result instanceof Promise) {
194
- result.then((value) => {
202
+ if (this.#pending) {
203
+ const next = this.#pending.then((v) => fn(v));
204
+ this.#pending = next;
205
+ next.then((value) => {
206
+ if (this.#pending !== next)
207
+ return;
208
+ this.#pending = null;
195
209
  this.#current = value;
196
210
  this.#schedule();
197
211
  });
198
- } else {
212
+ return;
213
+ }
214
+ const result = fn(this.#current);
215
+ if (!(result instanceof Promise)) {
199
216
  this.#current = result;
200
217
  this.#schedule();
218
+ return;
201
219
  }
220
+ const captured = result;
221
+ this.#pending = captured;
222
+ captured.then((value) => {
223
+ if (this.#pending !== captured)
224
+ return;
225
+ this.#pending = null;
226
+ this.#current = value;
227
+ this.#schedule();
228
+ });
202
229
  }
203
230
  }
204
231
 
205
232
  // src/public/store.ts
206
- var $store = Symbol("store");
233
+ var $store = Symbol.for("creo.store");
207
234
 
208
235
  class Store {
209
236
  [$store] = true;
210
237
  #current;
211
238
  #subscribers = new Set;
239
+ #pending;
212
240
  constructor(initial) {
213
241
  this.#current = initial;
214
242
  }
@@ -216,20 +244,38 @@ class Store {
216
244
  return this.#current;
217
245
  }
218
246
  set(value) {
247
+ this.#pending = null;
219
248
  this.#current = value;
220
249
  this.#notify();
221
250
  }
222
251
  update(fn) {
223
- const result = fn(this.#current);
224
- if (result instanceof Promise) {
225
- result.then((value) => {
252
+ if (this.#pending) {
253
+ const next = this.#pending.then((v) => fn(v));
254
+ this.#pending = next;
255
+ next.then((value) => {
256
+ if (this.#pending !== next)
257
+ return;
258
+ this.#pending = null;
226
259
  this.#current = value;
227
260
  this.#notify();
228
261
  });
229
- } else {
262
+ return;
263
+ }
264
+ const result = fn(this.#current);
265
+ if (!(result instanceof Promise)) {
230
266
  this.#current = result;
231
267
  this.#notify();
268
+ return;
232
269
  }
270
+ const captured = result;
271
+ this.#pending = captured;
272
+ captured.then((value) => {
273
+ if (this.#pending !== captured)
274
+ return;
275
+ this.#pending = null;
276
+ this.#current = value;
277
+ this.#notify();
278
+ });
233
279
  }
234
280
  subscribe(cb) {
235
281
  this.#subscribers.add(cb);
@@ -262,12 +308,15 @@ function shallowEqual(a2, b2) {
262
308
  let countA = 0;
263
309
  for (const key in a2) {
264
310
  countA++;
265
- if (!Object.is(a2[key], b2[key]))
311
+ if (a2[key] !== b2[key])
266
312
  return false;
267
313
  }
268
314
  let countB = 0;
269
- for (const _ in b2)
315
+ for (const _ in b2) {
270
316
  countB++;
317
+ if (countB > countA)
318
+ return false;
319
+ }
271
320
  return countA === countB;
272
321
  }
273
322
 
@@ -307,15 +356,10 @@ function lis(arr) {
307
356
  }
308
357
 
309
358
  // src/internal/engine.ts
310
- var STATEFUL_DOM_KEYS = ["value", "checked", "selected", "indeterminate", "muted"];
311
- function hasStatefulDomKey(props) {
312
- if (props == null || typeof props !== "object")
313
- return false;
314
- for (const k of STATEFUL_DOM_KEYS) {
315
- if (k in props)
316
- return true;
317
- }
318
- return false;
359
+ function getConsumerRef(view2) {
360
+ if (view2.flags & F_PRIMITIVE)
361
+ return;
362
+ return view2.props?.ref;
319
363
  }
320
364
 
321
365
  class Engine {
@@ -345,11 +389,18 @@ class Engine {
345
389
  keyToView: null,
346
390
  unsubscribe: null,
347
391
  parent,
348
- scHost: null
392
+ scHost: null,
393
+ pos: -1,
394
+ publicRef: null
349
395
  };
350
396
  if (slot2) {
351
- const slotFn = typeof slot2 === "string" ? this.#stringSlot(slot2) : slot2;
352
- res.sc = this.#collect(slotFn, [], res);
397
+ if (typeof slot2 === "string") {
398
+ res.sc = [
399
+ this.newView(textViewFn, res, slot2, null, null)
400
+ ];
401
+ } else {
402
+ res.sc = this.#collect(slot2, [], res);
403
+ }
353
404
  }
354
405
  return res;
355
406
  }
@@ -396,6 +447,10 @@ class Engine {
396
447
  child.parent = this.#collectFor ?? view2;
397
448
  this.#collector?.push(child);
398
449
  }
450
+ },
451
+ ref: (value) => {
452
+ view2.publicRef = value;
453
+ applyRef(getConsumerRef(view2), value);
399
454
  }
400
455
  });
401
456
  }
@@ -448,28 +503,34 @@ class Engine {
448
503
  this.#collectFor = beforeParent;
449
504
  return collector;
450
505
  }
451
- #stringSlot(content) {
452
- return () => {
453
- this.view(textViewFn, content, null, null);
454
- };
455
- }
456
506
  nextProps(view2, nextProps, nextSlot, preCollectedSc) {
507
+ const prevRef = getConsumerRef(view2);
508
+ const nextRef = nextProps?.ref;
509
+ if (prevRef !== nextRef) {
510
+ if (prevRef)
511
+ applyRef(prevRef, null);
512
+ if (nextRef && view2.publicRef != null)
513
+ applyRef(nextRef, view2.publicRef);
514
+ }
457
515
  const prevSc = view2.sc;
458
516
  view2.slot = nextSlot;
459
517
  if (preCollectedSc) {
460
518
  for (const child of preCollectedSc)
461
519
  child.parent = view2;
462
520
  view2.sc = preCollectedSc;
463
- } else {
464
- if (nextSlot) {
465
- const slotFn = typeof nextSlot === "string" ? this.#stringSlot(nextSlot) : nextSlot;
466
- view2.sc = this.#collect(slotFn, [], view2);
521
+ } else if (nextSlot) {
522
+ if (typeof nextSlot === "string") {
523
+ view2.sc = [
524
+ this.newView(textViewFn, view2, nextSlot, null, null)
525
+ ];
467
526
  } else {
468
- view2.sc = null;
527
+ view2.sc = this.#collect(nextSlot, [], view2);
469
528
  }
529
+ } else {
530
+ view2.sc = null;
470
531
  }
471
532
  const structChanged = hasScStructuralChange(prevSc, view2.sc);
472
- const shouldUpdate = view2.body?.shouldUpdate ? view2.body.shouldUpdate(nextProps) : !shallowEqual(view2.props, nextProps) || (view2.flags & F_PRIMITIVE) !== 0 && hasStatefulDomKey(nextProps);
533
+ const shouldUpdate = view2.body?.shouldUpdate ? view2.body.shouldUpdate(nextProps) : !shallowEqual(view2.props, nextProps) || (view2.flags & F_PRIMITIVE) !== 0 && this.renderer.shouldReassert?.(view2, nextProps) === true;
473
534
  if (shouldUpdate || structChanged) {
474
535
  view2.props = nextProps;
475
536
  this.markDirty(view2);
@@ -521,7 +582,9 @@ class Engine {
521
582
  }
522
583
  if (view2.children == null) {
523
584
  view2.children = pendingChildren;
524
- for (const child of pendingChildren) {
585
+ for (let i2 = 0;i2 < pendingChildren.length; i2++) {
586
+ const child = pendingChildren[i2];
587
+ child.pos = i2;
525
588
  this.initViewBody(child);
526
589
  this.markDirty(child);
527
590
  if (child.userKey != null) {
@@ -547,9 +610,11 @@ class Engine {
547
610
  const old = oldChildren[i2];
548
611
  const pend = pending[i2];
549
612
  this.#patchOrReplace(view2, oldChildren, i2, old, pend);
613
+ oldChildren[i2].pos = i2;
550
614
  }
551
615
  for (let i2 = oldLen;i2 < newLen; i2++) {
552
616
  oldChildren[i2] = pending[i2];
617
+ pending[i2].pos = i2;
553
618
  this.initViewBody(pending[i2]);
554
619
  this.markDirty(pending[i2]);
555
620
  }
@@ -589,21 +654,46 @@ class Engine {
589
654
  view2.keyToView.set(pending[j].userKey, pending[j]);
590
655
  }
591
656
  }
592
- view2.children = [
593
- ...oldChildren.slice(0, i2),
594
- ...pending.slice(i2, newEnd + 1),
595
- ...oldChildren.slice(i2, oldEnd + 1)
596
- ];
657
+ const tailStart2 = oldEnd + 1;
658
+ const tailLen2 = oldChildren.length - tailStart2;
659
+ const insertCount = newEnd - i2 + 1;
660
+ const out2 = new Array(i2 + insertCount + tailLen2);
661
+ for (let j = 0;j < i2; j++) {
662
+ const c = oldChildren[j];
663
+ c.pos = j;
664
+ out2[j] = c;
665
+ }
666
+ for (let j = 0;j < insertCount; j++) {
667
+ const c = pending[i2 + j];
668
+ c.pos = i2 + j;
669
+ out2[i2 + j] = c;
670
+ }
671
+ for (let j = 0;j < tailLen2; j++) {
672
+ const c = oldChildren[tailStart2 + j];
673
+ c.pos = i2 + insertCount + j;
674
+ out2[i2 + insertCount + j] = c;
675
+ }
676
+ view2.children = out2;
597
677
  return;
598
678
  }
599
679
  if (i2 > newEnd) {
600
680
  for (let j = i2;j <= oldEnd; j++) {
601
681
  this.dispose(oldChildren[j]);
602
682
  }
603
- view2.children = [
604
- ...oldChildren.slice(0, i2),
605
- ...oldChildren.slice(oldEnd + 1)
606
- ];
683
+ const tailStart2 = oldEnd + 1;
684
+ const tailLen2 = oldChildren.length - tailStart2;
685
+ const out2 = new Array(i2 + tailLen2);
686
+ for (let j = 0;j < i2; j++) {
687
+ const c = oldChildren[j];
688
+ c.pos = j;
689
+ out2[j] = c;
690
+ }
691
+ for (let j = 0;j < tailLen2; j++) {
692
+ const c = oldChildren[tailStart2 + j];
693
+ c.pos = i2 + j;
694
+ out2[i2 + j] = c;
695
+ }
696
+ view2.children = out2;
607
697
  return;
608
698
  }
609
699
  const newKeyToIndex = new Map;
@@ -630,7 +720,14 @@ class Engine {
630
720
  }
631
721
  }
632
722
  const stable = lis(newIdxToOldIdx);
633
- const newChildren = new Array(middleLen);
723
+ const tailStart = oldEnd + 1;
724
+ const tailLen = oldChildren.length - tailStart;
725
+ const out = new Array(i2 + middleLen + tailLen);
726
+ for (let j = 0;j < i2; j++) {
727
+ const c = oldChildren[j];
728
+ c.pos = j;
729
+ out[j] = c;
730
+ }
634
731
  for (let j = middleLen - 1;j >= 0; j--) {
635
732
  const newIdx = i2 + j;
636
733
  const pendView = pending[newIdx];
@@ -642,19 +739,25 @@ class Engine {
642
739
  view2.keyToView = new Map;
643
740
  view2.keyToView.set(pendView.userKey, pendView);
644
741
  }
645
- newChildren[j] = pendView;
742
+ pendView.pos = i2 + j;
743
+ out[i2 + j] = pendView;
646
744
  } else {
647
745
  const oldView = oldChildren[newIdxToOldIdx[j]];
648
746
  this.#patchOrReplace(view2, oldChildren, newIdxToOldIdx[j], oldView, pendView);
649
747
  if (!stable.has(j)) {
650
748
  this.markMoved(oldView);
651
749
  }
652
- newChildren[j] = oldView;
750
+ const placed = oldChildren[newIdxToOldIdx[j]];
751
+ placed.pos = i2 + j;
752
+ out[i2 + j] = placed;
653
753
  }
654
754
  }
655
- const head = oldChildren.slice(0, i2);
656
- const tail = oldChildren.slice(oldEnd + 1);
657
- view2.children = [...head, ...newChildren, ...tail];
755
+ for (let j = 0;j < tailLen; j++) {
756
+ const c = oldChildren[tailStart + j];
757
+ c.pos = i2 + middleLen + j;
758
+ out[i2 + middleLen + j] = c;
759
+ }
760
+ view2.children = out;
658
761
  }
659
762
  #patchOrReplace(parent, oldChildren, idx, oldView, pendView) {
660
763
  if (oldView.viewFn === pendView.viewFn) {
@@ -682,6 +785,8 @@ class Engine {
682
785
  }
683
786
  }
684
787
  }
788
+ view2.body?.dispose?.();
789
+ applyRef(getConsumerRef(view2), null);
685
790
  if (view2.unsubscribe)
686
791
  for (const unsub of view2.unsubscribe)
687
792
  unsub();
@@ -697,6 +802,8 @@ class Engine {
697
802
  for (const child of view2.children)
698
803
  this.#disposeVirtual(child);
699
804
  }
805
+ view2.body?.dispose?.();
806
+ applyRef(getConsumerRef(view2), null);
700
807
  if (view2.unsubscribe)
701
808
  for (const unsub of view2.unsubscribe)
702
809
  unsub();
@@ -763,45 +870,6 @@ function createApp(slot2, renderer, options) {
763
870
  };
764
871
  }
765
872
  // src/render/html_render.ts
766
- function isEventProp(key) {
767
- return key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && key.charCodeAt(2) >= 65 && key.charCodeAt(2) <= 90;
768
- }
769
- var DOM_EVENT = {
770
- Click: "click",
771
- Dblclick: "dblclick",
772
- PointerDown: "pointerdown",
773
- PointerUp: "pointerup",
774
- PointerMove: "pointermove",
775
- Input: "input",
776
- Change: "change",
777
- KeyDown: "keydown",
778
- KeyUp: "keyup",
779
- Focus: "focus",
780
- Blur: "blur",
781
- MouseEnter: "mouseenter",
782
- MouseLeave: "mouseleave",
783
- PointerEnter: "pointerenter",
784
- PointerLeave: "pointerleave",
785
- Scroll: "scroll",
786
- Load: "load",
787
- Error: "error",
788
- Toggle: "toggle",
789
- VolumeChange: "volumechange",
790
- Play: "play",
791
- Pause: "pause",
792
- Ended: "ended",
793
- TimeUpdate: "timeupdate",
794
- LoadedMetadata: "loadedmetadata",
795
- LoadedData: "loadeddata",
796
- CanPlay: "canplay",
797
- CanPlayThrough: "canplaythrough",
798
- DurationChange: "durationchange",
799
- RateChange: "ratechange",
800
- Seeking: "seeking",
801
- Seeked: "seeked",
802
- Stalled: "stalled",
803
- Waiting: "waiting"
804
- };
805
873
  var $EV = Symbol.for("creo.ev");
806
874
  var containerState = new WeakMap;
807
875
  function getState(container) {
@@ -818,7 +886,7 @@ function getState(container) {
818
886
  if (evObj) {
819
887
  const handler = evObj[domEvent];
820
888
  if (handler) {
821
- handler(mapEventData(domEvent, e));
889
+ handler(mapEventData(domEvent, e, dom));
822
890
  if (e.cancelBubble)
823
891
  return;
824
892
  }
@@ -836,8 +904,6 @@ function getState(container) {
836
904
  var CAPTURE_EVENTS = new Set([
837
905
  "focus",
838
906
  "blur",
839
- "mouseenter",
840
- "mouseleave",
841
907
  "pointerenter",
842
908
  "pointerleave",
843
909
  "scroll",
@@ -861,8 +927,6 @@ var CAPTURE_EVENTS = new Set([
861
927
  "waiting"
862
928
  ]);
863
929
  var NO_WALK_EVENTS = new Set([
864
- "mouseenter",
865
- "mouseleave",
866
930
  "pointerenter",
867
931
  "pointerleave"
868
932
  ]);
@@ -898,8 +962,7 @@ var POINTER_EVENTS = new Set([
898
962
  "pointerdown",
899
963
  "pointerup",
900
964
  "pointermove",
901
- "mouseenter",
902
- "mouseleave",
965
+ "pointercancel",
903
966
  "pointerenter",
904
967
  "pointerleave"
905
968
  ]);
@@ -920,11 +983,32 @@ var MEDIA_EVENTS = new Set([
920
983
  "stalled",
921
984
  "waiting"
922
985
  ]);
923
- function mapEventData(domEvent, e) {
986
+ function mapEventData(domEvent, e, currentTarget) {
924
987
  let data2;
925
988
  if (POINTER_EVENTS.has(domEvent)) {
926
989
  const pe = e;
927
- data2 = { x: pe.clientX, y: pe.clientY };
990
+ const pointerId = typeof pe.pointerId === "number" ? pe.pointerId : -1;
991
+ data2 = {
992
+ x: pe.clientX,
993
+ y: pe.clientY,
994
+ pointerId,
995
+ pointerType: typeof pe.pointerType === "string" ? pe.pointerType : "",
996
+ button: typeof pe.button === "number" ? pe.button : 0,
997
+ buttons: typeof pe.buttons === "number" ? pe.buttons : 0,
998
+ target: e.target,
999
+ currentTarget,
1000
+ capture: () => {
1001
+ if (pointerId >= 0 && currentTarget.setPointerCapture) {
1002
+ currentTarget.setPointerCapture(pointerId);
1003
+ }
1004
+ },
1005
+ release: () => {
1006
+ if (pointerId >= 0 && currentTarget.releasePointerCapture) {
1007
+ currentTarget.releasePointerCapture(pointerId);
1008
+ }
1009
+ },
1010
+ nativeEvent: e
1011
+ };
928
1012
  } else if (domEvent === "input" || domEvent === "change") {
929
1013
  const target = e.target;
930
1014
  data2 = { value: target.value, checked: !!target.checked };
@@ -992,6 +1076,7 @@ class HtmlRender {
992
1076
  const domRef = { element, prevProps: null };
993
1077
  view2.renderRef = domRef;
994
1078
  this.setAttributes(element, props);
1079
+ domRef.prevProps = props;
995
1080
  if (view2.children?.length === 1) {
996
1081
  const child = view2.children[0];
997
1082
  if (child.flags & F_PRIMITIVE && child.viewFn[$primitive] === "text") {
@@ -1001,6 +1086,12 @@ class HtmlRender {
1001
1086
  }
1002
1087
  }
1003
1088
  parentNode.insertBefore(element, refNode);
1089
+ if (props != null && props.autofocus === true && typeof element.focus === "function") {
1090
+ element.focus();
1091
+ }
1092
+ if (props != null) {
1093
+ applyRef(props.ref, element);
1094
+ }
1004
1095
  }
1005
1096
  } else {
1006
1097
  view2.renderRef = true;
@@ -1050,6 +1141,28 @@ class HtmlRender {
1050
1141
  }
1051
1142
  view2.renderRef = undefined;
1052
1143
  }
1144
+ shouldReassert(view2, nextProps) {
1145
+ if (nextProps == null || typeof nextProps !== "object")
1146
+ return false;
1147
+ const ref = view2.renderRef;
1148
+ if (!ref || ref.element instanceof Text)
1149
+ return false;
1150
+ const el = ref.element;
1151
+ const props = nextProps;
1152
+ for (const key of DOM_PROPERTIES) {
1153
+ if (!(key in props))
1154
+ continue;
1155
+ const live = el[key];
1156
+ const next = props[key];
1157
+ if (typeof next === "boolean" || typeof live === "boolean") {
1158
+ if (Boolean(live) !== Boolean(next))
1159
+ return true;
1160
+ } else if (String(live) !== String(next)) {
1161
+ return true;
1162
+ }
1163
+ }
1164
+ return false;
1165
+ }
1053
1166
  findParentDom(view2) {
1054
1167
  let parent = view2.parent;
1055
1168
  while (parent) {
@@ -1070,7 +1183,9 @@ class HtmlRender {
1070
1183
  if (children[children.length - 1] === view2) {
1071
1184
  return this.#parentEndAnchor(parent);
1072
1185
  }
1073
- const idx = children.indexOf(view2);
1186
+ let idx = view2.pos;
1187
+ if (idx < 0 || children[idx] !== view2)
1188
+ idx = children.indexOf(view2);
1074
1189
  for (let i2 = idx + 1;i2 < children.length; i2++) {
1075
1190
  const dom = this.getFirstDomNode(children[i2]);
1076
1191
  if (dom)
@@ -1084,59 +1199,88 @@ class HtmlRender {
1084
1199
  return this.findInsertionPoint(parent);
1085
1200
  }
1086
1201
  setAttributes(element, props) {
1202
+ if (props == null)
1203
+ return;
1087
1204
  for (const key in props) {
1088
1205
  const value = props[key];
1089
- if (key === "key" || value == null)
1090
- continue;
1091
- if (isEventProp(key)) {
1092
- this.bindEvent(element, key, value);
1206
+ if (key === "key" || key === "ref" || key === "on" || value == null)
1093
1207
  continue;
1094
- }
1095
1208
  this.setAttribute(element, key, value);
1096
1209
  }
1210
+ const on = props.on;
1211
+ if (on) {
1212
+ for (const ev in on) {
1213
+ const handler = on[ev];
1214
+ if (handler)
1215
+ this.bindEvent(element, ev, handler);
1216
+ }
1217
+ }
1097
1218
  }
1098
1219
  diffAttributes(element, prev, next) {
1099
- for (const key in prev) {
1100
- if (key === "key")
1101
- continue;
1102
- if (!(key in next) || next[key] == null) {
1103
- if (isEventProp(key)) {
1104
- this.unbindEvent(element, key);
1105
- } else {
1220
+ if (prev) {
1221
+ for (const key in prev) {
1222
+ if (key === "key" || key === "ref" || key === "on")
1223
+ continue;
1224
+ if (next == null || !(key in next) || next[key] == null) {
1106
1225
  this.removeAttribute(element, key);
1107
1226
  }
1108
1227
  }
1109
1228
  }
1110
- for (const key in next) {
1111
- const value = next[key];
1112
- if (key === "key" || value == null)
1113
- continue;
1114
- if (prev[key] === value && !DOM_PROPERTIES.has(key))
1115
- continue;
1116
- if (isEventProp(key)) {
1117
- const creoName = key.slice(2);
1118
- const domEvent = DOM_EVENT[creoName] ?? creoName.toLowerCase();
1229
+ if (next) {
1230
+ for (const key in next) {
1231
+ const value = next[key];
1232
+ if (key === "key" || key === "ref" || key === "on" || value == null)
1233
+ continue;
1234
+ if (prev && prev[key] === value && !DOM_PROPERTIES.has(key))
1235
+ continue;
1236
+ this.setAttribute(element, key, value);
1237
+ }
1238
+ }
1239
+ const prevOn = prev?.on;
1240
+ const nextOn = next?.on;
1241
+ if (prevOn !== nextOn) {
1242
+ this.diffEvents(element, prevOn, nextOn);
1243
+ }
1244
+ const prevRef = prev?.ref;
1245
+ const nextRef = next?.ref;
1246
+ if (prevRef !== nextRef) {
1247
+ applyRef(prevRef, null);
1248
+ applyRef(nextRef, element);
1249
+ }
1250
+ }
1251
+ diffEvents(element, prev, next) {
1252
+ if (prev) {
1253
+ for (const ev in prev) {
1254
+ if (!next || next[ev] == null) {
1255
+ this.unbindEvent(element, ev);
1256
+ }
1257
+ }
1258
+ }
1259
+ if (next) {
1260
+ for (const ev in next) {
1261
+ const value = next[ev];
1262
+ if (value == null)
1263
+ continue;
1264
+ if (prev && prev[ev] === value)
1265
+ continue;
1266
+ const domEvent = ev.toLowerCase();
1119
1267
  const evObj = element[$EV];
1120
- if (evObj) {
1268
+ if (evObj && domEvent in evObj) {
1121
1269
  evObj[domEvent] = value;
1122
1270
  } else {
1123
- this.bindEvent(element, key, value);
1271
+ this.bindEvent(element, ev, value);
1124
1272
  }
1125
- } else {
1126
- this.setAttribute(element, key, value);
1127
1273
  }
1128
1274
  }
1129
1275
  }
1130
- bindEvent(element, prop, handler) {
1131
- const creoName = prop.slice(2);
1132
- const domEvent = DOM_EVENT[creoName] ?? creoName.toLowerCase();
1276
+ bindEvent(element, eventName, handler) {
1277
+ const domEvent = eventName.toLowerCase();
1133
1278
  const evObj = element[$EV] ?? (element[$EV] = {});
1134
1279
  evObj[domEvent] = handler;
1135
1280
  ensureDelegated(this.container, domEvent);
1136
1281
  }
1137
- unbindEvent(element, prop) {
1138
- const creoName = prop.slice(2);
1139
- const domEvent = DOM_EVENT[creoName] ?? creoName.toLowerCase();
1282
+ unbindEvent(element, eventName) {
1283
+ const domEvent = eventName.toLowerCase();
1140
1284
  const evObj = element[$EV];
1141
1285
  if (evObj) {
1142
1286
  delete evObj[domEvent];
@@ -1210,6 +1354,9 @@ class HtmlRender {
1210
1354
  }
1211
1355
  delete ref.element[$EV];
1212
1356
  }
1357
+ const prevProps = ref.prevProps;
1358
+ if (prevProps)
1359
+ applyRef(prevProps.ref, null);
1213
1360
  ref.element.parentNode?.removeChild(ref.element);
1214
1361
  }
1215
1362
  }
@@ -1230,7 +1377,7 @@ class JsonRender {
1230
1377
  }
1231
1378
  const parentNode = view2.parent.renderRef;
1232
1379
  if (parentNode) {
1233
- const idx = view2.parent.children ? view2.parent.children.indexOf(view2) : -1;
1380
+ const idx = view2.pos;
1234
1381
  if (idx >= 0 && idx < parentNode.children.length) {
1235
1382
  parentNode.children.splice(idx, 0, node);
1236
1383
  } else {
@@ -1242,11 +1389,13 @@ class JsonRender {
1242
1389
  if (view2.parent) {
1243
1390
  const parentNode = view2.parent.renderRef;
1244
1391
  if (parentNode) {
1245
- const oldIdx = parentNode.children.indexOf(existing);
1246
- const targetIdx = view2.parent.children ? view2.parent.children.indexOf(view2) : -1;
1247
- if (oldIdx !== -1 && targetIdx !== -1 && oldIdx !== targetIdx) {
1248
- parentNode.children.splice(oldIdx, 1);
1249
- parentNode.children.splice(Math.min(targetIdx, parentNode.children.length), 0, existing);
1392
+ const targetIdx = view2.pos;
1393
+ if (targetIdx >= 0 && parentNode.children[targetIdx] !== existing) {
1394
+ const oldIdx = parentNode.children.indexOf(existing);
1395
+ if (oldIdx !== -1) {
1396
+ parentNode.children.splice(oldIdx, 1);
1397
+ parentNode.children.splice(Math.min(targetIdx, parentNode.children.length), 0, existing);
1398
+ }
1250
1399
  }
1251
1400
  }
1252
1401
  }
@@ -1292,9 +1441,6 @@ var VOID_TAGS = new Set([
1292
1441
  "wbr"
1293
1442
  ]);
1294
1443
  var DOM_PROPERTIES2 = new Set(["value", "checked", "selected", "indeterminate", "muted"]);
1295
- function isEventProp2(key) {
1296
- return key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && key.charCodeAt(2) >= 65 && key.charCodeAt(2) <= 90;
1297
- }
1298
1444
  function escapeHtml(str) {
1299
1445
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1300
1446
  }
@@ -1331,12 +1477,14 @@ class HtmlStringRender {
1331
1477
  return this.buildChildren(rec);
1332
1478
  }
1333
1479
  buildAttrs(props) {
1480
+ if (props == null)
1481
+ return "";
1334
1482
  let result = "";
1335
1483
  for (const key in props) {
1336
1484
  const value = props[key];
1337
1485
  if (key === "key" || value == null)
1338
1486
  continue;
1339
- if (isEventProp2(key))
1487
+ if (key === "on" || key === "ref")
1340
1488
  continue;
1341
1489
  if (DOM_PROPERTIES2.has(key))
1342
1490
  continue;
@@ -1368,7 +1516,6 @@ class HtmlStringRender {
1368
1516
  return result;
1369
1517
  }
1370
1518
  }
1371
- var StringRender = HtmlStringRender;
1372
1519
  // src/functional/maybe.ts
1373
1520
  function just(maybe, errorMessage) {
1374
1521
  if (maybe == null) {
@@ -1500,11 +1647,11 @@ export {
1500
1647
  aside,
1501
1648
  article,
1502
1649
  area,
1650
+ applyRef,
1503
1651
  address,
1504
1652
  abbr,
1505
1653
  a,
1506
1654
  _,
1507
- StringRender,
1508
1655
  Store,
1509
1656
  State,
1510
1657
  JsonRender,
@@ -1514,4 +1661,4 @@ export {
1514
1661
  $primitive
1515
1662
  };
1516
1663
 
1517
- //# debugId=AEF6273D02CC4DF064756E2164756E21
1664
+ //# debugId=020C6F0F4AB24D1164756E2164756E21