import { type VNode } from '../vdom.js'; declare const SUBMODEL_MESSAGE_BRAND = "__submodelMessage"; /** A view function branded with the Message type it dispatches. Build * one with {@link defineView}: * * ```ts * export const view = defineView( * (model) => h.button([h.OnClick(Increment())], ['+']), * ) * ``` * * When `ViewInputs` is provided, the view takes a second `viewInputs` * argument: * * ```ts * export const view = defineView< * Checkbox.Model, * Checkbox.Message, * ViewInputs * >((model, viewInputs) => viewInputs.toView({ checkbox: [...] })) * ``` * * Required at the `h.submodel` call site so unbranded plain functions * fail to type-check there. */ export type SubmodelView = (ViewInputs extends void ? (model: Model) => VNode | null : (model: Model, viewInputs: ViewInputs) => VNode | null) & { readonly [SUBMODEL_MESSAGE_BRAND]: Message; }; /** Defines the view function of a Submodel, a child component embedded * via `h.submodel`. * * Use this ONLY for views that will be embedded via `h.submodel`. Plain * view functions (page-level render functions, helper render functions * that compose Html, etc.) don't need to be defined this way. Write * them as ordinary `(model) => Html` functions. * * Explicit type arguments are required because Message has no * inferable source on the function signature itself. */ export declare const defineView: (fn: ViewInputs extends void ? (model: Model) => VNode | null : (model: Model, viewInputs: ViewInputs) => VNode | null) => SubmodelView; type AnySubmodelView = ((...args: ReadonlyArray) => VNode | null) & { readonly [SUBMODEL_MESSAGE_BRAND]: unknown; }; type ViewModelOf = Parameters[0]; type ViewInputsOf = Parameters extends [unknown, infer ViewInputs] ? ViewInputs : void; type ViewMessageOf = View extends { readonly [SUBMODEL_MESSAGE_BRAND]: infer Message; } ? Message : never; /** Configuration for embedding a child Submodel into a parent's view. * * - `slotId`: unique identifier for this Submodel instance under the * current boundary. Name the slot semantically (e.g. * `'sidebar-group'`). For lists, use a stable per-item id (typically * `entry.id`), not the array index. If the same model is rendered in * two DOM positions (desktop + mobile, master + detail), each slot * needs its own id (e.g. `'desktop-sidebar-group'`, * `'mobile-sidebar-group'`). Two `h.submodel` calls inside the same * parent boundary with the same `slotId` throw at view-build time, * including across `createLazy`/`createKeyedLazy` cache hits. * - `view`: the child's `SubmodelView`. Must be branded via * {@link defineView} so `h.submodel` can infer the child's Message * type. Unbranded plain functions fail to type-check here. * - `model`: the child's model, inferred from `view`'s first parameter. * Compared by `===` when the boundary is wrapped in a memoizing * helper such as `createKeyedLazy`. * - `viewInputs`: optional second-argument data passed to `view`, * inferred from `view`'s second parameter. Function values AT THE TOP * LEVEL of `viewInputs` (slot callbacks like `toView`) are * auto-wrapped to execute in the parent's boundary so handlers the * consumer builds inside them dispatch through the parent's wrapping * chain. Function values nested below the top level (e.g. * `viewInputs: { config: { onSubmit } }`) throw at view-build time * with a path-based error like `viewInputs.config.onSubmit`. The * check is runtime-only (TypeScript cannot distinguish a * user-declared nested callback from a data value whose prototype * carries methods), so a misuse compiles cleanly and surfaces the * first time the boundary renders. Keep slot callbacks at the top * level of `viewInputs`. * - `toParentMessage`: function that lifts a child message into the * current boundary's Message type. The argument is typed as the * child's Message via the view's brand, so destructuring is correctly * typed without annotation. For per-instance identifiers, capture * them in a closure * (`(message) => GotEntryMessage({ entryId: entry.id, message })`). * * High-level events the parent handles declaratively flow through * each Submodel's `OutMessage`. The parent's `GotChildMessage` * handler unpacks the third tuple element of the child's `update` * return and pattern-matches on `Option`. See `Menu`, * `Listbox`, etc., for examples. */ export type SubmodelConfig = Readonly<{ slotId: string; model: ViewModelOf; view: View; viewInputs?: ViewInputsOf; toParentMessage: (message: ViewMessageOf) => unknown; }>; export declare const submodel: (config: SubmodelConfig) => VNode | null; export {}; //# sourceMappingURL=submodel.d.ts.map