Files
sigpro/docs/api/if.md
2026-04-06 18:28:07 +02:00

180 lines
5.0 KiB
Markdown

# 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
```typescript
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
```typescript
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
```javascript
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
```javascript
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
```javascript
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.
```javascript
If(() => user.isLogged(),
() => Dashboard(), // Only executed if logged in
() => LoginGate() // Only executed if guest
)
```
### 4. Complex Conditions
```javascript
If(() => count() > 10 && status() === 'ready',
Span("Threshold reached!")
)
```
### 5. If.not Helper
```javascript
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.
1. **Stop Watchers**: All `Watch` calls inside the inactive branch are permanently stopped.
2. **Unbind Events**: Event listeners attached via `Tag` are removed.
3. **Recursive Sweep**: SigPro performs a deep "sweep" of the removed branch.
4. **Transition Respect**: When using transitions, destruction only happens AFTER the `out` animation 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
```javascript
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
```javascript
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
```javascript
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); }
};
```