@moku-labs/web 1.15.1 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.mts +222 -26
- package/dist/browser.mjs +452 -84
- package/dist/index.cjs +452 -84
- package/dist/index.d.cts +222 -26
- package/dist/index.d.mts +222 -26
- package/dist/index.mjs +452 -84
- package/dist/{render-DLZEOe4M.cjs → render-KdufA3_b.cjs} +23 -0
- package/dist/{render-BNe0s7fr.mjs → render-UO4nimWr.mjs} +23 -1
- package/dist/testing.d.mts +389 -0
- package/dist/testing.mjs +854 -0
- package/package.json +7 -1
package/dist/index.d.mts
CHANGED
|
@@ -870,7 +870,7 @@ type Api$4 = {
|
|
|
870
870
|
composeTitle(head: HeadConfig | undefined): string;
|
|
871
871
|
};
|
|
872
872
|
declare namespace types_d_exports$7 {
|
|
873
|
-
export { COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentHooks, ComponentInstance, ExtractApi$1 as ExtractApi, PageData, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
|
|
873
|
+
export { AnyVNode, COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentEventHandler, ComponentEvents, ComponentHooks, ComponentInstance, ComponentRender, ComponentRouteSlice, ComponentSpec, ComponentSpecExtras, ComponentStateFactory, ExtractApi$1 as ExtractApi, PageData, RenderResult, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
|
|
874
874
|
}
|
|
875
875
|
/** Payload map for the events `spa` emits, used to type the kernel's `emit` closure. */
|
|
876
876
|
type SpaEvents = {
|
|
@@ -971,12 +971,83 @@ interface ResolvedSpaConfig {
|
|
|
971
971
|
components: ComponentDef[];
|
|
972
972
|
}
|
|
973
973
|
/**
|
|
974
|
-
*
|
|
975
|
-
*
|
|
976
|
-
*
|
|
977
|
-
*
|
|
974
|
+
* What a component's `render` may return:
|
|
975
|
+
* - a Preact `VNode` — committed into the host through the lazy Preact gate (`commitVNode`);
|
|
976
|
+
* - a `Node` — replaces the host's children;
|
|
977
|
+
* - a `string` — set as the host's `innerHTML`;
|
|
978
|
+
* - `void`/`undefined` — the render mutated the DOM itself (DOM-only islands → no Preact loaded).
|
|
978
979
|
*/
|
|
979
|
-
|
|
980
|
+
type RenderResult = AnyVNode | Node | string | void;
|
|
981
|
+
/**
|
|
982
|
+
* A Preact `VNode` of ANY props shape. A render returns `h(Component, props)`, i.e. a
|
|
983
|
+
* `VNode<SomeProps>`; the props generic is invariant under `exactOptionalPropertyTypes`,
|
|
984
|
+
* so the only supertype that accepts every concrete `VNode<P>` is `VNode<any>`.
|
|
985
|
+
*/
|
|
986
|
+
type AnyVNode = import("preact").VNode<any>;
|
|
987
|
+
/**
|
|
988
|
+
* Factory that builds a component's typed per-instance state (mirrors a plugin's
|
|
989
|
+
* `createState`). Called ONCE at mount; the returned object is stored on the
|
|
990
|
+
* {@link ComponentInstance} and exposed read-only as `ctx.state`.
|
|
991
|
+
*
|
|
992
|
+
* @param ctx - The component context for this instance (state is not yet set).
|
|
993
|
+
* @returns The initial per-instance state.
|
|
994
|
+
* @example
|
|
995
|
+
* state: (ctx): BoardState => ({ boardId: ctx.params.id ?? "", cards: [] })
|
|
996
|
+
*/
|
|
997
|
+
type ComponentStateFactory<S extends object> = (ctx: ComponentContext<S>) => S;
|
|
998
|
+
/**
|
|
999
|
+
* Pure render of `(state, ctx)` → {@link RenderResult}. Called after mount-state-init
|
|
1000
|
+
* and again (microtask-batched) after every `ctx.set`. Must be free of side effects
|
|
1001
|
+
* beyond producing its result.
|
|
1002
|
+
*
|
|
1003
|
+
* @param state - The current per-instance state (read-only).
|
|
1004
|
+
* @param ctx - The component context for this instance.
|
|
1005
|
+
* @returns The render result to commit into the host.
|
|
1006
|
+
* @example
|
|
1007
|
+
* render: (state) => h(BoardView, { snapshot: state.snapshot })
|
|
1008
|
+
*/
|
|
1009
|
+
type ComponentRender<S extends object> = (state: Readonly<S>, ctx: ComponentContext<S>) => RenderResult;
|
|
1010
|
+
/**
|
|
1011
|
+
* A delegated DOM event handler. `target` is the element matched by the key's selector
|
|
1012
|
+
* (already resolved via `closest` — no `instanceof`/`closest` ceremony in the body).
|
|
1013
|
+
*
|
|
1014
|
+
* Typed `void` for ergonomics (the void-return rule accepts async handlers returning
|
|
1015
|
+
* `Promise<void>` too); the kernel ignores any returned value.
|
|
1016
|
+
*
|
|
1017
|
+
* @param ctx - The component context (carries the live per-instance `state`).
|
|
1018
|
+
* @param event - The raw DOM event.
|
|
1019
|
+
* @param target - The element matched by the selector (the host when no selector).
|
|
1020
|
+
* @returns void (a returned promise is ignored by the kernel).
|
|
1021
|
+
* @example
|
|
1022
|
+
* (ctx, event, button) => { event.preventDefault(); ctx.set({ open: true }); }
|
|
1023
|
+
*/
|
|
1024
|
+
type ComponentEventHandler<S extends object> = (ctx: ComponentContext<S>, event: Event, target: Element) => void;
|
|
1025
|
+
/**
|
|
1026
|
+
* Declarative delegated event map. Each key is `"<type> <selector>"` (the selector is
|
|
1027
|
+
* optional → a host-level listener). ONE real listener per event TYPE is attached to
|
|
1028
|
+
* the host; dispatch walks `event.target.closest(selector)` within the host. All
|
|
1029
|
+
* listeners are auto-removed on destroy.
|
|
1030
|
+
*
|
|
1031
|
+
* @example
|
|
1032
|
+
* events: {
|
|
1033
|
+
* "click [data-action='delete']": (ctx, _e, btn) => ctx.set(removeCard(ctx.state, btn)),
|
|
1034
|
+
* "submit [data-add]": (ctx, e) => { e.preventDefault(); add(ctx); }
|
|
1035
|
+
* }
|
|
1036
|
+
*/
|
|
1037
|
+
type ComponentEvents<S extends object> = Record<string, ComponentEventHandler<S>>;
|
|
1038
|
+
/**
|
|
1039
|
+
* Context handed to every component lifecycle hook, render, and event handler — the
|
|
1040
|
+
* bound element + page data, plus the matched route's `params`/`meta`/`locale` and a
|
|
1041
|
+
* link builder, so an island can read its route context (e.g. a `card` route's
|
|
1042
|
+
* `ctx.meta.focus` + `ctx.params.id`) directly, without the page bridging it through
|
|
1043
|
+
* `data-*` attributes.
|
|
1044
|
+
*
|
|
1045
|
+
* Generic over the per-instance state `S` (default `undefined` so every existing
|
|
1046
|
+
* hooks-only island still type-checks). The additive members (`state`/`set`/`flush`/
|
|
1047
|
+
* `cleanup`/`component`) are ALWAYS-PRESENT functions — never optional keys — so they
|
|
1048
|
+
* never trip `exactOptionalPropertyTypes`.
|
|
1049
|
+
*/
|
|
1050
|
+
interface ComponentContext<S = undefined> {
|
|
980
1051
|
/** The element the component instance is bound to. */
|
|
981
1052
|
el: Element;
|
|
982
1053
|
/** Page data extracted from the `script#__DATA__` payload. */
|
|
@@ -989,9 +1060,52 @@ interface ComponentContext {
|
|
|
989
1060
|
readonly locale: string;
|
|
990
1061
|
/** Build a link to a named route by pattern substitution (same output as `app.router.toUrl`). */
|
|
991
1062
|
readonly url: (name: string, params?: Record<string, string>) => string;
|
|
1063
|
+
/** The live per-instance state (the object returned by `spec.state`). `undefined` for legacy hooks-only islands. */
|
|
1064
|
+
readonly state: S;
|
|
1065
|
+
/**
|
|
1066
|
+
* Merge a patch into the per-instance state, then schedule ONE batched render.
|
|
1067
|
+
* Accepts a partial object or an updater `(prev) => partial`. A no-op for legacy
|
|
1068
|
+
* islands with no `state`/`render`.
|
|
1069
|
+
*
|
|
1070
|
+
* @param patch - A partial state object, or an updater returning one.
|
|
1071
|
+
* @returns void
|
|
1072
|
+
* @example
|
|
1073
|
+
* ctx.set({ open: true });
|
|
1074
|
+
* ctx.set(prev => ({ count: prev.count + 1 }));
|
|
1075
|
+
*/
|
|
1076
|
+
set(patch: Partial<S> | ((prev: Readonly<S>) => Partial<S>)): void;
|
|
1077
|
+
/**
|
|
1078
|
+
* Force a synchronous render now (drains any pending scheduled render). Rarely
|
|
1079
|
+
* needed in app code — `ctx.set` already schedules one; mainly a test seam.
|
|
1080
|
+
*
|
|
1081
|
+
* @returns void
|
|
1082
|
+
* @example
|
|
1083
|
+
* ctx.flush();
|
|
1084
|
+
*/
|
|
1085
|
+
flush(): void;
|
|
1086
|
+
/**
|
|
1087
|
+
* Register a disposer run on `onDestroy` (subscriptions, timers, manual/global
|
|
1088
|
+
* listeners the declarative `events` map cannot cover). Disposers run LIFO.
|
|
1089
|
+
*
|
|
1090
|
+
* @param dispose - The teardown function.
|
|
1091
|
+
* @returns void
|
|
1092
|
+
* @example
|
|
1093
|
+
* ctx.cleanup(onPatch(p => applyPatch(ctx, p)));
|
|
1094
|
+
*/
|
|
1095
|
+
cleanup(dispose: () => void): void;
|
|
1096
|
+
/**
|
|
1097
|
+
* Resolve another island's registered `api` by name. Returns `undefined` when no
|
|
1098
|
+
* provider is registered (optional-dependency semantics, mirroring `ctx.has`).
|
|
1099
|
+
*
|
|
1100
|
+
* @param name - The provider island's component name.
|
|
1101
|
+
* @returns The provider's api, or `undefined`.
|
|
1102
|
+
* @example
|
|
1103
|
+
* ctx.component<LightboxApi>("lightbox")?.open(slides, index);
|
|
1104
|
+
*/
|
|
1105
|
+
component<T = unknown>(name: string): T | undefined;
|
|
992
1106
|
}
|
|
993
|
-
/** Lifecycle hooks a component may implement. */
|
|
994
|
-
interface ComponentHooks {
|
|
1107
|
+
/** Lifecycle hooks a component may implement. Generic over the per-instance state `S`. */
|
|
1108
|
+
interface ComponentHooks<S = undefined> {
|
|
995
1109
|
/**
|
|
996
1110
|
* Called once when the instance is created (before DOM attach).
|
|
997
1111
|
*
|
|
@@ -1000,7 +1114,7 @@ interface ComponentHooks {
|
|
|
1000
1114
|
* @example
|
|
1001
1115
|
* onCreate({ el }) { el.dataset.ready = "1"; }
|
|
1002
1116
|
*/
|
|
1003
|
-
onCreate?(ctx: ComponentContext): void;
|
|
1117
|
+
onCreate?(ctx: ComponentContext<S>): void;
|
|
1004
1118
|
/**
|
|
1005
1119
|
* Called after the instance is attached to its element.
|
|
1006
1120
|
*
|
|
@@ -1008,8 +1122,10 @@ interface ComponentHooks {
|
|
|
1008
1122
|
* @returns void
|
|
1009
1123
|
* @example
|
|
1010
1124
|
* onMount({ el }) { el.textContent = "0"; }
|
|
1125
|
+
* @example
|
|
1126
|
+
* async onMount(ctx) { ctx.set({ items: await load() }); } // async is allowed; the harness awaits it via settle()
|
|
1011
1127
|
*/
|
|
1012
|
-
onMount?(ctx: ComponentContext): void;
|
|
1128
|
+
onMount?(ctx: ComponentContext<S>): void;
|
|
1013
1129
|
/**
|
|
1014
1130
|
* Called when a navigation begins while this instance is mounted.
|
|
1015
1131
|
*
|
|
@@ -1018,7 +1134,7 @@ interface ComponentHooks {
|
|
|
1018
1134
|
* @example
|
|
1019
1135
|
* onNavStart({ el }) { el.dataset.loading = ""; }
|
|
1020
1136
|
*/
|
|
1021
|
-
onNavStart?(ctx: ComponentContext): void;
|
|
1137
|
+
onNavStart?(ctx: ComponentContext<S>): void;
|
|
1022
1138
|
/**
|
|
1023
1139
|
* Called when a navigation completes while this instance is mounted.
|
|
1024
1140
|
*
|
|
@@ -1027,7 +1143,7 @@ interface ComponentHooks {
|
|
|
1027
1143
|
* @example
|
|
1028
1144
|
* onNavEnd({ el }) { delete el.dataset.loading; }
|
|
1029
1145
|
*/
|
|
1030
|
-
onNavEnd?(ctx: ComponentContext): void;
|
|
1146
|
+
onNavEnd?(ctx: ComponentContext<S>): void;
|
|
1031
1147
|
/**
|
|
1032
1148
|
* Called before the instance is detached from its element.
|
|
1033
1149
|
*
|
|
@@ -1036,7 +1152,7 @@ interface ComponentHooks {
|
|
|
1036
1152
|
* @example
|
|
1037
1153
|
* onUnMount({ el }) { el.replaceChildren(); }
|
|
1038
1154
|
*/
|
|
1039
|
-
onUnMount?(ctx: ComponentContext): void;
|
|
1155
|
+
onUnMount?(ctx: ComponentContext<S>): void;
|
|
1040
1156
|
/**
|
|
1041
1157
|
* Called once when the instance is destroyed (after detach).
|
|
1042
1158
|
*
|
|
@@ -1045,17 +1161,60 @@ interface ComponentHooks {
|
|
|
1045
1161
|
* @example
|
|
1046
1162
|
* onDestroy({ el }) { delete el.dataset.ready; }
|
|
1047
1163
|
*/
|
|
1048
|
-
onDestroy?(ctx: ComponentContext): void;
|
|
1164
|
+
onDestroy?(ctx: ComponentContext<S>): void;
|
|
1049
1165
|
}
|
|
1050
1166
|
/** Allowed hook names — single source of truth for fail-fast validation. */
|
|
1051
1167
|
declare const COMPONENT_HOOK_NAMES: readonly ["onCreate", "onMount", "onNavStart", "onNavEnd", "onUnMount", "onDestroy"];
|
|
1052
|
-
/**
|
|
1168
|
+
/**
|
|
1169
|
+
* The plugin-mirror authoring form for {@link createComponent}: typed per-instance
|
|
1170
|
+
* `state`, `render`, declarative `events`, and a cross-island `api` on top of the
|
|
1171
|
+
* lifecycle hooks. All keys optional + additive; the presence of any spec-only key
|
|
1172
|
+
* (`state`/`render`/`events`/`api`) selects the spec overload of `createComponent`.
|
|
1173
|
+
*
|
|
1174
|
+
* @example
|
|
1175
|
+
* createComponent<{ boards: Board[] }>("board-list", {
|
|
1176
|
+
* state: () => ({ boards: [] }),
|
|
1177
|
+
* async onMount(ctx) { ctx.set({ boards: await ctx.component<Api>("api")!.list() }); },
|
|
1178
|
+
* render: (s) => h(BoardList, { boards: s.boards }),
|
|
1179
|
+
* events: { "submit [data-create]": (ctx, e) => { e.preventDefault(); create(ctx); } }
|
|
1180
|
+
* });
|
|
1181
|
+
*/
|
|
1182
|
+
interface ComponentSpec<S extends object = object, A = unknown> extends ComponentHooks<S> {
|
|
1183
|
+
/** Build typed per-instance state at mount (stored on the instance, not a module WeakMap). */
|
|
1184
|
+
state?: ComponentStateFactory<S>;
|
|
1185
|
+
/** Pure render re-invoked (microtask-batched) on every `ctx.set`. */
|
|
1186
|
+
render?: ComponentRender<S>;
|
|
1187
|
+
/** Declarative delegated DOM events with auto-teardown. */
|
|
1188
|
+
events?: ComponentEvents<S>;
|
|
1189
|
+
/** Public api factory — registered under the component name; reached via `app.spa.component(name)`. */
|
|
1190
|
+
api?: (ctx: ComponentContext<S>) => A;
|
|
1191
|
+
}
|
|
1192
|
+
/**
|
|
1193
|
+
* The spec extras carried on a {@link ComponentDef}, type-erased to `object` state
|
|
1194
|
+
* (authors keep full `S` inference at the `createComponent` call site; the registry
|
|
1195
|
+
* stores the runtime-only erased form). Absent for legacy `(name, hooks)` defs.
|
|
1196
|
+
*/
|
|
1197
|
+
interface ComponentSpecExtras {
|
|
1198
|
+
/** Per-instance state factory. */
|
|
1199
|
+
state?: ComponentStateFactory<object>;
|
|
1200
|
+
/** Render called on mount + after every `ctx.set`. */
|
|
1201
|
+
render?: ComponentRender<object>;
|
|
1202
|
+
/** Declarative delegated events. */
|
|
1203
|
+
events?: ComponentEvents<object>;
|
|
1204
|
+
/** Public api factory registered under the component name. */
|
|
1205
|
+
api?: (ctx: ComponentContext<object>) => unknown;
|
|
1206
|
+
}
|
|
1207
|
+
/** A registered component definition (an opaque token; author inference lives on `createComponent`). */
|
|
1053
1208
|
interface ComponentDef {
|
|
1054
1209
|
/** Unique component name (matched against `data-component`). */
|
|
1055
1210
|
name: string;
|
|
1056
|
-
/** Lifecycle hooks. */
|
|
1057
|
-
hooks: ComponentHooks
|
|
1211
|
+
/** Lifecycle hooks (the subset shared with the legacy form). */
|
|
1212
|
+
hooks: ComponentHooks<object>;
|
|
1213
|
+
/** Plugin-mirror extras (state/render/events/api). Absent for legacy `(name, hooks)` defs. */
|
|
1214
|
+
spec?: ComponentSpecExtras;
|
|
1058
1215
|
}
|
|
1216
|
+
/** The matched-route slice carried on a live instance (params/meta/locale + link builder). */
|
|
1217
|
+
type ComponentRouteSlice = Pick<ComponentContext, "params" | "meta" | "locale" | "url">;
|
|
1059
1218
|
/** A live, mounted component instance. */
|
|
1060
1219
|
interface ComponentInstance {
|
|
1061
1220
|
/** The definition this instance was created from. */
|
|
@@ -1068,6 +1227,26 @@ interface ComponentInstance {
|
|
|
1068
1227
|
* page-specific: full unmount/destroy on every navigation.
|
|
1069
1228
|
*/
|
|
1070
1229
|
persistent: boolean;
|
|
1230
|
+
/** The single per-instance context reused by every hook, event handler, and render. */
|
|
1231
|
+
ctx: ComponentContext<object>;
|
|
1232
|
+
/** Live per-instance state (the object returned by `spec.state`), or undefined for hooks-only islands. */
|
|
1233
|
+
state: object | undefined;
|
|
1234
|
+
/** This instance's public api (the object returned by `spec.api`), or undefined when none declared. */
|
|
1235
|
+
api: unknown;
|
|
1236
|
+
/** Current matched-route slice (updated on navigation; read by `ctx.params/meta/locale/url`). */
|
|
1237
|
+
route: ComponentRouteSlice;
|
|
1238
|
+
/** Current page data payload (updated on navigation; read by `ctx.data`). */
|
|
1239
|
+
data: PageData;
|
|
1240
|
+
/** Disposers from `ctx.cleanup` + the declarative `events` listeners — run LIFO on destroy. */
|
|
1241
|
+
cleanups: Array<() => void>;
|
|
1242
|
+
/** Synchronously drain a pending render (the `ctx.flush` implementation). */
|
|
1243
|
+
flush: () => void;
|
|
1244
|
+
/** True while a render is queued for the next microtask — coalesces multiple `set` calls. */
|
|
1245
|
+
renderScheduled: boolean;
|
|
1246
|
+
/** Re-entrancy depth guard for the render scheduler (a render that calls `ctx.set`). */
|
|
1247
|
+
renderDepth: number;
|
|
1248
|
+
/** onMount's returned promise (+ render-module load) — awaited by the test harness's `settle()`. */
|
|
1249
|
+
mountPromise: Promise<void> | undefined;
|
|
1071
1250
|
}
|
|
1072
1251
|
/** Page data payload parsed from the inline `script#__DATA__` element. */
|
|
1073
1252
|
type PageData = Record<string, unknown>;
|
|
@@ -1151,6 +1330,8 @@ interface SpaState {
|
|
|
1151
1330
|
registeredComponents: Map<string, ComponentDef>;
|
|
1152
1331
|
/** Live component instances keyed by their bound element. */
|
|
1153
1332
|
instances: Map<Element, ComponentInstance>;
|
|
1333
|
+
/** Registered island apis by component name (the cross-island `ctx.component`/`app.spa.component` seam). */
|
|
1334
|
+
componentApis: Map<string, unknown>;
|
|
1154
1335
|
/** The current resolved URL (pathname + search). */
|
|
1155
1336
|
currentUrl: string;
|
|
1156
1337
|
/** Teardown handle for the attached router listeners (null when detached). */
|
|
@@ -1188,6 +1369,16 @@ type SpaApi = {
|
|
|
1188
1369
|
* const url = app.spa.current(); // "/about"
|
|
1189
1370
|
*/
|
|
1190
1371
|
current(): string;
|
|
1372
|
+
/**
|
|
1373
|
+
* Resolve a registered island's api by name (the cross-island seam). Returns
|
|
1374
|
+
* `undefined` when no provider with that name is currently registered.
|
|
1375
|
+
*
|
|
1376
|
+
* @param name - The provider island's component name.
|
|
1377
|
+
* @returns The provider's api, or `undefined`.
|
|
1378
|
+
* @example
|
|
1379
|
+
* app.spa.component<LightboxApi>("lightbox")?.open(slides, 0);
|
|
1380
|
+
*/
|
|
1381
|
+
component<T = unknown>(name: string): T | undefined;
|
|
1191
1382
|
};
|
|
1192
1383
|
declare namespace types_d_exports {
|
|
1193
1384
|
export { Api$3 as Api, BuildCacheEntry, BuildEvents, BuildResult, BuildRunOverrides, Config$3 as Config, ExtractApi, OgFont, OgImageConfig, PhaseContext, PhaseEmit, PhaseLog, PhaseName, PhaseRequire, RenderCacheEntry, RichOgInput, RunOptions, State$3 as State };
|
|
@@ -3313,21 +3504,26 @@ declare const sitePlugin: import("@moku-labs/core").PluginInstance<"site", Confi
|
|
|
3313
3504
|
//#endregion
|
|
3314
3505
|
//#region src/plugins/spa/components.d.ts
|
|
3315
3506
|
/**
|
|
3316
|
-
* Create a validated component definition.
|
|
3317
|
-
*
|
|
3318
|
-
*
|
|
3507
|
+
* Create a validated component definition. Accepts either the legacy hooks-only form
|
|
3508
|
+
* (`createComponent("counter", { onMount() {} })`) or the plugin-mirror spec form
|
|
3509
|
+
* (`createComponent("board", { state, render, events, api, ...hooks })`). Spec-only
|
|
3510
|
+
* keys (`state`/`render`/`events`/`api`) are partitioned out before hook-name
|
|
3511
|
+
* validation, so a real typo (e.g. `onMout`) still throws immediately while the spec
|
|
3512
|
+
* keys are accepted.
|
|
3319
3513
|
*
|
|
3320
3514
|
* @param name - Unique component name.
|
|
3321
|
-
* @param
|
|
3515
|
+
* @param spec - Lifecycle hooks, or the `{ state, render, events, api, ...hooks }` spec.
|
|
3322
3516
|
* @returns A `ComponentDef` ready to `register`.
|
|
3323
|
-
* @throws {Error} If `name` is empty,
|
|
3324
|
-
*
|
|
3517
|
+
* @throws {Error} If `name` is empty, a hook key is unknown, or an extra/hook value has the wrong shape.
|
|
3518
|
+
* @example
|
|
3519
|
+
* const counter = createComponent("counter", { onMount({ el }) { el.textContent = "0"; } });
|
|
3325
3520
|
* @example
|
|
3326
|
-
* const
|
|
3327
|
-
*
|
|
3521
|
+
* const list = createComponent<{ items: string[] }>("list", {
|
|
3522
|
+
* state: () => ({ items: [] }),
|
|
3523
|
+
* render: (s) => h(List, { items: s.items })
|
|
3328
3524
|
* });
|
|
3329
3525
|
*/
|
|
3330
|
-
declare function createComponent(name: string,
|
|
3526
|
+
declare function createComponent<S extends object = object, A = unknown>(name: string, spec: ComponentSpec<S, A>): ComponentDef;
|
|
3331
3527
|
//#endregion
|
|
3332
3528
|
//#region src/plugins/spa/lazy-embed.d.ts
|
|
3333
3529
|
/**
|