Skip to content

fix(components): retire AccordionItem.icon, honor item-level disabled - #4723

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-4652-accordion-item-keys
Aug 15, 2026
Merged

fix(components): retire AccordionItem.icon, honor item-level disabled#4723
yinlianghui merged 1 commit into
mainfrom
claude/issue-4652-accordion-item-keys

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Fixes#4652

AccordionItem declared disabled?: boolean and icon?: string while the accordion
renderer read neither — it mapped items to value/title/content only. Premise
re-verified against origin/main (fec06835e): both keys declared at
packages/types/src/disclosure.ts:39,43 and its Zod mirror
packages/types/src/zod/disclosure.zod.ts; neither read at
packages/components/src/renderers/disclosure/accordion.tsx. Radix's underlying
AccordionPrimitive.Item (spread via packages/components/src/ui/accordion.tsx) supports
disabled natively. The mechanism hypothesis held in full — same shape as objectui#4632
(PR #4651), one interface up in the same file.

The measurement (per the inherited #4632/#4651 framing)

Enforce-or-remove, decided per key by measured pull, not by symmetry. Full corpus sweep:
schema catalog (examples/schema-catalog), docs (content/docs), example/application
code (apps/console, apps/site), and this repo's objectstack sibling checkout.

keysites authoring itcode reading itdirection
icon0noneretire
disabled0none in accordion — but honored by 6 sibling componentswire
  • icon — retired. Zero measured pull anywhere in the sweep, including the
    objectstack sibling checkout (no AccordionItem/page:accordion icon authoring
    found there at all — page:accordion items are a separate, unrelated interface, see
    Notes). Under declared=enforced it is removed rather than speculatively implemented.
  • disabled — wired, despite also having zero direct catalog pull today. Item-level
    disabled is established live convention in this codebase: tabs, select,
    dropdown-menu, menubar, context-menu and (objectui#4632) toggle-group all
    forward it. accordion was the next outlier, and the underlying Radix item supports
    disabled natively, so forwarding one prop is the whole change — the synced no-touch
    ui/accordion.tsx (AGENTS.md 构建一个 **Live Playground (实时演练场)** (用于展示引擎能力) #7) is untouched.

Surfaces changed

  • packages/types/src/disclosure.tsicon removed from AccordionItem; disabled
    kept and documented as forwarded.
  • packages/types/src/zod/disclosure.zod.tsAccordionItemSchema declared icon too;
    removed in the same commit so the retirement closes on both hand-maintained
    declarations together.
  • packages/components/src/renderers/disclosure/accordion.tsx — forwards disabled per
    item to the AccordionItem primitive.
  • examples/schema-catalog/.../basic-accordion.json — one item now demonstrates
    disabled: true, so the corpus teaches a key that actually works. Contents-only edit,
    no index regeneration (examples/schema-catalog/src/index.ts imports the file by path;
    per fix(examples,scripts): regenerating the schema catalog stops discarding curated metadata #4637's own model).
  • content/docs/components/disclosure/accordion.mdx — one line of prose above the
    SchemaExample describing the new disabled-item demo. The page's "Schema" code block
    underneath is pre-existing, unrelated drift (missing value, wrong root field names
    defaultOpen/multiple vs. the real accordionType/defaultValue/etc.) — left alone
    and filed separately as finding(docs): accordion.mdx's schema block is stale against the real AccordionSchema/AccordionItem interface #4722, since fixing it is a different defect class than this
    card's declared-but-unenforced-key settlement.

Tests, all at 015360404

Full verification ran after the final commit, tree clean.

  • New: packages/types/src/__tests__/accordion-item-authorable-keys.test.ts (declaration
    surfaces — icon retired via @ts-expect-error + Zod-drop + Zod-shape pins; disabled
    stays declared, preserved through the Zod mirror, rejects non-boolean).
  • New: packages/components/src/__tests__/accordion-item-disabled.test.tsx (behavior — the
    disabled item's trigger carries a real disabled attribute and does not expand on
    click; positive control: a non-disabled item does expand on click; leaves every item
    enabled when none declares disabled; still renders each title).
  • pnpm exec vitest run --maxWorkers=2 packages/types/ packages/components/ examples/schema-catalog/173 files / 3114 tests passed.
  • pnpm --filter @object-ui/types type-check and pnpm --filter @object-ui/components type-check — clean (dependency closure built first via
    pnpm --filter '@object-ui/components^...' build, a fresh worktree fails type-check on
    unresolved workspace deps otherwise).
  • check-changeset-presence / check-changeset-no-major / check-control-bytes /
    check-doc-links — all green. ESLint on the changed files: 0 errors (1 pre-existing
    no-explicit-any warning on an untouched line, confirmed present on origin/main).

Reverse verification, direction predicted before each run:

  1. Ablate the renderer's disabled forward (drop disabled={item.disabled}) ⇒ predicted
    the two behavior pins asserting the forward go red, the rest of the file stays green.
    Observed exactly that: disables exactly the item that declares it and does not expand the disabled item on click failed (dump showed aria-expanded="true" and no disabled
    attribute on the trigger button); the positive-control test, the no-disabled-declared
    test, and the title-render test stayed green (2 failed / 3 passed).
  2. Cross-package: authored icon in a @object-ui/components-side scratch test against
    the rebuilt@object-ui/types d.ts ⇒ error TS2353: Object literal may only specify known properties, and 'icon' does not exist in type 'AccordionItem'. Observed exactly
    that; the retirement reaches consumers, and the verdict came from the rebuilt
    declaration, not a cached one. Scratch file removed afterward, type-check re-confirmed
    green.

Each ablation was restored with git checkout from the committed state and confirmed
byte-clean (git status --porcelain empty).

Notes

Generated by Claude Code

AccordionItem declared icon?: string and disabled?: boolean while the
accordion renderer read neither. Same defect as ToggleGroupItem in the
same file (objectui#4632, PR #4651): a corpus sweep (schema catalog,
docs, example apps, and the objectstack sibling checkout) found zero
sites authoring either key. icon is retired from the interface and the
Zod mirror. disabled is wired, since item-level disabled is already
established convention (tabs, select, dropdown-menu, menubar,
context-menu, toggle-group) and Radix's accordion item supports it
natively, so the renderer forwarding one prop is the whole change.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnQd8iMMUwXQEV1crFmQiQ
@vercel

vercelBot commented Aug 15, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredAug 15, 2026 5:33pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)24.7 KB350 KB
Entry fileindex-ZE_Wqlli.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)9.56KB3.59KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)8.92KB3.41KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)25.13KB5.40KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)38.46KB10.17KB
auth (createAuthenticatedFetch.js)6.34KB2.43KB
auth (index.js)2.35KB1.07KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.02KB0.88KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)489.93KB108.68KB
core (index.js)3.79KB1.52KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)156.79KB43.21KB
fields (index.js)230.37KB57.17KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.32KB1.77KB
i18n (index.js)3.35KB1.38KB
i18n (pickLocalized.js)3.69KB1.73KB
i18n (provider.js)23.12KB7.62KB
i18n (useDisplayLocale.js)2.84KB1.45KB
i18n (useObjectLabel.js)27.59KB6.63KB
i18n (useSafeTranslation.js)7.77KB3.13KB
layout (index.js)38.98KB10.85KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)8.75KB3.06KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)3.67KB1.12KB
permissions (evaluator.js)4.41KB1.44KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.55KB0.71KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.86KB12.91KB
plugin-charts (index.js)64.44KB18.28KB
plugin-chatbot (index.js)181.21KB43.14KB
plugin-dashboard (index.js)121.90KB31.76KB
plugin-designer (index.js)212.39KB42.83KB
plugin-detail (index.js)239.86KB59.99KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)114.72KB27.70KB
plugin-gantt (index.js)164.30KB40.02KB
plugin-grid (index.js)192.10KB51.24KB
plugin-kanban (index.js)52.74KB14.53KB
plugin-list (index.js)111.14KB26.92KB
plugin-map (index.js)18.16KB5.81KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)41.38KB11.09KB
plugin-timeline (index.js)26.68KB7.66KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)83.81KB20.49KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.71KB3.53KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.67KB2.37KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)27.64KB9.44KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.28KB0.68KB
react (schema-input.js)1.45KB0.83KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)4.09KB1.74KB
sdui-parser (index.js)4.47KB2.03KB
sdui-parser (parse.js)10.04KB2.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)4.69KB1.48KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.05KB1.52KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

