Mixins / foldkit-mixins

SlotView

namespace · packages/mixins/src/slotView.ts:8

export * as SlotView from './slotView.js'

SlotView is the structural equivalent of a Surface: a pure Foldkit view that publishes typed Slots and lets Mixins attach without forking it. It owns no state and runs no Effects. Attached Mixins are resolved into ordinary Foldkit attributes per slot, using the view's own h so Message capability masking is preserved.

In the guides

Members

SlotView.AssemblyRender

type · packages/mixins/src/slotView.ts:387

type AssemblyRender<Slots, Input, Message> = (
  input: Input,
  slots: SlotBuilders<Slots, Message>,
  h: HtmlBuilder<Message>,
  draw: (part: Part<Slots, Input, Message>) => Html,
) => Html

An assembly's own drawing: the parts it places, by draw, and anything else around them.

SlotView.attach

function · packages/mixins/src/slotView.ts:361

function attach(mixin: StaticMixin<never> | Mixin<never>): SlotViewTransform
function attach<MixinMessage>(
  mixin: Mixin<MixinMessage>,
): SlotViewTransformFor<MixinMessage>

Attach one Mixin. Returns a new view; the original is unchanged.

SlotView.buildersFor

function · packages/mixins/src/slotView.ts:268

function buildersFor<Slots, Message, Input>(
  slots: Slots,
  mixins: ReadonlyArray<MixinFor<Message>>,
  context: {
    readonly input: Input
    readonly h: HtmlBuilder<Message>
  },
): SlotBuilders<Slots, Message>

Build one attrs resolver per published slot, evaluating Mixins lazily.

SlotView.define

function · packages/mixins/src/slotView.ts:308

function define<Slots, Input, Message>(
  slots: Slots,
  render: SlotViewRender<Slots, Input, Message>,
  options?: {
    readonly name?: string
  },
): SlotView<Slots, Input, Message>

Defines a view over published Slots.

Message has no anchor but the render callback's builder, so it is inferred from an explicit h: HtmlBuilder<Message> annotation on that parameter. Without one it resolves to unknown, and the first error appears later and elsewhere — an invariance mismatch at Style.attach/Behavior.attach that does not name the missing annotation. forMessages<Message>() fixes the Message universe up front instead, and leaves h contextually typed.

SlotView.forMessages

function · packages/mixins/src/slotView.ts:348

function forMessages<Message>(): MessageSlotView<Message>

Binds the view constructors to one Message universe, so the render callback no longer has to annotate h to pin it. Input is still inferred from the callback's own input annotation.

Example

ts
const Field = SlotView.forMessages<Message>().define(
  FieldSlots,
  (input: FieldInput, slots, h) =>
    h.input(slots.input.attrs([h.OnInput(value => Message.ChangedValue({ value }))])),
)

SlotView.inertBuilder

function · packages/mixins/src/slotView.ts:322

function inertBuilder<Message>(): HtmlBuilder<Message>

Foldkit's inertHtml typed for a Message universe, for rendering a view outside a runtime (tests, demos, static description). inertHtml is HtmlBuilder<never>, and the builder is invariant in Message, so this is the one cast: sound outside a runtime render, where no handler is ever dispatched. Inside one it is the same builder every view is given, so its handlers would reach the frame's update: use the view's own h there.

SlotView.MessageSlotView

interface · packages/mixins/src/slotView.ts:326

interface MessageSlotView<Message> {
  readonly define: <Slots, Input>(
    slots: Slots,
    render: SlotViewRender<Slots, Input, Message>,
    options?: {
      readonly name?: string
    },
  ) => SlotView<Slots, Input, Message>
}

The SlotView constructors with Message already fixed.

SlotView.Part

interface · packages/mixins/src/slotView.ts:373

