5.0 KiB
5.0 KiB
Reactive Branching: $if( )
The $if function is a reactive control flow operator. It manages the conditional rendering of components with optional smooth transitions, ensuring that only the active branch exists in the DOM and in memory.
Function Signature
$if(
condition: Signal<boolean> | Function,
thenVal: Component | Node,
otherwiseVal?: Component | Node,
transition?: Transition
): HTMLElement
| Parameter | Type | Required | Description |
|---|---|---|---|
condition |
Signal |
Yes | A reactive source that determines which branch to render. |
thenVal |
any |
Yes | The content to show when the condition is truthy. |
otherwiseVal |
any |
No | The content to show when the condition is falsy (defaults to null). |
transition |
Transition |
No | Optional animation hooks for enter/exit transitions. |
Returns: A div element with display: contents that acts as a reactive portal for the branches.
Transition Interface
interface Transition {
/** Called when branch enters. Use for fade-in, slide-in, etc. */
in: (el: HTMLElement) => void;
/** Called when branch leaves. Call `done()` when animation completes. */
out: (el: HTMLElement, done: () => void) => void;
}
Example: Fade Transition
const fade = {
in: (el) => {
el.style.opacity = "0";
el.style.transition = "opacity 0.3s";
requestAnimationFrame(() => {
el.style.opacity = "1";
});
},
out: (el, done) => {
el.style.transition = "opacity 0.3s";
el.style.opacity = "0";
setTimeout(done, 300);
}
};
$if(show, Modal, null, fade);
Usage Patterns
1. Simple Toggle
const isVisible = $(false);
Div([
Button({ onclick: () => isVisible(!isVisible()) }, "Toggle Message"),
$if(isVisible,
P("Now you see me!"),
P("Now you don't...")
)
]);
2. With Smooth Animation
const showModal = $(false);
Div([
Button({ onclick: () => showModal(true) }, "Open Modal"),
$if(showModal,
() => Modal({ onClose: () => showModal(false) }),
null,
fade // ← Smooth enter/exit animation
)
]);
3. Lazy Component Loading
Unlike CSS display: none, $if is lazy. The inactive branch is never created, saving memory.
$if(() => user.isLogged(),
() => Dashboard(), // Only executed if logged in
() => LoginGate() // Only executed if guest
)
4. Complex Conditions
$if(() => count() > 10 && status() === 'ready',
Span("Threshold reached!")
)
5. $if.not Helper
$if.not(loading,
() => Content(), // Shows when loading is FALSE
() => Spinner() // Shows when loading is TRUE
)
Automatic Cleanup
One of the core strengths of $if is its integrated Cleanup logic. SigPro ensures that when a branch is swapped out, it is completely purged.
- Stop Watchers: All
$watchcalls inside the inactive branch are permanently stopped. - Unbind Events: Event listeners attached via
$htmlare removed. - Recursive Sweep: SigPro performs a deep "sweep" of the removed branch.
- Transition Respect: When using transitions, destruction only happens AFTER the
outanimation completes.
Best Practices
- Function Wrappers: For heavy components, use
() => MyComponent()to prevent initialization until needed. - Reusable Transitions: Define common transitions (fade, slide, scale) in a shared module.
- Cleanup: No manual cleanup needed. SigPro handles everything automatically.
Technical Comparison
| Feature | Standard CSS hidden |
SigPro $if |
|---|---|---|
| DOM Presence | Always present | Only if active |
| Reactivity | Still processing | Paused/Destroyed |
| Memory usage | Higher | Optimized |
| Cleanup | Manual | Automatic |
| Smooth Transitions | Manual | Built-in hook |
| Animation Timing | You manage | Respected by core |
Complete Transition Examples
Fade
const fade = {
in: (el) => { el.style.opacity = "0"; requestAnimationFrame(() => { el.style.transition = "opacity 0.3s"; el.style.opacity = "1"; }); },
out: (el, done) => { el.style.transition = "opacity 0.3s"; el.style.opacity = "0"; setTimeout(done, 300); }
};
Slide
const slide = {
in: (el) => { el.style.transform = "translateX(-100%)"; requestAnimationFrame(() => { el.style.transition = "transform 0.3s"; el.style.transform = "translateX(0)"; }); },
out: (el, done) => { el.style.transition = "transform 0.3s"; el.style.transform = "translateX(-100%)"; setTimeout(done, 300); }
};
Scale
const scale = {
in: (el) => { el.style.transform = "scale(0)"; requestAnimationFrame(() => { el.style.transition = "transform 0.2s"; el.style.transform = "scale(1)"; }); },
out: (el, done) => { el.style.transition = "transform 0.2s"; el.style.transform = "scale(0)"; setTimeout(done, 200); }
};