@zeus-js/runtime-dom 0.1.1-beta.1 → 0.1.1-beta.11

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * runtime-dom v0.1.1-beta.1
2
+ * runtime-dom v0.1.1-beta.11
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -420,22 +420,14 @@ function stringifyText(value) {
420
420
  function setAttr(el, name, value) {
421
421
  const attrName = normalizeAttrName(name);
422
422
  const propName = getBooleanDomPropertyName(name);
423
- if (propName && el instanceof HTMLElement) {
424
- el[propName] = Boolean(value);
425
- if (value == null || value === false) el.removeAttribute(attrName);
426
- else if (value === true) el.setAttribute(attrName, "");
427
- else el.setAttribute(attrName, String(value));
428
- return;
429
- }
430
- if (value == null || value === false) {
431
- el.removeAttribute(attrName);
432
- return;
423
+ const serialized = value == null || value === false ? null : value === true ? "" : String(value);
424
+ if (serialized === null ? !el.hasAttribute(attrName) : el.getAttribute(attrName) === serialized) {
425
+ if (!propName || !(el instanceof HTMLElement)) return;
426
+ if (Boolean(value) === Boolean(el[propName])) return;
433
427
  }
434
- if (value === true) {
435
- el.setAttribute(attrName, "");
436
- return;
437
- }
438
- el.setAttribute(attrName, String(value));
428
+ if (propName && el instanceof HTMLElement) el[propName] = Boolean(value);
429
+ if (serialized === null) el.removeAttribute(attrName);
430
+ else el.setAttribute(attrName, serialized);
439
431
  }
440
432
  function getBooleanDomPropertyName(name) {
441
433
  return BOOLEAN_DOM_PROPERTY_NAME[name];
@@ -459,9 +451,7 @@ function normalizeAttrName(name) {
459
451
  return name === "className" ? "class" : name;
460
452
  }
461
453
  function bindAttr(el, name, value, once = false) {
462
- applyBinding(value, once, (next) => {
463
- setAttr(el, name, next);
464
- });
454
+ applyBinding(value, once, (next) => setAttr(el, name, next));
465
455
  }
466
456
  function bindProp(el, name, value, once = false) {
467
457
  applyBinding(value, once, (next) => {
@@ -495,42 +485,45 @@ function bindStyle(el, value, once = false) {
495
485
  prev = void 0;
496
486
  return;
497
487
  }
498
- patchStyle(el, prev, next);
499
- prev = next;
488
+ prev = patchStyle(el, prev, next);
500
489
  });
501
490
  }
502
491
  function patchStyle(el, prev, next) {
503
492
  const style = el.style;
504
- if (prev) {
505
- for (const key in prev) if (!(key in next)) style.setProperty(toKebabCase$2(key), "");
493
+ const values = prev ? prev[0] : Object.create(null);
494
+ const keys = Object.keys(next);
495
+ const state = style.cssText + keys.join(",");
496
+ const styleChanged = prev && state != prev[1];
497
+ let wrote = false;
498
+ for (const key in values) if (!(key in next)) {
499
+ style.setProperty(key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`), "");
500
+ wrote = true;
501
+ delete values[key];
506
502
  }
507
503
  for (const key in next) {
508
504
  const value = next[key];
509
- const name = toKebabCase$2(key);
510
- if (value == null) style.setProperty(name, "");
511
- else style.setProperty(name, normalizeStyleValue(key, value));
505
+ const expected = value == null ? "" : normalizeStyleValue(key, value);
506
+ if (values[key] === expected && !styleChanged) continue;
507
+ style.setProperty(key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`), expected);
508
+ wrote = true;
509
+ values[key] = expected;
512
510
  }
511
+ return prev && !wrote ? prev : [values, style.cssText + keys.join(",")];
513
512
  }
514
513
  function normalizeStyleValue(key, value) {
515
- if (typeof value === "number" && value !== 0 && !isUnitlessNumber(key)) return `${value}px`;
514
+ if (typeof value === "number" && value !== 0 && unitlessNumbers[key] !== true) return `${value}px`;
516
515
  return String(value);
517
516
  }
518
- const unitlessNumbers = /* @__PURE__ */ new Set([
519
- "opacity",
520
- "zIndex",
521
- "fontWeight",
522
- "lineHeight",
523
- "flex",
524
- "flexGrow",
525
- "flexShrink",
526
- "order"
527
- ]);
528
- function isUnitlessNumber(key) {
529
- return unitlessNumbers.has(key);
530
- }
531
- function toKebabCase$2(value) {
532
- return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
533
- }
517
+ const unitlessNumbers = {
518
+ opacity: true,
519
+ zIndex: true,
520
+ fontWeight: true,
521
+ lineHeight: true,
522
+ flex: true,
523
+ flexGrow: true,
524
+ flexShrink: true,
525
+ order: true
526
+ };
534
527
  //#endregion
535
528
  //#region packages/core/runtime-dom/src/events.ts
536
529
  const delegatedEvents = /* @__PURE__ */ new Set();
@@ -733,7 +726,9 @@ function mountIndexFor(parent, marker, each, render) {
733
726
  function mountKeyedFor(parent, marker, each, key, render) {
734
727
  let records = [];
735
728
  const subtreeContext = captureScopedSubtreeContext();
736
- let latestEntries = [];
729
+ let latestItems = [];
730
+ const latestKeys = [];
731
+ let latestItemsUseFixedSlots = false;
737
732
  let reconcileRequested = false;
738
733
  let reconciling = false;
739
734
  let disposed = false;
@@ -747,7 +742,7 @@ function mountKeyedFor(parent, marker, each, key, render) {
747
742
  for (const record of currentRecords) disposeListRecord(record);
748
743
  };
749
744
  (0, _zeus_js_signal_internal.onScopeDispose)(dispose, true);
750
- const reconcile = (nextEntries) => {
745
+ const reconcileEntries = (nextEntries) => {
751
746
  if (disposed) return;
752
747
  const oldMap = /* @__PURE__ */ new Map();
753
748
  for (const record of records) oldMap.set(record.key, record);
@@ -760,7 +755,10 @@ function mountKeyedFor(parent, marker, each, key, render) {
760
755
  const oldRecord = oldMap.get(itemKey);
761
756
  if (oldRecord) {
762
757
  oldMap.delete(itemKey);
763
- oldRecord.setItem(() => item);
758
+ if (!Object.is(oldRecord.item, item)) {
759
+ oldRecord.item = item;
760
+ oldRecord.setItem(() => item);
761
+ }
764
762
  oldRecord.setIndex(i);
765
763
  nextRecords.push(oldRecord);
766
764
  } else {
@@ -768,6 +766,7 @@ function mountKeyedFor(parent, marker, each, key, render) {
768
766
  const [readIndex, setIndex] = (0, _zeus_js_signal_internal.createSignal)(i);
769
767
  const subtree = new ScopedSubtree(parent, marker, subtreeContext);
770
768
  const record = {
769
+ item,
771
770
  key: itemKey,
772
771
  setItem,
773
772
  setIndex,
@@ -824,13 +823,48 @@ function mountKeyedFor(parent, marker, each, key, render) {
824
823
  throw error;
825
824
  }
826
825
  };
826
+ const reconcileLatestItems = () => {
827
+ if (disposed) return;
828
+ if (latestItemsUseFixedSlots) {
829
+ const items = latestItems;
830
+ (0, _zeus_js_signal_internal.batch)(() => {
831
+ for (let i = 0; i < items.length; i++) {
832
+ const item = items[i];
833
+ const record = records[i];
834
+ if (!Object.is(record.item, item)) {
835
+ record.item = item;
836
+ record.setItem(() => item);
837
+ }
838
+ }
839
+ });
840
+ if (!disposed) emitDevtoolsEvent({
841
+ type: "mount-for",
842
+ length: records.length
843
+ });
844
+ return;
845
+ }
846
+ const items = latestItems;
847
+ const nextEntries = [];
848
+ const nextKeys = /* @__PURE__ */ new Set();
849
+ for (let i = 0; i < items.length; i++) {
850
+ const item = items[i];
851
+ const itemKey = latestKeys[i];
852
+ if (nextKeys.has(itemKey)) throw duplicateKeyError(itemKey, i);
853
+ nextKeys.add(itemKey);
854
+ nextEntries.push({
855
+ item,
856
+ key: itemKey
857
+ });
858
+ }
859
+ reconcileEntries(nextEntries);
860
+ };
827
861
  const drainReconciliations = () => {
828
862
  if (reconciling) return;
829
863
  reconciling = true;
830
864
  try {
831
865
  while (reconcileRequested) {
832
866
  reconcileRequested = false;
833
- (0, _zeus_js_signal_internal.untrack)(() => reconcile(latestEntries));
867
+ (0, _zeus_js_signal_internal.untrack)(reconcileLatestItems);
834
868
  }
835
869
  } finally {
836
870
  reconciling = false;
@@ -847,19 +881,16 @@ function mountKeyedFor(parent, marker, each, key, render) {
847
881
  runner = (0, _zeus_js_signal_internal.effect)(() => {
848
882
  var _each2;
849
883
  const nextItems = (_each2 = each()) !== null && _each2 !== void 0 ? _each2 : [];
850
- const nextEntries = [];
851
- const nextKeys = /* @__PURE__ */ new Set();
884
+ let useFixedSlots = nextItems.length === records.length;
852
885
  for (let i = 0; i < nextItems.length; i++) {
853
886
  const item = nextItems[i];
854
887
  const itemKey = key(item, i);
855
- if (nextKeys.has(itemKey)) throw duplicateKeyError(itemKey, i);
856
- nextKeys.add(itemKey);
857
- nextEntries.push({
858
- item,
859
- key: itemKey
860
- });
888
+ latestKeys[i] = itemKey;
889
+ if (useFixedSlots && !Object.is(itemKey, records[i].key)) useFixedSlots = false;
861
890
  }
862
- latestEntries = nextEntries;
891
+ latestKeys.length = nextItems.length;
892
+ latestItems = nextItems;
893
+ latestItemsUseFixedSlots = useFixedSlots;
863
894
  }, { scheduler: scheduleReconciliation });
864
895
  } catch (error) {
865
896
  dispose();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zeus-js/runtime-dom",
3
3
  "type": "module",
4
- "version": "0.1.1-beta.1",
4
+ "version": "0.1.1-beta.11",
5
5
  "description": "@zeus-js/runtime-dom",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -31,7 +31,7 @@
31
31
  "dist"
32
32
  ],
33
33
  "dependencies": {
34
- "@zeus-js/signal": "0.1.1-beta.1"
34
+ "@zeus-js/signal": "0.1.1-beta.11"
35
35
  },
36
36
  "author": "Baicie",
37
37
  "bugs": {