diff --git a/docs/api/jsx.md b/docs/api/jsx.md index fc9fffe..effee43 100644 --- a/docs/api/jsx.md +++ b/docs/api/jsx.md @@ -1,4 +1,4 @@ -# Hyperscript & Tag Helpers +# Hyperscript & Tag Helpers & JSX Style SigPro provides two complementary ways to create DOM elements: @@ -9,135 +9,6 @@ Both are reactive, auto‑cleanup, and support SVG, events, two‑way binding, a --- -## `h( )` – Hyperscript Function - -The `h` function is the **core DOM builder** of SigPro. Use it directly when you need a dynamic tag name or prefer an explicit style. - -### Function Signature - -```typescript -h( - tag: string | Function, - props?: object | Node | any[], - children?: any -): Node -``` - -| Parameter | Type | Description | -| :--- | :--- | :--- | -| **`tag`** | `string` or `Function` | HTML tag name (e.g., `"div"`) or a component function. | -| **`props`** | `object` | Optional. Attributes, event handlers, refs, etc. | -| **`children`** | `any` | Optional. Text, nodes, arrays, or reactive functions. | - -**Returns:** A DOM node (or array of nodes when the tag is a component that returns an array). - -### Usage Examples - -```js -// Basic element -h('div', {}, 'Hello world'); - -// With attributes and events -h('button', { class: 'btn', onclick: () => alert('clicked') }, 'Click me'); - -// Nested children -h('div', { class: 'container' }, [ - h('h1', {}, 'Title'), - h('p', {}, 'Paragraph') -]); - -// Reactive child (function) -const count = $(0); -h('div', {}, [ - h('p', {}, () => `Count: ${count()}`), - h('button', { onclick: () => count(count() + 1) }, '+1') -]); - -// Reactive attribute -const theme = $('dark'); -h('div', { class: () => `box ${theme()}` }, 'Themed box'); - -// Two-way binding on input -const name = $(''); -h('input', { type: 'text', value: name, placeholder: 'Your name' }); -h('p', {}, () => `Hello, ${name()}`); - -// Component as tag -const Button = (props, { children }) => - h('button', { class: 'btn', onclick: props.onClick }, children); - -h(Button, { onClick: () => alert('clicked') }, 'Click me'); - -// SVG (auto-namespace) -h('svg', { width: 100, height: 100 }, [ - h('circle', { cx: 50, cy: 50, r: 40, fill: 'red' }) -]); -``` - -### Special Props - -| Prop | Behaviour | -| :--- | :--- | -| **`ref`** | `ref: (el) => ...` or `ref: { current: null }` – direct DOM node access. | -| **`onEvent`** | Any prop starting with `on` (e.g., `onClick`) is an event listener – auto‑removed on cleanup. | -| **`value` / `checked`** | When a signal is passed, creates two‑way binding for form elements. | -| **`class`** | Use `class` (not `className`). Accepts a string or reactive function. | - ---- - -## Global Tag Helpers (Lowercase) - -When you import SigPro (either via `import 'sigpro'` or the CDN), it automatically injects a helper function for **every standard HTML tag** directly onto `window`. These helpers are **lowercase** and work exactly like `h`, but with a cleaner syntax. - -### Available Helpers - -All standard HTML5 tags: `div`, `span`, `p`, `section`, `nav`, `header`, `footer`, `h1`…`h6`, `ul`, `ol`, `li`, `button`, `a`, `input`, `form`, `table`, `svg`, `circle`, etc. - -### Usage Examples - -```js -// Instead of h('div', ...) -div({ class: 'container' }, 'Content'); - -// Children only (skip props) -section([ - h2('Title'), - p('Paragraph') -]); - -// Reactive attribute -const theme = $('light'); -div({ class: () => `app-${theme()}` }, 'Themed'); - -// Two-way binding -const search = $(''); -input({ type: 'text', value: search, placeholder: 'Search...' }); -p(() => `You typed: ${search()}`); - -// Dynamic children -const count = $(0); -div([ - p(() => `Count: ${count()}`), - button({ onClick: () => count(count() + 1) }, '+1') -]); -``` - -### Complete Example - -```js -const App = () => - div({ class: 'app' }, [ - h1('Welcome'), - input({ value: name, placeholder: 'Your name' }), - p(() => `Hello, ${name() || 'stranger'}!`), - button({ onClick: () => alert('Hi') }, 'Click me') - ]); - -mount(App, '#app'); -``` - ---- - ## JSX with SigPro SigPro works seamlessly with JSX. You can use JSX as a compile‑time syntax sugar for `h` calls. diff --git a/docs/api/tags.md b/docs/api/tags.md index f6f2d8d..538383f 100644 --- a/docs/api/tags.md +++ b/docs/api/tags.md @@ -29,7 +29,7 @@ When you use the **IIFE bundle** (`sigpro.js` or `sigpro.min.js`) with a traditi ``` ### 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: +**ES module** (`import { ... } from 'sigpro'`) or full `import 'sigpro'`. ```js import 'sigpro'; @@ -38,7 +38,6 @@ import 'sigpro'; const App = () => div({ class: "app" }, "Ready!"); ``` -> **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. --- diff --git a/package.json b/package.json index a7d3b88..d75d419 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sigpro", - "version": "1.2.28", + "version": "1.2.30", "type": "module", "license": "MIT", "author": { diff --git a/sigpro.js b/sigpro.js index d83123c..6d5b47e 100644 --- a/sigpro.js +++ b/sigpro.js @@ -497,6 +497,8 @@ router.to = p => window.location.hash = p.replace(/^#?\/?/, "#/") router.back = () => window.history.back() router.path = () => window.location.hash.replace(/^#/, "") || "/" +const Fragment = (props) => props.children; + const mount = (comp, target) => { const t = typeof target === "string" ? doc.querySelector(target) : target if (!t) return @@ -508,10 +510,10 @@ const mount = (comp, target) => { } if (typeof window !== "undefined") { - Object.assign(window, { $, $$, watch, h, when, each, router, mount, batch, onUnmount, isArr, isFunc, isObj }) + Object.assign(window, { $, $$, watch, h, Fragment, when, each, router, mount, batch, onUnmount, isArr, isFunc, isObj }) "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 h2 h3 h4 h5 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" .split(" ") .forEach(tag => { window[tag] = (props, children) => h(tag, props, children) }) } -export { $, $$, watch, batch, h, mount, when, each, router, onUnmount, isArr, isFunc, isObj } \ No newline at end of file +export { $, $$, watch, batch, h, Fragment, mount, when, each, router, onUnmount, isArr, isFunc, isObj } \ No newline at end of file