Skip to content

finding(types): ToastSchema and the toast renderer disagree in BOTH directions — two keys read but undeclared, two declared but unread #6496

Description

@os-support-ai

Found while implementing objectui#6250, and it constrained that PR's answer — recording it rather than resolving it there, because both halves are declaration-side calls.

Measured on 7975f2d85, packages/types built fresh

Direction 1 — read by the renderer, declared by no type

packages/components/src/renderers/feedback/toast.tsx:

<ButtononClick={showToast}variant={schema.buttonVariant}className={schema.className}> // :30
{schema.buttonLabel||'Show Toast'} // :31

ToastSchema (packages/types/src/feedback.ts:115, mirror packages/types/src/zod/feedback.zod.ts:61) declares type, title, description, variant, duration, position, action, onDismiss. Neither buttonLabel nor buttonVariant.

The registry metadata in the same renderer file declares buttonLabel as an authoring input (:49, defaultValue: 'Show Toast') — so the designer offers a control for a key the shipped type does not have — and declares no buttonVariant input at all, so that one is read by the renderer and named by nothing.

SonnerSchema declares both (feedback.ts:204ff: buttonLabel?: string, buttonVariant?: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'). The two sibling components have the same trigger-button mechanism and only one of them declares it.

Direction 2 — declared by the type, read by no renderer

ToastSchema declares:

action?: { label: string; onClick: ()=>void};// feedback.ts:143
onDismiss?: ()=>void;// feedback.ts:150

renderers/feedback/toast.tsx reads neither. Its whole body is toastFn(title, { description, duration }) plus the trigger <Button>, so there is no in-toast action button and no dismiss callback on this tree. The zod mirror widens action further (z.union([SchemaNodeSchema, z.array(SchemaNodeSchema)])), and onDismiss is a z.function() — one of the mirror keys objectui#6124 measures as unsatisfiable by any JSON document.

Why this is being filed rather than fixed

objectui#6250's charter is "docs teach only what runs", and it hit both halves at once:

  • Direction 2 meant its "With Action" and "With Undo Action" demos had no working spelling — the toast renderer cannot draw an in-toast action button — so those demos were re-pointed at the info and warning variants instead. sonner's "Promise Toast" demo went the same way, for the same reason.
  • Direction 1 meant the corrected toast demos could not author a per-demo trigger label the way the corrected sonner demos can, so all seven now render the default Show Toast button. Teaching buttonLabel would have re-introduced an undeclared key into the very fixtures that card was cleaning; objectui#6161 already set the posture here — "a key a renderer genuinely reads would have been routed out as an undeclared capability rather than deleted".

This is that routing-out.

The two resolutions are opposite in kind

  • Direction 1 is declare what already runs: add buttonLabel / buttonVariant to ToastSchema and its mirror, matching SonnerSchema limb for limb. Cheap, and it makes the seven toast demos expressible.
  • Direction 2 is enforce or remove (ADR-0049 shape): either the renderer grows an action button and a dismiss callback — a capability expansion with zero runtime today, so implementation-first posture applies — or action / onDismiss are retired from ToastSchema.

Unassigned; no grading — triage's call, and the second half may belong with the objectui#6182 / objectui#6124 handler-dialect family.

Refs: objectui#6250 · objectui#6124 · objectui#6161 · objectui#6157 · objectui#5250.

Filed by the objectui#6250 execution seat, session session_011SfZeFWrhGLHmfq61xbz4q.


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions