All files / src/components Show.ts

100% Statements 33/33
100% Branches 10/10
100% Functions 1/1
100% Lines 33/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 531x 1x                 1x 5x 5x 5x 5x 5x   5x 8x     8x 3x   3x   8x 8x   8x   7x 7x   7x 3x 3x 3x 7x 7x 8x 1x 1x     8x 7x 7x 5x   5x 5x  
import { createEffect } from '../primitives/effect';
import { createRoot, onCleanup } from '../lifecycle/lifecycle';  // Added import for onCleanup
import type { Disposer, SignalGetter } from '../types';
 
type ShowProps<T> = {
  when: SignalGetter<T>;
  fallback?: () => Node;
  children: () => Node;
};
 
export function Show<T>(props: ShowProps<T>): Node {
  const { when, fallback, children } = props;
  const container = document.createDocumentFragment();
  const endMarker = document.createTextNode('');  // Added: Invisible marker for insertion point
  container.appendChild(endMarker);
  let currentDisposer: Disposer | null = null;
 
  createEffect(() => {
    const condition = !!when();
 
    // Always clean up the previous state before rendering the new one
    if (currentDisposer) {
      currentDisposer();
      // Removed: container.textContent = ''; (invalid on DocumentFragment)
    }
 
    const renderer = condition ? children : fallback;
    let branchElement: Node | null = null;  // Local to this effect run
 
    if (renderer) {
      // Create a new root for the branch, so it gets its own lifecycle
      currentDisposer = createRoot(() => {
        branchElement = renderer();
        // Added: Explicit cleanup to remove the node from DOM on dispose
        onCleanup(() => {
          if (branchElement && branchElement.parentNode) {
            branchElement.parentNode.removeChild(branchElement);
          }
        });
      });
    } else {
      currentDisposer = null;
    }
 
    // Added: Insert the new branch before the endMarker (handles fragment initial / DOM updates)
    if (branchElement) {
      endMarker.parentNode!.insertBefore(branchElement, endMarker);
    }
  });
 
  return container;
}