@deijose/nix-js 1.0.6 → 1.0.8
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 +59 -276
- package/dist/lib/nix/async.d.ts +8 -54
- package/dist/lib/nix/component.d.ts +6 -6
- package/dist/lib/nix/context.d.ts +11 -45
- package/dist/lib/nix/form.d.ts +6 -129
- package/dist/lib/nix/lifecycle.d.ts +13 -107
- package/dist/lib/nix/reactivity.d.ts +16 -88
- package/dist/lib/nix/router.d.ts +23 -186
- package/dist/lib/nix/store.d.ts +5 -30
- package/dist/lib/nix/template.d.ts +25 -289
- package/dist/lib/nix-js.cjs +3 -3
- package/dist/lib/nix-js.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,322 +1,105 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Nix.js
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@deijose/nix-js)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[]()
|
|
6
|
+
[]()
|
|
7
|
+
[]()
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
A lightweight, fully reactive micro-framework for building modern web UIs — no virtual DOM, no compiler, no build-time magic. Just signals, tagged templates, and pure TypeScript.
|
|
6
10
|
|
|
7
11
|
```
|
|
8
|
-
~
|
|
12
|
+
~24 KB minified · ~8 KB gzipped · zero dependencies · TypeScript-first · ES2022
|
|
9
13
|
```
|
|
10
14
|
|
|
11
15
|
## Installation
|
|
12
16
|
|
|
13
17
|
```bash
|
|
14
18
|
npm install @deijose/nix-js
|
|
15
|
-
# or
|
|
16
|
-
bun add @deijose/nix-js
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
##
|
|
21
|
+
## Quick Start
|
|
20
22
|
|
|
21
23
|
```typescript
|
|
22
|
-
import { signal, html, mount } from "@deijose/nix-js";
|
|
24
|
+
import { signal, html, NixTemplate, NixComponent, mount, createRouter, RouterView, Link, useRouter } from "@deijose/nix-js";
|
|
23
25
|
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
+
// --- Pages as function components (NixTemplate) ---
|
|
27
|
+
// Plain functions returning html`` are recommended for pages and
|
|
28
|
+
// display-only components — no class needed, signals just work.
|
|
26
29
|
|
|
30
|
+
function HomePage(): NixTemplate {
|
|
31
|
+
const count = signal(0);
|
|
27
32
|
return html`
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
</div>
|
|
33
|
+
<h1>Home</h1>
|
|
34
|
+
<p>Count: ${() => count.value}</p>
|
|
35
|
+
<button @click=${() => count.value++}>+1</button>
|
|
32
36
|
`;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```typescript
|
|
41
|
-
import { signal, computed, effect, watch } from "@deijose/nix-js";
|
|
42
|
-
|
|
43
|
-
const price = signal(10);
|
|
44
|
-
const qty = signal(3);
|
|
45
|
-
const total = computed(() => price.value * qty.value);
|
|
46
|
-
|
|
47
|
-
effect(() => console.log("Total:", total.value)); // logs on every change
|
|
48
|
-
|
|
49
|
-
watch(total, (next, prev) => console.log(prev, "→", next));
|
|
50
|
-
|
|
51
|
-
price.value = 20; // effect & watch fire automatically
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Components
|
|
39
|
+
function UserPage(): NixTemplate {
|
|
40
|
+
const router = useRouter();
|
|
41
|
+
return html`<h1>User: ${() => router.params.value.id}</h1>`;
|
|
42
|
+
}
|
|
55
43
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
import { signal } from "@deijose/nix-js";
|
|
44
|
+
// --- Stateful component as class component (NixComponent) ---
|
|
45
|
+
// Use a class when you need lifecycle hooks: onInit / onMount / onUnmount.
|
|
59
46
|
|
|
60
|
-
class
|
|
61
|
-
private
|
|
47
|
+
class Clock extends NixComponent {
|
|
48
|
+
private time = signal(new Date().toLocaleTimeString());
|
|
49
|
+
private _id = 0;
|
|
62
50
|
|
|
63
|
-
|
|
64
|
-
|
|
51
|
+
onMount() {
|
|
52
|
+
this._id = setInterval(() => {
|
|
53
|
+
this.time.value = new Date().toLocaleTimeString();
|
|
54
|
+
}, 1000);
|
|
55
|
+
return () => clearInterval(this._id); // auto-cleanup on unmount
|
|
65
56
|
}
|
|
66
57
|
|
|
67
58
|
render() {
|
|
68
|
-
return html`<p
|
|
59
|
+
return html`<p>Clock: ${() => this.time.value}</p>`;
|
|
69
60
|
}
|
|
70
61
|
}
|
|
71
62
|
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### Stores
|
|
76
|
-
|
|
77
|
-
```typescript
|
|
78
|
-
import { createStore } from "@deijose/nix-js";
|
|
79
|
-
|
|
80
|
-
const counter = createStore({ count: 0 }, (state) => ({
|
|
81
|
-
increment() { state.count.value++; },
|
|
82
|
-
reset() { state.count.value = 0; },
|
|
83
|
-
}));
|
|
84
|
-
|
|
85
|
-
counter.count.value; // reactive signal
|
|
86
|
-
counter.increment();
|
|
87
|
-
```
|
|
63
|
+
// --- Router ---
|
|
88
64
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
import { createRouter, RouterView, Link, html } from "@deijose/nix-js";
|
|
93
|
-
|
|
94
|
-
const router = createRouter([
|
|
95
|
-
{ path: "/", component: Home },
|
|
96
|
-
{ path: "/about", component: About },
|
|
65
|
+
createRouter([
|
|
66
|
+
{ path: "/", component: () => HomePage() },
|
|
67
|
+
{ path: "/user/:id", component: () => UserPage() },
|
|
97
68
|
]);
|
|
98
69
|
|
|
99
|
-
|
|
100
|
-
<nav>
|
|
101
|
-
${Link({ href: "/" }, "Home")}
|
|
102
|
-
${Link({ href: "/about" }, "About")}
|
|
103
|
-
</nav>
|
|
104
|
-
${RouterView(router)}
|
|
105
|
-
`;
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### Forms
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
import { createForm, required, email, minLength, min } from "@deijose/nix-js";
|
|
112
|
-
|
|
113
|
-
const form = createForm(
|
|
114
|
-
{ name: "", email: "", age: 0 },
|
|
115
|
-
{
|
|
116
|
-
validators: {
|
|
117
|
-
name: [required(), minLength(2)],
|
|
118
|
-
email: [required(), email()],
|
|
119
|
-
age: [required(), min(18)],
|
|
120
|
-
},
|
|
121
|
-
// Optional: plug in Zod, Valibot, Yup, or any schema library
|
|
122
|
-
validate(values) {
|
|
123
|
-
const r = zodSchema.safeParse(values);
|
|
124
|
-
if (r.success) return null;
|
|
125
|
-
return Object.fromEntries(
|
|
126
|
-
Object.entries(r.error.flatten().fieldErrors).map(([k, v]) => [k, v?.[0]])
|
|
127
|
-
);
|
|
128
|
-
},
|
|
129
|
-
}
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
html`
|
|
133
|
-
<form @submit=${form.handleSubmit(onSubmit)}>
|
|
134
|
-
<input value=${() => form.fields.name.value.value}
|
|
135
|
-
@input=${form.fields.name.onInput}
|
|
136
|
-
@blur=${form.fields.name.onBlur} />
|
|
137
|
-
${() => form.fields.name.error.value
|
|
138
|
-
? html`<p class="err">${form.fields.name.error.value}</p>`
|
|
139
|
-
: null}
|
|
140
|
-
<button type="submit">Submit</button>
|
|
141
|
-
</form>
|
|
142
|
-
`
|
|
143
|
-
|
|
144
|
-
// Inject server errors after a failed API call:
|
|
145
|
-
form.setErrors({ email: "Email already in use" });
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Children & slots
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
import type { NixChildren } from "@deijose/nix-js";
|
|
70
|
+
// --- App shell (function component) ---
|
|
152
71
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
<footer>${this.slot("footer") ?? html`<small>Footer</small>`}</footer>
|
|
160
|
-
</div>
|
|
161
|
-
`;
|
|
162
|
-
}
|
|
72
|
+
function App(): NixTemplate {
|
|
73
|
+
return html`
|
|
74
|
+
<nav>${new Link("/", "Home")} ${new Link("/user/42", "User 42")}</nav>
|
|
75
|
+
${new Clock()}
|
|
76
|
+
${new RouterView()}
|
|
77
|
+
`;
|
|
163
78
|
}
|
|
164
79
|
|
|
165
|
-
|
|
166
|
-
.setSlot("header", html`<h1>Título</h1>`)
|
|
167
|
-
.setChildren(html`<p>Cuerpo del card</p>`)
|
|
168
|
-
.setSlot("footer", html`<small>© 2026</small>`);
|
|
169
|
-
|
|
170
|
-
// Function component style:
|
|
171
|
-
function Box({ children }: { children?: NixChildren }) {
|
|
172
|
-
return html`<div class="box">${children}</div>`;
|
|
173
|
-
}
|
|
80
|
+
mount(App(), "#app");
|
|
174
81
|
```
|
|
175
82
|
|
|
176
|
-
|
|
83
|
+
## What's Included
|
|
177
84
|
|
|
178
|
-
|
|
179
|
-
preserving its state, listeners, and child components.
|
|
85
|
+
Everything ships in a single zero-dependency import:
|
|
180
86
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
<!-- hidden when truthy (inverse of show) -->
|
|
192
|
-
<form hide=${() => loading.value}>...</form>
|
|
193
|
-
<div show=${() => loading.value}>⏳ Submitting…</div>
|
|
194
|
-
`
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
Imperative use outside a template:
|
|
198
|
-
|
|
199
|
-
```typescript
|
|
200
|
-
import { showWhen, effect } from "@deijose/nix-js";
|
|
201
|
-
|
|
202
|
-
const panel = document.getElementById("panel") as HTMLElement;
|
|
203
|
-
effect(() => showWhen(panel, isOpen.value));
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Portal
|
|
207
|
-
|
|
208
|
-
Render a template into `document.body` (or any target) — escaping
|
|
209
|
-
`overflow: hidden` and stacking contexts. Ideal for modals, tooltips, toasts.
|
|
210
|
-
The portal is cleaned up automatically when its parent unmounts.
|
|
211
|
-
|
|
212
|
-
```typescript
|
|
213
|
-
import { signal, portal, html } from "@deijose/nix-js";
|
|
214
|
-
|
|
215
|
-
const isOpen = signal(false);
|
|
216
|
-
|
|
217
|
-
html`
|
|
218
|
-
<button @click=${() => { isOpen.value = true; }}>Open modal</button>
|
|
219
|
-
|
|
220
|
-
${() => isOpen.value
|
|
221
|
-
? portal(html`
|
|
222
|
-
<div class="overlay" @click=${() => { isOpen.value = false; }}>
|
|
223
|
-
<div class="modal" @click.stop=${() => {}}>
|
|
224
|
-
<h2>Hello!</h2>
|
|
225
|
-
<button @click=${() => { isOpen.value = false; }}>Close</button>
|
|
226
|
-
</div>
|
|
227
|
-
</div>
|
|
228
|
-
`) // renders into document.body by default
|
|
229
|
-
: null
|
|
230
|
-
}
|
|
231
|
-
`
|
|
232
|
-
|
|
233
|
-
// Custom target:
|
|
234
|
-
portal(html`<div class="toast">Saved!</div>`, "#toast-root")
|
|
235
|
-
portal(html`<Tooltip />`, document.getElementById("tooltip-layer")!)
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Error Boundaries
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
import { createErrorBoundary, html, mount, signal } from "@deijose/nix-js";
|
|
242
|
-
|
|
243
|
-
// Catch render and reactive errors in a subtree
|
|
244
|
-
mount(
|
|
245
|
-
createErrorBoundary(
|
|
246
|
-
html`<div>${() => riskyData()}</div>`,
|
|
247
|
-
(err) => html`<div class="error">Failed: ${String(err)}</div>`
|
|
248
|
-
),
|
|
249
|
-
"#app"
|
|
250
|
-
);
|
|
251
|
-
|
|
252
|
-
// Catches onInit / render / onMount / reactive effects
|
|
253
|
-
createErrorBoundary(new DataWidget(), html`<p>Service unavailable</p>`)
|
|
254
|
-
|
|
255
|
-
// Nested: inner catches first, outer is app-level
|
|
256
|
-
createErrorBoundary(
|
|
257
|
-
html`
|
|
258
|
-
${createErrorBoundary(new RiskyWidget(), html`<p>Widget error</p>`)}
|
|
259
|
-
`,
|
|
260
|
-
html`<p>App crashed</p>`
|
|
261
|
-
)
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Transitions
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
import { signal, html, transition, mount } from "@deijose/nix-js";
|
|
268
|
-
|
|
269
|
-
const show = signal(true);
|
|
270
|
-
|
|
271
|
-
/* CSS in your stylesheet:
|
|
272
|
-
.fade-enter-active, .fade-leave-active { transition: opacity 0.3s ease; }
|
|
273
|
-
.fade-enter-from, .fade-leave-to { opacity: 0; }
|
|
274
|
-
*/
|
|
275
|
-
|
|
276
|
-
mount(
|
|
277
|
-
transition(
|
|
278
|
-
() => show.value ? html`<p>Hello!</p>` : null,
|
|
279
|
-
{ name: "fade" }
|
|
280
|
-
),
|
|
281
|
-
"#app"
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
// Animate on first render too
|
|
285
|
-
transition(html`<header>App</header>`, { name: "slide-down", appear: true });
|
|
286
|
-
|
|
287
|
-
// JS hooks
|
|
288
|
-
transition(content, {
|
|
289
|
-
name: "fade",
|
|
290
|
-
onBeforeEnter: (el) => el.setAttribute("aria-hidden", "false"),
|
|
291
|
-
onAfterLeave: (el) => el.setAttribute("aria-hidden", "true"),
|
|
292
|
-
});
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### Dependency injection
|
|
296
|
-
|
|
297
|
-
```typescript
|
|
298
|
-
import { provide, inject, createInjectionKey } from "@deijose/nix-js";
|
|
299
|
-
|
|
300
|
-
const ThemeKey = createInjectionKey<string>("theme");
|
|
301
|
-
|
|
302
|
-
// Parent component
|
|
303
|
-
function App() {
|
|
304
|
-
provide(ThemeKey, "dark");
|
|
305
|
-
return html`${ThemedCard()}`;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Child component
|
|
309
|
-
function ThemedCard() {
|
|
310
|
-
const theme = inject(ThemeKey); // "dark"
|
|
311
|
-
return html`<div class="card-${theme}">...</div>`;
|
|
312
|
-
}
|
|
313
|
-
```
|
|
87
|
+
| Category | APIs |
|
|
88
|
+
|---|---|
|
|
89
|
+
| **Reactivity** | `signal`, `computed`, `effect`, `batch`, `watch`, `untrack`, `nextTick` |
|
|
90
|
+
| **Templates** | `` html` ` ``, `repeat`, `ref`, `portal`, `transition`, `showWhen` |
|
|
91
|
+
| **Components** | `NixTemplate` (function components), `NixComponent` (lifecycle class), `mount`, children & named slots |
|
|
92
|
+
| **Router** | `createRouter`, `RouterView`, `Link`, `useRouter`, guards, nested routes |
|
|
93
|
+
| **Forms** | `useField`, `createForm`, built-in validators, Zod/Valibot interop |
|
|
94
|
+
| **State** | `createStore`, `provide`, `inject`, `createInjectionKey` |
|
|
95
|
+
| **Async** | `suspend`, `lazy` |
|
|
96
|
+
| **Error handling** | `createErrorBoundary` |
|
|
314
97
|
|
|
315
98
|
## Documentation
|
|
316
99
|
|
|
317
|
-
|
|
100
|
+
Full API reference, guides, and examples:
|
|
318
101
|
|
|
319
|
-
**→ [
|
|
102
|
+
**→ [github.com/DeijoseDevelop/nix-js](https://github.com/DeijoseDevelop/nix-js)**
|
|
320
103
|
|
|
321
104
|
## License
|
|
322
105
|
|
package/dist/lib/nix/async.d.ts
CHANGED
|
@@ -1,68 +1,22 @@
|
|
|
1
1
|
import { NixComponent } from "./lifecycle";
|
|
2
2
|
import type { NixTemplate } from "./template";
|
|
3
3
|
export interface SuspenseOptions {
|
|
4
|
-
/**
|
|
5
|
-
* Template a mostrar mientras la promesa está pendiente.
|
|
6
|
-
* Por defecto: spinner de puntos animados.
|
|
7
|
-
*/
|
|
4
|
+
/** Template shown while the promise is pending. */
|
|
8
5
|
fallback?: NixTemplate;
|
|
9
|
-
/**
|
|
10
|
-
* Factory que recibe el error y devuelve el template de error.
|
|
11
|
-
* Por defecto: mensaje de error en rojo.
|
|
12
|
-
*/
|
|
6
|
+
/** Factory receiving the error, returns the error template. */
|
|
13
7
|
errorFallback?: (err: unknown) => NixTemplate;
|
|
14
|
-
/**
|
|
15
|
-
* Si `true`, mantiene el fallback visible mientras `asyncFn` vuelve a
|
|
16
|
-
* ejecutarse tras un cambio reactivo. Si `false` (por defecto), durante
|
|
17
|
-
* las recargas se sigue mostrando el contenido anterior hasta que la nueva
|
|
18
|
-
* promesa se resuelva.
|
|
19
|
-
*/
|
|
8
|
+
/** If `true`, shows fallback during re-fetches instead of stale content. */
|
|
20
9
|
resetOnRefresh?: boolean;
|
|
21
10
|
}
|
|
22
11
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* @param asyncFn Función que devuelve una promesa con los datos.
|
|
27
|
-
* @param renderFn Recibe los datos resueltos y devuelve el template/componente.
|
|
28
|
-
* @param options `fallback`, `errorFallback`, `resetOnRefresh`.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* // Uso simple con fallback por defecto
|
|
32
|
-
* const userView = suspend(
|
|
33
|
-
* () => fetchUser(userId.value),
|
|
34
|
-
* user => html`<div>${user.name}</div>`
|
|
35
|
-
* );
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* // Con fallback personalizado y manejo de error
|
|
39
|
-
* suspend(
|
|
40
|
-
* () => api.getItems(),
|
|
41
|
-
* items => html`<ul>${items.map(i => html`<li>${i}</li>`)}</ul>`,
|
|
42
|
-
* {
|
|
43
|
-
* fallback: html`<span>Cargando items…</span>`,
|
|
44
|
-
* errorFallback: err => html`<p style="color:red">Error: ${String(err)}</p>`,
|
|
45
|
-
* }
|
|
46
|
-
* )
|
|
12
|
+
* Runs an async function and renders based on its state (pending/resolved/error).
|
|
13
|
+
* Equivalent to the Suspense pattern in other frameworks.
|
|
47
14
|
*/
|
|
48
15
|
export declare function suspend<T>(asyncFn: () => Promise<T>, renderFn: (data: T) => NixTemplate | NixComponent, options?: SuspenseOptions): NixComponent;
|
|
49
16
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* El módulo importado debe exportar el componente como **export default**.
|
|
55
|
-
*
|
|
56
|
-
* @param importFn Función que hace el import dinámico.
|
|
57
|
-
* @param fallback Template opcional mientras se descarga el chunk.
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* createRouter([
|
|
61
|
-
* { path: "/", component: lazy(() => import("./pages/Home")) },
|
|
62
|
-
* { path: "/about", component: lazy(() => import("./pages/About")) },
|
|
63
|
-
* { path: "/admin", component: lazy(() => import("./pages/Admin"),
|
|
64
|
-
* html`<p>Cargando panel…</p>`) },
|
|
65
|
-
* ])
|
|
17
|
+
* Wraps a dynamic import for lazy-loading route components.
|
|
18
|
+
* The module is loaded once (cached). Compatible with `RouteRecord.component`.
|
|
19
|
+
* The imported module must use a default export.
|
|
66
20
|
*/
|
|
67
21
|
export declare function lazy(importFn: () => Promise<{
|
|
68
22
|
default: new () => NixComponent;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { NixTemplate, NixMountHandle } from "./template";
|
|
2
2
|
import { type NixComponent } from "./lifecycle";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Mounts a NixTemplate or NixComponent into the DOM.
|
|
5
5
|
*
|
|
6
|
-
* mount(
|
|
7
|
-
* mount(new Timer(), "#app");
|
|
6
|
+
* mount(Counter(), "#app"); // NixTemplate (function component)
|
|
7
|
+
* mount(new Timer(), "#app"); // NixComponent (class with lifecycle)
|
|
8
8
|
*
|
|
9
|
-
* @param component NixTemplate (
|
|
10
|
-
* @param container
|
|
11
|
-
* @returns { unmount() }
|
|
9
|
+
* @param component NixTemplate (result of html``) or a NixComponent instance.
|
|
10
|
+
* @param container CSS selector or HTMLElement to mount into.
|
|
11
|
+
* @returns { unmount() } — disposes effects and removes DOM.
|
|
12
12
|
*/
|
|
13
13
|
export declare function mount(component: NixTemplate | NixComponent, container: Element | string): NixMountHandle;
|
|
@@ -1,61 +1,27 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Clave tipada para provide/inject.
|
|
3
|
-
* El parámetro genérico T garantiza coherencia entre proveedor y consumidor.
|
|
4
|
-
*
|
|
5
|
-
* @example
|
|
6
|
-
* const THEME_KEY = createInjectionKey<Signal<string>>("theme");
|
|
7
|
-
*/
|
|
1
|
+
/** Typed key for provide/inject. Generic `T` enforces type safety between provider and consumer. */
|
|
8
2
|
export type InjectionKey<T> = symbol & {
|
|
9
3
|
readonly __nixType?: T;
|
|
10
4
|
};
|
|
11
|
-
/**
|
|
12
|
-
* Crea una InjectionKey única y tipada.
|
|
13
|
-
* Cada llamada produce un símbolo distinto, evitando colisiones.
|
|
14
|
-
*
|
|
15
|
-
* @param description Nombre descriptivo (aparece en Symbol.toString())
|
|
16
|
-
*/
|
|
5
|
+
/** Creates a unique typed InjectionKey. */
|
|
17
6
|
export declare function createInjectionKey<T>(description?: string): InjectionKey<T>;
|
|
18
|
-
/** @internal —
|
|
7
|
+
/** @internal — returns a copy of the stack for capturing in effect closures. */
|
|
19
8
|
export declare function _captureContextSnapshot(): Map<unknown, unknown>[];
|
|
20
|
-
/** @internal —
|
|
9
|
+
/** @internal — pushes an empty context for a new component (static render). */
|
|
21
10
|
export declare function _pushComponentContext(): void;
|
|
22
|
-
/** @internal —
|
|
11
|
+
/** @internal — pops the current component context (static render). */
|
|
23
12
|
export declare function _popComponentContext(): void;
|
|
24
13
|
/**
|
|
25
|
-
* @internal —
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* Usado por efectos reactivos que pueden re-ejecutarse fuera del árbol de
|
|
29
|
-
* rendering original (p.ej. NixComponents dentro de `() => new MyComp()`).
|
|
14
|
+
* @internal — executes `fn` with `parentSnapshot` as ancestors and a fresh
|
|
15
|
+
* empty context on top, then restores the previous stack.
|
|
30
16
|
*/
|
|
31
17
|
export declare function _withComponentContext<T>(parentSnapshot: Map<unknown, unknown>[], fn: () => T): T;
|
|
32
18
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* Debe llamarse en `onInit()` o en el constructor de un `NixComponent`.
|
|
37
|
-
* Si se llama fuera del contexto de render de un componente, lanza un error.
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* class ThemeProvider extends NixComponent {
|
|
41
|
-
* theme = signal("dark");
|
|
42
|
-
* onInit() { provide(THEME_KEY, this.theme); } // ← aquí
|
|
43
|
-
* render() { return html`${new ThemedButton()}`; }
|
|
44
|
-
* }
|
|
19
|
+
* Registers a value so descendant components can retrieve it via `inject()`.
|
|
20
|
+
* Must be called inside `onInit()` of a NixComponent.
|
|
45
21
|
*/
|
|
46
22
|
export declare function provide<T>(key: InjectionKey<T> | string | symbol, value: T): void;
|
|
47
23
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* Úsalo como propiedad de clase o dentro de `onInit()`.
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* class ThemedButton extends NixComponent {
|
|
55
|
-
* theme = inject(THEME_KEY); // Signal<string> | undefined
|
|
56
|
-
* render() {
|
|
57
|
-
* return html`<button class=${() => this.theme?.value ?? "light"}>OK</button>`;
|
|
58
|
-
* }
|
|
59
|
-
* }
|
|
24
|
+
* Retrieves a value provided by an ancestor component.
|
|
25
|
+
* Searches child-to-parent; returns `undefined` if the key was not provided.
|
|
60
26
|
*/
|
|
61
27
|
export declare function inject<T>(key: InjectionKey<T> | string | symbol): T | undefined;
|