@constela/runtime 0.15.1 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +84 -36
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -240,18 +240,18 @@ function createStateStore(definitions) {
240
240
  initialValue = cookieValue !== void 0 ? cookieValue : def.initial.default;
241
241
  } else {
242
242
  initialValue = def.initial;
243
- }
244
- if (name === "theme" && typeof window !== "undefined") {
245
- try {
246
- const stored = localStorage.getItem("theme");
247
- if (stored !== null) {
248
- try {
249
- initialValue = JSON.parse(stored);
250
- } catch {
251
- initialValue = stored;
243
+ if (name === "theme" && typeof window !== "undefined") {
244
+ try {
245
+ const stored = localStorage.getItem("theme");
246
+ if (stored !== null) {
247
+ try {
248
+ initialValue = JSON.parse(stored);
249
+ } catch {
250
+ initialValue = stored;
251
+ }
252
252
  }
253
+ } catch {
253
254
  }
254
- } catch {
255
255
  }
256
256
  }
257
257
  signals.set(name, createSignal(initialValue));
@@ -14393,6 +14393,21 @@ function hydrateElement(node, el, ctx) {
14393
14393
  hydrateChildren(node.children, el, ctx);
14394
14394
  }
14395
14395
  }
14396
+ function findSsrIfBranchMarker(parent, beforeNode) {
14397
+ let current = beforeNode ? beforeNode.previousSibling : parent.lastChild;
14398
+ while (current) {
14399
+ if (current.nodeType === Node.COMMENT_NODE) {
14400
+ const comment2 = current;
14401
+ const text3 = comment2.textContent;
14402
+ if (text3 === "if:then") return { branch: "then", marker: comment2 };
14403
+ if (text3 === "if:else") return { branch: "else", marker: comment2 };
14404
+ if (text3 === "if:none") return { branch: "none", marker: comment2 };
14405
+ }
14406
+ if (current.nodeType === Node.ELEMENT_NODE) break;
14407
+ current = current.previousSibling;
14408
+ }
14409
+ return null;
14410
+ }
14396
14411
  function hydrateChildren(children, parent, ctx) {
14397
14412
  const domChildren = [];
14398
14413
  for (let i = 0; i < parent.childNodes.length; i++) {
@@ -14423,19 +14438,35 @@ function hydrateChildren(children, parent, ctx) {
14423
14438
  }
14424
14439
  } else if (childNode.kind === "if") {
14425
14440
  const ifNode = childNode;
14426
- const initialCondition = evaluate(ifNode.condition, {
14441
+ const clientCondition = evaluate(ifNode.condition, {
14427
14442
  state: ctx.state,
14428
14443
  locals: ctx.locals,
14429
14444
  ...ctx.imports && { imports: ctx.imports },
14430
14445
  ...ctx.route && { route: ctx.route }
14431
14446
  });
14432
- const hasDomForIf = Boolean(initialCondition) || Boolean(ifNode.else);
14447
+ const clientBranch = Boolean(clientCondition) ? "then" : ifNode.else ? "else" : "none";
14433
14448
  const domChild = domChildren[domIndex];
14434
- if (hasDomForIf && domChild) {
14435
- hydrate(childNode, domChild, ctx);
14449
+ const ssrInfo = findSsrIfBranchMarker(parent, domChild || null);
14450
+ const ssrBranch = ssrInfo?.branch ?? null;
14451
+ const ssrHasDom = ssrBranch === "then" || ssrBranch === "else";
14452
+ if (ssrInfo?.marker) {
14453
+ ssrInfo.marker.remove();
14454
+ }
14455
+ if (ssrHasDom && domChild) {
14456
+ hydrateIf(ifNode, domChild, ctx, { ssrBranch, clientBranch });
14436
14457
  domIndex++;
14458
+ } else if (ssrBranch === "none") {
14459
+ hydrateIfWithoutDom(ifNode, parent, domChildren[domIndex] || null, ctx, {
14460
+ clientBranch
14461
+ });
14437
14462
  } else {
14438
- hydrateIfWithoutDom(ifNode, parent, domChildren[domIndex] || null, ctx);
14463
+ const hasDomForIf = Boolean(clientCondition) || Boolean(ifNode.else);
14464
+ if (hasDomForIf && domChild) {
14465
+ hydrate(childNode, domChild, ctx);
14466
+ domIndex++;
14467
+ } else {
14468
+ hydrateIfWithoutDom(ifNode, parent, domChildren[domIndex] || null, ctx);
14469
+ }
14439
14470
  }
14440
14471
  } else if (childNode.kind === "each") {
14441
14472
  const items = evaluate(childNode.items, {
@@ -14525,32 +14556,37 @@ function formatValue2(value) {
14525
14556
  }
14526
14557
  return String(value);
14527
14558
  }
14528
- function hydrateIf(node, initialDomNode, ctx) {
14559
+ function hydrateIf(node, initialDomNode, ctx, branchInfo) {
14529
14560
  const anchor = document.createComment("if");
14530
14561
  const parent = initialDomNode.parentNode;
14531
14562
  if (!parent) return;
14532
14563
  parent.insertBefore(anchor, initialDomNode);
14533
14564
  let currentNode = initialDomNode;
14534
- let currentBranch = "none";
14535
14565
  let branchCleanups = [];
14536
14566
  let isFirstRun = true;
14537
- const initialCondition = evaluate(node.condition, {
14538
- state: ctx.state,
14539
- locals: ctx.locals,
14540
- ...ctx.imports && { imports: ctx.imports },
14541
- ...ctx.route && { route: ctx.route }
14542
- });
14543
- currentBranch = Boolean(initialCondition) ? "then" : node.else ? "else" : "none";
14544
- if (currentBranch === "then") {
14545
- const localCleanups = [];
14546
- const branchCtx = { ...ctx, cleanups: localCleanups };
14547
- hydrate(node.then, currentNode, branchCtx);
14548
- branchCleanups = localCleanups;
14549
- } else if (currentBranch === "else" && node.else) {
14550
- const localCleanups = [];
14551
- const branchCtx = { ...ctx, cleanups: localCleanups };
14552
- hydrate(node.else, currentNode, branchCtx);
14553
- branchCleanups = localCleanups;
14567
+ const hasMismatch = branchInfo && branchInfo.ssrBranch !== branchInfo.clientBranch;
14568
+ let currentBranch = branchInfo?.ssrBranch ?? "none";
14569
+ if (!branchInfo) {
14570
+ const initialCondition = evaluate(node.condition, {
14571
+ state: ctx.state,
14572
+ locals: ctx.locals,
14573
+ ...ctx.imports && { imports: ctx.imports },
14574
+ ...ctx.route && { route: ctx.route }
14575
+ });
14576
+ currentBranch = Boolean(initialCondition) ? "then" : node.else ? "else" : "none";
14577
+ }
14578
+ if (!hasMismatch) {
14579
+ if (currentBranch === "then") {
14580
+ const localCleanups = [];
14581
+ const branchCtx = { ...ctx, cleanups: localCleanups };
14582
+ hydrate(node.then, currentNode, branchCtx);
14583
+ branchCleanups = localCleanups;
14584
+ } else if (currentBranch === "else" && node.else) {
14585
+ const localCleanups = [];
14586
+ const branchCtx = { ...ctx, cleanups: localCleanups };
14587
+ hydrate(node.else, currentNode, branchCtx);
14588
+ branchCleanups = localCleanups;
14589
+ }
14554
14590
  }
14555
14591
  const effectCleanup = createEffect(() => {
14556
14592
  const condition = evaluate(node.condition, {
@@ -14563,7 +14599,10 @@ function hydrateIf(node, initialDomNode, ctx) {
14563
14599
  const newBranch = shouldShowThen ? "then" : node.else ? "else" : "none";
14564
14600
  if (isFirstRun) {
14565
14601
  isFirstRun = false;
14566
- return;
14602
+ if (hasMismatch) {
14603
+ } else {
14604
+ return;
14605
+ }
14567
14606
  }
14568
14607
  if (newBranch !== currentBranch) {
14569
14608
  for (const cleanup of branchCleanups) {
@@ -14603,7 +14642,7 @@ function hydrateIf(node, initialDomNode, ctx) {
14603
14642
  }
14604
14643
  });
14605
14644
  }
14606
- function hydrateIfWithoutDom(node, parent, nextSibling, ctx) {
14645
+ function hydrateIfWithoutDom(node, parent, nextSibling, ctx, branchInfo) {
14607
14646
  const anchor = document.createComment("if");
14608
14647
  if (nextSibling) {
14609
14648
  parent.insertBefore(anchor, nextSibling);
@@ -14613,6 +14652,8 @@ function hydrateIfWithoutDom(node, parent, nextSibling, ctx) {
14613
14652
  let currentNode = null;
14614
14653
  let currentBranch = "none";
14615
14654
  let branchCleanups = [];
14655
+ const needsImmediateRender = branchInfo && branchInfo.clientBranch !== "none";
14656
+ let isFirstRun = true;
14616
14657
  const effectCleanup = createEffect(() => {
14617
14658
  const condition = evaluate(node.condition, {
14618
14659
  state: ctx.state,
@@ -14622,6 +14663,13 @@ function hydrateIfWithoutDom(node, parent, nextSibling, ctx) {
14622
14663
  });
14623
14664
  const shouldShowThen = Boolean(condition);
14624
14665
  const newBranch = shouldShowThen ? "then" : node.else ? "else" : "none";
14666
+ if (isFirstRun) {
14667
+ isFirstRun = false;
14668
+ if (needsImmediateRender) {
14669
+ } else if (newBranch === "none") {
14670
+ return;
14671
+ }
14672
+ }
14625
14673
  if (newBranch !== currentBranch) {
14626
14674
  for (const cleanup of branchCleanups) {
14627
14675
  cleanup();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constela/runtime",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "Runtime DOM renderer for Constela UI framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -29,7 +29,7 @@
29
29
  "tsup": "^8.0.0",
30
30
  "typescript": "^5.3.0",
31
31
  "vitest": "^2.0.0",
32
- "@constela/server": "8.0.0"
32
+ "@constela/server": "8.0.1"
33
33
  },
34
34
  "engines": {
35
35
  "node": ">=20.0.0"