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
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* (`streetui --version`) — the consolidated test-suite pins all three to the
|
|
8
8
|
* same coordinated release so they can never silently drift apart.
|
|
9
9
|
*/
|
|
10
|
-
declare const VERSION = "
|
|
10
|
+
declare const VERSION = "2.0.0";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* StreetUI reactive signals — framework-owned reactivity, no external libraries.
|
|
@@ -128,6 +128,86 @@ declare function signalKind(source: ReadonlySignal<unknown>): SignalKind;
|
|
|
128
128
|
*/
|
|
129
129
|
declare function observerCount(source: ReadonlySignal<unknown>): number | undefined;
|
|
130
130
|
|
|
131
|
+
/**
|
|
132
|
+
* StreetUI async resources — framework-native asynchronous data.
|
|
133
|
+
*
|
|
134
|
+
* A `resource` wraps a Promise-returning loader and exposes its lifecycle as
|
|
135
|
+
* ordinary StreetUI signals (status / data / error), so it composes with
|
|
136
|
+
* `derived`, `effect`, `when()`, `listOf` and the renderer with no second
|
|
137
|
+
* reactive system.
|
|
138
|
+
*
|
|
139
|
+
* State machine:
|
|
140
|
+
*
|
|
141
|
+
* idle ──(load)──▶ loading ──(resolve)──▶ success
|
|
142
|
+
* │
|
|
143
|
+
* └────(reject)──────▶ error
|
|
144
|
+
*
|
|
145
|
+
* Refetch keeps the previously-loaded `data` visible while `status` is
|
|
146
|
+
* `'loading'` again (see `isRefetching`) — there is no separate `'refetching'`
|
|
147
|
+
* status; it is expressed through `status === 'loading'` with `data` still set.
|
|
148
|
+
*
|
|
149
|
+
* The resource is transport-agnostic: the loader is any function returning a
|
|
150
|
+
* value or a Promise. When it accepts the provided `AbortSignal`, in-flight
|
|
151
|
+
* work is cancelled on `dispose()` or when a newer request supersedes it.
|
|
152
|
+
*/
|
|
153
|
+
|
|
154
|
+
type ResourceStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
155
|
+
/** Context handed to the loader; carries an AbortSignal for cancellation. */
|
|
156
|
+
interface ResourceLoaderContext {
|
|
157
|
+
readonly signal: AbortSignal;
|
|
158
|
+
}
|
|
159
|
+
/** Any value-or-Promise producing function. Receives an abort-aware context. */
|
|
160
|
+
type ResourceLoader<T> = (ctx: ResourceLoaderContext) => Promise<T> | T;
|
|
161
|
+
interface ResourceOptions<T = unknown> {
|
|
162
|
+
/** Load immediately on creation. Defaults to `true`. When `false`, stays `idle` until `refetch()`. */
|
|
163
|
+
readonly immediate?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Explicit reactive dependencies. When any listed signal changes, the
|
|
166
|
+
* resource refetches. Dependencies are explicit (not auto-tracked from the
|
|
167
|
+
* loader body) so there is no risk of an accidental infinite refetch loop.
|
|
168
|
+
*/
|
|
169
|
+
readonly watch?: ReadonlyArray<ReadonlySignal<unknown>>;
|
|
170
|
+
/**
|
|
171
|
+
* Optional teardown registrar (e.g. a route's `ctx.onCleanup`). When given,
|
|
172
|
+
* the resource registers its own `dispose` so it is cleaned up automatically
|
|
173
|
+
* when its owner is removed.
|
|
174
|
+
*/
|
|
175
|
+
readonly onCleanup?: (fn: () => void) => void;
|
|
176
|
+
/**
|
|
177
|
+
* Server-provided initial value for hydration. When present the resource
|
|
178
|
+
* starts in `'success'` with this data already visible, and the initial
|
|
179
|
+
* auto-load is skipped (so the client does not refetch data the server
|
|
180
|
+
* already resolved). This is the client half of SSR resource transfer; the
|
|
181
|
+
* server side awaits `refetch()` before serializing. Set `immediate: true`
|
|
182
|
+
* explicitly to force a client refetch anyway.
|
|
183
|
+
*/
|
|
184
|
+
readonly initialData?: T;
|
|
185
|
+
/** Server-provided initial error for hydration (mirrors `initialData`). */
|
|
186
|
+
readonly initialError?: unknown;
|
|
187
|
+
/**
|
|
188
|
+
* Explicit initial status override. Rarely needed — inferred as `'success'`
|
|
189
|
+
* from `initialData` or `'error'` from `initialError`.
|
|
190
|
+
*/
|
|
191
|
+
readonly initialStatus?: ResourceStatus;
|
|
192
|
+
}
|
|
193
|
+
interface Resource<T> {
|
|
194
|
+
/** Reactive lifecycle status. */
|
|
195
|
+
readonly status: ReadonlySignal<ResourceStatus>;
|
|
196
|
+
/** The last successfully-loaded value, or `undefined` before first success. */
|
|
197
|
+
readonly data: ReadonlySignal<T | undefined>;
|
|
198
|
+
/** The most recent error, or `undefined` when there is none. Typed `unknown` — never `any`. */
|
|
199
|
+
readonly error: ReadonlySignal<unknown>;
|
|
200
|
+
/** Convenience: `status === 'loading'`. */
|
|
201
|
+
readonly loading: ReadonlySignal<boolean>;
|
|
202
|
+
/** Convenience: loading while previously-loaded data is still present (a refetch). */
|
|
203
|
+
readonly isRefetching: ReadonlySignal<boolean>;
|
|
204
|
+
/** Trigger a new request. Resolves when the request settles (or is superseded). */
|
|
205
|
+
refetch(): Promise<void>;
|
|
206
|
+
/** Cancel in-flight work, drop watchers, and ignore any late results. Idempotent. */
|
|
207
|
+
dispose(): void;
|
|
208
|
+
}
|
|
209
|
+
declare function resource<T>(loader: ResourceLoader<T>, options?: ResourceOptions<T>): Resource<T>;
|
|
210
|
+
|
|
131
211
|
/**
|
|
132
212
|
* Node and application identity utilities.
|
|
133
213
|
* Every node in the semantic graph has a stable, unique identity.
|
|
@@ -195,7 +275,7 @@ declare function formatDiagnostic(d: Diagnostic): string;
|
|
|
195
275
|
* in the Semantic Application Graph.
|
|
196
276
|
*/
|
|
197
277
|
|
|
198
|
-
type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional' | 'portal';
|
|
278
|
+
type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional' | 'portal' | 'head';
|
|
199
279
|
interface NodeMetadata {
|
|
200
280
|
readonly createdAt: number;
|
|
201
281
|
readonly [key: string]: unknown;
|
|
@@ -446,6 +526,218 @@ declare function component<P = Record<string, never>>(setup: ComponentSetup<P>,
|
|
|
446
526
|
/** Runtime guard: is `value` a component definition? */
|
|
447
527
|
declare function isComponentDefinition(value: unknown): value is ComponentDefinition<unknown>;
|
|
448
528
|
|
|
529
|
+
/**
|
|
530
|
+
* Transition configuration (§2, §4).
|
|
531
|
+
*
|
|
532
|
+
* A `TransitionConfig` is a pure, declarative description of a CSS class-based
|
|
533
|
+
* enter/leave transition — the engine choice for this milestone. It contains NO
|
|
534
|
+
* DOM references, NO timers and NO browser-only APIs, so it is safe to build on
|
|
535
|
+
* the server (where it is simply ignored — see the renderer's SSR guard) and to
|
|
536
|
+
* carry on a graph handler (`__transition__<nodeId>`) alongside the existing
|
|
537
|
+
* `__overlay__`/`__component__` descriptors.
|
|
538
|
+
*
|
|
539
|
+
* The class model follows the widely-understood enter/leave convention:
|
|
540
|
+
*
|
|
541
|
+
* enter: [enterActive (+ enter) whole phase] · enterFrom (start) → enterTo (end)
|
|
542
|
+
* leave: [leaveActive (+ leave) whole phase] · leaveFrom (start) → leaveTo (end)
|
|
543
|
+
*
|
|
544
|
+
* `name` is a shorthand that expands to `${name}-enter-from`,
|
|
545
|
+
* `${name}-enter-active`, `${name}-enter-to` and the leave equivalents; explicit
|
|
546
|
+
* class fields override the derived ones. Because the classes are just strings,
|
|
547
|
+
* SSR output is deterministic (no class is applied on the server at all — the
|
|
548
|
+
* controller is browser-only), satisfying §4/§21.
|
|
549
|
+
*/
|
|
550
|
+
interface TransitionConfig {
|
|
551
|
+
/** Shorthand base: expands to `${name}-enter-from`, `${name}-enter-active`, … */
|
|
552
|
+
readonly name?: string;
|
|
553
|
+
/** Class(es) present for the whole enter phase (in addition to `enterActive`). */
|
|
554
|
+
readonly enter?: string;
|
|
555
|
+
/** Class(es) applied at the start of enter, removed on the next frame. */
|
|
556
|
+
readonly enterFrom?: string;
|
|
557
|
+
/** Class(es) present for the whole enter phase (where the CSS `transition` lives). */
|
|
558
|
+
readonly enterActive?: string;
|
|
559
|
+
/** Class(es) added on the next frame, removed when enter completes. */
|
|
560
|
+
readonly enterTo?: string;
|
|
561
|
+
/** Class(es) present for the whole leave phase (in addition to `leaveActive`). */
|
|
562
|
+
readonly leave?: string;
|
|
563
|
+
/** Class(es) applied at the start of leave, removed on the next frame. */
|
|
564
|
+
readonly leaveFrom?: string;
|
|
565
|
+
/** Class(es) present for the whole leave phase (where the CSS `transition` lives). */
|
|
566
|
+
readonly leaveActive?: string;
|
|
567
|
+
/** Class(es) added on the next frame, removed when leave completes. */
|
|
568
|
+
readonly leaveTo?: string;
|
|
569
|
+
/**
|
|
570
|
+
* Also animate the very first appearance (initial mount). Hydration never
|
|
571
|
+
* animates appear (the DOM is already present and correct); this only affects
|
|
572
|
+
* fresh browser mounts. Defaults to false.
|
|
573
|
+
*/
|
|
574
|
+
readonly appear?: boolean;
|
|
575
|
+
/**
|
|
576
|
+
* Fallback completion timeout in milliseconds. A transition normally completes
|
|
577
|
+
* on the element's `transitionend`/`animationend`. This timeout is the safety
|
|
578
|
+
* net for (a) transitions that fire no such event and (b) test DOMs like
|
|
579
|
+
* happy-dom that dispatch no transition events at all — making tests
|
|
580
|
+
* deterministic without a real browser (§24). Defaults to 1000. Use a small
|
|
581
|
+
* value (or 0 → next macrotask) in tests.
|
|
582
|
+
*/
|
|
583
|
+
readonly duration?: number;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* The resolved, ready-to-apply form of a {@link TransitionConfig}: each phase's
|
|
587
|
+
* classes are pre-split into arrays so the controller applies/removes them with
|
|
588
|
+
* no per-run string parsing. Produced once by {@link resolveTransition} at wire
|
|
589
|
+
* time (browser only).
|
|
590
|
+
*/
|
|
591
|
+
interface ResolvedTransition {
|
|
592
|
+
/** enter classes present for the whole phase (base `enter` + `enterActive`). */
|
|
593
|
+
readonly enterActive: readonly string[];
|
|
594
|
+
/** enter start classes (removed next frame). */
|
|
595
|
+
readonly enterFrom: readonly string[];
|
|
596
|
+
/** enter end classes (added next frame). */
|
|
597
|
+
readonly enterTo: readonly string[];
|
|
598
|
+
readonly leaveActive: readonly string[];
|
|
599
|
+
readonly leaveFrom: readonly string[];
|
|
600
|
+
readonly leaveTo: readonly string[];
|
|
601
|
+
readonly appear: boolean;
|
|
602
|
+
readonly duration: number;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Resolve a {@link TransitionConfig} into applied class arrays. The `name`
|
|
606
|
+
* shorthand supplies defaults; any explicit field overrides the derived class
|
|
607
|
+
* for that phase-slot (still merged with `enter`/`leave` base classes).
|
|
608
|
+
*/
|
|
609
|
+
declare function resolveTransition(config: TransitionConfig): ResolvedTransition;
|
|
610
|
+
/** Runtime brand check for a transition descriptor value. */
|
|
611
|
+
declare function isTransitionConfig(value: unknown): value is TransitionConfig;
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Document head / metadata model (2.0 §1–§3).
|
|
615
|
+
*
|
|
616
|
+
* `head({...})` is a first-class StreetUI primitive for declaring document
|
|
617
|
+
* metadata — title, meta, link, canonical, Open Graph, Twitter/X, robots,
|
|
618
|
+
* theme-color and favicon. It is NOT a copy of another framework's API: it is
|
|
619
|
+
* expressed on StreetUI's own component/graph model. A `head()` call creates a
|
|
620
|
+
* `'head'` graph node (rendered as a neutral inline anchor, like a portal) and
|
|
621
|
+
* registers a `__head__<nodeId>` descriptor — exactly the handler-registry
|
|
622
|
+
* convention used by `__overlay__`/`__transition__`/`__component__`. The
|
|
623
|
+
* renderer reads that descriptor to:
|
|
624
|
+
*
|
|
625
|
+
* • apply the contribution to `document.head` on the browser
|
|
626
|
+
* (`wireHeadBehavior`), adopting server-emitted tags on hydration so there
|
|
627
|
+
* are no duplicates, and cleaning up its own tags on unmount / route change;
|
|
628
|
+
* • emit only the active graph's merged metadata as an HTML string on the
|
|
629
|
+
* server (`renderHead`).
|
|
630
|
+
*
|
|
631
|
+
* This module is pure and DOM-free (like `transition.ts`): it defines the config
|
|
632
|
+
* shape and normalises it into an ordered list of {@link HeadEntry} with stable
|
|
633
|
+
* *dedup keys*. All merge/precedence/DOM work happens in the renderer, keyed by
|
|
634
|
+
* these entries.
|
|
635
|
+
*
|
|
636
|
+
* ── Deduplication & precedence (§3) ──────────────────────────────────────────
|
|
637
|
+
* Every entry carries a `dedupKey`. When several `head()` nodes are live at once
|
|
638
|
+
* (e.g. an app-level default, a route-level `head()`, and a component-level
|
|
639
|
+
* `head()`), the renderer merges all of their entries and, for each `dedupKey`,
|
|
640
|
+
* the LAST contribution in document order wins. Document order is pre-order DFS
|
|
641
|
+
* = mount order, so a `head()` declared deeper/later (a route or a component
|
|
642
|
+
* nested inside the app shell) deterministically overrides an app-level default
|
|
643
|
+
* for the same key. Removing that node (navigating away, unmounting the
|
|
644
|
+
* component) re-exposes the previously-shadowed default. `<title>` and each
|
|
645
|
+
* single-instance meta/link (description, robots, theme-color, viewport,
|
|
646
|
+
* charset, canonical, favicon, and each og: or twitter: property) collapse to one
|
|
647
|
+
* effective tag; generic `meta[]`/`link[]` array entries are keyed by their
|
|
648
|
+
* identifying attributes so independent tags coexist.
|
|
649
|
+
*/
|
|
650
|
+
|
|
651
|
+
/** A head value that may be a literal string or a reactive signal of a string. */
|
|
652
|
+
type BindableString = string | ReadonlySignal<string> | Signal<string>;
|
|
653
|
+
/** A single `<meta>` descriptor. Provide exactly one identifying key. */
|
|
654
|
+
interface MetaDescriptor {
|
|
655
|
+
/** `name="…"` (e.g. "description", "robots", "theme-color", "twitter:card"). */
|
|
656
|
+
readonly name?: string;
|
|
657
|
+
/** `property="…"` (e.g. "og:title", "og:image") — the Open Graph convention. */
|
|
658
|
+
readonly property?: string;
|
|
659
|
+
/** `http-equiv="…"` (e.g. "content-security-policy"). */
|
|
660
|
+
readonly httpEquiv?: string;
|
|
661
|
+
/** `charset="…"` (e.g. "utf-8"). Standalone; no `content`. */
|
|
662
|
+
readonly charset?: string;
|
|
663
|
+
/** The tag's `content`. May be reactive. */
|
|
664
|
+
readonly content?: BindableString;
|
|
665
|
+
}
|
|
666
|
+
/** A single `<link>` descriptor. `rel`+`href` identify it. */
|
|
667
|
+
interface LinkDescriptor {
|
|
668
|
+
readonly rel: string;
|
|
669
|
+
readonly href: string;
|
|
670
|
+
readonly sizes?: string;
|
|
671
|
+
readonly type?: string;
|
|
672
|
+
readonly media?: string;
|
|
673
|
+
readonly as?: string;
|
|
674
|
+
readonly crossorigin?: string;
|
|
675
|
+
readonly hreflang?: string;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Declarative document metadata. Every field is optional; convenience fields
|
|
679
|
+
* (title/description/canonical/robots/themeColor/viewport/charset/favicon/
|
|
680
|
+
* openGraph/twitter) expand into the same normalized entries as the raw
|
|
681
|
+
* `meta`/`link` arrays, with single-instance dedup keys so a later `head()`
|
|
682
|
+
* cleanly overrides an earlier one.
|
|
683
|
+
*/
|
|
684
|
+
interface HeadMetadata {
|
|
685
|
+
/** `<title>` text. May be reactive. Single-instance (dedup key `title`). */
|
|
686
|
+
readonly title?: BindableString;
|
|
687
|
+
/** `<meta name="description">`. May be reactive. */
|
|
688
|
+
readonly description?: BindableString;
|
|
689
|
+
/** `<link rel="canonical">` href. */
|
|
690
|
+
readonly canonical?: string;
|
|
691
|
+
/** `<meta name="robots">` (e.g. "index,follow" / "noindex"). */
|
|
692
|
+
readonly robots?: string;
|
|
693
|
+
/** `<meta name="theme-color">`. */
|
|
694
|
+
readonly themeColor?: string;
|
|
695
|
+
/** `<meta name="viewport">`. */
|
|
696
|
+
readonly viewport?: string;
|
|
697
|
+
/** `<meta charset>`. */
|
|
698
|
+
readonly charset?: string;
|
|
699
|
+
/** Favicon: a shorthand for `<link rel="icon">`. String = href, or a full descriptor. */
|
|
700
|
+
readonly favicon?: string | LinkDescriptor;
|
|
701
|
+
/** Open Graph properties — each key `k` becomes `<meta property="og:k">`. Values may be reactive. */
|
|
702
|
+
readonly openGraph?: Readonly<Record<string, BindableString>>;
|
|
703
|
+
/** Twitter/X card properties — each key `k` becomes `<meta name="twitter:k">`. Values may be reactive. */
|
|
704
|
+
readonly twitter?: Readonly<Record<string, BindableString>>;
|
|
705
|
+
/** Raw `<meta>` tags (for anything the convenience fields don't cover). */
|
|
706
|
+
readonly meta?: readonly MetaDescriptor[];
|
|
707
|
+
/** Raw `<link>` tags (stylesheets, preload, alternate, etc.). */
|
|
708
|
+
readonly link?: readonly LinkDescriptor[];
|
|
709
|
+
/** `<base href>` — single-instance. */
|
|
710
|
+
readonly base?: string;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* A normalized head tag: one `<title>`, `<meta>`, `<link>` or `<base>`. Attr
|
|
714
|
+
* values and the title's text may still be reactive (`BindableString`); the
|
|
715
|
+
* renderer peeks them for SSR and subscribes to them on the browser. `dedupKey`
|
|
716
|
+
* is what the merge collapses on.
|
|
717
|
+
*/
|
|
718
|
+
interface HeadEntry {
|
|
719
|
+
readonly tag: 'title' | 'meta' | 'link' | 'base';
|
|
720
|
+
readonly dedupKey: string;
|
|
721
|
+
/** Static + reactive attributes (no `undefined` values). */
|
|
722
|
+
readonly attrs: Readonly<Record<string, BindableString>>;
|
|
723
|
+
/** Text content — only meaningful for `tag === 'title'`. */
|
|
724
|
+
readonly text?: BindableString;
|
|
725
|
+
}
|
|
726
|
+
/** The value a `__head__<id>` handler returns: this node's ordered contribution. */
|
|
727
|
+
interface HeadContribution {
|
|
728
|
+
readonly entries: readonly HeadEntry[];
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Normalise a {@link HeadMetadata} into an ordered list of {@link HeadEntry}.
|
|
732
|
+
* Emission order within one `head()` is: charset → base → title → description →
|
|
733
|
+
* canonical → robots → theme-color → viewport → favicon → openGraph → twitter →
|
|
734
|
+
* explicit meta[] → explicit link[]. (Merge across nodes is document order; this
|
|
735
|
+
* per-node order only affects the sequence of same-priority tags.)
|
|
736
|
+
*/
|
|
737
|
+
declare function resolveHead(config: HeadMetadata): HeadContribution;
|
|
738
|
+
/** Runtime brand check for a head-contribution descriptor value. */
|
|
739
|
+
declare function isHeadContribution(value: unknown): value is HeadContribution;
|
|
740
|
+
|
|
449
741
|
/**
|
|
450
742
|
* StreetUI DSL type system.
|
|
451
743
|
* All builder callbacks and option shapes live here.
|
|
@@ -492,6 +784,14 @@ interface A11yOptions {
|
|
|
492
784
|
readonly ariaRequired?: boolean;
|
|
493
785
|
/** aria-modal — mark a dialog as modal (content outside is inert to AT). */
|
|
494
786
|
readonly ariaModal?: boolean;
|
|
787
|
+
/** aria-owns — id(s) of elements owned by this one when the DOM can't express it. */
|
|
788
|
+
readonly ariaOwns?: string;
|
|
789
|
+
/** aria-activedescendant — id of the active option in a composite widget (menu/listbox/combobox). */
|
|
790
|
+
readonly ariaActiveDescendant?: string;
|
|
791
|
+
/** aria-haspopup — the element opens a popup ('menu' | 'listbox' | 'dialog' | 'grid' | 'tree' | true). */
|
|
792
|
+
readonly ariaHasPopup?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';
|
|
793
|
+
/** aria-selected — selection state within a composite widget. */
|
|
794
|
+
readonly ariaSelected?: boolean;
|
|
495
795
|
}
|
|
496
796
|
interface TextOptions extends A11yOptions {
|
|
497
797
|
readonly class?: string;
|
|
@@ -555,6 +855,15 @@ interface ContainerOptions extends A11yOptions {
|
|
|
555
855
|
readonly class?: string;
|
|
556
856
|
readonly id?: string;
|
|
557
857
|
readonly key?: string;
|
|
858
|
+
/**
|
|
859
|
+
* Enter/leave transition for this element (§2). CSS class-based and
|
|
860
|
+
* browser-only: on the server it is ignored (deterministic SSR output). The
|
|
861
|
+
* enter animation runs when the element is added by a reactive `when`/`listOf`
|
|
862
|
+
* change (or on initial mount when `appear` is set); the leave animation runs
|
|
863
|
+
* before the element is removed and disposed — the reconciler defers teardown
|
|
864
|
+
* until the transition completes.
|
|
865
|
+
*/
|
|
866
|
+
readonly transition?: TransitionConfig;
|
|
558
867
|
}
|
|
559
868
|
interface SectionOptions extends ContainerOptions {
|
|
560
869
|
}
|
|
@@ -562,6 +871,21 @@ interface FormOptions extends ContainerOptions {
|
|
|
562
871
|
readonly onSubmit?: (e: Event) => void;
|
|
563
872
|
}
|
|
564
873
|
interface ListOptions extends ContainerOptions {
|
|
874
|
+
/**
|
|
875
|
+
* Enter/leave transition applied to each list item (§7). Preserves keyed
|
|
876
|
+
* identity: reordering reuses items (no leave/enter), append/prepend enter,
|
|
877
|
+
* remove leaves before disposal, and a removed key that reappears mid-leave is
|
|
878
|
+
* reclaimed (leave→enter). `transition` (inherited) applies to the list
|
|
879
|
+
* container itself; `itemTransition` applies to its rows.
|
|
880
|
+
*/
|
|
881
|
+
readonly itemTransition?: TransitionConfig;
|
|
882
|
+
}
|
|
883
|
+
/** Options for `when()` (§2 conditional transitions). */
|
|
884
|
+
interface WhenOptions {
|
|
885
|
+
/** Transition applied to the active branch as it mounts/unmounts. */
|
|
886
|
+
readonly transition?: TransitionConfig;
|
|
887
|
+
/** Also animate the branch present on the initial mount (appear). */
|
|
888
|
+
readonly appear?: boolean;
|
|
565
889
|
}
|
|
566
890
|
/** Options for a plain portal (mount children into `document.body`). */
|
|
567
891
|
interface PortalOptions extends ContainerOptions {
|
|
@@ -606,6 +930,40 @@ interface ErrorBoundaryOptions {
|
|
|
606
930
|
readonly source?: ErrorSource | ReadonlyArray<ErrorSource>;
|
|
607
931
|
/** Invoked by the fallback's `retry()`, before the body is re-attempted (e.g. `resource.refetch`). */
|
|
608
932
|
readonly onRetry?: () => void;
|
|
933
|
+
/**
|
|
934
|
+
* Error-reporting hook (§6/§7). Called with the current error each time the
|
|
935
|
+
* boundary ENTERS its error state (i.e. when the fallback mounts), including
|
|
936
|
+
* on a re-entry after a failed retry. Use it to forward the error to a
|
|
937
|
+
* production diagnostics sink. It observes only — it never changes the
|
|
938
|
+
* boundary's behavior, and receives the same `unknown` error the fallback
|
|
939
|
+
* sees (no sensitive framework internals are injected).
|
|
940
|
+
*/
|
|
941
|
+
readonly onError?: (error: unknown) => void;
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Branch builders for {@link ContainerDSL.asyncBoundary} — the loading / error /
|
|
945
|
+
* success states of a {@link Resource}. This is deliberately NOT a new async
|
|
946
|
+
* system: it is thin sugar over the existing `resource` state machine and
|
|
947
|
+
* `when()`. Exactly one branch is live at a time, chosen by the resource's
|
|
948
|
+
* reactive `status`/`data` (error takes precedence, then resolved data, then
|
|
949
|
+
* loading), so mounting/unmounting and cleanup all reuse the conditional
|
|
950
|
+
* machinery. Branch signature mirrors `errorBoundary`'s fallback: the content
|
|
951
|
+
* scope comes first.
|
|
952
|
+
*/
|
|
953
|
+
interface AsyncBoundaryBranches<T> {
|
|
954
|
+
/** Shown while the resource is idle or performing its first load (no data yet). */
|
|
955
|
+
readonly loading?: (content: ContainerDSL) => void;
|
|
956
|
+
/**
|
|
957
|
+
* Shown while the resource is in its error state. Receives the current error
|
|
958
|
+
* and a `retry()` that re-runs the loader (a thin wrapper over `refetch`).
|
|
959
|
+
*/
|
|
960
|
+
readonly error?: (content: ContainerDSL, error: unknown, retry: () => void) => void;
|
|
961
|
+
/**
|
|
962
|
+
* Shown once the resource has data (including while a refetch keeps the old
|
|
963
|
+
* value visible). Receives the data as a `ReadonlySignal<T>` so the branch can
|
|
964
|
+
* bind it reactively and update in place without remounting.
|
|
965
|
+
*/
|
|
966
|
+
readonly success: (content: ContainerDSL, data: ReadonlySignal<T>) => void;
|
|
609
967
|
}
|
|
610
968
|
interface ContentDSL {
|
|
611
969
|
heading(text: BindableText, options?: HeadingOptions): void;
|
|
@@ -634,7 +992,7 @@ interface ContainerDSL extends ContentDSL {
|
|
|
634
992
|
* renders while the condition is false. Compiles into the same reactive
|
|
635
993
|
* reconciliation machinery as `listOf` — there is no separate render path.
|
|
636
994
|
*/
|
|
637
|
-
when(condition: Bindable<boolean>, builder: ContainerBuilder, elseBuilder?: ContainerBuilder): void;
|
|
995
|
+
when(condition: Bindable<boolean>, builder: ContainerBuilder, elseBuilder?: ContainerBuilder, options?: WhenOptions): void;
|
|
638
996
|
/**
|
|
639
997
|
* Render `builder`, but swap to `options.fallback` when the boundary enters an
|
|
640
998
|
* error state. A boundary enters that state when (a) any observed `source`
|
|
@@ -646,6 +1004,23 @@ interface ContainerDSL extends ContentDSL {
|
|
|
646
1004
|
* removal. It does NOT trap arbitrary global errors; errors remain observable.
|
|
647
1005
|
*/
|
|
648
1006
|
errorBoundary(id: string, builder: ContainerBuilder, options: ErrorBoundaryOptions): void;
|
|
1007
|
+
/**
|
|
1008
|
+
* Render the loading / error / success states of an async {@link Resource}
|
|
1009
|
+
* (§4). This is sugar over the existing `resource` state machine and `when()`
|
|
1010
|
+
* — NOT a second async system and NOT a literal port of React Suspense. It
|
|
1011
|
+
* renders exactly one branch at a time based on the resource's reactive state:
|
|
1012
|
+
* the `error` branch while `status === 'error'` (with a `retry()` that calls
|
|
1013
|
+
* `refetch`), otherwise the `success` branch once data is present (data passed
|
|
1014
|
+
* as a `ReadonlySignal<T>` so it updates in place, and stays visible while a
|
|
1015
|
+
* refetch is in flight), otherwise the `loading` branch. Because it is built
|
|
1016
|
+
* from `when()`, SSR renders whichever branch matches the resource's current
|
|
1017
|
+
* (peeked) state — so a server that awaits the resource before serializing
|
|
1018
|
+
* emits the resolved `success` branch, and hydration (seeded via the
|
|
1019
|
+
* resource's `initialData`) reuses it with no duplicate work. Resource
|
|
1020
|
+
* cleanup/cancellation is the resource's own concern (pass its `dispose` to
|
|
1021
|
+
* the owning scope's `onCleanup`, e.g. a component's `ctx.onCleanup`).
|
|
1022
|
+
*/
|
|
1023
|
+
asyncBoundary<T>(key: string, resource: Resource<T>, branches: AsyncBoundaryBranches<T>): void;
|
|
649
1024
|
/**
|
|
650
1025
|
* Render `builder`'s subtree into `document.body` instead of inline at this
|
|
651
1026
|
* position (a neutral inline anchor is left behind). On the server there is no
|
|
@@ -694,6 +1069,18 @@ interface ContainerDSL extends ContentDSL {
|
|
|
694
1069
|
* `ctx.renderChildren` (§6 native child composition).
|
|
695
1070
|
*/
|
|
696
1071
|
component<P>(key: string, def: ComponentDefinition<P>, props: P, children?: ContainerBuilder): void;
|
|
1072
|
+
/**
|
|
1073
|
+
* Declare document metadata (§1–§3): title, meta, link, canonical, Open Graph,
|
|
1074
|
+
* Twitter/X, robots, theme-color, favicon. Renders nothing visible at this
|
|
1075
|
+
* position (a neutral empty anchor); the framework applies the metadata to
|
|
1076
|
+
* `document.head` on the browser and emits it via `renderHead()` on the
|
|
1077
|
+
* server. Several `head()` calls compose — an app-level default, a route-level
|
|
1078
|
+
* `head()`, and a component-level `head()` are merged and, per metadata key,
|
|
1079
|
+
* the last declared (deepest/latest in document order) wins. Removing a
|
|
1080
|
+
* `head()` node (route change / component unmount) re-exposes the previously
|
|
1081
|
+
* shadowed value, and server tags are adopted on hydration without duplication.
|
|
1082
|
+
*/
|
|
1083
|
+
head(metadata: HeadMetadata): void;
|
|
697
1084
|
}
|
|
698
1085
|
interface SectionDSL extends ContainerDSL {
|
|
699
1086
|
}
|
|
@@ -753,9 +1140,25 @@ declare class ContainerBuilderBase extends ContentBuilderBase implements Contain
|
|
|
753
1140
|
list(key: string, builder: ListBuilder, options?: ListOptions): void;
|
|
754
1141
|
listOf<T>(key: string, items: Signal<T[]> | ReadonlySignal<T[]>, renderItem: (item: T, index: number, content: ContentDSL) => void, options?: ListOptions): void;
|
|
755
1142
|
form(key: string, builder: FormBuilder, options?: FormOptions): void;
|
|
756
|
-
when(condition: Bindable<boolean>, builder: ContainerBuilder, elseBuilder?: ContainerBuilder): void;
|
|
1143
|
+
when(condition: Bindable<boolean>, builder: ContainerBuilder, elseBuilder?: ContainerBuilder, options?: WhenOptions): void;
|
|
757
1144
|
errorBoundary(id: string, builder: ContainerBuilder, options: ErrorBoundaryOptions): void;
|
|
1145
|
+
asyncBoundary<T>(key: string, res: Resource<T>, branches: AsyncBoundaryBranches<T>): void;
|
|
758
1146
|
portal(key: string, builder: ContainerBuilder, options?: PortalOptions): void;
|
|
1147
|
+
/**
|
|
1148
|
+
* Declare document metadata (2.0 §1–§3). Creates a `'head'` node — a neutral,
|
|
1149
|
+
* empty inline anchor at this position (one node / one element, so positional
|
|
1150
|
+
* hydration is preserved) — and registers a `__head__<id>` descriptor holding
|
|
1151
|
+
* this call's normalized, dedup-keyed {@link resolveHead} contribution. The
|
|
1152
|
+
* renderer applies it to `document.head` on the browser (adopting server tags
|
|
1153
|
+
* on hydration, cleaning up on unmount / route change) and emits the active
|
|
1154
|
+
* graph's merged metadata as a string on the server (`renderHead`).
|
|
1155
|
+
*
|
|
1156
|
+
* Multiple `head()` nodes may be live at once (app default + route + component)
|
|
1157
|
+
* — the renderer merges them and, per dedup key, the last in document order
|
|
1158
|
+
* wins (see head.ts). No new render path: this reuses the same graph-node +
|
|
1159
|
+
* handler-registry convention as overlays/transitions/components.
|
|
1160
|
+
*/
|
|
1161
|
+
head(metadata: HeadMetadata): void;
|
|
759
1162
|
/**
|
|
760
1163
|
* Shared assembly for every overlay kind: a `portal` node whose single child
|
|
761
1164
|
* is a `when(open, panel)` conditional. The panel container carries the
|
|
@@ -880,4 +1283,67 @@ declare function compile(app: StreetApp, options?: CompileOptions): CompiledAppl
|
|
|
880
1283
|
*/
|
|
881
1284
|
declare function compileGraph(graph: ApplicationGraph, options?: CompileOptions): CompiledApplication;
|
|
882
1285
|
|
|
883
|
-
|
|
1286
|
+
/**
|
|
1287
|
+
* Hydration diagnostics — dev-only, opt-in explanations of hydration mismatches.
|
|
1288
|
+
*
|
|
1289
|
+
* Hydration is self-repairing: when the server-rendered DOM does not match the
|
|
1290
|
+
* graph at a position, the renderer mounts a fresh subtree in place and drops
|
|
1291
|
+
* the offending element (see `hydrateChildren` in `hydrate.ts`). That recovery
|
|
1292
|
+
* is silent by design — a local mismatch must never tear down the whole app.
|
|
1293
|
+
*
|
|
1294
|
+
* During development, though, a silent repair hides a real problem (usually a
|
|
1295
|
+
* server/client divergence). A `HydrationDiagnosticSink` can be attached to the
|
|
1296
|
+
* renderer to *observe* those repairs without changing them: for every mismatch
|
|
1297
|
+
* the renderer reports what it expected, what it found, where, and what it did
|
|
1298
|
+
* to recover. Nothing is thrown, nothing is mutated differently, and when no
|
|
1299
|
+
* sink is attached there is zero additional work on the hydration path.
|
|
1300
|
+
*/
|
|
1301
|
+
/** What kind of divergence the hydrator encountered at a position. */
|
|
1302
|
+
type HydrationMismatchType = 'tag-mismatch' | 'missing-element' | 'surplus-element';
|
|
1303
|
+
/** A single, fully-described hydration divergence and the repair taken. */
|
|
1304
|
+
interface HydrationDiagnostic {
|
|
1305
|
+
/** The category of mismatch. */
|
|
1306
|
+
readonly type: HydrationMismatchType;
|
|
1307
|
+
/** The tag the graph expected at this position (null for a surplus element). */
|
|
1308
|
+
readonly expected: string | null;
|
|
1309
|
+
/** The tag actually found in the server DOM (null for a missing element). */
|
|
1310
|
+
readonly found: string | null;
|
|
1311
|
+
/** A human-readable path to the position, e.g. `app / page[0] / section[1]`. */
|
|
1312
|
+
readonly path: string;
|
|
1313
|
+
/** The graph node id involved, when one exists (null for surplus DOM). */
|
|
1314
|
+
readonly nodeId: string | null;
|
|
1315
|
+
/** The semantic node type involved, when one exists (null for surplus DOM). */
|
|
1316
|
+
readonly nodeType: string | null;
|
|
1317
|
+
/** The recovery action the renderer performed. */
|
|
1318
|
+
readonly action: string;
|
|
1319
|
+
/** A single-line, developer-facing summary of the whole diagnostic. */
|
|
1320
|
+
readonly message: string;
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* Receives hydration diagnostics as they are discovered. Kept intentionally
|
|
1324
|
+
* tiny so any logger — `console`, a test collector, a `DiagnosticSink` — can
|
|
1325
|
+
* satisfy it. Implementations must not throw.
|
|
1326
|
+
*/
|
|
1327
|
+
interface HydrationDiagnosticSink {
|
|
1328
|
+
report(diagnostic: HydrationDiagnostic): void;
|
|
1329
|
+
}
|
|
1330
|
+
/** Build the canonical one-line message for a diagnostic. */
|
|
1331
|
+
declare function formatHydrationDiagnostic(d: Omit<HydrationDiagnostic, 'message'>): string;
|
|
1332
|
+
/**
|
|
1333
|
+
* A ready-made sink that accumulates diagnostics into an array — the shape most
|
|
1334
|
+
* useful for tests and for a DevTools panel. The returned `diagnostics` array is
|
|
1335
|
+
* appended to in-place as repairs happen.
|
|
1336
|
+
*/
|
|
1337
|
+
declare function createHydrationDiagnosticCollector(): {
|
|
1338
|
+
readonly sink: HydrationDiagnosticSink;
|
|
1339
|
+
readonly diagnostics: HydrationDiagnostic[];
|
|
1340
|
+
};
|
|
1341
|
+
/**
|
|
1342
|
+
* A sink that forwards each diagnostic to a `console`-like logger as a single
|
|
1343
|
+
* warning line. Handy default when you just want the messages surfaced in dev.
|
|
1344
|
+
*/
|
|
1345
|
+
declare function consoleHydrationDiagnosticSink(logger?: {
|
|
1346
|
+
warn(message: string): void;
|
|
1347
|
+
}): HydrationDiagnosticSink;
|
|
1348
|
+
|
|
1349
|
+
export { type FormBuilder as $, type ApplicationId as A, BaseNode as B, type CompiledApplication as C, DiagnosticCollector as D, type ComponentRender as E, type ComponentSetup as F, GraphNode as G, type HydrationDiagnostic as H, ContainerBuilderImpl as I, type ContainerOptions as J, type ContentDSL as K, type ControlledInputOptions as L, DerivedSignal as M, type Diagnostic as N, DiagnosticError as O, type PageDSL as P, type DiagnosticLocation as Q, type ReadonlySignal as R, StreetApp as S, type TransitionConfig as T, type Unsubscribe as U, VERSION as V, type DiagnosticSeverity as W, type ErrorBoundaryOptions as X, type ErrorFallbackBuilder as Y, type ErrorSource as Z, type EventDescriptor as _, type ComponentDefinition as a, observerCount as a$, FormBuilderImpl as a0, type FormDSL as a1, type FormOptions as a2, type GraphNodeData as a3, type HandlerFn as a4, type HeadContribution as a5, type HeadEntry as a6, type HeadMetadata as a7, type HeadingOptions as a8, type HydrationMismatchType as a9, type SectionOptions as aA, type SerializedGraph as aB, type SerializedNode as aC, type StateRef as aD, type StreetUI as aE, type TextOptions as aF, type TextValue as aG, type WhenOptions as aH, batch as aI, compile as aJ, compileGraph as aK, component as aL, consoleHydrationDiagnosticSink as aM, createHydrationDiagnosticCollector as aN, createNodeId as aO, derived as aP, effect as aQ, formatDiagnostic as aR, formatHydrationDiagnostic as aS, generateApplicationId as aT, generateNodeId as aU, isBatching as aV, isComponentDefinition as aW, isHeadContribution as aX, isTransitionConfig as aY, nextId as aZ, nodeIdPrefix as a_, type ImageOptions as aa, type InputOptions as ab, type InputOptionsBase as ac, type LinkDescriptor as ad, type LinkOptions as ae, type ListBuilder as af, ListBuilderImpl as ag, type ListDSL as ah, type ListOptions as ai, type ListPlanEntry as aj, type MetaDescriptor as ak, type NodeId as al, type NodeMetadata as am, type OverlayOptions as an, type PageBuilder as ao, PageBuilderImpl as ap, type PortalOptions as aq, type PropValue as ar, type Props as as, type ReactiveConsumer as at, type ReactiveSource as au, type ResolvedTransition as av, type ResourceLoader as aw, type SectionBuilder as ax, SectionBuilderImpl as ay, type SectionDSL as az, type ContainerBuilder as b, reactiveListItemKey as b0, reactiveListItemSignature as b1, resetIdCounter as b2, resolveHead as b3, resolveTransition as b4, resource as b5, signal as b6, signalKind as b7, streetui as b8, Signal as c, type Subscriber as d, type ResourceStatus as e, type ResourceOptions as f, type Resource as g, type ResourceLoaderContext as h, ApplicationGraph as i, type HydrationDiagnosticSink as j, type SemanticNodeType as k, type ContainerDSL as l, type SignalKind as m, type A11yOptions as n, AppBuilder as o, type AppDSL as p, type AppOptions as q, type ApplicationGraphOptions as r, type AsyncBoundaryBranches as s, type Bindable as t, type BindableString as u, type BindableText as v, type BoundInputOptions as w, type ButtonOptions as x, type CompileOptions as y, type ComponentContext as z };
|