Review verdict: ACCEPT (reviewer of record, PM session session_01RnQd8iMMUwXQEV1crFmQiQ).

Verified against this PR, not the report: all eight changed files are enumerated and justified in the body — including the catalog example now exercising the wired key and the one-line docs pointer, which the corpus-teaches-what-works lesson explicitly wants shipped together (the report summary under-enumerated these two; the PR body is the complete account, so recorded as a nit only). Fixes #4652 is the only closing keyword; #4721/#4722/#4632/#4631 all carry explicit non-closure language. I independently re-verified the retirement's reference face on origin/main: zero item.icon reads in the disclosure renderer and zero authored icon keys in accordion catalog entries. Both reverse verifications are the direction-predicted form, and the cross-package one proves the verdict came from a rebuilt declaration. Changeset minor matches the identical-class precedent. Gates green on 015360404 = current head; flipping ready and arming auto-merge now.

The two out-of-scope findings (#4721, #4722) get their first-touch grades on their own cards.


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 15, 2026 17:51
@yinlianghui
yinlianghui added this pull request to the merge queueAug 15, 2026
Merged via the queue into main with commit 58b8346Aug 15, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-4652-accordion-item-keys branch August 15, 2026 17:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(components): AccordionItem declares icon and disabled but the accordion renderer reads neither

2 participants

@yinlianghui@claude