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

@@ -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');
```
```