Skip to content

docs(components): follow the shipped types on the last five action props - #6345

Draft
os-warren wants to merge 1 commit into
mainfrom
claude/issue-6132-delete-undeclared-action-props
Draft

docs(components): follow the shipped types on the last five action props#6345
os-warren wants to merge 1 commit into
mainfrom
claude/issue-6132-delete-undeclared-action-props

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes #6132

Maintainer ruling of 2026-08-25, verbatim 「6132 6166 同意」 — Option A: documentation
follows the shipped types, and where a real declared slot exists one level down, the page
points there instead of going silent.

Population — derived from the tree, not from the card

The card estimates "15 pages". My count is 5, and it governs. The 15 was the whole
objectui#6122 population (16 sites / 15 pages); 6 of those were corrected in #6130 and 5
more in #6142, leaving exactly the 5 this card rules on. Deriving command and its output:

$ grep -rn "ActionConfig" content/docs --include=*.mdx | sort
content/docs/components/basic/button-group.mdx:47:  onValueChange?: string | ActionConfig;
content/docs/components/feedback/sonner.mdx:40:    onClick: string | ActionConfig;
content/docs/components/overlay/context-menu.mdx:36:  onSelect?: string | ActionConfig;
content/docs/components/overlay/dropdown-menu.mdx:42:  onSelect?: string | ActionConfig;
content/docs/components/overlay/menubar.mdx:34:  onSelect?: string | ActionConfig;

One site per file, five files — matching the five ruled prop names exactly. Post-change the
same command returns nothing (exit 1).

The delete-versus-redirect split

Deleted — nothing declares them, at any level.

page prop shipped type
feedback/sonner.mdx action?: { label; onClick } SonnerSchema (src/feedback.ts:204) declares message/title/description/variant/buttonLabel/buttonVariant and no action; the Zod mirror (src/zod/feedback.zod.ts:116) agrees, and the renderer reads none of it
basic/button-group.mdx onValueChange ButtonGroupSchema (src/navigation.ts:335) declares only type/buttons/variant/size

On button-group I considered and rejected a redirect. ButtonGroupButton does declare
onClick?: () => void (src/navigation.ts:325), so a slot does exist one level down — but a
per-button click is not a group-level selection-change; redirecting onValueChange there
would assert an equivalence neither the types nor the ruling make. The ruling scopes the
redirect to "the menu pages" and names only MenuItem.onClick. So: deletion.

Redirected — the real slot is one level down, and it is genuinely declared.

overlay/context-menu.mdx, overlay/dropdown-menu.mdx, overlay/menubar.mdx each documented
a menu-level onSelect. No menu schema declares any event slot at all (DropdownMenuSchema
declares onOpenChange and nothing else; ContextMenuSchema and MenubarSchema declare
none). The handler is declared on the item — quoted from source, as asked:

// packages/types/src/overlay.ts:330-346
export interface MenuItem {
  label: string;
  icon?: string;
  disabled?: boolean;
  /**
   * Click handler
   */
  onClick?: () => void;          // this is line 346

Independently confirmed in three places, so this is not a redirect to a second undeclared prop:

