@tinyfx/runtime 0.1.8 → 0.2.0

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.
Files changed (52) hide show
  1. package/dist/__tests__/http-errors.test.d.ts +1 -0
  2. package/dist/__tests__/http-errors.test.js +65 -0
  3. package/dist/__tests__/mount-state.test.d.ts +1 -0
  4. package/dist/__tests__/mount-state.test.js +30 -0
  5. package/dist/__tests__/page-registry.test.d.ts +1 -0
  6. package/dist/__tests__/page-registry.test.js +38 -0
  7. package/dist/__tests__/path-matcher.test.d.ts +1 -0
  8. package/dist/__tests__/path-matcher.test.js +43 -0
  9. package/dist/__tests__/registry.test.d.ts +1 -0
  10. package/dist/__tests__/registry.test.js +67 -0
  11. package/dist/__tests__/router-merged.test.d.ts +1 -0
  12. package/dist/__tests__/router-merged.test.js +33 -0
  13. package/dist/__tests__/signals.test.d.ts +1 -0
  14. package/dist/__tests__/signals.test.js +93 -0
  15. package/dist/context.d.ts +15 -0
  16. package/dist/context.js +0 -2
  17. package/dist/dom.d.ts +35 -0
  18. package/dist/dom.js +35 -0
  19. package/dist/each.d.ts +10 -0
  20. package/dist/each.js +24 -0
  21. package/dist/http/data.d.ts +84 -17
  22. package/dist/http/data.js +15 -23
  23. package/dist/http/helper.d.ts +20 -0
  24. package/dist/http/helper.js +20 -0
  25. package/dist/http/http.d.ts +13 -0
  26. package/dist/http/http.js +19 -6
  27. package/dist/index.d.ts +10 -2
  28. package/dist/index.js +9 -1
  29. package/dist/init.d.ts +12 -0
  30. package/dist/init.js +42 -0
  31. package/dist/mount-state.d.ts +17 -0
  32. package/dist/mount-state.js +27 -0
  33. package/dist/page-registry.d.ts +31 -0
  34. package/dist/page-registry.js +38 -0
  35. package/dist/registry.d.ts +31 -0
  36. package/dist/registry.js +49 -0
  37. package/dist/router/active-links.d.ts +3 -0
  38. package/dist/router/active-links.js +3 -0
  39. package/dist/router/index.d.ts +21 -22
  40. package/dist/router/index.js +12 -35
  41. package/dist/router/lifecycle.d.ts +28 -2
  42. package/dist/router/lifecycle.js +28 -2
  43. package/dist/router/navigate.d.ts +8 -0
  44. package/dist/router/navigate.js +8 -0
  45. package/dist/router/params.d.ts +15 -7
  46. package/dist/router/params.js +16 -25
  47. package/dist/router/path-matcher.d.ts +30 -0
  48. package/dist/router/path-matcher.js +45 -0
  49. package/dist/router/types.d.ts +15 -2
  50. package/dist/signals.d.ts +28 -7
  51. package/dist/signals.js +41 -21
  52. package/package.json +6 -2
