chore: improve component conventions for AI-assisted development - #2993
Merged
Conversation
huacnlee
force-pushed
the
audit/ai-native
branch
from
September 7, 2026 09:43
edf112d to
b79f4ce
Compare
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
huacnlee
enabled auto-merge (squash)
September 7, 2026 13:26
feigeCode
pushed a commit
to feigeCode/gpui-component
that referenced
this pull request
Sep 8, 2026
…gbridge#2993) Improves the conventions AI consumers can transfer between GPUI Kit components: predictable constructors, semantic value callbacks, and explicit Form composition. Adds executable consumer examples and strengthens Shell/type feedback so incorrect assumptions are caught by repeatable checks. The tables below cover all 50 changed files. Paths are relative to the repository root. | Area | Files | Detailed change | Consumer behavior and compatibility | | --- | --- | --- | --- | | Checkbox events | `crates/component/src/checkbox.rs` | Adds `on_change` receiving the requested `&bool`; documents application-owned state updates and notification. | The same callback shape can be transferred to Switch and Radio. Existing `on_click` delegates to the same handler; the last setter wins. | | Switch events | `crates/component/src/switch.rs` | Adds `on_change` for pointer and keyboard value requests, using the existing callback storage and activation behavior. | Preserves the existing `on_click` signature, disabled behavior, and controlled-state semantics. | | Radio events | `crates/component/src/radio.rs` | Adds `Radio::on_change` receiving `&bool` and `RadioGroup::on_change` receiving the requested `&usize` index. | Existing `on_click` methods remain aliases. Radio selection retains its existing semantics; the group owner stores `Some(*index)`. | | RadioGroup construction | `crates/component/src/radio.rs` | Makes `RadioGroup::new(id)` public. | The natural `new(id)` constructor now compiles. Defaults remain vertical layout with no selected item; horizontal/vertical constructors remain available. | | Form construction | `crates/component/src/form/form.rs` | Makes `Form::new()` public and implements `Default`. | Both create one field column with labels above controls, matching the existing vertical default. | | Form label orientation | `crates/component/src/form/form.rs` | Adds `label_layout(Axis)`; makes `layout(Axis)` delegate to it; clarifies horizontal/vertical constructor documentation. Corrects the documented label width from 100px to 140px. | Label orientation and `columns(count)` are independent decisions. Existing builders retain their meaning and behavior. | | Form actions | `crates/component/src/form/form.rs` | Adds replaceable `footer(element)` content rendered after fields, spanning all columns, with trailing alignment and a zero minimum width. | `child` continues to accept typed Fields; buttons have an explicit composition slot. No footer row is created unless supplied. The application owns action callbacks and submission. | | Control convention tests | `crates/component/tests/controlled_change_callbacks.rs` | Adds two interaction tests: a four-control matrix across both callback names, both setter orders, enabled/disabled states, mouse/Enter/Space activation; and owner state writeback across redraw and subsequent activation. | Checks one callback per enabled activation, no disabled callbacks, replacement of earlier handlers, public RadioGroup construction, and controlled-state persistence. | | Form contract tests | `crates/component/src/form/tests.rs` | Adds four tests for builder defaults, label direction independent of two field columns, footer geometry, and legacy geometry without a footer. Layout bounds are checked at 360px and 800px. | Verifies labels above/beside controls, row placement, footer full-span/trailing alignment, and unchanged no-footer geometry. | | Table constructor documentation | `crates/component/src/table/state.rs` | Corrects two rustdoc examples to call `TableState::new(delegate, window, cx)`. | Documentation-only signature correction; no Table runtime behavior changes. | | Area | Files | Detailed change | Consumer behavior and compatibility | | --- | --- | --- | --- | | Single-snapshot checking | `crates/shell/src/plugin.rs` | `ShellRuntime::check` builds one snapshot, materializes its eager native elements, and returns that snapshot's debug description. Keeps the application and callback-owning snapshot alive through materialization. | Registered-component construction failures now reach the check result. `--print-spec` describes the same snapshot that was checked. Adds assertions for exactly one script render and one materialization. | | Structured materialization errors | `crates/shell/src/materialize.rs` | Adds internal `try_materialize`, wrapping the existing materializer in an error frame. | Source checks receive registered-component failures instead of only an error fallback element. Normal rendering continues to use the existing materializer. | | Hidden-window initialization | `crates/shell/src/host.rs` | Completes the catalog-provided window opener before calling runtime checks through the opened window. | Component materializers can access the installed Root and other window facilities. | | CLI failure status and help | `crates/shell/src/host.rs` | Centralizes reporting and process exit in `CheckOutcome::exit`, including failures before window creation; rewrites `check` help to state its actual stages. | Invalid metadata, load/render errors, and materialization failures exit 1. The help explicitly excludes layout, paint, deferred slots, nested view renders, and later interactions. | | Test-only description helper | `crates/shell/src/engine/quickjs/mod.rs` | Gates `render_to_spec` with `#[cfg(test)]` after production checking moves to snapshots. | Internal cleanup; production checks use the same snapshot for inspection and materialization. | | Renderable and native types | `crates/shell/src/typings.rs` | Introduces `NativeElement` for native/Base builders and makes `Element` a union of native and registered component builders. Updates generated factory, host-module, TextView, and FPS declarations accordingly. | Registered components remain usable as children and view results while retaining component-specific signatures such as semantic size. Helpers requiring native-only signatures should use `NativeElement`. | | Fluent type preservation | `crates/shell/src/typings.rs` | Uses explicit receiver generics across fluent methods, parameterized/nullary styles, child/slot composition, state styles, and conditionals. `map` preserves its actual result type. Registered builders derive from `NativeElement` with descriptor overrides and withheld behaviors. | Styling or composition no longer widens a registered builder into an unrestricted element. Unsupported handlers and invalid size values remain rejected after chaining. Generated registered-component types also withhold native `role` and `transition` unless the descriptor provides them; native builders retain these methods. | | Declaration regression assertions | `crates/shell/src/typings.rs`, `crates/shell/src/tests/render.rs` | Updates declaration expectations for native factories, receiver-preserving methods, registered descriptors, imports, and specialized element behavior. | Keeps generated declarations aligned with the revised fluent type structure and existing runtime descriptors. | | CLI integration tests | `crates/component-shell/tests/check.rs` | Adds six tests covering valid typed children and printed descriptions; invalid ordinary Form children; styles on data-only components; load/render failures without hanging; invalid metadata before window creation; and structured error propagation/reset between checks. | Exercises real CLI exit behavior and ensures a failed check does not contaminate the next successful check. | | TypeScript contract fixtures | `crates/component-shell/tests/types/fluent.ts` | Adds a complete positive application exercising typed fluent composition, native roles/transitions, typed Form children, component-specific methods, and `map` return values. Its emitted JavaScript is the actual runtime fixture. | The same positive source must pass strict TypeScript checking and the actual CLI check; there is no independent runtime copy that can omit failing calls. | | Negative TypeScript fixture | `crates/component-shell/tests/types/rejected.ts` | Separates expected compiler failures from executable positive examples, including direct and chained unsupported `role`/`transition` calls. | Fails if a forbidden call becomes accepted; negative expressions are never executed as the valid application. | | Reproducible type test runner | `crates/component-shell/tests/types/run.mjs`, `crates/component-shell/tests/types/package.json`, `crates/component-shell/tests/types/package-lock.json`, `crates/component-shell/tests/types/README.md` | Pins TypeScript 5.9.3; generates declarations in a temporary directory; emits and executes the strict positive TypeScript fixture, checks separate negative fixtures and the shipped JavaScript gallery, and runs six expected CLI rejection cases; cleans up temporary files. Supports an explicit host-binary override. | Tests use the existing editor configuration's `skipLibCheck`; they validate consumer contracts rather than all ambient library declarations. | | Shipped gallery typing | `examples/js_story/stories/registered.js` | Adds a JSDoc array type for MessageScroller messages, preserving literal alignment and variant values. | The shipped JavaScript example passes generated-type checking without changing runtime behavior. | | Area | Files | Detailed change | Consumer behavior and verification | | --- | --- | --- | --- | | Isolated consumer package | `examples/ai_recipes/Cargo.toml`, `examples/ai_recipes/Cargo.lock` | Adds an independent workspace depending on the `gpui-kit` facade and a committed lockfile. | Production compilation does not rely on unrelated workspace members supplying missing dependencies or features. The standalone lockfile accounts for most added lines. | | Complete Settings view | `examples/ai_recipes/src/lib.rs` | Retains Input state and its subscription; updates preview text; uses Checkbox/Switch/RadioGroup `on_change` callbacks with owner writeback; composes typed Form fields and an About-button footer; renders dialog, sheet, and notification layers. | Provides one complete source example of state ownership, transferable callbacks, form composition, and overlays. | | Application entry point | `examples/ai_recipes/src/main.rs` | Adds application initialization, assets, window creation, and Root setup around the Settings view. | The recipe has a runnable entry point as well as a compilable view. | | Retained-input regression | `examples/ai_recipes/tests/settings.rs` | Exercises typing after unrelated redraws and checks owner state updates. | Detects lost subscription/state lifetime behavior in the published recipe. | | Recipe inventory and guidance | `examples/ai_recipes/recipes.json`, `examples/ai_recipes/README.md` | Maps source to three published fragments and documents run/sync commands, task-specific acceptance profiles, and verification limits. | Consumers can select the appropriate check and understand what a passing result proves. | | Source-to-doc synchronization | `script/check-ai-recipes` | Adds fragment freshness checks and `--sync`; rejects missing/duplicate markers and empty coverage; checks isolated recipe formatting, production-binary compilation, all targets, and tests. Provides an explicitly limited `--docs-only` mode. | Published recipes must match compiled source. Documentation-only checks cannot be mistaken for compilation or interaction verification. | | Drift-detection tests | `script/tests/test_ai_recipes.py` | Adds three tests for stale source and synchronization, removed/duplicate markers, and empty inventories. | Prevents recipe coverage from silently disappearing or reporting a false pass. | | Acceptance entry point | `script/check-ai` | Adds `docs`, `rust`, `shell`, and `all` profiles with failure propagation and a shared target directory. Rust includes consumer checks, control callback tests, existing legacy-control compatibility tests, and Form geometry tests. Shell includes declaration/render tests, component-host tests, and pinned TypeScript/CLI fixtures. | Provides repeatable task-scoped commands instead of relying on manual interpretation of separate checks. | | CI integration | `.github/workflows/ci.yml` | Runs docs/Rust acceptance profiles on macOS and installs/runs pinned generated TypeScript contracts in the component-shell job. | Recipe drift and the new component conventions are checked continuously alongside component-host type contracts. | | Area | Files | Detailed change | Effect on AI consumers | | --- | --- | --- | --- | | Dependency/facade guidance | `README.md`, `README.zh-CN.md`, `crates/kit/Cargo.toml` | Corrects the facade description to GPUI, Base, Component, and assets; identifies Shell as a separate host dependency and Component Shell as the styled catalog. The English README links executable recipes and acceptance checks. | Avoids generating imports or dependencies based on a nonexistent Shell re-export. | | Shell capability guidance | `crates/shell/README.md` | Fixes the missing `div` import; documents the existing styled host/gallery and component inventory; replaces outdated unavailable-component claims; explains materialization checks and their limits. | Guides consumers to the correct host and actual supported surfaces without implying full Rust API parity. | | Skill entry point | `skills/gpui-kit/SKILL.md` | Links family conventions and tested recipes early; prefers `llms.txt` plus a targeted page, retaining `llms-full.txt` for broader reference. | Makes constructor/state/event/layout decisions discoverable before loading the full catalog. | | Component-family reference | `skills/gpui-kit/references/conventions.md` | Adds a task-to-family table, constructor and ownership rules, semantic callback patterns, independent Form layout decisions, capability-trait imports, and verification guidance. Distinguishes Rust conventions from the JavaScript host catalog. | Lets a model transfer known patterns while recognizing family-specific constructor and state models. | | Usage reference corrections | `skills/gpui-kit/references/usage.md` | Corrects facade/import examples; retains Input/List subscriptions on the owner; shows Checkbox/Switch state writeback through `on_change`; places Form actions in `footer`; replaces the blanket `new(id)` claim with family-specific guidance. | Removes examples that encourage dropped subscriptions, invalid imports, invalid Form children, or overgeneralized constructors. | | Published application recipe | `skills/gpui-kit/references/recipes.md`, `website/docs/getting-started.md`, `website/zh-CN/docs/getting-started.md` | Publishes synchronized copies of the complete Settings view and associated setup/verification guidance; corrects getting-started guidance around the executable consumer. | The three marked source fragments are checked against the same compilable implementation. | | Checkbox documentation | `website/docs/components/checkbox.md`, `website/zh-CN/docs/components/checkbox.md` | Makes `on_change` the documented value callback; explains owner writeback, notification, and `on_click` alias replacement behavior; updates examples. | Establishes one reusable controlled-value pattern. | | Switch documentation | `website/docs/components/switch.md`, `website/zh-CN/docs/components/switch.md` | Updates callback examples/reference to `on_change` and documents the shared alias/ownership contract. | Transfers the Checkbox pattern to Switch without rediscovering event naming. | | Radio documentation | `website/docs/components/radio.md`, `website/zh-CN/docs/components/radio.md` | Documents semantic callbacks, their payloads, compatibility aliases, and the public `RadioGroup::new(id)` default. | Clarifies boolean Radio requests versus indexed RadioGroup requests and predictable group construction. | | Form documentation | `website/docs/components/form.md`, `website/zh-CN/docs/components/form.md` | Adds explicit examples of `Form::new`, `label_layout`, independent `columns`, and `footer`; states that the application owns values, validation, submission, and responsive column choices. | Reduces ambiguity between label orientation and field placement, and shows where action buttons belong. | | Surface | Breaking change? | Migration or effect | | --- | --- | --- | | Rust component builders | No | Adds methods/constructors; preserves `on_click`, existing Form constructors/layout builders, and default behavior. | | TypeScript `Element` | Yes, at the type level | Changes from an interface to a renderable union. Interface extension/declaration merging against `Element` is no longer supported. Use `NativeElement` for native-specific interfaces/helpers; use `Element` for general render results. | | Registered TypeScript capabilities | Stricter validation | Previously accepted unsupported `role`/`transition` calls now fail compilation, including after chaining. Such calls already failed at runtime. Use a native wrapper for native behavior where appropriate. | | Shell `check` | Stricter failure behavior | Previously missed eager materialization and metadata errors now return exit 1. Passing checks still do not prove layout, paint, or later interactions. | | Verification | Coverage | Recorded result | | --- | --- | --- | | `script/check-ai docs` | Three synchronized published fragments and three drift-detection tests. | Passed locally. | | `script/check-ai rust` | Isolated production/test-target compilation; one retained-input interaction test; two control callback/state tests; four existing legacy compatibility tests; four Form contract tests. | Passed locally; 11 Rust tests across these suites. | | Control activation matrix | Four controls, mouse/Enter/Space, enabled/disabled, both callback names, and both alias setter orders. | Passed locally. | | Form layout bounds | 360px and 800px widths; independent label direction/field columns; full-span and trailing footer placement; legacy no-footer geometry. | Passed locally. | | `script/check-ai shell` | Generated declarations, Shell rendering, component-host targets, pinned TypeScript positive/negative contracts, shipped JavaScript checking, and real CLI acceptance/rejection. | Passed locally. | | Single-snapshot regression | `cargo test -p gpui-shell --lib runtime_check_returns_the_rendered_description` checks one script render and one materialization. | Passed locally. | | Component Clippy | `cargo clippy -p gpui-component --lib --tests --no-default-features -- -D warnings`. | Passed locally. | | Shell Clippy | `cargo clippy -p gpui-shell -p gpui-component-shell --all-targets -- -D warnings`. | Passed locally. | | Formatting and documentation hygiene | Workspace formatting, changed-file spelling, and diff whitespace checks. | Passed locally. | Local validation was performed on macOS; these results do not assert the current remote CI status. This is an initial component-family improvement, not coverage of every component. Deterministic contract tests do not measure AI first-attempt success rates. Native visual/accessibility review and model benchmarks were not performed. Shell checks cover eager materialization, not layout, paint, deferred slots, nested view renders, or later interactions. Type fixtures use `skipLibCheck` and do not certify all ambient declarations. Authored with Codex. --------- Co-authored-by: Codex <codex@openai.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Improves the conventions AI consumers can transfer between GPUI Kit components: predictable constructors, semantic value callbacks, and explicit Form composition. Adds executable consumer examples and strengthens Shell/type feedback so incorrect assumptions are caught by repeatable checks.
Detailed Changes
The tables below cover all 50 changed files. Paths are relative to the repository root.
Rust component conventions
crates/component/src/checkbox.rson_changereceiving the requested&bool; documents application-owned state updates and notification.on_clickdelegates to the same handler; the last setter wins.crates/component/src/switch.rson_changefor pointer and keyboard value requests, using the existing callback storage and activation behavior.on_clicksignature, disabled behavior, and controlled-state semantics.crates/component/src/radio.rsRadio::on_changereceiving&boolandRadioGroup::on_changereceiving the requested&usizeindex.on_clickmethods remain aliases. Radio selection retains its existing semantics; the group owner storesSome(*index).crates/component/src/radio.rsRadioGroup::new(id)public.new(id)constructor now compiles. Defaults remain vertical layout with no selected item; horizontal/vertical constructors remain available.crates/component/src/form/form.rsForm::new()public and implementsDefault.crates/component/src/form/form.rslabel_layout(Axis); makeslayout(Axis)delegate to it; clarifies horizontal/vertical constructor documentation. Corrects the documented label width from 100px to 140px.columns(count)are independent decisions. Existing builders retain their meaning and behavior.crates/component/src/form/form.rsfooter(element)content rendered after fields, spanning all columns, with trailing alignment and a zero minimum width.childcontinues to accept typed Fields; buttons have an explicit composition slot. No footer row is created unless supplied. The application owns action callbacks and submission.crates/component/tests/controlled_change_callbacks.rscrates/component/src/form/tests.rscrates/component/src/table/state.rsTableState::new(delegate, window, cx).Shell runtime and generated TypeScript
crates/shell/src/plugin.rsShellRuntime::checkbuilds one snapshot, materializes its eager native elements, and returns that snapshot's debug description. Keeps the application and callback-owning snapshot alive through materialization.--print-specdescribes the same snapshot that was checked. Adds assertions for exactly one script render and one materialization.crates/shell/src/materialize.rstry_materialize, wrapping the existing materializer in an error frame.crates/shell/src/host.rscrates/shell/src/host.rsCheckOutcome::exit, including failures before window creation; rewritescheckhelp to state its actual stages.crates/shell/src/engine/quickjs/mod.rsrender_to_specwith#[cfg(test)]after production checking moves to snapshots.crates/shell/src/typings.rsNativeElementfor native/Base builders and makesElementa union of native and registered component builders. Updates generated factory, host-module, TextView, and FPS declarations accordingly.NativeElement.crates/shell/src/typings.rsmappreserves its actual result type. Registered builders derive fromNativeElementwith descriptor overrides and withheld behaviors.roleandtransitionunless the descriptor provides them; native builders retain these methods.crates/shell/src/typings.rs,crates/shell/src/tests/render.rscrates/component-shell/tests/check.rscrates/component-shell/tests/types/fluent.tsmapreturn values. Its emitted JavaScript is the actual runtime fixture.crates/component-shell/tests/types/rejected.tsrole/transitioncalls.crates/component-shell/tests/types/run.mjs,crates/component-shell/tests/types/package.json,crates/component-shell/tests/types/package-lock.json,crates/component-shell/tests/types/README.mdskipLibCheck; they validate consumer contracts rather than all ambient library declarations.examples/js_story/stories/registered.jsExecutable examples and acceptance checks
examples/ai_recipes/Cargo.toml,examples/ai_recipes/Cargo.lockgpui-kitfacade and a committed lockfile.examples/ai_recipes/src/lib.rson_changecallbacks with owner writeback; composes typed Form fields and an About-button footer; renders dialog, sheet, and notification layers.examples/ai_recipes/src/main.rsexamples/ai_recipes/tests/settings.rsexamples/ai_recipes/recipes.json,examples/ai_recipes/README.mdscript/check-ai-recipes--sync; rejects missing/duplicate markers and empty coverage; checks isolated recipe formatting, production-binary compilation, all targets, and tests. Provides an explicitly limited--docs-onlymode.script/tests/test_ai_recipes.pyscript/check-aidocs,rust,shell, andallprofiles with failure propagation and a shared target directory. Rust includes consumer checks, control callback tests, existing legacy-control compatibility tests, and Form geometry tests. Shell includes declaration/render tests, component-host tests, and pinned TypeScript/CLI fixtures..github/workflows/ci.ymlDocumentation and AI discovery
README.md,README.zh-CN.md,crates/kit/Cargo.tomlcrates/shell/README.mddivimport; documents the existing styled host/gallery and component inventory; replaces outdated unavailable-component claims; explains materialization checks and their limits.skills/gpui-kit/SKILL.mdllms.txtplus a targeted page, retainingllms-full.txtfor broader reference.skills/gpui-kit/references/conventions.mdskills/gpui-kit/references/usage.mdon_change; places Form actions infooter; replaces the blanketnew(id)claim with family-specific guidance.skills/gpui-kit/references/recipes.md,website/docs/getting-started.md,website/zh-CN/docs/getting-started.mdwebsite/docs/components/checkbox.md,website/zh-CN/docs/components/checkbox.mdon_changethe documented value callback; explains owner writeback, notification, andon_clickalias replacement behavior; updates examples.website/docs/components/switch.md,website/zh-CN/docs/components/switch.mdon_changeand documents the shared alias/ownership contract.website/docs/components/radio.md,website/zh-CN/docs/components/radio.mdRadioGroup::new(id)default.website/docs/components/form.md,website/zh-CN/docs/components/form.mdForm::new,label_layout, independentcolumns, andfooter; states that the application owns values, validation, submission, and responsive column choices.Compatibility
on_click, existing Form constructors/layout builders, and default behavior.ElementElementis no longer supported. UseNativeElementfor native-specific interfaces/helpers; useElementfor general render results.role/transitioncalls now fail compilation, including after chaining. Such calls already failed at runtime. Use a native wrapper for native behavior where appropriate.checkTest Plan
script/check-ai docsscript/check-ai rustscript/check-ai shellcargo test -p gpui-shell --lib runtime_check_returns_the_rendered_descriptionchecks one script render and one materialization.cargo clippy -p gpui-component --lib --tests --no-default-features -- -D warnings.cargo clippy -p gpui-shell -p gpui-component-shell --all-targets -- -D warnings.Local validation was performed on macOS; these results do not assert the current remote CI status. This is an initial component-family improvement, not coverage of every component. Deterministic contract tests do not measure AI first-attempt success rates. Native visual/accessibility review and model benchmarks were not performed. Shell checks cover eager materialization, not layout, paint, deferred slots, nested view renders, or later interactions. Type fixtures use
skipLibCheckand do not certify all ambient declarations.Authored with Codex.