interface Part<Slots, Input, Message> {
  readonly name: string
  readonly reads: ReadonlyArray<keyof Input>
  readonly mixins: ReadonlyArray<MixinFor<Message>>
  readonly render: (
    input: any,
    slots: SlotBuilders<Slots, Message>,
    h: HtmlBuilder<Message>,
  ) => Html
}

One piece of an assembled view, drawn from its own selection of the view's input: the keys it names in reads, and nothing else. It is drawn again only when one of those values changed, by identity.

SlotView.Parts

interface · packages/mixins/src/slotView.ts:394

interface Parts<Slots, Input, Message> {
  readonly part: <const Reads extends ReadonlyArray<keyof Input>>(
    name: string,
    options: {
      readonly reads: Reads
      readonly behaviors?: ReadonlyArray<
        NamedBehavior<Slots, Pick<Input, Reads[number]>, Message>
      >
    },
    render: (
      input: Pick<Input, Reads[number]>,
      slots: SlotBuilders<Slots, Message>,
      h: HtmlBuilder<Message>,
    ) => Html,
  ) => Part<Slots, Input, Message>
  readonly assemble: (
    render: AssemblyRender<Slots, Input, Message>,
    options?: {
      readonly name?: string
    },
  ) => SlotView<Slots, Input, Message>
}

SlotView.parts

function · packages/mixins/src/slotView.ts:475

function parts<Slots>(
  slots: Slots,
): <Input, Message>() => Parts<Slots, Input, Message>

Parts over one set of Slots and one input, and the assembly that places them.

Example

ts
const Parts = SlotView.parts(PanelSlots)<PanelInput, Message>()
const Title = Parts.part('Title', { reads: ['title'] }, (input, slots, h) =>
  h.h2(slots.title.attrs(), [input.title]),
)
const Panel = Parts.assemble((input, slots, h, draw) => h.section(slots.root.attrs(), [draw(Title)]))

SlotView.SlotBuilder

type · packages/mixins/src/slotView.ts:25

type SlotBuilder<Message, Slots = unknown> = {
  readonly attrs: (
    base?: SlotAttributes<Message>,
    item?: SlotItem,
  ) => SlotAttributes<Message>
  readonly lazy: <const Args extends Readonly<Record<string, unknown>>>(
    item: SlotItem,
    draw: (
      slots: SlotBuilders<Slots, Message>,
      h: HtmlBuilder<Message>,
      args: Args,
    ) => Html,
    args: Args,
  ) => Html
}

SlotView.SlotBuilders

type · packages/mixins/src/slotView.ts:48

type SlotBuilders<Slots, Message> = {
  readonly [K in keyof Slots]: SlotBuilder<Message, Slots>
}

SlotView.SlotView

interface · packages/mixins/src/slotView.ts:58

interface SlotView<Slots, Input, Message> extends Pipeable<
  SlotView<Slots, Input, Message>
> {
  (input: Input, h: HtmlBuilder<Message>): Html
  readonly name?: string
  readonly slots: Slots
  readonly mixins: ReadonlyArray<MixinFor<Message>>
  readonly render: SlotViewRender<Slots, Input, Message>
}

SlotView.SlotViewRender

type · packages/mixins/src/slotView.ts:52

type SlotViewRender<Slots, Input, Message> = (
  input: Input,
  slots: SlotBuilders<Slots, Message>,
  h: HtmlBuilder<Message>,
) => Html

SlotView.SlotViewTransform

type · packages/mixins/src/slotView.ts:351

type SlotViewTransform = <Slots, Input, Message>(
  view: SlotView<Slots, Input, Message>,
) => SlotView<Slots, Input, Message>

A transform on any view, used by Message-free static mixins such as Style.

SlotView.SlotViewTransformFor

type · packages/mixins/src/slotView.ts:356

type SlotViewTransformFor<Message> = <Slots, Input>(
  view: SlotView<Slots, Input, Message>,
) => SlotView<Slots, Input, Message>

A transform restricted to one Message universe, for Behavior mixins.