@tinyfx/runtime 0.1.6 → 0.1.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 +48 -121
- package/dist/context.d.ts +4 -0
- package/dist/context.js +3 -0
- package/dist/http.d.ts +2 -10
- package/dist/http.js +1 -38
- package/dist/index.d.ts +4 -8
- package/dist/index.js +3 -7
- package/dist/router/index.d.ts +3 -0
- package/dist/router/index.js +3 -1
- package/dist/router/lifecycle.js +5 -1
- package/dist/router/params.d.ts +1 -0
- package/dist/router/params.js +3 -0
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
# @tinyfx/runtime
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
A lightweight collection of helpers for reactivity, DOM manipulation, and typed HTTP communication. Designed to be used standalone or as part of the `tinyfx` build pipeline.
|
|
3
|
+
The TinyFX browser runtime: signals, DOM helpers, typed HTTP, and router lifecycle utilities.
|
|
6
4
|
|
|
7
5
|
## Features
|
|
8
6
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
7
|
+
- Signals (`signal`, `effect`)
|
|
8
|
+
- DOM binding helpers (`bindText`, `bindAttr`, `bindClass`)
|
|
9
|
+
- Typed HTTP client (`createHttp`)
|
|
10
|
+
- Router helpers (`initRouter`, `navigate`, `goBack`, `getParam`)
|
|
11
|
+
- Lifecycle hooks (`onMount`, `onDestroy`)
|
|
12
|
+
- Lightweight `TinyFxContext` (`params`, `navigate`)
|
|
14
13
|
|
|
15
14
|
## Installation
|
|
16
15
|
|
|
@@ -20,27 +19,21 @@ npm install @tinyfx/runtime
|
|
|
20
19
|
|
|
21
20
|
## Usage
|
|
22
21
|
|
|
23
|
-
### Signals
|
|
24
|
-
|
|
25
|
-
Signals provide a simple way to manage state that triggers effects when changed.
|
|
22
|
+
### Signals
|
|
26
23
|
|
|
27
24
|
```ts
|
|
28
25
|
import { signal, effect } from "@tinyfx/runtime";
|
|
29
26
|
|
|
30
27
|
const count = signal(0);
|
|
31
28
|
|
|
32
|
-
// Runs immediately, and re-runs whenever count() changes
|
|
33
29
|
effect(() => {
|
|
34
|
-
console.log("
|
|
30
|
+
console.log("count:", count());
|
|
35
31
|
});
|
|
36
32
|
|
|
37
|
-
count.set(
|
|
38
|
-
count.set(count() + 1); // logs: "The count is: 2"
|
|
33
|
+
count.set(count() + 1);
|
|
39
34
|
```
|
|
40
35
|
|
|
41
|
-
### DOM
|
|
42
|
-
|
|
43
|
-
Keep your JS decoupled from the DOM while maintaining reactive updates.
|
|
36
|
+
### DOM bindings
|
|
44
37
|
|
|
45
38
|
```ts
|
|
46
39
|
import { signal, bindText, bindClass, bindAttr } from "@tinyfx/runtime";
|
|
@@ -51,132 +44,66 @@ const isActive = signal(false);
|
|
|
51
44
|
const el = document.getElementById("counter");
|
|
52
45
|
const btn = document.querySelector("button");
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
### Typed HTTP Client
|
|
60
|
-
|
|
61
|
-
A thin wrapper over `fetch` that returns typed responses.
|
|
62
|
-
|
|
63
|
-
```ts
|
|
64
|
-
import { createHttp } from "@tinyfx/runtime";
|
|
65
|
-
|
|
66
|
-
interface User {
|
|
67
|
-
id: number;
|
|
68
|
-
name: string;
|
|
47
|
+
if (el && btn) {
|
|
48
|
+
bindText(el, () => `Count: ${count()}`);
|
|
49
|
+
bindClass(btn, "active", isActive);
|
|
50
|
+
bindAttr(btn, "disabled", () => count() > 10);
|
|
69
51
|
}
|
|
70
|
-
|
|
71
|
-
const api = createHttp({ baseUrl: "/api" });
|
|
72
|
-
|
|
73
|
-
// Fully typed response
|
|
74
|
-
const users = await api.get<User[]>("/users");
|
|
75
|
-
|
|
76
|
-
// POST with data
|
|
77
|
-
await api.post("/users", { name: "Alice" });
|
|
78
52
|
```
|
|
79
53
|
|
|
80
|
-
###
|
|
81
|
-
|
|
82
|
-
TinyFX includes a small dependency injection container to avoid importing singleton instances everywhere.
|
|
83
|
-
|
|
84
|
-
Import it from `@tinyfx/runtime/di`:
|
|
54
|
+
### HTTP client
|
|
85
55
|
|
|
86
56
|
```ts
|
|
87
|
-
import {
|
|
88
|
-
|
|
89
|
-
class Config {
|
|
90
|
-
constructor(public baseUrl: string) {}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const container = new Container();
|
|
94
|
-
container.provide(Config, new Config("/api"));
|
|
95
|
-
|
|
96
|
-
const cfg = container.inject(Config);
|
|
97
|
-
console.log(cfg.baseUrl);
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
#### Using DI with tinyfx components
|
|
101
|
-
|
|
102
|
-
When you use the tinyfx compiler, the generated glue calls your component behavior as:
|
|
57
|
+
import { createHttp } from "@tinyfx/runtime";
|
|
103
58
|
|
|
104
|
-
|
|
105
|
-
|
|
59
|
+
const http = createHttp({ baseUrl: "/api" });
|
|
60
|
+
const users = await http.get<{ id: number; name: string }[]>("/users");
|
|
106
61
|
```
|
|
107
62
|
|
|
108
|
-
|
|
63
|
+
### TinyFxContext
|
|
109
64
|
|
|
110
65
|
```ts
|
|
111
|
-
import type { TinyFxContext } from "@tinyfx/runtime
|
|
112
|
-
import { HttpService } from "../lib/http.service";
|
|
66
|
+
import type { TinyFxContext } from "@tinyfx/runtime";
|
|
113
67
|
|
|
114
68
|
export function init(el: HTMLElement, ctx: TinyFxContext) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
el.textContent = text;
|
|
118
|
-
});
|
|
69
|
+
console.log(ctx.params);
|
|
70
|
+
ctx.navigate("/about");
|
|
119
71
|
}
|
|
120
72
|
```
|
|
121
73
|
|
|
122
|
-
|
|
74
|
+
### Router + lifecycle hooks
|
|
123
75
|
|
|
124
76
|
```ts
|
|
125
|
-
|
|
126
|
-
import { createHttp } from "@tinyfx/runtime";
|
|
127
|
-
|
|
128
|
-
export class HttpService {
|
|
129
|
-
private readonly http;
|
|
77
|
+
import { initRouter, onMount, onDestroy } from "@tinyfx/runtime";
|
|
130
78
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
getWeather() {
|
|
136
|
-
// wttr.in can return plain text; your wrapper returns text when not JSON.
|
|
137
|
-
return this.http.get<string>("");
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
```ts
|
|
143
|
-
// src/main.ts
|
|
144
|
-
import { Container } from "@tinyfx/runtime/di";
|
|
145
|
-
import { setupComponents } from "./tinyfx.gen";
|
|
146
|
-
import { HttpService } from "./lib/http.service";
|
|
79
|
+
initRouter({
|
|
80
|
+
"/": { page: "index", path: "/" },
|
|
81
|
+
});
|
|
147
82
|
|
|
148
|
-
|
|
149
|
-
|
|
83
|
+
onMount(() => {
|
|
84
|
+
console.log("mounted");
|
|
85
|
+
});
|
|
150
86
|
|
|
151
|
-
|
|
152
|
-
|
|
87
|
+
onDestroy(() => {
|
|
88
|
+
console.log("destroyed");
|
|
153
89
|
});
|
|
154
90
|
```
|
|
155
91
|
|
|
156
|
-
## API
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
- `
|
|
160
|
-
- `
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
- `
|
|
164
|
-
- `
|
|
165
|
-
- `
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
- `
|
|
169
|
-
- `
|
|
170
|
-
- `
|
|
171
|
-
- `client.put<T>(url: string, data?: any): Promise<T>`
|
|
172
|
-
- `client.del<T>(url: string): Promise<T>`
|
|
173
|
-
|
|
174
|
-
### DI
|
|
175
|
-
- `new Container()`
|
|
176
|
-
- `container.provide(token, instance)`
|
|
177
|
-
- `container.inject(token)`
|
|
178
|
-
- `createToken<T>(description: string): symbol`
|
|
179
|
-
- `TinyFxContext` (passed to component init via tinyfx glue)
|
|
92
|
+
## API overview
|
|
93
|
+
|
|
94
|
+
- `signal<T>(value: T)`
|
|
95
|
+
- `effect(fn)`
|
|
96
|
+
- `bindText(el, source)`
|
|
97
|
+
- `bindAttr(el, attr, source)`
|
|
98
|
+
- `bindClass(el, className, source)`
|
|
99
|
+
- `createHttp(config?)`
|
|
100
|
+
- `initRouter(routes)`
|
|
101
|
+
- `getParam(name)`
|
|
102
|
+
- `navigate(path)`
|
|
103
|
+
- `goBack()`
|
|
104
|
+
- `onMount(fn)`
|
|
105
|
+
- `onDestroy(fn)`
|
|
106
|
+
- `TinyFxContext`
|
|
180
107
|
|
|
181
108
|
## License
|
|
182
109
|
|
package/dist/context.js
ADDED
package/dist/http.d.ts
CHANGED
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
headers?: Record<string, string>;
|
|
4
|
-
}
|
|
5
|
-
export declare function createHttp(config?: HttpConfig): {
|
|
6
|
-
get: <T>(url: string) => Promise<T>;
|
|
7
|
-
post: <T>(url: string, body?: unknown) => Promise<T>;
|
|
8
|
-
put: <T>(url: string, body?: unknown) => Promise<T>;
|
|
9
|
-
del: <T>(url: string) => Promise<T>;
|
|
10
|
-
};
|
|
1
|
+
export { createHttp } from "./http/http";
|
|
2
|
+
export type { HttpConfig } from "./http/data";
|
package/dist/http.js
CHANGED
|
@@ -1,38 +1 @@
|
|
|
1
|
-
|
|
2
|
-
// Thin, typed wrapper over fetch.
|
|
3
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
-
});
|
|
11
|
-
};
|
|
12
|
-
export function createHttp(config = {}) {
|
|
13
|
-
var _a, _b;
|
|
14
|
-
const base = (_a = config.baseUrl) !== null && _a !== void 0 ? _a : "";
|
|
15
|
-
const defaultHeaders = (_b = config.headers) !== null && _b !== void 0 ? _b : {};
|
|
16
|
-
function request(method, url, body) {
|
|
17
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
18
|
-
const headers = Object.assign({}, defaultHeaders);
|
|
19
|
-
if (body !== undefined) {
|
|
20
|
-
headers["Content-Type"] = "application/json";
|
|
21
|
-
}
|
|
22
|
-
const res = yield fetch(base + url, {
|
|
23
|
-
method,
|
|
24
|
-
headers,
|
|
25
|
-
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
26
|
-
});
|
|
27
|
-
if (!res.ok)
|
|
28
|
-
throw new Error(`${method} ${url}: ${res.status} ${res.statusText}`);
|
|
29
|
-
return res.json();
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
return {
|
|
33
|
-
get: (url) => request("GET", url),
|
|
34
|
-
post: (url, body) => request("POST", url, body),
|
|
35
|
-
put: (url, body) => request("PUT", url, body),
|
|
36
|
-
del: (url) => request("DELETE", url),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
1
|
+
export { createHttp } from "./http/http";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
export { signal, effect
|
|
1
|
+
export { signal, effect } from "./signals";
|
|
2
2
|
export { bindText, bindAttr, bindClass } from "./dom";
|
|
3
|
-
export { createHttp } from "./http
|
|
4
|
-
export
|
|
5
|
-
export { Container, createToken } from "./di";
|
|
6
|
-
export type { Token, TinyFxContext } from "./di";
|
|
7
|
-
export { initRouter } from "./router/index";
|
|
8
|
-
export { getParam } from "./router/params";
|
|
3
|
+
export { createHttp } from "./http";
|
|
4
|
+
export { initRouter, getParam, navigate, goBack } from "./router/index";
|
|
9
5
|
export { onMount, onDestroy } from "./router/lifecycle";
|
|
10
|
-
export {
|
|
6
|
+
export type { TinyFxContext } from "./context";
|
|
11
7
|
export type { RouteMap, RouteMeta } from "./router/types";
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
// @tinyfx/runtime — barrel export
|
|
2
|
-
export { signal, effect
|
|
2
|
+
export { signal, effect } from "./signals";
|
|
3
3
|
export { bindText, bindAttr, bindClass } from "./dom";
|
|
4
|
-
export { createHttp } from "./http
|
|
5
|
-
export {
|
|
6
|
-
// Router — hard file-based router
|
|
7
|
-
export { initRouter } from "./router/index";
|
|
8
|
-
export { getParam } from "./router/params";
|
|
4
|
+
export { createHttp } from "./http";
|
|
5
|
+
export { initRouter, getParam, navigate, goBack } from "./router/index";
|
|
9
6
|
export { onMount, onDestroy } from "./router/lifecycle";
|
|
10
|
-
export { navigate, goBack } from "./router/navigate";
|
package/dist/router/index.d.ts
CHANGED
package/dist/router/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// @tinyfx/runtime — router entry point
|
|
2
|
-
import {
|
|
2
|
+
import { navigate, goBack } from "./navigate";
|
|
3
|
+
import { getParam, resolveParams } from "./params";
|
|
3
4
|
import { initLifecycle } from "./lifecycle";
|
|
4
5
|
import { highlightActiveLinks } from "./active-links";
|
|
6
|
+
export { navigate, goBack, getParam };
|
|
5
7
|
/**
|
|
6
8
|
* Initialise the TinyFX router for the current page.
|
|
7
9
|
*
|
package/dist/router/lifecycle.js
CHANGED
|
@@ -8,7 +8,11 @@ const destroyCallbacks = [];
|
|
|
8
8
|
* - If the document is already loaded, the callback runs immediately.
|
|
9
9
|
*/
|
|
10
10
|
export function onMount(fn) {
|
|
11
|
-
|
|
11
|
+
if (document.readyState === "loading") {
|
|
12
|
+
mountCallbacks.push(fn);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
fn();
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
18
|
* Register a callback to run when the user navigates away from this page.
|
package/dist/router/params.d.ts
CHANGED
package/dist/router/params.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinyfx/runtime",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Minimal frontend runtime — signals, DOM helpers, typed HTTP, DTO mapping",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
"./signals": "./dist/signals.js",
|
|
11
11
|
"./dom": "./dist/dom.js",
|
|
12
12
|
"./http": "./dist/http.js",
|
|
13
|
-
"./di": "./dist/di.js",
|
|
14
13
|
"./router": "./dist/router/index.js"
|
|
15
14
|
},
|
|
16
15
|
"files": [
|