Skip to content

fix: type FilterListBox.Item and CommandMenu.Item as CollectionItem - #1284

Merged
tenphi merged 2 commits into
mainfrom
fix-item-types
Aug 7, 2026
Merged

fix: type FilterListBox.Item and CommandMenu.Item as CollectionItem#1284
tenphi merged 2 commits into
mainfrom
fix-item-types

Conversation

@tenphi

@tenphi tenphi commented Aug 7, 2026

Copy link
Copy Markdown
Member

Problem

At runtime FilterListBox.Item and CommandMenu.Item are the very same object as ListBox.Item / Menu.Item (CollectionItem), but their declarations pointed at react-stately's bare Item. Consumers therefore got type errors for props that work perfectly at runtime:

<FilterListBox.Item key="a" rightIcon={<SomeIcon />}>A</FilterListBox.Item>
//                          ^^^^^^^^^ not assignable to `ItemProps<unknown>`

The gap is invisible inside this repo: tsconfig.json sets preserveSymlinks: true, which makes typeof Item from react-stately silently resolve to any (see the existing note in tsconfig.json). Consumers compile without that flag, so they see the real — and wrong — ItemProps<T>.

Fix

Both components now import CollectionItem as Item from src/components/CollectionItem, matching what ComboBox, SearchComboBox and CommandTextArea already do. Purely a typing change — CollectionItem is react-stately's Item at runtime (Object.assign mutates the target), so no behaviour changes.

Also:

  • FilterListBox.Item = Item instead of = ListBox.Item, so the declaration and the assignment refer to the same symbol (identical object either way).
  • mergeProps(customValueProps ?? {}, newCustomValueProps ?? {}) — with Item no longer any, TS surfaced that mergeProps of two optional args produces an intersection including undefined, which cannot be spread.

Audit of the other collection components

Every public component exposing .Item was checked with a type probe compiled with preserveSymlinks: false (passing description + rightIcon to .Item inside a .Section):

Component Before After
FilterListBox ❌ react-stately Item CollectionItem
CommandMenu ❌ react-stately Item CollectionItem
ListBox, Menu, Select CollectionItem unchanged
Picker, FilterPicker typeof ListBox.Item unchanged
ComboBox, SearchComboBox, CommandTextArea CollectionItem alias unchanged

.Section is correct everywhere (plain react-stately Section; the Cube wrappers add only a displayName). Disclosure.Item and Form.Item are unrelated components, not collection items.

Verification

  • tsc --noEmit --preserveSymlinks false against the probe above: 2 errors before (FilterListBox.Item, CommandMenu.Item), 0 after. Probe removed before committing.
  • tsc --noEmit: byte-identical to the pre-change baseline (24 pre-existing errors, no new ones).
  • Full vitest run: 59 files / 1208 tests passing, 0 failures.
  • oxlint src and prettier --check clean.

🤖 Generated with Claude Code


Note

Low Risk
Public API is typings-only (runtime unchanged); FilterListBox’s mergeProps tweak is a small defensive typing fix with no intended behavior change.

Overview
FilterListBox.Item and CommandMenu.Item now expose CollectionItem types instead of react-stately’s bare Item, so TypeScript accepts the same extended props (icon, rightIcon, description, hotkeys, actions, etc.) that already work at runtime—aligned with ListBox.Item, Menu.Item, and ComboBox.

In FilterListBox, FilterListBox.Item is assigned the same CollectionItem symbol used in the module, and custom-value Item spreads use mergeProps(customValueProps ?? {}, newCustomValueProps ?? {}) so optional prop bags type-check after Item is no longer any.

AGENTS.md adds a Before You Start block (pnpm install && pnpm rebuild esbuild, lockfile version checks) so local tsc/tests aren’t trusted on a stale tree. A patch changeset documents the public typing fix.

Reviewed by Cursor Bugbot for commit 5574fa4. Bugbot is set up for automated code reviews on this repo. Configure here.

Both were declared as react-stately's bare `Item`, so `Item` props
(`icon`, `rightIcon`, `description`, `hotkeys`, `actions`) were rejected
by TypeScript despite working at runtime.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5574fa4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cube-dev/ui-kit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cube-ui-kit Ready Ready Preview Aug 7, 2026 10:34am

Request Review

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

📦 NPM canary release

Deployed canary version 0.0.0-canary-e41a2a2.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🧪 Storybook is successfully deployed!

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🏋️ Size limit report

Name Size Passed?
All 449.37 KB (+0.01% 🔺) Yes 🎉
Tree shaking (just a Button) 118.94 KB (0% 🟰) Yes 🎉

Click here if you want to find out what is changed in this build

A stale node_modules silently inverts test and type results, which is
how a correct source file was "fixed" into a CI failure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tenphi
tenphi merged commit fc51747 into main Aug 7, 2026
15 checks passed
@tenphi
tenphi deleted the fix-item-types branch August 7, 2026 10:45
@tenphi tenphi mentioned this pull request Aug 7, 2026
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.

1 participant