@source-crafter/xzor-runtime 0.0.0-stage → 0.1.1

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/index.d.ts ADDED
@@ -0,0 +1,233 @@
1
+ type Handler = (e: Event) => unknown;
2
+ type Modifier = "preventDefault" | "stopPropagation";
3
+ type Modifiers = Partial<Record<Modifier, boolean>>;
4
+ export type VText = {
5
+ kind: "text";
6
+ text: string;
7
+ dom?: Text;
8
+ };
9
+ export type VElement = {
10
+ kind: "element";
11
+ tag: string;
12
+ attrs: Record<string, string>;
13
+ events: Record<string, Handler>;
14
+ modifiers: Record<string, Modifiers>;
15
+ children: VNode[];
16
+ key?: unknown;
17
+ ref?: (el: Element) => void;
18
+ dom?: Element;
19
+ };
20
+ /** One `@cascade:name(value)` provider; created on the region's first render and carried across the next ones. */
21
+ type CascadeRecord = {
22
+ name: string;
23
+ value: unknown;
24
+ fixed: boolean;
25
+ consumers: Set<ComponentBase> | undefined;
26
+ parent: CascadeRecord | undefined;
27
+ };
28
+ /** Output of one `@if`/`@for`/`@switch`/`@cascade`; its contents are diffed in isolation. */
29
+ export type VRegion = {
30
+ kind: "region";
31
+ children: VNode[];
32
+ anchor?: Comment;
33
+ name?: string;
34
+ value?: unknown;
35
+ fixed?: boolean;
36
+ cascade?: CascadeRecord;
37
+ };
38
+ /** A child component; the diff decides whether it keeps its previous instance. */
39
+ export type VComponent = {
40
+ kind: "component";
41
+ type: Ctor<ComponentBase>;
42
+ props: Record<string, unknown>;
43
+ slots?: object;
44
+ key?: unknown;
45
+ ref?: (c: ComponentBase) => void;
46
+ instance?: ComponentBase;
47
+ mounted?: Mounted;
48
+ onError?: (err: unknown, nav: number) => void;
49
+ nav?: number;
50
+ };
51
+ export type VNode = VText | VElement | VRegion | VComponent;
52
+ /** One entry of the generated `.xzor/routes.ts` table; `match` converts the path segments or rejects them. */
53
+ export type RouteEntry = {
54
+ tag: string | undefined;
55
+ pattern: string;
56
+ /** The page's shortest pattern this one extends: routes of one family share the page instance. */
57
+ family?: string;
58
+ component: unknown;
59
+ match: (s: string[]) => Record<string, unknown> | null;
60
+ };
61
+ /** The project's routes, in precedence order. */
62
+ export type RouteTable = readonly RouteEntry[];
63
+ /**
64
+ * The state of the current navigation, published to the routes block and as the cascading value `route`.
65
+ * `Tags` maps each route tag to its params; the generated table fixes it (`AppRoute`) so `is` checks tags.
66
+ */
67
+ export declare class Route<P = Record<string, unknown>, Tags extends object = Record<string, Record<string, unknown>>> {
68
+ #private;
69
+ readonly path: string;
70
+ readonly tag: (keyof Tags & string) | undefined;
71
+ readonly params: P;
72
+ readonly query: URLSearchParams;
73
+ readonly match: Record<string, string>;
74
+ constructor(path: string, tag: (keyof Tags & string) | undefined, params: P, query: URLSearchParams, match: Record<string, string>, nav?: Navigation);
75
+ /** Narrows `params` to the routes carrying `tag`. */
76
+ is<K extends keyof Tags & string>(tag: K): this is Route<Tags[K], Tags> & {
77
+ readonly tag: K;
78
+ };
79
+ /** History navigation under `@ClientRoutes`; `@ServerRoutes` loads the url. */
80
+ navigate(url: string, opts?: {
81
+ replace?: boolean;
82
+ }): void;
83
+ }
84
+ /** One section of a `@ClientRoutes`/`@ServerRoutes` block; xzor emits these in source order. */
85
+ export type RouteSection = {
86
+ kind: "tag";
87
+ tag: string;
88
+ render: (route: Route, page: RenderFragment) => RenderFragment;
89
+ } | {
90
+ kind: "regex";
91
+ re: RegExp;
92
+ page: boolean;
93
+ render: (route: Route, page: RenderFragment) => RenderFragment;
94
+ } | {
95
+ kind: "pattern";
96
+ match: (segments: string[]) => Record<string, string> | null;
97
+ page: boolean;
98
+ render: (route: Route, page: RenderFragment) => RenderFragment;
99
+ } | {
100
+ kind: "notFound";
101
+ render: (route: Route) => RenderFragment;
102
+ } | {
103
+ kind: "catch";
104
+ render: (route: Route, error: unknown) => RenderFragment;
105
+ } | {
106
+ kind: "default";
107
+ render: (route: Route, page: RenderFragment) => RenderFragment;
108
+ };
109
+ /** How `@ClientRoutes` reaches the browser's history; `setNavigationForTests` swaps it. */
110
+ export type Navigation = {
111
+ current(): URL;
112
+ navigate(url: string, replace: boolean): void;
113
+ subscribe(fn: () => void): () => void;
114
+ /** Like `subscribe`, without taking over link clicks (a `NavLink` only watches). Defaults to `subscribe`. */
115
+ observe?(fn: () => void): () => void;
116
+ };
117
+ /** @internal Swaps in a memory navigation; set it before mounting the routes block. */
118
+ export declare function setNavigationForTests(nav: Navigation | undefined): void;
119
+ /** The path of `<base href>` without its last segment: "" without one, "/docs" under `<base href="/docs/">`. */
120
+ export declare function basePath(): string;
121
+ type Ctor<C extends ComponentBase> = new (...args: any[]) => C;
122
+ type Mounted = {
123
+ tree: VNode[];
124
+ anchor: Comment;
125
+ app: IApplication | undefined;
126
+ scope: CascadeRecord | undefined;
127
+ latest: VComponent | undefined;
128
+ pass: number;
129
+ nav?: number;
130
+ };
131
+ /** Builds components that need injected services; generated by xzor from `@Mount` and `@ServiceProvider`. */
132
+ export interface IApplication {
133
+ onStarted?(): void | Promise<void>;
134
+ /** Consulted only for component classes with a non-empty `static inject`; returns the component, a promise for it, or `undefined` (the runtime then throws). */
135
+ createComponent?(type: Function): ComponentBase | Promise<ComponentBase> | undefined;
136
+ }
137
+ type DisposeSymbols = {
138
+ dispose: symbol;
139
+ asyncDispose: symbol;
140
+ };
141
+ /** @internal Engines without explicit resource management get the registry symbols that TypeScript's downlevel helpers use. */
142
+ export declare function polyfillDisposeSymbols(target: Partial<DisposeSymbols>): void;
143
+ type ServiceDecorator = {
144
+ <T>(impl: new (...a: any[]) => T): ClassDecorator;
145
+ <T>(key: string, factory: (...a: any[]) => T | Promise<T>): ClassDecorator;
146
+ };
147
+ export declare const ServiceProvider: () => ClassDecorator;
148
+ export declare const Mount: (_component: Function, _target: string) => ClassDecorator;
149
+ export declare const Import: (..._providers: Function[]) => ClassDecorator;
150
+ export declare const Singleton: ServiceDecorator;
151
+ export declare const Scoped: ServiceDecorator;
152
+ export declare const Transient: ServiceDecorator;
153
+ export declare const SharedInstance: unique symbol;
154
+ declare const FRAGMENT: unique symbol;
155
+ type Fragment = ((builder: RenderTreeBuilder) => void) & {
156
+ readonly [FRAGMENT]: true;
157
+ };
158
+ /** Markup held as a value (Blazor's RenderFragment); render it with `@member`. */
159
+ export type RenderFragment = Fragment;
160
+ export type Renderer = RenderFragment;
161
+ /** A component event; invoking it re-renders the component that passed it in. */
162
+ export type EventCallback<T = void> = (arg: T) => unknown;
163
+ /** The DOM element type for a tag name, as `document.createElement` would return it. */
164
+ export type ElementOf<T extends string> = T extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[T] : T extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[T] : HTMLElement;
165
+ export declare abstract class ComponentBase {
166
+ /** Wraps builder calls as a RenderFragment; xzor emits this for markup used as a value. */
167
+ static fragment(build: (builder: RenderTreeBuilder) => void): RenderFragment;
168
+ /** Reads a bound input's new value, converted to the bound field's current type. */
169
+ static bindValue<T>(e: Event, current: T): T;
170
+ /** Content the parent passed for each `@slot`; xzor declares the exact type per component. */
171
+ slots: {};
172
+ protected abstract buildRenderTree(builder: RenderTreeBuilder): void;
173
+ protected onInitialized(): void;
174
+ protected onInitializedAsync(): Promise<void> | void;
175
+ protected onParametersSet(): void;
176
+ protected onParametersSetAsync(): Promise<void> | void;
177
+ protected onAfterRender(_firstRender: boolean): void;
178
+ protected onAfterRenderAsync(_firstRender: boolean): Promise<void> | void;
179
+ protected shouldRender(): boolean;
180
+ /** Called when the component leaves the tree. */
181
+ protected dispose(): void;
182
+ /** Re-renders this component. Event handlers it owns do this automatically. */
183
+ stateHasChanged(): void;
184
+ }
185
+ export declare class RenderTreeBuilder {
186
+ #private;
187
+ private readonly owner;
188
+ constructor(owner: ComponentBase);
189
+ get nodes(): VNode[];
190
+ openElement(tag: string): void;
191
+ closeElement(): void;
192
+ openRegion(): void;
193
+ /** `@cascade:name(value)`: a region whose children see `value` under `name`; `fixed` keeps the first value. */
194
+ openCascade(name: string, value: unknown, fixed?: boolean): void;
195
+ closeRegion(): void;
196
+ /** `@ClientRoutes`/`@ServerRoutes`: renders the section that matches the current navigation. */
197
+ addRoutes(engine: "client" | "server", table: RouteTable, sections: readonly RouteSection[]): void;
198
+ addAttribute(name: string, value: unknown): void;
199
+ /** `@attributes`: each entry is added in order, so later attributes override it. */
200
+ addAttributes(attrs: Record<string, unknown> | null | undefined): void;
201
+ /** `@onclick:preventDefault` and `@onclick:stopPropagation`, with or without a handler. */
202
+ addEventModifier(event: string, modifier: Modifier, enabled: boolean): void;
203
+ /** `@key`: list diffs match this element by key instead of position. */
204
+ setKey(key: unknown): void;
205
+ /** `@ref`: receives the DOM element (typed from its tag) after each render. */
206
+ setRef<T extends string>(_tag: T, ref: (el: ElementOf<T>) => void): void;
207
+ addEventHandler<K extends keyof HTMLElementEventMap>(event: K, handler: (e: HTMLElementEventMap[K]) => unknown): void;
208
+ addEventHandler(event: string, handler: Handler): void;
209
+ addText(text: string): void;
210
+ addContent(value: unknown): void;
211
+ addComponent<C extends ComponentBase>(type: Ctor<C>, props: Partial<C>, slots?: C["slots"], extra?: {
212
+ key?: unknown;
213
+ ref?: (c: C) => void;
214
+ }): void;
215
+ /** Wraps a handler passed to a child as an EventCallback (re-renders this owner). */
216
+ callback<T>(handler: (arg: T) => unknown): EventCallback<T>;
217
+ }
218
+ /** `target` is an element, an element id, or a selector (anything containing `#`, `.` or `[`). */
219
+ export declare function mount<C extends ComponentBase>(type: Ctor<C>, target: string | Element, app?: IApplication): C;
220
+ /** An `<a>` that carries `activeClass` while the current URL is on its `href`; it follows navigation itself. */
221
+ export declare class NavLink extends ComponentBase {
222
+ #private;
223
+ href: string;
224
+ activeClass: string;
225
+ match: "prefix" | "exact";
226
+ slots: {
227
+ default?: () => RenderFragment;
228
+ };
229
+ protected onInitialized(): void;
230
+ protected dispose(): void;
231
+ protected buildRenderTree(b: RenderTreeBuilder): void;
232
+ }
233
+ export {};