Update Sigpro

This commit is contained in:
2026-03-26 17:06:17 +01:00
parent b5da486820
commit 1f2229ddda
6 changed files with 224 additions and 182 deletions

View File

@@ -21,40 +21,48 @@ $.html(tagName: string, props?: Object, children?: any[] | any): HTMLElement
### 1. Attribute Handling
SigPro intelligently decides how to apply each property:
* **Standard Props**: Applied via `setAttribute` or direct property assignment.
* **Boolean Props**: Uses `toggleAttribute` (e.g., `checked`, `disabled`, `hidden`).
* **Class Names**: Supports `class` or `className` interchangeably.
* **Boolean Props**: Automatic handling for `checked`, `disabled`, `hidden`, etc.
### 2. Event Listeners & Modifiers
Events are defined by the `on` prefix. SigPro supports **Dot Notation** for common event operations:
### 2. Event Listeners
Events are defined by the `on` prefix. SigPro automatically registers the listener and ensures it is cleaned up when the element is destroyed.
```javascript
$.html("button", {
// e.preventDefault() is called automatically
"onsubmit.prevent": (e) => save(e),
// e.stopPropagation() is called automatically
"onclick.stop": () => console.log("No bubbling"),
// { once: true } listener option
"onclick.once": () => console.log("Runs only once")
Button({
onclick: (e) => console.log("Clicked!", e),
}, "Click Me");
```
### 3. Reactive Attributes
### 3. Reactive Attributes (One-Way)
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", {
Div({
// Updates the class whenever 'theme()' changes
class: () => theme() === "dark" ? "bg-black" : "bg-white"
});
```
### 4. Reactive Children
### 4. Smart Two-Way Binding (Automatic)
SigPro automatically enables **bidirectional synchronization** when it detects a **Signal** assigned to a form-capable attribute (`value` or `checked`) on an input element (`input`, `textarea`, `select`).
```javascript
// Syncs input value <-> signal automatically
Input({
type: "text",
value: username // No special symbols needed!
})
```
> **Note:** To use a Signal as **read-only** in an input, wrap it in an anonymous function: `value: () => username()`.
### 5. Reactive Children
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", {}, [
Div({}, [
H1("Static Title"),
// Only this text node re-renders when 'count' changes
() => `Current count: ${count()}`
@@ -63,27 +71,16 @@ $.html("div", {}, [
---
## 🔄 Two-Way Binding Operator (`$`)
When a property starts with `$`, `$.html` enables bidirectional synchronization. This is primarily used for form inputs.
```javascript
$.html("input", {
type: "text",
$value: username // Syncs input value <-> signal
});
```
## 🧹 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**.
* **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**.
---
## 💡 Tag Constructors (The Shortcuts)
Instead of writing `$.html("div", ...)` every time, SigPro provides PascalCase global functions:
Instead of writing `$.html("div", ...)` every time, SigPro provides PascalCase global functions for all standard HTML tags:
```javascript
// This:

View File

