Update Docs

This commit is contained in:
2026-04-26 15:38:10 +02:00
parent 13f7fba03c
commit a792e72b63
16 changed files with 294 additions and 256 deletions

View File

@@ -1,42 +1,55 @@
<div class="w-full -mt-10"><section class="relative py-20 overflow-hidden border-b border-base-200/30 text-center flex flex-col items-center"><div class="relative z-10 max-w-5xl mx-auto px-6 flex flex-col items-center"><div class="flex justify-center mb-10"><img src="logo.svg" alt="SigPro Logo" class="w-48 h-48 md:w-64 md:h-64 object-contain drop-shadow-2xl"></div><h1 class="text-7xl md:text-9xl font-black tracking-tighter mb-4 bg-clip-text text-transparent bg-linear-to-r from-primary via-secondary to-accent !text-center w-full">SigPro</h1><div class="text-2xl md:text-3xl font-bold text-base-content/90 mb-4 !text-center w-full">Atomic Unified Reactive Engine</div><div class="text-xl text-base-content/60 max-w-3xl mx-auto mb-10 leading-relaxed italic text-balance font-light !text-center w-full">"The efficiency of direct DOM manipulation with the elegance of functional reactivity."</div><div class="flex flex-wrap justify-center gap-4 w-full"><a href="#/install" class="btn btn-primary btn-lg shadow-xl shadow-primary/20 group px-10 border-none">Get Started <span class="group-hover:translate-x-1 transition-transform inline-block">→</span></a><button onclick="window.open('https://github.com/natxocc/sigpro')" class="btn btn-outline btn-lg border-base-300 hover:bg-base-300 hover:text-base-content">GitHub</button></div></div><div class="absolute top-0 left-1/2 -translate-x-1/2 w-full h-full -z-0 opacity-10 pointer-events-none"><div class="absolute top-10 left-1/4 w-96 h-96 bg-primary filter blur-3xl rounded-full animate-pulse"></div><div class="absolute bottom-10 right-1/4 w-96 h-96 bg-accent filter blur-3xl rounded-full animate-pulse" style="animation-delay: 2.5s"></div></div></section></div>
<section class="max-w-6xl mx-auto px-6 py-16"><div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 items-stretch"><div class="card bg-base-200/30 border border-base-300 hover:border-primary/40 transition-all p-1"><div class="card-body p-6"><h3 class="card-title text-xl font-black text-primary italic">FUNCTIONAL</h3><p class="text-sm opacity-70">No strings. No templates. Pure JS function calls for instant DOM mounting.</p></div></div><div class="card bg-base-200/30 border border-base-300 hover:border-secondary/40 transition-all p-1"><div class="card-body p-6"><h3 class="card-title text-xl font-black text-secondary italic">ATOMIC</h3><p class="text-sm opacity-70">Fine-grained signals update exactly what changes. No V-DOM diffing overhead.</p></div></div><div class="card bg-base-200/30 border border-base-300 hover:border-accent/40 transition-all p-1"><div class="card-body p-6"><h3 class="card-title text-xl font-black text-accent italic">ULTRA-THIN</h3><p class="text-sm opacity-70">Sub-2KB runtime. Infinitely smaller bundle than React, Vue or even Svelte.</p></div></div><div class="card bg-base-200/30 border border-base-300 hover:border-base-content/20 transition-all p-1"><div class="card-body p-6"><h3 class="card-title text-xl font-black italic text-base-content">COMPILER-FREE</h3><p class="text-sm opacity-70">Standard Vanilla JS. What you write is what the browser executes. Period.</p></div></div></div></section></div>
<section class="max-w-6xl mx-auto px-6 py-16"><div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 items-stretch"><div class="card bg-base-200/30 border border-base-300 hover:border-primary/40 transition-all p-1"><div class="card-body p-6"><h3 class="card-title text-xl font-black text-primary italic">FUNCTIONAL</h3><p class="text-sm opacity-70">No strings. No templates. Pure JS function calls for instant DOM mounting.</p></div></div><div class="card bg-base-200/30 border border-base-300 hover:border-secondary/40 transition-all p-1"><div class="card-body p-6"><h3 class="card-title text-xl font-black text-secondary italic">ATOMIC</h3><p class="text-sm opacity-70">Finegrained signals update exactly what changes. No VDOM diffing overhead.</p></div></div><div class="card bg-base-200/30 border border-base-300 hover:border-accent/40 transition-all p-1"><div class="card-body p-6"><h3 class="card-title text-xl font-black text-accent italic">ULTRATHIN</h3><p class="text-sm opacity-70">Sub2KB runtime. Infinitely smaller bundle than React, Vue or even Svelte.</p></div></div><div class="card bg-base-200/30 border border-base-300 hover:border-base-content/20 transition-all p-1"><div class="card-body p-6"><h3 class="card-title text-xl font-black italic text-base-content">COMPILERFREE</h3><p class="text-sm opacity-70">Standard Vanilla JS. What you write is what the browser executes. Period.</p></div></div></div></section>
## Functional DOM Construction
<div class="max-w-6xl mx-auto px-6 py-8"><h2 class="text-4xl font-black mb-6">Functional DOM Construction</h2><p class="text-lg opacity-80 mb-6">SigPro replaces slow "Template Parsing" with <strong>HighEfficiency Function Calls</strong>. While other frameworks force the browser to parse strings of HTML or execute complex JSX transformations, SigPro uses a direct functional approach.</p>
SigPro replaces the slow "Template Parsing" with **High-Efficiency Function Calls**.
<table class="table w-full mb-12">
<thead><tr><th>Feature</th><th>Standard HTML / JSX</th><th>SigPro Functional</th></tr></thead>
<tbody>
<tr><td>Syntax</td><td><code>&lt;div&gt;Hello&lt;/div&gt;</code></td><td><code>div("Hello")</code> (or <code>h('div', "Hello")</code>)</td></tr>
<tr><td>Processing</td><td>Parse → Diff → Patch</td><td>Direct API Call</td></tr>
<tr><td>Overhead</td><td>High (VDOM / Parser)</td><td><strong>Zero</strong></td></tr>
<tr><td>Reactivity</td><td>Componentwide</td><td><strong>Atomic (Nodelevel)</strong></td></tr>
</tbody>
</table>
While other frameworks force the browser to parse strings of HTML or execute complex JSX transformations, SigPro uses a direct functional approach:
<h3 class="text-2xl font-bold mt-8 mb-4">Less Code, More Power</h3>
<p class="mb-4">By sharing a minuscule runtime, your final application bundle is <strong>infinitely smaller</strong>.</p>
<ul class="list-disc pl-6 space-y-2 mb-8">
<li><strong>React/Vue:</strong> You ship a heavy orchestrator (~3090KB) just to say "Hello World".</li>
<li><strong>Solid/Svelte:</strong> You still depend on a compilation step that generates extra boilerplate.</li>
<li><strong>SigPro:</strong> You ship <strong>Pure Vanilla JS</strong>. The runtime is so small that it often costs less than a single highres icon.</li>
</ul>
| Feature | Standard HTML / JSX | SigPro Functional |
| :--- | :--- | :--- |
| **Syntax** | `<div>Hello</div>` | `Div("Hello")` |
| **Processing** | Parse → Diff → Patch | Direct API Call |
| **Overhead** | High (V-DOM / Parser) | **Zero** |
| **Reactivity** | Component-wide | **Atomic (Node-level)** |
<h3 class="text-2xl font-bold mt-8 mb-4">Two Ways to Use SigPro (v1.2.19+)</h3>
<p class="mb-2"><strong>🎯 Modern ESM (recommended):</strong> Import only the functions you need zero global pollution.</p>
<pre class="bg-base-300/30 p-4 rounded-lg mb-4"><code>import { $, div, button, mount } from 'sigpro';
const count = $(0);
mount(() => div([ button({ onclick: () => count(count()+1) }, count) ]), '#app');</code></pre>
<p class="mb-2"><strong>🌍 Classic Global (IIFE):</strong> Load the script and everything is automatically on <code>window</code> no imports needed.</p>
<pre class="bg-base-300/30 p-4 rounded-lg mb-4"><code>&lt;script src="https://cdn.jsdelivr.net/npm/sigpro@1.2.19/dist/sigpro.js"&gt;&lt;/script&gt;
&lt;script&gt;
const count = $(0);
mount(() => div([ button({ onclick: () => count(count()+1) }, count) ]), '#app');
&lt;/script&gt;</code></pre>
<p class="mb-2"><strong>🔧 ESM + Global injection:</strong> If you want the global helpers but still use <code>type="module"</code>, call <code>sigpro()</code>.</p>
<pre class="bg-base-300/30 p-4 rounded-lg"><code>&lt;script type="module"&gt;
import { sigpro } from 'https://cdn.jsdelivr.net/npm/sigpro@1.2.19/+esm';
sigpro(); // now $, div, button, etc. are global
&lt;/script&gt;</code></pre>
### Less Code, More Power
By sharing a miniscule runtime, your final application bundle is **infinitely smaller**.
<h3 class="text-2xl font-bold mt-10 mb-4">Precision Engineering</h3>
<h4 class="text-xl font-semibold mt-6 mb-2">1. Functional Efficiency</h4>
<p><code>div()</code>, <code>button()</code>, <code>span()</code>… These aren't just wrappers; they are preoptimized constructors. When you call <code>div({ class: 'btn' }, "Click")</code>, SigPro creates the element and attaches its reactive listeners in a single, surgical operation.</p>
* **React/Vue:** You ship a heavy orchestrator (~30-90KB) just to say "Hello World".
* **Solid/Svelte:** You still depend on a compilation step that generates extra boilerplate.
* **SigPro:** You ship **Pure Vanilla JS**. The runtime is so small that it often costs less than a single high-res icon.
<h4 class="text-xl font-semibold mt-6 mb-2">2. The "NoBundle" Bundle</h4>
<p>Because SigPro is so small, it is the only engine where <strong>the more code you write, the more the efficiency gap grows</strong>. While others grow linearly with components and framework overhead, SigPro stays flat, leveraging the native power of modern browser engines.</p>
---
<h4 class="text-xl font-semibold mt-6 mb-2">3. Shared Runtime</h4>
<p>All components share the same atomic engine. One signal can update a single character in a paragraph across 100 components without ever reevaluating the component functions themselves.</p>
</div>
## Precision Engineering
### 1. Functional Efficiency
`Div()`, `Button()`, `Span()`... These aren't just wrappers; they are pre-optimized constructors. When you call `Div({ class: 'btn' }, "Click")`, SigPro creates the element and attaches its reactive listeners in a single, surgical operation.
### 2. The "No-Bundle" Bundle
Because SigPro is so small, it is the only engine where **the more code you write, the more the efficiency gap grows**. While others grow linearly with components and framework overhead, SigPro stays flat, leveraging the native power of modern browser engines.
### 3. Shared Runtime
All components share the same atomic engine. One signal can update a single character in a paragraph across 100 components without ever re-evaluating the component functions themselves.
---
<div class="bg-base-200/50 rounded-3xl p-10 my-16 border border-base-300 shadow-inner"><div class="grid grid-cols-1 lg:grid-cols-3 gap-8 items-center"><div class="lg:col-span-2"><h2 class="text-4xl font-black mb-4 mt-0 tracking-tight italic text-primary">Kill the Bloat.</h2><p class="text-xl opacity-80 leading-relaxed">Stop shipping 100KB of "Framework" for 2KB of business logic. SigPro gives you the tools to build ultra-fast, modern apps with <strong>True Vanilla Performance</strong>.</p></div></div></div>
<div class="bg-base-200/50 rounded-3xl p-10 my-16 border border-base-300 shadow-inner max-w-6xl mx-auto"><div class="grid grid-cols-1 lg:grid-cols-3 gap-8 items-center"><div class="lg:col-span-2"><h2 class="text-4xl font-black mb-4 mt-0 tracking-tight italic text-primary">Kill the Bloat.</h2><p class="text-xl opacity-80 leading-relaxed">Stop shipping 100KB of "Framework" for 2KB of business logic. SigPro gives you the tools to build ultrafast, modern apps with <strong>True Vanilla Performance</strong>.</p></div></div></div>
<div class="text-center py-10 opacity-30 font-mono text-xs tracking-widest uppercase">Precision Reactive Engine — NatxoCC</div>

