nuclo 0.2.18 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -15
- package/package.json +2 -3
- package/types/features/render.d.ts +2 -1
- package/types/svg/base.d.ts +2 -2
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# nuclo
|
|
2
2
|
|
|
3
|
-
**A lightweight DOM framework with
|
|
3
|
+
**A lightweight, type-safe JS/TS DOM framework with plain mutable state and explicit updates.**
|
|
4
4
|
|
|
5
|
-
Create elements with plain functions, and pass a function anywhere a value depends on state — that
|
|
5
|
+
Create elements with plain functions, and pass a function anywhere a value depends on state — that function is registered so Nuclo can evaluate it again later. Change regular JavaScript values directly, then call `update()` when you want Nuclo to synchronize the DOM. No virtual DOM, no proxies, no signals, and no automatic state tracking.
|
|
6
6
|
|
|
7
7
|
Nuclo's workflow has three parts:
|
|
8
8
|
|
|
9
|
-
1. **Create the UI with builder functions** — text, attributes, conditions, and lists can be passed a function whenever they depend on state; this registers a
|
|
9
|
+
1. **Create the UI with builder functions** — text, attributes, conditions, and lists can be passed a function whenever they depend on state; this registers the function as a state-dependent value.
|
|
10
10
|
2. **Mutate regular JavaScript state** — no signals, no proxies, no wrapped values. `count++` is just `count++`. Mutating state does not, by itself, touch the DOM.
|
|
11
|
-
3. **Call `update()`** — this explicitly
|
|
11
|
+
3. **Call `update()`** — this explicitly starts synchronization: Nuclo reevaluates the state-dependent values registered in step 1 and applies changed results to the real DOM.
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
import 'nuclo';
|
|
@@ -28,13 +28,13 @@ render(counter, document.body);
|
|
|
28
28
|
|
|
29
29
|
## Why nuclo?
|
|
30
30
|
|
|
31
|
-
- **
|
|
31
|
+
- **State-Dependent Values** – Pass a function for any text, attribute, condition, or list that depends on state; Nuclo can evaluate it again later
|
|
32
32
|
- **Explicit and Predictable** – Reevaluation doesn't happen on mutation — you trigger it yourself with a simple `update()` call
|
|
33
33
|
- **Real DOM, No Virtual Layer** – Nuclo creates and updates real DOM nodes directly; there's no virtual DOM to diff
|
|
34
34
|
- **Tiny Footprint** – ~13 KB gzipped, zero dependencies
|
|
35
35
|
- **Global Tag Builders** – Natural API with global functions for all HTML and SVG elements
|
|
36
36
|
- **TypeScript-First** – Full type definitions for all 175 HTML and SVG builders
|
|
37
|
-
- **Targeted DOM Updates** – `update()` re-runs registered
|
|
37
|
+
- **Targeted DOM Updates** – `update()` re-runs registered state-dependent values and only touches DOM where values changed
|
|
38
38
|
- **Atomic Styling** – Built-in `css()` / `createCss()` with TypeScript autocomplete, theming, and SSR CSS collection
|
|
39
39
|
- **Server-Side Rendering** – `renderToString()` + `hydrate()` with a lightweight DOM polyfill
|
|
40
40
|
|
|
@@ -313,12 +313,12 @@ render(app, document.body);
|
|
|
313
313
|
**The mental model:**
|
|
314
314
|
|
|
315
315
|
1. Create the UI with builder functions — `h1(...)`, `when()`, `list()`.
|
|
316
|
-
2. Use functions for values that depend on state — `h1(() => \`Count: ${count}\`)`. This registers a
|
|
316
|
+
2. Use functions for values that depend on state — `h1(() => \`Count: ${count}\`)`. This registers a state-dependent value.
|
|
317
317
|
3. Mutate regular JavaScript state — `count++`.
|
|
318
318
|
4. Call `update()`.
|
|
319
|
-
5. Nuclo reevaluates registered
|
|
319
|
+
5. Nuclo reevaluates the registered state-dependent values and applies the changes to the existing DOM.
|
|
320
320
|
|
|
321
|
-
State mutation and the `update()` call are plain JavaScript: you write `count++` and call `update()` yourself. Nuclo does not watch your variables — nothing reevaluates until `update()` runs.
|
|
321
|
+
State mutation and the `update()` call are plain JavaScript: you write `count++` and call `update()` yourself. Nuclo does not watch your variables — nothing reevaluates until `update()` runs. The function from step 2 stays registered so it can be evaluated again, but only `update()` starts that evaluation.
|
|
322
322
|
|
|
323
323
|
### 1. **Explicit Updates**
|
|
324
324
|
|
|
@@ -361,7 +361,7 @@ user.name = 'Alice'; // triggers update
|
|
|
361
361
|
|
|
362
362
|
### 2. **Dynamic Functions**
|
|
363
363
|
|
|
364
|
-
Zero-arg functions become
|
|
364
|
+
Zero-arg functions become state-dependent values: Nuclo keeps them registered and can evaluate them again, but only when you call `update()` — mutating the state they read does nothing on its own:
|
|
365
365
|
|
|
366
366
|
```ts
|
|
367
367
|
let count = 0;
|
|
@@ -736,18 +736,18 @@ These markers identify conditional and list boundaries in the DOM.
|
|
|
736
736
|
### Gotchas
|
|
737
737
|
|
|
738
738
|
**Parameter count decides what a function modifier means.**
|
|
739
|
-
A modifier with **zero declared parameters** is treated as
|
|
739
|
+
A modifier with **zero declared parameters** is treated as dynamic text (or a dynamic `cn()` className) and is called with no arguments. A modifier with **one or more declared parameters** is a node-modifier function receiving `(element, index)`. Default and rest parameters don't count as declared parameters (`fn.length` is 0), so these are all treated as *dynamic text*, not node modifiers:
|
|
740
740
|
|
|
741
741
|
```ts
|
|
742
|
-
div((el = fallback) => el.id); //
|
|
743
|
-
div((...args) => args[0]); //
|
|
742
|
+
div((el = fallback) => el.id); // dynamic text — el is undefined!
|
|
743
|
+
div((...args) => args[0]); // dynamic text — args is empty!
|
|
744
744
|
div((el) => el.id = "x"); // node modifier — el is the element ✓
|
|
745
745
|
```
|
|
746
746
|
|
|
747
747
|
If a modifier needs the element, declare it as a plain required parameter.
|
|
748
748
|
|
|
749
|
-
**Detached nodes
|
|
750
|
-
|
|
749
|
+
**Detached nodes stop updating.**
|
|
750
|
+
Registered state-dependent values (text, attributes, `list()`, `when()`) are pruned for any node that is disconnected from the DOM when `update()` runs. Re-attaching the node later does **not** restore them. Keep-alive and portal-style patterns should rebuild content after re-attaching instead of moving live subtrees between updates.
|
|
751
751
|
|
|
752
752
|
---
|
|
753
753
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuclo",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.2.
|
|
5
|
-
"description": "Lightweight DOM library with
|
|
4
|
+
"version": "0.2.19",
|
|
5
|
+
"description": "Lightweight, type-safe DOM library with plain mutable state and explicit updates — global tag builders, SSR, hydration, and atomic CSS, no virtual DOM, no compiler.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Danilo Celestino de Castro (https://github.com/dan2dev)",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"dom",
|
|
10
|
-
"reactive",
|
|
11
10
|
"ui",
|
|
12
11
|
"ssr",
|
|
13
12
|
"hydration",
|
|
@@ -26,7 +26,8 @@ declare global {
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Hydrates an existing server-rendered DOM tree by walking it in parallel with
|
|
29
|
-
* the component tree, reusing existing nodes and re-
|
|
29
|
+
* the component tree, reusing existing nodes and re-registering their
|
|
30
|
+
* state-dependent values for future `update()` calls.
|
|
30
31
|
*
|
|
31
32
|
* @param nodeModFn The NodeModFn to hydrate (same component used for SSR)
|
|
32
33
|
* @param parent The parent element containing the SSR HTML (defaults to document.body)
|
package/types/svg/base.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ declare global {
|
|
|
5
5
|
// SVG attribute types that accept string values for all SVG properties
|
|
6
6
|
// This is needed because SVG DOM properties like 'width' are SVGAnimatedLength,
|
|
7
7
|
// but we set them as strings using setAttribute()
|
|
8
|
-
// Supports
|
|
8
|
+
// Supports state-dependent values (functions) for dynamic attributes
|
|
9
9
|
export type SVGAttributes = {
|
|
10
10
|
// Common SVG attributes
|
|
11
11
|
width?: SVGAttributeValue<string | number>;
|
|
@@ -70,7 +70,7 @@ declare global {
|
|
|
70
70
|
"clip-path"?: SVGAttributeValue<string>;
|
|
71
71
|
mask?: SVGAttributeValue<string>;
|
|
72
72
|
|
|
73
|
-
// Allow any other string attributes (including
|
|
73
|
+
// Allow any other string attributes (including state-dependent functions)
|
|
74
74
|
// Using a more restrictive type to maintain type safety
|
|
75
75
|
} & {
|
|
76
76
|
[K in string]?: SVGAttributeValue;
|