package/dist/http/data.js CHANGED
@@ -1,26 +1,18 @@
1
- export class HttpError extends Error {
2
- constructor(status, statusText, url, method, response) {
3
- super(`HTTP ${status} ${statusText}: ${method} ${url}`);
4
- this.status = status;
5
- this.statusText = statusText;
6
- this.url = url;
7
- this.method = method;
8
- this.response = response;
9
- this.name = "HttpError";
10
- }
1
+ export function httpError(status, statusText, url, method, response) {
2
+ return { kind: "http", status, statusText, url, method, response };
11
3
  }
12
- export class HttpTimeoutError extends Error {
13
- constructor(url, timeout) {
14
- super(`Request timeout after ${timeout}ms: ${url}`);
15
- this.url = url;
16
- this.timeout = timeout;
17
- this.name = "HttpTimeoutError";
18
- }
4
+ export function timeoutError(url, timeout) {
5
+ return { kind: "timeout", url, timeout };
19
6
  }
20
- export class HttpParseError extends Error {
21
- constructor(message, url) {
22
- super(message);
23
- this.url = url;
24
- this.name = "HttpParseError";
25
- }
7
+ export function parseError(message, url) {
8
+ return { kind: "parse", message, url };
9
+ }
10
+ export function isHttpError(err) {
11
+ return typeof err === "object" && err !== null && "kind" in err && err.kind === "http";
12
+ }
13
+ export function isTimeoutError(err) {
14
+ return typeof err === "object" && err !== null && "kind" in err && err.kind === "timeout";
15
+ }
16
+ export function isParseError(err) {
17
+ return typeof err === "object" && err !== null && "kind" in err && err.kind === "parse";
26
18
  }
@@ -1,2 +1,22 @@
1
+ /**
2
+ * Builds a request URL by combining a base path with optional query params.
3
+ *
4
+ * @param url - The request path or URL fragment
5
+ * @param base - The configured base URL prefix
6
+ * @param params - Optional query parameters to append
7
+ * @returns The final request URL string
8
+ *
9
+ * @example
10
+ * buildUrl("/posts", "/api", { page: 2, published: true });
11
+ */
1
12
  export declare function buildUrl(url: string, base: string, params?: Record<string, string | number | boolean>): string;
13
+ /**
14
+ * Waits for a number of milliseconds.
15
+ *
16
+ * @param ms - The delay duration in milliseconds
17
+ * @returns A promise that resolves after the delay completes
18
+ *
19
+ * @example
20
+ * await sleep(250);
21
+ */
2
22
  export declare function sleep(ms: number): Promise<void>;
@@ -1,3 +1,14 @@
1
+ /**
2
+ * Builds a request URL by combining a base path with optional query params.
3
+ *
4
+ * @param url - The request path or URL fragment
5
+ * @param base - The configured base URL prefix
6
+ * @param params - Optional query parameters to append
7
+ * @returns The final request URL string
8
+ *
9
+ * @example
10
+ * buildUrl("/posts", "/api", { page: 2, published: true });
11
+ */
1
12
  export function buildUrl(url, base, params) {
2
13
  const fullUrl = base + url;
3
14
  if (!params || Object.keys(params).length === 0)
@@ -8,6 +19,15 @@ export function buildUrl(url, base, params) {
8
19
  });
9
20
  return urlObj.toString().replace(urlObj.origin, '');
10
21
  }
22
+ /**
23
+ * Waits for a number of milliseconds.
24
+ *
25
+ * @param ms - The delay duration in milliseconds
26
+ * @returns A promise that resolves after the delay completes
27
+ *
28
+ * @example
29
+ * await sleep(250);
30
+ */
11
31
  export async function sleep(ms) {
12
32
  return new Promise(resolve => setTimeout(resolve, ms));
13
33
  }
@@ -1,4 +1,17 @@
1
1
  import { HttpConfig, RequestOptions } from "./data";
2
+ /**
3
+ * Creates a typed HTTP client around `fetch`.
4
+ *
5
+ * The client exposes `get`, `post`, `put`, `patch`, `del`, and `delete`
6
+ * helpers and applies the default configuration to every request.
7
+ *
8
+ * @param config - Default HTTP configuration such as base URL, headers, and retry policy
9
+ * @returns An object containing typed request methods
10
+ *
11
+ * @example
12
+ * const http = createHttp({ baseUrl: "/api", timeout: 5000 });
13
+ * const posts = await http.get<{ id: number; title: string }[]>("/posts");
14
+ */
2
15
  export declare function createHttp(config?: HttpConfig): {
3
16
  get: <T>(url: string, options?: RequestOptions) => Promise<T>;
4
17
  post: <T>(url: string, body?: unknown, options?: RequestOptions) => Promise<T>;
package/dist/http/http.js CHANGED
@@ -1,7 +1,20 @@
1
1
  // @tinyfx/runtime — HTTP client
2
2
  // Thin, typed wrapper over fetch.
3
- import { HttpError, HttpParseError, HttpTimeoutError } from "./data";
3
+ import { httpError, timeoutError, parseError, isHttpError } from "./data";
4
4
  import { buildUrl, sleep } from "./helper";
5
+ /**
6
+ * Creates a typed HTTP client around `fetch`.
7
+ *
8
+ * The client exposes `get`, `post`, `put`, `patch`, `del`, and `delete`
9
+ * helpers and applies the default configuration to every request.
10
+ *
11
+ * @param config - Default HTTP configuration such as base URL, headers, and retry policy
12
+ * @returns An object containing typed request methods
13
+ *
14
+ * @example
15
+ * const http = createHttp({ baseUrl: "/api", timeout: 5000 });
16
+ * const posts = await http.get<{ id: number; title: string }[]>("/posts");
17
+ */
5
18
  export function createHttp(config = {}) {
6
19
  var _a, _b, _c, _d, _e, _f, _g;
7
20
  const base = (_a = config.baseUrl) !== null && _a !== void 0 ? _a : "";
@@ -60,7 +73,7 @@ export function createHttp(config = {}) {
60
73
  if ((_b = options.signal) === null || _b === void 0 ? void 0 : _b.aborted) {
61
74
  throw err; // User cancelled
62
75
  }
63
- throw new HttpTimeoutError(requestUrl, timeoutMs);
76
+ throw timeoutError(requestUrl, timeoutMs);
64
77
  }
65
78
  throw err;
66
79
  }
@@ -72,7 +85,7 @@ export function createHttp(config = {}) {
72
85
  res = await interceptor(res);
73
86
  }
74
87
  if (!res.ok) {
75
- throw new HttpError(res.status, res.statusText, requestUrl, method, res);
88
+ throw httpError(res.status, res.statusText, requestUrl, method, res);
76
89
  }
77
90
  // Parse response based on content type
78
91
  const contentType = res.headers.get("content-type") || "";
@@ -85,7 +98,7 @@ export function createHttp(config = {}) {
85
98
  return JSON.parse(text);
86
99
  }
87
100
  catch (err) {
88
- throw new HttpParseError(`Failed to parse JSON response: ${err instanceof Error ? err.message : "Unknown error"}`, requestUrl);
101
+ throw parseError(`Failed to parse JSON response: ${err instanceof Error ? err.message : "Unknown error"}`, requestUrl);
89
102
  }
90
103
  }
91
104
  if (contentType.includes("text/")) {
@@ -102,8 +115,8 @@ export function createHttp(config = {}) {
102
115
  }
103
116
  catch (err) {
104
117
  // Retry logic for network errors or 5xx errors
105
- const shouldRetry = attempts < maxAttempts &&
106
- (!(err instanceof HttpError) || (err.status >= 500 && err.status < 600));
118
+ const is5xx = isHttpError(err) && err.status >= 500 && err.status < 600;
119
+ const shouldRetry = attempts < maxAttempts && (!isHttpError(err) || is5xx);
107
120
  if (shouldRetry) {
108
121
  await sleep(retryDelay * attempts);
109
122
  continue;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  export { signal, effect } from "./signals";
2
+ export { registerInstance, destroyNode } from "./each";
2
3
  export { bindText, bindAttr, bindClass } from "./dom";
3
4
  export { createHttp } from "./http";
4
- export { initRouter, getParam, navigate, goBack } from "./router/index";
5
+ export { registerComponent, getComponentFactory, mountComponents } from "./registry";
6
+ export { registerPage, getPageModule, runPageInit } from "./page-registry";
7
+ export { markMounted, isMounted } from "./mount-state";
8
+ export { matchPath, splitPath } from "./router/path-matcher";
9
+ export type { RouteDef } from "./router/path-matcher";
10
+ export { init } from "./init";
11
+ export type { InitConfig } from "./init";
12
+ export { getParam, getParams, navigate, goBack } from "./router/index";
5
13
  export { onMount, onDestroy } from "./router/lifecycle";
6
14
  export type { TinyFxContext } from "./context";
7
- export type { RouteMap, RouteMeta } from "./router/types";
15
+ export type { RouteMap, RouteMeta } from "./router/index";
package/dist/index.js CHANGED
@@ -1,6 +1,14 @@
1
1
  // @tinyfx/runtime — barrel export
2
2
  export { signal, effect } from "./signals";
3
+ export { registerInstance, destroyNode } from "./each";
3
4
  export { bindText, bindAttr, bindClass } from "./dom";
4
5
  export { createHttp } from "./http";
5
- export { initRouter, getParam, navigate, goBack } from "./router/index";
6
+ // New decoupled APIs
7
+ export { registerComponent, getComponentFactory, mountComponents } from "./registry";
8
+ export { registerPage, getPageModule, runPageInit } from "./page-registry";
9
+ export { markMounted, isMounted } from "./mount-state";
10
+ export { matchPath, splitPath } from "./router/path-matcher";
11
+ export { init } from "./init";
12
+ // Keep existing router exports
13
+ export { getParam, getParams, navigate, goBack } from "./router/index";
6
14
  export { onMount, onDestroy } from "./router/lifecycle";
package/dist/init.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { TinyFxContext } from "./context";
2
+ import type { RouteDef } from "./router/path-matcher";
3
+ export interface InitConfig {
4
+ routes: Record<string, RouteDef>;
5
+ setupDirectives?: (ctx: TinyFxContext) => void;
6
+ }
7
+ export interface InitResult {
8
+ matchedPath: string;
9
+ params: Record<string, string>;
10
+ instances: any[];
11
+ }
12
+ export declare function init(config: InitConfig): InitResult | null;
package/dist/init.js ADDED
@@ -0,0 +1,42 @@
1
+ // @tinyfx/runtime — unified initialization
2
+ // Single entry point for TinyFX bootstrap.
3
+ import { matchPath, splitPath } from "./router/path-matcher";
4
+ import { initLifecycle } from "./router/lifecycle";
5
+ import { highlightActiveLinks } from "./router/active-links";
6
+ import { navigate } from "./router/index";
7
+ import { setParams } from "./router/params";
8
+ import { mountComponents } from "./registry";
9
+ import { runPageInit } from "./page-registry";
10
+ let initialized = false;
11
+ export function init(config) {
12
+ if (initialized)
13
+ return null;
14
+ initialized = true;
15
+ const pathname = window.location.pathname;
16
+ const pathSegments = splitPath(pathname);
17
+ let matchedPath = null;
18
+ let params = {};
19
+ for (const [path, def] of Object.entries(config.routes)) {
20
+ const result = matchPath(def, pathSegments);
21
+ if (result) {
22
+ matchedPath = path;
23
+ params = result;
24
+ break;
25
+ }
26
+ }
27
+ if (!matchedPath) {
28
+ console.warn(`[tinyfx] No route matched for pathname: "${pathname}". ` +
29
+ "Check that a page file exists for this URL in src/pages/.");
30
+ return null;
31
+ }
32
+ initLifecycle();
33
+ highlightActiveLinks(pathname);
34
+ setParams(params);
35
+ const ctx = { params, navigate };
36
+ const instances = mountComponents(ctx);
37
+ if (config.setupDirectives) {
38
+ config.setupDirectives(ctx);
39
+ }
40
+ runPageInit(matchedPath, ctx);
41
+ return { matchedPath, params, instances };
42
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Mark an element as mounted. Returns false if already mounted.
3
+ *
4
+ * @param el - The element to mark
5
+ * @returns true if newly marked, false if already mounted
6
+ *
7
+ * @example
8
+ * if (!markMounted(el)) return undefined;
9
+ */
10
+ export declare function markMounted(el: HTMLElement): boolean;
11
+ /**
12
+ * Check if an element has been marked as mounted.
13
+ *
14
+ * @param el - The element to check
15
+ * @returns true if the element is marked as mounted
16
+ */
17
+ export declare function isMounted(el: HTMLElement): boolean;
@@ -0,0 +1,27 @@
1
+ // @tinyfx/runtime — mount state tracking
2
+ // WeakSet-based mount tracking that is safe for minifier mangling.
3
+ const mounted = new WeakSet();
4
+ /**
5
+ * Mark an element as mounted. Returns false if already mounted.
6
+ *
7
+ * @param el - The element to mark
8
+ * @returns true if newly marked, false if already mounted
9
+ *
10
+ * @example
11
+ * if (!markMounted(el)) return undefined;
12
+ */
13
+ export function markMounted(el) {
14
+ if (mounted.has(el))
15
+ return false;
16
+ mounted.add(el);
17
+ return true;
18
+ }
19
+ /**
20
+ * Check if an element has been marked as mounted.
21
+ *
22
+ * @param el - The element to check
23
+ * @returns true if the element is marked as mounted
24
+ */
25
+ export function isMounted(el) {
26
+ return mounted.has(el);
27
+ }
@@ -0,0 +1,31 @@
1
+ import type { TinyFxContext } from "./context";
2
+ type PageModule = {
3
+ init?: (el: HTMLElement, ctx: TinyFxContext) => void;
4
+ };
5
+ /**
6
+ * Register a page module by its route path.
7
+ *
8
+ * @param path - The route path (e.g., "/blog/:slug")
9
+ * @param module - The page module object with optional init()
10
+ * @returns Nothing
11
+ *
12
+ * @example
13
+ * registerPage("/blog/:slug", PageModule);
14
+ */
15
+ export declare function registerPage(path: string, module: PageModule): void;
16
+ /**
17
+ * Retrieve a registered page module.
18
+ *
19
+ * @param path - The route path to look up
20
+ * @returns The page module, or undefined if not registered
21
+ */
22
+ export declare function getPageModule(path: string): PageModule | undefined;
23
+ /**
24
+ * Run the init() function for a registered page module.
25
+ *
26
+ * @param path - The route path of the page to initialize
27
+ * @param ctx - The TinyFx context to pass to page init
28
+ * @returns Nothing
29
+ */
30
+ export declare function runPageInit(path: string, ctx: TinyFxContext): void;
31
+ export {};
@@ -0,0 +1,38 @@
1
+ // @tinyfx/runtime — page module registry
2
+ // Decoupled page module registration for tree-shakable bundles.
3
+ const modules = new Map();
4
+ /**
5
+ * Register a page module by its route path.
6
+ *
7
+ * @param path - The route path (e.g., "/blog/:slug")
8
+ * @param module - The page module object with optional init()
9
+ * @returns Nothing
10
+ *
11
+ * @example
12
+ * registerPage("/blog/:slug", PageModule);
13
+ */
14
+ export function registerPage(path, module) {
15
+ modules.set(path, module);
16
+ }
17
+ /**
18
+ * Retrieve a registered page module.
19
+ *
20
+ * @param path - The route path to look up
21
+ * @returns The page module, or undefined if not registered
22
+ */
23
+ export function getPageModule(path) {
24
+ return modules.get(path);
25
+ }
26
+ /**
27
+ * Run the init() function for a registered page module.
28
+ *
29
+ * @param path - The route path of the page to initialize
30
+ * @param ctx - The TinyFx context to pass to page init
31
+ * @returns Nothing
32
+ */
33
+ export function runPageInit(path, ctx) {
34
+ const mod = modules.get(path);
35
+ if (typeof (mod === null || mod === void 0 ? void 0 : mod.init) === "function") {
36
+ mod.init(document.body, ctx);
37
+ }
38
+ }
@@ -0,0 +1,31 @@
1
+ import type { TinyFxContext } from "./context";
2
+ type ComponentFactory = (el: HTMLElement, ctx: TinyFxContext) => any;
3
+ /**
4
+ * Register a component factory by name.
5
+ *
6
+ * @param name - The component name (matches `data-component` attribute)
7
+ * @param factory - A function that mounts the component and returns an instance
8
+ * @returns Nothing
9
+ *
10
+ * @example
11
+ * registerComponent("Button", (el, ctx) => {
12
+ * return ButtonModule.mount(el, ctx);
13
+ * });
14
+ */
15
+ export declare function registerComponent(name: string, factory: ComponentFactory): void;
16
+ /**
17
+ * Retrieve a registered component factory.
18
+ *
19
+ * @param name - The component name to look up
20
+ * @returns The factory function, or undefined if not registered
21
+ */
22
+ export declare function getComponentFactory(name: string): ComponentFactory | undefined;
23
+ /**
24
+ * Mount all registered components found within a root element.
25
+ *
26
+ * @param ctx - The TinyFx context to pass to each component
27
+ * @param root - The root element to scan (defaults to document)
28
+ * @returns Array of mounted component instances
29
+ */
30
+ export declare function mountComponents(ctx: TinyFxContext, root?: Document | HTMLElement): any[];
31
+ export {};
@@ -0,0 +1,49 @@
1
+ // @tinyfx/runtime — component registry
2
+ // Decoupled component registration for tree-shakable bundles.
3
+ const factories = new Map();
4
+ /**
5
+ * Register a component factory by name.
6
+ *
7
+ * @param name - The component name (matches `data-component` attribute)
8
+ * @param factory - A function that mounts the component and returns an instance
9
+ * @returns Nothing
10
+ *
11
+ * @example
12
+ * registerComponent("Button", (el, ctx) => {
13
+ * return ButtonModule.mount(el, ctx);
14
+ * });
15
+ */
16
+ export function registerComponent(name, factory) {
17
+ factories.set(name, factory);
18
+ }
19
+ /**
20
+ * Retrieve a registered component factory.
21
+ *
22
+ * @param name - The component name to look up
23
+ * @returns The factory function, or undefined if not registered
24
+ */
25
+ export function getComponentFactory(name) {
26
+ return factories.get(name);
27
+ }
28
+ /**
29
+ * Mount all registered components found within a root element.
30
+ *
31
+ * @param ctx - The TinyFx context to pass to each component
32
+ * @param root - The root element to scan (defaults to document)
33
+ * @returns Array of mounted component instances
34
+ */
35
+ export function mountComponents(ctx, root = document) {
36
+ const instances = [];
37
+ root.querySelectorAll("[data-component]").forEach((el) => {
38
+ const name = el.getAttribute("data-component");
39
+ if (!name)
40
+ return;
41
+ const factory = factories.get(name);
42
+ if (!factory)
43
+ return;
44
+ const inst = factory(el, ctx);
45
+ if (inst)
46
+ instances.push(inst);
47
+ });
48
+ return instances;
49
+ }
@@ -5,6 +5,9 @@
5
5
  * Only the pathname portion of each href is compared (query strings and
6
6
  * fragments are ignored).
7
7
  *
8
+ * @param pathname - The pathname to compare each link against
9
+ * @returns Nothing
10
+ *
8
11
  * @example
9
12
  * // In a nav: <a href="/blog">Blog</a>
10
13
  * // On the /blog page this element will get data-active="true"
@@ -6,6 +6,9 @@
6
6
  * Only the pathname portion of each href is compared (query strings and
7
7
  * fragments are ignored).
8
8
  *
9
+ * @param pathname - The pathname to compare each link against
10
+ * @returns Nothing
11
+ *
9
12
  * @example
10
13
  * // In a nav: <a href="/blog">Blog</a>
11
14
  * // On the /blog page this element will get data-active="true"
@@ -1,24 +1,23 @@
1
- import type { RouteMap } from "./types";
2
- import { navigate, goBack } from "./navigate";
3
- import { getParam } from "./params";
4
- export type { RouteMap };
5
- export { navigate, goBack, getParam };
6
1
  /**
7
- * Initialise the TinyFX router for the current page.
8
- *
9
- * Called automatically from the compiler-generated `tinyfx.gen.ts` on every
10
- * page load. Matches `window.location.pathname` against the compiled route
11
- * map, resolves URL params, starts lifecycle hooks, and highlights active
12
- * navigation links.
13
- *
14
- * @param routes - The route map emitted by `tinyfx build`.
15
- *
16
- * @example
17
- * // tinyfx.gen.ts (auto-generated — do not edit)
18
- * initRouter({
19
- * "/": { page: "home", path: "/" },
20
- * "/blog": { page: "blog", path: "/blog" },
21
- * "/blog/:slug":{ page: "blog-post", path: "/blog/:slug" },
22
- * });
2
+ * Metadata for a single route produced by the compiler.
23
3
  */
24
- export declare function initRouter(routes: RouteMap): void;
4
+ export interface RouteMeta {
5
+ /** The page name, derived from the source filename. */
6
+ page: string;
7
+ /** The declared URL pattern, e.g. "/blog/:slug". */
8
+ path: string;
9
+ }
10
+ /**
11
+ * The full route map emitted by `tinyfx build` into `tinyfx.gen.ts`.
12
+ */
13
+ export type RouteMap = Record<string, RouteMeta>;
14
+ /**
15
+ * Navigate to the given path.
16
+ * This is a full browser navigation — not a DOM swap.
17
+ */
18
+ export declare function navigate(path: string): void;
19
+ /**
20
+ * Go back one step in the browser history.
21
+ */
22
+ export declare function goBack(): void;
23
+ export { getParam, getParams } from "./params";
@@ -1,38 +1,15 @@
1
- // @tinyfx/runtime — router entry point
2
- import { navigate, goBack } from "./navigate";
3
- import { getParam, resolveParams } from "./params";
4
- import { initLifecycle } from "./lifecycle";
5
- import { highlightActiveLinks } from "./active-links";
6
- export { navigate, goBack, getParam };
1
+ // @tinyfx/runtime — router utilities
7
2
  /**
8
- * Initialise the TinyFX router for the current page.
9
- *
10
- * Called automatically from the compiler-generated `tinyfx.gen.ts` on every
11
- * page load. Matches `window.location.pathname` against the compiled route
12
- * map, resolves URL params, starts lifecycle hooks, and highlights active
13
- * navigation links.
14
- *
15
- * @param routes - The route map emitted by `tinyfx build`.
16
- *
17
- * @example
18
- * // tinyfx.gen.ts (auto-generated — do not edit)
19
- * initRouter({
20
- * "/": { page: "home", path: "/" },
21
- * "/blog": { page: "blog", path: "/blog" },
22
- * "/blog/:slug":{ page: "blog-post", path: "/blog/:slug" },
23
- * });
3
+ * Navigate to the given path.
4
+ * This is a full browser navigation — not a DOM swap.
24
5
  */
25
- export function initRouter(routes) {
26
- const pathname = window.location.pathname;
27
- for (const pattern of Object.keys(routes)) {
28
- if (resolveParams(pattern, pathname)) {
29
- // Match found
30
- initLifecycle();
31
- highlightActiveLinks(pathname);
32
- return;
33
- }
34
- }
35
- // No route matched — log a warning and do nothing else.
36
- console.warn(`[tinyfx] No route matched for pathname: "${pathname}". ` +
37
- "Check that a page file exists for this URL in src/pages/.");
6
+ export function navigate(path) {
7
+ window.location.href = path;
38
8
  }
9
+ /**
10
+ * Go back one step in the browser history.
11
+ */
12
+ export function goBack() {
13
+ window.history.go(-1);
14
+ }
15
+ export { getParam, getParams } from "./params";
@@ -4,21 +4,47 @@ type LifecycleCallback = () => void;
4
4
  *
5
5
  * - If the document is still loading, the callback runs after DOMContentLoaded.
6
6
  * - If the document is already loaded, the callback runs immediately.
7
+ *
8
+ * @param fn - The callback to run on mount
9
+ * @returns Nothing
10
+ *
11
+ * @example
12
+ * onMount(() => {
13
+ * console.log("page ready");
14
+ * });
7
15
  */
8
16
  export declare function onMount(fn: LifecycleCallback): void;
9
17
  /**
10
18
  * Register a callback to run when the user navigates away from this page.
11
19
  * Fires on the browser's `pagehide` event.
20
+ *
21
+ * @param fn - The callback to run during page teardown
22
+ * @returns Nothing
23
+ *
24
+ * @example
25
+ * onDestroy(() => {
26
+ * console.log("page leaving");
27
+ * });
12
28
  */
13
29
  export declare function onDestroy(fn: LifecycleCallback): void;
14
30
  /**
15
31
  * Trigger all registered `onMount` callbacks.
16
- * Called by `initRouter` after matching the current route.
32
+ * Called by `init()` after matching the current route.
33
+ *
34
+ * @returns Nothing
35
+ *
36
+ * @example
37
+ * flushMount();
17
38
  */
18
39
  export declare function flushMount(): void;
19
40
  /**
20
41
  * Wire up registered `onDestroy` callbacks to the `pagehide` event.
21
- * Called by `initRouter` after matching the current route.
42
+ * Called by `init()` after matching the current route.
43
+ *
44
+ * @returns Nothing
45
+ *
46
+ * @example
47
+ * initLifecycle();
22
48
  */
23
49
  export declare function initLifecycle(): void;
24
50
  export {};