New modular Sigpro
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 3s
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 3s
This commit is contained in:
184
docs/api/fx.md
184
docs/api/fx.md
@@ -1,184 +0,0 @@
|
||||
# Animation Helper: `fx( )`
|
||||
|
||||
The `fx` function applies simple **enter animations** to DOM elements. You can either use a predefined CSS keyframes animation or declare inline transition effects (scale, slide, rotate, blur). It is designed to be used when dynamically creating elements – especially inside `when` or `each` branches.
|
||||
|
||||
## Function Signature
|
||||
|
||||
```typescript
|
||||
fx(
|
||||
options: {
|
||||
name?: string; // CSS keyframes animation name (will append '-in')
|
||||
duration?: number; // Animation duration in ms (default: 200)
|
||||
scale?: boolean; // Start with scale(0.95) → none
|
||||
slide?: boolean; // Start with translateY(-10px) → none
|
||||
rotate?: boolean; // Start with rotate(-2deg) → none
|
||||
blur?: boolean; // Start with blur(4px) → none
|
||||
},
|
||||
child: Node | (() => Node)
|
||||
): Node
|
||||
```
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **`options`** | `object` | Yes | Animation configuration. |
|
||||
| **`options.name`** | `string` | No | Name of a CSS `@keyframes` animation. The actual animation name becomes `${name}-in`. |
|
||||
| **`options.duration`** | `number` | No | Duration in milliseconds (default `200`). |
|
||||
| **`options.scale`** | `boolean` | No | Add a scale transform from `0.95` to `none`. |
|
||||
| **`options.slide`** | `boolean` | No | Add a vertical slide from `translateY(-10px)` to `none`. |
|
||||
| **`options.rotate`** | `boolean` | No | Add a small rotation from `rotate(-2deg)` to `none`. |
|
||||
| **`options.blur`** | `boolean` | No | Add a blur filter from `blur(4px)` to `none`. |
|
||||
| **`child`** | `Node` or `() => Node` | Yes | The element to animate. If a function is passed, it is called to obtain the node. |
|
||||
|
||||
**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
|
||||
|
||||
### 1. Named CSS Keyframes Animation
|
||||
|
||||
Define a `@keyframes` rule in your CSS, for example:
|
||||
|
||||
```css
|
||||
@keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
```
|
||||
|
||||
Then apply it with `fx`:
|
||||
|
||||
```javascript
|
||||
const MyComponent = () =>
|
||||
fx({ name: "fade", duration: 300 },
|
||||
div("I will fade in")
|
||||
);
|
||||
```
|
||||
|
||||
> The animation name used is `${name}-in`. In this example: `fade-in`.
|
||||
|
||||
### 2. Inline Transition (Scale + Opacity)
|
||||
|
||||
No CSS keyframes needed. The element starts with `opacity: 0` and `transform: scale(0.95)`, then transitions to `opacity: 1` and `transform: none`.
|
||||
|
||||
```javascript
|
||||
fx({ scale: true, duration: 200 },
|
||||
button({ onClick: () => alert("Hi") }, "Click me")
|
||||
);
|
||||
```
|
||||
|
||||
### 3. Combining Multiple Effects
|
||||
|
||||
You can combine `scale`, `slide`, `rotate`, and `blur` at the same time.
|
||||
|
||||
```javascript
|
||||
fx({ scale: true, slide: true, blur: true, duration: 250 },
|
||||
div({ class: "card" }, "Smooth enter")
|
||||
);
|
||||
```
|
||||
|
||||
### 4. Using with `when` (Conditional Rendering)
|
||||
|
||||
Wrap the branch content with `fx` to animate entering elements.
|
||||
|
||||
```javascript
|
||||
when(show,
|
||||
() => fx({ slide: true },
|
||||
div("This slides in when visible")
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### 5. Using a Function as Child
|
||||
|
||||
If the element is created inside a function (e.g. to avoid recreation until needed), pass a function that returns the node.
|
||||
|
||||
```javascript
|
||||
fx({ scale: true },
|
||||
() => div("Lazy created and then animated")
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What Happens Under the Hood
|
||||
|
||||
### With `name` (CSS animation)
|
||||
|
||||
- Sets `el.style.animation = `${name}-in ${duration}ms``.
|
||||
- The element animates according to your keyframes.
|
||||
- No further inline style changes are applied.
|
||||
|
||||
### Without `name` (transition effects)
|
||||
|
||||
- Sets `el.style.transition = `all ${duration}ms ease``.
|
||||
- Sets initial `opacity: 0`.
|
||||
- Applies initial transforms (`scale`, `slide`, `rotate`) if selected.
|
||||
- Applies initial `filter: blur(4px)` if `blur: true`.
|
||||
- In the next animation frame (via `requestAnimationFrame`), sets:
|
||||
- `opacity: 1`
|
||||
- `transform: none`
|
||||
- `filter: none`
|
||||
- The element transitions smoothly from the start state to the final state.
|
||||
|
||||
> **Important:** The element must be **in the DOM** when the animation starts. `fx` does **not** automatically mount the node – you must already have appended it or be about to mount it. In practice, when you call `fx` inside a component that is being mounted, the element will be added to the DOM shortly after, and the animation runs correctly.
|
||||
|
||||
---
|
||||
|
||||
## Complete Example
|
||||
|
||||
```javascript
|
||||
const App = () =>
|
||||
div([
|
||||
fx({ name: "fade", duration: 400 },
|
||||
h1("Welcome to SigPro")
|
||||
),
|
||||
fx({ scale: true, slide: true, duration: 250 },
|
||||
button({ onClick: () => alert("Animated!") }, "Animated button")
|
||||
)
|
||||
]);
|
||||
|
||||
mount(App, "#app");
|
||||
```
|
||||
|
||||
With accompanying CSS:
|
||||
|
||||
```css
|
||||
@keyframes fade-in {
|
||||
from { opacity: 0; transform: translateY(10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- `fx` is **not** required for basic reactivity – it is purely a visual helper for enter animations.
|
||||
- For exit animations (when an element is removed), use CSS transitions on the element itself combined with `when` – or consider adding a wrapper that delays removal. SigPro does not include built‑in exit animations.
|
||||
- The function returns the same node you passed, so you can inline it inside `h` or tag helpers:
|
||||
|
||||
```javascript
|
||||
div([
|
||||
fx({ scale: true }, span("Hello"))
|
||||
])
|
||||
```
|
||||
|
||||
- If `child` is not a DOM node (e.g., a string or number), `fx` returns it unchanged – no animation is applied.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Option | Effect |
|
||||
| :--- | :--- |
|
||||
| `name` | Uses `@keyframes ${name}-in` CSS animation. |
|
||||
| `duration` | Controls animation/transition length (ms). |
|
||||
| `scale` | Start scale `0.95` → `none`. |
|
||||
| `slide` | Start `translateY(-10px)` → `none`. |
|
||||
| `rotate` | Start `rotate(-2deg)` → `none`. |
|
||||
| `blur` | Start `blur(4px)` → `none`. |
|
||||
|
||||
Combine options to create smooth, modern entrance effects without writing extra CSS.
|
||||
@@ -112,6 +112,7 @@ export const filteredTodos = $(() => {
|
||||
```javascript
|
||||
// components/TodoApp.js
|
||||
import { todos, filter, addTodo, toggleTodo, filteredTodos } from "../store/todos.js";
|
||||
import "sigpro/tags" // tags helpers available in global
|
||||
|
||||
const TodoApp = () =>
|
||||
div({ class: "todo-app" }, [
|
||||
|
||||
@@ -120,6 +120,7 @@ When `destroy()` is called (or when a new mount replaces an old one), everything
|
||||
|
||||
```javascript
|
||||
import { $, mount, div, h1, button } from 'sigpro';
|
||||
import "sigpro/tags" // tags helpers available in global
|
||||
|
||||
const App = () => {
|
||||
const count = $(0);
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
# ⚡ SigPro – Complete API Reference
|
||||
# SigPro – Complete API Reference
|
||||
|
||||
SigPro is a **Real‑DOM first** reactive micro‑framework. No virtual DOM, no diffing overhead – it updates the DOM directly with surgical precision. Built‑in 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, 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.
|
||||
import { $, $$, watch, h, when, each, router, mount, batch } from 'sigpro'
|
||||
// Optional side‑effects (activate global helpers & security):
|
||||
import 'sigpro/tags' // → window.div, window.span, etc.
|
||||
import 'sigpro/xss' // → attribute sanitisation
|
||||
```
|
||||
|
||||
In a classic IIFE script (`<script src="sigpro.min.js">`), **everything** (core, router, tags, XSS, global functions) is available automatically.
|
||||
|
||||
---
|
||||
|
||||
## 🔁 Core Reactivity
|
||||
## Core Reactivity
|
||||
|
||||
### `$(value, localStorageKey?)` – Signal & Computed
|
||||
|
||||
@@ -82,7 +84,7 @@ watch([count, double], ([newCount, newDouble]) => {
|
||||
|
||||
---
|
||||
|
||||
## 🧱 Components & DOM (Hyperscript)
|
||||
## Components & DOM (Hyperscript)
|
||||
|
||||
### `h(tag, props, children)` – Create DOM Nodes
|
||||
|
||||
@@ -96,7 +98,7 @@ The universal builder. `props` can be omitted. Children can be strings, numbers,
|
||||
| Two‑way binding | `value: mySignal` (works on `input`, `textarea`, `select`) |
|
||||
| Refs | `ref: (el) => ...` or `ref: { current: null }` |
|
||||
| SVG support | tag names like `svg`, `circle`, `path` – sets correct namespace |
|
||||
| Dangerous URL sanitising | `href` / `src` with `javascript:` or `data:` are blocked → `'#'` |
|
||||
| Dangerous URL sanitising | `href` / `src` with `javascript:` or `data:` are blocked → `'#'` (when XSS shield is active) |
|
||||
|
||||
**Dynamic children** – pass a function as a child, it will be re‑executed and the DOM patched automatically:
|
||||
|
||||
@@ -108,28 +110,40 @@ h('div', {}, [
|
||||
|
||||
### Tag shortcuts
|
||||
|
||||
When using the **ESM module with named imports**, you can import the tag helpers individually:
|
||||
Tag helpers are **not exported individually** from the core. To use them globally without the `h(...)` wrapper, activate the side‑effect module:
|
||||
|
||||
```javascript
|
||||
import { div, h1, button } from 'sigpro'
|
||||
import 'sigpro/tags' // now window.div, window.span, etc. are available
|
||||
|
||||
// You can now write:
|
||||
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.
|
||||
In the **IIFE bundle** (`sigpro.min.js`), the helpers are already injected globally – no import needed.
|
||||
|
||||
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`.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Flow Control Components
|
||||
## Built‑in XSS Shield (Optional)
|
||||
|
||||
SigPro includes an optional security layer that sanitises dangerous attributes (`href`, `src`, `formaction`, etc.) and blocks `javascript:` / `data:` / `vbscript:` protocols.
|
||||
To enable it in ESM environments:
|
||||
|
||||
```javascript
|
||||
import 'sigpro/xss'
|
||||
```
|
||||
|
||||
In the IIFE bundle, the shield is **active by default**.
|
||||
|
||||
When the shield is enabled, trying to set `href="javascript:alert(1)"` will log a warning and replace the value with `'#'`.
|
||||
|
||||
---
|
||||
|
||||
## Flow Control Components
|
||||
|
||||
### `when(condition, thenComponent, elseComponent?)`
|
||||
|
||||
@@ -162,7 +176,7 @@ When the array changes, elements are added, removed, or reordered with minimal D
|
||||
|
||||
---
|
||||
|
||||
## 💥 Batch
|
||||
## Batch
|
||||
|
||||
### `batch(fn)`
|
||||
|
||||
@@ -178,33 +192,13 @@ batch(() => {
|
||||
|
||||
---
|
||||
|
||||
## ✨ Animations – `fx(options, child)`
|
||||
|
||||
Applies smooth enter animations (CSS transitions / keyframes). Returns the modified element.
|
||||
|
||||
```javascript
|
||||
fx({ name: 'fade', duration: 300 },
|
||||
div({}, 'Hello')
|
||||
)
|
||||
```
|
||||
|
||||
**Options**
|
||||
- `name` – uses predefined keyframes `${name}-in` (you must define them in your CSS)
|
||||
- `duration` – in ms (default 200)
|
||||
- `scale` – adds `scale(0.95)` → `none`
|
||||
- `slide` – adds `translateY(-10px)` → `none`
|
||||
- `rotate` – adds `rotate(-2deg)` → `none`
|
||||
- `blur` – adds `blur(4px)` → `none`
|
||||
|
||||
If `name` is given, it sets `animation: ${name}-in ${duration}ms`. Otherwise it applies a smooth transition from the initial transform/filter to the final state.
|
||||
|
||||
---
|
||||
|
||||
## 🧭 Router – `router(routes)`
|
||||
## Router – `router(routes)`
|
||||
|
||||
Hash‑based SPA router. Returns a DOM node that renders the current route.
|
||||
|
||||
```javascript
|
||||
import { router } from 'sigpro'
|
||||
|
||||
const routes = [
|
||||
{ path: '/', component: () => div({}, 'Home') },
|
||||
{ path: '/user/:id', component: (params) => div({}, `User ${params.id}`) },
|
||||
@@ -229,44 +223,7 @@ const App = () => div({}, [
|
||||
|
||||
---
|
||||
|
||||
## 🌐 HTTP Requests – `req(config)`
|
||||
|
||||
Creates a reactive request controller with built‑in loading/error/data signals and abort support.
|
||||
|
||||
```javascript
|
||||
const fetchUser = req({ url: '/api/user/1', method: 'GET' })
|
||||
|
||||
// start the request
|
||||
fetchUser.run().catch(console.error)
|
||||
|
||||
// reactively display state
|
||||
watch(() => {
|
||||
if (fetchUser.loading()) console.log('loading...')
|
||||
if (fetchUser.error()) console.error(fetchUser.error())
|
||||
if (fetchUser.data()) console.log(fetchUser.data())
|
||||
})
|
||||
|
||||
// abort if needed
|
||||
fetchUser.abort()
|
||||
```
|
||||
|
||||
**Options**
|
||||
- `url` (required)
|
||||
- `method` (default `'GET'`)
|
||||
- `headers` (object, default `{}`)
|
||||
|
||||
**Return value**
|
||||
- `run(body?)` – initiates the request, returns a promise.
|
||||
- `abort()` – aborts the current request (AbortController).
|
||||
- `loading` – signal (boolean)
|
||||
- `error` – signal (`null` or error message)
|
||||
- `data` – signal (`null` or parsed JSON)
|
||||
|
||||
> **Note**: Automatically sets `Content-Type: application/json` unless `body` is a `FormData`. Timeout after 10 seconds aborts the request.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Mounting – `mount(component, target)`
|
||||
## Mounting – `mount(component, target)`
|
||||
|
||||
Clears the target element and mounts the application. Returns the runtime instance (which has a `.destroy()` method).
|
||||
|
||||
@@ -280,7 +237,7 @@ If you mount again on the same target, the previous instance is automatically de
|
||||
|
||||
---
|
||||
|
||||
## 🧹 Global Cleanup & Memory
|
||||
## Global Cleanup & Memory
|
||||
|
||||
SigPro tracks every effect, DOM event listener, and nested component. When a component is unmounted:
|
||||
- All its effects are disposed.
|
||||
@@ -292,10 +249,12 @@ You never need to manually clean up – just write reactive code.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Full Example – Counter with Persistence
|
||||
## Full Example – Counter with Persistence
|
||||
|
||||
```javascript
|
||||
import { $, watch, h, mount } from 'sigpro'
|
||||
import { $, watch, mount } from 'sigpro'
|
||||
import 'sigpro/tags' // ← activate global helpers
|
||||
import 'sigpro/xss' // ← activate security (optional)
|
||||
|
||||
const count = $(0, 'counter') // persists in localStorage
|
||||
|
||||
@@ -320,8 +279,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 (after calling `sigpro()` or using the classic script):
|
||||
In the IIFE bundle, the core functions are already available as both `window.$` and `window.SigPro.$`, so you can alias them globally if needed:
|
||||
|
||||
```javascript
|
||||
window.myReactive = $
|
||||
window.myReactive = $ // or window.SigPro.$
|
||||
```
|
||||
184
docs/api/req.md
184
docs/api/req.md
@@ -1,184 +0,0 @@
|
||||
# HTTP Requests: `req( )`
|
||||
|
||||
The `req` function creates a **reactive HTTP request controller**. It returns signals for `loading`, `error`, and `data`, plus a `run` method to execute the request and an `abort` method to cancel it. All signals update automatically as the request progresses.
|
||||
|
||||
## Function Signature
|
||||
|
||||
```typescript
|
||||
req(config: {
|
||||
url: string;
|
||||
method?: string; // default: 'GET'
|
||||
headers?: Record<string, string>;
|
||||
}): {
|
||||
run: (body?: any) => Promise<any>;
|
||||
abort: () => void;
|
||||
loading: Signal<boolean>;
|
||||
error: Signal<string | null>;
|
||||
data: Signal<any | null>;
|
||||
}
|
||||
```
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **`url`** | `string` | Yes | The endpoint to call. |
|
||||
| **`method`** | `string` | No | HTTP method (`'GET'`, `'POST'`, etc.). Default `'GET'`. |
|
||||
| **`headers`** | `object` | No | Custom headers (will be merged with defaults). |
|
||||
|
||||
**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
|
||||
|
||||
### 1. Basic GET Request
|
||||
|
||||
```javascript
|
||||
const users = req({ url: '/api/users' });
|
||||
|
||||
// Start the request
|
||||
users.run().catch(console.error);
|
||||
|
||||
// React to the response
|
||||
watch(() => {
|
||||
if (users.loading()) console.log('Loading...');
|
||||
if (users.error()) console.error(users.error());
|
||||
if (users.data()) console.log('Data:', users.data());
|
||||
});
|
||||
```
|
||||
|
||||
### 2. POST Request with Body
|
||||
|
||||
```javascript
|
||||
const createUser = req({ url: '/api/users', method: 'POST' });
|
||||
|
||||
const handleSubmit = async (formData) => {
|
||||
try {
|
||||
await createUser.run(formData);
|
||||
alert('User created!');
|
||||
} catch (err) {
|
||||
// Error already in createUser.error()
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Aborting a Request
|
||||
|
||||
```javascript
|
||||
const search = req({ url: '/api/search' });
|
||||
|
||||
// Abort if the user types again quickly
|
||||
let timeout;
|
||||
input({ onInput: (e) => {
|
||||
clearTimeout(timeout);
|
||||
search.abort(); // cancel previous in-flight request
|
||||
timeout = setTimeout(() => search.run({ q: e.target.value }), 300);
|
||||
}});
|
||||
```
|
||||
|
||||
### 4. Reactive UI with Signals
|
||||
|
||||
```javascript
|
||||
const profile = req({ url: '/api/me' });
|
||||
|
||||
const App = () =>
|
||||
div([
|
||||
when(() => profile.loading(),
|
||||
() => div("Loading...")
|
||||
),
|
||||
when(() => profile.error(),
|
||||
() => div("Error: " + profile.error())
|
||||
),
|
||||
when(() => profile.data(),
|
||||
() => div([
|
||||
h2(profile.data().name),
|
||||
p(profile.data().email)
|
||||
])
|
||||
)
|
||||
]);
|
||||
|
||||
profile.run();
|
||||
mount(App, '#app');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Request Lifecycle
|
||||
|
||||
When you call `run(body?)`:
|
||||
|
||||
1. Any previous request is **aborted** automatically.
|
||||
2. `loading` becomes `true`.
|
||||
3. `error` is cleared.
|
||||
4. A 10‑second timeout is set (auto‑abort).
|
||||
5. The request is sent using `fetch`.
|
||||
6. On success: `data` is set with the parsed JSON, `loading` becomes `false`.
|
||||
7. On error: `error` is set with the message, `data` is cleared, `loading` becomes `false`.
|
||||
|
||||
> **Important:** The response body is parsed as JSON. If the response is not OK or the JSON parsing fails, `error` is set and the promise rejects.
|
||||
|
||||
---
|
||||
|
||||
## Automatic Headers
|
||||
|
||||
- If `body` is a plain object or array, the request automatically includes `Content-Type: application/json` (unless you override it in `headers`).
|
||||
- If `body` is a `FormData` instance, the `Content-Type` is not set (browser will set it automatically with the correct boundary).
|
||||
- Other headers can be added via the `headers` option.
|
||||
|
||||
```javascript
|
||||
const upload = req({
|
||||
url: '/upload',
|
||||
method: 'POST',
|
||||
headers: { 'X-Custom': 'value' }
|
||||
});
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', fileInput.files[0]);
|
||||
upload.run(formData);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Network errors, timeouts, and HTTP error statuses (4xx, 5xx) all set `error` and cause the promise to reject.
|
||||
- The `error` signal contains a human‑readable message.
|
||||
- Abort errors (calling `abort()` or timeout) are **silent** – they do not set `error` or reject the promise?
|
||||
Actually, according to the source: if `e.name === 'AbortError'`, it does **not** call `error(e.message)`, but the promise still rejects with the AbortError. You can handle it with `.catch()` if needed.
|
||||
|
||||
---
|
||||
|
||||
## Complete Example
|
||||
|
||||
```javascript
|
||||
const api = req({ url: 'https://jsonplaceholder.typicode.com/posts/1' });
|
||||
|
||||
const App = () =>
|
||||
div({ class: "demo" }, [
|
||||
when(() => api.loading(), () => p("⏳ Loading...")),
|
||||
when(() => api.error(), () => p("❌ " + api.error())),
|
||||
when(() => api.data(), () => div([
|
||||
h2(api.data().title),
|
||||
p(api.data().body)
|
||||
])),
|
||||
button({
|
||||
onClick: () => api.run(),
|
||||
disabled: () => api.loading()
|
||||
}, "Fetch")
|
||||
]);
|
||||
|
||||
mount(App, '#app');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Member | Type | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `run(body?)` | `(any) => Promise` | Starts the request. Returns a promise. |
|
||||
| `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`. |
|
||||
@@ -153,6 +153,7 @@ If you want the router outlet to have no layout impact, you can set `display: co
|
||||
|
||||
```javascript
|
||||
import { $, router, mount } from "sigpro";
|
||||
import "sigpro/tags" // tags helpers available in global
|
||||
|
||||
const Home = () => div("Welcome home");
|
||||
const About = () => div("About us");
|
||||
|
||||
113
docs/api/tags.md
113
docs/api/tags.md
@@ -4,58 +4,72 @@ In **SigPro**, you don't need to manually type `h('div', ...)` for every element
|
||||
|
||||
## 1. How it Works
|
||||
|
||||
SigPro iterates through a list of standard HTML tags and creates a wrapper function for each one.
|
||||
SigPro creates a wrapper function for each standard HTML tag.
|
||||
- **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.
|
||||
|
||||
These helpers can be used in two ways, depending on your environment:
|
||||
|
||||
### Mode A: Classic (IIFE) – Auto‑global
|
||||
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
|
||||
```
|
||||
> **Note:** All tag helpers are **lowercase** (e.g., `div`, `span`, `button`) and can be used directly once globally enabled.
|
||||
|
||||
---
|
||||
|
||||
## 2. The Complete List of Tag Helpers
|
||||
## 2. Activating the Tag Helpers
|
||||
|
||||
All helpers are **lowercase** and follow HTML5 tag names. You can use them globally (after injection) or import them individually.
|
||||
Depending on how you load SigPro, the activation varies:
|
||||
|
||||
### A. Classic IIFE – Automatic Global Helpers
|
||||
When you use the **IIFE bundle** (`sigpro.js` or `sigpro.min.js`) with a traditional `<script>` tag (no `type="module"`), **all tag helpers, signals, and XSS protection are automatically installed on `window`**. No extra steps needed.
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/sigpro@latest/dist/sigpro.min.js"></script>
|
||||
<script>
|
||||
// div, span, button, $, h, mount, router... are already global
|
||||
const App = () => div({ class: "card" }, "Hello");
|
||||
mount(App, '#app');
|
||||
</script>
|
||||
```
|
||||
|
||||
### B. ESM (Modern JavaScript) – Explicit Activation
|
||||
When you import the **ES module** (`import { ... } from 'sigpro'`), the core **does not** add helpers to `window` by default. To enable global tags, import the dedicated side‑effect module:
|
||||
|
||||
```js
|
||||
import 'sigpro/tags'; // ← activates window.div, window.span, etc.
|
||||
|
||||
// Now you can use helpers globally
|
||||
const App = () => div({ class: "app" }, "Ready!");
|
||||
```
|
||||
|
||||
If you also want built‑in **XSS protection**, enable it once:
|
||||
|
||||
```js
|
||||
import 'sigpro/xss'; // ← add security layer
|
||||
import 'sigpro/tags'; // ← global helpers
|
||||
```
|
||||
|
||||
Both are side‑effect modules, so the order doesn’t matter.
|
||||
|
||||
> **Important:** The tag helpers are **not** exported as individual named exports from the core (`sigpro`). They become available as global functions (`window.div`, etc.) after the side‑effect runs.
|
||||
> If you prefer to avoid globals, you can always use `h('div', ...)` directly—it’s perfectly fine.
|
||||
|
||||
---
|
||||
|
||||
## 3. The Complete List of Tag Helpers
|
||||
|
||||
All helpers are **lowercase** and follow HTML5 tag names.
|
||||
|
||||
| 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` |
|
||||
| **Typography** | `h1`…`h6`, `ul`, `ol`, `li`, `dl`, `dt`, `dd`, `strong`, `em`, `code`, `pre`, `small`, `b`, `u`, `mark` |
|
||||
| **Interactive** | `button`, `a`, `label`, `br`, `hr`, `details`, `summary`, `dialog` |
|
||||
| **Forms** | `form`, `input`, `select`, `option`, `textarea`, `fieldset`, `legend` |
|
||||
| **Tables** | `table`, `thead`, `tbody`, `tr`, `th`, `td`, `tfoot`, `caption` |
|
||||
| **Media** | `img`, `canvas`, `video`, `audio`, `svg`, `iframe`, `picture`, `source` |
|
||||
|
||||
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`.
|
||||
Full list: `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
|
||||
## 4. Usage Patterns
|
||||
|
||||
### A. Attributes + Children
|
||||
|
||||
@@ -79,7 +93,7 @@ section([
|
||||
|
||||
---
|
||||
|
||||
## 4. Reactive Power
|
||||
## 5. Reactive Power
|
||||
|
||||
These helpers are natively wired into SigPro's reactivity system.
|
||||
|
||||
@@ -126,7 +140,7 @@ div([
|
||||
|
||||
---
|
||||
|
||||
## 5. Custom Components with `h()` or Tag Helpers
|
||||
## 6. Custom Components with `h()` or Tag Helpers
|
||||
|
||||
While the tag helpers cover all standard HTML tags, you can create reusable components using them directly.
|
||||
|
||||
@@ -170,7 +184,7 @@ const Timer = () => {
|
||||
|
||||
---
|
||||
|
||||
## 6. Comparison with `h()`
|
||||
## 7. Comparison with `h()`
|
||||
|
||||
| Use case | Recommendation |
|
||||
| :--- | :--- |
|
||||
@@ -182,11 +196,17 @@ const Timer = () => {
|
||||
|
||||
---
|
||||
|
||||
## 7. Complete Example
|
||||
## 8. Complete Example
|
||||
|
||||
### ESM (modern projects)
|
||||
|
||||
```javascript
|
||||
// In a modern ESM environment (recommended)
|
||||
import { div, h1, input, p, button, mount, $ } from 'sigpro';
|
||||
// Enable global helpers + security
|
||||
import 'sigpro/tags';
|
||||
import 'sigpro/xss';
|
||||
|
||||
// Import core functions
|
||||
import { $, mount } from 'sigpro';
|
||||
|
||||
const nameSignal = $('');
|
||||
|
||||
@@ -204,10 +224,10 @@ const App = () =>
|
||||
mount(App, '#app');
|
||||
```
|
||||
|
||||
Or using the classic script (auto‑global):
|
||||
### Classic IIFE (auto‑global)
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/sigpro@1.2.19/dist/sigpro.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sigpro@1.2.23/dist/sigpro.min.js"></script>
|
||||
<script>
|
||||
const nameSignal = $('');
|
||||
const App = () => div({ class: "app" }, [
|
||||
@@ -222,23 +242,24 @@ Or using the classic script (auto‑global):
|
||||
|
||||
---
|
||||
|
||||
## 8. Important Notes
|
||||
## 9. Important Notes
|
||||
|
||||
- **Naming:** All tag helpers are **lowercase**.
|
||||
- **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.
|
||||
- **IIFE script** – automatically on `window`.
|
||||
- **ESM module** – not global by default; use `import 'sigpro/tags'` to activate them.
|
||||
- **Custom components:** Use **PascalCase** for your own component functions (e.g., `UserCard`) to visually distinguish them from built‑in tags.
|
||||
|
||||
---
|
||||
|
||||
## 9. Summary
|
||||
## 10. Summary
|
||||
|
||||
| Feature | Description |
|
||||
| :--- | :--- |
|
||||
| **Tag helpers** | Lowercase functions for every HTML element (e.g., `div()`, `button()`). |
|
||||
| **Availability** | Auto‑global in IIFE; in ESM use named imports or `sigpro()`. |
|
||||
| **Activation** | IIFE: automatic. ESM: `import 'sigpro/tags'`. |
|
||||
| **Reactive attributes** | Pass a function to any attribute to keep it synced. |
|
||||
| **Two‑way binding** | Assign a signal directly to `value` or `checked` on form elements. |
|
||||
| **Dynamic children** | Pass a function as a child for live updating content. |
|
||||
| **Auto‑cleanup** | All effects, events, and children are disposed when the element is removed. |
|
||||
| **Security** | Optional XSS shield: `import 'sigpro/xss'`. |
|
||||
|
||||
Reference in New Issue
Block a user