streetui 1.8.0 → 2.0.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.
- package/dist/bin.cjs +1 -1
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/create-bin.cjs +1 -1
- package/dist/create-bin.cjs.map +1 -1
- package/dist/create-bin.js +1 -1
- package/dist/create-bin.js.map +1 -1
- package/dist/{compile-CJJQYi71.d.cts → hydration-diagnostics-CFYDXBlm.d.cts} +471 -5
- package/dist/{compile-CJJQYi71.d.ts → hydration-diagnostics-CFYDXBlm.d.ts} +471 -5
- package/dist/index.cjs +1401 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +598 -147
- package/dist/index.d.ts +598 -147
- package/dist/index.js +1379 -47
- package/dist/index.js.map +1 -1
- package/dist/renderer-interface-BUhHV7ja.d.cts +26 -0
- package/dist/renderer-interface-B_-hWnKk.d.ts +26 -0
- package/dist/{server-CnLEnlYU.d.cts → server-C0PvFBzD.d.ts} +181 -2
- package/dist/{server-DNlg7ou2.d.ts → server-DnAOFpMP.d.cts} +181 -2
- package/dist/server.cjs +482 -32
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +481 -32
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +754 -41
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +42 -4
- package/dist/testing.d.ts +42 -4
- package/dist/testing.js +746 -40
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/hydration-diagnostics-BQeehq3i.d.cts +0 -89
- package/dist/hydration-diagnostics-DNAJumYF.d.ts +0 -89
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { c as Signal, d as Subscriber, U as Unsubscribe, R as ReadonlySignal, A as ApplicationId, D as DiagnosticCollector,
|
|
2
|
-
export {
|
|
3
|
-
import {
|
|
4
|
-
export { H as
|
|
5
|
-
import {
|
|
6
|
-
export { R as RenderToStringOptions, S as STATE_MARKER_ATTR, a as ServerDOMAdapter, r as readState, b as renderToString, s as serializeState, c as serverDOMAdapter } from './server-CnLEnlYU.cjs';
|
|
1
|
+
import { c as Signal, d as Subscriber, U as Unsubscribe, R as ReadonlySignal, e as ResourceStatus, f as ResourceOptions, g as Resource, h as ResourceLoaderContext, A as ApplicationId, D as DiagnosticCollector, i as ApplicationGraph, G as GraphNode, C as CompiledApplication, j as HydrationDiagnosticSink, k as SemanticNodeType, P as PageDSL, T as TransitionConfig, l as ContainerDSL, m as SignalKind } from './hydration-diagnostics-CFYDXBlm.cjs';
|
|
2
|
+
export { n as A11yOptions, o as AppBuilder, p as AppDSL, q as AppOptions, r as ApplicationGraphOptions, s as AsyncBoundaryBranches, B as BaseNode, t as Bindable, u as BindableString, v as BindableText, w as BoundInputOptions, x as ButtonOptions, y as CompileOptions, b as ComponentChildren, z as ComponentContext, a as ComponentDefinition, E as ComponentRender, F as ComponentSetup, b as ContainerBuilder, I as ContainerBuilderImpl, J as ContainerOptions, K as ContentDSL, L as ControlledInputOptions, M as DerivedSignal, N as Diagnostic, O as DiagnosticError, Q as DiagnosticLocation, W as DiagnosticSeverity, X as ErrorBoundaryOptions, Y as ErrorFallbackBuilder, Z as ErrorSource, _ as EventDescriptor, $ as FormBuilder, a0 as FormBuilderImpl, a1 as FormDSL, a2 as FormOptions, a3 as GraphNodeData, a4 as HandlerFn, a5 as HeadContribution, a6 as HeadEntry, a7 as HeadMetadata, a8 as HeadingOptions, H as HydrationDiagnostic, a9 as HydrationMismatchType, aa as ImageOptions, ab as InputOptions, ac as InputOptionsBase, ad as LinkDescriptor, ae as LinkOptions, af as ListBuilder, ag as ListBuilderImpl, ah as ListDSL, ai as ListOptions, aj as ListPlanEntry, ak as MetaDescriptor, al as NodeId, am as NodeMetadata, an as OverlayOptions, ao as PageBuilder, ap as PageBuilderImpl, aq as PortalOptions, ar as PropValue, as as Props, at as ReactiveConsumer, au as ReactiveSource, av as ResolvedTransition, aw as ResourceLoader, ax as SectionBuilder, ay as SectionBuilderImpl, az as SectionDSL, aA as SectionOptions, aB as SerializedGraph, aC as SerializedNode, aD as StateRef, S as StreetApp, aE as StreetUI, aF as TextOptions, aG as TextValue, V as VERSION, aH as WhenOptions, aI as batch, aJ as compile, aK as compileGraph, aL as component, aM as consoleHydrationDiagnosticSink, aN as createHydrationDiagnosticCollector, aO as createNodeId, aP as derived, aQ as effect, aR as formatDiagnostic, aS as formatHydrationDiagnostic, aT as generateApplicationId, aU as generateNodeId, aV as isBatching, aW as isComponentDefinition, aX as isHeadContribution, aY as isTransitionConfig, aZ as nextId, a_ as nodeIdPrefix, a$ as observerCount, b0 as reactiveListItemKey, b1 as reactiveListItemSignature, b2 as resetIdCounter, b3 as resolveHead, b4 as resolveTransition, b5 as resource, b6 as signal, b7 as signalKind, b8 as streetui } from './hydration-diagnostics-CFYDXBlm.cjs';
|
|
3
|
+
import { L as Lifecycle, C as CleanupRegistry, D as DOMAdapter, N as NodeInstance, R as RenderContext } from './server-DnAOFpMP.cjs';
|
|
4
|
+
export { H as HeadManager, a as LifecycleHook, b as LifecyclePhase, c as RenderToStringOptions, S as STATE_MARKER_ATTR, d as ServerDOMAdapter, e as createRenderContext, r as readState, f as renderHead, g as renderToString, s as serializeState, h as serverDOMAdapter, w as wireHeadBehavior } from './server-DnAOFpMP.cjs';
|
|
5
|
+
import { R as RenderHandle, S as StreetRenderer } from './renderer-interface-BUhHV7ja.cjs';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* A simple reactive store built on top of signals.
|
|
@@ -23,84 +22,229 @@ declare class Store<T extends StoreState> {
|
|
|
23
22
|
declare function createStore<T extends StoreState>(initial: T): Store<T>;
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
|
-
* StreetUI
|
|
25
|
+
* StreetUI mutations — framework-native asynchronous *writes*.
|
|
27
26
|
*
|
|
28
|
-
* A `resource`
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
27
|
+
* A `resource` models a read: a loader that runs on creation / on demand and
|
|
28
|
+
* whose value the UI observes. A `mutation` is its write-side counterpart: an
|
|
29
|
+
* explicit, argument-taking async action (create / update / delete, a form
|
|
30
|
+
* submit, a "mark as done" click) whose lifecycle is exposed as ordinary
|
|
31
|
+
* StreetUI signals so it composes with `derived`, `when()`, and the renderer
|
|
32
|
+
* with NO second reactive system.
|
|
32
33
|
*
|
|
33
|
-
* State machine
|
|
34
|
+
* State machine (mirrors `resource`, but only ever advances on an explicit
|
|
35
|
+
* `mutate()` — a mutation never runs on its own):
|
|
34
36
|
*
|
|
35
|
-
* idle ──(
|
|
36
|
-
*
|
|
37
|
-
*
|
|
37
|
+
* idle ──(mutate)──▶ loading ──(resolve)──▶ success
|
|
38
|
+
* │
|
|
39
|
+
* └────(reject)──────▶ error
|
|
38
40
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* value or a Promise. When it accepts the provided `AbortSignal`, in-flight
|
|
45
|
-
* work is cancelled on `dispose()` or when a newer request supersedes it.
|
|
41
|
+
* There is deliberately NO global cache and NO automatic invalidation registry
|
|
42
|
+
* (that would be a second state system with its own lifetime and coherency
|
|
43
|
+
* rules). Invalidation is explicit and local: pass an `onSuccess` that calls the
|
|
44
|
+
* `refetch()` of whichever resources the write affected. This keeps data flow
|
|
45
|
+
* one-directional and readable — the write says exactly what it invalidates.
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
/** Any value-or-Promise producing function. Receives an abort-aware context. */
|
|
54
|
-
type ResourceLoader<T> = (ctx: ResourceLoaderContext) => Promise<T> | T;
|
|
55
|
-
interface ResourceOptions<T = unknown> {
|
|
56
|
-
/** Load immediately on creation. Defaults to `true`. When `false`, stays `idle` until `refetch()`. */
|
|
57
|
-
readonly immediate?: boolean;
|
|
48
|
+
/** A mutation shares the resource status vocabulary (idle/loading/success/error). */
|
|
49
|
+
type MutationStatus = ResourceStatus;
|
|
50
|
+
/** The async action a mutation runs. Receives the caller's argument. */
|
|
51
|
+
type Mutator<TArgs, TResult> = (args: TArgs) => Promise<TResult> | TResult;
|
|
52
|
+
interface MutationOptions<TArgs, TResult> {
|
|
58
53
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
54
|
+
* Run after a successful mutation, before `mutate()`'s promise resolves. The
|
|
55
|
+
* natural place to invalidate reads: call the affected resources' `refetch()`.
|
|
56
|
+
* May be async; its completion is awaited so callers can rely on reads being
|
|
57
|
+
* up to date once `mutate()` resolves.
|
|
62
58
|
*/
|
|
63
|
-
readonly
|
|
59
|
+
readonly onSuccess?: (result: TResult, args: TArgs) => void | Promise<void>;
|
|
60
|
+
/** Run after a failed mutation (the thrown value is passed through). */
|
|
61
|
+
readonly onError?: (error: unknown, args: TArgs) => void | Promise<void>;
|
|
62
|
+
/** Run after success OR error, once the lifecycle has settled. */
|
|
63
|
+
readonly onSettled?: (args: TArgs) => void | Promise<void>;
|
|
64
64
|
/**
|
|
65
|
-
* Optional teardown registrar (e.g. a
|
|
66
|
-
* the
|
|
67
|
-
*
|
|
65
|
+
* Optional teardown registrar (e.g. a component's `ctx.onCleanup`). When
|
|
66
|
+
* given, the mutation registers its own `dispose` so late results from an
|
|
67
|
+
* in-flight `mutate()` are ignored once the owner is removed.
|
|
68
68
|
*/
|
|
69
69
|
readonly onCleanup?: (fn: () => void) => void;
|
|
70
|
+
}
|
|
71
|
+
interface Mutation<TArgs, TResult> {
|
|
72
|
+
/** Reactive lifecycle status. */
|
|
73
|
+
readonly status: ReadonlySignal<MutationStatus>;
|
|
74
|
+
/** The most recent successful result, or `undefined` before first success. */
|
|
75
|
+
readonly data: ReadonlySignal<TResult | undefined>;
|
|
76
|
+
/** The most recent error, or `undefined` when there is none. Typed `unknown`. */
|
|
77
|
+
readonly error: ReadonlySignal<unknown>;
|
|
78
|
+
/** Convenience: `status === 'loading'` (an in-flight write). */
|
|
79
|
+
readonly pending: ReadonlySignal<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* Run the mutation. Resolves with the result on success. On failure the
|
|
82
|
+
* rejection is surfaced through `error`/`status` AND re-thrown, so a caller
|
|
83
|
+
* that wants to react imperatively can `try/catch`; a caller that only wants
|
|
84
|
+
* the reactive state can ignore the returned promise. Superseded/disposed
|
|
85
|
+
* runs never write state (race guard), matching `resource`.
|
|
86
|
+
*/
|
|
87
|
+
mutate(args: TArgs): Promise<TResult>;
|
|
88
|
+
/** Reset back to `idle` with no data/error. */
|
|
89
|
+
reset(): void;
|
|
90
|
+
/** Ignore any in-flight result and mark the mutation inert. Idempotent. */
|
|
91
|
+
dispose(): void;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Create a {@link Mutation}. The zero-argument form is written
|
|
95
|
+
* `mutation<void, T>(() => …)` and invoked as `mutate(undefined)`.
|
|
96
|
+
*/
|
|
97
|
+
declare function mutation<TArgs, TResult>(mutator: Mutator<TArgs, TResult>, options?: MutationOptions<TArgs, TResult>): Mutation<TArgs, TResult>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Optional HTTP data client (2.0 §17) — the integration path between StreetUI's
|
|
101
|
+
* transport-agnostic `resource`/`mutation` primitives and a real backend (a
|
|
102
|
+
* StreetJS server, or any HTTP/JSON API).
|
|
103
|
+
*
|
|
104
|
+
* This is deliberately OPTIONAL and dependency-free: it imports nothing from
|
|
105
|
+
* StreetJS (or any server framework), so StreetUI's core stays independent — an
|
|
106
|
+
* app that never calls `createClient` never pays for it, and StreetUI does not
|
|
107
|
+
* take on a backend dependency. It is a thin, honest convenience over the
|
|
108
|
+
* standard `fetch`: URL joining, JSON encode/decode, header merging, abort
|
|
109
|
+
* propagation, and a typed error. All state still flows through the existing
|
|
110
|
+
* `resource`/`mutation` signals — there is no cache and no second data system.
|
|
111
|
+
*
|
|
112
|
+
* ```ts
|
|
113
|
+
* const api = createClient({ baseUrl: '/api' });
|
|
114
|
+
* const users = api.resource<User[]>('/users'); // a read
|
|
115
|
+
* const create = api.mutation<NewUser, User>('POST', '/users', {
|
|
116
|
+
* onSuccess: () => users.refetch(), // explicit invalidation
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
/** A `fetch`-compatible function. Injectable for tests / non-browser runtimes. */
|
|
122
|
+
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
123
|
+
interface ClientConfig {
|
|
124
|
+
/** Prefix joined to every request path (e.g. `/api` or `https://x/api`). */
|
|
125
|
+
readonly baseUrl?: string;
|
|
126
|
+
/** Headers merged into every request (per-request headers win). */
|
|
127
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
70
128
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* auto-load is skipped (so the client does not refetch data the server
|
|
74
|
-
* already resolved). This is the client half of SSR resource transfer; the
|
|
75
|
-
* server side awaits `refetch()` before serializing. Set `immediate: true`
|
|
76
|
-
* explicitly to force a client refetch anyway.
|
|
129
|
+
* The fetch implementation to use. Defaults to the global `fetch`. Injecting
|
|
130
|
+
* one keeps the client testable and usable where no global fetch exists.
|
|
77
131
|
*/
|
|
78
|
-
readonly
|
|
79
|
-
|
|
80
|
-
|
|
132
|
+
readonly fetch?: FetchLike;
|
|
133
|
+
}
|
|
134
|
+
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
135
|
+
interface RequestConfig {
|
|
136
|
+
/** Extra headers for this request (merged over the client's). */
|
|
137
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
138
|
+
/** Abort signal — pass a resource/mutation loader's `ctx.signal` for cancellation. */
|
|
139
|
+
readonly signal?: AbortSignal;
|
|
140
|
+
/** Query parameters appended to the URL. */
|
|
141
|
+
readonly query?: Readonly<Record<string, string | number | boolean>>;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* A failed HTTP response (non-2xx). Carries the status and the parsed body when
|
|
145
|
+
* one was returned. NOTE: the body may contain server-supplied detail; the §7
|
|
146
|
+
* error reporter never enumerates an error's own-properties, so `HttpError.body`
|
|
147
|
+
* never leaks into a diagnostics report unless an app deliberately reads it.
|
|
148
|
+
*/
|
|
149
|
+
declare class HttpError extends Error {
|
|
150
|
+
readonly status: number;
|
|
151
|
+
readonly statusText: string;
|
|
152
|
+
readonly url: string;
|
|
153
|
+
readonly body: unknown;
|
|
154
|
+
constructor(status: number, statusText: string, url: string, body: unknown);
|
|
155
|
+
}
|
|
156
|
+
interface Client {
|
|
157
|
+
/** Issue a request and return the parsed JSON body (throws `HttpError` on non-2xx). */
|
|
158
|
+
request<T>(method: HttpMethod, path: string, body?: unknown, config?: RequestConfig): Promise<T>;
|
|
159
|
+
get<T>(path: string, config?: RequestConfig): Promise<T>;
|
|
160
|
+
post<T>(path: string, body?: unknown, config?: RequestConfig): Promise<T>;
|
|
161
|
+
put<T>(path: string, body?: unknown, config?: RequestConfig): Promise<T>;
|
|
162
|
+
patch<T>(path: string, body?: unknown, config?: RequestConfig): Promise<T>;
|
|
163
|
+
del<T>(path: string, config?: RequestConfig): Promise<T>;
|
|
81
164
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
165
|
+
* A GET-backed {@link Resource}. The loader forwards the resource's abort
|
|
166
|
+
* signal, so `dispose()`/supersede cancels the request.
|
|
84
167
|
*/
|
|
85
|
-
|
|
168
|
+
resource<T>(path: string, options?: ResourceOptions<T> & {
|
|
169
|
+
readonly query?: RequestConfig['query'];
|
|
170
|
+
}): Resource<T>;
|
|
171
|
+
/**
|
|
172
|
+
* A {@link Mutation} that issues `method path` with the mutate() argument as
|
|
173
|
+
* the JSON body. Pair with `onSuccess` to refetch affected resources.
|
|
174
|
+
*/
|
|
175
|
+
mutation<TArgs, TResult>(method: HttpMethod, path: string, options?: MutationOptions<TArgs, TResult>): Mutation<TArgs, TResult>;
|
|
176
|
+
}
|
|
177
|
+
/** Create an optional HTTP data client. Uses global `fetch` unless one is injected. */
|
|
178
|
+
declare function createClient(config?: ClientConfig): Client;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Optional auth session primitive (2.0 §19) — reactive authentication state for
|
|
182
|
+
* building sign-in UIs and protected routes, composed entirely from the existing
|
|
183
|
+
* `resource` (the "who am I" read) and `mutation` (logout / refresh writes).
|
|
184
|
+
*
|
|
185
|
+
* There is no new auth framework here and no credential handling: the app
|
|
186
|
+
* supplies a `loadUser` function (however it authenticates — a StreetJS session
|
|
187
|
+
* cookie, a bearer token, anything) that returns the current user or `null`. The
|
|
188
|
+
* primitive turns that into the states a UI switches on — `loading`,
|
|
189
|
+
* `authenticated`, `unauthenticated`, `error` — plus `refresh()` and `logout()`.
|
|
190
|
+
*
|
|
191
|
+
* How the pieces the spec names fit together (all EXISTING seams, no new ones):
|
|
192
|
+
* - loading / unauth / auth → switch UI with `when(session.authenticated, …)`
|
|
193
|
+
* etc. (the renderer's existing conditional).
|
|
194
|
+
* - refresh / logout → `session.refresh()` / `session.logout()`.
|
|
195
|
+
* - protected route → in a route's setup, read `session.status`; when
|
|
196
|
+
* `unauthenticated`, navigate to the login route (router). Throwing inside a
|
|
197
|
+
* guarded builder is caught by `errorBoundary` for an error fallback. This
|
|
198
|
+
* module stays router-agnostic so core has no router dependency — the app
|
|
199
|
+
* wires the navigation, exactly as with any other signal.
|
|
200
|
+
*/
|
|
201
|
+
|
|
202
|
+
/** The four states an auth-aware UI switches on. */
|
|
203
|
+
type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated' | 'error';
|
|
204
|
+
/** Load the current user, or `null`/`undefined` when nobody is signed in. */
|
|
205
|
+
type LoadUser<TUser> = (ctx: ResourceLoaderContext) => Promise<TUser | null | undefined> | TUser | null | undefined;
|
|
206
|
+
interface AuthSessionConfig<TUser> {
|
|
207
|
+
/** Resolve the current user (or null when unauthenticated). Abort-aware. */
|
|
208
|
+
readonly loadUser: LoadUser<TUser>;
|
|
209
|
+
/**
|
|
210
|
+
* Perform the server-side logout (clear the cookie/token). Optional — when
|
|
211
|
+
* omitted, `logout()` just re-checks the session. After it resolves the
|
|
212
|
+
* session refreshes, so `loadUser` should then return null.
|
|
213
|
+
*/
|
|
214
|
+
readonly logout?: () => Promise<void> | void;
|
|
215
|
+
/** Skip the initial load; stays `loading` until the first `refresh()`. */
|
|
216
|
+
readonly immediate?: boolean;
|
|
217
|
+
/** Teardown registrar (e.g. a component's `ctx.onCleanup`). */
|
|
218
|
+
readonly onCleanup?: (fn: () => void) => void;
|
|
86
219
|
}
|
|
87
|
-
interface
|
|
88
|
-
/**
|
|
89
|
-
readonly status: ReadonlySignal<
|
|
90
|
-
/** The
|
|
91
|
-
readonly
|
|
92
|
-
/** The most recent error, or `undefined
|
|
220
|
+
interface AuthSession<TUser> {
|
|
221
|
+
/** The current coarse auth state. */
|
|
222
|
+
readonly status: ReadonlySignal<AuthStatus>;
|
|
223
|
+
/** The signed-in user, or `undefined` when not authenticated. */
|
|
224
|
+
readonly user: ReadonlySignal<TUser | undefined>;
|
|
225
|
+
/** The most recent load/logout error, or `undefined`. */
|
|
93
226
|
readonly error: ReadonlySignal<unknown>;
|
|
94
|
-
/**
|
|
227
|
+
/** `status === 'authenticated'`. */
|
|
228
|
+
readonly authenticated: ReadonlySignal<boolean>;
|
|
229
|
+
/** `status === 'unauthenticated'`. */
|
|
230
|
+
readonly unauthenticated: ReadonlySignal<boolean>;
|
|
231
|
+
/** `status === 'loading'` (the initial who-am-I is still in flight). */
|
|
95
232
|
readonly loading: ReadonlySignal<boolean>;
|
|
96
|
-
/**
|
|
97
|
-
readonly
|
|
98
|
-
/**
|
|
99
|
-
|
|
100
|
-
/**
|
|
233
|
+
/** True while a `logout()` is in flight. */
|
|
234
|
+
readonly loggingOut: ReadonlySignal<boolean>;
|
|
235
|
+
/** Re-run `loadUser` (e.g. after a token refresh or a focus regain). */
|
|
236
|
+
refresh(): Promise<void>;
|
|
237
|
+
/** Run the configured server logout, then refresh (→ unauthenticated). */
|
|
238
|
+
logout(): Promise<void>;
|
|
239
|
+
/** Cancel in-flight work and detach. Idempotent. */
|
|
101
240
|
dispose(): void;
|
|
102
241
|
}
|
|
103
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Create an {@link AuthSession}. The session starts in `loading` and resolves to
|
|
244
|
+
* `authenticated`/`unauthenticated` once `loadUser` settles (unless
|
|
245
|
+
* `immediate: false`).
|
|
246
|
+
*/
|
|
247
|
+
declare function createAuthSession<TUser>(config: AuthSessionConfig<TUser>): AuthSession<TUser>;
|
|
104
248
|
|
|
105
249
|
/**
|
|
106
250
|
* Deterministic accessibility id helpers.
|
|
@@ -124,14 +268,24 @@ interface A11yIds {
|
|
|
124
268
|
readonly base: string;
|
|
125
269
|
/** Id for the primary interactive element (e.g. the input). */
|
|
126
270
|
readonly input: string;
|
|
127
|
-
/** Id for a label element / labelling text. */
|
|
271
|
+
/** Id for a label element / labelling text (target of `aria-labelledby`). */
|
|
128
272
|
readonly label: string;
|
|
129
|
-
/** Id for descriptive/help text. */
|
|
273
|
+
/** Id for descriptive/help text (target of `aria-describedby`). */
|
|
130
274
|
readonly description: string;
|
|
131
275
|
/** Id for an error message element. */
|
|
132
276
|
readonly error: string;
|
|
133
|
-
/** Id for a title element (e.g. a dialog title). */
|
|
277
|
+
/** Id for a title element (e.g. a dialog title; target of `aria-labelledby`). */
|
|
134
278
|
readonly title: string;
|
|
279
|
+
/**
|
|
280
|
+
* Id for a control that triggers a popup (button/summary). Pair with
|
|
281
|
+
* `controls` on the popup it opens (`ariaControls: ids.controls`,
|
|
282
|
+
* `ariaExpanded: open`).
|
|
283
|
+
*/
|
|
284
|
+
readonly trigger: string;
|
|
285
|
+
/** Id for a popup/region a `trigger` controls (target of `aria-controls`). */
|
|
286
|
+
readonly controls: string;
|
|
287
|
+
/** Id for a subtree owned out-of-DOM-order (target of `aria-owns`). */
|
|
288
|
+
readonly owns: string;
|
|
135
289
|
/** Derive an arbitrary suffixed id from the same base. */
|
|
136
290
|
id(suffix: string): string;
|
|
137
291
|
}
|
|
@@ -143,35 +297,14 @@ interface A11yIds {
|
|
|
143
297
|
* // ids.input === 'email-input', ids.label === 'email-label', ...
|
|
144
298
|
* input({ bind: value, id: ids.input, ariaLabelledBy: ids.label, ariaDescribedBy: ids.error });
|
|
145
299
|
* text('Email', { id: ids.label });
|
|
146
|
-
*/
|
|
147
|
-
declare function a11yIds(base: string): A11yIds;
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Application and component lifecycle primitives.
|
|
151
300
|
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
301
|
+
* @example
|
|
302
|
+
* // A menu button that controls its popup, wired by shared ids:
|
|
303
|
+
* const m = a11yIds('actions');
|
|
304
|
+
* button('Actions', { id: m.trigger, ariaControls: m.controls, ariaExpanded: open });
|
|
305
|
+
* page.dropdown('menu', { open, id: m.controls }, (d) => { … });
|
|
154
306
|
*/
|
|
155
|
-
|
|
156
|
-
type LifecycleHook = () => void | Promise<void>;
|
|
157
|
-
declare class Lifecycle {
|
|
158
|
-
private _phase;
|
|
159
|
-
private readonly _hooks;
|
|
160
|
-
get phase(): LifecyclePhase;
|
|
161
|
-
get isMounted(): boolean;
|
|
162
|
-
get isDestroyed(): boolean;
|
|
163
|
-
on(phase: LifecyclePhase, hook: LifecycleHook): () => void;
|
|
164
|
-
transition(to: LifecyclePhase): Promise<void>;
|
|
165
|
-
onMount(hook: LifecycleHook): () => void;
|
|
166
|
-
onUnmount(hook: LifecycleHook): () => void;
|
|
167
|
-
onDestroy(hook: LifecycleHook): () => void;
|
|
168
|
-
}
|
|
169
|
-
/** A simple cleanup registry — collect teardown functions and run them all at once. */
|
|
170
|
-
declare class CleanupRegistry {
|
|
171
|
-
private readonly _fns;
|
|
172
|
-
add(fn: () => void): void;
|
|
173
|
-
run(): void;
|
|
174
|
-
}
|
|
307
|
+
declare function a11yIds(base: string): A11yIds;
|
|
175
308
|
|
|
176
309
|
/**
|
|
177
310
|
* Environment detection and capability flags.
|
|
@@ -256,6 +389,30 @@ interface DiagnosticContext {
|
|
|
256
389
|
readonly route?: string;
|
|
257
390
|
/** A resource identifier involved, when applicable. */
|
|
258
391
|
readonly resource?: string;
|
|
392
|
+
/**
|
|
393
|
+
* The component name involved (from a `component()` definition's `name`), when
|
|
394
|
+
* the diagnostic arises inside a component. A stable identifier, never a value.
|
|
395
|
+
*/
|
|
396
|
+
readonly component?: string;
|
|
397
|
+
/**
|
|
398
|
+
* A signal identifier involved (e.g. a named/derived signal's debug name),
|
|
399
|
+
* when applicable. This is the signal's *identity*, never its current value —
|
|
400
|
+
* signal contents may be user data and are never placed in a diagnostic.
|
|
401
|
+
*/
|
|
402
|
+
readonly signal?: string;
|
|
403
|
+
/**
|
|
404
|
+
* Where in a node's lifecycle the diagnostic arose: `render` (building the
|
|
405
|
+
* subtree), `effect` (a reactive effect), `setup` (a component's setup),
|
|
406
|
+
* `loader` (a resource loader), `event` (a DOM handler), or `hydrate`.
|
|
407
|
+
*/
|
|
408
|
+
readonly phase?: 'render' | 'effect' | 'setup' | 'loader' | 'event' | 'hydrate';
|
|
409
|
+
/**
|
|
410
|
+
* A non-sensitive DOM association for where the error surfaced, e.g.
|
|
411
|
+
* `div#app` or `button.primary`. Callers must pass only structural
|
|
412
|
+
* identifiers (tag / id / class) — never `textContent`, attribute *values*,
|
|
413
|
+
* or anything that could carry user data.
|
|
414
|
+
*/
|
|
415
|
+
readonly element?: string;
|
|
259
416
|
}
|
|
260
417
|
/**
|
|
261
418
|
* The application-provided logging seam. Every method is optional; the
|
|
@@ -289,6 +446,65 @@ declare function frameworkError(message: string, context?: DiagnosticContext): S
|
|
|
289
446
|
declare function reportDiagnostic(sink: DiagnosticSink | undefined, level: 'debug' | 'info' | 'warn' | 'error', message: string, context?: DiagnosticContext): void;
|
|
290
447
|
/** A sink that forwards to a `console`-like object, one call per level. */
|
|
291
448
|
declare function consoleDiagnosticSink(logger?: Partial<Record<'debug' | 'info' | 'warn' | 'error', (msg: string) => void>>): DiagnosticSink;
|
|
449
|
+
/**
|
|
450
|
+
* Options controlling how much of an error is disclosed in a report.
|
|
451
|
+
*
|
|
452
|
+
* Everything defaults to the SAFE (production) posture: no stack, no cause
|
|
453
|
+
* chain. A stack trace can embed absolute file paths and, in some runtimes,
|
|
454
|
+
* source fragments, so it is opt-in and belongs to development / trusted server
|
|
455
|
+
* logging — never to a report that might reach a browser or a third party.
|
|
456
|
+
*/
|
|
457
|
+
interface ErrorReportOptions {
|
|
458
|
+
/** Include `error.stack` in the report. Default `false` (production-safe). */
|
|
459
|
+
readonly includeStack?: boolean;
|
|
460
|
+
/**
|
|
461
|
+
* Follow and describe `error.cause` (recursively, up to a small depth) when
|
|
462
|
+
* present. Default `false`. The cause is described with the SAME redaction
|
|
463
|
+
* rules — only its name/message/(optional)stack, never arbitrary properties.
|
|
464
|
+
*/
|
|
465
|
+
readonly includeCause?: boolean;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* A production-safe, serializable description of an error plus the framework
|
|
469
|
+
* context in which it surfaced. This is what §7 asks a diagnostics sink to
|
|
470
|
+
* receive: enough to locate the failure (component / route / resource / signal /
|
|
471
|
+
* phase / DOM association via {@link DiagnosticContext}) WITHOUT any sensitive
|
|
472
|
+
* data. It deliberately carries ONLY the error's class name and message (both
|
|
473
|
+
* author-controlled), never enumerated own-properties (which frequently hold
|
|
474
|
+
* request bodies, tokens, or user records), and the stack only when explicitly
|
|
475
|
+
* opted in.
|
|
476
|
+
*/
|
|
477
|
+
interface ErrorReport {
|
|
478
|
+
/** The error's constructor name, e.g. `TypeError` (`Error` when unknown). */
|
|
479
|
+
readonly name: string;
|
|
480
|
+
/** The error's message. For a non-Error throw, its `String(...)` form. */
|
|
481
|
+
readonly message: string;
|
|
482
|
+
/** Whether the thrown value was a real `Error` instance. */
|
|
483
|
+
readonly isError: boolean;
|
|
484
|
+
/** The framework context, when supplied. */
|
|
485
|
+
readonly context?: DiagnosticContext;
|
|
486
|
+
/** The stack, only when `includeStack` was set and one exists. */
|
|
487
|
+
readonly stack?: string;
|
|
488
|
+
/** The described cause, only when `includeCause` was set and one exists. */
|
|
489
|
+
readonly cause?: ErrorReport;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Build a {@link ErrorReport} from any thrown value and (optionally) the
|
|
493
|
+
* framework {@link DiagnosticContext} it surfaced in. Production-safe by
|
|
494
|
+
* default: no stack, no cause, no enumerated properties. This is a pure
|
|
495
|
+
* function — it performs no logging and has no side effects, so it is safe to
|
|
496
|
+
* call from any layer (an `errorBoundary` `onError`, an `asyncBoundary` error
|
|
497
|
+
* branch, a resource loader `catch`).
|
|
498
|
+
*/
|
|
499
|
+
declare function describeError(error: unknown, context?: DiagnosticContext, options?: ErrorReportOptions): ErrorReport;
|
|
500
|
+
/**
|
|
501
|
+
* Convenience bridge: build a production-safe {@link ErrorReport} and route it
|
|
502
|
+
* to a {@link DiagnosticSink} at the `error` level. The sink receives the
|
|
503
|
+
* report's message and the structured {@link DiagnosticContext}; the full
|
|
504
|
+
* report is returned to the caller for forwarding elsewhere (e.g. an app's own
|
|
505
|
+
* crash reporter). Safe with `undefined` sink (no-op) and never throws.
|
|
506
|
+
*/
|
|
507
|
+
declare function reportError(sink: DiagnosticSink | undefined, error: unknown, context?: DiagnosticContext, options?: ErrorReportOptions): ErrorReport;
|
|
292
508
|
|
|
293
509
|
/**
|
|
294
510
|
* Compiler-phase validation of the ApplicationGraph.
|
|
@@ -558,6 +774,7 @@ declare class BrowserDOMAdapter implements DOMAdapter {
|
|
|
558
774
|
getElementById(id: string): Element | null;
|
|
559
775
|
focus(element: Element): void;
|
|
560
776
|
body(): Element | null;
|
|
777
|
+
head(): Element | null;
|
|
561
778
|
activeElement(): Element | null;
|
|
562
779
|
contains(ancestor: Element, node: Node): boolean;
|
|
563
780
|
matches(element: Element, selector: string): boolean;
|
|
@@ -703,72 +920,65 @@ declare function focusInitial(dom: DOMAdapter, container: Element, initialFocusI
|
|
|
703
920
|
* cleanup is still callable.
|
|
704
921
|
*/
|
|
705
922
|
declare function trapFocus(dom: DOMAdapter, container: Element): () => void;
|
|
706
|
-
/**
|
|
707
|
-
* Modal containment: if focus moves to an element outside `container`, redirect
|
|
708
|
-
* it back inside. Listens on the document body (focusin bubbles there) and
|
|
709
|
-
* returns a cleanup function. Server-safe no-op (body() is null).
|
|
710
|
-
*/
|
|
711
923
|
declare function containFocus(dom: DOMAdapter, container: Element): () => void;
|
|
712
924
|
/**
|
|
713
925
|
* Invoke `handler` when Escape is pressed while focus is within `target`.
|
|
714
926
|
* Returns a cleanup function. Server-safe no-op.
|
|
715
927
|
*/
|
|
716
928
|
declare function onEscape(dom: DOMAdapter, target: Element, handler: () => void): () => void;
|
|
717
|
-
|
|
718
929
|
/**
|
|
719
|
-
*
|
|
930
|
+
* Roving-focus keyboard navigation for a menu (role="menu") container: the
|
|
931
|
+
* arrow keys move focus between the container's focusable items (wrap-around at
|
|
932
|
+
* both ends), Home/End jump to the first/last item, and Enter/Space activate
|
|
933
|
+
* the currently-focused item (a native `click`, so an item's `onClick` fires).
|
|
934
|
+
* `Tab` and `Escape` are deliberately left alone — the overlay layer wires
|
|
935
|
+
* Escape-to-close separately and a menu does not trap Tab.
|
|
720
936
|
*
|
|
721
|
-
*
|
|
722
|
-
*
|
|
937
|
+
* Items are re-queried on every key (via {@link getFocusable}) so a menu whose
|
|
938
|
+
* items change reactively is always navigated against the live set, and items
|
|
939
|
+
* disabled after mount are skipped. Attaches a keydown listener to the
|
|
940
|
+
* container and returns a cleanup function. Server-safe: `addEventListener` is
|
|
941
|
+
* a no-op and the returned cleanup is still callable.
|
|
723
942
|
*/
|
|
724
|
-
|
|
725
|
-
declare class NodeInstance {
|
|
726
|
-
readonly graphNode: GraphNode;
|
|
727
|
-
/** The primary DOM node for this instance (element or text node). */
|
|
728
|
-
domNode: Node;
|
|
729
|
-
readonly children: NodeInstance[];
|
|
730
|
-
readonly cleanup: CleanupRegistry;
|
|
731
|
-
constructor(graphNode: GraphNode, domNode: Node);
|
|
732
|
-
addChild(child: NodeInstance): void;
|
|
733
|
-
/** Subscribe to a signal; auto-cleanup on unmount. */
|
|
734
|
-
trackSignal<T>(sig: ReadonlySignal<T>, handler: (v: T) => void): void;
|
|
735
|
-
/** Register a raw cleanup fn (DOM event removal, etc.). */
|
|
736
|
-
trackCleanup(fn: () => void): void;
|
|
737
|
-
dispose(): void;
|
|
738
|
-
}
|
|
943
|
+
declare function rovingMenu(dom: DOMAdapter, container: Element, selector?: string): () => void;
|
|
739
944
|
|
|
740
945
|
/**
|
|
741
|
-
*
|
|
946
|
+
* ARIA live-region announcer (§15).
|
|
742
947
|
*
|
|
743
|
-
*
|
|
744
|
-
*
|
|
948
|
+
* Screen readers announce text that appears inside an `aria-live` region. The
|
|
949
|
+
* naive approach — append a fresh `<div aria-live>` per message — leaks a
|
|
950
|
+
* growing pile of stale nodes and (because a node inserted *already carrying*
|
|
951
|
+
* its text is often not re-announced) is unreliable. This announcer instead
|
|
952
|
+
* keeps exactly TWO persistent regions on `<body>` — one `polite`, one
|
|
953
|
+
* `assertive` — and mutates their text to speak. Announcing clears the region
|
|
954
|
+
* first and writes on a microtask so that repeating the same string still
|
|
955
|
+
* triggers a DOM mutation the AT will pick up.
|
|
956
|
+
*
|
|
957
|
+
* Built entirely on the {@link DOMAdapter}, so it is server-safe: when
|
|
958
|
+
* `dom.body()` is null (SSR / headless) construction returns an inert announcer
|
|
959
|
+
* whose `announce`/`clear`/`destroy` are no-ops. There is never any SSR markup
|
|
960
|
+
* for a live region — announcements are a runtime-only concept.
|
|
745
961
|
*/
|
|
746
962
|
|
|
747
|
-
interface
|
|
748
|
-
readonly dom: DOMAdapter;
|
|
749
|
-
readonly graph: ApplicationGraph;
|
|
750
|
-
/** Maps GraphNode.id → its live NodeInstance */
|
|
751
|
-
readonly instances: Map<string, NodeInstance>;
|
|
752
|
-
/** The root container element. */
|
|
753
|
-
readonly container: Element;
|
|
963
|
+
interface Announcer {
|
|
754
964
|
/**
|
|
755
|
-
*
|
|
756
|
-
*
|
|
757
|
-
* DevTools/diagnostics stay off the production runtime path.
|
|
965
|
+
* Announce `message`. `assertive` (default false) routes to the assertive
|
|
966
|
+
* region (interrupts the user) instead of the polite one (waits for a pause).
|
|
758
967
|
*/
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
* node's id is in this map, the renderer emits the precomputed HTML via
|
|
767
|
-
* `dom.createRawHTML` instead of recursively constructing the subtree.
|
|
768
|
-
*/
|
|
769
|
-
readonly staticHTML?: ReadonlyMap<string, string>;
|
|
968
|
+
announce(message: string, options?: {
|
|
969
|
+
assertive?: boolean;
|
|
970
|
+
}): void;
|
|
971
|
+
/** Clear both regions without announcing anything. */
|
|
972
|
+
clear(): void;
|
|
973
|
+
/** Remove both regions from the DOM. Idempotent. */
|
|
974
|
+
destroy(): void;
|
|
770
975
|
}
|
|
771
|
-
|
|
976
|
+
/**
|
|
977
|
+
* Create a live-region announcer bound to `dom`. Idempotent per call — each
|
|
978
|
+
* call owns its own pair of regions, so an app that wants a single shared
|
|
979
|
+
* announcer should create one and reuse it (and `destroy()` it on teardown).
|
|
980
|
+
*/
|
|
981
|
+
declare function createAnnouncer(dom: DOMAdapter): Announcer;
|
|
772
982
|
|
|
773
983
|
/**
|
|
774
984
|
* Attribute and property application helpers.
|
|
@@ -815,6 +1025,7 @@ declare function textUpdate(dom: DOMAdapter, el: Element, textNode: Text): (prop
|
|
|
815
1025
|
declare function headingUpdate(dom: DOMAdapter, el: Element): (propKey: string, value: unknown) => void;
|
|
816
1026
|
declare function inputUpdate(dom: DOMAdapter, el: Element): (propKey: string, value: unknown) => void;
|
|
817
1027
|
declare function buttonUpdate(dom: DOMAdapter, el: Element): (propKey: string, value: unknown) => void;
|
|
1028
|
+
declare function linkUpdate(dom: DOMAdapter, el: Element): (propKey: string, value: unknown) => void;
|
|
818
1029
|
declare function applyNodeProps(ctx: RenderContext, graphNode: GraphNode, el: Element): void;
|
|
819
1030
|
declare function wireSignalBindings(ctx: RenderContext, graphNode: GraphNode, instance: NodeInstance, onUpdate: (propKey: string, value: unknown) => void): void;
|
|
820
1031
|
/**
|
|
@@ -824,7 +1035,7 @@ declare function wireSignalBindings(ctx: RenderContext, graphNode: GraphNode, in
|
|
|
824
1035
|
* (spec §15). A `conditional` node has no plan handler and falls back to the
|
|
825
1036
|
* eager build factory (it only ever renders 0..1 branch, so eager is fine).
|
|
826
1037
|
*/
|
|
827
|
-
declare function wireReactiveList(ctx: RenderContext, graphNode: GraphNode, instance: NodeInstance, el: Element): void;
|
|
1038
|
+
declare function wireReactiveList(ctx: RenderContext, graphNode: GraphNode, instance: NodeInstance, el: Element, runAppear?: boolean): void;
|
|
828
1039
|
/**
|
|
829
1040
|
* Attach overlay focus/keyboard behavior to a mounted portal. Server-safe: on
|
|
830
1041
|
* the server `dom.body()` is null so this returns immediately (SSR emits inert
|
|
@@ -859,6 +1070,122 @@ declare function wireComponentBehavior(ctx: RenderContext, graphNode: GraphNode,
|
|
|
859
1070
|
|
|
860
1071
|
declare function patchNode(ctx: RenderContext, graphNode: GraphNode, propKey: string, newValue: unknown): void;
|
|
861
1072
|
|
|
1073
|
+
/**
|
|
1074
|
+
* CSS class-based enter/leave transition controller (§2–§8).
|
|
1075
|
+
*
|
|
1076
|
+
* This is the browser-only runtime that consumes the `__transition__<nodeId>`
|
|
1077
|
+
* descriptor the DSL registers (a pre-resolved {@link ResolvedTransitionLike}).
|
|
1078
|
+
* It is deliberately structural about that descriptor — like the renderer's
|
|
1079
|
+
* `__overlay__`/`__component__` handling — so the renderer takes NO compile-time
|
|
1080
|
+
* dependency on the DSL package.
|
|
1081
|
+
*
|
|
1082
|
+
* Engine (confirmed decision): CSS classes, no Web Animations API, no
|
|
1083
|
+
* browser-only API referenced at module scope. Every timer / rAF / event
|
|
1084
|
+
* binding is reached lazily through `globalThis` and only ever runs when
|
|
1085
|
+
* `dom.body() !== null` (the same SSR guard `wireOverlayBehavior` uses), so:
|
|
1086
|
+
* - server output is byte-identical (nothing here runs during SSR — §21);
|
|
1087
|
+
* - happy-dom, which dispatches no `transitionend`/`animationend`, still
|
|
1088
|
+
* completes deterministically via the fallback timeout (§24).
|
|
1089
|
+
*
|
|
1090
|
+
* The controller is created once per reactive container instance (reactive-list
|
|
1091
|
+
* or conditional) so its `leaving` map survives across reconcile passes — that
|
|
1092
|
+
* is what makes leave→enter reclaim (§6) and keyed-identity list leave (§7)
|
|
1093
|
+
* correct.
|
|
1094
|
+
*/
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* The renderer's structural view of the resolved transition the DSL stores in
|
|
1098
|
+
* `__transition__<id>`. Mirrors `streetui`'s `ResolvedTransition` without
|
|
1099
|
+
* importing it (no renderer→dsl dependency).
|
|
1100
|
+
*/
|
|
1101
|
+
interface ResolvedTransitionLike {
|
|
1102
|
+
readonly enterActive: readonly string[];
|
|
1103
|
+
readonly enterFrom: readonly string[];
|
|
1104
|
+
readonly enterTo: readonly string[];
|
|
1105
|
+
readonly leaveActive: readonly string[];
|
|
1106
|
+
readonly leaveFrom: readonly string[];
|
|
1107
|
+
readonly leaveTo: readonly string[];
|
|
1108
|
+
readonly appear: boolean;
|
|
1109
|
+
readonly duration: number;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Hooks handed to the reconciler so it can (a) reclaim an instance that is
|
|
1113
|
+
* mid-leave when its key re-enters (leave→enter cancellation), (b) defer the
|
|
1114
|
+
* remove/dispose/forget/detach chain for a leaving instance until its animation
|
|
1115
|
+
* ends, and (c) play the enter animation for a freshly-inserted instance. When
|
|
1116
|
+
* no transition applies (or we are on the server) every hook degrades to the
|
|
1117
|
+
* pre-transition synchronous behaviour.
|
|
1118
|
+
*/
|
|
1119
|
+
interface TransitionHooks {
|
|
1120
|
+
/**
|
|
1121
|
+
* If an instance for `key` is currently animating out, cancel its leave and
|
|
1122
|
+
* return it for reuse; otherwise undefined. The caller re-mounts nothing and
|
|
1123
|
+
* reuses the returned instance's live DOM node.
|
|
1124
|
+
*/
|
|
1125
|
+
takeLeaving(key: string): NodeInstance | undefined;
|
|
1126
|
+
/**
|
|
1127
|
+
* Begin a leave animation for a removed instance. Returns true when the whole
|
|
1128
|
+
* teardown chain has been deferred to animation-end (caller must NOT remove,
|
|
1129
|
+
* dispose, forget or detach it), or false when there is no transition / no
|
|
1130
|
+
* browser and the caller should tear it down synchronously as before.
|
|
1131
|
+
*/
|
|
1132
|
+
beginLeave(inst: NodeInstance): boolean;
|
|
1133
|
+
/** Play the enter animation for a freshly-inserted (or reclaimed) instance. */
|
|
1134
|
+
onEnter(inst: NodeInstance): void;
|
|
1135
|
+
}
|
|
1136
|
+
/** Read the pre-resolved transition descriptor for a node, if any. */
|
|
1137
|
+
declare function getResolvedTransition(graph: ApplicationGraph, nodeId: string): ResolvedTransitionLike | undefined;
|
|
1138
|
+
/** Which half of a transition to play on a bare element. */
|
|
1139
|
+
type TransitionPhase = 'enter' | 'leave';
|
|
1140
|
+
/**
|
|
1141
|
+
* Play one enter/leave transition on a bare DOM element, outside the keyed
|
|
1142
|
+
* reconciler — the seam the router uses for route leave/enter (§9) and any other
|
|
1143
|
+
* consumer that owns a single host element rather than a reactive container.
|
|
1144
|
+
*
|
|
1145
|
+
* Reuses the exact same {@link startRun} mechanics as list/conditional
|
|
1146
|
+
* transitions (from+active applied immediately, next-frame flip to `to`,
|
|
1147
|
+
* completion on transitionend/animationend or the fallback timer), so there is
|
|
1148
|
+
* one transition engine, not two. The returned handle's `cancel()` settles the
|
|
1149
|
+
* run immediately WITHOUT invoking `onDone` — the caller uses it to abort an
|
|
1150
|
+
* in-flight enter when the same host is about to start leaving (rapid
|
|
1151
|
+
* navigation), avoiding overlapping runs/duplicate listeners on one element.
|
|
1152
|
+
*
|
|
1153
|
+
* On the server (or any non-element target) there is nothing to animate, so
|
|
1154
|
+
* `onDone` runs synchronously and `cancel()` is a no-op — the caller's teardown
|
|
1155
|
+
* still happens exactly once.
|
|
1156
|
+
*/
|
|
1157
|
+
declare function runElementTransition(dom: DOMAdapter, el: Element, rt: ResolvedTransitionLike, phase: TransitionPhase, onDone: () => void): {
|
|
1158
|
+
cancel(): void;
|
|
1159
|
+
};
|
|
1160
|
+
/**
|
|
1161
|
+
* Per-container transition controller. One instance is created for each
|
|
1162
|
+
* reactive-list / conditional NodeInstance in {@link wireReactiveList}; its
|
|
1163
|
+
* `leaving` map persists across every reconcile of that container.
|
|
1164
|
+
*/
|
|
1165
|
+
declare class TransitionController {
|
|
1166
|
+
private readonly dom;
|
|
1167
|
+
private readonly graph;
|
|
1168
|
+
/** Full teardown of a leaving instance (remove + dispose + forget + detach). */
|
|
1169
|
+
private readonly finalize;
|
|
1170
|
+
private readonly leaving;
|
|
1171
|
+
constructor(dom: DOMAdapter, graph: ApplicationGraph,
|
|
1172
|
+
/** Full teardown of a leaving instance (remove + dispose + forget + detach). */
|
|
1173
|
+
finalize: (inst: NodeInstance) => void);
|
|
1174
|
+
/** True only in a real DOM environment (browser). */
|
|
1175
|
+
private get browser();
|
|
1176
|
+
private keyOf;
|
|
1177
|
+
private resolved;
|
|
1178
|
+
/** Run the enter animation for `inst` if it carries a transition (browser only). */
|
|
1179
|
+
enter(inst: NodeInstance): void;
|
|
1180
|
+
/**
|
|
1181
|
+
* Play `appear` for any initial child that opted into it (fresh browser mount
|
|
1182
|
+
* only — hydration must never animate appear, §22, and this is called only on
|
|
1183
|
+
* the mount path).
|
|
1184
|
+
*/
|
|
1185
|
+
appear(children: readonly NodeInstance[]): void;
|
|
1186
|
+
hooks(): TransitionHooks;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
862
1189
|
/**
|
|
863
1190
|
* Reconciliation — diff-based child list updates.
|
|
864
1191
|
*
|
|
@@ -911,7 +1238,7 @@ interface PlanEntry {
|
|
|
911
1238
|
* @param newNodes New graph children (in desired order)
|
|
912
1239
|
* @param mountFn Factory to create a new NodeInstance for a graph node
|
|
913
1240
|
*/
|
|
914
|
-
declare function reconcileChildren(ctx: RenderContext, parentDom: Element, oldInstances: NodeInstance[], newNodes: readonly GraphNode[], mountFn: MountFn): ReconcileResult;
|
|
1241
|
+
declare function reconcileChildren(ctx: RenderContext, parentDom: Element, oldInstances: NodeInstance[], newNodes: readonly GraphNode[], mountFn: MountFn, hooks?: TransitionHooks): ReconcileResult;
|
|
915
1242
|
/**
|
|
916
1243
|
* Plan-based keyed reconciliation (spec §15 — the optimised reactive-list path).
|
|
917
1244
|
*
|
|
@@ -930,7 +1257,7 @@ declare function reconcileChildren(ctx: RenderContext, parentDom: Element, oldIn
|
|
|
930
1257
|
* DOM reordering uses a longest-increasing-subsequence pass so the number of
|
|
931
1258
|
* moves is minimal (e.g. a prepend into a 10k list moves 1 node, not 10k).
|
|
932
1259
|
*/
|
|
933
|
-
declare function reconcileChildrenByPlan(ctx: RenderContext, parentDom: Element, oldInstances: NodeInstance[], plan: readonly PlanEntry[], mountFn: MountFn): ReconcileResult;
|
|
1260
|
+
declare function reconcileChildrenByPlan(ctx: RenderContext, parentDom: Element, oldInstances: NodeInstance[], plan: readonly PlanEntry[], mountFn: MountFn, hooks?: TransitionHooks): ReconcileResult;
|
|
934
1261
|
|
|
935
1262
|
/**
|
|
936
1263
|
* StreetUI Renderer — framework-owned DOM renderer.
|
|
@@ -1253,6 +1580,17 @@ interface MountRouterOptions {
|
|
|
1253
1580
|
* subsequent client-side navigations mount normally. Defaults to false.
|
|
1254
1581
|
*/
|
|
1255
1582
|
readonly hydrate?: boolean;
|
|
1583
|
+
/**
|
|
1584
|
+
* Optional enter/leave transition played on client-side navigations (§9). When
|
|
1585
|
+
* set, each navigation mounts the incoming route into its own host wrapper,
|
|
1586
|
+
* plays the enter animation on it, and defers the outgoing route's disposal
|
|
1587
|
+
* (route-scoped cleanup + DOM removal) until its leave animation ends — so
|
|
1588
|
+
* resources stay alive exactly as long as the departing DOM. History is
|
|
1589
|
+
* untouched (the router already navigated), and the initial mount/hydration is
|
|
1590
|
+
* NOT animated (§22-style: the first paint must match the server). Reuses the
|
|
1591
|
+
* single CSS-class transition engine — no second animation system.
|
|
1592
|
+
*/
|
|
1593
|
+
readonly transition?: TransitionConfig;
|
|
1256
1594
|
}
|
|
1257
1595
|
interface MountedRouter {
|
|
1258
1596
|
/** The element route content is rendered into. */
|
|
@@ -1490,6 +1828,58 @@ interface InspectedComponent {
|
|
|
1490
1828
|
* fine-grained prop updates (which never rebuild the node).
|
|
1491
1829
|
*/
|
|
1492
1830
|
declare function inspectComponents(graph: ApplicationGraph): InspectedComponent[];
|
|
1831
|
+
/** An overlay currently wired in the graph (dialog/popover/tooltip/…). */
|
|
1832
|
+
interface InspectedOverlay {
|
|
1833
|
+
/** The build-order node id of the overlay's portal host. */
|
|
1834
|
+
id: string;
|
|
1835
|
+
/** The stable author-provided key, if any. */
|
|
1836
|
+
key: string | undefined;
|
|
1837
|
+
/** Whether the overlay is open right now (peeked, no subscription). */
|
|
1838
|
+
open: boolean;
|
|
1839
|
+
/** Modal (focus-trapping) overlay? */
|
|
1840
|
+
modal: boolean;
|
|
1841
|
+
/** Does it move focus into itself on open? */
|
|
1842
|
+
takesFocus: boolean;
|
|
1843
|
+
/** Is it a roving-focus menu (role="menu")? */
|
|
1844
|
+
menu: boolean;
|
|
1845
|
+
/** Does Escape close it? */
|
|
1846
|
+
closeOnEscape: boolean;
|
|
1847
|
+
/** Does it restore focus to the opener on close? */
|
|
1848
|
+
restoreFocus: boolean;
|
|
1849
|
+
/** Depth of the portal host node in the graph. */
|
|
1850
|
+
depth: number;
|
|
1851
|
+
}
|
|
1852
|
+
/** A transition currently wired on a graph node. */
|
|
1853
|
+
interface InspectedTransition {
|
|
1854
|
+
/** The build-order node id the transition is attached to. */
|
|
1855
|
+
id: string;
|
|
1856
|
+
/** The stable author-provided key, if any. */
|
|
1857
|
+
key: string | undefined;
|
|
1858
|
+
/** The node type the transition animates (element/portal/list-item/…). */
|
|
1859
|
+
nodeType: string;
|
|
1860
|
+
/** Fallback completion timeout in ms (the resolved `duration`). */
|
|
1861
|
+
duration: number;
|
|
1862
|
+
/** Does it animate the very first appearance (initial mount)? */
|
|
1863
|
+
appear: boolean;
|
|
1864
|
+
/** Depth of the node in the graph. */
|
|
1865
|
+
depth: number;
|
|
1866
|
+
}
|
|
1867
|
+
/** A prod-safe snapshot of the graph's interaction wiring. */
|
|
1868
|
+
interface InspectedInteractions {
|
|
1869
|
+
overlays: InspectedOverlay[];
|
|
1870
|
+
transitions: InspectedTransition[];
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Snapshot every overlay and transition currently wired in the graph, in
|
|
1874
|
+
* document order. This is the interaction-aware companion to
|
|
1875
|
+
* {@link inspectComponents}: it reads only the `__overlay__<id>` /
|
|
1876
|
+
* `__transition__<id>` handler descriptors and public graph structure — it
|
|
1877
|
+
* peeks the `open` signal without subscribing, retains no DOM nodes, mutates
|
|
1878
|
+
* nothing, and is safe to call in production. Because a departing overlay's
|
|
1879
|
+
* handler is pruned on detach (`_unregisterNodeHandlers`), a closed-and-removed
|
|
1880
|
+
* overlay simply no longer appears here.
|
|
1881
|
+
*/
|
|
1882
|
+
declare function inspectInteractions(graph: ApplicationGraph): InspectedInteractions;
|
|
1493
1883
|
|
|
1494
1884
|
/**
|
|
1495
1885
|
* DevTools foundation (v0.6, Phase 18). A single read-only entry point that
|
|
@@ -1794,12 +2184,35 @@ interface PerformancePanel {
|
|
|
1794
2184
|
readonly snapshot: ApplicationInspection['perf'];
|
|
1795
2185
|
readonly diagnostics: readonly PerfDiagnostic[];
|
|
1796
2186
|
}
|
|
2187
|
+
/**
|
|
2188
|
+
* Compilation diagnostics for the DevTools "Diagnostics" panel (§8). These are
|
|
2189
|
+
* the compiler's own findings (errors + warnings), surfaced verbatim — not a
|
|
2190
|
+
* runtime error stream. Runtime/production error reports flow through the
|
|
2191
|
+
* separate `reportError`/`DiagnosticSink` seam in `streetui` (§7).
|
|
2192
|
+
*/
|
|
2193
|
+
interface DiagnosticsPanel {
|
|
2194
|
+
readonly errors: number;
|
|
2195
|
+
readonly warnings: number;
|
|
2196
|
+
readonly messages: readonly string[];
|
|
2197
|
+
}
|
|
1797
2198
|
/** All panels captured at one `refresh()`. */
|
|
1798
2199
|
interface DevToolsSnapshot {
|
|
1799
2200
|
readonly application: ApplicationPanel;
|
|
1800
2201
|
readonly graph: InspectedNode;
|
|
1801
2202
|
readonly signals: SignalsPanel;
|
|
1802
2203
|
readonly performance: PerformancePanel;
|
|
2204
|
+
/**
|
|
2205
|
+
* Component tree (§9): every `component()` instance in document order, with
|
|
2206
|
+
* its stable key/name/location. Read structurally from the graph — the same
|
|
2207
|
+
* data an app/component-tree UI panel renders.
|
|
2208
|
+
*/
|
|
2209
|
+
readonly components: readonly InspectedComponent[];
|
|
2210
|
+
/** Overlays currently wired (§13), in graph/containment order (dialog/popover/…). */
|
|
2211
|
+
readonly overlays: readonly InspectedOverlay[];
|
|
2212
|
+
/** Transitions currently wired on nodes (§14). Structural — never interferes with lifecycle. */
|
|
2213
|
+
readonly transitions: readonly InspectedTransition[];
|
|
2214
|
+
/** Compilation diagnostics (§8). */
|
|
2215
|
+
readonly diagnostics: DiagnosticsPanel;
|
|
1803
2216
|
readonly router?: RouterInspection;
|
|
1804
2217
|
readonly resources?: Readonly<Record<string, ResourceInspection>>;
|
|
1805
2218
|
readonly forms?: Readonly<Record<string, FormInspection>>;
|
|
@@ -1869,6 +2282,44 @@ interface DevToolsSession {
|
|
|
1869
2282
|
*/
|
|
1870
2283
|
declare function createDevTools(compiled: CompiledApplication, sources?: DevToolsSources, options?: DevToolsOptions): DevToolsSession;
|
|
1871
2284
|
|
|
2285
|
+
/**
|
|
2286
|
+
* DevTools view (2.0 §8) — a DOM-free HTML renderer for a {@link DevToolsSnapshot}.
|
|
2287
|
+
*
|
|
2288
|
+
* This is the "initial UI" layer: it turns the headless snapshot (already
|
|
2289
|
+
* composed from the existing read-only inspectors) into a single self-contained
|
|
2290
|
+
* HTML string a host can inject into a panel, an iframe, or a static report. It
|
|
2291
|
+
* is deliberately a *pure string builder*:
|
|
2292
|
+
*
|
|
2293
|
+
* - No DOM API is touched and nothing is mounted, so it runs anywhere (Node,
|
|
2294
|
+
* a worker, a test) and adds nothing to the running app.
|
|
2295
|
+
* - It reads ONLY the snapshot — no second graph, no reactive subscriptions,
|
|
2296
|
+
* no retained resource/DOM references.
|
|
2297
|
+
* - Every dynamic value is HTML-escaped, so an app's data (signal values that
|
|
2298
|
+
* the caller chose to expose, route paths, form labels) can never break out
|
|
2299
|
+
* of the markup.
|
|
2300
|
+
*
|
|
2301
|
+
* HONEST SCOPE: this produces markup. Whether it *renders* correctly in a real
|
|
2302
|
+
* browser, is accessible to a screen reader, or performs at 60fps is NOT claimed
|
|
2303
|
+
* here and has NOT been verified — no browser/AT is available in this
|
|
2304
|
+
* environment (the §24 browser gate remains BLOCKED). The value proven by tests
|
|
2305
|
+
* is that the string faithfully and safely reflects the snapshot.
|
|
2306
|
+
*
|
|
2307
|
+
* EFFECTS (§8): StreetUI keeps no global registry of effects (that would require
|
|
2308
|
+
* instrumenting the reactive runtime, which DevTools deliberately does not do).
|
|
2309
|
+
* The closest safe signal is each live signal's `observerCount` — the number of
|
|
2310
|
+
* effects/derivations currently depending on it — which the Signals section
|
|
2311
|
+
* shows. The view labels this honestly rather than inventing an effect list.
|
|
2312
|
+
*/
|
|
2313
|
+
|
|
2314
|
+
/** Escape a string for safe interpolation into HTML text/attribute content. */
|
|
2315
|
+
declare function escapeHtml(value: unknown): string;
|
|
2316
|
+
/**
|
|
2317
|
+
* Render a snapshot to a complete, self-contained HTML document string. The
|
|
2318
|
+
* markup is static; call `renderDevToolsHTML(session.refresh())` again to
|
|
2319
|
+
* reflect new state (DevTools pulls — it is never pushed to).
|
|
2320
|
+
*/
|
|
2321
|
+
declare function renderDevToolsHTML(s: DevToolsSnapshot): string;
|
|
2322
|
+
|
|
1872
2323
|
/**
|
|
1873
2324
|
* StreetUI project configuration (Phase 9). The config is intentionally tiny:
|
|
1874
2325
|
* every field has a sensible default so `streetui.config.ts` is optional. A
|
|
@@ -1923,4 +2374,4 @@ interface ResolvedConfig {
|
|
|
1923
2374
|
/** Identity helper that gives `streetui.config.ts` full type-checking + inference. */
|
|
1924
2375
|
declare function defineConfig(config: StreetUIConfig): StreetUIConfig;
|
|
1925
2376
|
|
|
1926
|
-
export { type A11yIds, Application, ApplicationGraph, ApplicationId, type ApplicationIdentity, type ApplicationInspection, type ApplicationOptions, type ApplicationPanel, BrowserDOMAdapter, CleanupRegistry, CompiledApplication, ContainerDSL, type Context, type ContextInspection, type ContextLike, DEFAULT_PERF_THRESHOLDS, DOMAdapter, type DevToolsOptions, type DevToolsSession, type DevToolsSnapshot, type DevToolsSources, DiagnosticCollector, type DiagnosticContext, type DiagnosticSink, type DiagnosticsSummary, type DomBinding, DomEventRegistry, Environment, type EnvironmentCapabilities, type EnvironmentKind, EventBus, type EventHandler, FOCUSABLE_SELECTOR, type Field, type Form, type FormConfig, type FormInspection, type FormLike, type FormValidators, type FormValues, GraphNode, HydrationDiagnosticSink, type I18n, type I18nConfig, type I18nInspection, type I18nLike, type InspectFormOptions, type InspectI18nOptions, type InspectResourceOptions, type InspectSignalOptions, type InspectedComponent, type InspectedNode, type InspectedPage, type InterpolationParams, type IsActiveOptions, type Job, Lifecycle, type
|
|
2377
|
+
export { type A11yIds, type Announcer, Application, ApplicationGraph, ApplicationId, type ApplicationIdentity, type ApplicationInspection, type ApplicationOptions, type ApplicationPanel, type AuthSession, type AuthSessionConfig, type AuthStatus, BrowserDOMAdapter, CleanupRegistry, type Client, type ClientConfig, CompiledApplication, ContainerDSL, type Context, type ContextInspection, type ContextLike, DEFAULT_PERF_THRESHOLDS, DOMAdapter, type DevToolsOptions, type DevToolsSession, type DevToolsSnapshot, type DevToolsSources, DiagnosticCollector, type DiagnosticContext, type DiagnosticSink, type DiagnosticsPanel, type DiagnosticsSummary, type DomBinding, DomEventRegistry, Environment, type EnvironmentCapabilities, type EnvironmentKind, type ErrorReport, type ErrorReportOptions, EventBus, type EventHandler, FOCUSABLE_SELECTOR, type FetchLike, type Field, type Form, type FormConfig, type FormInspection, type FormLike, type FormValidators, type FormValues, GraphNode, HttpError, type HttpMethod, HydrationDiagnosticSink, type I18n, type I18nConfig, type I18nInspection, type I18nLike, type InspectFormOptions, type InspectI18nOptions, type InspectResourceOptions, type InspectSignalOptions, type InspectedComponent, type InspectedInteractions, type InspectedNode, type InspectedOverlay, type InspectedPage, type InspectedTransition, type InterpolationParams, type IsActiveOptions, type Job, Lifecycle, type LoadUser, type MatchResult, type MessageMap, type MountFn, type MountRouterOptions, type MountedApplication, type MountedRouter, type Mutation, type MutationOptions, type MutationStatus, type Mutator, type NavigateOptions, NodeInstance, type NodeInstanceOptions, PageDSL, type PerfDiagnostic, type PerfDiagnosticCode, type PerfSnapshot, type PerfThresholds, type PerformancePanel, type PlanEntry, type Priority, ROUTER_OUTLET_ID, ReadonlySignal, type ReconcileResult, RenderContext, RenderHandle, type RequestConfig, type ResolvedConfig, type ResolvedTransitionLike, Resource, type ResourceInspection, type ResourceLike, ResourceLoaderContext, ResourceOptions, ResourceStatus, type RouteBuilder, type RouteContext, type RouteDefinition, type RouteMatch, type RouteMatchLike, type Router, type RouterHistory, type RouterInspection, type RouterLike, type RouterLocation, type RouterOptions, Runtime, RuntimeNodeInstance, type RuntimeOptions, Scheduler, type SchedulerDiagnostics, SemanticNodeType, ServerComment, ServerElement, ServerFragment, type ServerNode, type ServerNodeKind, type ServerParent, ServerRawHTML, ServerStyle, ServerText, type ShellBuilder, Signal, type SignalInspection, SignalKind, type SignalsPanel, Store, type StoreState, type StreetEvent, type StreetEventType, StreetFrameworkError, StreetRenderHandle, StreetRenderer, StreetRendererImpl, type StreetRendererOptions, type StreetUIConfig, type SubmitStatus, Subscriber, TransitionConfig, TransitionController, type TransitionHooks, type TransitionPhase, Unsubscribe, type Validator, a11yIds, applyNodeProps, applyProp, bindDomEvent, browserDOMAdapter, buttonUpdate, consoleDiagnosticSink, containFocus, createAnnouncer, createApplication, createAuthSession, createBrowserHistory, createClient, createContext, createDevTools, createForm, createI18n, createMemoryHistory, createRenderer, createRouter, createRuntime, createStore, createStreetEvent, defineConfig, describeError, diagnosePerformance, email, environment, escapeHtml, escapeHtmlAttr, escapeHtmlText, flushSync, focusById, focusFirst, focusInitial, formatDiagnosticContext, frameworkError, getFocusable, getResolvedTransition, globalEventBus, headingUpdate, hydrateGraph, inputUpdate, inspectApplication, inspectComponents, inspectContext, inspectForm, inspectGraph, inspectI18n, inspectInteractions, inspectResource, inspectRouter, inspectSignal, interpolate, linkUpdate, matchPattern, matchRoutes, maxLength, minLength, mountGraph, mountNode, mountRouter, mutation, nodeTypeStats, normalizePath, onEscape, patchNode, patchProp, pattern, printDiagnostics, printGraph, reconcileChildren, reconcileChildrenByPlan, renderDevToolsHTML, reportDiagnostic, reportError, required, resolveTag, restoreFocus, routerOutlet, rovingMenu, runElementTransition, runValidators, saveFocus, scheduleImmediate, scheduleUpdate, scheduler, serializeChildren, serializeServerNode, splitTarget, textUpdate, toIdToken, transformGraph, trapFocus, validateGraph, wireComponentBehavior, wireEvents, wireOverlayBehavior, wireReactiveList, wireSignalBindings };
|