1.1.5
This commit is contained in:
@@ -41,9 +41,7 @@ export default defineConfig({
|
||||
items: [
|
||||
{ text: 'Quick Start', link: '/api/quick' },
|
||||
{ text: '$', link: '/api/signal' },
|
||||
{ text: '$.effect', link: '/api/effect' },
|
||||
{ text: '$.ignore', link: '/api/ignore' },
|
||||
{ text: '$.view', link: '/api/view' },
|
||||
{ text: '$.watch', link: '/api/watch' },
|
||||
{ text: '$.html', link: '/api/html' },
|
||||
{ text: '$.router', link: '/api/router' },
|
||||
{ text: '$.mount', link: '/api/mount' },
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
# ⚡ Side Effects: `$.effect( )`
|
||||
|
||||
The `$.effect` function allows you to run a piece of code whenever the signals it depends on are updated. It automatically tracks any signal called within its body.
|
||||
|
||||
## 🛠 Function Signature
|
||||
|
||||
```typescript
|
||||
$.effect(callback: Function): StopFunction
|
||||
```
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **`callback`** | `Function` | Yes | The code to run. It will execute immediately and then re-run on dependency changes. |
|
||||
|
||||
**Returns:** A `StopFunction` that, when called, cancels the effect and prevents further executions.
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage Patterns
|
||||
|
||||
### 1. Basic Tracking
|
||||
Any signal you "touch" inside the effect becomes a dependency.
|
||||
|
||||
```javascript
|
||||
const count = $(0);
|
||||
|
||||
$.effect(() => {
|
||||
// This runs every time 'count' changes
|
||||
console.log(`The count is now: ${count()}`);
|
||||
});
|
||||
|
||||
count(1); // Console: "The count is now: 1"
|
||||
```
|
||||
|
||||
### 2. Manual Cleanup
|
||||
If your effect creates something that needs to be destroyed (like a timer or a global event listener), you can return a cleanup function.
|
||||
|
||||
```javascript
|
||||
$.effect(() => {
|
||||
const timer = setInterval(() => console.log("Tick"), 1000);
|
||||
|
||||
// SigPro will run this BEFORE the next effect execution
|
||||
// or when the effect is stopped.
|
||||
return () => clearInterval(timer);
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Nesting & Automatic Cleanup
|
||||
If you create a signal or another effect inside an effect, SigPro tracks them as "children". When the parent effect re-runs or stops, all children are automatically cleaned up to prevent memory leaks.
|
||||
|
||||
```javascript
|
||||
$.effect(() => {
|
||||
if (isLoggedIn()) {
|
||||
// This sub-effect is only active while 'isLoggedIn' is true
|
||||
$.effect(() => {
|
||||
console.log("Fetching user data...");
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛑 Stopping an Effect
|
||||
You can stop an effect manually by calling the function it returns. This is useful for one-time operations or complex logic.
|
||||
|
||||
```javascript
|
||||
const stop = $.effect(() => {
|
||||
console.log(count());
|
||||
});
|
||||
|
||||
// Later...
|
||||
stop(); // The effect is destroyed and will never run again.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Pro Tip: Batching
|
||||
SigPro uses a **Microtask Queue** to handle updates. If you update multiple signals at once, the effect will only run **once** at the end of the current task.
|
||||
|
||||
```javascript
|
||||
const a = $(0);
|
||||
const b = $(0);
|
||||
|
||||
$.effect(() => console.log(a(), b()));
|
||||
|
||||
// This triggers only ONE re-run, not two.
|
||||
a(1);
|
||||
b(2);
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
# 🏗️ The DOM Factory: `$.html( )`
|
||||
|
||||
`$.html` is the internal engine that creates, attributes, and attaches reactivity to DOM elements. It is the foundation for all Tag Constructors in SigPro.
|
||||
`$.html` is the internal engine that creates, attributes, and attaches reactivity to DOM elements. In V2, it uses `$.watch` to maintain a live, high-performance link between your Signals and the Document Object Model.
|
||||
|
||||
## 🛠 Function Signature
|
||||
|
||||
@@ -41,7 +41,7 @@ $.html("button", {
|
||||
```
|
||||
|
||||
### 3. Reactive Attributes
|
||||
If an attribute value is a **function** (like a Signal), `$.html` creates an internal `$.effect` to keep the DOM in sync with the state.
|
||||
If an attribute value is a **function** (like a Signal), `$.html` creates an internal **`$.watch`** to keep the DOM in sync with the state.
|
||||
|
||||
```javascript
|
||||
$.html("div", {
|
||||
@@ -51,7 +51,7 @@ $.html("div", {
|
||||
```
|
||||
|
||||
### 4. Reactive Children
|
||||
Children can be static or dynamic. When a child is a function, SigPro creates a reactive boundary for that specific part of the DOM.
|
||||
Children can be static or dynamic. When a child is a function, SigPro creates a reactive boundary using `$.watch` for that specific part of the DOM.
|
||||
|
||||
```javascript
|
||||
$.html("div", {}, [
|
||||
@@ -74,9 +74,10 @@ $.html("input", {
|
||||
});
|
||||
```
|
||||
|
||||
## 🧹 Automatic Cleanup
|
||||
Every element created with `$.html` gets a hidden `._cleanups` property (a `Set`).
|
||||
* When SigPro removes an element via `$.view` or `$.router`, it automatically executes all functions stored in this Set (stopping effects, removing listeners, etc.).
|
||||
## 🧹 Memory Management (Internal)
|
||||
Every element created with `$.html` is "self-aware" regarding its reactive dependencies.
|
||||
* **`._cleanups`**: A hidden `Set` attached to the element that stores all `stop()` functions from its internal `$.watch` calls and event listeners.
|
||||
* **Lifecycle**: When an element is removed by a Controller (`$.If`, `$.For`, or `$.router`), SigPro performs a recursive "sweep" to execute these cleanups, ensuring **zero memory leaks**.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
# 🛑 Untracking: `$.ignore( )`
|
||||
|
||||
The `$.ignore` function allows you to read a signal's value inside an effect or a computed signal **without** creating a dependency.
|
||||
|
||||
## 🛠 Function Signature
|
||||
|
||||
```typescript
|
||||
$.ignore(callback: Function): any
|
||||
```
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **`callback`** | `Function` | Yes | A function where signals can be read "silently". |
|
||||
|
||||
**Returns:** Whatever the callback function returns.
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage Patterns
|
||||
|
||||
### 1. Preventing Dependency Tracking
|
||||
Normally, reading a signal inside `$.effect` makes the effect re-run when that signal changes. `$.ignore` breaks this link.
|
||||
|
||||
```javascript
|
||||
const count = $(0);
|
||||
const logLabel = $("System Log");
|
||||
|
||||
$.effect(() => {
|
||||
// This effect tracks 'count'...
|
||||
const currentCount = count();
|
||||
|
||||
// ...but NOT 'logLabel'.
|
||||
// Changing 'logLabel' will NOT re-run this effect.
|
||||
const label = $.ignore(() => logLabel());
|
||||
|
||||
console.log(`${label}: ${currentCount}`);
|
||||
});
|
||||
|
||||
count(1); // Console: "System Log: 1" (Triggers re-run)
|
||||
logLabel("UI"); // Nothing happens in console (Ignored)
|
||||
```
|
||||
|
||||
### 2. Reading State in Event Handlers
|
||||
Inside complex UI logic, you might want to take a "snapshot" of a signal without triggering a reactive chain.
|
||||
|
||||
```javascript
|
||||
const handleClick = () => {
|
||||
// Accessing state without letting the caller know we touched it
|
||||
const data = $.ignore(() => mySignal());
|
||||
process(data);
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Avoiding Infinite Loops
|
||||
If you need to **write** to a signal based on its own value inside an effect (and you aren't using the functional updater), `$.ignore` prevents the effect from triggering itself.
|
||||
|
||||
```javascript
|
||||
$.effect(() => {
|
||||
const value = someSignal();
|
||||
|
||||
if (value > 100) {
|
||||
// We update the signal, but we ignore the read to avoid a loop
|
||||
$.ignore(() => someSignal(0));
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Why use it?
|
||||
|
||||
* **Performance:** Prevents expensive effects from running when non-essential data changes.
|
||||
* **Logic Control:** Allows "sampling" a signal at a specific point in time.
|
||||
* **Safety:** Essential for complex state orchestrations where circular dependencies might occur.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 🔌 Application Mounter: `$.mount( )`
|
||||
|
||||
The `$.mount` function is the entry point of your reactive world. It bridges the gap between your SigPro logic and the browser's Real DOM by injecting a component into the document.
|
||||
The `$.mount` function is the entry point of your reactive world. It bridges the gap between your SigPro logic and the browser's Real DOM by injecting a component into the document and initializing its reactive lifecycle.
|
||||
|
||||
## 1. Function Signature
|
||||
## 🛠️ Function Signature
|
||||
|
||||
```typescript
|
||||
$.mount(node: Function | HTMLElement, target?: string | HTMLElement): RuntimeObject
|
||||
@@ -13,100 +13,73 @@ $.mount(node: Function | HTMLElement, target?: string | HTMLElement): RuntimeObj
|
||||
| **`node`** | `Function` or `Node` | **Required** | The component function or DOM element to render. |
|
||||
| **`target`** | `string` or `Node` | `document.body` | CSS selector or DOM element where the app will live. |
|
||||
|
||||
**Returns:** A `Runtime` object containing the `container` and a `destroy()` method.
|
||||
**Returns:** A `Runtime` object containing the `container` and a `destroy()` method to wipe all reactivity and DOM nodes.
|
||||
|
||||
---
|
||||
|
||||
## 2. Common Usage Scenarios
|
||||
## 📖 Common Usage Scenarios
|
||||
|
||||
### A. The "Clean Slate" (SPA Entry)
|
||||
In a modern Single Page Application, you typically want SigPro to manage the entire view. By default, if no target is provided, it mounts to `document.body`.
|
||||
### 1. The SPA Entry Point
|
||||
In a Single Page Application, you typically mount your main component to the body or a root div. SigPro manages the entire view from that point.
|
||||
|
||||
```javascript
|
||||
import { $ } from './sigpro.js';
|
||||
import App from './App.js';
|
||||
|
||||
// Mounts your main App component directly to the body
|
||||
$.mount(App);
|
||||
// Mounts your main App component
|
||||
$.mount(App, '#app-root');
|
||||
```
|
||||
|
||||
### B. Targeting a Specific Container
|
||||
If your HTML has a predefined structure, you can tell SigPro exactly where to render by passing a CSS selector or a direct reference.
|
||||
|
||||
```html
|
||||
<div id="sidebar"></div>
|
||||
<main id="app-root"></main>
|
||||
```
|
||||
### 2. Reactive "Islands"
|
||||
SigPro is perfect for adding reactivity to static pages. You can mount small widgets into specific parts of an existing HTML layout.
|
||||
|
||||
```javascript
|
||||
// Mount using a CSS selector
|
||||
$.mount(MyComponent, '#app-root');
|
||||
|
||||
// Mount using a direct DOM reference
|
||||
const sidebar = document.querySelector('#sidebar');
|
||||
$.mount(SidebarComponent, sidebar);
|
||||
```
|
||||
|
||||
### C. Creating "Reactive Islands"
|
||||
SigPro is excellent for "sprinkling" reactivity onto legacy or static pages. You can inject small reactive widgets into any part of an existing HTML layout.
|
||||
|
||||
```javascript
|
||||
// A small reactive widget
|
||||
const CounterWidget = () => {
|
||||
const Counter = () => {
|
||||
const count = $(0);
|
||||
return Button({ onclick: () => count(c => c + 1) }, [
|
||||
"Clicks: ", count
|
||||
]);
|
||||
};
|
||||
|
||||
// Mount it into a specific div in your static HTML
|
||||
$.mount(CounterWidget, '#counter-container');
|
||||
// Mount only the counter into a specific sidebar div
|
||||
$.mount(Counter, '#sidebar-widget');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. How it Works (Lifecycle)
|
||||
## 🔄 How it Works (Lifecycle & Saneamiento)
|
||||
|
||||
When `$.mount` is executed, it performs these critical steps:
|
||||
When `$.mount` is executed, it performs these critical steps to ensure a leak-free environment:
|
||||
|
||||
1. **Resolution & Wrapping**: If you pass a **Function**, SigPro wraps it in a `$.view()`. This starts tracking all internal signals and effects.
|
||||
2. **Target Clearance**: It uses `target.replaceChildren()`. This efficiently wipes any existing HTML or "zombie" nodes inside the target before mounting.
|
||||
3. **Injection**: The component's container is appended to the target.
|
||||
4. **Memory Management**: It stores the `Runtime` instance associated with that DOM element. If you call `$.mount` again on the same target, SigPro automatically **destroys the previous app** to prevent memory leaks.
|
||||
1. **Duplicate Detection**: If you call `$.mount` on a target that already has a SigPro instance, it automatically calls `.destroy()` on the previous instance. This prevents "Zombie Effects" from stacking in memory.
|
||||
2. **Internal Scoping**: It executes the component function inside an internal **Reactive Owner**. This captures every `$.watch` and event listener created during the render.
|
||||
3. **Target Injection**: It clears the target using `replaceChildren()` and appends the new component.
|
||||
4. **Runtime Creation**: It returns a control object:
|
||||
* `container`: The actual DOM element created.
|
||||
* `destroy()`: The "kill switch" that runs all cleanups, stops all watchers, and removes the element from the DOM.
|
||||
|
||||
---
|
||||
|
||||
## 4. Global vs. Local Scope
|
||||
## 🛑 Manual Unmounting
|
||||
|
||||
### The "Framework" Way (Global)
|
||||
By importing your core in your entry file, SigPro automatically initializes global Tag Constructors (`Div`, `Span`, `H1`, etc.). This allows for a clean, declarative DX across your entire project.
|
||||
While SigPro handles most cleanups automatically (via `$.If`, `$.For`, and `$.router`), you can manually destroy any mounted instance. This is vital for imperatively managed UI like **Toasts** or **Modals**.
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
import './sigpro.js';
|
||||
const instance = $.mount(MyToast, '#toast-container');
|
||||
|
||||
// Now any file can simply do:
|
||||
$.mount(() => H1("Global SigPro App"));
|
||||
```
|
||||
|
||||
### The "Library" Way (Local)
|
||||
If you prefer to avoid global variables, you can use the low-level `$.html` factory to create elements locally.
|
||||
|
||||
```javascript
|
||||
import { $ } from './sigpro.js';
|
||||
|
||||
const myNode = $.html('div', { class: 'widget' }, 'Local Instance');
|
||||
$.mount(myNode, '#widget-target');
|
||||
// Later, to remove the toast and kill its reactivity:
|
||||
instance.destroy();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Summary Cheat Sheet
|
||||
## 💡 Summary Cheat Sheet
|
||||
|
||||
| Goal | Code Pattern |
|
||||
| :--- | :--- |
|
||||
| **Mount to body** | `$.mount(App)` |
|
||||
| **Mount to ID** | `$.mount(App, '#root')` |
|
||||
| **Mount to Element** | `$.mount(App, myElement)` |
|
||||
| **Mount raw Node** | `$.mount(Div("Hello"), '#id')` |
|
||||
| **Unmount/Destroy** | `const app = $.mount(App); app.destroy();` |
|
||||
| **Mount to CSS Selector** | `$.mount(App, '#root')` |
|
||||
| **Mount to DOM Node** | `$.mount(App, myElement)` |
|
||||
| **Clean & Re-mount** | Calling `$.mount` again on the same target |
|
||||
| **Total Saneamiento** | `const app = $.mount(App); app.destroy();` |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 🎨 Global Tag Helpers
|
||||
|
||||
In **SigPro**, you don't need to manually type `$.html('div', ...)` for every element. To keep your code declarative and readable, the engine automatically generates **Global Helper Functions** for all standard HTML5 tags upon initialization.
|
||||
In **SigPro V2**, you don't need to manually type `$.html('div', ...)` for every element. To keep your code declarative and readable, the engine automatically generates **Global Helper Functions** for all standard HTML5 tags upon initialization.
|
||||
|
||||
## 1. How it Works
|
||||
|
||||
@@ -59,23 +59,23 @@ Span(42);
|
||||
|
||||
---
|
||||
|
||||
## 4. Reactive Power Examples
|
||||
## 4. Reactive Power V2
|
||||
|
||||
These helpers are natively wired into SigPro's reactivity. No manual `useEffect` or `watch` calls are needed.
|
||||
These helpers are natively wired into SigPro's **`$.watch`** engine. No manual effect management is needed; the lifecycle is tied to the DOM node.
|
||||
|
||||
### Reactive Attributes
|
||||
Simply pass a Signal (function) to any attribute. SigPro handles the rest.
|
||||
Simply pass a Signal (function) to any attribute. SigPro creates an internal `$.watch` to keep the DOM in sync.
|
||||
```javascript
|
||||
const theme = $("light");
|
||||
|
||||
Div({
|
||||
// Updates 'class' automatically when theme() changes
|
||||
// Updates 'class' automatically via internal $.watch
|
||||
class: () => `app-box ${theme()}`
|
||||
}, "Themeable Box");
|
||||
```
|
||||
|
||||
### The Binding Operator (`$`)
|
||||
Use the `$` prefix for **Two-Way Binding** on inputs.
|
||||
Use the `$` prefix for **Two-Way Binding** on inputs. This bridges the Signal and the Input element bi-directionally.
|
||||
```javascript
|
||||
const search = $("");
|
||||
|
||||
@@ -86,13 +86,13 @@ Input({
|
||||
});
|
||||
```
|
||||
|
||||
### Dynamic Lists
|
||||
Combine tags with `ui.For` for high-performance list rendering.
|
||||
### Dynamic Flow & Saneamiento
|
||||
Combine tags with Core controllers for high-performance rendering. SigPro automatically cleans up the `$.watch` instances when nodes are removed.
|
||||
```javascript
|
||||
const items = $(["Apple", "Banana", "Cherry"]);
|
||||
|
||||
Ul({ class: "list-disc" }, [
|
||||
ui.For(items, (item) => Li(item), (item) => item)
|
||||
$.For(items, (item) => Li(item))
|
||||
]);
|
||||
```
|
||||
|
||||
@@ -103,13 +103,13 @@ Ul({ class: "list-disc" }, [
|
||||
Since SigPro injects these helpers into the global `window` object, follow these rules to avoid bugs:
|
||||
|
||||
1. **Avoid Shadowing**: Don't name your local variables like the tags (e.g., `const Div = ...`). This will "hide" the SigPro helper.
|
||||
2. **Custom Components**: Always use **PascalCase**, **UPPERCASE**, or **Underscore** prefixes for your own component functions (e.g., `UserCard`, `INPUT`, or `_Input`) to distinguish them from the built-in Tag Helpers and avoid naming collisions.
|
||||
2. **Custom Components**: Always use **PascalCase** for your own component functions (e.g., `UserCard`, `NavMenu`) to distinguish them from the built-in Tag Helpers and maintain architectural clarity.
|
||||
:::
|
||||
---
|
||||
|
||||
## 6. Logic to UI Comparison
|
||||
## 5. Logic to UI Comparison
|
||||
|
||||
Here is how a dynamic **User Status** component translates from SigPro logic to the final DOM structure.
|
||||
Here is how a dynamic **User Status** component translates from SigPro logic to the final DOM structure, handled by the V2 "Saneamiento" engine.
|
||||
|
||||
```javascript
|
||||
// SigPro Component
|
||||
@@ -121,16 +121,14 @@ const UserStatus = (name, $online) => (
|
||||
class: 'w-3 h-3 bg-green-500 rounded-full'
|
||||
}),
|
||||
P({
|
||||
// Reactive text content
|
||||
// Reactive text content via automatic $.watch
|
||||
class: () => $online() ? "text-bold" : "text-gray-400"
|
||||
}, name)
|
||||
])
|
||||
);
|
||||
```
|
||||
|
||||
| State (`$online`) | Rendered HTML |
|
||||
| :--- | :--- |
|
||||
| **`true`** | `<div class="flex..."><span class="w-3..."></span><p class="text-bold">John</p></div>` |
|
||||
| **`false`** | `<div class="flex..."><span hidden class="w-3..."></span><p class="text-gray-400">John</p></div>` |
|
||||
|
||||
|
||||
| State (`$online`) | Rendered HTML | Memory Management |
|
||||
| :--- | :--- | :--- |
|
||||
| **`true`** | `<div class="flex..."><span class="w-3..."></span><p class="text-bold">John</p></div>` | Watcher active |
|
||||
| **`false`** | `<div class="flex..."><span hidden class="w-3..."></span><p class="text-gray-400">John</p></div>` | Attribute synced |
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
# 🖼️ Component Lifecycle: `$.view( )`
|
||||
|
||||
The `$.view` function is a specialized wrapper used to manage the lifecycle of a UI component. It tracks all signals, effects, and DOM elements created within it, providing a single point of destruction to prevent memory leaks.
|
||||
|
||||
## 🛠 Function Signature
|
||||
|
||||
```typescript
|
||||
$.view(renderFn: Function): RuntimeObject
|
||||
```
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **`renderFn`** | `Function` | Yes | A function that returns a DOM Node or an array of Nodes. |
|
||||
|
||||
**Returns:** A `Runtime` object containing:
|
||||
* `container`: A `div` (with `display: contents`) holding the rendered content.
|
||||
* `destroy()`: A function that unmounts the view and cleans up all internal effects/listeners.
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage Patterns
|
||||
|
||||
### 1. Basic Component Wrapper
|
||||
When you wrap logic in `$.view`, SigPro creates a "boundary".
|
||||
|
||||
```javascript
|
||||
const myView = $.view(() => {
|
||||
const count = $(0);
|
||||
|
||||
// This effect is "owned" by this view
|
||||
$.effect(() => console.log(count()));
|
||||
|
||||
return Div([
|
||||
H1("Internal View"),
|
||||
Button({ onclick: () => count(c => c + 1) }, "Add")
|
||||
]);
|
||||
});
|
||||
|
||||
// To show it:
|
||||
document.body.appendChild(myView.container);
|
||||
|
||||
// To kill it (removes from DOM and stops all internal effects):
|
||||
myView.destroy();
|
||||
```
|
||||
|
||||
### 2. Manual Cleanups with `onCleanup`
|
||||
The `renderFn` receives a helper object that allows you to register custom cleanup logic (like closing a WebSocket or a third-party library instance).
|
||||
|
||||
```javascript
|
||||
const ChartComponent = () => $.view(({ onCleanup }) => {
|
||||
const socket = new WebSocket("ws://...");
|
||||
|
||||
onCleanup(() => {
|
||||
socket.close();
|
||||
console.log("Cleanup: WebSocket closed");
|
||||
});
|
||||
|
||||
return Div({ class: "chart-container" });
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Internal Architecture
|
||||
|
||||
When `$.view` is called, it performs the following:
|
||||
1. **Isolation**: It creates a new `Set` of cleanups.
|
||||
2. **Execution**: It runs your function and captures any `$.effect` or child `$.view` created during execution.
|
||||
3. **Container**: It wraps the result in a `display: contents` element (which doesn't affect your CSS layout).
|
||||
4. **Disposal**: When `destroy()` is called, it recursively calls all cleanup functions and removes the container from the DOM.
|
||||
|
||||
---
|
||||
|
||||
## 💡 Why use `$.view`?
|
||||
|
||||
* **Automatic Cleanup**: You don't have to manually stop every effect when a user navigates away.
|
||||
* **Router Integration**: The SigPro Router (`$.router`) uses `$.view` internally to swap pages and clean up the previous one automatically.
|
||||
* **Performance**: It ensures that background processes (like intervals or observers) stop as soon as the element is no longer visible.
|
||||
91
src/docs/api/watch.md
Normal file
91
src/docs/api/watch.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# ⚡ Reactivity Control: `$.watch( )`
|
||||
|
||||
The `$.watch` function is the reactive engine of SigPro. It allows you to execute code automatically when signals change. In V2, `$.watch` is **polymorphic**: it can track dependencies automatically or follow an explicit list.
|
||||
|
||||
## 🛠 Function Signature
|
||||
|
||||
```typescript
|
||||
// Automatic Mode (Magic Tracking)
|
||||
$.watch(callback: Function): StopFunction
|
||||
|
||||
// Explicit Mode (Isolated Dependencies)
|
||||
$.watch(deps: Signal[], callback: Function): StopFunction
|
||||
```
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **`target / deps`** | `Function` | `Array` | Yes | Either the code to run (Auto) or an array of signals to watch (Explicit). |
|
||||
| **`callback`** | `Function` | Only in Explicit | The code that will run when the `deps` change. |
|
||||
|
||||
**Returns:** A `StopFunction` that, when called, destroys the watcher and releases memory.
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage Patterns
|
||||
|
||||
### 1. Automatic Mode (Default)
|
||||
Any signal you "touch" inside the callback becomes a dependency. SigPro tracks them behind the scenes.
|
||||
|
||||
```javascript
|
||||
const count = $(0);
|
||||
|
||||
$.watch(() => {
|
||||
// Re-runs every time 'count' changes
|
||||
console.log(`Count is: ${count()}`);
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Explicit Mode (Advanced Saneamiento) 🚀
|
||||
This mode **isolates** execution. The callback only triggers when the signals in the array change. Any other signal accessed *inside* the callback will NOT trigger a re-run. This is the "gold standard" for Routers and heavy components.
|
||||
|
||||
```javascript
|
||||
const sPath = $("/home");
|
||||
const user = $("Admin");
|
||||
|
||||
$.watch([sPath], () => {
|
||||
// Only triggers when 'sPath' changes.
|
||||
// Changes to 'user' will NOT trigger this, preventing accidental re-renders.
|
||||
console.log(`Navigating to ${sPath()} as ${user()}`);
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Automatic Cleanup
|
||||
If your logic creates timers, event listeners, or other reactive effects, SigPro tracks them as "children" of the current watch. When the watcher re-runs or stops, it kills everything inside automatically.
|
||||
|
||||
```javascript
|
||||
$.watch(() => {
|
||||
const timer = setInterval(() => console.log("Tick"), 1000);
|
||||
|
||||
// Register a manual cleanup if needed
|
||||
// Or simply rely on SigPro to kill nested $.watch() calls
|
||||
return () => clearInterval(timer);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛑 Stopping a Watcher
|
||||
Call the returned function to manually kill the watcher. This is essential for manual DOM injections (like Toasts) or long-lived background processes.
|
||||
|
||||
```javascript
|
||||
const stop = $.watch(() => console.log(count()));
|
||||
|
||||
// Later...
|
||||
stop(); // The link between the signal and this code is physically severed.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Pro Tip: The Microtask Queue
|
||||
SigPro batches updates. If you update multiple signals in the same execution block, the watcher will only fire **once** at the end of the task.
|
||||
|
||||
```javascript
|
||||
const a = $(0);
|
||||
const b = $(0);
|
||||
|
||||
$.watch(() => console.log(a(), b()));
|
||||
|
||||
// This triggers only ONE re-run.
|
||||
a(1);
|
||||
b(2);
|
||||
```
|
||||
@@ -1,15 +1,25 @@
|
||||
|
||||
# 🧩 UI Components `(WIP)`
|
||||
|
||||
> **Status: Work In Progress.** > These are high-level, complex visual components designed to speed up development. They often replace native HTML elements with "superpowered" versions that handle their own internal logic, reactivity, and accessibility.
|
||||
> **Status: Work In Progress.** > These are high-level, complex visual components designed to speed up development. They replace native HTML elements with "superpowered" versions that handle their own internal logic, reactivity, and professional styling.
|
||||
|
||||
## ⚠️ Prerequisites
|
||||
|
||||
To ensure all components render correctly with their reactive themes and states, your project **must** have the following versions installed:
|
||||
|
||||
* **Tailwind CSS v4+**: For the new engine performance and modern CSS variables.
|
||||
* **DaisyUI v5+**: Required for the updated theme-selectors and improved component classes used in the SigPro UI library.
|
||||
|
||||
---
|
||||
|
||||
## 1. What are UI Components?
|
||||
|
||||
Unlike **Tag Helpers** (which are just functional mirrors of HTML tags), SigPro UI Components are smart abstractions.
|
||||
Unlike **Tag Helpers** (which are just functional mirrors of HTML tags), SigPro UI Components are smart abstractions:
|
||||
|
||||
* **Stateful**: They manage complex internal states (like date ranges, search filtering, or API lifecycles).
|
||||
* **Reactive**: Attributes prefixed with `$` are automatically tracked.
|
||||
* **Self-Cleaning**: They automatically use `_cleanups` to destroy observers or event listeners when removed from the DOM.
|
||||
* **Themed**: Fully compatible with Tailwind CSS and DaisyUI themes.
|
||||
* **Reactive**: Attributes prefixed with `$` are automatically tracked via `$.watch`.
|
||||
* **Self-Sane**: They automatically use `._cleanups` to destroy observers or event listeners when removed from the DOM.
|
||||
* **Themed**: Fully compatible with the DaisyUI v5 theme system and Tailwind v4 utility classes.
|
||||
|
||||
---
|
||||
|
||||
@@ -17,7 +27,6 @@ Unlike **Tag Helpers** (which are just functional mirrors of HTML tags), SigPro
|
||||
|
||||
| Category | Components |
|
||||
| :--- | :--- |
|
||||
| **Logic & Flow** | `If`, `For`, `Json` |
|
||||
| **Forms & Inputs** | `Button`, `Input`, `Select`, `Autocomplete`, `Datepicker`, `Colorpicker`, `CheckBox`, `Radio`, `Range`, `Rating`, `Swap` |
|
||||
| **Feedback** | `Alert`, `Toast`, `Modal`, `Loading`, `Badge`, `Tooltip`, `Indicator` |
|
||||
| **Navigation** | `Navbar`, `Menu`, `Drawer`, `Tabs`, `Accordion`, `Dropdown` |
|
||||
@@ -28,7 +37,7 @@ Unlike **Tag Helpers** (which are just functional mirrors of HTML tags), SigPro
|
||||
## 3. Examples with "Superpowers"
|
||||
|
||||
### A. The Declarative API Flow (`Request` & `Response`)
|
||||
Instead of manually managing `loading` and `error` flags, use these two together to handle data fetching elegantly.
|
||||
Instead of manually managing `loading` and `error` flags, use these together to handle data fetching elegantly.
|
||||
|
||||
```javascript
|
||||
// 1. Define the request (it tracks dependencies automatically)
|
||||
@@ -48,7 +57,7 @@ Div({ class: "p-4" }, [
|
||||
```
|
||||
|
||||
### B. Smart Inputs & Autocomplete
|
||||
Native inputs are boring. SigPro UI inputs handle labels, icons, password toggles, and validation states out of the box.
|
||||
SigPro UI inputs handle labels, icons, password toggles, and validation states out of the box using DaisyUI v5 classes.
|
||||
|
||||
```javascript
|
||||
const searchQuery = $("");
|
||||
@@ -63,7 +72,7 @@ Autocomplete({
|
||||
```
|
||||
|
||||
### C. The Reactive Datepicker
|
||||
Handles single dates or ranges with a clean, reactive interface.
|
||||
Handles single dates or ranges with a clean, reactive interface that automatically syncs with your signals.
|
||||
|
||||
```javascript
|
||||
const myDate = $(""); // or { start: "", end: "" } for range
|
||||
@@ -71,15 +80,15 @@ const myDate = $(""); // or { start: "", end: "" } for range
|
||||
Datepicker({
|
||||
label: "Select Expiry Date",
|
||||
$value: myDate,
|
||||
range: false // Set to true for range selection
|
||||
range: false
|
||||
});
|
||||
```
|
||||
|
||||
### D. Imperative Toasts & Modals
|
||||
Sometimes you just need to trigger a message without cluttering your template.
|
||||
Trigger complex UI elements from your logic. These components use `$.mount` internally to ensure they are properly cleaned up from memory after they close.
|
||||
|
||||
```javascript
|
||||
// Show a notification from anywhere in your logic
|
||||
// Show a notification (Self-destroying after 3s)
|
||||
Toast("Settings saved successfully!", "alert-success", 3000);
|
||||
|
||||
// Control a modal with a simple signal
|
||||
@@ -104,15 +113,15 @@ The UI library comes with a built-in locale system. It currently supports `es` a
|
||||
// Set the global UI language
|
||||
SetLocale("en");
|
||||
|
||||
// Access translated strings in your own components
|
||||
const t = tt("confirm"); // Returns a signal that tracks the current locale
|
||||
// Access translated strings (Returns a signal that tracks the current locale)
|
||||
const t = tt("confirm");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Best Practices
|
||||
|
||||
* **Use `$` for Reactivity**: If a property starts with `$`, it expects a Signal (e.g., `$value: mySignal`).
|
||||
* **Key your Lists**: When using `For`, always provide a `keyFn` to ensure high-performance DOM reconciliation.
|
||||
* **Cleanups**: If you build custom components that use `setInterval` or `observers`, add them to the element's `_cleanups` Set.
|
||||
* **Use `$` for Reactivity**: If a property starts with `$`, the component expects a Signal (e.g., `$value: mySignal`).
|
||||
* **Automatic Cleaning**: You don't need to manually destroy these components if they are inside a `$.If` or `$.For`. SigPro's core will "sweep" their internal watchers automatically.
|
||||
* **Manual Cleanups**: If you build custom components using `setInterval` or third-party observers, always add the stop functions to the element's `._cleanups` Set.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user