View File

@@ -8,7 +8,7 @@ The `each` function is a highperformance keyed list renderer. It maps a react
each(
source: Signal<any[]> | (() => any[]) | any[],
itemFn: (item: any, index: number) => Node | (() => Node),
keyFn?: (item: any, index: number) => string | number
keyField?: string
): HTMLElement
```
@@ -16,7 +16,7 @@ each(
| :--- | :--- | :--- | :--- |
| **`source`** | `Signal`, `() => any[]`, or `any[]` | Yes | The reactive array to iterate over. |
| **`itemFn`** | `(item, index) => Node` | Yes | Returns a DOM node (or a function that returns a node) for each item. |
| **`keyFn`** | `(item, index) => string/number` | No | Extracts a unique key. Default: `item?.id ?? index`. |
| **`keyField`** | `string` | No | Name of the property to use as unique key (e.g., `"id"`). Default: `item?.id ?? index`. |
**Returns:** A `div` with `style="display: contents"` that contains the live list.
@@ -26,7 +26,7 @@ each(
### 1. Basic Keyed List (Recommended)
Always provide a unique `id` as the key. This allows SigPro to reuse DOM nodes when the list is reordered or filtered.
Pass the name of the property that contains the unique identifier (e.g., `"id"`). This allows SigPro to reuse DOM nodes when the list is reordered or filtered.
```javascript
const users = $([
@@ -37,14 +37,14 @@ const users = $([
ul({ class: "list" }, [
each(users,
(user) => li({ class: "p-2" }, user.name),
(user) => user.id // stable unique key
"id" // ← use property "id" as stable key
)
]);
```
### 2. Automatic Key (Simple Lists)
If you omit the `keyFn`, `each` defaults to `item?.id ?? index`. For primitive arrays or objects without an `id`, the index is used.
If you omit the `keyField`, `each` defaults to `item?.id ?? index`. For primitive arrays or objects without an `id`, the index is used.
```javascript
const tags = $(["Tech", "JS", "Web"]);
@@ -55,7 +55,20 @@ div({ class: "flex gap-1" }, [
]);
```
### 3. Dynamic Content Using Functions
### 3. Using a Different Property Name
If your unique identifier is not called `id` (e.g., `_id`, `userId`, `slug`), just pass the property name as the third parameter:
```javascript
const products = $([
{ _id: 101, name: "Laptop" },
{ _id: 102, name: "Mouse" }
]);
each(products, (item) => li(item.name), "_id");
```
### 4. Dynamic Content Using Functions
If your `itemFn` returns a **function**, that function is reexecuted every time the items data changes (but the node is reused).
@@ -69,11 +82,11 @@ each(todos,
input({ type: "checkbox", checked: () => todo.done, onInput: e => todo.done = e.target.checked }),
span(() => todo.done ? s(todo.text) : todo.text)
]),
(todo) => todo.id
"id"
);
```
### 4. Source as a Plain Array or Function
### 5. Source as a Plain Array or Function
`source` can be a plain array (nonreactive) or a function that returns an array it will still react to changes if signals are read inside the function.
@@ -86,7 +99,7 @@ const filteredTodos = () => {
return all;
};
each(filteredTodos, (todo) => li(todo.text), (todo) => todo.id);
each(filteredTodos, (todo) => li(todo.text), "id");
```
---
@@ -95,7 +108,7 @@ each(filteredTodos, (todo) => li(todo.text), (todo) => todo.id);
When the `source` changes, `each`:
1. **Compares keys** between the old and new items using the `keyFn`.
1. **Compares keys** between the old and new items using the specified `keyField` (or `item.id` / index).
2. **Reuses existing DOM nodes** for keys that stay the same.
3. **Moves nodes** if order changed (no recreation).
4. **Creates new nodes** for new keys.
@@ -107,8 +120,8 @@ When the `source` changes, `each`:
## Performance Tips
- **Stable keys** Use a real `id` (like a database primary key). Avoid `Math.random()` or array `index` for lists that can be reordered.
- **State preservation** If a list item contains an input or a local state, using a stable key ensures that state is preserved even when the list is filtered or sorted.
- **Stable keys** Use a property that never changes (like a database primary key). Avoid `Math.random()` or array `index` for lists that can be reordered.
- **State preservation** If a list item contains an input or local state, using a stable key ensures that state is preserved even when the list is filtered or sorted.
- **Lazy item functions** If an item is expensive to render, wrap it in a function: `() => ExpensiveComponent(item)`. The component is only created when the item actually appears in the DOM.
---
@@ -151,7 +164,7 @@ const App = () =>
span(`${item.name} $${item.price}`),
button({ onClick: () => removeItem(item.id) }, "X")
]),
(item) => item.id
"id"
)
)
]);

View File

@@ -31,6 +31,8 @@ fx(
**Returns:** The same DOM node (or the child if it is not a `Node`), after applying the animation setup.
> **Availability:** `fx` is exported from the SigPro module. In **ESM** you must import it (`import { fx } from 'sigpro'`) or inject all globals via `sigpro()`. In the **IIFE** classic script, it is automatically available on `window`. The examples below assume the function is already in scope.
---
## Usage Patterns

View File

@@ -2,6 +2,8 @@
SigPro leverages the native power and efficiency of **signals** to create robust global stores with **zero complexity**. While other frameworks force you into heavy libraries and rigid boilerplate (Redux, Pinia, or Svelte stores), SigPro treats “the store” as a simple architectural choice: **defining a signal outside of a component.**
> **Availability:** `$` (and other core functions) are exported from the SigPro module. In **ESM** you must import them (`import { $ } from 'sigpro'`) or inject all globals via `sigpro()`. In the **IIFE** classic script, `$` is automatically available on `window`. The examples below assume `$` is already in scope (via import or global).
## Modular Organization (Zero Constraints)
You are not restricted to a single `store.js`. You can organize your state by **feature**, **domain**, or **page**. Since a SigPro store is just a standard JavaScript module exporting signals, you can name your files whatever you like (`auth.js`, `cart.js`, `settings.js`) to keep your logic clean.
@@ -12,7 +14,7 @@ Creating a dedicated file allows you to export only what you need. This modulari
```javascript
// auth.js
import { $ } from 'sigpro'; // or just rely on global `$` after import
import { $ } from 'sigpro';
// A simple global signal
export const user = $({ name: "Guest", loggedIn: false });
@@ -136,4 +138,4 @@ const TodoApp = () =>
]);
mount(TodoApp, "#app");
```
```

View File

@@ -2,6 +2,8 @@
The `h` function is the **core DOM builder** of SigPro. It creates DOM elements from a tag name, props, and children. While the global tag helpers (`div()`, `button()`, etc.) are built on top of `h`, you may need `h` directly for dynamic tag names or when you prefer an explicit function style.
> **Availability:** `h` and all tag helpers (`div`, `button`, etc.) are exported from the SigPro module. In **ESM** you must import them (`import { h, div, button } from 'sigpro'`) or inject all globals via `sigpro()`. In the **IIFE** classic script, `h` and all tag helpers are automatically available on `window`. The examples below assume the functions are already in scope.
## Function Signature
```typescript
@@ -120,16 +122,16 @@ h('svg', { width: 100, height: 100 }, [
---
## `h` vs Global Tag Helpers
## `h` vs Tag Helpers
| Feature | `h('div', ...)` | `div(...)` |
| Feature | `h('div', ...)` | `div(...)` (tag helper) |
| :--- | :--- | :--- |
| **Dynamic tag names** | ✅ `h(tagName, ...)` | ❌ Must know tag name at write time |
| **Explicit style** | More verbose | Cleaner, DSLlike |
| **Tree shaking** | Same | Same (helpers are generated once) |
| **Availability** | Import or global | Import or global (same) |
| **Performance** | Identical | Identical (helpers call `h` internally) |
> **Recommendation:** Use global tag helpers (`div()`, `button()`, etc.) for most cases they are shorter and more readable. Use `h` directly only when the tag name is dynamic (e.g., `h(props.tag, ...)`).
> **Recommendation:** Use tag helpers (`div()`, `button()`, etc.) for most cases they are shorter and more readable. Use `h` directly only when the tag name is dynamic (e.g., `h(props.tag, ...)`). Remember that in ESM you need to import the helpers or call `sigpro()` to make them global.
---
@@ -155,5 +157,5 @@ mount(App, '#app');
- `h` is the lowlevel DOM builder used internally by all tag helpers.
- It supports reactive attributes, reactive children, twoway binding, event listeners, and SVG.
- Use `h` directly when you need a **dynamic tag name**; otherwise, prefer the convenient global helpers.
- Components written with `h` are fully reactive and automatically cleaned up.
- Use `h` directly when you need a **dynamic tag name**; otherwise, prefer the convenient tag helpers (import them or inject globally).
- Components written with `h` are fully reactive and automatically cleaned up.

View File

@@ -1,14 +1,3 @@
Aquí tienes el archivo `h.md` actualizado, que ahora incluye:
- La función `h` (hyperscript)
- Los helpers globales de etiquetas (lowercase)
- Una nueva sección sobre **JSX con SigPro** (configuración, ejemplos y alternativas como `htm`).
El documento está en inglés, como los originales, y listo para integrarse en tu documentación.
---
```markdown
# Hyperscript & Tag Helpers
SigPro provides two complementary ways to create DOM elements:
@@ -318,6 +307,3 @@ mount(App, '#app');
| **`htm`** | Optional | `` html`<div>...</div>` `` | Buildless but HTMLlike syntax |
> **Tip:** All approaches are fully reactive, support twoway binding, events, SVG, and automatic cleanup. Choose the one that fits your workflow.
```
```

View File

@@ -17,6 +17,8 @@ mount(component: Function | Node, target: string | HTMLElement): RuntimeObject
- `container`: The actual DOM element created by the renderer.
- `destroy()`: A method to completely unmount and clean up the application.
> **Availability:** `mount` is exported from the SigPro module. In **ESM** you must import it (`import { mount } from 'sigpro'`) or inject all globals via `sigpro()`. In the **IIFE** classic script, it is automatically available on `window`. The examples below assume the function is already in scope.
---
## Usage Patterns
@@ -145,4 +147,4 @@ setTimeout(() => runtime.destroy(), 10000);
| Manual destruction | `const app = mount(App, '#app'); app.destroy();` |
| Autoreplace on same target | Just call `mount` again SigPro handles cleanup. |
> **Note:** The function name is `mount` (lowercase). It is exported from SigPro and also available globally after importing the library. The target must exist in the DOM at the time of mounting.
> **Note:** The target must exist in the DOM at the time of mounting.

View File

@@ -1,10 +1,12 @@
# ⚡ SigPro 1.2.18 Complete API Reference
# ⚡ SigPro Complete API Reference
SigPro is a **RealDOM first** reactive microframework. No virtual DOM, no diffing overhead it updates the DOM directly with surgical precision. Builtin automatic cleanup prevents memory leaks, and the API is designed to be both tiny and powerful.
```javascript
import { $, $$, watch, h, when, each, fx, router, req, mount, batch } from 'sigpro'
// or use globally as window.$ etc.
// Or, if you prefer the global style in an ESM environment:
// import { sigpro } from 'sigpro'; sigpro(); // then $, h, div... become window globals
// In a classic IIFE script (<script src="sigpro.js">), everything is available globally automatically.
```
---
@@ -106,15 +108,23 @@ h('div', {}, [
### Tag shortcuts
SigPro defines **all standard HTML5 tags** as PascalCase globals (when run in browser) and also exports them as named exports. Example:
When using the **ESM module with named imports**, you can import the tag helpers individually:
```javascript
Div({ class: 'container' }, [
H1({}, 'Title'),
Button({ onClick: () => alert('hi') }, 'Click me')
import { div, h1, button } from 'sigpro'
div({ class: 'container' }, [
h1({}, 'Title'),
button({ onClick: () => alert('hi') }, 'Click me')
])
```
If you prefer the **global style** (all tags and core functions on `window`), either:
- Use the classic IIFE script: `<script src="sigpro.js"></script>`
- Or in ESM, call `sigpro()` after importing: `import { sigpro } from 'sigpro'; sigpro();`
After that, you can write `div()`, `span()`, etc. directly, without any import.
Available tags: `a`, `abbr`, `article`, `aside`, `audio`, `b`, `blockquote`, `br`, `button`, `canvas`, `caption`, `cite`, `code`, `col`, `colgroup`, `datalist`, `dd`, `del`, `details`, `dfn`, `dialog`, `div`, `dl`, `dt`, `em`, `embed`, `fieldset`, `figcaption`, `figure`, `footer`, `form`, `h1``h6`, `header`, `hr`, `i`, `iframe`, `img`, `input`, `ins`, `kbd`, `label`, `legend`, `li`, `main`, `mark`, `meter`, `nav`, `object`, `ol`, `optgroup`, `option`, `output`, `p`, `picture`, `pre`, `progress`, `section`, `select`, `slot`, `small`, `source`, `span`, `strong`, `sub`, `summary`, `sup`, `svg`, `table`, `tbody`, `td`, `template`, `textarea`, `tfoot`, `th`, `thead`, `time`, `tr`, `u`, `ul`, `video`.
---
@@ -128,8 +138,8 @@ Reactive conditional rendering. `condition` can be a boolean, a signal, or any f
```javascript
when(
() => user.loggedIn(),
() => Div({}, 'Welcome back!'),
() => Button({ onClick: () => login() }, 'Login')
() => div({}, 'Welcome back!'),
() => button({ onClick: () => login() }, 'Login')
)
```
@@ -152,19 +162,7 @@ When the array changes, elements are added, removed, or reordered with minimal D
---
## 💥 Effects & Lifecycle
### `onUnmount(fn)`
Inside a component (function called from `h`), registers a cleanup function that runs when that component is removed from the DOM.
```javascript
const Timer = () => {
const interval = setInterval(() => console.log('tick'), 1000)
onUnmount(() => clearInterval(interval))
return Div({}, 'Timer running')
}
```
## 💥 Batch
### `batch(fn)`
@@ -178,16 +176,6 @@ batch(() => {
})
```
### `untrack(fn)`
Run a function without tracking any signal reads.
```javascript
const logCount = () => {
untrack(() => console.log('count is', count()))
}
```
---
## ✨ Animations `fx(options, child)`
@@ -218,14 +206,14 @@ Hashbased SPA router. Returns a DOM node that renders the current route.
```javascript
const routes = [
{ path: '/', component: () => Div({}, 'Home') },
{ path: '/user/:id', component: (params) => Div({}, `User ${params.id}`) },
{ path: '*', component: () => Div({}, '404') }
{ path: '/', component: () => div({}, 'Home') },
{ path: '/user/:id', component: (params) => div({}, `User ${params.id}`) },
{ path: '*', component: () => div({}, '404') }
]
const App = () => Div({}, [
A({ href: '#/' }, 'Home'),
A({ href: '#/user/42' }, 'User 42'),
const App = () => div({}, [
a({ href: '#/' }, 'Home'),
a({ href: '#/user/42' }, 'User 42'),
router(routes)
])
```
@@ -312,11 +300,11 @@ import { $, watch, h, mount } from 'sigpro'
const count = $(0, 'counter') // persists in localStorage
const App = () =>
Div({ class: 'counter' }, [
H1({}, () => `Count: ${count()}`),
Button({ onClick: () => count(count() + 1) }, '+'),
Button({ onClick: () => count(count() - 1) }, '-'),
Button({ onClick: () => count(0) }, 'Reset')
div({ class: 'counter' }, [
h1({}, () => `Count: ${count()}`),
button({ onClick: () => count(count() + 1) }, '+'),
button({ onClick: () => count(count() - 1) }, '-'),
button({ onClick: () => count(0) }, 'Reset')
])
mount(App, '#app')
@@ -332,22 +320,8 @@ You can rename everything in one line:
import { $ as signal, watch as effect, h as element, mount as render } from 'sigpro'
```
Or assign globally:
Or assign globally (after calling `sigpro()` or using the classic script):
```javascript
window.myReactive = $
```
All functions are also exposed on the global `window` object when included via `<script>`.
---
## 📜 License & Version
Current version: **1.2.18**
Released under MIT.
Zero dependencies, ~3KB gzipped.
---
> **Need legacy IE support?** Not supported requires modern JavaScript (Proxy, WeakMap, etc.).
```

View File

@@ -26,6 +26,8 @@ req(config: {
**Returns:** A controller object with reactive signals and methods.
> **Availability:** `req` is exported from the SigPro module. In **ESM** you must import it (`import { req } from 'sigpro'`) or inject all globals via `sigpro()`. In the **IIFE** classic script, it is automatically available on `window`. The examples below assume the function is already in scope.
---
## Usage Patterns
@@ -179,4 +181,4 @@ mount(App, '#app');
| `abort()` | `() => void` | Cancels the current request. |
| `loading` | `Signal<boolean>` | `true` while request is in flight. |
| `error` | `Signal<string\|null>` | Contains an error message, or `null`. |
| `data` | `Signal<any\|null>` | Contains the parsed response (JSON), or `null`. |
| `data` | `Signal<any\|null>` | Contains the parsed response (JSON), or `null`. |

View File

@@ -17,6 +17,8 @@ router(routes: Route[]): HTMLElement
**Returns:** A `div` element (with class `"router-hook"`) that acts as the router outlet. The router automatically destroys the previous view and mounts the matched component when the hash changes.
> **Availability:** `router` and its helper methods (`router.to`, `router.back`, `router.path`, `router.params`) are exported from the SigPro module. In **ESM** you must import them (`import { router } from 'sigpro'`) or inject all globals via `sigpro()`. In the **IIFE** classic script, they are automatically available on `window`. The examples below assume the functions are already in scope.
---
## Usage Patterns

View File

@@ -27,7 +27,7 @@ Creates a writable signal. It returns a function that acts as both **getter** an
<div id="demo-signal-simple"></div>
```js
```javascript
{
const count = $(0);
const App = () => div({ class: "example" }, [
@@ -44,7 +44,7 @@ Creates a writable signal that syncs with the browser's storage.
<div id="demo-signal-persist"></div>
```js
```javascript
{
const theme = $("light", "theme-persist-demo");
const App = () => div([
@@ -62,7 +62,7 @@ Creates a read-only signal that updates automatically when any signal used insid
<div id="demo-signal-computed"></div>
```js
```javascript
{
const price = $(100);
const tax = $(0.21);
@@ -86,7 +86,7 @@ When calling the setter, you can pass an **updater function** to access the curr
<div id="demo-signal-updater"></div>
```js
```javascript
{
const list = $(["A", "B"]);
const App = () => div([
@@ -123,7 +123,7 @@ $$<T extends object>(obj: T): T
<div id="demo-dollar-simple"></div>
```js
```javascript
{
const state = $$({ count: 0, name: "Juan" });
watch(() => console.log(`Count is now ${state.count}`));
@@ -141,7 +141,7 @@ $$<T extends object>(obj: T): T
<div id="demo-dollar-deep"></div>
```js
```javascript
{
const user = $$({
profile: {
@@ -164,7 +164,7 @@ $$<T extends object>(obj: T): T
<div id="demo-dollar-array"></div>
```js
```javascript
{
const todos = $$([
{ id: 1, text: "Learn SigPro", done: false },
@@ -186,7 +186,7 @@ $$<T extends object>(obj: T): T
<div id="demo-dollar-mixed"></div>
```js
```javascript
{
const form = $$({
fields: { email: "", password: "" },
@@ -232,7 +232,7 @@ $$<T extends object>(obj: T): T
<div id="demo-use-dollar"></div>
```js
```javascript
{
const count = $(0);
const firstName = $("John");
@@ -254,7 +254,7 @@ $$<T extends object>(obj: T): T
<div id="demo-use-dollar-dollar"></div>
```js
```javascript
{
const form = $$({ email: "", password: "" });
const settings = $$({ theme: "dark", notifications: true });
@@ -275,7 +275,7 @@ $$<T extends object>(obj: T): T
## Important Notes
### ✅ DO:
```js
```javascript
// Access properties directly
state.count = 10;
state.user.name = "Ana";
@@ -287,7 +287,7 @@ watch(() => state.user.name, () => {});
```
### ❌ DON'T:
```js
```javascript
// Destructuring breaks reactivity
const { count, user } = state; // ❌ count and user are not reactive
@@ -326,7 +326,7 @@ Like all SigPro reactive primitives, `$$()` integrates with the cleanup system:
<div id="demo-complete"></div>
```js
```javascript
{
const app = {
theme: $("dark", "theme_complete"),
@@ -372,7 +372,7 @@ Like all SigPro reactive primitives, `$$()` integrates with the cleanup system:
If you have code using nested signals:
```js
```javascript
// Before - Manual nesting
const user = $({
name: $(""),

View File

@@ -1,23 +1,48 @@
# Global Tag Helpers
In **SigPro**, you don't need to manually type `h('div', ...)` for every element. To keep your code declarative and readable, the engine automatically generates **helper functions** for all standard HTML5 tags upon initialization.
In **SigPro**, you don't need to manually type `h('div', ...)` for every element. To keep your code declarative and readable, the engine provides **helper functions** for all standard HTML5 tags.
## 1. How it Works
SigPro iterates through a list of standard HTML tags and attaches a wrapper function for each one directly to the `window` object. This creates a specialized **DSL** (Domain Specific Language) that looks like a template engine but is **100% standard JavaScript**.
SigPro iterates through a list of standard HTML tags and creates a wrapper function for each one.
- **Under the hood:** `h('button', { onclick: ... }, 'Click')`
- **SigPro Style:** `button({ onclick: ... }, 'Click')`
* **Under the hood:** `h('button', { onclick: ... }, 'Click')`
* **SigPro Style:** `button({ onclick: ... }, 'Click')`
> **Note:** All tag helpers are **lowercase** (e.g., `div`, `span`, `button`). This keeps the syntax close to raw HTML.
> **Note:** All tag helpers are **lowercase** (e.g. `div`, `span`, `button`). PascalCase versions (`Div`, `Span`, `Button`) are **not** created. This keeps the syntax close to raw HTML.
These helpers can be used in two ways, depending on your environment:
### Mode A: Classic (IIFE) Autoglobal
When you load the **IIFE bundle** (`sigpro.js`) with a traditional `<script>` tag (no `type="module"`), all tag helpers are automatically injected into the `window` object.
```html
<script src="https://cdn.jsdelivr.net/npm/sigpro@1.2.19/dist/sigpro.js"></script>
<script>
// div, span, button, ... are already global
const App = () => div({ class: "card" }, "Hello");
</script>
```
### Mode B: ESM (Modern) Explicit or Imported
When you import the **ES module** (via `import` or CDN with `type="module"`), nothing is added to `window` by default. You have two options:
1. **Manual global injection** import `sigpro` and call it:
```javascript
import { sigpro } from 'sigpro';
sigpro(); // now div, span, button, etc. become global
```
2. **Named imports** (recommended) import the helpers you need directly:
```javascript
import { div, span, button } from 'sigpro';
// use them directly
```
---
## 2. The Complete Global Registry
## 2. The Complete List of Tag Helpers
The following functions are injected into the global scope using **lowercase** names to match HTML tags:
All helpers are **lowercase** and follow HTML5 tag names. You can use them globally (after injection) or import them individually.
| Category | Available Global Functions |
| Category | Available functions |
| :--- | :--- |
| **Structure** | `div`, `span`, `p`, `section`, `nav`, `main`, `header`, `footer`, `article`, `aside` |
| **Typography** | `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `ul`, `ol`, `li`, `dl`, `dt`, `dd`, `strong`, `em`, `code`, `pre`, `small`, `b`, `u`, `mark` |
@@ -26,26 +51,24 @@ The following functions are injected into the global scope using **lowercase** n
| **Tables** | `table`, `thead`, `tbody`, `tr`, `th`, `td`, `tfoot`, `caption` |
| **Media** | `img`, `canvas`, `video`, `audio`, `svg`, `iframe`, `picture`, `source` |
Full list includes: `a`, `abbr`, `article`, `aside`, `audio`, `b`, `blockquote`, `br`, `button`, `canvas`, `caption`, `cite`, `code`, `col`, `colgroup`, `datalist`, `dd`, `del`, `details`, `dfn`, `dialog`, `div`, `dl`, `dt`, `em`, `embed`, `fieldset`, `figcaption`, `figure`, `footer`, `form`, `h1``h6`, `header`, `hr`, `i`, `iframe`, `img`, `input`, `ins`, `kbd`, `label`, `legend`, `li`, `main`, `mark`, `meter`, `nav`, `object`, `ol`, `optgroup`, `option`, `output`, `p`, `picture`, `pre`, `progress`, `section`, `select`, `slot`, `small`, `source`, `span`, `strong`, `sub`, `summary`, `sup`, `svg`, `table`, `tbody`, `td`, `template`, `textarea`, `tfoot`, `th`, `thead`, `time`, `tr`, `u`, `ul`, `video`.
Full list includes all standard tags: `a`, `abbr`, `article`, `aside`, `audio`, `b`, `blockquote`, `br`, `button`, `canvas`, `caption`, `cite`, `code`, `col`, `colgroup`, `datalist`, `dd`, `del`, `details`, `dfn`, `dialog`, `div`, `dl`, `dt`, `em`, `embed`, `fieldset`, `figcaption`, `figure`, `footer`, `form`, `h1`…`h6`, `header`, `hr`, `i`, `iframe`, `img`, `input`, `ins`, `kbd`, `label`, `legend`, `li`, `main`, `mark`, `meter`, `nav`, `object`, `ol`, `optgroup`, `option`, `output`, `p`, `picture`, `pre`, `progress`, `section`, `select`, `slot`, `small`, `source`, `span`, `strong`, `sub`, `summary`, `sup`, `svg`, `table`, `tbody`, `td`, `template`, `textarea`, `tfoot`, `th`, `thead`, `time`, `tr`, `u`, `ul`, `video`.
---
## 3. Usage Patterns
SigPro tag helpers are flexible. They automatically detect if you are passing attributes, children, or both.
### A. Attributes + Children
```javascript
div({ class: 'container', id: 'main' }, [
h1("Welcome to SigPro"),
p("The zero-VDOM framework.")
p("The zeroVDOM framework.")
]);
```
### B. Children Only
If you don't need attributes, you can pass the content directly as the first argument.
If you don't need attributes, pass the content directly as the first argument.
```javascript
section([
@@ -74,7 +97,7 @@ div({
### TwoWay Binding (Automatic)
SigPro automatically bridges the **signal** and the **input element** bidirectionally when you assign a signal to `value` or `checked`.
Assign a **signal** directly to `value` or `checked` on form inputs SigPro automatically bridges the signal and the input element bidirectionally.
```javascript
const search = $("");
@@ -86,11 +109,11 @@ input({
});
```
> **Pro Tip:** If you want an input to be **readonly** but still reactive, wrap the signal in an anonymous function: `value: () => search()`. This prevents backward synchronization.
> **Pro Tip:** To make an input **readonly** but still reactive, wrap the signal in a function: `value: () => search()` this prevents backward synchronization.
### Dynamic Children
You can pass a function as a child it will be reexecuted whenever any signal inside changes, and the DOM will be patched surgically.
You can pass a **function as a child** it will be reexecuted whenever any signal inside changes, and the DOM will be patched surgically.
```javascript
const count = $(0);
@@ -103,9 +126,9 @@ div([
---
## 5. Custom Components with `h()`
## 5. Custom Components with `h()` or Tag Helpers
While the global tag helpers cover all standard HTML tags, you can create reusable components using the `h` function directly (or by returning the result of tag helpers).
While the tag helpers cover all standard HTML tags, you can create reusable components using them directly.
### Basic Component
@@ -151,7 +174,7 @@ const Timer = () => {
| Use case | Recommendation |
| :--- | :--- |
| Standard tags (`div`, `span`, `button`) | Use global helpers: `div()`, `span()`, `button()` |
| Standard tags (`div`, `span`, `button`) | Use tag helpers: `div()`, `span()`, `button()` |
| Dynamic tag names (unknown at write time) | Use `h(tagName, props, children)` |
| Components returning a single node | Any function that returns a node (using helpers or `h`) |
@@ -162,13 +185,17 @@ const Timer = () => {
## 7. Complete Example
```javascript
// In a modern ESM environment (recommended)
import { div, h1, input, p, button, mount, $ } from 'sigpro';
const nameSignal = $('');
const App = () =>
div({ class: "app" }, [
h1("Welcome"),
input({
placeholder: "Your name",
value: nameSignal,
onInput: (e) => nameSignal(e.target.value)
value: nameSignal
}),
p(() => `Hello, ${nameSignal() || "stranger"}!`),
button({ onClick: () => alert("Clicked") }, "Click me")
@@ -177,27 +204,41 @@ const App = () =>
mount(App, '#app');
```
---
Or using the classic script (autoglobal):
<div class="alert alert-info">
<div>
<h3>Important Notes</h3>
<ul>
<li><b>Naming:</b> All tag helpers are <b>lowercase</b>. There are no PascalCase helpers (<code>Div</code>, <code>Button</code>).</li>
<li><b>Global availability:</b> After importing SigPro (via <code>import 'sigpro'</code> or CDN), all helpers are on <code>window</code>. You can use them anywhere without importing.</li>
<li><b>Custom components:</b> Use PascalCase for your own component functions to visually distinguish them from builtin tags (e.g., <code>UserCard</code>).</li>
</ul>
</div>
</div>
```html
<script src="https://cdn.jsdelivr.net/npm/sigpro@1.2.19/dist/sigpro.js"></script>
<script>
const nameSignal = $('');
const App = () => div({ class: "app" }, [
h1("Welcome"),
input({ placeholder: "Your name", value: nameSignal }),
p(() => `Hello, ${nameSignal() || "stranger"}!`),
button({ onClick: () => alert("Clicked") }, "Click me")
]);
mount(App, '#app');
</script>
```
---
## 8. Summary
## 8. Important Notes
- **Naming:** All tag helpers are **lowercase** no PascalCase helpers (`Div`, `Button`).
- **Global availability:**
- **IIFE script** → automatically on `window`.
- **ESM module** → not global by default; use `import { div } from 'sigpro'` or call `sigpro()` to inject all globals.
- **Custom components:** Use **PascalCase** for your own component functions (e.g., `UserCard`) to visually distinguish them from builtin tags.
---
## 9. Summary
| Feature | Description |
| :--- | :--- |
| **Tag helpers** | Lowercase functions for every HTML element (e.g., `div()`, `button()`). |
| **Availability** | Autoglobal in IIFE; in ESM use named imports or `sigpro()`. |
| **Reactive attributes** | Pass a function to any attribute to keep it synced. |
| **Twoway binding** | Assign a signal directly to `value` or `checked` on form elements. |
| **Dynamic children** | Pass a function as a child for live updating content. |
| **Autocleanup** | All effects, events, and children are disposed when the element is removed. |
| **Autocleanup** | All effects, events, and children are disposed when the element is removed. |

View File

@@ -20,6 +20,8 @@ watch(deps: Signal[], callback: (values: any[]) => void): StopFunction
**Returns:** A `StopFunction` that, when called, destroys the watcher and releases memory.
> **Availability:** `watch` is exported from the SigPro module. In **ESM** you must import it (`import { watch } from 'sigpro'`) or inject all globals via `sigpro()`. In the **IIFE** classic script, it is automatically available on `window`. The examples below assume the function is already in scope.
---
## Usage Patterns
@@ -95,7 +97,7 @@ This is achieved via `queueMicrotask`, ensuring optimal performance.
## Key Points
- **Function name:** `watch` (lowercase) exported from SigPro and also available globally.
- **Function name:** `watch` (lowercase) exported from SigPro and also available globally (depending on environment).
- **Auto mode:** `watch(fn)` automatically tracks any signals read inside `fn`.
- **Explicit mode:** `watch([sig1, sig2], (values) => {...})` only reruns when listed signals change; callback receives an array of their new values.
- **Stop function:** returned by both modes; call it to dispose the effect and its children.
@@ -119,5 +121,4 @@ watch([count, step], ([newCount, newStep]) => {
count(5); // logs: auto + explicit
step(2); // logs: explicit only (auto does not track step)
```
```

View File

@@ -20,7 +20,7 @@ when(
**Returns:** A `div` with `style="display:contents"` that acts as an anchor for the dynamic content. This element is part of the DOM and will be replaced/updated automatically.
> **Note:** The function name is `when` (lowercase). It is exported from SigPro and also available globally after importing.
> **Availability:** `when` is exported from the SigPro module. In **ESM** you must import it (`import { when } from 'sigpro'`) or inject all globals via `sigpro()`. In the **IIFE** classic script, it is automatically available on `window`. The examples below assume the function is already in scope.
---
@@ -129,4 +129,4 @@ const App = () =>
]);
mount(App, '#app');
```
```

View File

@@ -67,40 +67,5 @@
<script src="./sigpro.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script>
<style>
button, input {
font-family: inherit;
font-size: 1rem;
}
button {
background-color: #3b82f6;
color: white;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
border: none;
cursor: pointer;
margin: 0.25rem;
transition: background-color 0.2s;
}
button:hover {
background-color: #2563eb;
}
input {
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 0.375rem;
margin: 0.25rem;
background-color: white;
}
input:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 2px rgba(59,130,246,0.2);
}
/* Opcional: para listas y párrafos dentro de demos */
.example, div:has(> button) {
padding: 0.5rem;
}
</style>
</body>
</html>

View File

@@ -1,4 +1,4 @@
# Installation & Setup (SigPro 1.2.18)
# Installation & Setup
SigPro is designed to be drop-in ready. Whether you are building a complex application with a bundler or a simple reactive widget in a single HTML file, SigPro scales with your needs.
@@ -42,14 +42,40 @@ bun add sigpro
```
</div>
<input type="radio" name="install_method" class="tab border-base-300 whitespace-nowrap" aria-label="CDN (ESM)" />
<div class="tab-content bg-base-100 border-base-300 rounded-box p-6">
```html
<script type="module">
// Import the core it auto-installs itself globally
import 'https://cdn.jsdelivr.net/npm/sigpro@1.2.18/+esm';
// Now $, $$, watch, h, when, each, fx, router, req, mount, batch and all lowercase tag helpers (div, button, etc.) are available
// Import the module no automatic global injection
import { sigpro, $, h, mount } from 'https://cdn.jsdelivr.net/npm/sigpro@1.2.19/+esm';
// Option A: manually inject all globals (like the classic script)
sigpro(); // now $, h, div, watch, etc. are on window
// Option B: use named imports (no global pollution)
const count = $(0);
mount(() => h1(() => `Count: ${count()}`), '#app');
</script>
```
</div>
<input type="radio" name="install_method" class="tab border-base-300 whitespace-nowrap" aria-label="CDN (IIFE)" />
<div class="tab-content bg-base-100 border-base-300 rounded-box p-6">
```html
<!-- Classic script: autoinstalls everything on window -->
<script src="https://cdn.jsdelivr.net/npm/sigpro@1.2.19/dist/sigpro.js"></script>
<script>
// $, h, div, button, watch, ... are already global
const count = $(0);
const App = () => div({ class: "card" }, [
h1(() => `Count: ${count()}`),
button({ onclick: () => count(count() + 1) }, "Increment")
]);
mount(App, '#app');
</script>
```
@@ -63,31 +89,26 @@ bun add sigpro
SigPro uses **lowercase** Tag Helpers (e.g., `div`, `button`) to keep the syntax close to raw HTML, while still being pure JavaScript functions.
<div class="tabs tabs-box w-full mt-8 mb-12 bg-base-200/50 p-2 rounded-xl border border-base-300">
<input type="radio" name="quick_start_tabs" class="tab !rounded-lg" aria-label="Mainstream (Bundlers)" checked />
<input type="radio" name="quick_start_tabs" class="tab !rounded-lg" aria-label="Bundlers (ESM)" checked />
<div class="tab-content bg-base-100 border-base-300 rounded-lg p-6 mt-2">
```javascript
// File: App.js
import 'sigpro'; // auto-installs globals
// App.js Using named imports (recommended)
import { $, h1, button, div, mount } from 'sigpro';
export const App = () => {
const count = $(0);
// Tag helpers like div, h1, button are available globally (lowercase)
return div({ class: "card p-4" }, [
h1(() => `Count is: ${count()}`),
button(
{
class: "btn btn-primary",
onclick: () => count(count() + 1),
},
{ class: "btn btn-primary", onclick: () => count(count() + 1) },
"Increment"
),
]);
};
// File: main.js
import 'sigpro';
// main.js
import { mount } from 'sigpro';
import { App } from './App.js';
mount(App, '#app');
@@ -104,23 +125,19 @@ mount(App, '#app');
<body>
<div id="app"></div>
<script type="module">
import 'https://cdn.jsdelivr.net/npm/sigpro@1.2.18/+esm';
<script src="https://cdn.jsdelivr.net/npm/sigpro@1.2.19/dist/sigpro.js"></script>
<script>
// Everything is already global no import needed
const name = $('Developer');
// Lowercase tag helpers: section, h2, input
const App = () =>
section({ class: "container" }, [
h2(() => `Welcome, ${name()}`),
input({
type: "text",
class: "input input-bordered",
value: name, // ✅ Two-way binding: signal as value + automatic input event
placeholder: "Type your name...",
}),
]);
const App = () => section({ class: "container" }, [
h2(() => `Welcome, ${name()}`),
input({
type: "text",
class: "input input-bordered",
value: name,
placeholder: "Type your name...",
}),
]);
mount(App, '#app');
</script>
</body>
@@ -132,26 +149,42 @@ mount(App, '#app');
---
## 3. Global by Design
## 3. Global by Design (Two Modes)
One of SigPro's core strengths is its **Global API**, which eliminates "Import Hell" while remaining ESM-compatible.
SigPro gives you full control over global pollution.
- **The "Zero-Config" Import:** By simply adding `import 'sigpro'` (or importing from the CDN), the framework automatically "hydrates" the global `window` object.
- **Core Functions:** You get immediate access to `$`, `$$`, `watch`, `h`, `when`, `each`, `fx`, `router`, `req`, `mount`, `batch` anywhere in your scripts.
- **Auto-Installation:** This happens instantly upon import thanks to its built-in selfinstallation, making it "Plug & Play" for both local projects and CDN usage.
### Mode A: Classic (IIFE) Autoinjection
When you load the **IIFE bundle** (`sigpro.js`) with a traditional `<script>` tag (no `type="module"`), the library automatically injects:
- All core functions (`$`, `$$`, `watch`, `h`, `when`, `each`, `fx`, `router`, `req`, `mount`, `batch`) into `window`.
- Lowercase tag helpers (`div`, `span`, `button`, etc.) also become global functions.
- **Lowercase Tag Helpers:** All standard HTML tags are pre-registered as global functions (`div`, `span`, `button`, `section`, `input`, `h1`, `h2`, etc.).
- **Clean UI Syntax:** Write UI structures that look almost like HTML but are pure, reactive JavaScript: `div({ class: "card" }, [ h1("Title") ])`.
✅ Zero configuration just drop the script and start coding.
- **Tree Shaking Friendly:** For maximum optimization, you can still use named imports: `import { $, watch, mount } from 'sigpro'`. Modern bundlers (Vite, esbuild) will prune unused code.
### Mode B: ESM (Modern) Explicit Injection
When you import the **ESM module** (from CDN or via `import`), **nothing** is added to `window` by default. You have two clean options:
- **Custom Components:** We recommend using **PascalCase** for your own components (e.g., `UserCard()`) to distinguish them from built-in lowercase tag helpers.
1. **Named imports** (recommended for most apps):
```javascript
import { $, h, mount } from 'sigpro';
```
No global pollution, perfect for bundlers and large projects.
2. **Manual global injection** (similar to classic mode but controlled):
```javascript
import { sigpro } from 'sigpro';
sigpro(); // now $, h, div, button, ... are on window
```
Useful for quick prototyping or when you prefer the global style.
### Why two modes?
- **Legacy / nobuild**: Use the IIFE script and get everything automatically.
- **Modern ESM**: Keep your global namespace clean, leverage treeshaking, or inject only when you need it.
---
## 4. Why no build step?
Because SigPro uses **native ES Modules** and standard JavaScript functions to generate the DOM, you don't actually _need_ a compiler like Babel or a transformer for JSX.
Because SigPro uses **native ES Modules** and standard JavaScript functions to generate the DOM, you don't actually *need* a compiler like Babel or a transformer for JSX.
- **Development:** Just save and refresh. Pure JS, no "transpilation" required.
- **Performance:** Extremely lightweight. Use any modern bundler (Vite, esbuild) only when you are ready to minify and tree-shake for production.
@@ -177,7 +210,7 @@ SigPro stands out by removing the "Build Step" tax and the "Virtual DOM" overhea
- **Fine-Grained Reactivity**: State changes only trigger updates where the data is actually used, not on the entire component.
- **Native Web Standards**: Everything is a standard JS function. No custom template syntax to learn.
- **Zero Magic**: No hidden compilers. What you write is what runs in the browser.
- **Global by Design**: Tag helpers and core functions are available globally to eliminate "Import Hell" and keep your code clean.
- **Global by Design** (with control): Tag helpers and core functions can be globally available (IIFE) or imported on demand (ESM) you choose.
---
@@ -185,4 +218,4 @@ SigPro stands out by removing the "Build Step" tax and the "Virtual DOM" overhea
SigPro isn't just another framework; it's a bridge to the native web. By using standard ES Modules and functional DOM generation, you get the benefits of a modern reactive library with the weight of a utility script.
**Because, in the end... why fight the web when we can embrace it?**
**Because, in the end... why fight the web when we can embrace it?**