@@ -13,7 +13,7 @@ SigPro iterates through a manifest of standard HTML tags and attaches a wrapper
## 2. The Complete Global Registry
The following functions are injected into the global scope (using **PascalCase** to prevent naming collisions with common JS variables) and are ready to use:
The following functions are injected into the global scope using **PascalCase** to prevent naming collisions with common JS variables:
| Category | Available Global Functions |
| :--- | :--- |
@@ -24,8 +24,6 @@ The following functions are injected into the global scope (using **PascalCase**
| **Tables** | `Table`, `Thead`, `Tbody`, `Tr`, `Th`, `Td`, `Tfoot`, `Caption` |
| **Media** | `Img`, `Canvas`, `Video`, `Audio`, `Svg`, `Iframe`, `Picture`, `Source` |
> **The SigPro Philosophy:** Tags are not "magic strings" handled by a compiler. They are **functional constructors**. Every time you call `Div()`, you execute a pure JS function that returns a real, reactive DOM element.
---
## 3. Usage Patterns (Smart Arguments)
@@ -33,7 +31,6 @@ The following functions are injected into the global scope (using **PascalCase**
SigPro tag helpers are flexible. They automatically detect if you are passing attributes, children, or both.
### A. Attributes + Children
The standard way to build structured UI.
```javascript
Div({ class: 'container', id: 'main' }, [
H1("Welcome to SigPro"),
@@ -42,7 +39,7 @@ Div({ class: 'container', id: 'main' }, [
```
### B. Children Only (The "Skipper")
If you don't need attributes, you can skip the object and pass the content (string, array, or function) directly as the first argument.
If you don't need attributes, you can pass the content directly as the first argument.
```javascript
Section([
H2("Clean Syntax"),
@@ -50,85 +47,79 @@ Section([
]);
```
### C. Primitive Content
For simple tags, just pass a string or a number.
```javascript
H1("Hello World");
Span(42);
```
---
## 4. Reactive Power
These helpers are natively wired into SigPro's **`$.watch`** engine. No manual effect management is needed; the lifecycle is tied to the DOM node.
These helpers are natively wired into SigPro's **`$.watch`** engine.
### Reactive Attributes
### Reactive Attributes (One-Way)
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 via internal $.watch
class: () => `app-box ${theme()}`
}, "Themeable Box");
```
### The Binding Operator (`$`)
Use the `$` prefix for **Two-Way Binding** on inputs. This bridges the Signal and the Input element bi-directionally.
### Smart Two-Way Binding (Automatic)
SigPro automatically bridges the **Signal** and the **Input** element bi-directionally when you assign a Signal to `value` or `checked`. No special operators are required.
```javascript
const search = $("");
// UI updates Signal AND Signal updates UI automatically
Input({
type: "text",
placeholder: "Search...",
$value: search // UI updates Signal AND Signal updates UI
value: search
});
```
> **Pro Tip:** If you want an input to be **read-only** but still reactive, wrap the signal in an anonymous function: `value: () => search()`. This prevents the "backwards" synchronization.
### Dynamic Flow & Cleanup
Combine tags with Core controllers for high-performance rendering. SigPro automatically cleans up the `$.watch` instances when nodes are removed.
Combine tags with Core controllers. SigPro automatically cleans up the `$.watch` instances and event listeners when nodes are removed from the DOM.
```javascript
const items = $(["Apple", "Banana", "Cherry"]);
Ul({ class: "list-disc" }, [
$.For(items, (item) => Li(item))
$.for(items, (item) => Li(item), (item) => item)
]);
```
---
::: danger
## ⚠️ Important: Naming Conventions
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** for your own component functions (e.g., `UserCard`, `NavMenu`) to distinguish them from the built-in Tag Helpers and maintain architectural clarity.
1. **Avoid Shadowing**: Don't name your local variables like the tags (e.g., `const Div = ...`). This will "hide" the global SigPro helper.
2. **Custom Components**: Always use **PascalCase** for your own component functions (e.g., `UserCard`, `NavMenu`) to distinguish them from built-in Tag Helpers.
:::
---
## 5. Logic to UI Comparison
Here is how a dynamic **User Status** component translates from SigPro logic to the final DOM structure, handled by the engine.
Here is how a dynamic **User Status** component translates from SigPro logic to the final DOM structure.
```javascript
// SigPro Component
const UserStatus = (name, $online) => (
const UserStatus = (name, online) => (
Div({ class: 'flex items-center gap-2' }, [
Span({
// Boolean toggle for 'hidden' attribute
hidden: () => !$online(),
hidden: () => !online(),
class: 'w-3 h-3 bg-green-500 rounded-full'
}),
P({
// Reactive text content via automatic $.watch
class: () => $online() ? "text-bold" : "text-gray-400"
class: () => online() ? "text-bold" : "text-gray-400"
}, name)
])
);
```
| State (`$online`) | Rendered HTML | Memory Management |
| 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 |

51
src/docs/ui/buttons.md Normal file
View File

@@ -0,0 +1,51 @@
# Buttons
The **SigPro** Button component wraps [DaisyUI 5](https://daisyui.com/components/button/) styles with native reactive logic.
## Basic Usage
<button class="btn btn-primary btn-secondary btn-accent btn-neutral btn-info btn-lg btn-sm btn-xs">Test</button>
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
if (typeof window === 'undefined') return;
const init = () => {
// 1. Esperamos a que el Core ($) y los helpers (Button, Div) existan
if (!window.$ || !window.Button || !window.Input) {
setTimeout(init, 100);
return;
}
// 2. Usamos las funciones tal cual las crea tu Core (con Mayúscula inicial)
const { $, Button, Input, Div, P, Span } = window;
const Mount = $.mount;
const HTML = $.html;
// --- DEMO REACTIVA ---
const nombre = $('Mundo');
return Mount(
Div({ class: 'flex flex-col gap-4' }, [
// Usamos el helper Input de tu librería
Input({
class: 'input input-bordered input-primary w-full max-w-xs',
value: nombre, // Tu Core maneja el binding si es una señal
placeholder: 'Escribe tu nombre...'
}),
// El P y el Span también son helpers de tu Core
P({ class: 'text-xl' }, [
'Hola ',
Span({ class: 'text-primary font-bold' }, nombre),
'!'
])
]),
'#demo-input-simple'
);
};
init();
})
</script>