  1. Source: packages/types/src/overlay.ts:346.
  2. Built types: packages/types/dist/overlay.d.ts:334 — the exact line the card cited.
  3. Zod mirror: packages/types/src/zod/overlay.zod.ts:136,
    onClick: z.function().optional().describe('Click handler').

MenuItem is the element type of DropdownMenuSchema.items, ContextMenuSchema.items and
MenubarMenu.items, so one declaration serves all three pages. Each page gains
onClick?: () => void on its item interface plus a two-line note that handlers live on the
item, not the menu.

Gates

Run on the final commit cb56e5ae1; HEAD was re-read after the run and had not moved. Exit
codes captured by redirect before any pipe; each line is the gate's own verdict.

gate exit verdict
check:doc-fences 0 every TypeScript block in 223 document(s) is fenced ts/tsx/typescript, except 80 declared file(s) carrying 93 block(s) of objectui#5867's remaining population
check:doc-types 0 Every documented component type is registered.
check:doc-snippets 0 Every covered documentation snippet compiles against the built types.
check:control-bytes 0 OK (scanned 5225 tracked text file(s); skipped 85 binary)
docs:check-links 0 Links are valid across 17 scan roots.
check-changeset-presence 0 No source of a released package changed in this range, so no changeset is owed.

On the flagged check:doc-snippets precondition — it did first exit 2 with
PRECONDITION NOT MET ... the packages it resolves against are not built. That is not a red,
and I did not report it as a green either: I ran the build the gate itself prescribes
(turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2,
32/32 tasks, 2m18s) and re-ran the gate, which then returned a real exit 0 with its
controls firing correctly (sentinel 1 diagnostic TS2305, positive 0 diagnostics, undeclared 1
diagnostic TS2307). So the green above is measured, not declared.

Fence-count evidence (the ratchet this diff could have moved): the five pages hold 10
plaintext fence markers before and after — delta 0
. check:doc-fences reports objectui#5867's
SHRINK-ONLY declared population unchanged at 80 files / 93 blocks. I did not convert any fence:
that is objectui#5867's scope, deliberately untouched.

Repo-wide pnpm lint — a measured narrowing, not a skip. eslint --no-inline-config --format json over all 6 changed paths exits 0 and reports, for every one of them, "File
ignored because no matching configuration was supplied."
— read from eslint's own config,
counted from its JSON output (6 files). .mdx and .changeset/*.md are outside the linted
population entirely, so this diff cannot move any verdict on any untouched file.

Changeset: the presence gate says none is owed (docs-only, no published package source).
One is added anyway as the empty-frontmatter docs-only declaration this repo uses, matching
#6142's convention. No skip-changeset label (#4912).

Coordination

  • PR docs(closure-claims): single-source the thresholds claim, bound the block-family one #6337 — no overlap. It touches content/docs/blocks/block-schema.mdx and
    content/docs/plugins/plugin-dashboard.mdx; neither is in my 5-file list, so no merge of
    main was needed and none was done.
  • objectui#5867 is not addressed here and remains open — landing this is what unblocks its
    71-file components group, which is the whole contribution. Its scope was not entered.
  • The Option-B follow-up types card was not filed: the ruling explicitly does not mandate it.
  • content/docs/releases/ untouched.

One finding this work surfaced (filed separately, not fixed here)

The redirect target is declared, but the three menu renderers read item.onSelect — a prop
MenuItem does not declare — while the declared MenuItem.onClick is read by nothing
(packages/components/src/renderers/overlay/dropdown-menu.tsx:67,
context-menu.tsx:65; menubar wires no item handler at all). Declared and enforced disagree at
the item level. That is a code-side contract question, not this card's docs question, and
fixing it here would widen into packages/. Filed as its own card, along with the remaining
undeclared props on these same pages.


Generated by Claude Code

The five `content/docs/components` pages that objectui#6122 measured as having
NO declared slot at all are corrected against the built `packages/types/dist`.
Maintainer ruled Option A on 2026-08-25: documentation follows the shipped types.

Two remedies, because the cases differ:

Deleted, nothing declares them at any level:
  * feedback/sonner.mdx     action?: { label; onClick }  -- SonnerSchema has no
    `action` (src/feedback.ts:204); the renderer reads only message/title/
    description/variant/buttonLabel/buttonVariant/className.
  * basic/button-group.mdx  onValueChange -- ButtonGroupSchema declares only
    type/buttons/variant/size (src/navigation.ts:335). `ButtonGroupButton`
    does declare `onClick`, but a per-button click is not a group-level
    selection-change, so this is a deletion and not a redirect.

Redirected, the real slot is one level down on the item:
  * overlay/context-menu.mdx, overlay/dropdown-menu.mdx, overlay/menubar.mdx
    documented a menu-level `onSelect`; no menu schema declares any event slot
    (DropdownMenuSchema declares `onOpenChange` and nothing else). `MenuItem`
    declares `onClick?: () => void` at src/overlay.ts:346, built at
    dist/overlay.d.ts:334 -- the exact line the card cited -- and mirrored in
    Zod at src/zod/overlay.zod.ts:136. `MenuItem` is the element type of all
    three `items` arrays, so one declaration serves all three pages.

The `string |` half goes with the name: objectui#4453 narrowed the runtime to
`typeof === 'function'`, so an authored string handler is dropped.

No type was minted. No fence moved: the five pages hold 10 `plaintext` fence
markers before and after, leaving objectui#5867's SHRINK-ONLY population at
80 files / 93 blocks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CZgmFFzqA9cX8tBMhvpFe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Decision] Five documented action props have no declared slot at all — delete them, move them onto the item, or is this a types gap?

2 participants