{"owner":"longbridge","repo":"gpui-component","hasSkills":true,"totalSkillsCount":34,"totalTokensCount":93784,"categories":["command-prompt","root-instruction","claude-rule","project-spec","anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":[".agents/commands/release-notes.md",".claude/commands/release-notes.md","AGENTS.md","CLAUDE.md","docs/ARCHITECTURE.md","skills/gpui-kit-design-guides/SKILL.md","skills/gpui-kit-design-guides/references/design-guides.md","skills/gpui-kit/SKILL.md","skills/gpui-kit/references/coding-guides.md","skills/gpui-kit/references/conventions.md","skills/gpui-kit/references/gpui/action.md","skills/gpui-kit/references/gpui/async.md","skills/gpui-kit/references/gpui/context.md","skills/gpui-kit/references/gpui/element-advanced.md","skills/gpui-kit/references/gpui/element-api.md","skills/gpui-kit/references/gpui/element-best-practices.md","skills/gpui-kit/references/gpui/element-examples.md","skills/gpui-kit/references/gpui/element-id.md","skills/gpui-kit/references/gpui/element-patterns.md","skills/gpui-kit/references/gpui/element.md","skills/gpui-kit/references/gpui/entity-advanced.md","skills/gpui-kit/references/gpui/entity-api.md","skills/gpui-kit/references/gpui/entity-best-practices.md","skills/gpui-kit/references/gpui/entity-patterns.md","skills/gpui-kit/references/gpui/entity.md","skills/gpui-kit/references/gpui/event.md","skills/gpui-kit/references/gpui/focus-handle.md","skills/gpui-kit/references/gpui/global.md","skills/gpui-kit/references/gpui/layout-style.md","skills/gpui-kit/references/gpui/test-examples.md","skills/gpui-kit/references/gpui/test-reference.md","skills/gpui-kit/references/gpui/test.md","skills/gpui-kit/references/recipes.md","skills/gpui-kit/references/usage.md"],"skills":{".agents/commands/release-notes.md":"# Release Notes\n\nWrite release notes using the input supplied by the user: either a tag such\nas `v0.6.2`, or the auto-generated \"## What's Changed\" list copied from the\nGitHub release draft. When no input is supplied, use the `version` in the\nworkspace `Cargo.toml` with a `v` prefix.\n\n## Gather\n\n1. Read the previous release with `gh release view <previous-tag> --json body -q .body`\n   to match its structure, tone, and section names. The previous tag is\n   `git describe --tags --abbrev=0 <tag>^` (or the latest published release\n   when `<tag>` does not exist yet).\n2. If no \"What's Changed\" list was pasted, generate it:\n\n   ```bash\n   gh api repos/longbridge/gpui-kit/releases/generate-notes \\\n     -f tag_name=<tag> -f previous_tag_name=<previous-tag> -q .body\n   ```\n\n   Keep this list, its \"New Contributors\" section, and the \"Full Changelog\"\n   line verbatim; they close the notes.\n3. Read the body of every PR that adds a component, a public API, a platform,\n   or a behavior change, with `gh pr view <n> --json title,body`. Take API\n   names, method names, and `## Breaking Changes` diff blocks from the PR\n   text; never invent a name from the title alone. Fix-only PRs can be\n   summarized from their titles.\n\n## Write\n\nProduce one Markdown document in this shape, in English:\n\n```markdown\n# GPUI Kit <tag>\n\n<Two or three sentences: the headline features first, then what else the\nrelease improves.>\n\n## <Theme>\n\n- **<Feature>**: what a consumer can now do, with the API in backticks.\n  ([#123](https://github.com/longbridge/gpui-kit/pull/123))\n- Fixed ... ([#124](...), [#125](...))\n\n...\n\n## Breaking Changes            <!-- only when a PR has one -->\n\n<One sentence per change naming the PR, then its diff block.>\n\nThank you to everyone who contributed code, documentation, testing, and feedback!\n\n## What's Changed\n<verbatim list>\n\n## New Contributors\n<verbatim list>\n\n**Full Changelog**: <verbatim line>\n```\n\nRules:\n\n- Group by product area, ordered by significance: headline features (new\n  platforms, new components), then editor and text input, Markdown and text\n  rendering, motion, dock, other components (one bold component name per\n  bullet), shell, runtime and platform, documentation and website. Drop a\n  section that has nothing to say; merge small ones.\n- Every bullet cites its PR numbers as `[#n](https://github.com/longbridge/gpui-kit/pull/n)`\n  at the end, in parentheses. Combine PRs that land one change into one bullet.\n- Leave out chores, CI, lockfile refreshes, test-only changes, and a PR that\n  reverts another PR in the same release (leave both out).\n- Bold the feature, not the sentence; write what it does for an application,\n  not what the diff touched.\n- Do not create or edit the GitHub release unless asked. Save the document to\n  the scratchpad and show it, so it can be pasted into the release draft.\n",".claude/commands/release-notes.md":"---\ndescription: Write the GitHub release notes for a gpui-kit version in the established style\nargument-hint: [tag] or the pasted \"What's Changed\" list\n---\n\nRead and follow the shared release-notes workflow in\n`.agents/commands/release-notes.md` (relative to the repository root).\n\nUse the following as the workflow input; if empty, use the shared workflow's\ndefault version:\n\n$ARGUMENTS\n","AGENTS.md":"# AGENTS.md\n\nThis file provides shared guidance for coding agents working in this repository.\nKeep project rules here; `CLAUDE.md` imports this file for Claude Code.\n\n## Canonical Design and Coding Guides\n\nBefore changing UI, interaction, interface language, layout, styling,\ncomponents, or application architecture, read and follow the repository's\ncanonical guides:\n\n- [Design Guides](website/docs/design-guides.md)\n- [Coding Guides](website/docs/coding-guides.md)\n\nThese guides are requirements, not optional inspiration. Do not copy generic\nweb conventions, infer a design system from one existing screen, or add a\ncontrol merely because the underlying feature exists. Preserve the documented\ntask hierarchy, interaction promise, desktop conventions, spacing, alignment,\ntheme tokens, component boundaries, naming, and crate architecture. Review the\nfinished work against both guides before considering it complete.\n\nFor Chinese documentation and UI, apply the terminology rules in Design Guides.\nKeep established framework, component, and API names in their canonical English\nform when translation would reduce precision; write the surrounding Chinese as\nnatural Chinese rather than word-for-word translation.\n\n## Project Overview\n\nGPUI Kit is a Rust desktop application framework built on GPUI, published at <https://gpui-kit.com>. It ships as three crates: `gpui-base` (unstyled behavior and infrastructure), `gpui-shell` (JavaScript extensions for a Rust host), and `gpui-component` (GPUI Component, the styled component library with 60+ cross-platform desktop UI components, inspired by macOS/Windows controls and combined with shadcn/ui design). Applications depend on the umbrella crate `gpui-kit` (`crates/kit`), which pins the matching `gpui-pre-*` snapshot of GPUI and puts GPUI at its root (`use gpui_kit::*;`) with `gpui_kit::platform`, `gpui_kit::base`, `gpui_kit::component` and `gpui_kit::assets` reachable by name, so they never list GPUI itself. `gpui-shell` is not part of `gpui-kit` and is not published yet (its `llrt_*` dependencies are git-only); use it as a git dependency.\n\nThis is a Rust workspace project with the following main crates:\n\n- `crates/kit` - Umbrella crate applications depend on (published as `gpui-kit`)\n- `crates/component` - Core UI component library (published as `gpui-component`)\n- `crates/story` - Gallery application for showcasing and testing components\n- `crates/story-web` - Web version of the story gallery (using WebAssembly)\n- `crates/component-macros` - Procedural macros (`IntoPlot` derive)\n- `crates/assets` - Static assets\n- `crates/webview` - WebView component support\n- `examples/` - Various example applications\n\n## Common Commands\n\n### Development and Testing\n\n```bash\n# Run Story Gallery (component showcase application)\ncargo run\n\n# Run individual examples\ncargo run --example hello_world\ncargo run --example table\n\n# Build the project\ncargo build\n\n# Lint check\ncargo clippy -- --deny warnings\n\n# Format check\ncargo fmt --check\n\n# Spell check\ntypos\n\n# Check for unused dependencies\ncargo machete\n```\n\n### Testing\n\n**Note**: Per user configuration, tests do not need to be run.\n\nFor pure UI visual or sizing adjustments, do not add automated tests solely to\nassert presentation dimensions. Add tests when the change affects behavior,\ninteraction, data flow, or prevents a meaningful regression.\n\n```bash\n# Run all tests\ncargo test --all\n\n# Run tests for a specific crate\ncargo test -p gpui-component\n\n# Run doc tests\ncargo test -p gpui-component --doc\n```\n\n### Performance Profiling\n\n```bash\n# View FPS on macOS (using Metal HUD)\nMTL_HUD_ENABLED=1 cargo run\n\n# Profile performance using samply\nsamply record cargo run\n```\n\n## Core Architecture\n\n### Architecture Refactoring Constraints\n\nThe implemented foundation architecture is documented in\n`docs/ARCHITECTURE.md`, with styling and motion rules in\n`docs/STYLING-AND-MOTION.md`. Preserve these constraints when designing or\nimplementing this architecture:\n\n- Do not modify `gpui-base` unless the user explicitly requests a Base-layer\n  change. By default, implement component behavior and visual styling in\n  `crates/component` or the application layer.\n\n- Keep GPUI Kit as the ecosystem and product brand; `gpui-component` is its\n  styled component layer, alongside `gpui-base` and `gpui-shell`.\n- Name the foundation crate `gpui-base`.\n- Follow the ownership boundary: the framework owns behavior and infrastructure;\n  the application owns component source and visual style.\n- Keep the base layer visually unopinionated. It may provide interaction behavior,\n  accessibility, focus, overlay and popup infrastructure, positioning, animation,\n  virtual lists, dock infrastructure, and semantic design tokens.\n- Theme APIs must expose semantic tokens (colors, spacing, radius, typography, and\n  shadows), not an ever-growing set of component-specific styling fields.\n- Keep source distribution or registry tooling above the `gpui-base` seam; no\n  registry or CLI crate is currently part of the workspace.\n- Preserve 100% backward compatibility for existing consumers, including current\n  imports such as `use gpui_kit::component::button::Button;`.\n\n### Component Initialization\n\nCall `gpui_kit::init(cx)` before opening windows that use styled components.\nIt includes Base initialization and registers Component's window extension.\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx| {\n        gpui_kit::init(cx);\n        gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| {\n            cx.new(|_| MyView)\n        })\n        .expect(\"Failed to open window\");\n    });\n}\n```\n\nBase-only fixtures use GPUI directly and must not depend on Kit or Component.\nApplications and Kit tests use `gpui_kit::open_window` as their window entry point.\n\n### Root View System\n\n`gpui_base::Root` is the top-level view for every window created by\n`gpui_kit::open_window`. The helper belongs only to Kit; Base supplies the Root\nimplementation. `component::Root` re-exports the Base type. Cargo features do not\nselect a different root type.\n\nBase owns content and overlay hosting, keyboard navigation (Tab/Shift-Tab),\nand selection copying. Explicit Component initialization registers per-window\nstate and presentation for dialogs, sheets, notifications, tooltips, menus,\ntouch selection, themes and window chrome. Initialize before creating windows.\n\nThe helper returns the window handle and application content entity. Its builder\nmust return content, not another Root. Overlay layers mount automatically; do not\ncall the removed `Root::render_*_layer` methods. In async contexts call the helper\ninside `cx.update`. Tests should use the same helper and retain its returned\ncontent entity when they need to inspect or update application state. Avoid\nconstructing `Root` directly in application and test startup code.\n\nQuit/close actions, keyboard shortcuts and confirmation flows belong to the application.\n\n### Theme System\n\n- Uses `Theme` global singleton for theme configuration\n- Supports light/dark mode switching\n- Access theme via `ActiveTheme` trait: `cx.theme()`\n- Theme configuration includes:\n  - Colors (`ThemeColor`)\n  - Syntax highlighting theme (`HighlightTheme`)\n  - Font configuration (system font and monospace font)\n  - UI parameters like border radius, shadows\n  - Scrollbar display mode\n\n### Dock System\n\nLayout behavior lives in `crates/base/src/dock`; `crates/component/src/dock` is a\npresentation skin (`DockSkin`) over it. See `docs/ARCHITECTURE.md`.\n\n- **`LayoutTree`**: Pure-data layout tree, the single source of truth.\n  - `NodeKind::Split` / `Tabs`: containers, addressed by `NodeId`\n  - Panels are addressed by `PanelId`; the tree holds no entity handles\n- **`DockArea`**: Owns the center and dock trees, reconciles them into a\n  cache of container entities keyed by `NodeId`\n- **`TabGroup`**: The `Tabs` container entity\n- **`Panel`**: Split at the seam — `gpui_base::dock::Panel` for behavior,\n  `gpui_component::dock::Panel` for presentation; a panel implements both\n- **`PanelRegistry`**: Resolves a persisted `panel_name` back to a panel type\n\nThe Dock system supports:\n\n- Panel drag-and-drop reordering\n- Panel zoom\n- Layout locking\n- Layout serialization/restoration\n\n### Input System\n\nText input system based on Rope data structure:\n\n- **InputState**: Input state management\n- **Rope**: Efficient text storage (from ropey crate)\n- LSP integration support (diagnostics, completion, hover)\n- Syntax highlighting support (Tree-sitter)\n- Multiple input modes:\n  - Regular input (`Input`)\n  - Number input (`NumberInput`)\n  - OTP input (`OtpInput`)\n\n### Component Design Principles\n\n1. **Stateless design**: Use `RenderOnce` trait, components should be stateless when possible\n2. **Size system**: Supports `xs`, `sm`, `md` (default), `lg` sizes via `Sizable` trait.\n3. **Mouse cursor**: Buttons use `default` cursor not `pointer` (desktop app convention), unless it's a link button\n4. **Style system**: Provides CSS-like styling API via `Styled` trait and `ElementExt` extensions\n5. **Base controls are no-style**: Base controls and parts do not install layout,\n   positioning, colors, sizing, gaps, radius, borders, shadows, variants, or animation.\n   Complete presentation belongs to `crates/component` or the application. The deliberate\n   exception is the foundational Base Input frame, which provides only a semantic\n   one-pixel input border and semantic radius baseline; UI/application layers own\n   its background, sizing, padding, typography, adornments, and richer focus style.\n6. **GPUI builder style**: Keep element construction as one fluent builder chain. Express\n   conditions with `when`, `when_some`, `when_none`, and `map`; do not split a chain into a\n   mutable temporary element followed by imperative reassignment when the builder API can\n   express the same operation.\n7. **No `pub` fields on public data types**: A public struct handed across the\n   `gpui-base`/application seam — a state snapshot, capability set, render context, or\n   option set — keeps its fields private, is constructed with a builder, and is read\n   through methods. Adding a `pub` field is a breaking change; adding one behind a builder\n   is not. Setters and readers must not collide: an all-boolean type names setters after\n   the field and readers `is_<adjective>`/`has_<noun>`, never `can_`; a type with\n   non-boolean fields prefixes every setter with `with_` and keeps the field name for\n   readers. Value types whose fields are the definition and cannot grow (`Point`,\n   `Selection`, `Edges`) are exempt. See the \"Public Data Types Across the Seam\" section\n   of `docs/ARCHITECTURE.md`.\n8. **Spell `Context` out**: Name a context type `ComboboxTriggerContext`, never `…Ctx`.\n   `cx` is reserved for GPUI's `App`, `Context<T>`, and `AsyncApp`, so `ctx` for anything\n   else reads as a competing context. A callback receiving both takes the GPUI one as `cx`\n   and names the other after what it holds (`trigger`, `state`).\n\n## Pull Request Reviews\n\nEvery PR review must present its conclusions in this order:\n\n1. Explain the PR's purpose: the problem it addresses and the scope of its changes.\n2. Assess whether the requirement and proposed approach are reasonable.\n3. Report concrete findings, followed by validation performed and its limitations.\n\nDo not start a review with findings alone; include the purpose and reasonableness\nassessment even when no issues are found.\n\n## Code Style\n\n- Follow naming and organization patterns from existing code\n- Reference macOS/Windows control API design for naming\n- AI-generated code must be refactored to match project style\n- Mark AI-generated portions when submitting PRs\n- When creating a PR, inspect previous PR titles in the repository and match\n  that style. Do not blindly use conventional prefixes like `fix:` or `feat:`\n  unless the existing PR title style uses them.\n- When a PR adds, changes or removes public API in any crate, list every item\n  under a `## Public API` section of the description, grouped by crate, with its\n  signature and one line on its purpose (JavaScript methods and TypeScript\n  declarations included). Changes to existing items also go under\n  `## Breaking Changes` with `diff` blocks showing the old and new usage. See\n  PR #2691 and the \"Describe public API changes\" section of `CONTRIBUTING.md`.\n- Avoid `Kind` as a type-name suffix. It says an enum classifies something\n  without saying what it classifies, and carries no meaning a reader could not\n  already infer from `enum`. Name the type after what its variants _are_\n  instead. Keep `Kind` only when no honest name covers the variant set —\n  `NodeKind`'s variants straddle two levels (`Split` is an interior node,\n  `Tabs` is a leaf), and every domain word for the leaf level\n  (`Pane`, most of all) would misdescribe `Split`; a vaguer name is better\n  than a precise wrong one. Prefer confining such a type to `pub(crate)`.\n  This governs new code; existing `Kind` names are not a rewrite target on\n  their own, and names owned by external crates (`CodeActionKind`,\n  `CompletionItemKind`, `WindowKind`) keep their upstream spelling.\n\n## Icon System\n\nThe `Icon` element does not include SVG files by default. You need to:\n\n- Use [Lucide](https://lucide.dev) or other icon libraries\n- Name SVG files according to the `IconName` enum definition (located in `crates/component/src/icon.rs`)\n\n## Dependencies\n\n- GPUI: Git version from Zed repository\n- Tree-sitter: For syntax highlighting\n- Ropey: Rope data structure for text, and `RopeExt` trait with more features.\n- Markdown rendering: `markdown` crate\n- HTML rendering: `html5ever` (basic support)\n- Charts: Built-in chart components\n- LSP: `lsp-types` crate\n\n## Internationalization\n\nUses `rust-i18n` crate.\n\n- Localization files are located in `crates/component/locales/`.\n- Only add `en`, `zh-CN`, `zh-HK` by default.\n- Accessibility (A11y) names and labels may remain in English; localization is\n  not required for these strings. Keep the item's own label when naming a\n  control that acts on it. This exception does not apply to visible UI copy.\n\n## Documentation\n\n- The documentation site source is in `website/`.\n- Site docs have two locales: English (`website/docs/`) and Chinese (`website/zh-CN/docs/`).\n- When modifying any documentation file, always sync changes to both `en` and `zh-CN` versions.\n- `docs/` holds internal architecture specifications (RFC, migration status, reviews).\n  These are single-language and are not published to the site; see `docs/README.md`.\n- `skills/gpui-kit/references/coding-guides.md` and\n  `skills/gpui-kit-design-guides/references/design-guides.md` are verbatim copies\n  of the English `website/docs/` originals, vendored so the skills work after\n  `npx skills add` in a project that does not have this repo. After editing either\n  guide, copy it across:\n\n  ```bash\n  cp website/docs/design-guides.md skills/gpui-kit-design-guides/references/design-guides.md\n  cp website/docs/coding-guides.md skills/gpui-kit/references/coding-guides.md\n  ```\n\n  Never edit the copy directly — edit `website/docs/`.\n\n## Platform Support\n\n- macOS (aarch64, x86_64)\n- Linux (x86_64)\n- Windows (x86_64)\n\nCI runs full test suite on each platform.\n\n## Skills Reference\n\nThis project provides skills for coding agents to assist with common development tasks:\n\n- **gpui-kit** (`skills/gpui-kit/SKILL.md`) - Building applications on the `gpui-kit` crate: setup, component catalog, stateless/stateful patterns, theming, GPUI mechanics (actions, async, contexts, custom elements, entities, events, focus, global state, layout, `ElementId`, testing), and the normative Coding Guides\n- **gpui-kit-design-guides** (`skills/gpui-kit-design-guides/SKILL.md`) - The normative Design Guides; load before any UI, layout, interaction, or interface-copy work\n\nWhen working on tasks related to these areas, read the appropriate `SKILL.md`\nfor specialized guidance and patterns.\n\n## Shared Workflows\n\n- [Release notes](.agents/commands/release-notes.md) - Write release notes from a\n  version tag or a pasted \"What's Changed\" list. Claude Code exposes this workflow\n  through `/release-notes`; other agents can read and follow the shared file.\n\n## Testing Guidelines\n\nSee `.agents/COMPONENT_TEST_RULES.md` for detailed testing principles:\n\n- **Simplicity First**: Focus on complex logic and core functionality, avoid excessive simple tests\n- **Builder Pattern Testing**: Every component should have a `test_*_builder` test covering the builder pattern\n- **Complex Logic Testing**: Test conditional branching, state transitions, and edge cases\n","CLAUDE.md":"# Claude Code\n\n@AGENTS.md\n","docs/ARCHITECTURE.md":"# gpui-base Architecture\n\n## Status and Scope\n\nThis document describes the architecture implemented by `crates/base`. It is a\nsource-derived reference, not a migration plan. Public exports in\n`crates/base/src/lib.rs` and the Rust API documentation remain authoritative for\nindividual methods.\n\n`gpui-base` is the reusable foundation below the styled `gpui-component` crate.\nIt is designed for both of these callers:\n\n- `crates/component`, which adapts base behavior into GPUI Component's complete visual\n  system;\n- applications that build and own a different visual system directly on top of\n  base behavior.\n\n## Architectural Thesis\n\nThe durable rule is:\n\n> Base owns reusable behavior and the geometry required to implement it. The\n> presentation layer owns the product's visual language.\n\n“Headless” does not mean that every base module is a single empty `Div`.\nKeyboard navigation, text editing, popup collision handling, virtualization,\ncalendar grids, resizable panels, and toast stacking require internal structure,\nmeasurement, and retained state. Base owns that complexity when moving it to\ncallers would duplicate difficult behavior.\n\nBase does not own product-level choices such as brand colors, typography,\ncontrol density, borders, radii, icons, variants, or final composition.\n\n## Dependency Direction\n\n```text\n                       application\n                     /             \\\n                    ▼               ▼\n       application-owned UI     gpui-component\n                    \\               /\n                     └──────┬──────┘\n                            ▼\n                        gpui-base\n                            ▼\n                           GPUI\n```\n\nDependencies point downward. `gpui-base` must not import `gpui-component`\nthemes, assets, or façade types. `gpui-component::init` may initialize and theme\nthe base layer, but the base layer must also work when initialized directly.\n\nThere is no Registry or CLI crate in the current workspace. Source distribution\ncan be added above this seam without changing the ownership model, but it is not\npart of the implemented architecture documented here.\n\n## Module Families\n\nThe public surface contains four distinct module families. Treating all of them\nas identical “primitives” hides important interface differences.\n\n### 1. Semantic elements\n\nExamples include Button, Checkbox, Radio, Switch, Toggle, Link, Tabs, Progress,\nAvatar, and the semantic Table parts.\n\nThese modules typically implement GPUI interfaces directly:\n\n```text\nIntoElement\n+ Styled\n+ ParentElement where composition is meaningful\n+ InteractiveElement for interactive roots\n```\n\nThey provide a stable element identity, event normalization, focus behavior,\nkeyboard activation, accessibility semantics, controlled values, and optional\nsemantic-state styles. The caller supplies visible children and presentation.\n\n`Button::new(\"save\")`, for example, receives an `ElementId`, not a label. It has\nno default height, padding, background, border, or radius.\n\n### 2. Compound behavior roots\n\nExamples include Accordion, Dialog, AlertDialog, Sheet, Popover, HoverCard,\nSelect, Combobox, DatePicker, and Popup.\n\nThese modules coordinate multiple parts or application-owned children. Their\ninterfaces encode behavior that would be fragile if every caller rebuilt it:\n\n- open-state requests and change reasons;\n- trigger and content focus transfer;\n- Escape, Confirm, and directional key actions;\n- dismissal ordering;\n- backdrop hit testing;\n- focus trapping;\n- trigger measurement and popup placement.\n\nParts such as `DialogTitle`, `DialogDescription`, and `DialogClose` are explicit\nsemantic seams. Base does not walk arbitrary descendant trees to discover them.\n\n### 3. Stateful systems\n\nExamples include InputState, TextareaState, EditorState, CalendarState, TreeState, SliderState,\nResizableState, OtpState, ColorPickerState, QuestionnaireState, ToastManager, ToastStackState,\nNavStackState, DockArea, and TabGroup.\n\nThese modules retain data because their behavior spans frames or requires\nmeasurement, subscriptions, history, focus, or incremental updates. State is\nusually stored in a GPUI `Entity`, a keyed element state, or an application-owned\nmodel passed back to the element.\n\nStateful systems expose application rendering seams rather than leaking their\nimplementation. Calendar provides a pre-wired `CalendarItem` and semantic\n`CalendarItemState` to an item renderer. Tree owns flattening, expansion,\nselection, keyboard movement, and virtualization while the caller renders each\nvisible `TreeEntry`.\n\n### 4. Infrastructure and utility modules\n\nExamples include Positioner, Scrollbar, VirtualList, FocusTrapElement,\nAutoScroll, motion, History, geometry helpers, measurement, theme tokens, and\nglobal initialization.\n\nThese are deep modules: a small interface hides layout, lifecycle, or data\nstructure complexity used by many controls. Their interface is also their test\nseam; callers should not need to reproduce the hidden algorithm to verify it.\n\n## State Ownership\n\nState ownership follows behavioral needs rather than one universal pattern.\n\n### Controlled values\n\nCheckbox, Radio, Switch, Toggle, Select, and similar roots accept the current\nvalue and report requested changes. They do not silently mutate application\nstate.\n\n```text\napplication value\n      │\n      ▼\nbase element ── activation ──▶ on_change(next_value)\n      ▲                            │\n      └──── next render ───────────┘\n```\n\nCallbacks describe intent. Pointer-originated value changes include the\n`ClickEvent` when modifier keys are useful. Model-driven changes, such as\npagination requests, do not invent a pointer event.\n\n### Handles and explicitly shared state\n\nDialog supports `DialogHandle` for imperative open and close requests while\nstill reporting `DialogChangeReason`. Scrollbar adapters share an underlying\nscroll handle. Toast stack geometry is shared through `ToastStackState`.\n\nHandles coordinate one logical behavior. They must not be reused across\nunrelated viewports or component instances.\n\n### Entity-backed state\n\nComplex modules use `Entity<State>` when they need GPUI observation,\nsubscriptions, focus handles, or incremental notification. The state entity owns\nbehavioral data; the presentation layer still owns how that data looks.\n\n### Keyed element state\n\nSmall pieces of ephemeral state tied to an element identity use\n`window.use_keyed_state`. Stable `ElementId` values are therefore part of the\ninterface, not an implementation detail. Changing an ID can reset focus,\nmeasurement, animation, or open-state bookkeeping.\n\n## Styling Model\n\nBase separates three styling mechanisms:\n\n1. ordinary GPUI `Styled` calls for instance presentation;\n2. typed semantic-state style builders such as checked, selected, or disabled;\n3. GPUI native runtime modifiers such as hover, active, and focus-visible.\n\nThe shared `state_style::resolve_style` function makes semantic precedence\nconsistent across controls. See [Styling and Motion](STYLING-AND-MOTION.md) for\nthe complete contract.\n\nCompound and stateful modules expose explicit presentation seams:\n\n- GPUI `Styled` on the root or part;\n- application-provided children;\n- typed part elements;\n- item renderer callbacks;\n- style refinements for internal virtualized containers;\n- presentation snapshots such as `InputPresentation`.\n\n## Public Data Types Across the Seam\n\nA public struct that crosses the base/application seam must not expose `pub`\nfields. Every field a caller can name is a field that cannot be added later:\nadding one breaks any struct literal, and removing or renaming one breaks every\nreader. The seam types are the ones that grow the most, because each new\ncapability of a control shows up as another flag in the state it hands out.\n\nThe shape to use instead:\n\n- private fields;\n- a builder for construction — `new()` plus one chained setter per field;\n- a reader per field.\n\nSetters and readers must not collide, which decides the naming:\n\n- a type whose fields are all boolean names its setters after the field and its\n  readers `is_<adjective>`/`has_<noun>`, never `can_`, matching how elements\n  read — `CalendarItemState`, `InputContextMenuCapabilities`;\n- a type carrying non-boolean fields prefixes every setter with `with_`, so the\n  readers keep the plain field name — `RenderOptions::with_item_ix` against\n  `RenderOptions::item_ix`. This follows `Sizable::with_size`.\n\nA `with_`-style setter that takes `self` by value also replaces functional\nupdate syntax, which stops compiling once the fields are private:\n\n```rust\n// was: RenderOptions { item_ix, ..*options }\nitem.render_item(&options.with_item_ix(item_ix), window, cx)\n```\n\nA type that is only ever built inside its own module — `InputPresentation` is\nbuilt by `InputBaseState::presentation` and nowhere else — needs the private\nfields and the readers, but not a public builder. Private fields already close\nthe breaking-change hole, and a public builder there would hand out a\nconstruction path the seam does not want. Such a type reads its non-boolean\nfields under the plain field name, which is why it cannot also carry\nfield-named setters.\n\n```rust\nlet capabilities = InputContextMenuCapabilities::new()\n    .code_editor(true)\n    .selection(true);\n\nif capabilities.is_editable() && capabilities.has_selection() { /* ... */ }\n```\n\nDerived answers belong on the type rather than at each call site. When several\nreaders are always combined the same way — `!disabled && !readonly` — publish\nthat combination as its own reader (`is_editable`) so the rule has one\ndefinition and new inputs to it stay invisible to callers.\n\nName such a type in full: `ComboboxTriggerContext`, never `…Ctx`. In a GPUI\ncodebase `cx` is reserved for `App`, `Context<T>`, and `AsyncApp`, so an\nabbreviated `ctx` for anything else reads as a second, competing context. A\ncallback that receives both takes the GPUI one as `cx` and gives the other a\nname describing what it holds.\n\nThis applies to state snapshots (`InputPresentation`, `CalendarItemState`),\ncapability sets (`InputContextMenuCapabilities`), render contexts\n(`ComboboxTriggerContext`), and option sets (`RenderOptions`). It does not\napply to value types whose fields _are_ the definition and cannot grow, such as\n`Point`, `Selection`, `Edges`, `IndexPath`, or `FoldRange`, nor to types that\nmirror an external schema, such as the LSP `Diagnostic`.\n\nDesign-token records (`ColorTokens`, `RadiusTokens`, and the rest of\n`theme_tokens`) still carry `pub` fields. They have the same growth problem, and\nconverting them is tracked separately because every theme in `gpui-component`\nconstructs them.\n\n## Input, Textarea, and Editor Architecture\n\nText editing is intentionally deeper than the semantic elements, but callers do\nnot need to learn the complete editor interface for every text field.\n\n### Public forms\n\nBoth `gpui-base` and `gpui-component` expose three purpose-specific forms:\n\n| Form       | State           | Intended interface                                                                                        |\n| ---------- | --------------- | --------------------------------------------------------------------------------------------------------- |\n| `Input`    | `InputState`    | Single-line values, placeholders, masks, validation, and submission                                       |\n| `Textarea` | `TextareaState` | Ordinary multi-line text, fixed rows, soft wrapping, and optional auto-grow limits                        |\n| `Editor`   | `EditorState`   | Source text, language-aware highlighting, line numbers, folding, search, diagnostics, and LSP integration |\n\n`gpui-base` provides unstyled forms. `gpui-component` adapts the same behavior\ninto the product theme and sizing system. `InputBase` is the foundational frame\nused for input semantics, state styling, accessibility, and application-owned\ncontent; it is not one of the three editing forms.\n\nExisting `gpui-component::Input::new(&Entity<InputState>)` call sites remain the\nsingle-line compatibility path. `InputState` is a real facade, not a type alias\nfor the editing engine: multiline, auto-grow, gutter, folding, diagnostics, and\nLSP configuration are absent from its API. Multi-line code must construct\n`TextareaState` or `EditorState` instead.\n\n### Shared engine\n\n`InputBaseState` owns mechanics shared by all three states:\n\n- Rope-backed text and edit history;\n- cursor, selection, IME, clipboard, and focus;\n- shaping, layout, hit testing, selection and caret painting;\n- auto-scroll, viewport scrolling, and cursor visibility;\n- native text-content integration where supported.\n\nThe implementation under `crates/base/src/input` is organized by responsibility:\n\n- `base/` contains the shared editing engine and foundational mechanics;\n- `input/` contains the single-line control and state facade;\n- `textarea/` contains the multi-line control and state facade;\n- `editor/` contains the editor control and state facade, plus display mapping,\n  highlighting, search, diagnostics, decorations, indentation, and LSP.\n\nThese are implementation folders rather than public Rust module segments. The\nexternal seam remains `gpui_base::input`, with stable re-exports in `mod.rs`.\n\nPurpose-specific state facades configure the shared engine and forward\n`InputEvent` without duplicating those mechanics. `InputState`, `TextareaState`,\nand `EditorState` are distinct GPUI entity types. Their private bridge to\n`InputBaseState` exists for component composition; it is not the application\nAPI.\n\nEditor-only implementation includes indentation, folding, decorations,\ndiagnostics, search, LSP providers, overlays, line-number/gutter painting, and\nsyntax highlighting. Textarea owns rows, soft wrapping, Enter submission, and\nauto-grow policy. Masking, validation, and number stepping remain input-only\nconcepts.\n\n### Presentation and geometry\n\nPresentation is injected through `InputEditorStyle`, highlighter interfaces,\nfold-icon renderers, context-menu adapters, and the higher-level UI forms.\n`gpui-component` supplies editor insets from its size system. Base consumes\nthose insets only as geometry so text, the fixed gutter, and scrollbars share a\ncoordinate system:\n\n- text remains inset from the frame;\n- vertical and horizontal scrollbars terminate at the frame edge;\n- the gutter background covers the complete fixed column, including top,\n  bottom, and leading insets;\n- editor focus does not add the single-line input focus-border treatment.\n\nThis keeps product values in the presentation layer while keeping coupled text,\ngutter, and scrollbar geometry local to the editing engine.\n\n### Input groups\n\n`gpui-component::input::InputGroup` composes one `Input` or `Textarea` with typed\naddons and buttons in a shared frame. It owns no editing state: the control is\nthe ordinary styled `Input`, rendered without its own border, background and\nfocus ring, so every capability the input gains — paste hooks, touch\nselection, native menus, accessibility — reaches a group without being\nmirrored. `InputGroup` owns the outer border, radius, focus and error\ntreatment, and four logical addon regions; `InputGroupButton` wraps a `Button`\nwith compact presentation and sizes through `Sizable`. Textarea viewport\ngeometry remains with the editing engine. Validation appearance is\ncaller-controlled, separately from edit acceptance.\n\nPlatform-specific behavior is isolated behind adapters. For example, folding is\ndisabled on WebAssembly, time uses `web_time` where needed, and native text\ncontent support is conditionally compiled.\n\n## Text Rendering for External Components\n\n`gpui_base::text::editor_host` adapts the same renderer used by `TextView`.\nIt is a rendering boundary for externally owned rich-text components, not an\nediting engine. The host projects its own document into `BlockNode` values;\nBase owns shaping, wrapping, inline-object layout and geometry. The host owns\ndocument identity and revisions, editing semantics, commands, history, selection,\nfocus, accessibility integration, native input and scrolling policy.\n\n### Identity and lifecycle\n\nThere are two independent identities. A stable GPUI element ID scopes retained\nrender state; `BlockNode::render_with_id` provides that scope for top-level\nblocks. Leaf keys identify geometry and decorations within one collection.\nKeys must be unique in that collection. Cloning the AST shares runtime state;\ncalling `with_leaf_key` detaches the leaf's runtime text/selection state so\nrekeying a clone does not rename the original leaf. Independently rendered\ninstances need distinct keys.\n\nRun `collect_leaf_geometry` around child prepaint, not rendering or painting.\nThe scope is synchronous, nests with isolation and restores its predecessor\nduring unwinding. Only prepainted leaves are reported. A virtualized or cached\nsubtree that does not prepaint is absent; a missing entry does not remove a leaf\nfrom the host document.\n\n`LeafGeometry` copies bounds and retains immutable shaped lines. It does not\nretain mutable `TextLayout` handles. A later frame cannot change an existing\nsnapshot, but that snapshot describes only its original content, typography,\nwidth and scroll offset. Hosts must associate geometry with their own document\nrevision and replace it when those inputs change.\n\n### Coordinates and presentation\n\nLeaf offsets are UTF-8 bytes. Each inline image or custom inline node occupies\none U+FFFC (three bytes), independent of its fallback text. Window coordinates\nare logical pixels, before display scaling. Hard breaks and empty lines retain\ncaret positions, including the final empty line. Native input APIs that use\nUTF-16 require conversion in the host.\n\nDecorations are ordered half-open byte ranges. Text decorations paint behind\nglyphs. Any nonempty overlap with an atom decorates its entire box, over the\ncontent, so an opaque image can show its selected state. The host supplies the\ncolor and should use translucency for an atom overlay. Empty ranges paint\nnothing. Decorations do not change layout.\n\n`RenderContext::new` accepts local presentation without application globals;\n`from_app` uses TextView defaults. A host can override syntax highlighting,\nimage resolution and link activation locally. Reference links need definitions\nfrom the entire document, including blocks outside the viewport. Register them\nthrough `with_link_reference`.\n\n### Evolution boundary\n\nKeep the sink, layout caches, flow fragments and shaping implementations private.\nThe public AST is a projection into the renderer, not a canonical editor model\nor persistence format. Do not add editor-specific document operations, history,\ncollaboration or serializer policy to Base merely to serve one consumer.\n\nThis boundary currently supports horizontal text rendered through TextView's\nblock flow. It is not a complete contract for every future editor. In particular,\na future extension for visual navigation must represent caret affinity at soft\nwraps and bidirectional runs; a byte index alone is insufficient. Per-position\ncaret metrics and range rectangles should be designed together with that\ncontract, not inferred from one leaf-wide line height. Pagination, arbitrary\nblock-level widgets, native accessibility text ranges and vertical writing need\ntheir own demonstrated requirements and contract tests before being promised.\n\nThe newly public `BlockNode` enum is non-exhaustive so variants may be added.\nIts existing named variant fields still constrain changes to those variants;\nnon-exhaustiveness is not permission to rename fields or add required fields.\nPrefer new private-field option types and additive constructors when extending\nthe seam. Preserve existing public types and import paths; a pre-1.0 disclaimer\ndoes not replace this project's compatibility requirement.\n\n## Overlay and Positioning Architecture\n\nOverlay modules separate lifecycle from placement and presentation.\n\n### Positioner\n\n`Positioner` is the shared placement implementation. It supports:\n\n- side placement with preferred-side selection, flipping, alignment, offset,\n  and viewport clamping;\n- corner placement compatible with anchored trigger geometry, with viewport\n  clamping but no side flip.\n\nPopup measures its trigger during prepaint, stores the captured bounds in keyed\nstate, and renders positioned content through a deferred element on the next\nframe. Tooltip reuses Positioner rather than maintaining another collision\nalgorithm.\n\n### Modal hosts\n\nDialog and Sheet create viewport-sized hosts. They own focus trapping, keyboard\nactions, backdrop or overlay dismissal, and callback ordering. They do not own\nthe final popup or panel placement: the application styles the supplied popup or\nsurface as centered, right-aligned, bottom-aligned, or another product-specific\nlayout.\n\nOverlay visuals and overlay hit targets are separate layers. The surface is\npainted above the dismissal target so a click inside content does not dismiss\nthe modal.\n\n## Scrolling and Virtualization\n\n`ScrollbarHandle` is the seam between scrolling implementations and the shared\nScrollbar element. An adapter reports:\n\n- viewport bounds;\n- current offset;\n- content size;\n- offset updates;\n- optional drag lifecycle notifications.\n\nAdapters exist for GPUI `ScrollHandle`, `UniformListScrollHandle`, and\n`ListState`, plus base `VirtualListScrollHandle`.\n\nScrollbar normally overlays the viewport reported by its handle. Two explicit\nalternatives support deeper widgets:\n\n- `viewport_bounds` supplies custom-painted bounds, as the editor does;\n- `viewport_from_layout` uses same-frame layout bounds, as DataTable does when\n  excluding fixed headers and columns.\n\nVirtualList owns variable-size item layout, visible-range calculation, content\nmasking, deferred scroll-to-item requests, and clamped offsets. The caller owns\nitem sizes and renders only the requested range. Tree builds on GPUI's uniform\nlist because its visible entries share a row height.\n\n`ScrollableMask` owns wheel dispatch, not scrolling. GPUI's own overflow\nlistener runs in the bubble phase and never stops propagation, so a scroll area\nnested inside another one cannot win: `gpui::list` registers its listener after\nits items paint, and bubble runs in reverse registration order. The mask is a\nsibling of the scrolled element that consumes axis-dominant wheel events in the\ncapture phase, locks each gesture to the axis it started on, and stays inert\nwhile occluded. Edge semantics differ per axis, matching platform scrollers: a\nvertical mask chains to the ancestor at the edge, a horizontal one keeps\nconsuming. `horizontal_scroll_area` is the paired viewport and mask, used by the\nMarkdown scrolling table. A Markdown code block whose style sets `overflow.y` to\n`Overflow::Scroll` pairs its viewport with a vertical mask and a `Scrollbar`.\n\nA plain mouse wheel has only a vertical axis, which a native horizontal scroller\nwith a locked axis ignores. `ScrollableMask::vertical_wheel` sits over such a\nscroller and handles only that wheel: its lines move the scroller sideways and,\nat the edge, chain to the ancestor; trackpad gestures and horizontal wheels go\non to the scroller with its axis lock and bounce. TabBar, the attachment row,\nthe app menu bar and a horizontal `Scrollable` use it. The mask is pinned to its\nparent's top-left corner, so it covers the parent in a row as in a column.\n\nOne handle represents one logical viewport. Sharing a handle between nested or\nunrelated scroll areas causes offsets, hitboxes, and scrollbar geometry to\ninterfere.\n\n## Dock Layout Architecture\n\n`crates/base/src/dock` owns the layout tree, persistence, drag hit-testing,\nresize arithmetic, the active-panel state machine, zoom, focus, and the panel\nregistry. `crates/component/src/dock` is a skin: `DockSkin` implements the renderer\ntraits below to supply the tab bar, toolbar, drop-indicator, and dock-toggle\nappearance. A `DockArea` built without a renderer still docks, drags, and\npersists — it draws no chrome at all.\n\n### The layout tree\n\n`PaneTree` is the single source of truth for one region — the center, or\none of the left/bottom/right docks. It stores no GPUI entity handles:\ncontainers are addressed by `NodeId`, panels by `PanelId` (the panel entity's\n`EntityId`), and a container's `NodeKind` is one of `Split` or `Tabs`. There\nis no leaf variant, so a panel can only ever live inside a `Tabs` node — the\ninvariant a runtime assertion checked in the old implementation is expressed\nin the type instead.\n\n`NodeKind` stays private. Callers read a node through the borrowed `PaneRef`\nprojection and never construct one directly; every mutation goes through\n`PaneTree`'s edit methods (`insert_panel`, `remove_panel`, `move_panel`,\n`split`, `set_active`, `set_sizes`), each\nof which runs `normalize` before returning. When base needs a fact about a\npanel — its name, its visibility, its dump — it asks a `PanelSource` rather\nthan the entity directly, which is what makes the layout algebra testable as\npure functions with no `TestAppContext`.\n\nBuilding a layout is entity-free too: `DockLayout` (`h_split`, `v_split`,\n`tabs`, chained with `.child(...)`, `.panel_view(...)`, and\n`.active_index(...)`) produces a tree rather than\nconstructing containers. `DockArea::set_center` and `set_dock` reconcile a\n`DockLayout` into live entities when it is installed.\n\nPanels go in wrapped: `gpui_component::dock::panel_handle(panel)` is what\ncarries a panel's presentation across the renderer seam, and every entry point\ntakes one — `DockLayout::panel_view` when describing a layout,\n`DockArea::add_panel_view` when adding to a live one, and\nthe closure a `register_panel` builder returns.\n\n```rust,ignore\nlet center = DockLayout::h_split()\n    .child(DockLayout::tabs().panel_view(panel_handle(files), cx), Some(px(240.)))\n    .child(DockLayout::tabs().panel_view(panel_handle(editor), cx), None);\ndock_area.update(cx, |area, cx| area.set_center(center, window, cx));\n```\n\nBase's own `DockLayout::panel` and `DockArea::add_panel`\ntake a bare `Entity<P>` instead. They are the base-only forms: the panel docks,\ndrags and persists exactly the same, but base stores the bare entity and the\nskin cannot recover presentation from it, so **every tab draws the panel's\n`panel_name` where its title belongs**. The only signal is a one-off\n`tracing::warn!`. Use them only when there is no skin over the dock at all.\n\n### Normalization\n\nOne post-order pass, repeated to a fixpoint, replaces the mutually recursive\nparent-pointer collapse the old `StackPanel`/`TabPanel` pair used:\n\n1. An empty `Tabs` or `Split` is removed from its parent; the root\n   is exempt.\n2. A `Split` with one child is replaced by that child, which keeps its own\n   `NodeId` and inherits the split's slot size.\n3. A `Split` containing a `Split` of the same axis splices the inner\n   children into the outer node.\n4. `active_ix` is clamped to the panel count.\n5. Root shape is enforced per `RootKind` — the center's root is always a\n   `Split`, so an empty center still serializes as a stack; a dock's root is\n   unconstrained.\n\n`normalize` is idempotent and needs no parent pointers or deferred work: the\ntree is self-consistent the instant an edit operation returns.\n\n### Reconciliation\n\n`DockArea` holds the tree plus a cache of container and panel entities keyed\nby `NodeId` and `PanelId`. After any edit that reports a change, it walks the\ntree, creates an entity for each container id the cache does not yet have,\ndrops cache entries for ids no longer present — calling `on_removed` on the\npanels that departed — pushes sizes and `active_ix` into the surviving\nentities, and emits `DockEvent::LayoutChanged`.\n\nBecause `NodeId` survives every edit operation and every `normalize` rule, a\nsteady-state reconciliation pass creates and drops nothing: only genuinely\nnew or dead containers churn. That is what keeps a drag from resetting the\nstate of panels it did not touch.\n\n### Rendering seam\n\n`TabGroup` owns the panel list mirrored from the tree, the active index, the\nfocus handle, drag-and-drop hit state, and the zoom flag; it renders a\nskeleton and delegates all appearance to a `TabGroupRenderer`.\n`DockAreaRenderer` does the same for the area frame and the docks. Base\nattaches the drag source, drop-target hit testing, keyboard actions, and focus\nhandling — a renderer implementation never sees a drag event, only resolved\nstate through `TabGroupContext` and `DockContext`.\n\n`Panel` splits at the seam the same way: `gpui_base::dock::Panel` covers\nbehavior (`panel_name`, `visible`, `closable`, `zoomable`, `set_active`,\n`set_zoomed`, `on_added_to`, `on_removed`, `dump`), and\n`gpui_component::dock::Panel` extends it with presentation (`title`,\n`tab_name`, `toolbar_buttons`, `dropdown_menu`, `zoom_control`). A panel type\nimplements both.\n\n## Theme Projection\n\nThe base `Theme` contains:\n\n- `SemanticThemeTokens` for colors, radius, spacing, typography, and shadows;\n- global Scrollbar defaults;\n- the minimal Resizable handle colors required by its infrastructure.\n\nSemantic tokens describe roles and scales, never component names. They do not\nautomatically style base controls. A presentation layer reads and applies them.\n\n`gpui-component` projects its active theme into the base theme during\ninitialization and theme changes. Direct base users can mutate\n`gpui_base::Theme::global_mut(cx)` themselves.\n\n## Motion and Lifecycle\n\nOrdinary semantic controls do not install product motion. The generic\n`motion::transition` function manages keyed interpolation, timing, reversal,\nanimation frames, and reduced-motion behavior while the caller chooses the\nanimated property.\n\nSome deep behavior modules own configurable motion that is inseparable from\ntheir layout lifecycle. `ToastStack`, for example, owns stack expansion,\ncollapse, measurement, and overlap motion through `ToastMotion`. Its child\n`Toast` remains an unstyled semantic root, and the application owns toast\ncontent and visual styling.\n\nThis distinction is intentional:\n\n- product decoration and choreography belong to presentation;\n- motion required to keep a deep behavioral layout coherent may live in that\n  module and must be configurable.\n\n## Initialization\n\nCall `gpui_base::init(cx)` before constructing base controls. Initialization:\n\n- installs the base global theme if absent;\n- initializes shared global state;\n- reads the operating system's reduced-motion preference into\n  `App::set_reduce_motion` (see `reduce_motion.rs` for the per-platform\n  sources and the rule that an application's own setting wins);\n- registers key bindings and infrastructure for dialog, focus traps, popover,\n  sheet, combobox, color picker, select, number input, input, and tree.\n\nApplications that call `gpui_component::init(cx)` must not initialize base a\nsecond time; the styled crate includes base initialization.\n\n## Relationship to `gpui-component`\n\n`gpui-component` is a presentation adapter and compatibility layer above base.\nIt may:\n\n- map its Theme into base tokens and infrastructure defaults;\n- wrap base elements with labels, icons, sizes, variants, and product layout;\n- provide application-specific popup menus, LSP views, and native integrations;\n- preserve historical public interfaces while delegating behavior to base.\n\nThe migration of a UI control to a base module is complete only when behavior,\nfocus, keyboard interaction, accessibility, overlay geometry, and visual output\nremain correct. Sharing a type name or compiling an adapter is not sufficient.\n\n## Design Invariants\n\nChanges to `gpui-base` should preserve these invariants:\n\n1. Base remains independent of `gpui-component` presentation and assets.\n2. Reusable behavior is implemented once behind the lowest useful interface.\n3. Applications can replace the visual language without reimplementing the\n   behavior module.\n4. Behavioral geometry stays with the module that must keep it correct.\n5. Controlled elements report intent and do not own application values.\n6. Stable element identity is documented wherever keyed state is used.\n7. Pointer and keyboard paths converge on the same semantic action.\n8. Accessibility is behavior, not optional decoration.\n9. Overlay coordinates, paint order, and hitboxes use one viewport model.\n10. One scroll handle represents one logical viewport.\n11. Platform differences are isolated behind explicit adapters or conditional\n    implementations.\n12. Public types that cross the seam keep their fields private, are built with a\n    builder, and are read through methods, so a new field is not a breaking\n    change.\n13. Long-lived architectural facts belong here; progress logs and temporary\n    reviews belong in issues and pull requests.\n","skills/gpui-kit-design-guides/SKILL.md":"---\nname: gpui-kit-design-guides\ndescription: The normative Design Guides for GPUI Kit desktop applications. Read in full before designing or changing any screen, layout, spacing, visual hierarchy, color, density, component choice, interaction state, overlay, motion, data-heavy view, or interface copy in a GPUI Kit (gpui-kit / gpui-component) application, and before reviewing UI work for design quality. Also use when asked what the design rules are, or whether a UI decision follows them.\n---\n\n# GPUI Kit Design Guides\n\nThe guide is [references/design-guides.md](references/design-guides.md). It is\na requirement, not inspiration. Read the guide file itself before doing UI\nwork. Do not answer from this page, from an existing screen in the codebase, or\nfrom training data.\n\nIf the file is missing, fetch `https://gpui-kit.com/docs/design-guides.md`.\nThe guide is a verbatim copy of that page, so its link to `./coding-guides.md`\nmeans the Coding Guides in the `gpui-kit` skill (or `https://gpui-kit.com/docs/coding-guides.md`).\n\n## How to read it\n\nRead the whole guide for a new screen or a redesign. For a narrow change, read\n\"Design thesis\" and \"Start from the task\" first, then the section for the\nchange. Sections, in order (`grep -n '^## ' references/design-guides.md`):\n\n| Section                              | Read when                                                              |\n| ------------------------------------ | ---------------------------------------------------------------------- |\n| Design thesis                        | Always                                                                 |\n| Learning from Shadcn                 | Choosing what to borrow from web component libraries                   |\n| Start from the task                  | Always; task hierarchy, interaction promise, what to leave out         |\n| Visual language                      | Color, typography, spacing, radius, borders, elevation, density, icons |\n| Layout patterns                      | Window structure, sidebars, toolbars, panels, forms, resizable regions |\n| Components and composition           | Picking a component, composing parts, when to build a new one          |\n| Interaction states                   | Hover, focus, pressed, selected, disabled, loading, validation, danger |\n| Feedback and overlays                | Dialog, sheet, popover, menu, notification, tooltip, dismissal, focus  |\n| Motion                               | Any animation or transition                                            |\n| Designing data-heavy interfaces      | Tables, lists, trees, dashboards, dense inspectors                     |\n| Interface language                   | Any user-facing text: labels, buttons, titles, errors, empty states    |\n| Internationalization and platform fit | Multi-locale copy, Chinese terminology, macOS/Windows conventions     |\n| Guidance for AI-generated interfaces | Always when an agent produces UI                                       |\n| Accessibility checklist              | Before finishing                                                       |\n| Design review checklist              | Before finishing; run every item against the work                     |\n\n## Non-negotiables\n\nA floor, not a substitute for the guide.\n\n- **Desktop before web convention.** Keyboard access, window chrome, menus,\n  dense data views, resizable regions, persistent navigation.\n- **`Button` vs `Link`.** `Button` for every in-app command, `ghost` or\n  `outline` when it should read quietly. `Link` only for external URLs and\n  email addresses.\n- **Tokens before values.** No raw hex or `rgb(...)`; use `cx.theme()`\n  semantic tokens and rem-based helpers. Any spacing number quoted in the guide\n  is the current default scale, not a literal to repeat.\n- **State must be visible.** Hover, focus, selection, disabled, loading,\n  validation, and destructive states each need distinct, consistent treatment.\n- **Overlays.** Escape dismisses the topmost surface and returns focus to its\n  trigger.\n- **Copy.** Name the object and the verb: `Delete \"Roadmap\"?` with a `Delete`\n  button, not `Are you sure?` with `OK`.\n\nFinish by running the Design review checklist against the work.\n","skills/gpui-kit-design-guides/references/design-guides.md":"---\ntitle: Design Guides\ndescription: Product and interaction design guidance for GPUI Kit applications\norder: -12\n---\n\n# Design Guides\n\nUse this guide before choosing components or writing layout code. It records\nthe product judgment accumulated through years of GPUI Kit desktop work:\nan interface should feel native, restrained, precise, and understandable\nwithout guesswork.\n\nThis is a normative guide. **Must** identifies a correctness or ecosystem\nconstraint, **should** is the default that needs a concrete reason to override,\nand **may** is an optional technique. Component API documentation remains the\nauthority for individual methods.\n\nThe rules build on behavior in `gpui-base`, the GPUI Component theme and\ncomponent system, and familiar desktop interaction. <a href=\"https://ui.shadcn.com/docs\" target=\"_blank\" rel=\"noopener noreferrer\">shadcn/ui</a> contributes useful\nmethods—open code, composition, and dependable defaults—but does not determine\nhow a GPUI application should look. When influences conflict, preserve GPUI's\nlifecycle constraints and the interaction people already understand.\n\n## Design thesis\n\nBuild interfaces that feel native, quiet, and precise. Let content, hierarchy,\nand interaction carry the experience; decoration should support them rather\nthan compete with them.\n\n1. **Clarity before personality.** Make the primary task and next action clear\n   before adding brand expression.\n2. **Composition before invention.** Start with established components and\n   compose them into product-specific workflows. Create a new primitive only\n   when its behavior is genuinely new.\n3. **Tokens before values.** Colors, radii, typography, and spacing should form\n   a system. Avoid isolated literals that cannot respond to themes. See\n   [Style](./style) for GPUI's styling API.\n4. **Desktop before web convention.** Preserve keyboard access, window chrome,\n   menus, dense data views, resizable regions, and persistent navigation where\n   the task benefits from them.\n5. **State must be visible.** Hover, focus, selection, disabled, loading,\n   validation, and destructive states need distinct and consistent treatment.\n6. **Geometry explains containment.** Radii, insets, and boundaries should\n   describe one coherent hierarchy, even where surfaces overlap.\n7. **Feedback reflects reality.** Loading, tooltips, and motion should clarify\n   a real state or transition, not add ceremony to an immediate action.\n\n## Learning from Shadcn\n\nShadcn's most useful contribution is not a particular border color. It is a\nway of building a system:\n\n- own the top layer of the interface instead of fighting a sealed abstraction;\n- compose small, predictable parts into product-specific components;\n- provide defaults that already form one visual language;\n- keep the code and composition legible to both people and AI;\n- separate behavior primitives from the styled layer.\n\nGPUI Kit applies those ideas through a Rust library and the split between\n`gpui-base` and `gpui-component`. Applications normally compose or wrap the\npublished components; contributors move genuinely reusable behavior into Base\nand keep visual policy above it.\n\nDo not copy these web assumptions blindly:\n\n| Web habit | Native GPUI default |\n| --- | --- |\n| Pointing-hand cursor on every button | Default arrow cursor; pointing hand for links |\n| Page navigation as the main structure | Persistent windows, panes, sidebars, tabs, and menus |\n| Browser focus and scrolling as a fallback | Explicit focus ownership and region-owned scrolling |\n| Mobile-first single column | Resizable desktop shell with a defined minimum window size |\n| Hover-revealed critical actions | Keyboard- and pointer-reachable actions that do not depend on hover |\n| A row of hover-only icon buttons | A visible primary action plus `DropdownMenu` or `ContextMenu` for secondary commands |\n| Link-styled text for application commands | `Button`, `outline`, or `ghost`; Link only for URLs, web resources, or email addresses |\n| Large touch density everywhere | Medium density by default; compact only where information work benefits |\n| CSS overrides across descendants | Typed builders, semantic parts, and application composition |\n\n## Start from the task\n\nBefore drawing a screen, write down:\n\n- the user's primary task;\n- the object being viewed or changed;\n- the actions that must remain immediately available;\n- the information required to make a decision;\n- empty, loading, error, offline, read-only, and permission-denied states;\n- the keyboard path through the workflow.\n\nOrganize the window around those answers. Do not begin with a dashboard grid or\na component catalogue. A good desktop interface exposes the user's mental\nmodel: documents, accounts, projects, messages, settings, or another stable\nobject—not the internal service architecture.\n\nDesign the primary task before distributing controls. Its visual weight,\nlocation, and information depth should match its importance to the product. A\ncore result must not be reduced to a small count, an icon in a corner, or a\nweak footer action while secondary content consumes the page. When a result set\nis the product's main value, consider a summary region or card that exposes the\ncount, representative results, meaningful state, and a clear next action.\n\nFor every proposed action, name its visible object, current state, scope, and\nresult. If the interface does not show or clearly imply those things, the\naction is premature. Do not expose a capability merely because the backend has\nit; first design how the object enters the user's mental model.\n\n## Visual language\n\n### Hierarchy\n\nPrefer a small number of clear levels:\n\n- **window or page title** identifies the current object or workspace;\n- **section title** separates meaningful regions;\n- **body text** carries the work;\n- **muted text** provides secondary metadata and help;\n- **labels** identify controls and values.\n\nUse size, weight, spacing, and separators before adding color or containers.\nAvoid nesting cards inside cards: most desktop regions need only a background,\na hairline boundary, and intentional spacing.\n\nEvaluate hierarchy across the whole feature, not component by component. Hide\naccent color and decoration during review: the primary task, current selection,\nresult summary, and next action should still be obvious from structure. A\nscreen that contains individually plausible controls can still fail when they\ndo not form one reading order and one decision path.\n\nTreat emphasis as a limited budget. A local surface needs one clear focal point,\nnot a field of competing highlights. If everything is colored, badged, bold,\nboxed, or promoted to an alert, nothing reads as important. Establish priority\nwith structure and proximity first; spend stronger color and components only\nwhere a distinction changes what the user notices or does.\n\n### Color and themes\n\nRead colors from `cx.theme()` and use them by semantic role:\n\n- `background` and `foreground` for the main surface and text;\n- `group_box`, `popover`, `sidebar`, and their foreground tokens for their\n  named surfaces;\n- `muted` and `muted_foreground` for supporting information;\n- `primary` for the principal action or selection emphasis;\n- `danger`, `warning`, `success`, and `info` only for their meanings;\n- `border`, `input`, and focus-ring tokens for structure and interaction.\n\nDo not use a semantic status color as decoration. Do not encode meaning by\ncolor alone. Verify every custom surface in light and dark themes and with\ncustom theme values; never assume that foreground is black or background is\nwhite.\n\nUse Badge for a short state, count, or classification that benefits from rapid\nscanning—not for every label, metadata value, filter, or section title. Keep\nmost badges neutral; reserve semantic variants for states that truly carry\nsuccess, warning, danger, or informational meaning. A row of multicolored\nbadges is usually a missing hierarchy or grouping decision.\n\nApplication UI should not contain raw hex, `rgb`/`rgba`, or `hsla` colors.\nResolve colors from `cx.theme()` by semantic role. If the required role does\nnot exist, define it in the product's theme/token layer rather than embedding a\npalette value at the call site. Raw colors belong only inside theme definitions\nor in audited data/raster content whose color is itself the data.\n\n### Radius, spacing, and density\n\nUse a finite radius scale, as with type and control sizes. Choose from the\ntheme's named tiers (`sm`, `md`, `lg`, `xl`, and larger surface tiers) instead\nof inventing a radius for each element. Large containers may use a softer tier\nthan the controls they contain; compact controls and overlays use tighter\ntiers. For an ordinary rectangle, the radius should remain visibly smaller\nthan half its shorter side. Use `radius_full()` only for intentional circles\nand pills; a tooltip must not become a capsule by accident.\n\nNested surfaces should read as concentric shapes. Use\n`inner radius ≈ max(0, outer radius − gap)` to choose the closest suitable\ntheme tier; the visible band should remain even through the turn. Add a\nnamed application token if a repeated composition needs an intermediate\nvalue. A segmented control is one silhouette: its end segments follow the container's inner\ncorners, its middle segments remain square, and each boundary has one divider\nof consistent thickness.\n\n<img class=\"alignment-light\" src=\"/radius-hierarchy.svg?v=20260923-easing\" alt=\"Light theme chat composer: the inset surface, both buttons, and placeholder spacing change together; red guide circles show their shared corner center.\">\n<img class=\"alignment-dark\" src=\"/radius-hierarchy-dark.svg?v=20260923-easing\" alt=\"Dark theme chat composer: the inset surface, both buttons, and placeholder spacing change together; red guide circles show their shared corner center.\">\n\nA radius must govern the entire visible surface, not just its border. Exposed\ncorners remain transparent to the surface behind them; child backgrounds,\nselection fills, and scrolling content must also follow the boundary. In GPUI,\ndo not assume a rounded parent clips its descendants. Give inner surfaces their\nown radius or an appropriate clip, then inspect the composition against a\ncontrasting background in both themes. Preserve outward focus rings when\nchoosing a clip.\n\nUse a compact spacing scale and repeat it. Related label/control pairs should\nbe closer than separate groups; separate groups should be closer than separate\nsections. Prefer component sizes (`xsmall`, `small`, default medium, `large`)\nover one-off heights. Use compact variants for toolbars and data-dense screens,\nnot to squeeze an unclear layout into less space.\n\nThe shared semantic scale is intentionally small: spacing progresses through\nroughly 2, 4, 8, 12, 16, 24, and 32 pixels, while typography stays near 12,\n14, 16, 18, and 20 pixels. Treat these as relationships rather than permission\nto scatter their current values through feature code. GPUI Component currently\nprojects a fixed default `SpacingTokens` scale from its global `Theme`; unlike\ncolors and radii, `Theme::apply_semantic_tokens` does not persist a custom\nspacing scale. An application that needs different spacing must own that full\ntoken snapshot and use it consistently in its application components.\n\n### Spatial grammar\n\nSpacing expresses relationship. Choose a gap from the semantic scale by asking\nwhat the two things mean to each other:\n\n| Relationship | Typical token | Current scale | Examples |\n| --- | --- | --- | --- |\n| Optical correction | `xxs` | 2 px | icon baseline, compact separator |\n| Parts of one control | `xs` | 4 px | menu icon/label, title/description |\n| Closely related controls | `sm` | 8 px | button icon/label, dialog actions |\n| One content group | `md` | 12 px | notification columns, compact form rows |\n| Separate groups in one section | `lg` | 16 px | panel padding, form groups |\n| Separate sections | `xl` | 24 px | major blocks in a page or inspector |\n| Major region boundary | `xxl` | 32 px | empty-state breathing room, page bands |\n\nThese values describe the current default scale, not literals to repeat. Use\n`cx.theme().spacing_tokens()` or the corresponding GPUI scale helpers for the\necosystem default. A product-owned scale should preserve the ordering and\nrelationships and must be passed through the application's own design-system\ncontext rather than assumed to persist in the global GPUI Component theme.\n\nUse these rules when resolving horizontal and vertical space:\n\n1. **Inside before outside.** A component's padding belongs to the component;\n   the gap between components belongs to their parent.\n2. **Vertical rhythm shows grouping.** The gap between a title and its\n   description is smaller than the gap from that description to the next\n   section. Equal gaps imply equal relationships.\n3. **Horizontal space supports scanning.** Repeated rows keep icons, labels,\n   values, badges, and trailing actions on stable columns.\n4. **Leading and trailing are semantic.** Think in reading-order edges even\n   when the current API uses left/right; this keeps future RTL adaptation\n   possible.\n5. **Do not double padding.** A card placed in an already padded panel should\n   not automatically add another full panel inset.\n6. **Use optical alignment sparingly.** A one- or two-pixel correction is valid\n   for icon or glyph geometry, but document why it differs from the scale.\n\nCommon compositions in the current system illustrate the relationships:\n\n- button contents use 4 px at small sizes and 8 px at normal sizes;\n- dialog headers and footers use an 8 px internal gap;\n- compact list and menu rows use 4 px vertical and 8–12 px horizontal padding;\n- sheet headers use about 16 px leading and 12 px trailing space, leaving room\n  for a close affordance, while footers use 16 px horizontal and 12 px vertical\n  space;\n- notifications use 16 px horizontal padding and a 12 px column gap because\n  icon, message, and action are distinct groups.\n\nDo not treat these as copy-and-paste recipes for every surface. They reveal the\nsystem: controls are tighter internally, rows optimize scanning, and\ncontainers spend more space at their boundary than between their contents.\n\n### Proportion and layer hierarchy\n\nStart with content requirements, then set proportions. Avoid arbitrary halves\nwhen one pane has a clearly different role.\n\n- A navigation sidebar should be wide enough for stable labels but visibly\n  subordinate to the work area. Give it a minimum, preferred, and maximum\n  width rather than a percentage alone.\n- In master–detail layouts, let the collection remain scannable and give the\n  detail pane the surplus. A roughly one-third/two-thirds starting point is\n  often useful, but content constraints are authoritative.\n- Inspectors and auxiliary sheets should not cover the primary object by\n  default. They should be resizable or dismissible when their content grows.\n- Dialog width comes from the decision: short confirmation, medium form, or a\n  dedicated window/page for complex work. Do not enlarge a dialog simply to\n  create whitespace.\n- Reserve the strongest elevation for the topmost decision layer. Within a\n  layer, use background and hairlines—not successively larger shadows—to show\n  hierarchy.\n\nDefine three size constraints for every major region: the minimum at which its\ntask still works, a comfortable default, and how it consumes surplus. Persist\nuser-controlled splits when they represent workflow preference, and clamp\nrestored values against the current window.\n\n### Alignment details\n\nAlignment is a structural system, not a final polish pass. Establish a small\nset of alignment spines for each surface: shared leading and trailing edges,\ntext baselines, center lines, and fixed functional lanes. Elements at the same\nlevel should attach to the same spine from top to bottom or leading to trailing,\neven when they are different component types.\n\n<img class=\"alignment-light\" src=\"/alignment-spines.svg?v=20260822-4\" alt=\"Alignment spines across a desktop surface\">\n<img class=\"alignment-dark\" src=\"/alignment-spines-dark.svg?v=20260822-4\" alt=\"Alignment spines across a desktop surface\">\n\nVertical red lines sit beside shared edges or control centers for content,\nstatus, time, and trailing actions. Horizontal lines sit beneath text baselines\nor pass through a row center to show bottom and vertical-center alignment. The\ncompact comparison isolates a one-rendered-pixel drift that must be corrected\nat its structural owner.\n\n- Give sibling regions a shared content inset. A heading, toolbar, list row,\n  empty state, and footer that describe the same level should not each invent a\n  slightly different leading edge.\n- Repeat column geometry through the whole region. Headers, rows, summaries,\n  loading states, and inline editors should reserve the same lanes for identity,\n  metadata, status, numbers, and actions.\n- Align related controls across rows and sections. Form labels, fields,\n  descriptions, and validation messages should reveal a stable vertical grid\n  when the page is scanned from top to bottom.\n- Keep horizontal bands coherent. Items sharing a toolbar, title bar, status\n  bar, or row should use one baseline or center line instead of individually\n  tuned offsets.\n- Introduce indentation only for real hierarchy, containment, or disclosure.\n  Decorative indentation makes siblings look subordinate and breaks the\n  surface's reading line.\n- When a nested level ends, return exactly to the parent spine. Do not let\n  accumulated padding drift across nested containers.\n- Preserve the spine through optional content. Missing icons, badges,\n  descriptions, or trailing actions must not move the remaining labels; use\n  intentional slots or lanes when cross-row comparison matters.\n- Align major regions with one another where their hierarchy matches. Sidebar\n  headers, content titles, split panes, toolbars, and bottom bars need not share\n  every coordinate, but coincident levels should form visible continuous lines.\n\nNot every edge should align. A child can indent, a primary value can lead its\nsupporting metadata, and a destructive decision can gain separation. Such\nexceptions must communicate hierarchy or meaning; they must not result from\nuncoordinated component padding. Start with the shared spine, then make the\nexception explicit.\n\nTreat exact alignment and repeated gaps as quality invariants. When two edges\nor spaces are intended to be equal, a one-rendered-pixel difference is a defect,\nnot an acceptable optical approximation. Inspect resolved bounds with a\nmeasurement tool at representative window sizes, zoom levels, and display scale\nfactors. Compare coordinates and distances; do not approve alignment only from\na casual screenshot.\n\nThe rendered-pixel tolerance is a verification rule, not permission to patch\nthe code with raw pixel offsets. Equal relationships should resolve from the\nsame `rem` helper, spacing token, grid definition, or shared component inset.\nFix the common owner when they differ. Account for fractional layout and device\nrounding so intended spines land on the same physical pixel instead of drifting\nat particular zoom levels.\n\n- Align text by baselines, not by bounding-box centers, when mixed sizes share\n  a row.\n- Center icons in a fixed slot so labels do not move when icons differ in\n  intrinsic width.\n- Right-align comparable numbers; left-align prose and identifiers unless the\n  locale requires otherwise.\n- Keep trailing row actions and disclosure indicators in fixed-width lanes.\n- Align form controls by their interactive frame, not by help text below them.\n- Use `justify_between` only when the two sides truly own opposite edges; it\n  should not disguise missing structure in the middle.\n- Hairlines belong on the boundary owner. Two adjacent regions must not each\n  draw the same separator.\n- A scrollbar belongs to the region that scrolls and sits against that panel,\n  editor, or window's trailing edge. Content padding may inset text and rows;\n  it must not pull the scrollbar into the middle of the surface. Reserve a\n  deliberate scrollbar gutter when content needs clearance.\n\n### Density tiers\n\nMedium is the ecosystem default. Change density for the whole local context,\nnot one isolated control:\n\n- **comfortable / large:** onboarding, sparse forms, prominent decisions;\n- **standard / medium:** most application chrome and workflows;\n- **compact / small:** toolbars, menus, tables, and repeated professional data;\n- **extra compact / xsmall:** exceptional high-density utilities, never the\n  automatic choice for an entire application.\n\nThe current controls demonstrate a bounded scale rather than arbitrary sizing:\nbuttons commonly move through approximately 20, 24, and 32 px frames; input\nand data controls may extend to about 44 px at large size; table rows use about\n26, 30, 32, and 40 px. Use the component's `Size` API so typography, icon,\npadding, and hit target change together. A custom height that changes only the\nouter box is usually incomplete.\n\n### Zoom, base font, and `rem`\n\nA well-designed `rem` system preserves hierarchy while the interface zooms.\nZoom is successful when the relationship between title and body, control and\nicon, inner and outer spacing, primary and secondary regions still feels the\nsame at every scale—not merely when every object becomes larger.\n\nGPUI Component adopts the relative-scale idea familiar from <a href=\"https://tailwindcss.com/docs/theme\" target=\"_blank\" rel=\"noopener noreferrer\">Tailwind CSS</a>. The\ntheme's base `font_size` becomes the window's `rem` through `Root`, and GPUI\nscale helpers such as `text_sm()`, `gap_2()`, `p_4()`, `h_8()`, and `size_4()`\nresolve against it. This gives typography, spacing, controls, and icons one\nshared zoom axis.\n\nDesign in ratios:\n\n- type steps keep the same hierarchy around the base body size;\n- spacing steps keep the same grouping relationships around the type;\n- control frames, icons, and hit targets scale with their labels;\n- pane minima and comfortable widths account for the scaled content;\n- corner radii and focus treatment remain optically consistent with the\n  control frame.\n\nDo not implement zoom by changing text size alone. A larger label inside a\nfixed-height button, a larger document inside fixed pane minima, or larger rows\ninside a stale virtual-list measurement destroys the original rhythm and can\nclip content. Conversely, multiplying every physical pixel—including\nhairlines—can make the interface visually heavy.\n\nAs a rule, application layout should not call `px(...)` directly. Use GPUI's\nrem-based scale helpers (`p_2`, `gap_3`, `w_64`, `text_sm`, and related\nbuilders) or semantic component sizes. Use fixed pixels only when the value\nrepresents a physical or raster boundary:\na one-device-pixel hairline, platform window inset, bitmap dimension, minimum\nhit-test tolerance, or geometry that must match an external surface. These are\naudited, documented exceptions. Product spacing, typography, icon size, and\nordinary control geometry stay on the relative scale.\n\nTest interface zoom at several base-font values, not just the default. Verify\nhierarchy, wrapping, truncation, minimum window size, pane resizing, focus-ring\nclearance, popup placement, and virtualized row measurement. Also distinguish\ninterface zoom from Dock's panel zoom: Dock zoom makes one container fill its\narea while retaining its chrome; it does not change `rem` or application scale.\n\n### Surfaces and elevation\n\nUse elevation to explain stacking, not importance. The base window surface is\nflat; separators and background contrast define its regions. Popovers, menus,\ndialogs, and notifications may use progressively stronger shadows because they\nsit above other content. Do not put a shadow on every card.\n\nAll surfaces of the same kind should share one treatment. GPUI Component, for\nexample, deliberately gives popup families one themed popover surface so\nPopover, Select, Combobox, DatePicker, and menus do not drift apart. When an\napplication invents another anchored surface, reuse that semantic treatment\ninstead of approximating it with unrelated border and shadow literals.\n\n### Typography and icons\n\nUse the platform UI font for interface text and monospace only for code,\nidentifiers, shortcuts, and aligned numeric data. Keep body text readable and\navoid excessive uppercase or letter spacing, especially for CJK text.\n\nUse one icon family in a product. Icons supplement labels; they should not\nreplace unfamiliar actions with guesswork. Icon-only buttons always need an\naccessible name. Their visual explanation follows the tooltip policy below.\nUse filled or colored icons to communicate a state, not merely to make a\ntoolbar lively.\n\n## Layout patterns\n\n### Choose a stable shell\n\nMost applications should use one of these shells:\n\n- **single workspace:** toolbar or title bar above one primary view;\n- **sidebar workspace:** persistent navigation beside a changing detail view;\n- **master–detail:** resizable collection and detail panes;\n- **document workspace:** tabs or a dock area for multiple long-lived objects;\n- **utility window:** one focused task with a short, fixed action path.\n\nKeep global navigation stable while content changes. Give the primary work area\nthe remaining space with `flex_1()` and `min_w_0()` / `min_h_0()` where\noverflowing children must shrink. Use `Scrollable`, `VirtualList`, `Table`, or\n`DockArea` for their intended behavior instead of rebuilding scrolling or pane\nmanagement from nested `div`s.\n\nThe title bar is window chrome first. Preserve its drag region and avoid\nbinding ordinary title clicks to infrequent editing commands. Rename belongs\nbehind an explicit object command, with a keyboard path where appropriate.\n\n### Responsive desktop windows\n\nDesktop does not mean fixed-size. Decide what happens as a window narrows:\n\n1. preserve the primary task;\n2. allow resizable regions to reach a documented minimum;\n3. collapse secondary labels or inspectors;\n4. move low-frequency actions into a menu;\n5. scroll only the region whose content actually overflows.\n\nDo not hide an action without providing another path to it. Avoid making the\nentire window scroll when only a list or document body should scroll.\n\nGPUI flex layouts have the same intrinsic-size pressure found in other layout\nsystems: a `flex_1()` child may still refuse to shrink around long content.\nDesign and implementation must agree on which panes may shrink, truncate, wrap,\nor scroll. A clipped region also clips an outward focus ring; never trade away\nkeyboard visibility merely to simplify overflow.\n\n### Forms and settings\n\nUse a visible label for each field and place help or validation next to the\nfield it describes. Align related fields, but do not force long labels into a\nnarrow fixed column. Use the appropriate control: `Checkbox` for independent\nchoices, `RadioGroup` for a small visible set, `Select` for a longer set, and\n`Switch` for a setting that takes effect immediately.\n\nDisable submission while an operation is in flight, keep the user's input, and\nshow the result near the action. Reserve dialogs for short, focused decisions;\nuse a full page or sheet for workflows that need exploration or many fields.\n\nA loading treatment must represent actual waiting. Switching between settings\npanels whose content is already available should be immediate; a skeleton is\nappropriate only while content is genuinely loading and its shape is known.\n\n## Components and composition\n\nFollow the Shadcn principle that components are building material rather than a\nsealed design system. GPUI Component supplies coherent defaults, while the\napplication owns composition and product semantics.\n\n- Use component variants by meaning. Primary is reserved for the explicit\n  default commit in a decision area—normally the action invoked by Enter. A\n  lone, frequent, or desirable action is not automatically primary. An `Add`\n  command in a management toolbar normally uses a default Button; a form's\n  default `Create` commit may use primary. Use `danger` for destructive\n  commitment and `ghost` for quiet toolbar actions.\n- Prefer explicit compound parts and render callbacks over styling arbitrary\n  descendants.\n- Keep a repeated pattern consistent across the product. Wrap it in an\n  application component when it carries domain language or policy.\n- Use the standard component for its semantic role. A menu, dropdown menu,\n  popover, select, and command palette are not interchangeable boxes; each owns\n  different selection, focus, keyboard, dismissal, and layout contracts.\n- Preserve the component family's geometry. Menu rows share vertical and\n  horizontal padding, height, icon and checkmark slots, separators, radius, and\n  state treatment. Do not imitate one menu with a custom popup whose spacing\n  only approximates the system.\n- Do not wrap a library component merely to rename every method or freeze all\n  of its capabilities.\n- Move reusable behavior without product styling to `gpui-base`; keep themed,\n  opinionated presentation in GPUI Component or the application.\n\n## Interaction states\n\n### Make the result understandable before the click\n\nA control should predict its result. Use familiar desktop controls and\nplacement so people can act without learning the interface first. Its label\nnames the action and object, its state shows availability, and its feedback\nconfirms the same outcome.\n\nDo not label a Button `Save` if it opens a configuration flow, or `Delete` if\nit only removes an item from a group. Name the scope when context does not make\nit clear. Respond immediately to activation, prevent duplicate submission\nduring longer work, and show the result near the object that changed. Add a\nsuccess message only when the result itself is not visible.\n\nEvery interactive control should be designed for:\n\n| State | Design requirement |\n| --- | --- |\n| Rest | Clear affordance without visual noise |\n| Hover | Subtle pointer feedback, never the only cue |\n| Pressed | Immediate press feedback |\n| Open / pressed | Persistent feedback while an attached popup is open |\n| Focus visible | High-contrast keyboard focus ring |\n| Selected / checked | Persistent state distinct from hover |\n| Disabled | Lower emphasis and no misleading hover/pressed response |\n| Loading | Preserve context, prevent duplicate action, explain long waits |\n| Error | State what happened and how to recover |\n\nUse GPUI's focus system and Actions for commands that should work from the\nkeyboard. Match familiar desktop shortcuts, expose shortcuts in menus or\ntooltips, and keep focus in a logical place after opening or dismissing an\noverlay.\n\nSelection is part of the information model, not optional polish. Tabs,\nsegmented choices, selectable rows, filters, and navigation destinations must\nshow a persistent selected state. A Button that owns a dropdown must remain\nvisibly pressed or open until the popup closes; hover alone cannot explain the\nrelationship between trigger and surface.\n\nIn a segmented control, the selected fill and unselected surface must share\nthe container's silhouette. Neither may square off an end corner or make a\nboundary appear heavier than its peers.\n\nShow a selected navigation item, list row, or tab through the item's own\nsurface: a selected fill, stronger foreground, or heavier weight. Do not add a\nleading-edge bar or one-sided border as the selection marker. It is a web\ntemplate habit, not a desktop convention; it breaks the item's rounded\nsilhouette and adds a second, competing edge to a column that already aligns\non its text.\n\nFor destructive actions, distinguish between reversible and irreversible work.\nPrefer undo or a temporary notification for reversible changes. Use an\n`AlertDialog` when the consequence is serious and cannot be undone; name the\nspecific object and consequence in the confirmation copy.\n\n### Pointer conventions\n\nUse the default arrow cursor for buttons, checkboxes, menu items, tabs, and\nother native controls. Use a pointing hand for links and content that behaves\nas a link. Use text, resize, grab, and prohibited cursors only when they\ndescribe the active manipulation. A cursor reinforces an affordance; it does\nnot replace the control's visible state or accessible role.\n\nKeep hover effects modest because keyboard and accessibility interaction has no\nhover. Do not reveal the only copy of a destructive or essential action on\nhover. Contextual row actions may become quieter at rest if the same commands\nremain available through selection, keyboard, or a context menu.\n\n### Prefer desktop command surfaces over hover toolbars\n\nUse command frequency and scope to choose where an action lives:\n\n- keep the primary or frequent action visible as a labeled Button or familiar\n  toolbar control;\n- put secondary actions for the current region behind a visible\n  `DropdownMenu` trigger;\n- put commands that act on the object under the pointer in a `ContextMenu`;\n- expose the same important command through an [Action](./action)/[key binding](./keybinding) when it has a\n  natural keyboard form;\n- use a hover-revealed icon only as a shortcut to a command that remains\n  reachable elsewhere.\n\nThis is more than a visual preference. GPUI Component's menu system already\nowns directional keyboard navigation, confirmation and cancellation, disabled\nitems, separators, submenus, shortcut presentation, focus transfer and\nrestoration, and nested-menu dismissal. A custom strip of hover buttons must\nrebuild those behaviors and is invisible to keyboard-only and many assistive\ntechnology workflows.\n\nChoose `DropdownMenu` when users need a visible indication that more commands\nexist—for example a toolbar overflow, document actions, or account menu. Choose\n`ContextMenu` for selection- or object-scoped commands such as rename,\nduplicate, reveal, or remove. The context menu must not be the only way to\nperform an essential command; provide a menu-bar, toolbar, keyboard, or detail\nview path as appropriate.\n\nDo not put every action into a menu to make a screen look minimal. Discovery\nand speed matter: the main action stays visible, dangerous items remain clearly\nlabeled and separated, and a menu item should use the same verb, icon, shortcut,\nenabled state, and result everywhere it appears.\n\n### Button means application action; Link means external resource\n\nUse a Button when activation changes application state, confirms a decision,\nopens a tool, submits data, or runs a command. Choose its treatment by local\nhierarchy:\n\n- primary Button for the one emphasized commitment in a decision area;\n- default Button for ordinary visible actions;\n- outline Button when an action needs a clear boundary with less emphasis;\n- ghost Button for familiar, low-emphasis toolbar and inline actions;\n- icon Button only for a well-known symbol, with an accessible name and a\n  tooltip when meaning or scope is unclear.\n\nDo not assign primary because a Button is the only action on screen, because it\nis placed at the top right, or because the team wants more clicks. Primary\ncommunicates default commitment and keyboard behavior. If activation is merely\nan ordinary command such as adding an item, opening a tool, or refreshing a\nview, use a default, outline, or ghost Button according to its local hierarchy.\n\nUse an underlined Link only for an external resource target: a URL, web page,\nonline documentation, or email address. It uses the pointing-hand cursor\nbecause its contract is leaving the current application context for that\nresource. Do not use Link styling to make a functional command look quiet. A\nlink-shaped Delete, Save, Refresh, Add, Open-menu, or in-app navigation action\nhides the control's affordance and exposes the wrong accessibility role.\n\n“View” does not make an in-app destination a Link. A full report, analysis,\ndetails panel, or local record still opens through a Button, row, card, tab, or\ndisclosure control. Use concise context-aware labels such as `Full analysis`\nwhen the containing card already establishes what opens; reserve underlining\nfor a resource that actually opens in a browser or mail client.\n\nAll internal navigation—sidebar rows, tabs, breadcrumbs, list items, opening a\nlocal view, or switching workspaces—must use the corresponding native component\nor a Button/Action. Visual emphasis is chosen through Button variant or the\nnavigation component's selected state, never by lying about semantics.\n\n## Feedback and overlays\n\nChoose the smallest surface that fits the decision:\n\n- tooltip: a short explanation or shortcut;\n- popover: contextual controls that do not interrupt the task;\n- menu: a compact list of actions;\n- notification: asynchronous status that does not require a decision;\n- dialog: a focused decision or short form;\n- alert dialog: explicit confirmation of a consequential action;\n- sheet: supplementary work that benefits from more persistent space.\n\nA tooltip supplies missing meaning; it does not restate an obvious action.\nReserve it for an unfamiliar symbol, ambiguous scope, or a useful shortcut\nthat is otherwise hidden. Repeated, recognizable commands such as Copy and\nDownload in a message footer need accessible names and keyboard access, but\ntheir hover labels add interruption rather than clarity.\n\nAn Alert interrupts the visual hierarchy even when it does not open a modal.\nUse it for important, exceptional information that needs attention in the\ncurrent task, not as a decorated container for ordinary descriptions, tips, or\nempty space. Prefer inline help, muted text, or a normal section when the\ncontent does not require immediate notice or action.\n\nAvoid stacking overlays. Escape should dismiss the topmost dismissible layer,\nand focus should return to the trigger or the next logical target.\n\nAn overlay action must refer to an object or state the overlay actually shows.\nFor example, expose `Clear history` only when a distinct recent-history section\nis visible and contains entries. Search results, recent items, and favorites\nare different collections; label and separate them instead of merging them\ninto one unexplained list. Hide an inapplicable action or disable it with a\nuseful reason—do not park an ambiguous trash icon in a footer.\n\nFooter space is not a catch-all for capabilities that lacked a place in the\ndesign. A footer may present shortcuts, status, or actions that apply to the\nwhole surface, but each item must answer: what is its object, why is it\navailable now, what scope does it affect, and what visible state changes after\nactivation?\n\n## Motion\n\nMotion explains change; it is not ambient decoration. Use short transitions for\nappearance, dismissal, expansion, and spatial continuity. Avoid animating large\nlayout changes when opacity or transform communicates the same relationship.\nHonor reduced-motion preferences, never require animation to understand state,\nand do not add a default animation to every component.\n\nMotion policy belongs to the styled or application layer. Base may own the\nlifecycle mechanism or geometry needed for a transition, but it should not\ndecide that every product fades or slides. Give independently animated values\nstable identity, and make interruption reverse smoothly from the currently\nsampled value rather than restarting from an old endpoint.\n\nMotion follows the continuity of the interaction. While a pointer or scroll\nposition moves among related targets, keep the preview surface stable and\nupdate its content or position in place. Dismiss it only after the interaction\nends; repeated fade-out and re-entry on each update reads as flicker.\n\n## Designing data-heavy interfaces\n\nDense does not mean cramped. In tables, trees, command palettes, editors, and\ndocks:\n\n- keep headers and primary row identity visually stable;\n- align comparable values and use tabular numerals where appropriate;\n- distinguish focus, hover, active row, and multi-selection;\n- keep sorting and filtering visible and reversible;\n- preserve selection by domain identity across filtering and reordering;\n- virtualize large collections without changing keyboard semantics;\n- use progressive disclosure for secondary columns and inspectors;\n- provide a useful empty state that explains the next action.\n\nChoose a table for comparison across consistent fields, a list for scanning\nheterogeneous items, a tree for real hierarchy, and a dock only when users need\nto arrange long-lived tools or documents. Do not use a complex data component\nas a visual style.\n\n## Interface language\n\nWords are part of the interface architecture. Write the vocabulary for a\nfeature as a system—destinations, objects, commands, states, and outcomes—not as\nisolated translations of implementation features. Prefer the shortest wording\nthat remains accurate in its actual context.\n\n### Let context carry context\n\nDo not repeat information that the surrounding surface already establishes. A\nsidebar destination is usually the object or domain itself: use `Users`, not\n`User Management`; `Shortcuts`, not `Shortcut Configuration Management`. A\ncolumn whose rows already contain actions can omit a generic `Operation`\nheading. A dialog titled `Delete “Roadmap”?` does not need body text that asks\nthe same question again.\n\nThis is context economy, not deletion for its own sake. Add text when it changes\nthe decision: identify the affected scope, an irreversible consequence, an\nunusual prerequisite, or a way to recover. Every extra word should answer a\nquestion the current layout does not already answer.\n\nUse nouns for destinations and objects (`Users`, `Appearance`, `Orders`), verbs\nfor commands (`Save`, `Duplicate`, `Export`), and adjectives or short phrases\nfor states (`Offline`, `Up to date`, `Pending review`). Avoid wrappers such as\n`Management`, `Module`, `Page`, `Function`, `Operation`, and `System` unless the\nword distinguishes a real domain concept.\n\n### Write each language, do not translate its shape\n\nStart from shared intent, hierarchy, and terminology, then compose each locale\nas natural interface language. Do not preserve the source language's word\norder, number of words, politeness filler, or grammatical category. English\n`Users` can express a Chinese feature concept that would literally expand to\n“user management”; fidelity means preserving purpose, not preserving tokens.\n\nRemove words supplied by the enclosing information architecture. Inside a\n`Settings` surface, a destination is often simply `Account`, not `Account\nSettings` and never the unnatural singular `Account Setting`. The correct\nEnglish label is chosen from its role and neighbors, not from the standalone\nsource phrase.\n\nMaintain a small product lexicon for recurring objects, commands, and states.\nUse the same term in the toolbar, menu, context menu, dialog, shortcut search,\nand documentation unless the context genuinely changes its meaning. Review\ncopy in the rendered surface: neighboring labels often reveal repetition or\ninconsistent scope that a locale file cannot.\n\nIn localized technical writing, preserve an established framework term when a\ntranslation would be less precise. Keep API identifiers in their original form\nand format them as code. Do not retain ordinary foreign words merely to sound\ntechnical. Explain a retained term on first use when needed, then use the same\nform throughout the interface, documentation, and API examples.\n\nIn documentation, use the exact English name for a named API, component,\nsource file, or guide in link text, including localized pages. For example,\nwrite `Font`, `Render`, `Input element`, and `Plot label` rather than translating\ntheir names or adding a redundant `GPUI Kit` prefix. Keep surrounding explanations in the\npage's language. Link only the named target; place words such as “source”\noutside the link when they describe why it is cited.\n\nIn a technical comparison table shared across locales, keep capability names,\nframework names, API names, and model names in their established English form.\nTranslate the explanation around the table, not its technical labels. Common\ninterface words with an established local name may still be localized outside\nthat comparison context.\n\n### Buttons and confirmation dialogs\n\nButton labels are short by default—usually one or two words—and describe the\nresult, not the gesture or the component. Prefer `Save`, `Move`, or `Delete` to\n`Click to save`, `Perform move`, or `Confirm deletion`. Use `Cancel` consistently\nfor the action that leaves without committing. Reserve `OK` for acknowledging\npurely informational content.\n\nShort is a default, not a character limit. A deliberately longer label is\nbetter when its words expose a consequence or distinguish choices that users\ncould otherwise confuse, for example `Delete from this group` versus `Delete\neverywhere`, or `Restart without saving`. Length must buy decision-critical\ninformation; it must not restate the dialog title or body.\n\nUse the most specific concise result as the confirmation label when possible:\n\n| Context | Weak | Prefer |\n| --- | --- | --- |\n| Delete dialog | `Yes`, `Sure`, `Confirm deletion` | `Delete` |\n| Unsaved changes | `Confirm`, `Yes` | `Discard changes` |\n| Pure acknowledgement | `Confirm operation` | `OK` or `Done` |\n| Complex consent whose result has no clear verb | `Yes` | `Confirm` |\n\n`Confirm` is a useful fallback when the surrounding dialog fully names a\ncomplex commitment and no shorter result verb is accurate. It should not\nreplace a clear command. `Sure` is conversational rather than a stable English\ncommand and is too ambiguous for the standard vocabulary.\n\nA confirmation dialog should form one compact decision:\n\n- title: the decision or condition, such as `Delete “Roadmap”?`;\n- body: only new scope, consequence, or recovery information;\n- actions: `Cancel` and the result, such as `Delete`;\n- destructive styling: applied to the destructive result, not substituted for\n  precise wording.\n\nAvoid generic titles such as `Notice`, `Warning`, `Error`, and `Confirmation`\nwhen the actual condition can be named. Avoid ritual phrases such as “Are you\nsure you want to…”, “Would you like to…”, “Please note that…”, and “successfully”\nwhen the structure or state already communicates them. Courtesy should come\nfrom a calm, respectful tone, not repeated `please`.\n\n### Capitalization, punctuation, and symbols\n\nUse sentence case for English UI by default: `Reset layout`, not `Reset Layout`\nor `RESET LAYOUT`. Preserve proper nouns and established acronyms. Follow a\nplatform convention such as title case for native menu commands only when the\nplatform integration benefits from it, and apply that convention consistently\nwithin the component class.\n\nALL CAPS can provide restrained typographic emphasis for very short section\nlabels, eyebrows, statuses, established acronyms, and code-like identifiers.\nIts compact shape and measured tracking can form a level similar to bold type,\nbut it does not belong on Buttons, long headings, sentences, or dense lists. Do\nnot combine uppercase, strong color, and bold weight in the same region, and do\nnot transform every string automatically: product names, acronyms, and localized\ncontent must preserve their intended casing.\n\nLabels, buttons, menu items, tabs, headings, placeholders, and short states do\nnot take a final period. Complete explanatory, warning, and error sentences do.\nAvoid exclamation marks in routine success and failure messages. In Chinese,\nuse full-width punctuation in sentences and omit terminal punctuation from\nshort control labels by the same semantic rule.\n\nUse the single ellipsis character (`…`), not three periods. Append it to every\nButton or MenuItem that opens a dialog, sheet, or separate window, and to a\ncommand that requires more input or choices before it can complete, such as\n`Settings…` or `Export…`. An immediately executed command does not take an\nellipsis. Use an indeterminate progress indicator, not decorative dots, to\ncommunicate ongoing work.\n\nErrors should say what happened and, when useful, the next recovery action.\nSuccess feedback should name the resulting state only when that state is not\nalready visible. Prefer `Couldn’t save. Check your connection and try again.`\nto a technical code or a long apology; omit a `Saved successfully` toast when\nthe document visibly becomes saved.\n\n## Internationalization and platform fit\n\nAccessibility (A11y) names and labels may remain in English; localization is\nnot required for these strings. Keep the item's own label when naming a control\nthat acts on it, even when that label is localized. This exception does not\napply to visible UI copy.\n\nCopy must survive expansion, CJK typography, and different shortcut notation.\nDo not size a control from one English label. Keep text out of raster assets,\navoid concatenating translated fragments, and let labels wrap or truncate only\nwhere the product defines a recovery path such as a tooltip.\n\nRespect platform differences that carry meaning: Command versus Control,\nnative window decorations, system appearance, scrollbar behavior, menus, and\nnotification capabilities. Keep the product's information architecture stable\nacross platforms, but do not erase familiar platform behavior for superficial\npixel equality.\n\n## Guidance for AI-generated interfaces\n\nAn AI changing a GPUI interface should first inspect the nearest feature,\ntheme tokens, and component documentation. It should state the primary task,\nstate owner, component composition, and keyboard path before generating code.\nIt must not infer an API from React/Shadcn examples or invent a GPUI method\nbecause the name seems plausible.\n\nAI output is incomplete until a human can explain why the hierarchy, density,\ncomponent choice, and exceptional literal values belong in this product. A\nvisually plausible screenshot is not proof: keyboard behavior, focus, dynamic\ncontent, themes, resizing, and failure states are part of the design.\n\n## Accessibility checklist\n\nBefore considering a screen complete, verify that:\n\n- every action is reachable and operable by keyboard;\n- focus or\n\n<!-- [TRUNCATED AT 50KB] -->","skills/gpui-kit/SKILL.md":"---\nname: gpui-kit\ndescription: 'How to build desktop applications with GPUI Kit, the Rust framework published as the gpui-kit crate (GPUI plus gpui_kit::component, gpui_kit::base, gpui_kit::assets). Use when setting up a gpui-kit app, choosing or using a component (Button, Input, Select, Dialog, Sheet, Tabs, Sidebar, List, DataTable, Tree, Chart, etc.), handling component state, theming, or window overlays, and for GPUI mechanics: actions and keybindings, async tasks, contexts, custom elements, entities, events, focus, global state, layout and styling, ElementId, and tests including UI integration testing. Holds the normative Coding Guides: read them before any architecture, state-ownership, public API, naming, or testing decision. Pairs with the gpui-kit-design-guides skill for the Design Guides.'\n---\n\n# GPUI Kit\n\nApplications depend on one crate, `gpui-kit`. GPUI is `use gpui_kit::*;`, and\neach layer is reachable by name: `gpui_kit::component` (styled components),\n`gpui_kit::base` (unstyled behavior), `gpui_kit::assets` (default icons),\n`gpui_kit::platform`.\n\nStart with [component-family conventions](references/conventions.md) to choose the constructor, state owner, event, and layout contract for the task. Learn the family once, then verify the specific component supports the capability.\n\nFor a complete compiled view with retained state, subscriptions, and overlay\nlayers, read [the tested application recipe](references/recipes.md).\n\n## Read the Guides First\n\nTwo guides hold the rules this skill assumes. They are requirements, not\ninspiration. Read the guide file itself; do not answer from this page, from a\nsimilar file in the codebase, or from training data.\n\n| Guide                                                  | Read before                                                                                                                   |\n| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |\n| Design Guides, skill `gpui-kit-design-guides`          | Choosing components, layout, spacing, hierarchy, color, density, interaction states, overlays, motion, interface copy          |\n| [Coding Guides](references/coding-guides.md)           | Crate layering, `RenderOnce` vs `Entity<T>`, state ownership, `ElementId`, events, focus, async, public API, naming, testing |\n\nRead the Design Guides first when the change has a visible surface: code\nstructure preserves product intent, it does not replace it. If the design\nskill is not installed, fetch `https://gpui-kit.com/docs/design-guides.md`.\nThe coding guide is a verbatim copy of `https://gpui-kit.com/docs/coding-guides.md`,\nso its links to `./design-guides.md` and `./getting-started.md` mean the design\nskill and `https://gpui-kit.com/docs/getting-started.md`.\n\n### Coding Guides section map\n\nRead the whole guide for a new crate, module, or feature. For a narrow change,\nread \"Architecture at a glance\" and \"Rules for coding agents\" first, then the\nsection for the change (`grep -n '^## ' references/coding-guides.md`).\n\n| Section                              | Read when                                                              |\n| ------------------------------------ | ---------------------------------------------------------------------- |\n| Architecture at a glance             | Always; crate layering, ownership boundary                             |\n| Bootstrap and root ownership         | `main`, `init`, `Root`, window creation, app-level state               |\n| Understand GPUI's phases and contexts | Anything touching `App`, `Window`, `Context<T>`, render vs update      |\n| Choose the right unit                | Deciding `RenderOnce` vs `Entity<T>` vs custom `Element`               |\n| State ownership                      | Where a piece of state lives, who mutates it, `Entity<State>` handles  |\n| Stable identity                      | `ElementId`, lists, repeated elements, keyed state                     |\n| Rendering and composition            | `render`, builder chains, `when`/`map`, child composition              |\n| Behavior and presentation boundary   | `gpui-base` vs `gpui-component` vs application code                    |\n| Theme and styling                    | `cx.theme()`, tokens, `Styled`, sizes, variants                        |\n| Events, actions, and focus           | `cx.emit`, `subscribe`, `actions!`, keybindings, `FocusHandle`         |\n| Async work and side effects          | `cx.spawn`, `background_spawn`, `Task`, I/O, timers                    |\n| Layout, measurement, and scrolling   | Flex layout, sizing, `overflow`, scroll handles, measuring             |\n| Lists, tables, and large data        | `VirtualList`, `List`, `DataTable`, delegates, large collections       |\n| Public API design                    | Anything `pub`: builders, private fields, setter and reader naming     |\n| Platform and capability boundaries   | macOS/Windows/Linux/wasm differences, feature gates                    |\n| File and naming conventions          | New files, modules, type and method names, `Kind` suffix, `Context`    |\n| Testing strategy                     | What to test, `#[gpui_kit::test]`, `TestAppContext`                    |\n| Performance rules                    | Render cost, allocation, re-render triggers                            |\n| Common failure modes                 | Before finishing; invented APIs, state in render, index ids            |\n| Rules for coding agents              | Always when an agent writes code                                       |\n| Implementation checklist             | Before finishing; run every item against the work                     |\n\n### Non-negotiables\n\nA floor, not a substitute for the guides.\n\n- **Never invent an API.** Search the current source for the real signature.\n  Do not translate a React, CSS, or older-GPUI example by analogy; a\n  plausible-looking method that does not exist is the most common failure.\n- **One dependency.** Applications depend on `gpui-kit` alone. GPUI is\n  `use gpui_kit::*;`; the layers are `gpui_kit::component`, `gpui_kit::base`,\n  `gpui_kit::assets`, `gpui_kit::platform`.\n- **Framework owns behavior, application owns presentation.** Do not put\n  colors, sizing, or layout in `gpui-base`; do not put interaction behavior in\n  application styling code.\n- **Stable identity.** Repeated elements need domain-derived `ElementId`s, not\n  list indexes.\n- **No `pub` fields across the seam.** Public data types use builders and\n  reader methods.\n- **Spell `Context` out.** `cx` is GPUI's; name anything else after what it\n  holds.\n\n## Documentation\n\n- **Find a task/component page**: use `https://gpui-kit.com/llms.txt`, then load its Markdown page.\n- **Full reference**: `https://gpui-kit.com/llms-full.txt` is available when broad reference is actually needed\n- **Per-component API**: fetch `https://gpui-kit.com/component/{name}.md`,\n  e.g. `button.md`, `input.md`, `select.md`, `dialog.md`, `data-table.md`\n- **Any site page** can be fetched as Markdown by appending `.md` to the URL\n\n## Quick Reference\n\nSetup and examples: [references/usage.md](references/usage.md).\n\n```rust\nuse gpui_kit::*;\n\ngpui_kit::application()\n    .with_assets(gpui_kit::assets::Assets)\n    .run(|cx| {\n        gpui_kit::init(cx);                       // first, before anything else\n        gpui_kit::open_window(options, cx, |window, cx| {\n            cx.new(|cx| AppView::new(window, cx))\n        })\n        .expect(\"failed to open window\");\n    });\n```\n\n- **Stateless** (`RenderOnce`): build in `render`:\n  `Button::new(\"save\").primary().label(\"Save\").on_click(|_, _, _| {})`\n- **Stateful**: hold `Entity<State>` in the view, pass a reference in `render`:\n  `let input = cx.new(|cx| InputState::new(window, cx));` then `Input::new(&self.input)`\n- **Sizes**: `.xsmall()` `.small()` `.medium()` (default) `.large()`\n- **Theme**: `cx.theme().primary` · `.background` · `.foreground` · `.border` · `.muted`\n- **Overlays**: `window.open_dialog(...)`, `open_sheet(...)`, `push_notification(...)`\n  via `gpui_kit::component::WindowExt`\n\n## Component Catalog\n\nImport paths are relative to `gpui_kit::component::`, so `input::{Input, InputState}`\nmeans `use gpui_kit::component::input::{Input, InputState};`. For the full API\nfetch the component's `.md` doc.\n\n### Input & Form\n\n| Component     | Import                                          | Notes                                        |\n| ------------- | ----------------------------------------------- | -------------------------------------------- |\n| `Input`       | `input::{Input, InputState}`                    | Stateful. Text, password, mask, validation   |\n| `Textarea`    | `input::{Textarea, TextareaState}`              | Stateful. Multi-line text                    |\n| `Editor`      | `input::{Editor, EditorState}`                  | Stateful. Code editor, `tree-sitter` feature |\n| `NumberInput` | `input::{NumberInput, NumberInputEvent}`        | Stateful. Numeric with step                  |\n| `OtpInput`    | `input::OtpInput`                               | Stateful. One-time password                  |\n| `SpeechButton` | `speech::{SpeechButton, SpeechState}`          | Stateful. Dictation, `speech` feature        |\n| `Select`      | `select::{Select, SelectState}`                 | Stateful. Dropdown picker                    |\n| `Combobox`    | `combobox::{Combobox, ComboboxState}`           | Stateful. Searchable select                  |\n| `Checkbox`    | `checkbox::Checkbox`                            | Stateless. `on_click` receives `&bool`       |\n| `Switch`      | `switch::Switch`                                | Stateless. Toggle                            |\n| `Radio`       | `radio::{Radio, RadioGroup}`                    | Stateless.                                   |\n| `Slider`      | `slider::{Slider, SliderState}`                 | Stateful.                                    |\n| `Toggle`      | `button::Toggle`                                | Stateless.                                   |\n| `Rating`      | `rating::Rating`                                | Stateless.                                   |\n| `Stepper`     | `stepper::Stepper`                              | Stateless. Multi-step progress               |\n| `ColorPicker` | `color_picker::{ColorPicker, ColorPickerState}` | Stateful.                                    |\n| `DatePicker`  | `date_picker::{DatePicker, DatePickerState}`    | Stateful.                                    |\n| `TimeField`   | `time_field::{TimeField, TimeFieldState}`       | Stateful. Time of day, 24/12-hour            |\n| `Calendar`    | `calendar::{Calendar, CalendarState}`           | Stateful. Inline month view                  |\n| `Form`        | `form::{v_form, h_form, field}`                 | Layout container for form fields             |\n\n### Display & Feedback\n\n| Component   | Import                                    | Notes                                 |\n| ----------- | ----------------------------------------- | ------------------------------------- |\n| `Button`    | `button::{Button, ButtonGroup}`           | Stateless. Primary UI action          |\n| `Icon`      | `{Icon, IconName}`                        | Stateless. Lucide icons               |\n| `Badge`     | `badge::Badge`                            | Stateless.                            |\n| `Tag`       | `tag::Tag`                                | Stateless. Closable tags              |\n| `Avatar`    | `avatar::Avatar`                          | Stateless.                            |\n| `Label`     | `label::Label`                            | Stateless. Form label                 |\n| `Kbd`       | `kbd::Kbd`                                | Stateless. Keyboard key display       |\n| `Alert`     | `alert::Alert`                            | Stateless. Info/success/warning/error |\n| `Spinner`   | `spinner::Spinner`                        | Stateless. Loading indicator          |\n| `Skeleton`  | `skeleton::Skeleton`                      | Stateless. Loading placeholder        |\n| `Shimmer`   | `shimmer::{ShimmerText, ShimmerStyle}`    | Stateless. Streaming-text shimmer     |\n| `Marker`    | `marker::{Marker, MarkerVariant}`         | Stateless. Inline status marker       |\n| `Progress`  | `progress::{Progress, ProgressCircle}`    | Stateless.                            |\n| `Tooltip`   | `tooltip::Tooltip`                        | Via `.tooltip()` on elements          |\n| `HoverCard` | `hover_card::{HoverCard, HoverCardState}` | Stateful.                             |\n| `Clipboard` | `clipboard::Clipboard`                    | Stateless. Copy button                |\n| `TextView`  | `text::TextView`                          | `TextView::markdown(id, text)`, HTML too |\n| Image       | `gpui_kit::{img, ImageSource, ObjectFit}` | GPUI's `img()` element                |\n\n### Overlay & Popups\n\n| Component        | Import                                            | Notes                                    |\n| ---------------- | ------------------------------------------------- | ---------------------------------------- |\n| `Dialog`         | `dialog::Dialog` + `WindowExt`                    | Via `window.open_dialog(...)`            |\n| `AlertDialog`    | `WindowExt`                                       | Via `window.open_alert_dialog(...)`      |\n| `Sheet`          | `sheet::Sheet` + `WindowExt`                      | Side panel, via `window.open_sheet(...)` |\n| `Notification`   | `notification::Notification` + `WindowExt`        | Via `window.push_notification(...)`      |\n| `Popover`        | `popover::Popover`                                | Floating overlay                         |\n| `Menu`           | `menu::{PopupMenu, DropdownMenu}`                 | Context menus                            |\n| `DropdownButton` | `button::DropdownButton`                          | Button with dropdown menu                |\n| `Command`        | `command::{Command, CommandState, CommandGroup}`  | Stateful. Command palette                |\n| Focus trap       | `FocusTrapElement`                                | `.focus_trap(id, &handle)` on a container; `Dialog` and `Sheet` have it built in |\n\n### Navigation & Layout\n\n| Component         | Import                                                                   | Notes                     |\n| ----------------- | ------------------------------------------------------------------------ | ------------------------- |\n| `Tabs` / `TabBar` | `tab::{Tab, TabBar}`                                                     | Tabbed interface          |\n| `Sidebar`         | `sidebar::{Sidebar, SidebarMenu, ...}`                                   | App navigation panel      |\n| `TitleBar`        | `TitleBar`                                                               | Window title bar          |\n| `StatusBar`       | `status_bar::StatusBar`                                                  | Window status bar         |\n| `Breadcrumb`      | `breadcrumb::Breadcrumb`                                                 | Navigation breadcrumb     |\n| `Pagination`      | `pagination::Pagination`                                                 | Page navigation           |\n| `Accordion`       | `accordion::Accordion`                                                   | Collapsible sections      |\n| `Collapsible`     | `collapsible::Collapsible`                                               | Single collapsible        |\n| `GroupBox`        | `group_box::GroupBox`                                                    | Labeled container         |\n| `Resizable`       | `resizable::{h_resizable, v_resizable, resizable_panel, ResizableState}` | Draggable split panes     |\n| `ResizeHandle`    | `resizable::{resize_handle, HandleEdge}`                                 | Standalone resize edge    |\n| `Scrollbar`       | `scroll::Scrollbar`                                                      | Custom scrollbar          |\n\n### Data Display\n\n| Component         | Import                                          | Notes                         |\n| ----------------- | ----------------------------------------------- | ----------------------------- |\n| `DataTable`       | `table::{DataTable, TableState, TableDelegate}` | Stateful. Full-featured table |\n| `Diff`            | `diff::{Diff, DiffState, DiffFile}`           | Retained state, `RenderOnce` element. Readonly unified/Git diff display of one or more files, merge conflicts and source files; application supplies the patch |\n| `Table`           | `table::{Table, ...}`                           | Simpler table                 |\n| `VirtualList`     | `{v_virtual_list, h_virtual_list}`              | High-perf large lists         |\n| `List`            | `list::{List, ListState, ListDelegate}`         | Stateful. Searchable list     |\n| `Tree`            | `tree::{Tree, TreeState, TreeItem, TreeEntry}`  | Stateful. Hierarchy           |\n| `DescriptionList` | `description_list::DescriptionList`             | Key-value pairs               |\n| `Settings`        | `setting::Settings`                             | Settings panel                |\n\n### Chat & Messaging\n\n| Component         | Import                                                   | Notes                                 |\n| ----------------- | -------------------------------------------------------- | ------------------------------------- |\n| `Message`         | `message::{Message, MessageContent, MessageAlignment}`   | Stateless. Chat message row           |\n| `Bubble`          | `bubble::{Bubble, BubbleContent, BubbleVariant}`         | Stateless. Message bubble             |\n| `Attachment`      | `attachment::{Attachment, AttachmentContent, ...}`       | Stateless. File/media attachment card |\n| `MessageScroller` | `message_scroller::{MessageScroller, MessageScrollerState}` | Stateful. Auto-scrolling message list |\n\n### Charts\n\n| Component | Import                                                          | Notes                          |\n| --------- | --------------------------------------------------------------- | ------------------------------ |\n| `Chart`   | `chart::{AreaChart, BarChart, LineChart, PieChart, RadarChart}` | Bar, line, area, pie charts    |\n| `Plot`    | `plot::Plot`                                                    | `#[derive(IntoPlot)]` for data |\n\n## Testing\n\n**UI integration testing** means rendering real components in headless windows,\nsimulating input, and checking state, focus, layout and owner callbacks. Use\n`#[gpui_kit::test]` to run tests and `gpui_kit::test` to operate and inspect the UI.\nWhen asked to add component interaction coverage, describe it as UI integration testing.\n\nFor unit tests, GPUI context tests or UI integration tests, read\n[Testing](references/gpui/test.md). It includes dependency setup, a complete\nrunnable UI flow, scoped native interactions, frame/async handling and the\nlimits of accessibility and geometry assertions. Use the production view and\nverify the action's outcome through normal Rust assertions.\n\n## GPUI References\n\nLoad the file for the mechanism the task touches. Each file starts with a\ncontents line.\n\n| Topic                       | File                                                   | Load when                                                       |\n| --------------------------- | ------------------------------------------------------ | --------------------------------------------------------------- |\n| Actions & keybindings       | [action.md](references/gpui/action.md)                 | `actions!`, `bind_keys`, `on_action`, `key_context`             |\n| Async & background tasks    | [async.md](references/gpui/async.md)                   | `cx.spawn`, `background_spawn`, `Task`, async I/O               |\n| Context management          | [context.md](references/gpui/context.md)               | `App`, `Window`, `Context<T>`, `AsyncApp`                       |\n| Custom elements (low-level) | [element.md](references/gpui/element.md)               | `Element` trait, `request_layout`, `prepaint`, `paint`          |\n| Entity state                | [entity.md](references/gpui/entity.md)                 | `Entity<T>`, `WeakEntity`, state management                     |\n| Events & subscriptions      | [event.md](references/gpui/event.md)                   | `cx.emit`, `cx.subscribe`, `cx.observe`                         |\n| Focus & keyboard nav        | [focus-handle.md](references/gpui/focus-handle.md)     | `FocusHandle`, `track_focus`, Tab navigation                    |\n| Global state                | [global.md](references/gpui/global.md)                 | `Global` trait, `cx.set_global`, app-wide config                |\n| Layout & styling            | [layout-style.md](references/gpui/layout-style.md)     | `div()`, `h_flex()`, `v_flex()`, flexbox, overflow, positioning |\n| ElementId                   | [element-id.md](references/gpui/element-id.md)         | `ElementId`, `.id()`, uniqueness rules, stateful elements       |\n| Testing                     | [test.md](references/gpui/test.md)                     | `#[gpui_kit::test]`, `TestAppContext`, `VisualTestContext`      |\n\nDeep dives, for when the topic file is not enough:\n\n- **Element trait**: [element-api.md](references/gpui/element-api.md) (complete API, hitbox, events) ·\n  [element-patterns.md](references/gpui/element-patterns.md) (text, interactive, container, composite) ·\n  [element-examples.md](references/gpui/element-examples.md) (full examples) ·\n  [element-best-practices.md](references/gpui/element-best-practices.md) (performance, state, pitfalls) ·\n  [element-advanced.md](references/gpui/element-advanced.md) (custom layouts, async updates, virtual lists)\n- **Entities**: [entity-api.md](references/gpui/entity-api.md) (complete API, lifecycle) ·\n  [entity-patterns.md](references/gpui/entity-patterns.md) (model-view, cross-entity, observer) ·\n  [entity-best-practices.md](references/gpui/entity-best-practices.md) (memory, performance) ·\n  [entity-advanced.md](references/gpui/entity-advanced.md) (collections, registry, debounce, state machines)\n- **Testing**: [test-examples.md](references/gpui/test-examples.md) (organization, setup, assertions, running tests) ·\n  [test-reference.md](references/gpui/test-reference.md) (re-entrancy, property tests, mocking)\n","skills/gpui-kit/references/coding-guides.md":"---\ntitle: Coding Guides\ndescription: Architecture and coding conventions for maintainable GPUI Kit applications\norder: -13\n---\n\n# Coding Guides\n\nThis guide describes the application architecture and code patterns that have\nproved durable in GPUI Kit. It is written for both engineers and coding\nagents. Read [Design Guides](./design-guides.md) first: code structure should\npreserve product intent, not replace it.\n\nThis is a normative guide. **Must** marks lifecycle, correctness, or ecosystem\nconstraints; **should** is the default architecture and requires a concrete\nreason to depart from it. Current source and API docs remain authoritative for\nexact signatures.\n\n## Architecture at a glance\n\n<img class=\"architecture-light\" src=\"/application-layers-light.svg?v=20260822-16\" alt=\"GPUI application architecture layers\">\n<img class=\"architecture-dark\" src=\"/application-layers-dark.svg?v=20260822-16\" alt=\"GPUI application architecture layers\">\n\nDependencies point downward. Higher layers own domain meaning and orchestration;\nlower layers own reusable presentation or behavior. Do not make a reusable\ncomponent depend on an application screen, or make `gpui-base` depend on a\ntheme from GPUI Component.\n\nUse these boundaries:\n\n- **app shell:** compose windows and feature crates while keeping feature logic out;\n- **feature crate:** keep one capability's model, services, views, commands, dialogs,\n  and workflow behind one public boundary;\n- **app component:** a repeated domain-aware pattern;\n- **gpui-component:** themed, general-purpose UI;\n- **gpui-base:** reusable behavior and geometry without product presentation.\n\n### Organize large applications by capability\n\nIn a large Rust application, a feature should usually be a crate, not another\nfile in a global `views`, `models`, or `modals` directory. Keep the model,\nviews, commands, dialogs, and workflow for one capability together. A dialog\nthat edits a workspace belongs to the workspace feature; only the reusable\ndialog primitive belongs to the UI library.\n\n```text\ncrates/\n├── app/\n│   └── src/main.rs             # Compose windows and features\n├── workspace/\n│   └── src/\n│       ├── lib.rs              # The feature's public boundary\n│       ├── model.rs\n│       ├── commands.rs\n│       ├── workspace_view.rs\n│       └── rename_dialog.rs\n├── search/\n│   └── src/\n│       ├── lib.rs\n│       ├── model.rs\n│       ├── commands.rs\n│       ├── search_view.rs\n│       └── filters.rs\n├── settings/\n│   └── src/\n│       ├── lib.rs\n│       ├── model.rs\n│       ├── settings_view.rs\n│       └── account_dialog.rs\n└── shared/\n    └── src/\n        ├── lib.rs\n        └── recent_items.rs     # A stable capability with multiple owners\n```\n\nDo not invert this into global `models/`, `views/`, `modals/`, and `commands/`\ndirectories. Those folders classify files by implementation role while\nscattering every feature across the application.\n\nThe application shell composes feature crates but contains little feature\nlogic. A feature may depend on stable shared capabilities and UI foundations;\nit must not depend on the shell or reach into a sibling feature's internals.\nWhen two features need to communicate, prefer an explicit command, event, data\ntype, or small shared service over a dependency between their views. Extract a\nshared crate only after the capability has a coherent name and more than one\nreal owner.\n\nCrate boundaries are engineering boundaries. They let Cargo rebuild and test a\nsmaller dependency subgraph, make ownership visible in `Cargo.toml`, and limit\nthe review and regression surface of a change. They also make removal honest:\na feature that cannot be detached without searching through global view and\nmodal directories was never isolated.\n\nDo not create a crate for every screen or helper. Split where a capability has\nits own state and lifecycle, a stable public seam, or enough implementation to\nbenefit from independent compilation and tests. Keep dependencies acyclic and\npointing toward smaller, more stable crates.\n\n## Bootstrap and root ownership\n\nInitialize GPUI Component once, before creating component-backed views, and put\n`Root` at the first level of each window:\n\n```rust\napp.run(move |cx| {\n    gpui_kit::init(cx);\n\n    gpui_kit::open_window(WindowOptions::default(), cx, |window, cx| {\n        cx.new(|cx| Workspace::new(window, cx))\n    })\n    .expect(\"failed to open window\");\n});\n```\n\n`Root` coordinates window-level component facilities such as overlays and\nnotifications. Do not create a separate root for each page inside one window.\nIt also coordinates modal focus restoration, focus traps, tooltip/menu layers,\nand window-scoped text selection. Bypassing it can produce behavior that looks\ncorrect at rest but fails when overlays nest or focus changes quickly.\n\n## Understand GPUI's phases and contexts\n\nGPUI is retained state with declarative rendering. An entity survives across\nframes; the element tree returned by `render` is a fresh description of the\ncurrent frame. Keep that distinction explicit.\n\n- `Context<Self>` mutates the current entity, creates listeners tied to it,\n  emits its events, and notifies its observers.\n- `App` gives access to application globals and entity reads/updates without\n  implying ownership by the rendered element.\n- `Window` owns focus, actions, input dispatch, element-keyed state,\n  measurement, and animation-frame requests for that window.\n- layout, prepaint, and paint are later phases; use their hooks only when\n  resolved geometry is genuinely required.\n\nNever retain `&mut Window`, `&mut App`, or `&mut Context<_>` beyond the call in\nwhich it is provided. Retain typed handles—`Entity`, `WeakEntity`,\n`FocusHandle`, scroll handles, or domain IDs—instead.\n\n## Choose the right unit\n\n### Use `RenderOnce` for value-like elements\n\nUse a `RenderOnce`/`IntoElement` component when all inputs can be supplied by\nthe caller and the element does not need to retain application state between\nframes. This is the normal choice for presentational wrappers and small\ncontrols.\n\n```rust\n#[derive(IntoElement)]\nstruct EmptyState {\n    title: SharedString,\n}\n\nimpl RenderOnce for EmptyState {\n    fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {\n        div()\n            .v_flex()\n            .gap_2()\n            .items_center()\n            .text_color(cx.theme().muted_foreground)\n            .child(self.title)\n    }\n}\n```\n\n### Use `Entity<T>` for retained behavior\n\nUse an entity-backed `Render` view when behavior spans frames or needs\nobservation, subscriptions, focus, async work, history, measurement, or\nincremental updates. Store entities in an owning view rather than recreating\nthem in `render`.\n\n```rust\nstruct SearchView {\n    query: Entity<InputState>,\n}\n\nimpl SearchView {\n    fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let query = cx.new(|cx| InputState::new(window, cx).placeholder(\"Search…\"));\n        Self { query }\n    }\n}\n```\n\nDo not turn every visual fragment into an entity. Entity boundaries have\nlifecycle and coordination costs; use them where retained identity matters.\n\n### Elements, views, and behavior systems are different\n\nDo not force every component into one template. The ecosystem contains:\n\n- semantic elements such as Button, Checkbox, Link, and Tabs;\n- compound behavior roots such as Dialog, Popover, Select, and Combobox;\n- entity-backed systems such as Input, Table, Tree, Dock, and notifications;\n- infrastructure such as positioning, virtualization, scrolling, focus traps,\n  motion, history, and measurement.\n\nAn element may be internally complex and still be value-like to its caller. A\nstateful system may expose render callbacks so applications own presentation\nwithout reimplementing behavior. Choose the public seam from the behavior,\nnot from how many `div`s appear in its renderer.\n\n## State ownership\n\nPut each state in the narrowest owner that can keep it correct:\n\n- domain state belongs to a model or feature view;\n- transient view state belongs to the view that renders it;\n- reusable behavioral state belongs to the component state designed for it;\n- tiny element-local state may use GPUI keyed element state;\n- shared application services may be stored as GPUI globals.\n\nPrefer controlled values for ordinary selection and toggles: pass the current\nvalue into the component, receive a requested change, update the owner, and\nrender again. A callback reports intent; it should not create a second hidden\nsource of truth.\n\n```rust\nCheckbox::new(\"show-hidden\")\n    .checked(self.show_hidden)\n    .label(\"Show hidden files\")\n    .on_click(cx.listener(|this, checked, _, cx| {\n        this.show_hidden = *checked;\n        cx.notify();\n    }))\n```\n\nCall `cx.notify()` after a mutation that changes rendering. Use `cx.emit(...)`\nfor a semantic event that an owner should handle, and `cx.subscribe(...)` or\n`cx.observe(...)` when the lifetime should follow an entity. Keep returned\nsubscriptions alive when the API requires it.\n\nDo not notify merely because a value was read or derived. Avoid unconditional\nnotification from `render`; it schedules another render and can create a\npermanent redraw loop. When several fields form one invariant, update them\ntogether and notify once. A reusable state type that cannot receive a context\nshould make that limitation explicit and require its owner to emit/notify.\n\n### Avoid state feedback loops\n\nText input, selection, filters, and controlled popups commonly have two paths:\nan external owner updates the value, and user interaction requests a new value.\nDo not send an owner-supplied value back through the user callback during sync.\nTrack the origin or compare coherent snapshots so each logical change is\nreported once. Make callbacks re-entrancy-safe when a callback can synchronously\nclose, replace, or update the component that invoked it.\n\n## Stable identity\n\nAn `ElementId` is part of behavior. It gives an element stable identity and keys\nelement-local or component state. A component may also use it as one input to\nits own focus, measurement, or animation identity; focus and scrolling are\notherwise owned by their dedicated handles.\n\n- Use stable domain IDs for rows, tabs, tree nodes, and repeated controls.\n- Namespace child IDs with their owning object when the same control repeats.\n- Never derive identity from a translated label or a mutable list index when\n  items can be inserted or reordered.\n- Do not generate a fresh random ID during `render`.\n\n```rust\nButton::new((\"delete-project\", project.id))\n    .danger()\n    .label(\"Delete\")\n```\n\nA changed ID means a changed UI identity. Treat that reset as deliberate.\n\nThe same rule applies to transition channels, overlay tokens, scroll handles,\nand persistence IDs. If two independently retained behaviors share a key, they\ncan overwrite each other's state; if one behavior changes keys every frame, it\nnever accumulates state.\n\n## Rendering and composition\n\nKeep `render` declarative: read current state, derive presentation values, and\ncompose elements. Move domain operations, parsing, and non-trivial mutation to\nnamed methods or services.\n\n```rust\nimpl Render for ProjectView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .v_flex()\n            .size_full()\n            .child(self.render_toolbar(cx))\n            .child(self.render_content(cx))\n    }\n}\n```\n\nExtract a render helper when it names a meaningful region and reduces the\namount of state a reader must hold at once. Extract a new component when the\nregion has its own reusable contract or retained lifecycle—not merely because\na builder chain is long.\n\nUse GPUI Component's fluent traits consistently (`Sizable`, `Disableable`,\n`Selectable`, and component-specific builders). Prefer `.when(...)` and\n`.when_some(...)` for small conditional refinements; use ordinary Rust control\nflow when branches represent substantially different interfaces.\n\nCompose from the standard semantic component before building a custom surface.\nDo not reproduce a menu, select, dropdown, or command palette from generic\n`div`s merely to match one screenshot. Reusing the component preserves its\nitem geometry, focus transfer, keyboard navigation, selection, disabled state,\ndismissal, and accessibility contract. If the standard component cannot\nexpress a recurring valid pattern, improve its explicit API instead of styling\narbitrary descendants at each call site.\n\nRender callbacks supplied by application code should be side-effect-free. A\nlist item renderer, menu builder, or dock panel renderer may run whenever its\nowner needs to measure or redraw. It must not perform a business operation,\nappend data, or register an unbounded subscription.\n\n## Behavior and presentation boundary\n\nThe durable Base rule is:\n\n> Base owns reusable behavior and the geometry required to implement it. The\n> presentation layer owns the product's visual language.\n\n“Headless” does not mean “one empty `div`.” Popup collision, keyboard\nnavigation, editing, virtualization, resize arithmetic, focus trapping, and\ndock reconciliation require internal structure and state. Moving that work to\nevery caller would not create flexibility; it would duplicate fragile\nbehavior.\n\nConversely, Base must not choose brand colors, typography, density, final\nicons, component variants, or application composition. Expose presentation\nthrough `Styled`, typed semantic-state styles, explicit parts, child slots, and\nitem renderers. Do not inspect arbitrary descendants to discover titles,\ndescriptions, or close buttons—make semantic parts explicit.\n\n## Theme and styling\n\nRead semantic values from the active theme and apply layout with GPUI's\n`Styled` methods:\n\n```rust\ndiv()\n    .bg(cx.theme().background)\n    .text_color(cx.theme().foreground)\n    .border_1()\n    .border_color(cx.theme().border)\n    .rounded(cx.theme().radius)\n```\n\nRules:\n\n- do not hard-code product colors, corner radii, spacing, or control geometry;\n- application code must not introduce raw hex, `rgb`/`rgba`, or `hsla`; read a\n  semantic color from `cx.theme()` or add the missing role to the product theme;\n- application layout should use GPUI's rem-based scale helpers (`p_2()`,\n  `gap_3()`, `w_64()`, `text_sm()`) instead of direct `px(...)` values;\n- use semantic tokens for meaning, not palette position;\n- keep state-independent geometry in the ordinary builder chain;\n- use GPUI `hover`, `active`, `focus`, and `focus_visible` modifiers for\n  runtime interaction states;\n- use a component's semantic state styles for checked, selected, pressed, or\n  disabled appearance;\n- keep popup ownership in explicit state so its trigger can render the open or\n  pressed appearance until dismissal;\n- guard hover/active refinements when a disabled control must not react;\n- keep component variants few and meaningful rather than adding a variant for\n  every call site.\n- bind primary styling to the decision area's real default commit and Enter\n  action; do not derive it from action count, frequency, or toolbar position.\n- keep Badge and Alert variants semantic and scarce. Ordinary metadata stays\n  neutral; do not map every enum case or section to a different color merely\n  because a variant exists.\n\nThe effective precedence is instance style, active semantic value states,\ndisabled state, then GPUI runtime interaction refinements. Later layers only\nreplace fields they set.\n\nPrefer `Theme::semantic_tokens()` for new application-owned presentation. The\nsemantic token surface contains generic color roles plus radius, spacing,\ntypography, and shadow scales; it deliberately avoids component names. Legacy\ncomponent-specific theme values still exist for compatibility but should not\nbecome the extension point for every application widget.\n\nThere is one current ownership caveat: `Theme::spacing_tokens()` projects the\ndefault scale, and `Theme::apply_semantic_tokens(...)` does not store custom\nspacing or elevation scales. An application that customizes those scales must\nretain its own `SemanticThemeTokens` (or narrower design-system state) and make\nthat state available to its components. Do not write a custom spacing snapshot\ninto the global theme and expect a later `cx.theme().semantic_tokens()` call to\nreturn it.\n\nEdit the global GPUI Component theme through `Theme::update(cx, |theme| ...)`.\nThe theme keeps the same colors twice (`colors` as solid colors, `tokens` as\nrenderable backgrounds that may carry a gradient) and the Base layer holds a\nprojection for its scrollbars and resize handles; `update` brings all three\nback in step after the closure and refreshes every window. An edit through\n`Theme::global_mut(cx)` updates only the field you touched — a sidebar can then\npaint its text from the new colors and its background from the old tokens —\nso it owns the rest: derive `tokens` from `colors`, call `Theme::sync_base(cx)`,\nrefresh the windows. `Theme::change(...)` performs the projection as part of a\ncomplete theme change.\n\nAn outward focus ring needs physical room. An ancestor with\n`overflow_hidden()` clips it. Prefer layouts that leave room; if a product must\nclip heavily, use the theme's focus-ring policy and retain the focused border\ninstead of silently hiding all keyboard focus.\n\n### Base font is the application zoom control\n\nThe Component Root plugin calls `window.set_rem_size(cx.theme().font_size)` from\nits `prepare` hook before the Root surface is rendered. Therefore the theme's\nbase font is not only body typography; it is the reference length for the\napplication's rem-based design scale. This deliberately follows the useful part\nof Tailwind's model: named type, spacing, and size steps share one relative base\ninstead of becoming unrelated pixel constants.\n\nChange zoom by updating the base font and refreshing the window:\n\n```rust\nTheme::update(cx, |theme| theme.font_size = px(18.));\n```\n\nThe base font itself is a pixel value because it anchors the scale. Descendant\napplication UI should normally use relative helpers—`text_sm()`, `gap_2()`,\n`px_3()`, `h_8()`, `size_4()`—so type, whitespace, controls, and icons respond\ntogether. A custom component that combines rem-based text with fixed-pixel\npadding or icon geometry must document why that part should not zoom.\n\nTreat every direct `px(...)` and raw color constructor in application UI as a\nreview finding. Accept it only for a documented physical/platform boundary,\nmeasured runtime geometry, raster/data color, or the theme/token definition\nitself. Convenience and matching a screenshot are not valid exceptions.\n\nAnything cached from resolved layout must include `window.rem_size()` in its\ninvalidation key, directly or through a revision that changes with it. This\nincludes wrapped row heights, text shaping/layout, virtual-list measurement,\npopup and dialog geometry, icon sizing derived from text, and custom canvas\nmetrics. The Command component's variable-height rows are an ecosystem example:\nthey remeasure when rem changes because the same fixed width wraps differently\nat a larger base font.\n\nDo not confuse this application zoom with Dock panel zoom. Dock zoom is a\nstateful layout operation that makes one tab group fill the DockArea\nwhile keeping the container chrome and the way back out. It must not modify the\nwindow rem size.\n\n## Events, actions, and focus\n\nUse pointer callbacks for pointer-specific behavior. Use GPUI Actions for\ncommands that should support key bindings, menus, or dispatch from multiple\ninputs. Keep action handlers close to the view that owns the command.\n\nModel one logical desktop command once. A toolbar Button, `DropdownMenu` item,\n`ContextMenu` item, menu-bar item, and key binding should dispatch the same\nAction or call the same owner method instead of copying five mutations. Derive\ntheir label, icon, shortcut, and enabled state from one command policy where\npractical, so the entry points cannot disagree. The menu owns navigation and\ndismissal; the feature owner still owns whether the command is allowed and\nwhat it does.\n\nPreserve semantic roles in the element choice. Use `Button` for commands even\nwhen the desired treatment is quiet—select `outline`, `ghost`, or an icon\npresentation instead of replacing it with `Link`. GPUI Kit applications\nreserve `Link` for targets opened by a browser or mail client, such as a URL,\nweb document, or email address. Use the relevant navigation component for an\nin-app destination and `Button`/`Action` for a command. This is a product\nconvention, not a limitation of `gpui_kit::base::Link`, whose `open_with` seam can\nroute a destination elsewhere.\n\nOnly stop propagation when a nested interaction must prevent its parent from\nhandling the same event. Blanket propagation stops break menus, selection,\ndragging, and window-level commands in ways that are difficult to diagnose.\n\nBind keys before building the menu bar. `cx.set_menus` reads the keymap at\nthe moment it is called and bakes each item's shortcut into the native menu,\nso a binding registered afterwards never shows next to its menu item and the\nitem does not react to the key. Call `cx.bind_keys` first, then\n`cx.set_menus`; if the keymap changes later (a user keymap file, a locale\nswitch that rebuilds the menus), call `cx.set_menus` again.\n\nMake focus ownership explicit:\n\n- retain a `FocusHandle` in the entity that owns keyboard interaction;\n- register key contexts and actions on the appropriate focused region;\n- transfer focus when opening an overlay and restore it on dismissal;\n- render a visible `focus_visible` state;\n- do not request focus unconditionally from `render`.\n\nA tracked handle is a Tab stop only when it says so: build it with\n`cx.focus_handle().tab_stop(true)` (or `.tab_index(n)`), because the element's\nown `tab_index`/`tab_stop` settings do not apply to a handle passed to\n`track_focus`. A stateless component may create that handle in `render`\nthrough `window.use_keyed_state(id, cx, |_, cx| cx.focus_handle().tab_stop(true))`;\nthe keyed state survives re-renders, so the Tab order is stable — this is\nwhat `Button` does.\n\nAttach a `key_context` and its `on_action` handlers to the same focused region.\nBindings are contextual: a registered Action without the intended focus path\nis not a working keyboard interaction. Composite widgets should implement the\ncomplete navigation model—arrow movement, Home/End or page movement where\nappropriate, confirmation, cancellation, and Tab behavior—rather than a few\nisolated shortcuts.\n\nModal surfaces must trap focus and restore the previous valid focus target on\ndismissal. Nested overlays dismiss from the top. Handle rapid close/open\nsequences without restoring focus through an intermediate, already-closing\nsurface.\n\n## Async work and side effects\n\nStart async work from an event, lifecycle hook, or named method—not as an\nunconditional side effect of `render`. Capture weak entities when work should\nnot keep a closed view alive. When the task completes, update state through the\nGPUI context, handle the case where the entity or window no longer exists, and\nnotify once after the coherent state change.\n\nRepresent async operations with explicit states such as idle, loading, loaded,\nand failed. Preserve usable previous data during refresh when possible. Prevent\nduplicate destructive submissions and surface recoverable errors in the UI;\ndo not rely on logs as user feedback.\n\nUse background executors for expensive parsing or computation, but keep GPUI\nentity mutation on the appropriate application context. Results can arrive\nafter the request, document, view, or selection has changed; attach a revision\nor identity and reject stale work rather than applying it to new state.\n\n## Layout, measurement, and scrolling\n\n`h_flex` centres its children on the cross axis; `v_flex` leaves flexbox's\ndefault, `stretch`. This matches Zed's `h_flex`, and it is what a row of\ncontrols wants, so a row of icon and label says nothing. It is not what a row\nof full-height columns wants: a column placed in a bare `h_flex` does not fill\nthe row's height, so a column taller than the row is centred and its top —\ncommonly a header — is clipped off the top of the window, with nothing near the\ncolumn to say why. A row whose children are columns says `items_stretch()`:\n\n```rust\nh_flex()\n    .items_stretch()\n    .size_full()\n    .child(sidebar)\n    .child(content)\n```\n\nMost UI should use GPUI layout rather than measuring itself. Measurement is a\ndeep behavior tool for popups, virtualization, editors, resize handles, charts,\nand similar components whose correctness depends on resolved geometry.\n\n- Put measurement and geometry in the layer that owns the behavior.\n- Observe bounds in prepaint only when ordinary layout cannot express the\n  relationship.\n- Never mutate unrelated application state every prepaint.\n- Treat measured data as frame- or revision-scoped; it can become stale after\n  typography, rem size, width, theme, or content changes.\n- Centralize shared geometry such as popup flipping and viewport clamping so\n  every overlay follows the same edge policy.\n\nFor alignment invariants, prefer construction over correction: sibling regions\nshould consume the same spacing token or shared inset instead of repeating\nequivalent literals. Add geometry assertions or visual regression coverage for\ncritical repeated edges, columns, and gaps. Exercise more than the default\nwindow: rem zoom and display scaling can turn fractional coordinates into a\none-physical-pixel drift even when the default screenshot looks aligned.\n\nMeasure the resolved result when reviewing precision, but do not encode a\nmeasured correction as a raw `px(...)` nudge. Trace the mismatch to duplicated\npadding, nested insets, border ownership, font metrics, or rounding, then fix\nthe structural owner.\n\n`h_flex()` and `v_flex()` are not mirror images: `h_flex()` centers its\nchildren on the cross axis, `v_flex()` leaves them stretching. A column placed\nin a row therefore takes its content's height, not the row's, and a column\ntaller than the row is centered — its header is pushed off the top edge and\nclipped. Give a full-height column `h_full()`, or give the row `items_start()`\nor `items_stretch()`, whenever the child owns a header, a footer, or a scroll\nregion that must resolve against the row's height.\n\nEvery scrollable region must have one owner. In flex layouts, apply\n`min_w_0()` or `min_h_0()` to the flexible child that is allowed to shrink.\nA flex item only drops its content-based automatic minimum size when its own\noverflow is not visible, so an ordinary flexible child refuses to shrink around\nlong content until you say so. `Scrollable` handles this for its own wrapper,\nbut a plain `div` between it and the flex container still needs the minimum\nreleased. Avoid accidental nested scrolling; route wheel input to the intended\naxis and preserve platform/wasm differences when an API is not portable.\n\nAttach `Scrollable` to the element that owns the full panel, editor, or window\nviewport so its scrollbar resolves against the region edge. Put content inset\ninside that scroll owner rather than wrapping the scroll owner in a padded\ncontainer. A scrollbar floating between content and the panel boundary usually\nreveals the wrong scroll owner or padding on the wrong layer.\n\n## Lists, tables, and large data\n\nUse virtualization when data can grow beyond a small, bounded collection. Keep\nrow identity separate from visible position and avoid cloning the full data set\non every render. Let a stateful list or table own navigation, selection, scroll\ncoordination, and visible-range calculation while item renderers own row\npresentation.\n\nSeparate:\n\n- source data and domain IDs;\n- filtering/sorting state;\n- selection state;\n- viewport/scroll state;\n- row rendering.\n\nThis keeps updates local and prevents the view tree from becoming the data\nmodel.\n\nVirtualization is a behavioral contract, not just a performance switch. Item\nmeasurement must be invalidated when width, typography, rem size, or row\ncontent changes. Keyboard selection and scroll-to-item must operate in model\ncoordinates even when most elements do not exist in the current frame.\n\n## Public API design\n\nFor reusable components:\n\n- constructors should establish valid defaults;\n- builders take and return `Self` and use domain language;\n- callbacks describe requested changes and include pointer events only when\n  modifiers or pointer details are meaningful;\n- evolvable behavioral seams use private fields, builders for construction,\n  and readers for inspection;\n- boolean readers use `is_` or `has_` where a same-named builder exists;\n- non-boolean setters use `with_` when readers need the plain field name;\n- explicit compound parts are preferable to inspecting arbitrary descendants;\n- adding reusable behavior must not force a product-level visual choice.\n\nPrivate fields are the default for behavioral state that must evolve without\nbreaking callers. Public fields are appropriate for deliberately record-like\nconfiguration, theme tokens, geometry, and serialized schemas. Every public\nstruct with public fields must carry `#[non_exhaustive]`. Provide constructors,\n`Default`, or builders so callers can create values without exhaustive struct\nliterals. This preserves the ability to add fields without breaking callers.\nApply this rule to new types and public API changes; unrelated existing types\ncan be migrated separately.\n\nKeep public module paths stable while reorganizing internals: use a module seam\nwith deliberate re-exports so folders can change without forcing downstream\nimports to change. Prefer platform control terminology and established project\nnaming over web-framework vocabulary.\n\n## Platform and capability boundaries\n\nDo not assume every native or web target supports the same facility. Window\ndecorations, accessibility bridges, system notifications, clipboard behavior,\nscroll gestures, fonts, and timing can differ. Put platform-specific code\nbehind a narrow capability seam and define the fallback behavior.\n\nA platform branch must preserve the semantic contract even if presentation\ndiffers. For example, a system notification may have different retraction\nsupport, but the application still needs a coherent delivery state. Test both\nthe shared state machine and the platform adapter where possible.\n\n## File and naming conventions\n\n- Name views and entities after product concepts: `ProjectList`,\n  `ProjectEditor`, `SettingsState`.\n- Name event handlers after intent: `confirm_delete`, `open_project`,\n  `on_query_changed`.\n- Keep one main responsibility per module; split a file when state ownership or\n  lifecycle can no longer be understood without reading unrelated behavior.\n- Keep component module, state, events, and focused tests together when they\n  change together.\n- Document invariants and surprising lifecycle constraints; do not narrate\n  obvious builder calls.\n- Use `rustfmt` and satisfy the workspace's Clippy rules. Avoid broad `allow`\n  attributes that conceal unrelated warnings.\n\n### Vocabulary is part of the API\n\nUse the same word for the same concept across components. Before naming a new\nmethod, search GPUI, `gpui-base`, and GPUI Component for the established term;\nprefer macOS/Windows control terminology where the ecosystem has no precedent.\nLocalized documentation preserves exact API identifiers and established UI\nframework terms when translation would reduce precision. Format identifiers as\ncode, explain retained terms when needed, and do not mix languages merely to\nmake ordinary prose sound technical.\n\n| Concept | Naming pattern | Example |\n| --- | --- | --- |\n| Value-like rendered control | noun | `Button`, `Checkbox`, `Tab` |\n| Retained behavioral model | `<Control>State` | `InputState`, `TableState` |\n| Imperative shared reference | `<Control>Handle` | `DialogHandle`, scroll handle |\n| Semantic notification | `<Control>Event` | `TableEvent`, `SelectEvent` |\n| Keyboard command | verb or intent noun | `Confirm`, `Cancel`, `SelectNext` |\n| Pluggable data/behavior owner | `<Role>Delegate` / `<Role>Provider` | `TableDelegate`, `CompletionProvider` |\n| Application-supplied presentation | `render_<part>` or `<part>_renderer` | `render_item` |\n| Construction | `new`, or a semantic constructor | `new`, `horizontal`, `vertical` |\n| Fluent property | noun/adjective | `label`, `disabled`, `selected`, `placement` |\n| General non-boolean replacement builder | `with_<field>` | `with_size`, `with_mode` |\n| In-place mutation | `set_<field>` | `set_items`, `set_selected_index` |\n| Boolean reader | `is_<adjective>` / `has_<noun>` | `is_open`, `is_closable`, `has_selection` |\n| Plain value reader | field noun | `placement`, `selected_value` |\n| Callback registration | `on_<event or intent>` | `on_click`, `on_open_change` |\n| Rendering a named region | `render_<region>` | `render_toolbar`, `render_content` |\n\nFor new APIs, fluent builders omit `set_` because they consume and return\n`Self`; mutation through `&mut self` uses `set_`. Preserve established public\nnames when changing them would cause needless churn. Existing builder names\nsuch as `set_position` are compatibility exceptions, not patterns for new APIs.\n\nA boolean reader is either `has_<noun>`, when the value holds something, or\n`is_<adjective>`, when it describes a state or a permission. Reach for the\nadjective whenever the action has one: `is_closable` over `can_close`,\n`is_zoomable` over `can_zoom`, `is_copyable` over `can_copy`. When the action\nis a verb phrase with no adjective form, name the thing it needs instead:\n`has_definition`, not `can_go_to_definition`. Do not add new `can_` readers.\n\nBoolean builders may use the field name (`disabled(bool)`) while their readers\nuse `is_disabled()`. For a public seam struct containing non-boolean fields,\nuse `with_item_ix(...)` for construction and `item_ix()` for reading so setter\nand getter names never collide. Prefer `_ix` for new local or internal\nzero-based indices, preserve established public terms such as `selected_index`,\nand do not introduce `_idx`. If callers never construct the seam value, do not\npublish a builder merely for symmetry.\n\n### Let the enclosing name carry the context\n\nA name is read inside something. A field is read inside its type and a parameter\ninside its method, so neither repeats what encloses it: `with_item_ix(ix)`, not\n`with_item_ix(item_ix)`.\n\nKeep one type's fields at the same level of abbreviation. A single field spelled\nout in full becomes the odd one out, and a reader goes looking for the\ndistinction that made it different. Because a builder is named `with_<field>`,\nshortening a field shortens its builder with it and the pair stays matched.\n\nShorten only where the enclosing name really does disambiguate. When a short\nform is also the established term for a *different* quantity elsewhere in the\necosystem, say which one you mean in the doc comment rather than lengthening the\nidentifier — the doc is read at the call, and it can explain what a longer name\ncould only hint at.\n\n### Use precise domain words\n\n- **selected** is persistent membership or the active item; **focused** is the\n  current keyboard target; **hovered** is pointer presence; **confirmed** is an\n  activation result. Never use them interchangeably.\n- **open/close** describes an overlay or disclosure state; **show/hide** is for\n  transient presentation requests; **expand/collapse** describes structure.\n- **disabled** prevents interaction; **readonly** permits navigation and\n  selection but prevents editing; **loading** prevents duplicate work while an\n  operation is pending. Spell the state `readonly` — one word, as the\n  `readonly(bool)` builder and `is_readonly()` reader do — in identifiers,\n  interface labels, and documentation alike; never `read-only` or `read only`.\n- **index** is a current positional coordinate; **id** is stable identity;\n  `IndexPath` represents hierarchical position. Do not persist or key\n  reorderable data by index.\n- **value** is controlled domain data; **presentation** is a read-only snapshot\n  prepared for rendering; **state** is retained behavior.\n- **placement** is a side or anchor policy; **position** is resolved geometry.\n- **size** is a semantic control tier; **width/height/bounds** are geometry.\n- **child/children** follows GPUI composition; named slots such as `header`,\n  `footer`, `trigger`, and `content` carry additional semantics.\n\nAvoid vague public names such as `data`, `item2`, `handle_action`, `update_ui`,\n`process`, `manager`, or `config` when a narrower domain term exists. `Manager`\nis appropriate only when a type truly coordinates a collection or lifecycle,\nas `ToastManager` does.\n\n### Type and module style\n\n- Rust types and Actions use `UpperCamelCase`; modules, functions, methods,\n  fields, and local variables use `snake_case`; constants use\n  `SCREAMING_SNAKE_CASE`.\n- A module named after a component owns its public seam. Internal folders may\n  split state, element, geometry, platform adapter, and tests without leaking\n  those folder names into imports.\n- Use singular module names for one component concept and established\n  ecosystem names for families (`input`, `table`, `dock`).\n- Suffix type-erased wrappers with `Any` only when they erase a real type\n  boundary, such as `AnyInputState` or `AnyElement`.\n- Suffix identifiers with `Id`, zero-based indices with `ix`, and collections\n  with meaningful plurals. Do not alternate `idx`, `index`, and `ix` in one\n  subsystem.\n- Name predicates positively when possible. A positive `enabled`/`visible`\n  contract is easier to compose than multiple negatives, but preserve\n  established API terms such as `disabled` where they match control semantics.\n\n### Callback and event wording\n\nUse `on_click` only for a genuine click-level contract. A controlled semantic\nprimitive in Base should prefer `on_change(next_value, ...)`; a styled\ncompatibility component may retain `on_click` when pointer details or existing\nAPI expectations matter. Do not invent a `ClickEvent` for a model-driven\nchange.\n\nName before/after lifecycle hooks precisely. `on_will_change` can veto or\nprepare; `on_change` observes a requested/current value contract; `on_confirm`\ncommits a choice; `on_dismiss` closes a transient surface. Document whether a\ncallback runs before internal state changes, after them, or instead of them,\nand whether it may synchronously re-enter the component.\n\n### Documentation and copy style\n\nPublic docs should begin with what a type does and who owns its state. Examples\nmust use current, compilable APIs and show stable IDs. Document defaults,\nplatform limitations, focus behavior, callback ordering, and any requirement\nto call `notify`, `emit`, or a theme synchronization method.\n\nFollow the [interface-language rules](./design-guides.md#interface-language) for\nlabels, commands, confirmation dialogs, capitalization, and ellipses. Keep one\ncanonical term for each domain object, command, and state.\n\nTranslation keys describe stable intent (`dialog.delete_project.title`), not a\nsource-language sentence or a screen coordinate. Never assemble a sentence\nfrom translated fragments or reuse one key for meanings that happen to share\nthe same English text.\n\nLocalize intent, not syntax. Give every locale control over word order,\npluralization, punctuation, and the amount of context it needs. Review strings\ninside the component and with realistic data. Tests or linting should catch\nmissing keys, unintended CJK text in English resources, three-dot ellipses,\nunreviewed ALL CAPS, and inconsistent fixed terms; human review still decides\nwhether repetition is justified by context. Verify every string inside its\ncomponent with realistic content, text expansion, and application zoom.\n\n## Testing strategy\n\nTest at the lowest layer that can prove the behavior:\n\n1. pure tests for state transitions, geometry, parsing, and ordering;\n2. GPUI context tests for entities, events, and subscriptions;\n3. `VisualTestContext` interaction tests for focus, keyboard, pointer, layout,\n   and rendered state;\n4. example or application smoke tests for complete workflows.\n\nFor an interactive component, cover the semantic contract rather than its\nimplementation details: pointer and keyboard activation, controlled value\nchanges, disabled behavior, focus movement, event count/order, stable identity,\nand important empty or failure states. Add a regression test before fixing a\nbug whenever the failure can be reproduced deterministically.\n\nFor UI behavior that depends on the real window system, test through the\naccessibility tree by role, label, value, enabled state, focus, and selection.\nRe-read the tree after every state-changing action because element indexes are\nsnapshots. Use screenshots for visual facts the semantic tree cannot express;\nuse coordinate input only as a fallback. Report automated and manual evidence\nseparately.\n\n## Performance rules\n\n- Do not mutate state or notify unconditionally in `render`.\n- Avoid rebuilding entities, subscriptions, focus handles, and expensive data\n  structures per frame.\n- Notify the narrowest owning entity after a coherent state change.\n- Virtualize long collections and render only the visible range.\n- Avoid cloning large strings or collections solely to satisfy a closure;\n  capture stable handles or shared data.\n- Measure before adding caches. A cache must have a clear invalidation owner.\n- Keep animation work bounded and honor reduced motion.\n\n## Common failure modes\n\nAvoid these patterns:\n\n- one entity containing the entire application's unrelated state;\n- business logic and network requests embedded in a long `render` method;\n- random or index-based `ElementId` values for reorderable content;\n- literal colors and radii that break custom themes;\n- custom clickable `div`s where a semantic component already supplies focus,\n  keyboard, disabled, and accessibility behavior;\n- duplicated local state that drifts from a controlled model value;\n- `cx.notify()` loops caused by mutation during every render;\n- nested scroll containers without explicit ownership;\n- a new component variant for a one-off screen;\n- confirmation dialogs for reversible, low-risk actions;\n- tests that call internal methods but never exercise keyboard or pointer\n  behavior.\n\n## Rules for coding agents\n\nBefore editing, an agent must read the nearest implementation, its tests, the\nre-export seam, and the relevant component documentation. It must search the\ncurrent source for signatures instead of translating a React, CSS, or old GPUI\nexample by analogy.\n\nFor each change, the agent should be able to name:\n\n1. the behavior owner and presentation owner;\n2. the retained identity and state lifecycle;\n3. the pointer, keyboard, focus, and accessibility contract;\n4. the layout and overflow owner;\n5. the theme tokens and intentional exceptions;\n6. the test that would fail if the behavior regressed.\n\nGenerated code must be reviewed and tested by a person. “Compiles” is not a UI\nquality bar, and a broad refactor that merely makes generated code look tidy is\nnot a substitute for matching the repository's architecture.\n\n## Implementation checklist\n\nBefore opening a change for review, confirm that:\n\n- state and side-effect ownership are explicit;\n- `RenderOnce` versus `Entity<T>` is chosen deliberately;\n- repeated elements have stable domain-based IDs;\n- theme tokens and component sizes replace isolated visual literals;\n- keyboard actions, focus, disabled state, and overlays work together;\n- loading, empty, error, and cancellation paths are represented;\n- long data sets use an appropriate virtualized component;\n- public API additions preserve dependency direction and encapsulation;\n- tests prove behavior at the appropriate layer;\n- formatting, Clippy, targeted tests, and relevant examples pass.\n\nSee [Getting Started](./getting-started.md) for application setup and the\ncomponent pages for current API details.\n","skills/gpui-kit/references/conventions.md":"# Component-family conventions\n\nUse this page to predict a component's shape before reading its detailed API. These conventions describe Rust GPUI Component. JavaScript uses its host's generated catalog; a Rust method is not automatically a JavaScript method.\n\n## Choose the family\n\n| Task | Family and constructor | State owner | Event or composition |\n| --- | --- | --- | --- |\n| Execute a command | `Button::new(\"save\")` | Application owns the operation | `on_click` receives a click event |\n| Change a boolean | `Checkbox::new(\"remember\")`, `Switch::new(\"enabled\")`, `Radio::new(\"choice\")` | Application supplies `checked(bool)` | `on_change` receives the requested `&bool` |\n| Choose one radio option | `RadioGroup::new(\"delivery\")` | Application supplies `selected_index(Option<usize>)` | `on_change` receives the requested `&usize` |\n| Edit retained text | `Input::new(&self.input)` | View retains `Entity<InputState>` | Retain the subscription; handle `InputEvent` |\n| Display a supplied patch | `Diff::new(&self.diff)` | View retains `Entity<DiffState>`; application parses supplied unified/Git diff with `DiffFile::parse`; one state shows all files | Readonly `RenderOnce` element; retain subscriptions to `DiffEvent` when needed |\n| Lay out fields | `Form::new()` | Children retain their own state | `child(Field)`, `columns`, `label_layout`, `footer` |\n| Supply a compound part | `Field::new()`, `Tab::new()` | Containing component owns placement/selection | Read the parent's accepted child type |\n\nConstructors establish the component family's ownership model. Do not infer that every `new` takes an ID or that every `child` accepts an arbitrary element. Keep domain IDs stable when controls are reordered. Positional selection APIs remain positional; applications map them to domain identity when needed.\n\n## A value request is different from a command\n\nFor Checkbox, Switch, Radio, and RadioGroup, use the same owner-update pattern:\n\n```rust\nSwitch::new(\"enabled\")\n    .checked(self.enabled)\n    .on_change(cx.listener(|this, next, _, cx| {\n        this.enabled = *next;\n        cx.notify();\n    }))\n```\n\nReplace Switch with Checkbox or Radio without changing the boolean callback shape. Radio represents selecting an option; its activation semantics still differ from toggling a Switch. RadioGroup supplies an index, so its owner stores `Some(*next)` instead.\n\n`on_change` requests a value; it does not mutate your application model. Existing `on_click` calls on these four controls remain valid compatibility aliases. Both names set one handler, and the last call wins. Use `Button::on_click` for commands. Retained controls such as Input keep their existing event/subscription API because the state entity, rather than a transient builder, owns their changes.\n\n## Form layout has independent decisions\n\n| Decision | API | Default |\n| --- | --- | --- |\n| Label above or beside its control | `label_layout(Axis::Vertical / Horizontal)` | Above |\n| Number of field columns | `columns(count)` | One |\n| A field spanning several columns | `Field::col_span(count)` | One |\n| Commands after the fields | `footer(element)` | No footer; supplied footer spans all columns and aligns to the trailing edge |\n\n`Form::horizontal()` and `h_form()` mean labels beside controls. They do not put all fields into one horizontal row. `Form::vertical()`, `v_form()`, and `layout(Axis)` remain supported.\n\n```rust\nForm::new()\n    .label_layout(Axis::Horizontal)\n    .columns(2)\n    .child(Field::new().label(\"Name\").child(Input::new(&self.name)))\n    .child(Field::new().label(\"Email\").child(Input::new(&self.email)))\n    .footer(Button::new(\"save\").label(\"Save\"))\n```\n\nThe footer supplies layout only: attach the save action to the Button. Form does not own submission, validation, responsive breakpoints, or data persistence. Choose column count for the available width. Put multiple action buttons in one supplied action row with a shared gap. Keep field descriptions with their Field so they follow its alignment.\n\n## Import capabilities explicitly\n\nComponents live in their component modules. Common capabilities may be extension traits, not inherent methods: import `ButtonVariants` for button variants, `Sizable` for size tiers, `Disableable` for supported disabled builders, `ActiveTheme` for theme access, and `WindowExt` for window overlays. Do not infer that every component supports every trait.\n\nUse the [complete application recipe](recipes.md) for imports, retained ownership, initialization, Root, and overlay layers. For a narrow task, load its component page and the relevant section of the coding/design guides; a component catalog is not a required reading sequence.\n\n## Verify the convention transfer\n\nWhen transferring a pattern to another family member, check that it compiles, receives the expected requested value, preserves controlled state after redraw, and behaves correctly when disabled. For Form, check label orientation independently of column count and keep footer geometry outside the field grid's individual cells.\n\nIn this repository, `cargo test -p gpui-kit-recipes` compiles the external-style consumer and runs its interaction tests, and `script/check-ai rust` runs the control-family event and compatibility tests and Form geometry tests. These are deterministic contract checks, not measured AI first-attempt success rates.\n","skills/gpui-kit/references/gpui/action.md":"# Actions & Keybindings\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Key Formats](#key-formats) · [Menu Bar Shortcuts](#menu-bar-shortcuts) · [Action Naming](#action-naming) · [Context-Aware Bindings](#context-aware-bindings) · [Best Practices](#best-practices)\n\n## Overview\n\nActions provide declarative keyboard-driven UI interactions in GPUI.\n\n**Key Concepts:**\n- Define actions with `actions!` macro or `#[derive(Action)]`\n- Bind keys with `cx.bind_keys()`\n- Handle with `.on_action()` on elements\n- Context-aware via `key_context()`\n\n## Quick Start\n\n### Simple Actions\n\n```rust\nuse gpui_kit::actions;\n\nactions!(editor, [MoveUp, MoveDown, Save, Quit]);\n\nconst CONTEXT: &str = \"Editor\";\n\npub fn init(cx: &mut App) {\n    cx.bind_keys([\n        KeyBinding::new(\"up\", MoveUp, Some(CONTEXT)),\n        KeyBinding::new(\"down\", MoveDown, Some(CONTEXT)),\n        KeyBinding::new(\"cmd-s\", Save, Some(CONTEXT)),\n        KeyBinding::new(\"cmd-q\", Quit, Some(CONTEXT)),\n    ]);\n}\n\nimpl Render for Editor {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .key_context(CONTEXT)\n            .on_action(cx.listener(Self::move_up))\n            .on_action(cx.listener(Self::move_down))\n            .on_action(cx.listener(Self::save))\n    }\n}\n\nimpl Editor {\n    fn move_up(&mut self, _: &MoveUp, cx: &mut Context<Self>) {\n        // Handle move up\n        cx.notify();\n    }\n\n    fn move_down(&mut self, _: &MoveDown, cx: &mut Context<Self>) {\n        cx.notify();\n    }\n\n    fn save(&mut self, _: &Save, cx: &mut Context<Self>) {\n        // Save logic\n        cx.notify();\n    }\n}\n```\n\n### Actions with Parameters\n\n```rust\n#[derive(Clone, PartialEq, Action, Deserialize)]\n#[action(namespace = editor)]\npub struct InsertText {\n    pub text: String,\n}\n\n#[derive(Action, Clone, PartialEq, Eq, Deserialize)]\n#[action(namespace = editor, no_json)]\npub struct Digit(pub u8);\n\ncx.bind_keys([\n    KeyBinding::new(\"0\", Digit(0), Some(CONTEXT)),\n    KeyBinding::new(\"1\", Digit(1), Some(CONTEXT)),\n    // ...\n]);\n\nimpl Editor {\n    fn on_digit(&mut self, action: &Digit, cx: &mut Context<Self>) {\n        self.insert_digit(action.0, cx);\n    }\n}\n```\n\n## Key Formats\n\n```rust\n// Modifiers\n\"cmd-s\"         // Command (macOS) / Ctrl (Windows/Linux)\n\"ctrl-c\"        // Control\n\"alt-f\"         // Alt\n\"shift-tab\"     // Shift\n\"cmd-ctrl-f\"    // Multiple modifiers\n\n// Keys\n\"a-z\", \"0-9\"    // Letters and numbers\n\"f1-f12\"        // Function keys\n\"up\", \"down\", \"left\", \"right\"\n\"enter\", \"escape\", \"space\", \"tab\"\n\"backspace\", \"delete\"\n\"-\", \"=\", \"[\", \"]\", etc.  // Special characters\n```\n\n## Menu Bar Shortcuts\n\n`cx.set_menus` reads the keymap **at the moment it is called** and bakes each\nitem's shortcut into the native menu. A key bound afterwards never appears next\nto its menu item, and the item does not react to that key. There is no event to\nhook: bind first, then build the menus, and rebuild them when the keymap\nchanges.\n\n```rust\npub fn init(cx: &mut App) {\n    // 1. Bindings first — the menu items copy their shortcuts from these.\n    cx.bind_keys([\n        KeyBinding::new(\"cmd-n\", NewChat, None),\n        KeyBinding::new(\"cmd-,\", OpenSettings, None),\n        KeyBinding::new(\"cmd-q\", Quit, None),\n    ]);\n\n    // 2. Then the menu bar.\n    cx.set_menus(vec![Menu {\n        name: \"File\".into(),\n        items: vec![\n            MenuItem::action(\"New Chat\", NewChat),\n            MenuItem::action(\"Settings…\", OpenSettings),\n            MenuItem::separator(),\n            MenuItem::action(\"Quit\", Quit),\n        ],\n    }]);\n}\n```\n\nCall `cx.set_menus` again after anything that changes bindings or labels: a\nuser keymap file loaded later, a locale switch that renames the items. `Undo`,\n`Redo`, `Cut`, `Copy`, `Paste` need no `on_action` of your own — give the item\nan `OsAction` and the platform forwards it to the focused text control.\n\n## Action Naming\n\nPrefer verb-noun pattern:\n\n```rust\nactions!([\n    OpenFile,      // ✅ Good\n    CloseWindow,   // ✅ Good\n    ToggleSidebar, // ✅ Good\n    Save,          // ✅ Good (common exception)\n]);\n```\n\n## Context-Aware Bindings\n\n```rust\nconst EDITOR_CONTEXT: &str = \"Editor\";\nconst MODAL_CONTEXT: &str = \"Modal\";\n\n// Same key, different contexts\ncx.bind_keys([\n    KeyBinding::new(\"escape\", CloseModal, Some(MODAL_CONTEXT)),\n    KeyBinding::new(\"escape\", ClearSelection, Some(EDITOR_CONTEXT)),\n]);\n\n// Set context on element\ndiv()\n    .key_context(EDITOR_CONTEXT)\n    .child(editor_content)\n```\n\n## Best Practices\n\n### ✅ Use Contexts\n\n```rust\n// ✅ Good: Context-aware\ndiv()\n    .key_context(\"MyComponent\")\n    .on_action(cx.listener(Self::handle))\n```\n\n### ✅ Name Actions Clearly\n\n```rust\n// ✅ Good: Clear intent\nactions!([\n    SaveDocument,\n    CloseTab,\n    TogglePreview,\n]);\n```\n\n### ✅ Handle with Listeners\n\n```rust\n// ✅ Good: Proper handler naming\nimpl MyComponent {\n    fn on_action_save(&mut self, _: &Save, cx: &mut Context<Self>) {\n        // Handle save\n        cx.notify();\n    }\n}\n\ndiv().on_action(cx.listener(Self::on_action_save))\n```\n\n","skills/gpui-kit/references/gpui/async.md":"# Async & Background Tasks\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Core Patterns](#core-patterns) · [Common Pitfalls](#common-pitfalls)\n\n## Overview\n\nGPUI provides integrated async runtime for foreground UI updates and background computation.\n\n**Key Concepts:**\n\n- **Foreground tasks**: UI thread, can update entities (`cx.spawn`)\n- **Background tasks**: Worker threads, CPU-intensive work (`cx.background_spawn`)\n- All entity updates happen on foreground thread\n\n## Quick Start\n\n### Foreground Tasks (UI Updates)\n\nWhen spawned from `Context<Self>`, the closure receives `(WeakEntity<Self>, &mut AsyncApp)`:\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx: &mut AsyncApp| {\n            // Runs on UI thread, can await and update entities\n            let data = fetch_from_api().await;\n\n            this.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            }).ok();\n        }).detach();\n    }\n}\n```\n\nWhen spawned from `&mut App` (not inside an entity), the closure receives only `(cx: &mut AsyncApp)`:\n\n```rust\ncx.spawn(async move |cx: &mut AsyncApp| {\n    // No entity reference\n}).detach();\n```\n\n### Spawn with Window Context (spawn_in)\n\nUse `spawn_in` when the task also needs window access (`update_in`):\n\n```rust\nimpl MyComponent {\n    fn animate(&mut self, window: &mut Window, cx: &mut Context<Self>) {\n        cx.spawn_in(window, async move |this, cx| {\n            // cx here is AsyncWindowContext\n            this.update_in(cx, |state, window, cx| {\n                // Can access window here\n                state.frame += 1;\n                cx.notify();\n            }).ok();\n        }).detach();\n    }\n}\n```\n\n### Background Tasks (Heavy Work)\n\n```rust\nimpl MyComponent {\n    fn process_file(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            // Runs on background thread, CPU-intensive\n            let result = cx\n                .background_spawn(async move { heavy_computation() })\n                .await;\n\n            // Back on the foreground to update UI\n            this.update(cx, |state, cx| {\n                state.result = result;\n                cx.notify();\n            }).ok();\n        })\n        .detach();\n    }\n}\n```\n\n### Task Management\n\n```rust\nstruct MyView {\n    _task: Task<()>,  // Prefix with _ if stored but not accessed\n}\n\nimpl MyView {\n    fn new(cx: &mut Context<Self>) -> Self {\n        let _task = cx.spawn(async move |this, cx: &mut AsyncApp| {\n            // Task automatically cancelled when dropped\n            loop {\n                cx.background_executor().timer(Duration::from_secs(1)).await;\n\n                this.update(cx, |state, cx| {\n                    state.tick();\n                    cx.notify();\n                }).ok();\n            }\n        });\n\n        Self { _task }\n    }\n}\n```\n\n## Core Patterns\n\n### 1. Async Data Fetching (from Context<Self>)\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    let data = fetch_data().await?;\n    this.update(cx, |state, cx| {\n        state.data = Some(data);\n        cx.notify();\n    })?;\n    Ok::<_, anyhow::Error>(())\n}).detach();\n```\n\n### 2. Background Computation + UI Update\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    let result = cx.background_spawn(async move { heavy_work() }).await;\n    this.update(cx, |state, cx| {\n        state.result = result;\n        cx.notify();\n    }).ok();\n})\n.detach();\n```\n\n### 3. Periodic Tasks\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    loop {\n        cx.background_executor().timer(Duration::from_secs(5)).await;\n\n        this.update(cx, |state, cx| {\n            state.tick();\n            cx.notify();\n        }).ok();\n    }\n}).detach();\n```\n\n### 4. Task Cancellation\n\nTasks are automatically cancelled when dropped. Store in struct to keep alive.\n\n## Common Pitfalls\n\n### ❌ Don't: Use `defer_in` and then update the same entity through its handle\n\n`cx.defer_in(window, callback)` schedules `callback` to run **on the current entity** — GPUI re-acquires that entity's lock to execute it. Calling `entity.update(cx, …)` on the *same* entity from within the deferred callback re-enters the lock and panics:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: list entity is locked for the defer_in; calling list.update re-enters\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        parent.update(cx, |this, cx| {\n            this.inner_list.update(cx, |_, _| {}); // PANIC if inner_list == the deferred entity\n        });\n    });\n}\n```\n\n```rust\n// ✅ Correct: use the direct &mut reference — no lock needed\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // Access list data directly through the &mut reference\n        list_state.delegate_mut().some_method();\n\n        // Update a *different* entity — fine, different lock\n        parent.update(cx, |this, cx| { /* … */ });\n\n        // Sync list state directly after parent update — no lock needed\n        list_state.delegate_mut().update_snapshot(new_val);\n    });\n}\n```\n\nThe rule: inside a `defer_in` callback, **never call `entity.update(cx, …)` or `entity.read(cx)` on the entity the `defer_in` was scheduled on**. Use the `&mut Entity` direct reference the callback provides instead.\n\n### ❌ Don't: Update entities from background tasks\n\n```rust\n// ❌ Wrong: Can't update entities from background thread\ncx.background_spawn(async move {\n    entity.update(cx, |state, cx| { // Compile error!\n        state.data = data;\n    });\n});\n```\n\n### ✅ Do: Await the background task inside a foreground task\n\n```rust\n// ✅ Correct: the foreground task awaits the background result\ncx.spawn(async move |this, cx| {\n    let data = cx.background_spawn(async move { load_data() }).await;\n    this.update(cx, |state, cx| {\n        state.data = data;\n        cx.notify();\n    }).ok();\n})\n.detach();\n```\n\nGPUI has no `Task::then`. Await the background task inside `cx.spawn`. The\nclosure receives `(WeakEntity<Self>, &mut AsyncApp)`, not the background result.\n\n","skills/gpui-kit/references/gpui/context.md":"# Context Management\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Operations](#common-operations) · [Context Hierarchy](#context-hierarchy) · [cx.listener](#cxlistener--binding-callbacks-to-self) · [subscribe_in](#subscribe_in--subscribe-with-window-access) · [observe_window_activation](#observe_window_activation) · [observe_global](#observe_global) · [defer / defer_in](#defer-and-defer_in) · [Naming Convention](#context-naming-convention)\n\n## Overview\n\nGPUI uses different context types for different scenarios:\n\n**Context Types:**\n- **`App`**: Global app state, entity creation\n- **`Window`**: Window-specific operations, painting, layout\n- **`Context<T>`**: Entity-specific context for component `T`\n- **`AsyncApp`**: Async context for foreground tasks\n- **`AsyncWindowContext`**: Async context with window access\n\n## Quick Start\n\n### Context<T> - Component Context\n\n```rust\nimpl MyComponent {\n    fn update_state(&mut self, cx: &mut Context<Self>) {\n        self.value = 42;\n        cx.notify(); // Trigger re-render\n\n        // Spawn async task\n        cx.spawn(async move |cx| {\n            // Async work\n        }).detach();\n\n        // Get current entity\n        let entity = cx.entity();\n    }\n}\n```\n\n### App - Global Context\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx: &mut App| {\n        gpui_kit::init(cx);\n\n        // Create entities\n        let entity = cx.new(|cx| MyState::default());\n\n        // Open windows (wraps the view in a `Root`)\n        gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| cx.new(|_| MyView))\n            .expect(\"failed to open window\");\n    });\n}\n```\n\n### Window - Window Context\n\n```rust\nimpl Render for MyView {\n    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        // Window operations\n        let is_focused = window.is_window_focused();\n        let bounds = window.bounds();\n\n        div().child(\"Content\")\n    }\n}\n```\n\n### AsyncApp - Async Context\n\n```rust\ncx.spawn(async move |cx: &mut AsyncApp| {\n    let data = fetch_data().await;\n\n    entity.update(cx, |state, inner_cx| {\n        state.data = data;\n        inner_cx.notify();\n    }).ok();\n}).detach();\n```\n\n## Common Operations\n\n### Entity Operations\n\n```rust\n// Create entity\nlet entity = cx.new(|cx| MyState::default());\n\n// Update entity\nentity.update(cx, |state, cx| {\n    state.value = 42;\n    cx.notify();\n});\n\n// Read entity\nlet value = entity.read(cx).value;\n```\n\n### Notifications and Events\n\n```rust\n// Trigger re-render\ncx.notify();\n\n// Emit event\ncx.emit(MyEvent::Updated);\n\n// Observe entity\ncx.observe(&entity, |this, observed, cx| {\n    // React to changes\n}).detach();\n\n// Subscribe to events\ncx.subscribe(&entity, |this, source, event, cx| {\n    // Handle event\n}).detach();\n```\n\n### Window Operations\n\n```rust\n// Window state\nlet focused = window.is_window_focused();\nlet bounds = window.bounds();\nlet scale = window.scale_factor();\n\n// Close window\nwindow.remove_window();\n```\n\n### Async Operations\n\n```rust\n// Spawn foreground task\ncx.spawn(async move |cx| {\n    // Async work with entity access\n}).detach();\n\n// Spawn background task\ncx.background_spawn(async move {\n    // Heavy computation\n}).detach();\n```\n\n## Context Hierarchy\n\n```\nApp (Global)\n  └─ Window (Per-window)\n       └─ Context<T> (Per-component)\n            └─ AsyncApp (In async tasks)\n                 └─ AsyncWindowContext (Async + Window)\n```\n\n## cx.listener — Binding Callbacks to Self\n\n`cx.listener` creates a callback that borrows `&mut self` (the current entity). Use it for `on_click`, `on_action`, and other element event handlers:\n\n```rust\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .on_action(cx.listener(Self::on_save))\n            .child(\n                Button::new(\"btn\")\n                    .on_click(cx.listener(|this, _event, _window, cx| {\n                        this.count += 1;\n                        cx.notify();\n                    }))\n            )\n    }\n}\n\nimpl MyView {\n    fn on_save(&mut self, _: &Save, _window: &mut Window, cx: &mut Context<Self>) {\n        cx.notify();\n    }\n}\n```\n\n`cx.listener(Self::method)` is equivalent to creating a closure that calls `self.method(...)`.\n\n## subscribe_in — Subscribe with Window Access\n\nUse `subscribe_in` (instead of `subscribe`) when the callback needs `&mut Window`:\n\n```rust\nlet _subscription = cx.subscribe_in(&input, window, |this, state, event, window, cx| {\n    match event {\n        InputEvent::Change => {\n            let val = state.read(cx).value();\n            this.on_input_change(val, window, cx);\n        }\n        _ => {}\n    }\n});\n// Store _subscription in struct to keep it alive\n```\n\n`subscribe` vs `subscribe_in`:\n- `subscribe(&entity, |this, source, event, cx|)` — no window access\n- `subscribe_in(&entity, window, |this, source, event, window, cx|)` — has window access\n\n## observe_window_activation\n\nReact when the window gains or loses focus:\n\n```rust\nlet _sub = cx.observe_window_activation(window, |this, window, cx| {\n    if window.is_window_active() {\n        this.resume(cx);\n    } else {\n        this.pause(cx);\n    }\n});\n```\n\n## observe_global\n\nReact when a global value changes:\n\n```rust\ncx.observe_global::<Theme>(|cx| {\n    // Theme changed — react\n    cx.notify();\n});\n```\n\n## defer and defer_in\n\nSchedule work after the current update completes:\n\n```rust\n// defer: runs after current App update, no window access\ncx.defer(|cx| {\n    // Runs after current entity update is done\n});\n\n// defer_in: runs after update, with window access\ncx.defer_in(window, |this, window, cx| {\n    // Can access window here\n    // CAUTION: never call entity.update(cx) on *this same entity* inside defer_in\n    // — it re-enters the lock and panics. Use the &mut self reference directly.\n    this.some_method(window, cx);\n});\n```\n\n## Context Naming Convention\n\nAlways name contexts `cx` regardless of type:\n\n```rust\nfn new(window: &mut Window, cx: &mut App) {}             // cx = App\nimpl Render for View {\n    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) {}  // cx = Context<Self>\n}\ncx.spawn(async move |this, cx: &mut AsyncApp| {})         // cx = AsyncApp\n```\n","skills/gpui-kit/references/gpui/element-advanced.md":"# Advanced Element Patterns\n\n**Contents:** [Custom Layout Algorithms](#custom-layout-algorithms) · [Element Composition with Traits](#element-composition-with-traits) · [Async Element Updates](#async-element-updates) · [Element Memoization](#element-memoization) · [Virtual List Pattern](#virtual-list-pattern)\n\n## Custom Layout Algorithms\n\nImplementing custom layout algorithms not supported by GPUI's built-in layouts.\n\n### Masonry Layout (Pinterest-Style)\n\n```rust\npub struct MasonryLayout {\n    id: ElementId,\n    columns: usize,\n    gap: Pixels,\n    children: Vec<AnyElement>,\n}\n\nstruct MasonryLayoutState {\n    column_layouts: Vec<Vec<LayoutId>>,\n    column_heights: Vec<Pixels>,\n}\n\nstruct MasonryPaintState {\n    child_bounds: Vec<Bounds<Pixels>>,\n}\n\nimpl Element for MasonryLayout {\n    type RequestLayoutState = MasonryLayoutState;\n    type PrepaintState = MasonryPaintState;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, MasonryLayoutState) {\n        // Initialize columns\n        let mut columns: Vec<Vec<LayoutId>> = vec![Vec::new(); self.columns];\n        let mut column_heights = vec![px(0.); self.columns];\n\n        // Distribute children across columns\n        for child in &mut self.children {\n            let (child_layout_id, _) = child.request_layout(\n                global_id,\n                inspector_id,\n                window,\n                cx\n            );\n\n            let child_size = window.layout_bounds(child_layout_id).size;\n\n            // Find shortest column\n            let min_column_idx = column_heights\n                .iter()\n                .enumerate()\n                .min_by(|a, b| a.1.partial_cmp(b.1).unwrap())\n                .unwrap()\n                .0;\n\n            // Add child to shortest column\n            columns[min_column_idx].push(child_layout_id);\n            column_heights[min_column_idx] += child_size.height + self.gap;\n        }\n\n        // Calculate total layout size\n        let column_width = px(200.); // Fixed column width\n        let total_width = column_width * self.columns as f32\n            + self.gap * (self.columns - 1) as f32;\n        let total_height = column_heights.iter()\n            .max_by(|a, b| a.partial_cmp(b).unwrap())\n            .copied()\n            .unwrap_or(px(0.));\n\n        let layout_id = window.request_layout(\n            Style {\n                size: size(total_width, total_height),\n                ..default()\n            },\n            columns.iter().flatten().copied().collect(),\n            cx\n        );\n\n        (layout_id, MasonryLayoutState {\n            column_layouts: columns,\n            column_heights,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut MasonryLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> MasonryPaintState {\n        let column_width = px(200.);\n        let mut child_bounds = Vec::new();\n\n        // Position children in columns\n        for (col_idx, column) in layout_state.column_layouts.iter().enumerate() {\n            let x_offset = bounds.left()\n                + (column_width + self.gap) * col_idx as f32;\n            let mut y_offset = bounds.top();\n\n            for (child_idx, layout_id) in column.iter().enumerate() {\n                let child_size = window.layout_bounds(*layout_id).size;\n                let child_bound = Bounds::new(\n                    point(x_offset, y_offset),\n                    size(column_width, child_size.height)\n                );\n\n                self.children[child_idx].prepaint(\n                    global_id,\n                    inspector_id,\n                    child_bound,\n                    window,\n                    cx\n                );\n\n                child_bounds.push(child_bound);\n                y_offset += child_size.height + self.gap;\n            }\n        }\n\n        MasonryPaintState { child_bounds }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        _bounds: Bounds<Pixels>,\n        _layout_state: &mut MasonryLayoutState,\n        paint_state: &mut MasonryPaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        for (child, bounds) in self.children.iter_mut().zip(&paint_state.child_bounds) {\n            child.paint(global_id, inspector_id, *bounds, window, cx);\n        }\n    }\n}\n```\n\n### Circular Layout\n\n```rust\npub struct CircularLayout {\n    id: ElementId,\n    radius: Pixels,\n    children: Vec<AnyElement>,\n}\n\nimpl Element for CircularLayout {\n    type RequestLayoutState = Vec<LayoutId>;\n    type PrepaintState = Vec<Bounds<Pixels>>;\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Vec<LayoutId>) {\n        let child_layouts: Vec<_> = self.children\n            .iter_mut()\n            .map(|child| child.request_layout(global_id, inspector_id, window, cx).0)\n            .collect();\n\n        let diameter = self.radius * 2.;\n        let layout_id = window.request_layout(\n            Style {\n                size: size(diameter, diameter),\n                ..default()\n            },\n            child_layouts.clone(),\n            cx\n        );\n\n        (layout_id, child_layouts)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_ids: &mut Vec<LayoutId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Vec<Bounds<Pixels>> {\n        let center = bounds.center();\n        let angle_step = 2.0 * std::f32::consts::PI / self.children.len() as f32;\n\n        let mut child_bounds = Vec::new();\n\n        for (i, (child, layout_id)) in self.children.iter_mut()\n            .zip(layout_ids.iter())\n            .enumerate()\n        {\n            let angle = angle_step * i as f32;\n            let child_size = window.layout_bounds(*layout_id).size;\n\n            // Position child on circle\n            let x = center.x + self.radius * angle.cos() - child_size.width / 2.;\n            let y = center.y + self.radius * angle.sin() - child_size.height / 2.;\n\n            let child_bound = Bounds::new(point(x, y), child_size);\n\n            child.prepaint(global_id, inspector_id, child_bound, window, cx);\n            child_bounds.push(child_bound);\n        }\n\n        child_bounds\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        _bounds: Bounds<Pixels>,\n        _layout_ids: &mut Vec<LayoutId>,\n        child_bounds: &mut Vec<Bounds<Pixels>>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        for (child, bounds) in self.children.iter_mut().zip(child_bounds) {\n            child.paint(global_id, inspector_id, *bounds, window, cx);\n        }\n    }\n}\n```\n\n## Element Composition with Traits\n\nCreate reusable behaviors via traits for element composition.\n\n### Hoverable Trait\n\n```rust\npub trait Hoverable: Element {\n    fn on_hover<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static;\n\n    fn on_hover_end<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static;\n}\n\n// Implementation for custom element\npub struct HoverableElement {\n    id: ElementId,\n    content: AnyElement,\n    hover_handlers: Vec<Box<dyn Fn(&mut Window, &mut App)>>,\n    hover_end_handlers: Vec<Box<dyn Fn(&mut Window, &mut App)>>,\n    was_hovered: bool,\n}\n\nimpl Hoverable for HoverableElement {\n    fn on_hover<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static\n    {\n        self.hover_handlers.push(Box::new(f));\n        self\n    }\n\n    fn on_hover_end<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static\n    {\n        self.hover_end_handlers.push(Box::new(f));\n        self\n    }\n}\n\nimpl Element for HoverableElement {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = Hitbox;\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout: &mut LayoutId,\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let is_hovered = hitbox.is_hovered(window);\n\n        // Trigger hover events\n        if is_hovered && !self.was_hovered {\n            for handler in &self.hover_handlers {\n                handler(window, cx);\n            }\n        } else if !is_hovered && self.was_hovered {\n            for handler in &self.hover_end_handlers {\n                handler(window, cx);\n            }\n        }\n\n        self.was_hovered = is_hovered;\n\n        // Paint content\n        self.content.paint(bounds, window, cx);\n    }\n\n    // ... other methods\n}\n```\n\n### Clickable Trait\n\n```rust\npub trait Clickable: Element {\n    fn on_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static;\n\n    fn on_double_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static;\n}\n\npub struct ClickableElement {\n    id: ElementId,\n    content: AnyElement,\n    click_handlers: Vec<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    double_click_handlers: Vec<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    last_click_time: Option<Instant>,\n}\n\nimpl Clickable for ClickableElement {\n    fn on_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static\n    {\n        self.click_handlers.push(Box::new(f));\n        self\n    }\n\n    fn on_double_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static\n    {\n        self.double_click_handlers.push(Box::new(f));\n        self\n    }\n}\n```\n\n## Async Element Updates\n\nElements that update based on async operations.\n\n```rust\npub struct AsyncElement {\n    id: ElementId,\n    state: Entity<AsyncState>,\n    loading: bool,\n    data: Option<String>,\n}\n\npub struct AsyncState {\n    loading: bool,\n    data: Option<String>,\n}\n\nimpl Element for AsyncElement {\n    type RequestLayoutState = ();\n    type PrepaintState = Hitbox;\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout: &mut (),\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Display loading or data\n        if self.loading {\n            // Paint loading indicator\n            self.paint_loading(bounds, window, cx);\n        } else if let Some(data) = &self.data {\n            // Paint data\n            self.paint_data(data, bounds, window, cx);\n        }\n\n        // Trigger async update on click\n        window.on_mouse_event({\n            let state = self.state.clone();\n            let hitbox = hitbox.clone();\n\n            move |event: &MouseUpEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Spawn async task\n                    cx.spawn({\n                        let state = state.clone();\n                        async move {\n                            // Perform async operation\n                            let result = fetch_data_async().await;\n\n                            // Update state on completion\n                            state.update(cx, |state, cx| {\n                                state.loading = false;\n                                state.data = Some(result);\n                                cx.notify();\n                            });\n                        }\n                    }).detach();\n\n                    // Set loading state immediately\n                    state.update(cx, |state, cx| {\n                        state.loading = true;\n                        cx.notify();\n                    });\n\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n\n    // ... other methods\n}\n\nasync fn fetch_data_async() -> String {\n    // Simulate async operation\n    tokio::time::sleep(Duration::from_secs(1)).await;\n    \"Data loaded!\".to_string()\n}\n```\n\n## Element Memoization\n\nOptimize performance by memoizing expensive element computations.\n\n```rust\npub struct MemoizedElement<T: PartialEq + Clone + 'static> {\n    id: ElementId,\n    value: T,\n    render_fn: Box<dyn Fn(&T) -> AnyElement>,\n    cached_element: Option<AnyElement>,\n    last_value: Option<T>,\n}\n\nimpl<T: PartialEq + Clone + 'static> MemoizedElement<T> {\n    pub fn new<F>(id: ElementId, value: T, render_fn: F) -> Self\n    where\n        F: Fn(&T) -> AnyElement + 'static,\n    {\n        Self {\n            id,\n            value,\n            render_fn: Box::new(render_fn),\n            cached_element: None,\n            last_value: None,\n        }\n    }\n}\n\nimpl<T: PartialEq + Clone + 'static> Element for MemoizedElement<T> {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = ();\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, LayoutId) {\n        // Check if value changed\n        if self.last_value.as_ref() != Some(&self.value) || self.cached_element.is_none() {\n            // Recompute element\n            self.cached_element = Some((self.render_fn)(&self.value));\n            self.last_value = Some(self.value.clone());\n        }\n\n        // Request layout for cached element\n        let (layout_id, _) = self.cached_element\n            .as_mut()\n            .unwrap()\n            .request_layout(global_id, inspector_id, window, cx);\n\n        (layout_id, layout_id)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout_id: &mut LayoutId,\n        window: &mut Window,\n        cx: &mut App\n    ) -> () {\n        self.cached_element\n            .as_mut()\n            .unwrap()\n            .prepaint(global_id, inspector_id, bounds, window, cx);\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout_id: &mut LayoutId,\n        _: &mut (),\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        self.cached_element\n            .as_mut()\n            .unwrap()\n            .paint(global_id, inspector_id, bounds, window, cx);\n    }\n}\n\n// Usage\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    MemoizedElement::new(\n        ElementId::Name(\"memoized\".into()),\n        self.expensive_value.clone(),\n        |value| {\n            // Expensive rendering function only called when value changes\n            div().child(format!(\"Computed: {}\", value))\n        }\n    )\n}\n```\n\n## Virtual List Pattern\n\nEfficiently render large lists by only rendering visible items.\n\n```rust\npub struct VirtualList {\n    id: ElementId,\n    item_count: usize,\n    item_height: Pixels,\n    viewport_height: Pixels,\n    scroll_offset: Pixels,\n    render_item: Box<dyn Fn(usize) -> AnyElement>,\n}\n\nstruct VirtualListState {\n    visible_range: Range<usize>,\n    visible_item_layouts: Vec<LayoutId>,\n}\n\nimpl Element for VirtualList {\n    type RequestLayoutState = VirtualListState;\n    type PrepaintState = Hitbox;\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, VirtualListState) {\n        // Calculate visible range\n        let start_idx = (self.scroll_offset / self.item_height).floor() as usize;\n        let end_idx = ((self.scroll_offset + self.viewport_height) / self.item_height)\n            .ceil() as usize;\n        let visible_range = start_idx..end_idx.min(self.item_count);\n\n        // Request layout only for visible items\n        let visible_item_layouts: Vec<_> = visible_range.clone()\n            .map(|i| {\n                let mut item = (self.render_item)(i);\n                item.request_layout(global_id, inspector_id, window, cx).0\n            })\n            .collect();\n\n        let total_height = self.item_height * self.item_count as f32;\n        let layout_id = window.request_layout(\n            Style {\n                size: size(relative(1.0), self.viewport_height),\n                overflow: Overflow::Hidden,\n                ..default()\n            },\n            visible_item_layouts.clone(),\n            cx\n        );\n\n        (layout_id, VirtualListState {\n            visible_range,\n            visible_item_layouts,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        state: &mut VirtualListState,\n        window: &mut Window,\n        _cx: &mut App\n    ) -> Hitbox {\n        // Prepaint visible items at correct positions\n        for (i, layout_id) in state.visible_item_layouts.iter().enumerate() {\n            let item_idx = state.visible_range.start + i;\n            let y = item_idx as f32 * self.item_height - self.scroll_offset;\n            let item_bounds = Bounds::new(\n                point(bounds.left(), bounds.top() + y),\n                size(bounds.width(), self.item_height)\n            );\n\n            // Prepaint if visible\n            if item_bounds.intersects(&bounds) {\n                // Prepaint item...\n            }\n        }\n\n        window.insert_hitbox(bounds, HitboxBehavior::Normal)\n    }\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        state: &mut VirtualListState,\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint visible items\n        for (i, _layout_id) in state.visible_item_layouts.iter().enumerate() {\n            let item_idx = state.visible_range.start + i;\n            let y = item_idx as f32 * self.item_height - self.scroll_offset;\n            let item_bounds = Bounds::new(\n                point(bounds.left(), bounds.top() + y),\n                size(bounds.width(), self.item_height)\n            );\n\n            if item_bounds.intersects(&bounds) {\n                let mut item = (self.render_item)(item_idx);\n                item.paint(item_bounds, window, cx);\n            }\n        }\n\n        // Handle scroll\n        window.on_mouse_event({\n            let hitbox = hitbox.clone();\n            let total_height = self.item_height * self.item_count as f32;\n\n            move |event: &ScrollWheelEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    self.scroll_offset -= event.delta.y;\n                    self.scroll_offset = self.scroll_offset\n                        .max(px(0.))\n                        .min(total_height - self.viewport_height);\n                    cx.notify();\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\n// Usage: Efficiently render 10,000 items\nlet virtual_list = VirtualList {\n    id: ElementId::Name(\"large-list\".into()),\n    item_count: 10_000,\n    item_height: px(40.),\n    viewport_height: px(400.),\n    scroll_offset: px(0.),\n    render_item: Box::new(|index| {\n        div().child(format!(\"Item {}\", index))\n    }),\n};\n```\n\nThese advanced patterns enable sophisticated element implementations while maintaining performance and code quality.\n","skills/gpui-kit/references/gpui/element-api.md":"# Element API Reference\n\n**Contents:** [Element Trait Structure](#element-trait-structure) · [Associated Types](#associated-types) · [Methods](#methods) · [IntoElement Integration](#intoelement-integration) · [Layout System Integration](#layout-system-integration) · [Hitbox System](#hitbox-system) · [Event Handling](#event-handling) · [Cursor Styles](#cursor-styles)\n\n## Element Trait Structure\n\nThe `Element` trait requires implementing three associated types and five methods:\n\n```rust\npub trait Element: 'static + IntoElement {\n    type RequestLayoutState: 'static;\n    type PrepaintState: 'static;\n\n    fn id(&self) -> Option<ElementId>;\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>>;\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App,\n    ) -> (LayoutId, Self::RequestLayoutState);\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        request_layout: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App,\n    ) -> Self::PrepaintState;\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        request_layout: &mut Self::RequestLayoutState,\n        prepaint: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App,\n    );\n}\n```\n\n## Associated Types\n\n### RequestLayoutState\n\nData passed from `request_layout` to `prepaint` and `paint` phases.\n\n**Usage:**\n- Store layout calculations (styled text, child layout IDs)\n- Cache expensive computations\n- Pass child state between phases\n\n**Examples:**\n```rust\n// Simple: no state needed\ntype RequestLayoutState = ();\n\n// Single value\ntype RequestLayoutState = StyledText;\n\n// Multiple values\ntype RequestLayoutState = (StyledText, Vec<ChildLayout>);\n\n// Complex struct\npub struct MyLayoutState {\n    pub styled_text: StyledText,\n    pub child_layouts: Vec<(LayoutId, ChildState)>,\n    pub computed_bounds: Bounds<Pixels>,\n}\ntype RequestLayoutState = MyLayoutState;\n```\n\n### PrepaintState\n\nData passed from `prepaint` to `paint` phase.\n\n**Usage:**\n- Store hitboxes for interaction\n- Cache visual bounds\n- Store prepaint results\n\n**Examples:**\n```rust\n// Simple: just a hitbox\ntype PrepaintState = Hitbox;\n\n// Optional hitbox\ntype PrepaintState = Option<Hitbox>;\n\n// Multiple values\ntype PrepaintState = (Hitbox, Vec<Bounds<Pixels>>);\n\n// Complex struct\npub struct MyPaintState {\n    pub hitbox: Hitbox,\n    pub child_bounds: Vec<Bounds<Pixels>>,\n    pub visible_range: Range<usize>,\n}\ntype PrepaintState = MyPaintState;\n```\n\n## Methods\n\n### id()\n\nReturns optional unique identifier for debugging and inspection.\n\n```rust\nfn id(&self) -> Option<ElementId> {\n    Some(self.id.clone())\n}\n\n// Or if no ID needed\nfn id(&self) -> Option<ElementId> {\n    None\n}\n```\n\n### source_location()\n\nReturns source location for debugging. Usually returns `None` unless debugging is needed.\n\n```rust\nfn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n    None\n}\n```\n\n### request_layout()\n\nCalculates sizes and positions for the element tree.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Returns:**\n- `(LayoutId, Self::RequestLayoutState)`: Layout ID and state for next phases\n\n**Responsibilities:**\n1. Calculate child layouts by calling `child.request_layout()`\n2. Create own layout using `window.request_layout()`\n3. Return layout ID and state to pass to next phases\n\n**Example:**\n```rust\nfn request_layout(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    window: &mut Window,\n    cx: &mut App,\n) -> (LayoutId, Self::RequestLayoutState) {\n    // 1. Calculate child layouts\n    let child_layout_id = self.child.request_layout(\n        global_id,\n        inspector_id,\n        window,\n        cx\n    ).0;\n\n    // 2. Create own layout\n    let layout_id = window.request_layout(\n        Style {\n            size: size(px(200.), px(100.)),\n            ..default()\n        },\n        vec![child_layout_id],\n        cx\n    );\n\n    // 3. Return layout ID and state\n    (layout_id, MyLayoutState { child_layout_id })\n}\n```\n\n### prepaint()\n\nPrepares for painting by creating hitboxes and computing final bounds.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `bounds`: Final bounds calculated by layout engine\n- `request_layout`: Mutable reference to layout state\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Returns:**\n- `Self::PrepaintState`: State for paint phase\n\n**Responsibilities:**\n1. Compute final child bounds based on layout bounds\n2. Call `child.prepaint()` for all children\n3. Create hitboxes using `window.insert_hitbox()`\n4. Return state for paint phase\n\n**Example:**\n```rust\nfn prepaint(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    bounds: Bounds<Pixels>,\n    request_layout: &mut Self::RequestLayoutState,\n    window: &mut Window,\n    cx: &mut App,\n) -> Self::PrepaintState {\n    // 1. Compute child bounds\n    let child_bounds = bounds; // or calculated subset\n\n    // 2. Prepaint children\n    self.child.prepaint(\n        global_id,\n        inspector_id,\n        child_bounds,\n        &mut request_layout.child_state,\n        window,\n        cx\n    );\n\n    // 3. Create hitboxes\n    let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n    // 4. Return paint state\n    MyPaintState { hitbox }\n}\n```\n\n### paint()\n\nRenders the element and handles interactions.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `bounds`: Final bounds for rendering\n- `request_layout`: Mutable reference to layout state\n- `prepaint`: Mutable reference to prepaint state\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Responsibilities:**\n1. Paint children first (bottom to top)\n2. Paint own content (backgrounds, borders, etc.)\n3. Set up interactions (mouse events, cursor styles)\n\n**Example:**\n```rust\nfn paint(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    bounds: Bounds<Pixels>,\n    request_layout: &mut Self::RequestLayoutState,\n    prepaint: &mut Self::PrepaintState,\n    window: &mut Window,\n    cx: &mut App,\n) {\n    // 1. Paint children first\n    self.child.paint(\n        global_id,\n        inspector_id,\n        child_bounds,\n        &mut request_layout.child_state,\n        &mut prepaint.child_paint_state,\n        window,\n        cx\n    );\n\n    // 2. Paint own content\n    window.paint_quad(paint_quad(\n        bounds,\n        Anchor::all(px(4.)),\n        cx.theme().background,\n    ));\n\n    // 3. Set up interactions\n    window.on_mouse_event({\n        let hitbox = prepaint.hitbox.clone();\n        move |event: &MouseDownEvent, phase, window, cx| {\n            if hitbox.is_hovered(window) && phase.bubble() {\n                // Handle click\n                cx.stop_propagation();\n            }\n        }\n    });\n\n    window.set_cursor_style(CursorStyle::PointingHand, &prepaint.hitbox);\n}\n```\n\n## IntoElement Integration\n\nElements must also implement `IntoElement` to be used as children:\n\n```rust\nimpl IntoElement for MyElement {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n```\n\nThis allows your custom element to be used directly in the element tree:\n\n```rust\ndiv()\n    .child(MyElement::new()) // Works because of IntoElement\n```\n\n## Common Parameters\n\n### Global and Inspector IDs\n\nBoth are optional identifiers used for debugging and inspection:\n- `global_id`: Unique identifier across entire app\n- `inspector_id`: Identifier for dev tools/inspector\n\nUsually passed through to children without modification.\n\n### Window and Context\n\n- `window: &mut Window`: Window-specific operations (painting, hitboxes, events)\n- `cx: &mut App`: App-wide operations (spawning tasks, accessing globals)\n\n## Layout System Integration\n\n### window.request_layout()\n\nCreates a layout node with specified style and children:\n\n```rust\nlet layout_id = window.request_layout(\n    Style {\n        size: size(px(200.), px(100.)),\n        flex: Flex::Column,\n        gap: px(8.),\n        ..default()\n    },\n    vec![child1_layout_id, child2_layout_id],\n    cx\n);\n```\n\n### Bounds<Pixels>\n\nRepresents rectangular region:\n\n```rust\npub struct Bounds<T> {\n    pub origin: Point<T>,\n    pub size: Size<T>,\n}\n\n// Create bounds\nlet bounds = Bounds::new(\n    point(px(10.), px(20.)),\n    size(px(100.), px(50.))\n);\n\n// Access properties\nbounds.left()    // origin.x\nbounds.top()     // origin.y\nbounds.right()   // origin.x + size.width\nbounds.bottom()  // origin.y + size.height\nbounds.center()  // center point\n```\n\n## Hitbox System\n\n### Creating Hitboxes\n\n```rust\n// Normal hitbox (blocks events)\nlet hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n// Transparent hitbox (passes events through)\nlet hitbox = window.insert_hitbox(bounds, HitboxBehavior::Transparent);\n```\n\n### Using Hitboxes\n\n```rust\n// Check if hovered\nif hitbox.is_hovered(window) {\n    // ...\n}\n\n// Set cursor style\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n\n// Use in event handlers\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    if hitbox.is_hovered(window) && phase.bubble() {\n        // Handle event\n    }\n});\n```\n\n## Event Handling\n\n### Mouse Events\n\n```rust\n// Mouse down\nwindow.on_mouse_event(move |event: &MouseDownEvent, phase, window, cx| {\n    if phase.bubble() && bounds.contains(&event.position) {\n        // Handle mouse down\n        cx.stop_propagation(); // Prevent bubbling\n    }\n});\n\n// Mouse up\nwindow.on_mouse_event(move |event: &MouseUpEvent, phase, window, cx| {\n    // Handle mouse up\n});\n\n// Mouse move\nwindow.on_mouse_event(move |event: &MouseMoveEvent, phase, window, cx| {\n    // Handle mouse move\n});\n\n// Scroll\nwindow.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {\n    // Handle scroll\n});\n```\n\n### Event Phase\n\nEvents go through two phases:\n- **Capture**: Top-down (parent → child)\n- **Bubble**: Bottom-up (child → parent)\n\n```rust\nmove |event, phase, window, cx| {\n    if phase.capture() {\n        // Handle in capture phase\n    } else if phase.bubble() {\n        // Handle in bubble phase\n    }\n\n    cx.stop_propagation(); // Stop event from continuing\n}\n```\n\n## Cursor Styles\n\nAvailable cursor styles:\n\n```rust\nCursorStyle::Arrow\nCursorStyle::IBeam           // Text selection\nCursorStyle::PointingHand    // Clickable\nCursorStyle::ResizeLeft\nCursorStyle::ResizeRight\nCursorStyle::ResizeUp\nCursorStyle::ResizeDown\nCursorStyle::ResizeLeftRight\nCursorStyle::ResizeUpDown\nCursorStyle::Crosshair\nCursorStyle::OperationNotAllowed\n```\n\nUsage:\n\n```rust\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n```\n","skills/gpui-kit/references/gpui/element-best-practices.md":"# Element Best Practices\n\n**Contents:** [State Management](#state-management) · [Performance Considerations](#performance-considerations) · [Interaction Handling](#interaction-handling) · [Layout Strategies](#layout-strategies) · [Error Handling](#error-handling) · [Testing Element Implementations](#testing-element-implementations) · [Common Pitfalls](#common-pitfalls) · [Performance Checklist](#performance-checklist)\n\n## State Management\n\n### Using Associated Types Effectively\n\n**Good:** Use associated types to pass meaningful data between phases\n\n```rust\n// Good: Structured state with type safety\ntype RequestLayoutState = (StyledText, Vec<ChildLayout>);\ntype PrepaintState = (Hitbox, Vec<ChildBounds>);\n```\n\n**Bad:** Using empty state when you need data\n\n```rust\n// Bad: No state when you need to pass data\ntype RequestLayoutState = ();\ntype PrepaintState = ();\n// Now you can't pass layout info to paint phase!\n```\n\n### Managing Complex State\n\nFor elements with complex state, create dedicated structs:\n\n```rust\n// Good: Dedicated struct for complex state\npub struct TextElementState {\n    pub styled_text: StyledText,\n    pub text_layout: TextLayout,\n    pub child_states: Vec<ChildState>,\n}\n\ntype RequestLayoutState = TextElementState;\n```\n\n**Benefits:**\n- Clear documentation of state structure\n- Easy to extend\n- Type-safe access\n\n### State Lifecycle\n\n**Golden Rule:** State flows in one direction through the phases\n\n```\nrequest_layout → RequestLayoutState →\nprepaint → PrepaintState →\npaint\n```\n\n**Don't:**\n- Store state in the element struct that should be in associated types\n- Try to mutate element state in paint phase (use `cx.notify()` to schedule re-render)\n- Pass mutable references across phase boundaries\n\n## Performance Considerations\n\n### Minimize Allocations in Paint Phase\n\n**Critical:** Paint phase is called every frame during animations. Minimize allocations.\n\n**Good:** Pre-allocate in `request_layout` or `prepaint`\n\n```rust\nimpl Element for MyElement {\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Vec<StyledText>)\n    {\n        // Allocate once during layout\n        let styled_texts = self.children\n            .iter()\n            .map(|child| StyledText::new(child.text.clone()))\n            .collect();\n\n        (layout_id, styled_texts)\n    }\n\n    fn paint(&mut self, .., styled_texts: &mut Vec<StyledText>, ..) {\n        // Just use pre-allocated styled_texts\n        for text in styled_texts {\n            text.paint(..);\n        }\n    }\n}\n```\n\n**Bad:** Allocate in `paint` phase\n\n```rust\nfn paint(&mut self, ..) {\n    // Bad: Allocation in paint phase!\n    let styled_texts: Vec<_> = self.children\n        .iter()\n        .map(|child| StyledText::new(child.text.clone()))\n        .collect();\n}\n```\n\n### Cache Expensive Computations\n\nUse memoization for expensive operations:\n\n```rust\npub struct CachedElement {\n    // Cache key\n    last_text: Option<SharedString>,\n    last_width: Option<Pixels>,\n\n    // Cached result\n    cached_layout: Option<TextLayout>,\n}\n\nimpl Element for CachedElement {\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, TextLayout)\n    {\n        let current_width = window.bounds().width();\n\n        // Check if cache is valid\n        if self.last_text.as_ref() != Some(&self.text)\n            || self.last_width != Some(current_width)\n            || self.cached_layout.is_none()\n        {\n            // Recompute expensive layout\n            self.cached_layout = Some(self.compute_text_layout(current_width));\n            self.last_text = Some(self.text.clone());\n            self.last_width = Some(current_width);\n        }\n\n        // Use cached layout\n        let layout = self.cached_layout.as_ref().unwrap();\n        (layout_id, layout.clone())\n    }\n}\n```\n\n### Lazy Child Rendering\n\nOnly render visible children in scrollable containers:\n\n```rust\nfn paint(&mut self, .., bounds: Bounds<Pixels>, paint_state: &mut Self::PrepaintState, ..) {\n    for (i, child) in self.children.iter_mut().enumerate() {\n        let child_bounds = paint_state.child_bounds[i];\n\n        // Only paint visible children\n        if self.is_visible(&child_bounds, &bounds) {\n            child.paint(..);\n        }\n    }\n}\n\nfn is_visible(&self, child_bounds: &Bounds<Pixels>, container_bounds: &Bounds<Pixels>) -> bool {\n    child_bounds.bottom() >= container_bounds.top() &&\n    child_bounds.top() <= container_bounds.bottom()\n}\n```\n\n## Interaction Handling\n\n### Proper Event Bubbling\n\nAlways check phase and bounds before handling events:\n\n```rust\nfn paint(&mut self, .., window: &mut Window, cx: &mut App) {\n    window.on_mouse_event({\n        let hitbox = self.hitbox.clone();\n        move |event: &MouseDownEvent, phase, window, cx| {\n            // Check phase first\n            if !phase.bubble() {\n                return;\n            }\n\n            // Check if event is within bounds\n            if !hitbox.is_hovered(window) {\n                return;\n            }\n\n            // Handle event\n            self.handle_click(event);\n\n            // Stop propagation if handled\n            cx.stop_propagation();\n        }\n    });\n}\n```\n\n**Don't forget:**\n- Check `phase.bubble()` or `phase.capture()` as appropriate\n- Check hitbox hover state or bounds\n- Call `cx.stop_propagation()` if you handle the event\n\n### Hitbox Management\n\nCreate hitboxes in `prepaint` phase, not `paint`:\n\n**Good:**\n\n```rust\nfn prepaint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) -> Hitbox {\n    // Create hitbox in prepaint\n    window.insert_hitbox(bounds, HitboxBehavior::Normal)\n}\n\nfn paint(&mut self, .., hitbox: &mut Hitbox, window: &mut Window, ..) {\n    // Use hitbox in paint\n    window.set_cursor_style(CursorStyle::PointingHand, hitbox);\n}\n```\n\n**Hitbox Behaviors:**\n\n```rust\n// Normal: Blocks events from passing through\nHitboxBehavior::Normal\n\n// Transparent: Allows events to pass through to elements below\nHitboxBehavior::Transparent\n```\n\n### Cursor Style Guidelines\n\nSet appropriate cursor styles for interactivity cues:\n\n```rust\n// Text selection\nwindow.set_cursor_style(CursorStyle::IBeam, &hitbox);\n\n// Clickable elements (desktop convention: use default, not pointing hand)\nwindow.set_cursor_style(CursorStyle::Arrow, &hitbox);\n\n// Links (web convention: use pointing hand)\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n\n// Resizable edges\nwindow.set_cursor_style(CursorStyle::ResizeLeftRight, &hitbox);\n```\n\n**Desktop vs Web Convention:**\n- Desktop apps: Use `Arrow` for buttons\n- Web apps: Use `PointingHand` for links only\n\n## Layout Strategies\n\n### Fixed Size Elements\n\nFor elements with known, unchanging size:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App) -> (LayoutId, ()) {\n    let layout_id = window.request_layout(\n        Style {\n            size: size(px(200.), px(100.)),\n            ..default()\n        },\n        vec![], // No children\n        cx\n    );\n    (layout_id, ())\n}\n```\n\n### Content-Based Sizing\n\nFor elements sized by their content:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Size<Pixels>)\n{\n    // Measure content\n    let text_bounds = self.measure_text(window);\n    let padding = px(16.);\n\n    let layout_id = window.request_layout(\n        Style {\n            size: size(\n                text_bounds.width() + padding * 2.,\n                text_bounds.height() + padding * 2.,\n            ),\n            ..default()\n        },\n        vec![],\n        cx\n    );\n\n    (layout_id, text_bounds)\n}\n```\n\n### Flexible Layouts\n\nFor elements that adapt to available space:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Vec<LayoutId>)\n{\n    let mut child_layout_ids = Vec::new();\n\n    for child in &mut self.children {\n        let (layout_id, _) = child.request_layout(window, cx);\n        child_layout_ids.push(layout_id);\n    }\n\n    let layout_id = window.request_layout(\n        Style {\n            flex_direction: FlexDirection::Row,\n            gap: px(8.),\n            size: Size {\n                width: relative(1.0),  // Fill parent width\n                height: auto(),        // Auto height\n            },\n            ..default()\n        },\n        child_layout_ids.clone(),\n        cx\n    );\n\n    (layout_id, child_layout_ids)\n}\n```\n\n## Error Handling\n\n### Graceful Degradation\n\nHandle errors gracefully, don't panic:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Option<TextLayout>)\n{\n    // Try to create styled text\n    match StyledText::new(self.text.clone()).request_layout(None, None, window, cx) {\n        Ok((layout_id, text_layout)) => {\n            (layout_id, Some(text_layout))\n        }\n        Err(e) => {\n            // Log error\n            eprintln!(\"Failed to layout text: {}\", e);\n\n            // Fallback to simple text\n            let fallback_text = StyledText::new(\"(Error loading text)\".into());\n            let (layout_id, _) = fallback_text.request_layout(None, None, window, cx);\n            (layout_id, None)\n        }\n    }\n}\n```\n\n### Defensive Bounds Checking\n\nAlways validate bounds and indices:\n\n```rust\nfn paint_selection(&self, selection: &Selection, text_layout: &TextLayout, ..) {\n    // Validate selection bounds\n    let start = selection.start.min(self.text.len());\n    let end = selection.end.min(self.text.len());\n\n    if start >= end {\n        return; // Invalid selection\n    }\n\n    let rects = text_layout.rects_for_range(start..end);\n    // Paint selection...\n}\n```\n\n## Testing Element Implementations\n\n### Layout Tests\n\nTest that layout calculations are correct:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use gpui_kit::TestAppContext;\n\n    #[gpui_kit::test]\n    fn test_element_layout(cx: &mut TestAppContext) {\n        cx.update(|cx| {\n            let mut window = cx.open_window(Default::default(), |_, _| ()).unwrap();\n\n            window.update(cx, |window, cx| {\n                let mut element = MyElement::new();\n                let (layout_id, layout_state) = element.request_layout(\n                    None,\n                    None,\n                    window,\n                    cx\n                );\n\n                // Assert layout properties\n                let bounds = window.layout_bounds(layout_id);\n                assert_eq!(bounds.size.width, px(200.));\n                assert_eq!(bounds.size.height, px(100.));\n            });\n        });\n    }\n}\n```\n\n### Interaction Tests\n\nTest that interactions work correctly:\n\n```rust\n#[gpui_kit::test]\nfn test_element_click(cx: &mut TestAppContext) {\n    cx.update(|cx| {\n        let mut window = cx.open_window(Default::default(), |_, cx| {\n            cx.new(|_| MyElement::new())\n        }).unwrap();\n\n        window.update(cx, |window, cx| {\n            let view = window.root_view().unwrap();\n\n            // Simulate click\n            let position = point(px(10.), px(10.));\n            window.dispatch_event(MouseDownEvent {\n                position,\n                button: MouseButton::Left,\n                modifiers: Modifiers::default(),\n            });\n\n            // Assert element responded\n            view.read(cx).assert_clicked();\n        });\n    });\n}\n```\n\n## Common Pitfalls\n\n### ❌ Storing Layout State in Element Struct\n\n**Bad:**\n\n```rust\npub struct MyElement {\n    id: ElementId,\n    // Bad: This should be in RequestLayoutState\n    cached_layout: Option<TextLayout>,\n}\n```\n\n**Good:**\n\n```rust\npub struct MyElement {\n    id: ElementId,\n    text: SharedString,\n}\n\ntype RequestLayoutState = TextLayout; // Good: State in associated type\n```\n\n### ❌ Mutating Element in Paint Phase\n\n**Bad:**\n\n```rust\nfn paint(&mut self, ..) {\n    self.counter += 1; // Bad: Mutating element in paint\n}\n```\n\n**Good:**\n\n```rust\nfn paint(&mut self, .., window: &mut Window, cx: &mut App) {\n    window.on_mouse_event(move |event, phase, window, cx| {\n        if phase.bubble() {\n            self.counter += 1;\n            cx.notify(); // Schedule re-render\n        }\n    });\n}\n```\n\n### ❌ Creating Hitboxes in Paint Phase\n\n**Bad:**\n\n```rust\nfn paint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) {\n    // Bad: Creating hitbox in paint\n    let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n}\n```\n\n**Good:**\n\n```rust\nfn prepaint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) -> Hitbox {\n    // Good: Creating hitbox in prepaint\n    window.insert_hitbox(bounds, HitboxBehavior::Normal)\n}\n```\n\n### ❌ Ignoring Event Phase\n\n**Bad:**\n\n```rust\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    // Bad: Not checking phase\n    self.handle_click(event);\n});\n```\n\n**Good:**\n\n```rust\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    // Good: Checking phase\n    if !phase.bubble() {\n        return;\n    }\n    self.handle_click(event);\n});\n```\n\n## Performance Checklist\n\nBefore shipping an element implementation, verify:\n\n- [ ] No allocations in `paint` phase (except event handlers)\n- [ ] Expensive computations are cached/memoized\n- [ ] Only visible children are rendered in scrollable containers\n- [ ] Hitboxes created in `prepaint`, not `paint`\n- [ ] Event handlers check phase and bounds\n- [ ] Layout state is passed through associated types, not stored in element\n- [ ] Element implements proper error handling with fallbacks\n- [ ] Tests cover layout calculations and interactions\n","skills/gpui-kit/references/gpui/element-examples.md":"# Element Implementation Examples\n\nComplete examples of implementing custom elements for various scenarios.\n\n## Table of Contents\n\n1. [Simple Text Element](#simple-text-element)\n2. [Interactive Element with Selection](#interactive-element-with-selection)\n3. [Complex Element with Child Management](#complex-element-with-child-management)\n\n## Simple Text Element\n\nA basic text element with syntax highlighting support.\n\n```rust\npub struct SimpleText {\n    id: ElementId,\n    text: SharedString,\n    highlights: Vec<(Range<usize>, HighlightStyle)>,\n}\n\nimpl IntoElement for SimpleText {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for SimpleText {\n    type RequestLayoutState = StyledText;\n    type PrepaintState = Hitbox;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        // Create styled text with highlights\n        let mut runs = Vec::new();\n        let mut ix = 0;\n\n        for (range, highlight) in &self.highlights {\n            // Add unstyled text before highlight\n            if ix < range.start {\n                runs.push(window.text_style().to_run(range.start - ix));\n            }\n\n            // Add highlighted text\n            runs.push(\n                window.text_style()\n                    .highlight(*highlight)\n                    .to_run(range.len())\n            );\n            ix = range.end;\n        }\n\n        // Add remaining unstyled text\n        if ix < self.text.len() {\n            runs.push(window.text_style().to_run(self.text.len() - ix));\n        }\n\n        let styled_text = StyledText::new(self.text.clone()).with_runs(runs);\n        let (layout_id, _) = styled_text.request_layout(\n            global_id,\n            inspector_id,\n            window,\n            cx\n        );\n\n        (layout_id, styled_text)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        styled_text: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Self::PrepaintState {\n        // Prepaint the styled text\n        styled_text.prepaint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            window,\n            cx\n        );\n\n        // Create hitbox for interaction\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        hitbox\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        styled_text: &mut Self::RequestLayoutState,\n        hitbox: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint the styled text\n        styled_text.paint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            &mut (),\n            window,\n            cx\n        );\n\n        // Set cursor style for text\n        window.set_cursor_style(CursorStyle::IBeam, hitbox);\n    }\n}\n```\n\n## Interactive Element with Selection\n\nA text element that supports text selection via mouse interaction.\n\n```rust\n#[derive(Clone)]\npub struct Selection {\n    pub start: usize,\n    pub end: usize,\n}\n\npub struct SelectableText {\n    id: ElementId,\n    text: SharedString,\n    selectable: bool,\n    selection: Option<Selection>,\n}\n\nimpl IntoElement for SelectableText {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for SelectableText {\n    type RequestLayoutState = TextLayout;\n    type PrepaintState = Option<Hitbox>;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        let styled_text = StyledText::new(self.text.clone());\n        let (layout_id, _) = styled_text.request_layout(\n            global_id,\n            inspector_id,\n            window,\n            cx\n        );\n\n        // Extract text layout for selection painting\n        let text_layout = styled_text.layout().clone();\n\n        (layout_id, text_layout)\n    }\n\n    fn prepaint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _text_layout: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        _cx: &mut App\n    ) -> Self::PrepaintState {\n        // Only create hitbox if selectable\n        if self.selectable {\n            Some(window.insert_hitbox(bounds, HitboxBehavior::Normal))\n        } else {\n            None\n        }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        text_layout: &mut Self::RequestLayoutState,\n        hitbox: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint text\n        let styled_text = StyledText::new(self.text.clone());\n        styled_text.paint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            &mut (),\n            window,\n            cx\n        );\n\n        // Paint selection if any\n        if let Some(selection) = &self.selection {\n            Self::paint_selection(selection, text_layout, &bounds, window, cx);\n        }\n\n        // Handle mouse events for selection\n        if let Some(hitbox) = hitbox {\n            window.set_cursor_style(CursorStyle::IBeam, hitbox);\n\n            // Mouse down to start selection\n            window.on_mouse_event({\n                let bounds = bounds.clone();\n                move |event: &MouseDownEvent, phase, window, cx| {\n                    if bounds.contains(&event.position) && phase.bubble() {\n                        // Start selection at mouse position\n                        let char_index = Self::position_to_index(\n                            event.position,\n                            &bounds,\n                            text_layout\n                        );\n                        self.selection = Some(Selection {\n                            start: char_index,\n                            end: char_index,\n                        });\n                        cx.notify();\n                        cx.stop_propagation();\n                    }\n                }\n            });\n\n            // Mouse drag to extend selection\n            window.on_mouse_event({\n                let bounds = bounds.clone();\n                move |event: &MouseMoveEvent, phase, window, cx| {\n                    if let Some(selection) = &mut self.selection {\n                        if phase.bubble() {\n                            let char_index = Self::position_to_index(\n                                event.position,\n                                &bounds,\n                                text_layout\n                            );\n                            selection.end = char_index;\n                            cx.notify();\n                        }\n                    }\n                }\n            });\n        }\n    }\n}\n\nimpl SelectableText {\n    fn paint_selection(\n        selection: &Selection,\n        text_layout: &TextLayout,\n        bounds: &Bounds<Pixels>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Calculate selection bounds from text layout\n        let selection_rects = text_layout.rects_for_range(\n            selection.start..selection.end\n        );\n\n        // Paint selection background\n        for rect in selection_rects {\n            window.paint_quad(paint_quad(\n                Bounds::new(\n                    point(bounds.left() + rect.origin.x, bounds.top() + rect.origin.y),\n                    rect.size\n                ),\n                Anchor::default(),\n                cx.theme().selection_background,\n            ));\n        }\n    }\n\n    fn position_to_index(\n        position: Point<Pixels>,\n        bounds: &Bounds<Pixels>,\n        text_layout: &TextLayout\n    ) -> usize {\n        // Convert screen position to character index\n        let relative_pos = point(\n            position.x - bounds.left(),\n            position.y - bounds.top()\n        );\n        text_layout.index_for_position(relative_pos)\n    }\n}\n```\n\n## Complex Element with Child Management\n\nA container element that manages multiple children with scrolling support.\n\n```rust\npub struct ComplexElement {\n    id: ElementId,\n    children: Vec<Box<dyn Element<RequestLayoutState = (), PrepaintState = ()>>>,\n    scrollable: bool,\n    scroll_offset: Point<Pixels>,\n}\n\nstruct ComplexLayoutState {\n    child_layouts: Vec<LayoutId>,\n    total_height: Pixels,\n}\n\nstruct ComplexPaintState {\n    child_bounds: Vec<Bounds<Pixels>>,\n    hitbox: Hitbox,\n}\n\nimpl IntoElement for ComplexElement {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for ComplexElement {\n    type RequestLayoutState = ComplexLayoutState;\n    type PrepaintState = ComplexPaintState;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        let mut child_layouts = Vec::new();\n        let mut total_height = px(0.);\n\n        // Request layout for all children\n        for child in &mut self.children {\n            let (child_layout_id, _) = child.request_layout(\n                global_id,\n                inspector_id,\n                window,\n                cx\n            );\n            child_layouts.push(child_layout_id);\n\n            // Get child size from layout\n            let child_size = window.layout_bounds(child_layout_id).size();\n            total_height += child_size.height;\n        }\n\n        // Create container layout\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: FlexDirection::Column,\n                gap: px(8.),\n                size: Size {\n                    width: relative(1.0),\n                    height: if self.scrollable {\n                        // Fixed height for scrollable\n                        px(400.)\n                    } else {\n                        // Auto height for non-scrollable\n                        total_height\n                    },\n                },\n                ..default()\n            },\n            child_layouts.clone(),\n            cx\n        );\n\n        (layout_id, ComplexLayoutState {\n            child_layouts,\n            total_height,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Self::PrepaintState {\n        let mut child_bounds = Vec::new();\n        let mut y_offset = self.scroll_offset.y;\n\n        // Calculate child bounds and prepaint children\n        for (child, layout_id) in self.children.iter_mut()\n            .zip(&layout_state.child_layouts)\n        {\n            let child_size = window.layout_bounds(*layout_id).size();\n            let child_bound = Bounds::new(\n                point(bounds.left(), bounds.top() + y_offset),\n                child_size\n            );\n\n            // Only prepaint visible children\n            if self.is_visible(&child_bound, &bounds) {\n                child.prepaint(\n                    global_id,\n                    inspector_id,\n                    child_bound,\n                    &mut (),\n                    window,\n                    cx\n                );\n            }\n\n            child_bounds.push(child_bound);\n            y_offset += child_size.height + px(8.); // gap\n        }\n\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n        ComplexPaintState {\n            child_bounds,\n            hitbox,\n        }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut Self::RequestLayoutState,\n        paint_state: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint background\n        window.paint_quad(paint_quad(\n            bounds,\n            Anchor::all(px(4.)),\n            cx.theme().background,\n        ));\n\n        // Paint visible children only\n        for (i, child) in self.children.iter_mut().enumerate() {\n            let child_bounds = paint_state.child_bounds[i];\n\n            if self.is_visible(&child_bounds, &bounds) {\n                child.paint(\n                    global_id,\n                    inspector_id,\n                    child_bounds,\n                    &mut (),\n                    &mut (),\n                    window,\n                    cx\n                );\n            }\n        }\n\n        // Paint scrollbar if scrollable\n        if self.scrollable {\n            self.paint_scrollbar(bounds, layout_state, window, cx);\n        }\n\n        // Handle scroll events\n        if self.scrollable {\n            window.on_mouse_event({\n                let hitbox = paint_state.hitbox.clone();\n                let total_height = layout_state.total_height;\n                let visible_height = bounds.size.height;\n\n                move |event: &ScrollWheelEvent, phase, window, cx| {\n                    if hitbox.is_hovered(window) && phase.bubble() {\n                        // Update scroll offset\n                        self.scroll_offset.y -= event.delta.y;\n\n                        // Clamp scroll offset\n                        let max_scroll = (total_height - visible_height).max(px(0.));\n                        self.scroll_offset.y = self.scroll_offset.y\n                            .max(px(0.))\n                            .min(max_scroll);\n\n                        cx.notify();\n                        cx.stop_propagation();\n                    }\n                }\n            });\n        }\n    }\n}\n\nimpl ComplexElement {\n    fn is_visible(&self, child_bounds: &Bounds<Pixels>, container_bounds: &Bounds<Pixels>) -> bool {\n        // Check if child is within visible area\n        child_bounds.bottom() >= container_bounds.top() &&\n        child_bounds.top() <= container_bounds.bottom()\n    }\n\n    fn paint_scrollbar(\n        &self,\n        bounds: Bounds<Pixels>,\n        layout_state: &ComplexLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let scrollbar_width = px(8.);\n        let visible_height = bounds.size.height;\n        let total_height = layout_state.total_height;\n\n        if total_height <= visible_height {\n            return; // No need for scrollbar\n        }\n\n        // Calculate scrollbar position and size\n        let scroll_ratio = self.scroll_offset.y / (total_height - visible_height);\n        let thumb_height = (visible_height / total_height) * visible_height;\n        let thumb_y = scroll_ratio * (visible_height - thumb_height);\n\n        // Paint scrollbar track\n        let track_bounds = Bounds::new(\n            point(bounds.right() - scrollbar_width, bounds.top()),\n            size(scrollbar_width, visible_height)\n        );\n        window.paint_quad(paint_quad(\n            track_bounds,\n            Anchor::default(),\n            cx.theme().scrollbar_track,\n        ));\n\n        // Paint scrollbar thumb\n        let thumb_bounds = Bounds::new(\n            point(bounds.right() - scrollbar_width, bounds.top() + thumb_y),\n            size(scrollbar_width, thumb_height)\n        );\n        window.paint_quad(paint_quad(\n            thumb_bounds,\n            Anchor::all(px(4.)),\n            cx.theme().scrollbar_thumb,\n        ));\n    }\n}\n```\n\n## Usage Examples\n\n### Using SimpleText\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    div()\n        .child(SimpleText {\n            id: ElementId::Name(\"code-text\".into()),\n            text: \"fn main() { println!(\\\"Hello\\\"); }\".into(),\n            highlights: vec![\n                (0..2, HighlightStyle::keyword()),\n                (3..7, HighlightStyle::function()),\n            ],\n        })\n}\n```\n\n### Using SelectableText\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    div()\n        .child(SelectableText {\n            id: ElementId::Name(\"selectable-text\".into()),\n            text: \"Select this text with your mouse\".into(),\n            selectable: true,\n            selection: self.current_selection.clone(),\n        })\n}\n```\n\n### Using ComplexElement\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    let children: Vec<Box<dyn Element<_, _>>> = self.items\n        .iter()\n        .map(|item| Box::new(div().child(item.name.clone())) as Box<_>)\n        .collect();\n\n    div()\n        .child(ComplexElement {\n            id: ElementId::Name(\"scrollable-list\".into()),\n            children,\n            scrollable: true,\n            scroll_offset: self.scroll_offset,\n        })\n}\n```\n","skills/gpui-kit/references/gpui/element-id.md":"# ElementId\n\n`ElementId` is a unique identifier for a GPUI element. It is required for elements that need:\n- Mouse event handling (`on_click`, `on_hover`, etc.)\n- State storage via `window.use_keyed_state`\n- Interaction tracking\n\n## Making an Element Stateful\n\nCall `.id()` on a `div()` to create a `Stateful<Div>`:\n\n```rust\ndiv().id(\"my-element\")          // ElementId from &str\ndiv().id(42usize)               // ElementId from usize\ndiv().id(ElementId::from(idx))  // Explicit\n```\n\nWithout `.id()`, a div cannot receive mouse events or store state.\n\n## Accepted Types\n\n```rust\nimpl Into<ElementId> for &str      // \"my-id\"\nimpl Into<ElementId> for String    // String::from(\"my-id\")\nimpl Into<ElementId> for usize     // 0, 1, 2, ...\nimpl Into<ElementId> for u64\nimpl Into<ElementId> for SharedString\n```\n\n## Uniqueness Rules\n\nIDs must be unique within the same **stateful parent's scope** — not globally. GPUI builds a `GlobalElementId` by chaining parent IDs:\n\n```rust\ndiv().id(\"app\").child(\n    div().id(\"list1\").children(vec![\n        div().id(1usize).child(\"Item 1\"),  // GlobalId: [\"app\", \"list1\", 1]\n        div().id(2usize).child(\"Item 2\"),  // GlobalId: [\"app\", \"list1\", 2]\n    ])\n).child(\n    div().id(\"list2\").children(vec![\n        div().id(1usize).child(\"Item 1\"),  // GlobalId: [\"app\", \"list2\", 1] — no conflict\n    ])\n)\n```\n\nItems in different parent scopes can reuse simple IDs (integers, short strings).\n\n## In Component Structs\n\nComponents always store `id: ElementId` and pass it in `new()`:\n\n```rust\n#[derive(IntoElement)]\npub struct Button {\n    id: ElementId,\n    base: Stateful<Div>,\n    // ...\n}\n\nimpl Button {\n    pub fn new(id: impl Into<ElementId>) -> Self {\n        let id = id.into();\n        Self {\n            id: id.clone(),\n            base: div().id(id),  // id applied to base\n            // ...\n        }\n    }\n}\n\nimpl RenderOnce for Button {\n    fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {\n        self.base  // already has .id() applied\n            .on_click(/* ... */)\n    }\n}\n```\n\n## Usage at Call Sites\n\n```rust\n// Use unique string IDs for named components\nButton::new(\"save-btn\").label(\"Save\")\nButton::new(\"cancel-btn\").label(\"Cancel\")\n\n// Use index-based IDs in lists\nfor (i, item) in items.iter().enumerate() {\n    div().id(i)  // unique within this parent\n}\n\n// Use descriptive IDs for debugging\nInput::new(\"search-input\")\nSelect::new(\"country-select\")\n```\n","skills/gpui-kit/references/gpui/element-patterns.md":"# Common Element Patterns\n\n**Contents:** [Text Rendering Elements](#text-rendering-elements) · [Container Elements](#container-elements) · [Interactive Elements](#interactive-elements) · [Composite Elements](#composite-elements) · [Scrollable Elements](#scrollable-elements) · [Pattern Selection Guide](#pattern-selection-guide)\n\n## Text Rendering Elements\n\nElements that display and manipulate text content.\n\n### Pattern Characteristics\n\n- Use `StyledText` for text layout and rendering\n- Handle text selection in `paint` phase with hitbox interaction\n- Create hitboxes for text interaction in `prepaint`\n- Support text highlighting and custom styling via runs\n\n### Implementation Template\n\n```rust\npub struct TextElement {\n    id: ElementId,\n    text: SharedString,\n    style: TextStyle,\n}\n\nimpl Element for TextElement {\n    type RequestLayoutState = StyledText;\n    type PrepaintState = Hitbox;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, StyledText)\n    {\n        let styled_text = StyledText::new(self.text.clone())\n            .with_style(self.style);\n        let (layout_id, _) = styled_text.request_layout(None, None, window, cx);\n        (layout_id, styled_text)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, styled_text: &mut StyledText,\n                window: &mut Window, cx: &mut App) -> Hitbox\n    {\n        styled_text.prepaint(None, None, bounds, &mut (), window, cx);\n        window.insert_hitbox(bounds, HitboxBehavior::Normal)\n    }\n\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, styled_text: &mut StyledText,\n             hitbox: &mut Hitbox, window: &mut Window, cx: &mut App)\n    {\n        styled_text.paint(None, None, bounds, &mut (), &mut (), window, cx);\n        window.set_cursor_style(CursorStyle::IBeam, hitbox);\n    }\n}\n```\n\n### Use Cases\n\n- Code editors with syntax highlighting\n- Rich text displays\n- Labels with custom formatting\n- Selectable text areas\n\n## Container Elements\n\nElements that manage and layout child elements.\n\n### Pattern Characteristics\n\n- Manage child element layouts and positions\n- Handle scrolling and clipping when needed\n- Implement flex/grid-like layouts\n- Coordinate child interactions and event delegation\n\n### Implementation Template\n\n```rust\npub struct ContainerElement {\n    id: ElementId,\n    children: Vec<AnyElement>,\n    direction: FlexDirection,\n    gap: Pixels,\n}\n\nimpl Element for ContainerElement {\n    type RequestLayoutState = Vec<LayoutId>;\n    type PrepaintState = Vec<Bounds<Pixels>>;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Vec<LayoutId>)\n    {\n        let child_layout_ids: Vec<_> = self.children\n            .iter_mut()\n            .map(|child| child.request_layout(window, cx).0)\n            .collect();\n\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: self.direction,\n                gap: self.gap,\n                ..default()\n            },\n            child_layout_ids.clone(),\n            cx\n        );\n\n        (layout_id, child_layout_ids)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout_ids: &mut Vec<LayoutId>,\n                window: &mut Window, cx: &mut App) -> Vec<Bounds<Pixels>>\n    {\n        let mut child_bounds = Vec::new();\n\n        for (child, layout_id) in self.children.iter_mut().zip(layout_ids.iter()) {\n            let child_bound = window.layout_bounds(*layout_id);\n            child.prepaint(child_bound, window, cx);\n            child_bounds.push(child_bound);\n        }\n\n        child_bounds\n    }\n\n    fn paint(&mut self, .., child_bounds: &mut Vec<Bounds<Pixels>>,\n             window: &mut Window, cx: &mut App)\n    {\n        for (child, bounds) in self.children.iter_mut().zip(child_bounds.iter()) {\n            child.paint(*bounds, window, cx);\n        }\n    }\n}\n```\n\n### Use Cases\n\n- Panels and split views\n- List containers\n- Grid layouts\n- Tab containers\n\n## Interactive Elements\n\nElements that respond to user input (mouse, keyboard, touch).\n\n### Pattern Characteristics\n\n- Create appropriate hitboxes for interaction areas\n- Handle mouse/keyboard/touch events properly\n- Manage focus and cursor styles\n- Support hover, active, and disabled states\n\n### Implementation Template\n\n```rust\npub struct InteractiveElement {\n    id: ElementId,\n    content: AnyElement,\n    on_click: Option<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    hover_style: Option<Style>,\n}\n\nimpl Element for InteractiveElement {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = (Hitbox, bool); // hitbox and is_hovered\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, LayoutId)\n    {\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        (content_layout, content_layout)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, content_layout: &mut LayoutId,\n                window: &mut Window, cx: &mut App) -> (Hitbox, bool)\n    {\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        let is_hovered = hitbox.is_hovered(window);\n\n        self.content.prepaint(bounds, window, cx);\n\n        (hitbox, is_hovered)\n    }\n\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, content_layout: &mut LayoutId,\n             prepaint: &mut (Hitbox, bool), window: &mut Window, cx: &mut App)\n    {\n        let (hitbox, is_hovered) = prepaint;\n\n        // Paint hover background if hovered\n        if *is_hovered {\n            if let Some(hover_style) = &self.hover_style {\n                window.paint_quad(paint_quad(\n                    bounds,\n                    Anchor::all(px(4.)),\n                    hover_style.background_color.unwrap_or(cx.theme().hover),\n                ));\n            }\n        }\n\n        // Paint content\n        self.content.paint(bounds, window, cx);\n\n        // Handle click\n        if let Some(on_click) = self.on_click.as_ref() {\n            window.on_mouse_event({\n                let on_click = on_click.clone();\n                let hitbox = hitbox.clone();\n                move |event: &MouseUpEvent, phase, window, cx| {\n                    if hitbox.is_hovered(window) && phase.bubble() {\n                        on_click(event, window, cx);\n                        cx.stop_propagation();\n                    }\n                }\n            });\n        }\n\n        // Set cursor style\n        window.set_cursor_style(CursorStyle::PointingHand, hitbox);\n    }\n}\n```\n\n### Use Cases\n\n- Buttons\n- Links\n- Clickable cards\n- Drag handles\n- Menu items\n\n## Composite Elements\n\nElements that combine multiple child elements with complex coordination.\n\n### Pattern Characteristics\n\n- Combine multiple child elements with different types\n- Manage complex state across children\n- Coordinate animations and transitions\n- Handle focus delegation between children\n\n### Implementation Template\n\n```rust\npub struct CompositeElement {\n    id: ElementId,\n    header: AnyElement,\n    content: AnyElement,\n    footer: Option<AnyElement>,\n}\n\nstruct CompositeLayoutState {\n    header_layout: LayoutId,\n    content_layout: LayoutId,\n    footer_layout: Option<LayoutId>,\n}\n\nstruct CompositePaintState {\n    header_bounds: Bounds<Pixels>,\n    content_bounds: Bounds<Pixels>,\n    footer_bounds: Option<Bounds<Pixels>>,\n}\n\nimpl Element for CompositeElement {\n    type RequestLayoutState = CompositeLayoutState;\n    type PrepaintState = CompositePaintState;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, CompositeLayoutState)\n    {\n        let (header_layout, _) = self.header.request_layout(window, cx);\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        let footer_layout = self.footer.as_mut()\n            .map(|f| f.request_layout(window, cx).0);\n\n        let mut children = vec![header_layout, content_layout];\n        if let Some(footer) = footer_layout {\n            children.push(footer);\n        }\n\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: FlexDirection::Column,\n                size: Size {\n                    width: relative(1.0),\n                    height: auto(),\n                },\n                ..default()\n            },\n            children,\n            cx\n        );\n\n        (layout_id, CompositeLayoutState {\n            header_layout,\n            content_layout,\n            footer_layout,\n        })\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut CompositeLayoutState,\n                window: &mut Window, cx: &mut App) -> CompositePaintState\n    {\n        let header_bounds = window.layout_bounds(layout.header_layout);\n        let content_bounds = window.layout_bounds(layout.content_layout);\n        let footer_bounds = layout.footer_layout\n            .map(|id| window.layout_bounds(id));\n\n        self.header.prepaint(header_bounds, window, cx);\n        self.content.prepaint(content_bounds, window, cx);\n        if let (Some(footer), Some(bounds)) = (&mut self.footer, footer_bounds) {\n            footer.prepaint(bounds, window, cx);\n        }\n\n        CompositePaintState {\n            header_bounds,\n            content_bounds,\n            footer_bounds,\n        }\n    }\n\n    fn paint(&mut self, .., paint_state: &mut CompositePaintState,\n             window: &mut Window, cx: &mut App)\n    {\n        self.header.paint(paint_state.header_bounds, window, cx);\n        self.content.paint(paint_state.content_bounds, window, cx);\n        if let (Some(footer), Some(bounds)) = (&mut self.footer, paint_state.footer_bounds) {\n            footer.paint(bounds, window, cx);\n        }\n    }\n}\n```\n\n### Use Cases\n\n- Dialog boxes (header + content + footer)\n- Cards with multiple sections\n- Form layouts\n- Panels with toolbars\n\n## Scrollable Elements\n\nElements with scrollable content areas.\n\n### Pattern Characteristics\n\n- Manage scroll state (offset, velocity)\n- Handle scroll events (wheel, drag, touch)\n- Paint scrollbars (track and thumb)\n- Clip content to visible area\n\n### Implementation Template\n\n```rust\npub struct ScrollableElement {\n    id: ElementId,\n    content: AnyElement,\n    scroll_offset: Point<Pixels>,\n    content_size: Size<Pixels>,\n}\n\nstruct ScrollPaintState {\n    hitbox: Hitbox,\n    visible_bounds: Bounds<Pixels>,\n}\n\nimpl Element for ScrollableElement {\n    type RequestLayoutState = (LayoutId, Size<Pixels>);\n    type PrepaintState = ScrollPaintState;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, (LayoutId, Size<Pixels>))\n    {\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        let content_size = window.layout_bounds(content_layout).size;\n\n        let layout_id = window.request_layout(\n            Style {\n                size: Size {\n                    width: relative(1.0),\n                    height: px(400.), // Fixed viewport height\n                },\n                overflow: Overflow::Hidden,\n                ..default()\n            },\n            vec![content_layout],\n            cx\n        );\n\n        (layout_id, (content_layout, content_size))\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut (LayoutId, Size<Pixels>),\n                window: &mut Window, cx: &mut App) -> ScrollPaintState\n    {\n        let (content_layout, content_size) = layout;\n\n        // Calculate content bounds with scroll offset\n        let content_bounds = Bounds::new(\n            point(bounds.left(), bounds.top() - self.scroll_offset.y),\n            *content_size\n        );\n\n        self.content.prepaint(content_bounds, window, cx);\n\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n        ScrollPaintState {\n            hitbox,\n            visible_bounds: bounds,\n        }\n    }\n\n    fn paint(&mut self, .., layout: &mut (LayoutId, Size<Pixels>),\n             paint_state: &mut ScrollPaintState, window: &mut Window, cx: &mut App)\n    {\n        let (_, content_size) = layout;\n\n        // Paint content\n        self.content.paint(paint_state.visible_bounds, window, cx);\n\n        // Paint scrollbar\n        self.paint_scrollbar(paint_state.visible_bounds, *content_size, window, cx);\n\n        // Handle scroll events\n        window.on_mouse_event({\n            let hitbox = paint_state.hitbox.clone();\n            let content_height = content_size.height;\n            let visible_height = paint_state.visible_bounds.size.height;\n\n            move |event: &ScrollWheelEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Update scroll offset\n                    self.scroll_offset.y -= event.delta.y;\n\n                    // Clamp to valid range\n                    let max_scroll = (content_height - visible_height).max(px(0.));\n                    self.scroll_offset.y = self.scroll_offset.y\n                        .max(px(0.))\n                        .min(max_scroll);\n\n                    cx.notify();\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\nimpl ScrollableElement {\n    fn paint_scrollbar(\n        &self,\n        bounds: Bounds<Pixels>,\n        content_size: Size<Pixels>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let visible_height = bounds.size.height;\n        let content_height = content_size.height;\n\n        if content_height <= visible_height {\n            return; // No scrollbar needed\n        }\n\n        let scrollbar_width = px(8.);\n\n        // Calculate thumb position and size\n        let scroll_ratio = self.scroll_offset.y / (content_height - visible_height);\n        let thumb_height = (visible_height / content_height) * visible_height;\n        let thumb_y = scroll_ratio * (visible_height - thumb_height);\n\n        // Paint track\n        window.paint_quad(paint_quad(\n            Bounds::new(\n                point(bounds.right() - scrollbar_width, bounds.top()),\n                size(scrollbar_width, visible_height)\n            ),\n            Anchor::default(),\n            cx.theme().scrollbar_track,\n        ));\n\n        // Paint thumb\n        window.paint_quad(paint_quad(\n            Bounds::new(\n                point(bounds.right() - scrollbar_width, bounds.top() + thumb_y),\n                size(scrollbar_width, thumb_height)\n            ),\n            Anchor::all(px(4.)),\n            cx.theme().scrollbar_thumb,\n        ));\n    }\n}\n```\n\n### Use Cases\n\n- Scrollable lists\n- Code editors with large files\n- Long-form text content\n- Image galleries\n\n## Pattern Selection Guide\n\n| Need | Pattern | Complexity |\n|------|---------|------------|\n| Display styled text | Text Rendering | Low |\n| Layout multiple children | Container | Low-Medium |\n| Handle clicks/hovers | Interactive | Medium |\n| Complex multi-part UI | Composite | Medium-High |\n| Large content with scrolling | Scrollable | High |\n\nChoose the simplest pattern that meets your requirements, then extend as needed.\n","skills/gpui-kit/references/gpui/element.md":"# Custom Elements\n\n**Contents:** [When to Use](#when-to-use) · [Quick Start](#quick-start) · [Core Concepts](#core-concepts) · [Reference Documentation](#reference-documentation)\n\n## When to Use\n\nUse the low-level `Element` trait when:\n- Need fine-grained control over layout calculation\n- Building complex, performance-critical components\n- Implementing custom layout algorithms (masonry, circular, etc.)\n- High-level `Render`/`RenderOnce` APIs are insufficient\n\n**Prefer `Render`/`RenderOnce` for:** Simple components, standard layouts, declarative UI\n\n## Quick Start\n\nThe `Element` trait provides direct control over three rendering phases:\n\n```rust\nimpl Element for MyElement {\n    type RequestLayoutState = MyLayoutState;  // Data passed to later phases\n    type PrepaintState = MyPaintState;        // Data for painting\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    // Phase 1: Calculate sizes and positions\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Self::RequestLayoutState)\n    {\n        let layout_id = window.request_layout(\n            Style { size: size(px(200.), px(100.)), ..default() },\n            vec![],\n            cx\n        );\n        (layout_id, MyLayoutState { /* ... */ })\n    }\n\n    // Phase 2: Create hitboxes, prepare for painting\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,\n                window: &mut Window, cx: &mut App) -> Self::PrepaintState\n    {\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        MyPaintState { hitbox }\n    }\n\n    // Phase 3: Render and handle interactions\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,\n             paint_state: &mut Self::PrepaintState, window: &mut Window, cx: &mut App)\n    {\n        window.paint_quad(paint_quad(bounds, Anchor::all(px(4.)), cx.theme().background));\n\n        window.on_mouse_event({\n            let hitbox = paint_state.hitbox.clone();\n            move |event: &MouseDownEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Handle interaction\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\n// Enable element to be used as child\nimpl IntoElement for MyElement {\n    type Element = Self;\n    fn into_element(self) -> Self::Element { self }\n}\n```\n\n## Core Concepts\n\n### Three-Phase Rendering\n\n1. **request_layout**: Calculate sizes and positions, return layout ID and state\n2. **prepaint**: Create hitboxes, compute final bounds, prepare for painting\n3. **paint**: Render element, set up interactions (mouse events, cursor styles)\n\n### State Flow\n\n```\nRequestLayoutState → PrepaintState → paint\n```\n\nState flows in one direction through associated types, passed as mutable references between phases.\n\n### Key Operations\n\n- **Layout**: `window.request_layout(style, children, cx)` - Create layout node\n- **Hitboxes**: `window.insert_hitbox(bounds, behavior)` - Create interaction area\n- **Painting**: `window.paint_quad(...)` - Render visual content\n- **Events**: `window.on_mouse_event(handler)` - Handle user input\n\n## Reference Documentation\n\n### Complete API Documentation\n- **API**: See [element-api.md](element-api.md) — associated types, hitbox system, event handling, cursor styles\n- **Examples**: See [element-examples.md](element-examples.md) — text, interactive, complex elements\n- **Patterns**: See [element-patterns.md](element-patterns.md) — text, container, interactive, composite, scrollable\n- **Best Practices**: See [element-best-practices.md](element-best-practices.md) — performance, state, common pitfalls\n- **Advanced**: See [element-advanced.md](element-advanced.md) — masonry/circular layouts, memoization, virtual lists\n","skills/gpui-kit/references/gpui/entity-advanced.md":"# Advanced Entity Patterns\n\n**Contents:** [Entity Collections Management](#entity-collections-management) · [Conditional Update Patterns](#conditional-update-patterns) · [Entity State Machine Pattern](#entity-state-machine-pattern) · [Entity Proxy Pattern](#entity-proxy-pattern) · [Cascading Updates Pattern](#cascading-updates-pattern) · [Entity Snapshot Pattern](#entity-snapshot-pattern) · [Entity Transaction Pattern](#entity-transaction-pattern) · [Entity Pool Pattern](#entity-pool-pattern)\n\n## Entity Collections Management\n\n### Dynamic Collection with Cleanup\n\n```rust\nstruct EntityCollection<T> {\n    strong_refs: Vec<Entity<T>>,\n    weak_refs: Vec<WeakEntity<T>>,\n}\n\nimpl<T> EntityCollection<T> {\n    fn new() -> Self {\n        Self {\n            strong_refs: Vec::new(),\n            weak_refs: Vec::new(),\n        }\n    }\n\n    fn add(&mut self, entity: Entity<T>, cx: &mut App) {\n        self.strong_refs.push(entity.clone());\n        self.weak_refs.push(entity.downgrade());\n    }\n\n    fn remove(&mut self, entity_id: EntityId, cx: &mut App) {\n        self.strong_refs.retain(|e| e.entity_id() != entity_id);\n        self.weak_refs.retain(|w| {\n            w.upgrade()\n                .map(|e| e.entity_id() != entity_id)\n                .unwrap_or(false)\n        });\n    }\n\n    fn cleanup_invalid(&mut self, cx: &mut App) {\n        self.weak_refs.retain(|weak| weak.upgrade().is_some());\n    }\n\n    fn for_each<F>(&self, cx: &mut App, mut f: F)\n    where\n        F: FnMut(&Entity<T>, &mut App),\n    {\n        for entity in &self.strong_refs {\n            f(entity, cx);\n        }\n    }\n\n    fn for_each_weak<F>(&mut self, cx: &mut App, mut f: F)\n    where\n        F: FnMut(Entity<T>, &mut App),\n    {\n        self.weak_refs.retain(|weak| {\n            if let Some(entity) = weak.upgrade() {\n                f(entity, cx);\n                true\n            } else {\n                false // Remove invalid weak references\n            }\n        });\n    }\n}\n```\n\n### Entity Registry Pattern\n\n```rust\nuse std::collections::HashMap;\n\nstruct EntityRegistry<T> {\n    entities: HashMap<EntityId, WeakEntity<T>>,\n}\n\nimpl<T> EntityRegistry<T> {\n    fn new() -> Self {\n        Self {\n            entities: HashMap::new(),\n        }\n    }\n\n    fn register(&mut self, entity: &Entity<T>) {\n        self.entities.insert(entity.entity_id(), entity.downgrade());\n    }\n\n    fn unregister(&mut self, entity_id: EntityId) {\n        self.entities.remove(&entity_id);\n    }\n\n    fn get(&self, entity_id: EntityId) -> Option<Entity<T>> {\n        self.entities.get(&entity_id)?.upgrade()\n    }\n\n    fn cleanup(&mut self) {\n        self.entities.retain(|_, weak| weak.upgrade().is_some());\n    }\n\n    fn count(&self) -> usize {\n        self.entities.len()\n    }\n\n    fn all_entities(&self) -> Vec<Entity<T>> {\n        self.entities\n            .values()\n            .filter_map(|weak| weak.upgrade())\n            .collect()\n    }\n}\n```\n\n## Conditional Update Patterns\n\n### Debounced Updates\n\n```rust\nuse std::time::{Duration, Instant};\n\nstruct DebouncedEntity<T> {\n    entity: Entity<T>,\n    last_update: Instant,\n    debounce_duration: Duration,\n    pending_update: Option<Box<dyn FnOnce(&mut T, &mut Context<T>)>>,\n}\n\nimpl<T: 'static> DebouncedEntity<T> {\n    fn new(entity: Entity<T>, debounce_ms: u64) -> Self {\n        Self {\n            entity,\n            last_update: Instant::now(),\n            debounce_duration: Duration::from_millis(debounce_ms),\n            pending_update: None,\n        }\n    }\n\n    fn update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: FnOnce(&mut T, &mut Context<T>) + 'static,\n    {\n        let now = Instant::now();\n        let elapsed = now.duration_since(self.last_update);\n\n        if elapsed >= self.debounce_duration {\n            // Execute immediately\n            self.entity.update(cx, update_fn);\n            self.last_update = now;\n            self.pending_update = None;\n        } else {\n            // Store for later\n            self.pending_update = Some(Box::new(update_fn));\n\n            // Schedule execution\n            let entity = self.entity.clone();\n            let delay = self.debounce_duration - elapsed;\n\n            cx.spawn(async move |cx| {\n                tokio::time::sleep(delay).await;\n\n                if let Some(update) = self.pending_update.take() {\n                    entity.update(cx, |state, inner_cx| {\n                        update(state, inner_cx);\n                    });\n                }\n            }).detach();\n        }\n    }\n}\n```\n\n### Throttled Updates\n\n```rust\nstruct ThrottledEntity<T> {\n    entity: Entity<T>,\n    last_update: Instant,\n    throttle_duration: Duration,\n}\n\nimpl<T: 'static> ThrottledEntity<T> {\n    fn new(entity: Entity<T>, throttle_ms: u64) -> Self {\n        Self {\n            entity,\n            last_update: Instant::now(),\n            throttle_duration: Duration::from_millis(throttle_ms),\n        }\n    }\n\n    fn try_update<F>(&mut self, cx: &mut App, update_fn: F) -> bool\n    where\n        F: FnOnce(&mut T, &mut Context<T>),\n    {\n        let now = Instant::now();\n        let elapsed = now.duration_since(self.last_update);\n\n        if elapsed >= self.throttle_duration {\n            self.entity.update(cx, update_fn);\n            self.last_update = now;\n            true\n        } else {\n            false // Update throttled\n        }\n    }\n}\n```\n\n## Entity State Machine Pattern\n\n```rust\nenum AppState {\n    Idle,\n    Loading,\n    Loaded(String),\n    Error(String),\n}\n\nstruct StateMachine {\n    state: AppState,\n}\n\nimpl StateMachine {\n    fn new() -> Self {\n        Self {\n            state: AppState::Idle,\n        }\n    }\n\n    fn start_loading(&mut self, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Idle | AppState::Error(_)) {\n            self.state = AppState::Loading;\n            cx.notify();\n\n            let weak_entity = cx.entity().downgrade();\n\n            cx.spawn(async move |cx| {\n                let result = perform_load().await;\n\n                let _ = weak_entity.update(cx, |state, cx| {\n                    match result {\n                        Ok(data) => state.on_load_success(data, cx),\n                        Err(e) => state.on_load_error(e.to_string(), cx),\n                    }\n                });\n            }).detach();\n        }\n    }\n\n    fn on_load_success(&mut self, data: String, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Loading) {\n            self.state = AppState::Loaded(data);\n            cx.notify();\n        }\n    }\n\n    fn on_load_error(&mut self, error: String, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Loading) {\n            self.state = AppState::Error(error);\n            cx.notify();\n        }\n    }\n\n    fn reset(&mut self, cx: &mut Context<Self>) {\n        self.state = AppState::Idle;\n        cx.notify();\n    }\n}\n\nasync fn perform_load() -> Result<String, anyhow::Error> {\n    // Actual load implementation\n    Ok(\"Data\".to_string())\n}\n```\n\n## Entity Proxy Pattern\n\n```rust\nstruct EntityProxy<T> {\n    entity: WeakEntity<T>,\n}\n\nimpl<T> EntityProxy<T> {\n    fn new(entity: &Entity<T>) -> Self {\n        Self {\n            entity: entity.downgrade(),\n        }\n    }\n\n    fn with<F, R>(&self, cx: &mut App, f: F) -> Result<R, anyhow::Error>\n    where\n        F: FnOnce(&T, &App) -> R,\n    {\n        self.entity.read_with(cx, f)\n    }\n\n    fn update<F, R>(&self, cx: &mut App, f: F) -> Result<R, anyhow::Error>\n    where\n        F: FnOnce(&mut T, &mut Context<T>) -> R,\n    {\n        self.entity.update(cx, f)\n    }\n\n    fn is_valid(&self, cx: &App) -> bool {\n        self.entity.upgrade().is_some()\n    }\n}\n```\n\n## Cascading Updates Pattern\n\n```rust\nstruct CascadingUpdater {\n    entities: Vec<WeakEntity<UpdateTarget>>,\n}\n\nimpl CascadingUpdater {\n    fn new() -> Self {\n        Self {\n            entities: Vec::new(),\n        }\n    }\n\n    fn add_target(&mut self, entity: &Entity<UpdateTarget>) {\n        self.entities.push(entity.downgrade());\n    }\n\n    fn cascade_update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: Fn(&mut UpdateTarget, &mut Context<UpdateTarget>) + Clone,\n    {\n        // Update all entities in sequence\n        self.entities.retain(|weak| {\n            if let Ok(_) = weak.update(cx, |state, inner_cx| {\n                update_fn.clone()(state, inner_cx);\n            }) {\n                true // Keep valid entity\n            } else {\n                false // Remove invalid entity\n            }\n        });\n    }\n}\n\nstruct UpdateTarget {\n    value: i32,\n}\n```\n\n## Entity Snapshot Pattern\n\n```rust\nuse serde::{Serialize, Deserialize};\n\n#[derive(Clone, Serialize, Deserialize)]\nstruct EntitySnapshot {\n    data: String,\n    timestamp: u64,\n}\n\nstruct SnapshotableEntity {\n    data: String,\n    snapshots: Vec<EntitySnapshot>,\n}\n\nimpl SnapshotableEntity {\n    fn new(data: String) -> Self {\n        Self {\n            data,\n            snapshots: Vec::new(),\n        }\n    }\n\n    fn take_snapshot(&mut self, cx: &mut Context<Self>) {\n        let snapshot = EntitySnapshot {\n            data: self.data.clone(),\n            timestamp: current_timestamp(),\n        };\n        self.snapshots.push(snapshot);\n        cx.notify();\n    }\n\n    fn restore_snapshot(&mut self, index: usize, cx: &mut Context<Self>) -> Result<(), String> {\n        if let Some(snapshot) = self.snapshots.get(index) {\n            self.data = snapshot.data.clone();\n            cx.notify();\n            Ok(())\n        } else {\n            Err(\"Invalid snapshot index\".to_string())\n        }\n    }\n\n    fn clear_old_snapshots(&mut self, keep_last: usize, cx: &mut Context<Self>) {\n        if self.snapshots.len() > keep_last {\n            self.snapshots.drain(0..self.snapshots.len() - keep_last);\n            cx.notify();\n        }\n    }\n}\n\nfn current_timestamp() -> u64 {\n    use std::time::{SystemTime, UNIX_EPOCH};\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .unwrap()\n        .as_secs()\n}\n```\n\n## Entity Transaction Pattern\n\n```rust\nstruct Transaction<T> {\n    entity: Entity<T>,\n    original_state: Option<T>,\n}\n\nimpl<T: Clone> Transaction<T> {\n    fn begin(entity: Entity<T>, cx: &mut App) -> Self {\n        let original_state = entity.read(cx).clone();\n\n        Self {\n            entity,\n            original_state: Some(original_state),\n        }\n    }\n\n    fn update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: FnOnce(&mut T, &mut Context<T>),\n    {\n        self.entity.update(cx, update_fn);\n    }\n\n    fn commit(mut self, cx: &mut App) {\n        self.original_state = None; // Don't rollback\n        self.entity.update(cx, |_, cx| {\n            cx.notify();\n        });\n    }\n\n    fn rollback(mut self, cx: &mut App) {\n        if let Some(original) = self.original_state.take() {\n            self.entity.update(cx, |state, cx| {\n                *state = original;\n                cx.notify();\n            });\n        }\n    }\n}\n\nimpl<T> Drop for Transaction<T> {\n    fn drop(&mut self) {\n        // Auto-rollback if not committed\n        if self.original_state.is_some() {\n            eprintln!(\"Warning: Transaction dropped without commit\");\n        }\n    }\n}\n\n// Usage\nfn perform_transaction(entity: Entity<MyState>, cx: &mut App) -> Result<(), String> {\n    let mut tx = Transaction::begin(entity, cx);\n\n    tx.update(cx, |state, cx| {\n        state.value = 42;\n    });\n\n    if validate_state(&tx.entity, cx)? {\n        tx.commit(cx);\n        Ok(())\n    } else {\n        tx.rollback(cx);\n        Err(\"Validation failed\".to_string())\n    }\n}\n```\n\n## Entity Pool Pattern\n\n```rust\nstruct EntityPool<T> {\n    available: Vec<Entity<T>>,\n    in_use: Vec<WeakEntity<T>>,\n    factory: Box<dyn Fn(&mut App) -> Entity<T>>,\n}\n\nimpl<T: 'static> EntityPool<T> {\n    fn new<F>(factory: F) -> Self\n    where\n        F: Fn(&mut App) -> Entity<T> + 'static,\n    {\n        Self {\n            available: Vec::new(),\n            in_use: Vec::new(),\n            factory: Box::new(factory),\n        }\n    }\n\n    fn acquire(&mut self, cx: &mut App) -> Entity<T> {\n        let entity = if let Some(entity) = self.available.pop() {\n            entity\n        } else {\n            (self.factory)(cx)\n        };\n\n        self.in_use.push(entity.downgrade());\n        entity\n    }\n\n    fn release(&mut self, entity: Entity<T>, cx: &mut App) {\n        // Reset entity state if needed\n        entity.update(cx, |state, cx| {\n            // Reset logic here\n            cx.notify();\n        });\n\n        self.available.push(entity);\n        self.cleanup_in_use();\n    }\n\n    fn cleanup_in_use(&mut self) {\n        self.in_use.retain(|weak| weak.upgrade().is_some());\n    }\n\n    fn pool_size(&self) -> (usize, usize) {\n        (self.available.len(), self.in_use.len())\n    }\n}\n```\n\nThese advanced patterns provide powerful abstractions for managing complex entity scenarios while maintaining code quality and performance.\n","skills/gpui-kit/references/gpui/entity-api.md":"# Entity API Reference\n\n**Contents:** [Entity Types](#entity-types) · [Entity Creation](#entity-creation) · [Entity Operations](#entity-operations) · [Context Methods](#context-methods-for-entities) · [Async Operations](#async-operations) · [Entity Lifecycle](#entity-lifecycle) · [EntityId](#entityid) · [Error Handling](#error-handling) · [Type Conversions](#type-conversions)\n\n## Entity Types\n\n### Entity<T>\n\nA strong reference to state of type `T`.\n\n**Methods:**\n- `entity_id()` → `EntityId` - Returns unique identifier\n- `downgrade()` → `WeakEntity<T>` - Creates weak reference\n- `read(cx)` → `&T` - Immutable access to state\n- `read_with(cx, |state, cx| ...)` → `R` - Read with closure, returns closure result\n- `update(cx, |state, cx| ...)` → `R` - Mutable update with `Context<T>`, returns closure result\n- `update_in(cx, |state, window, cx| ...)` → `R` - Update with `Window` access (requires `AsyncWindowContext` or `VisualTestContext`)\n\n**Important Notes:**\n- Trying to update an entity while it's already being updated will panic\n- Within closures, use the inner `cx` provided to avoid multiple borrow issues\n- With async contexts, return values are wrapped in `anyhow::Result`\n\n### WeakEntity<T>\n\nA weak reference to state of type `T`.\n\n**Methods:**\n- `upgrade()` → `Option<Entity<T>>` - Convert to strong reference if still alive\n- `read_with(cx, |state, cx| ...)` → `Result<R>` - Read if entity exists\n- `update(cx, |state, cx| ...)` → `Result<R>` - Update if entity exists\n- `update_in(cx, |state, window, cx| ...)` → `Result<R>` - Update with window if entity exists\n\n**Use Cases:**\n- Avoid circular dependencies between entities\n- Store references in closures/callbacks without preventing cleanup\n- Optional relationships between components\n\n**Important:** All operations return `Result` since the entity may no longer exist.\n\n### AnyEntity\n\nDynamically-typed entity handle for storing entities of different types.\n\n### AnyWeakEntity\n\nDynamically-typed weak entity handle.\n\n## Entity Creation\n\n### cx.new()\n\nCreate new entity with initial state.\n\n```rust\nlet entity = cx.new(|cx| MyState {\n    count: 0,\n    name: \"Default\".to_string(),\n});\n```\n\n**Parameters:**\n- `cx: &mut App` or other context type\n- Closure receiving `&mut Context<T>` returning initial state `T`\n\n**Returns:** `Entity<T>`\n\n## Entity Operations\n\n### Reading State\n\n#### read()\n\nDirect read-only access to state.\n\n```rust\nlet count = my_entity.read(cx).count;\n```\n\n**Use when:** Simple field access, no context operations needed.\n\n#### read_with()\n\nRead with context access in closure.\n\n```rust\nlet count = my_entity.read_with(cx, |state, cx| {\n    // Can access both state and context\n    state.count\n});\n\n// Return multiple values\nlet (count, theme) = my_entity.read_with(cx, |state, cx| {\n    (state.count, cx.theme().clone())\n});\n```\n\n**Use when:** Need context operations, multiple return values, complex logic.\n\n### Updating State\n\n#### update()\n\nMutable update with `Context<T>`.\n\n```rust\nmy_entity.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify(); // Trigger re-render\n});\n```\n\n**Available Operations:**\n- `cx.notify()` - Trigger re-render\n- `cx.entity()` - Get current entity\n- `cx.emit(event)` - Emit event\n- `cx.spawn(task)` - Spawn async task\n- Other `Context<T>` methods\n\n#### update_in()\n\nUpdate with both `Window` and `Context<T>` access.\n\n```rust\nmy_entity.update_in(cx, |state, window, cx| {\n    state.focused = window.is_window_focused();\n    cx.notify();\n});\n```\n\n**Requires:** `AsyncWindowContext` or `VisualTestContext`\n\n**Use when:** Need window-specific operations like focus state, window bounds, etc.\n\n## Context Methods for Entities\n\n### cx.entity()\n\nGet current entity being updated.\n\n```rust\nimpl MyComponent {\n    fn some_method(&mut self, cx: &mut Context<Self>) {\n        let current_entity = cx.entity();  // Entity<MyComponent>\n        let weak = current_entity.downgrade();\n    }\n}\n```\n\n### cx.observe()\n\nObserve entity for changes.\n\n```rust\ncx.observe(&entity, |this, observed_entity, cx| {\n    // Called when observed_entity.update() calls cx.notify()\n    println!(\"Entity changed\");\n}).detach();\n```\n\n**Returns:** `Subscription` - Call `.detach()` to make permanent\n\n### cx.subscribe()\n\nSubscribe to events from entity.\n\n```rust\ncx.subscribe(&entity, |this, emitter, event: &SomeEvent, cx| {\n    // Called when emitter emits SomeEvent\n    match event {\n        SomeEvent::DataChanged => {\n            cx.notify();\n        }\n    }\n}).detach();\n```\n\n**Returns:** `Subscription` - Call `.detach()` to make permanent\n\n### cx.observe_new_entities()\n\nRegister callback for new entities of a type.\n\n```rust\ncx.observe_new_entities::<MyState>(|entity, cx| {\n    println!(\"New entity created: {:?}\", entity.entity_id());\n}).detach();\n```\n\n## Async Operations\n\n### cx.spawn()\n\nSpawn foreground task (UI thread).\n\n```rust\ncx.spawn(async move |this, cx| {\n    // `this`: WeakEntity<T>\n    // `cx`: &mut AsyncApp\n\n    let result = some_async_work().await;\n\n    // Update entity safely\n    let _ = this.update(cx, |state, cx| {\n        state.data = result;\n        cx.notify();\n    });\n}).detach();\n```\n\n**Note:** Always use weak entity reference in spawned tasks to prevent retain cycles.\n\n### cx.background_spawn()\n\nSpawn background task (background thread).\n\n```rust\ncx.background_spawn(async move {\n    // Long-running computation\n    let result = heavy_computation().await;\n    // Cannot directly update entities here\n    // Use channels or spawn foreground task to update\n}).detach();\n```\n\n## Entity Lifecycle\n\n### Creation\n\nEntities are created via `cx.new()` and immediately registered in the app.\n\n### Reference Counting\n\n- `Entity<T>` is a strong reference (increases reference count)\n- `WeakEntity<T>` is a weak reference (does not increase reference count)\n- Cloning `Entity<T>` increases reference count\n\n### Disposal\n\nEntities are automatically disposed when all strong references are dropped.\n\n```rust\n{\n    let entity = cx.new(|cx| MyState::default());\n    // entity exists\n} // entity dropped here if no other strong references exist\n```\n\n**Memory Leak Prevention:**\n- Use `WeakEntity` in closures/callbacks\n- Use `WeakEntity` for parent-child relationships\n- Avoid circular strong references\n\n## EntityId\n\nEvery entity has a unique identifier.\n\n```rust\nlet id: EntityId = entity.entity_id();\n\n// EntityIds can be compared\nif entity1.entity_id() == entity2.entity_id() {\n    // Same entity\n}\n```\n\n**Use Cases:**\n- Debugging and logging\n- Entity comparison without borrowing\n- Hash maps keyed by entity\n\n## Error Handling\n\n### WeakEntity Operations\n\nAll `WeakEntity` operations return `Result`:\n\n```rust\nlet weak = entity.downgrade();\n\n// Handle potential failure\nmatch weak.read_with(cx, |state, cx| state.count) {\n    Ok(count) => println!(\"Count: {}\", count),\n    Err(e) => eprintln!(\"Entity no longer exists: {}\", e),\n}\n\n// Or use Result combinators\nlet _ = weak.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify();\n}).ok(); // Ignore errors\n```\n\n### Update Panics\n\nNested updates on the same entity will panic:\n\n```rust\n// ❌ Will panic\nentity.update(cx, |state1, cx| {\n    entity.update(cx, |state2, cx| {\n        // Panic: entity already borrowed\n    });\n});\n```\n\n**Solution:** Perform updates sequentially or use different entities.\n\n## Type Conversions\n\n### Entity → WeakEntity\n\n```rust\nlet entity: Entity<T> = cx.new(|cx| T::default());\nlet weak: WeakEntity<T> = entity.downgrade();\n```\n\n### WeakEntity → Entity\n\n```rust\nlet weak: WeakEntity<T> = entity.downgrade();\nlet strong: Option<Entity<T>> = weak.upgrade();\n```\n\n### AnyEntity\n\n```rust\nlet any: AnyEntity = entity.into();\nlet typed: Option<Entity<T>> = any.downcast::<T>();\n```\n\n## Best Practice Guidelines\n\n### Always Use Inner cx\n\n```rust\n// ✅ Good: Use inner cx\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Use inner_cx, not outer cx\n});\n\n// ❌ Bad: Use outer cx\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong! Multiple borrow error\n});\n```\n\n### Weak References in Closures\n\n```rust\n// ✅ Good: Weak reference\nlet weak = cx.entity().downgrade();\ncallback(move || {\n    let _ = weak.update(cx, |state, cx| {\n        cx.notify();\n    });\n});\n\n// ❌ Bad: Strong reference (retain cycle)\nlet strong = cx.entity();\ncallback(move || {\n    strong.update(cx, |state, cx| {\n        // May never be dropped\n        cx.notify();\n    });\n});\n```\n\n### Sequential Updates\n\n```rust\n// ✅ Good: Sequential updates\nentity1.update(cx, |state, cx| { /* ... */ });\nentity2.update(cx, |state, cx| { /* ... */ });\n\n// ❌ Bad: Nested updates\nentity1.update(cx, |_, cx| {\n    entity2.update(cx, |_, cx| {\n        // May panic if entities are related\n    });\n});\n```\n","skills/gpui-kit/references/gpui/entity-best-practices.md":"# Entity Best Practices\n\n**Contents:** [Avoiding Common Pitfalls](#avoiding-common-pitfalls) · [Performance Optimization](#performance-optimization) · [Entity Lifecycle Management](#entity-lifecycle-management) · [Entity Observation Best Practices](#entity-observation-best-practices) · [Async Best Practices](#async-best-practices) · [Testing Best Practices](#testing-best-practices) · [Performance Checklist](#performance-checklist)\n\n## Avoiding Common Pitfalls\n\n### Avoid Re-entrant Entity Access (Same Entity)\n\n**Problem:** GPUI locks an entity for the entire duration of its render or update pass. Any attempt to `read` or `update` that *same* entity while the lock is held panics:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: entity_a updated from within entity_a's own update\nentity_a.update(cx, |_, cx| {\n    entity_a.update(cx, |_, _| {}); // PANIC\n});\n\n// ✅ Fine: updating a *different* entity from within an update\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, _| {}); // OK — different lock\n});\n```\n\n**Note:** Updating two *different* entities in a nested fashion is safe. The restriction is strictly about re-entering the *same* entity's lock.\n\n### `defer_in` Re-locks the Entity — Same Rules Apply\n\n`cx.defer_in(window, callback)` schedules `callback` to run *on the entity the context refers to*. GPUI re-acquires that entity's lock to execute the deferred callback, so the re-entrancy rules apply equally inside it:\n\n```rust\n// ❌ Panic: defer_in runs with ListState locked; calling list.update re-enters\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // list_state IS locked for this entire callback!\n        parent.update(cx, |this, cx| {\n            this.list.update(cx, |_, _| {}); // PANIC — re-enters ListState lock\n        });\n    });\n}\n```\n\n**Fix:** Use the direct `&mut` reference the callback provides instead of going through the entity handle:\n\n```rust\n// ✅ Correct: direct mutable access — no lock needed\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // Step 1: call hooks directly through list_state (no entity lock)\n        list_state.delegate_mut().on_will_change(&mut op, &snapshot);\n\n        // Step 2: update the parent entity — different lock, safe\n        let new_sel = parent.update(cx, |this, cx| {\n            this.state.apply_change(op);\n            cx.notify();\n            this.state.selection.clone() // return data needed for step 3\n        });\n\n        // Step 3: sync list state directly — no entity lock\n        if let Ok(sel) = new_sel {\n            list_state.delegate_mut().update_snapshot(sel.clone());\n            list_state.delegate_mut().on_confirm(&sel);\n        }\n    });\n}\n```\n\n### Render Callbacks Must Not Access External Entities\n\n`render_item` and any other rendering hook runs inside the entity's render pass. Calling `entity.read(cx)` or `entity.update(cx, …)` on an external entity (which may itself be in a render/update pass) panics with the same re-entrancy error.\n\n**Fix:** Keep a plain `snapshot` field updated eagerly from outside render after every mutation:\n\n```rust\n// ❌ Panic — called during ListState render; external entity access re-enters\nfn render_item(&mut self, ix: IndexPath, …) -> … {\n    let checked = parent.read(cx).selection.contains(&ix); // PANIC\n}\n\n// ✅ Read from snapshot field — no entity access at all\nfn render_item(&mut self, ix: IndexPath, …) -> … {\n    let checked = self.selection_snapshot.iter().any(|(sel_ix, _)| sel_ix == &ix);\n}\n// After every mutation from outside render:\nlist.update(cx, |l, _| l.delegate_mut().update_snapshot(new_snapshot));\n```\n\n### Use Weak References in Closures\n\n**Problem:** Strong references in closures can create retain cycles and memory leaks.\n\n```rust\n// ❌ Bad: Strong reference creates retain cycle\nimpl MyComponent {\n    fn setup_callback(&mut self, cx: &mut Context<Self>) {\n        let entity = cx.entity(); // Strong reference\n\n        some_callback(move || {\n            entity.update(cx, |state, cx| {\n                // This closure holds a strong reference\n                // If the closure itself is retained by the entity, memory leak!\n                cx.notify();\n            });\n        });\n    }\n}\n```\n\n**Solution:** Use weak references in closures.\n\n```rust\n// ✅ Good: Weak reference prevents retain cycle\nimpl MyComponent {\n    fn setup_callback(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade(); // Weak reference\n\n        some_callback(move || {\n            // Safe: weak reference doesn't prevent cleanup\n            let _ = weak_entity.update(cx, |state, cx| {\n                cx.notify();\n            });\n        });\n    }\n}\n```\n\n### Use Inner Context in Closures\n\n**Problem:** Using outer context causes multiple borrow errors.\n\n```rust\n// ❌ Bad: Using outer cx causes borrow issues\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong! Using outer cx\n    cx.spawn(...); // Multiple borrow error\n});\n```\n\n**Solution:** Always use the inner context provided to the closure.\n\n```rust\n// ✅ Good: Use inner cx\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Correct\n    inner_cx.spawn(...); // Works fine\n});\n```\n\n### Entity as Props - Use Weak References\n\n**Problem:** Strong entity references in props can create ownership issues.\n\n```rust\n// ❌ Questionable: Strong reference in child\nstruct ChildComponent {\n    parent: Entity<ParentComponent>, // Strong reference\n}\n```\n\n**Better:** Use weak references for parent relationships.\n\n```rust\n// ✅ Good: Weak reference prevents issues\nstruct ChildComponent {\n    parent: WeakEntity<ParentComponent>, // Weak reference\n}\n\nimpl ChildComponent {\n    fn notify_parent(&mut self, cx: &mut Context<Self>) {\n        // Check if parent still exists\n        if let Ok(_) = self.parent.update(cx, |parent_state, cx| {\n            // Update parent\n            cx.notify();\n        }) {\n            // Parent successfully updated\n        }\n    }\n}\n```\n\n## Performance Optimization\n\n### Minimize cx.notify() Calls\n\nEach `cx.notify()` triggers a re-render. Batch updates when possible.\n\n```rust\n// ❌ Bad: Multiple notifications\nimpl MyComponent {\n    fn update_multiple_fields(&mut self, cx: &mut Context<Self>) {\n        self.field1 = new_value1;\n        cx.notify(); // Unnecessary intermediate notification\n\n        self.field2 = new_value2;\n        cx.notify(); // Unnecessary intermediate notification\n\n        self.field3 = new_value3;\n        cx.notify();\n    }\n}\n```\n\n```rust\n// ✅ Good: Single notification after all updates\nimpl MyComponent {\n    fn update_multiple_fields(&mut self, cx: &mut Context<Self>) {\n        self.field1 = new_value1;\n        self.field2 = new_value2;\n        self.field3 = new_value3;\n        cx.notify(); // Single notification\n    }\n}\n```\n\n### Conditional Updates\n\nOnly notify when state actually changes.\n\n```rust\nimpl MyComponent {\n    fn set_value(&mut self, new_value: i32, cx: &mut Context<Self>) {\n        if self.value != new_value {\n            self.value = new_value;\n            cx.notify(); // Only notify if changed\n        }\n    }\n}\n```\n\n### Use read_with for Complex Operations\n\nPrefer `read_with` over separate `read` calls.\n\n```rust\n// ❌ Less efficient: Multiple borrows\nlet state_ref = entity.read(cx);\nlet value1 = state_ref.field1;\nlet value2 = state_ref.field2;\n// state_ref borrowed for entire scope\n\n// ✅ More efficient: Single borrow with closure\nlet (value1, value2) = entity.read_with(cx, |state, cx| {\n    (state.field1, state.field2)\n});\n```\n\n### Avoid Excessive Entity Creation\n\nCreating entities has overhead. Reuse when appropriate.\n\n```rust\n// ❌ Bad: Creating entity per item in render\nimpl Render for MyList {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div().children(\n            self.items.iter().map(|item| {\n                // Don't create entities in render!\n                let entity = cx.new(|_| item.clone());\n                ItemView { entity }\n            })\n        )\n    }\n}\n```\n\n```rust\n// ✅ Good: Create entities once, reuse\nstruct MyList {\n    item_entities: Vec<Entity<Item>>,\n}\n\nimpl MyList {\n    fn add_item(&mut self, item: Item, cx: &mut Context<Self>) {\n        let entity = cx.new(|_| item);\n        self.item_entities.push(entity);\n        cx.notify();\n    }\n}\n```\n\n## Entity Lifecycle Management\n\n### Clean Up Weak References\n\nPeriodically clean up invalid weak references from collections.\n\n```rust\nstruct Container {\n    weak_children: Vec<WeakEntity<Child>>,\n}\n\nimpl Container {\n    fn cleanup_invalid_children(&mut self, cx: &mut Context<Self>) {\n        // Remove weak references that are no longer valid\n        let before_count = self.weak_children.len();\n        self.weak_children.retain(|weak| weak.upgrade().is_some());\n        let after_count = self.weak_children.len();\n\n        if before_count != after_count {\n            cx.notify(); // Notify if list changed\n        }\n    }\n}\n```\n\n### Entity Cloning and Sharing\n\nUnderstand that cloning `Entity<T>` increases reference count.\n\n```rust\n// Each clone increases the reference count\nlet entity1: Entity<MyState> = cx.new(|_| MyState::default());\nlet entity2 = entity1.clone(); // Reference count: 2\nlet entity3 = entity1.clone(); // Reference count: 3\n\n// Entity is dropped only when all references are dropped\ndrop(entity1); // Reference count: 2\ndrop(entity2); // Reference count: 1\ndrop(entity3); // Reference count: 0, entity is deallocated\n```\n\n### Proper Resource Cleanup\n\nImplement cleanup in `Drop` or explicit cleanup methods.\n\n```rust\nstruct ManagedResource {\n    handle: Option<FileHandle>,\n}\n\nimpl ManagedResource {\n    fn close(&mut self, cx: &mut Context<Self>) {\n        if let Some(handle) = self.handle.take() {\n            // Explicit cleanup\n            handle.close();\n            cx.notify();\n        }\n    }\n}\n\nimpl Drop for ManagedResource {\n    fn drop(&mut self) {\n        // Automatic cleanup when entity is dropped\n        if let Some(handle) = self.handle.take() {\n            handle.close();\n        }\n    }\n}\n```\n\n## Entity Observation Best Practices\n\n### Detach Subscriptions Appropriately\n\nCall `.detach()` on subscriptions you want to keep alive.\n\n```rust\nimpl MyComponent {\n    fn new(other_entity: Entity<OtherComponent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observer will live as long as both entities exist\n            cx.observe(&other_entity, |this, observed, cx| {\n                // Handle changes\n                cx.notify();\n            }).detach(); // Important: detach to make permanent\n\n            Self { /* fields */ }\n        })\n    }\n}\n```\n\n### Avoid Observation Cycles\n\nDon't create mutual observation between entities.\n\n```rust\n// ❌ Bad: Mutual observation can cause infinite loops\nentity1.update(cx, |_, cx| {\n    cx.observe(&entity2, |_, _, cx| {\n        cx.notify(); // May trigger entity2's observer\n    }).detach();\n});\n\nentity2.update(cx, |_, cx| {\n    cx.observe(&entity1, |_, _, cx| {\n        cx.notify(); // May trigger entity1's observer → infinite loop\n    }).detach();\n});\n```\n\n## Async Best Practices\n\n### Always Use Weak References in Async Tasks\n\n```rust\n// ✅ Good: Weak reference in spawned task\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            let data = fetch_from_api().await;\n\n            // Entity may have been dropped during fetch\n            let _ = weak_entity.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n```\n\n### Handle Async Errors Gracefully\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            match fetch_from_api().await {\n                Ok(data) => {\n                    let _ = weak_entity.update(cx, |state, cx| {\n                        state.data = Some(data);\n                        state.error = None;\n                        cx.notify();\n                    });\n                }\n                Err(e) => {\n                    let _ = weak_entity.update(cx, |state, cx| {\n                        state.error = Some(e.to_string());\n                        cx.notify();\n                    });\n                }\n            }\n        }).detach();\n    }\n}\n```\n\n### Cancellation Patterns\n\nImplement cancellation for long-running tasks.\n\n```rust\nstruct DataFetcher {\n    current_task: Option<Task<()>>,\n    data: Option<String>,\n}\n\nimpl DataFetcher {\n    fn fetch_data(&mut self, url: String, cx: &mut Context<Self>) {\n        // Cancel previous task\n        self.current_task = None; // Dropping task cancels it\n\n        let weak_entity = cx.entity().downgrade();\n\n        let task = cx.spawn(async move |cx| {\n            let data = fetch_from_url(&url).await?;\n\n            let _ = weak_entity.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n\n            Ok::<(), anyhow::Error>(())\n        });\n\n        self.current_task = Some(task);\n    }\n}\n```\n\n## Testing Best Practices\n\n### Use TestAppContext for Entity Tests\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use gpui_kit::TestAppContext;\n\n    #[gpui_kit::test]\n    fn test_entity_update(cx: &mut TestAppContext) {\n        let entity = cx.new(|_| MyState { count: 0 });\n\n        entity.update(cx, |state, cx| {\n            state.count += 1;\n            assert_eq!(state.count, 1);\n        });\n\n        let count = entity.read(cx).count;\n        assert_eq!(count, 1);\n    }\n}\n```\n\n### Test Entity Observation\n\n```rust\n#[gpui_kit::test]\nfn test_entity_observation(cx: &mut TestAppContext) {\n    let observed = cx.new(|_| MyState { value: 0 });\n    let observer = cx.new(|cx| Observer::new(observed.clone(), cx));\n\n    // Update observed entity\n    observed.update(cx, |state, cx| {\n        state.value = 42;\n        cx.notify();\n    });\n\n    // Verify observer was notified\n    observer.read(cx).assert_observed();\n}\n```\n\n## Performance Checklist\n\nBefore shipping entity-based code, verify:\n\n- [ ] No strong references in closures/callbacks (use `WeakEntity`)\n- [ ] No nested entity updates (use sequential updates)\n- [ ] Using inner `cx` in update closures\n- [ ] Batching updates before calling `cx.notify()`\n- [ ] Cleaning up invalid weak references periodically\n- [ ] Using `read_with` for complex read operations\n- [ ] Properly detaching subscriptions and observers\n- [ ] Using weak references in async tasks\n- [ ] No observation cycles between entities\n- [ ] Proper error handling in async operations\n- [ ] Resource cleanup in `Drop` or explicit methods\n- [ ] Tests cover entity lifecycle and interactions\n","skills/gpui-kit/references/gpui/entity-patterns.md":"# Entity Patterns\n\n**Contents:** [Application Scenarios](#application-scenarios) · [Common Patterns](#common-patterns) · [Pattern Selection Guide](#pattern-selection-guide)\n\n## Application Scenarios\n\n### Model-View Separation\n\nSeparate business logic (model) from UI (view) using entities.\n\n```rust\nstruct CounterModel {\n    count: usize,\n    listeners: Vec<Box<dyn Fn(usize)>>,\n}\n\nstruct CounterView {\n    model: Entity<CounterModel>,\n}\n\nimpl CounterModel {\n    fn increment(&mut self, cx: &mut Context<Self>) {\n        self.count += 1;\n\n        // Notify listeners\n        for listener in &self.listeners {\n            listener(self.count);\n        }\n\n        cx.notify();\n    }\n\n    fn decrement(&mut self, cx: &mut Context<Self>) {\n        if self.count > 0 {\n            self.count -= 1;\n            cx.notify();\n        }\n    }\n}\n\nimpl CounterView {\n    fn new(cx: &mut App) -> Entity<Self> {\n        let model = cx.new(|_cx| CounterModel {\n            count: 0,\n            listeners: Vec::new(),\n        });\n\n        cx.new(|cx| Self { model })\n    }\n\n    fn increment_count(&mut self, cx: &mut Context<Self>) {\n        self.model.update(cx, |model, cx| {\n            model.increment(cx);\n        });\n    }\n}\n\nimpl Render for CounterView {\n    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let count = self.model.read(cx).count;\n\n        div()\n            .child(format!(\"Count: {}\", count))\n            .child(\n                Button::new(\"increment\")\n                    .label(\"Increment\")\n                    .on_click(cx.listener(|this, _, cx| {\n                        this.increment_count(cx);\n                    }))\n            )\n    }\n}\n```\n\n### Component State Management\n\nManaging complex component state with entities.\n\n```rust\nstruct TodoList {\n    todos: Vec<Todo>,\n    filter: TodoFilter,\n    next_id: usize,\n}\n\nstruct Todo {\n    id: usize,\n    text: String,\n    completed: bool,\n}\n\nenum TodoFilter {\n    All,\n    Active,\n    Completed,\n}\n\nimpl TodoList {\n    fn new() -> Self {\n        Self {\n            todos: Vec::new(),\n            filter: TodoFilter::All,\n            next_id: 0,\n        }\n    }\n\n    fn add_todo(&mut self, text: String, cx: &mut Context<Self>) {\n        self.todos.push(Todo {\n            id: self.next_id,\n            text,\n            completed: false,\n        });\n        self.next_id += 1;\n        cx.notify();\n    }\n\n    fn toggle_todo(&mut self, id: usize, cx: &mut Context<Self>) {\n        if let Some(todo) = self.todos.iter_mut().find(|t| t.id == id) {\n            todo.completed = !todo.completed;\n            cx.notify();\n        }\n    }\n\n    fn remove_todo(&mut self, id: usize, cx: &mut Context<Self>) {\n        self.todos.retain(|t| t.id != id);\n        cx.notify();\n    }\n\n    fn set_filter(&mut self, filter: TodoFilter, cx: &mut Context<Self>) {\n        self.filter = filter;\n        cx.notify();\n    }\n\n    fn visible_todos(&self) -> impl Iterator<Item = &Todo> {\n        self.todos.iter().filter(move |todo| match self.filter {\n            TodoFilter::All => true,\n            TodoFilter::Active => !todo.completed,\n            TodoFilter::Completed => todo.completed,\n        })\n    }\n}\n```\n\n### Cross-Entity Communication\n\nCoordinating state between parent and child entities.\n\n```rust\nstruct ParentComponent {\n    child_entities: Vec<Entity<ChildComponent>>,\n    global_message: String,\n}\n\nstruct ChildComponent {\n    id: usize,\n    message: String,\n    parent: WeakEntity<ParentComponent>,\n}\n\nimpl ParentComponent {\n    fn new(cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| Self {\n            child_entities: Vec::new(),\n            global_message: String::new(),\n        })\n    }\n\n    fn add_child(&mut self, cx: &mut Context<Self>) {\n        let parent_weak = cx.entity().downgrade();\n        let child_id = self.child_entities.len();\n\n        let child = cx.new(|cx| ChildComponent {\n            id: child_id,\n            message: String::new(),\n            parent: parent_weak,\n        });\n\n        self.child_entities.push(child);\n        cx.notify();\n    }\n\n    fn broadcast_message(&mut self, message: String, cx: &mut Context<Self>) {\n        self.global_message = message.clone();\n\n        // Update all children\n        for child in &self.child_entities {\n            child.update(cx, |child_state, cx| {\n                child_state.message = message.clone();\n                cx.notify();\n            });\n        }\n\n        cx.notify();\n    }\n}\n\nimpl ChildComponent {\n    fn notify_parent(&mut self, message: String, cx: &mut Context<Self>) {\n        if let Ok(_) = self.parent.update(cx, |parent_state, cx| {\n            parent_state.global_message = format!(\"Child {}: {}\", self.id, message);\n            cx.notify();\n        }) {\n            // Parent successfully notified\n        }\n    }\n}\n```\n\n### Async Operations with Entities\n\nManaging async state updates.\n\n```rust\nstruct DataLoader {\n    loading: bool,\n    data: Option<String>,\n    error: Option<String>,\n}\n\nimpl DataLoader {\n    fn new() -> Self {\n        Self {\n            loading: false,\n            data: None,\n            error: None,\n        }\n    }\n\n    fn load_data(&mut self, cx: &mut Context<Self>) {\n        // Set loading state\n        self.loading = true;\n        self.error = None;\n        cx.notify();\n\n        // Get weak reference for async task\n        let entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            // Simulate async operation\n            tokio::time::sleep(Duration::from_secs(2)).await;\n            let result = fetch_data().await;\n\n            // Update entity with result\n            let _ = entity.update(cx, |state, cx| {\n                state.loading = false;\n                match result {\n                    Ok(data) => state.data = Some(data),\n                    Err(e) => state.error = Some(e.to_string()),\n                }\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n\nasync fn fetch_data() -> Result<String, anyhow::Error> {\n    // Actual fetch implementation\n    Ok(\"Fetched data\".to_string())\n}\n```\n\n### Background Task Coordination\n\nUsing background tasks with entity updates.\n\n```rust\nstruct ImageProcessor {\n    images: Vec<ProcessedImage>,\n    processing: bool,\n}\n\nstruct ProcessedImage {\n    path: PathBuf,\n    thumbnail: Option<Vec<u8>>,\n}\n\nimpl ImageProcessor {\n    fn process_images(&mut self, paths: Vec<PathBuf>, cx: &mut Context<Self>) {\n        self.processing = true;\n        cx.notify();\n\n        cx.spawn(async move |this, cx| {\n            let processed = cx\n                .background_spawn(async move {\n                    let mut processed = Vec::new();\n\n                    for path in paths {\n                        // Process image on background thread\n                        let thumbnail = generate_thumbnail(&path).await;\n                        processed.push((path, thumbnail));\n                    }\n\n                    // Send results back to foreground\n                    processed\n                })\n                .await;\n\n            // Update entity on foreground thread\n            let _ = this.update(cx, |state, cx| {\n                for (path, thumbnail) in processed {\n                    state.images.push(ProcessedImage {\n                        path,\n                        thumbnail: Some(thumbnail),\n                    });\n                }\n                state.processing = false;\n                cx.notify();\n            });\n        })\n        .detach();\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Stateful Components\n\nUse entities for components that maintain internal state.\n\n```rust\nstruct StatefulComponent {\n    value: i32,\n    history: Vec<i32>,\n}\n\nimpl StatefulComponent {\n    fn update_value(&mut self, new_value: i32, cx: &mut Context<Self>) {\n        self.history.push(self.value);\n        self.value = new_value;\n        cx.notify();\n    }\n\n    fn undo(&mut self, cx: &mut Context<Self>) {\n        if let Some(prev_value) = self.history.pop() {\n            self.value = prev_value;\n            cx.notify();\n        }\n    }\n}\n```\n\n### 2. Shared State\n\nShare state between multiple components using entities.\n\n```rust\nstruct SharedState {\n    theme: Theme,\n    user: Option<User>,\n}\n\nstruct ComponentA {\n    shared: Entity<SharedState>,\n}\n\nstruct ComponentB {\n    shared: Entity<SharedState>,\n}\n\n// Both components can read/update the same shared state\nimpl ComponentA {\n    fn update_theme(&mut self, theme: Theme, cx: &mut Context<Self>) {\n        self.shared.update(cx, |state, cx| {\n            state.theme = theme;\n            cx.notify();\n        });\n    }\n}\n```\n\n### 3. Event Coordination\n\nUse entities to coordinate events between components.\n\n```rust\nstruct EventCoordinator {\n    listeners: Vec<WeakEntity<dyn EventListener>>,\n}\n\ntrait EventListener {\n    fn on_event(&mut self, event: &AppEvent, cx: &mut App);\n}\n\nimpl EventCoordinator {\n    fn emit_event(&mut self, event: AppEvent, cx: &mut Context<Self>) {\n        // Notify all listeners\n        self.listeners.retain(|weak_listener| {\n            weak_listener.update(cx, |listener, cx| {\n                listener.on_event(&event, cx);\n            }).is_ok()\n        });\n        cx.notify();\n    }\n}\n```\n\n### 4. Async State Management\n\nManage state that changes based on async operations.\n\n```rust\nstruct AsyncState<T> {\n    state: AsyncValue<T>,\n}\n\nenum AsyncValue<T> {\n    Loading,\n    Loaded(T),\n    Error(String),\n}\n\nimpl<T> AsyncState<T> {\n    fn is_loading(&self) -> bool {\n        matches!(self.state, AsyncValue::Loading)\n    }\n\n    fn value(&self) -> Option<&T> {\n        match &self.state {\n            AsyncValue::Loaded(v) => Some(v),\n            _ => None,\n        }\n    }\n}\n```\n\n### 5. Parent-Child Relationships\n\nManage hierarchical relationships with weak references.\n\n```rust\nstruct Parent {\n    children: Vec<Entity<Child>>,\n}\n\nstruct Child {\n    parent: WeakEntity<Parent>,\n    data: String,\n}\n\nimpl Child {\n    fn notify_parent_of_change(&mut self, cx: &mut Context<Self>) {\n        if let Ok(_) = self.parent.update(cx, |parent, cx| {\n            // Parent can react to child change\n            cx.notify();\n        }) {\n            // Successfully notified\n        }\n    }\n}\n```\n\n### 6. Observer Pattern\n\nReact to entity state changes using observers.\n\n```rust\nstruct Observable {\n    value: i32,\n}\n\nstruct Observer {\n    observed: Entity<Observable>,\n}\n\nimpl Observer {\n    fn new(observed: Entity<Observable>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observe the entity\n            cx.observe(&observed, |this, observed_entity, cx| {\n                // React to changes\n                let value = observed_entity.read(cx).value;\n                println!(\"Value changed to: {}\", value);\n            }).detach();\n\n            Self { observed }\n        })\n    }\n}\n```\n\n### 7. Event Subscription\n\nHandle events emitted by other entities.\n\n```rust\n#[derive(Clone)]\nenum DataEvent {\n    Updated,\n    Deleted,\n}\n\nstruct DataSource {\n    data: Vec<String>,\n}\n\nimpl DataSource {\n    fn update_data(&mut self, cx: &mut Context<Self>) {\n        // Update data\n        cx.emit(DataEvent::Updated);\n        cx.notify();\n    }\n}\n\nstruct DataConsumer {\n    source: Entity<DataSource>,\n}\n\nimpl DataConsumer {\n    fn new(source: Entity<DataSource>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Subscribe to events\n            cx.subscribe(&source, |this, source, event: &DataEvent, cx| {\n                match event {\n                    DataEvent::Updated => {\n                        // Handle update\n                        cx.notify();\n                    }\n                    DataEvent::Deleted => {\n                        // Handle deletion\n                    }\n                }\n            }).detach();\n\n            Self { source }\n        })\n    }\n}\n```\n\n### 8. Resource Management\n\nManage external resources with proper cleanup.\n\n```rust\nstruct FileHandle {\n    path: PathBuf,\n    file: Option<File>,\n}\n\nimpl FileHandle {\n    fn open(&mut self, cx: &mut Context<Self>) -> Result<()> {\n        self.file = Some(File::open(&self.path)?);\n        cx.notify();\n        Ok(())\n    }\n\n    fn close(&mut self, cx: &mut Context<Self>) {\n        self.file = None;\n        cx.notify();\n    }\n}\n\nimpl Drop for FileHandle {\n    fn drop(&mut self) {\n        // Cleanup when entity is dropped\n        if let Some(file) = self.file.take() {\n            drop(file);\n        }\n    }\n}\n```\n\n## Pattern Selection Guide\n\n| Need | Pattern | Complexity |\n|------|---------|------------|\n| Component with internal state | Stateful Components | Low |\n| State shared by multiple components | Shared State | Low |\n| Coordinate events between components | Event Coordination | Medium |\n| Handle async data fetching | Async State Management | Medium |\n| Parent-child component hierarchy | Parent-Child Relationships | Medium |\n| React to state changes | Observer Pattern | Medium |\n| Handle custom events | Event Subscription | Medium-High |\n| Manage external resources | Resource Management | High |\n\nChoose the simplest pattern that meets your requirements. Combine patterns as needed for complex scenarios.\n","skills/gpui-kit/references/gpui/entity.md":"# Entity State Management\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Core Principles](#core-principles) · [Common Use Cases](#common-use-cases) · [Extended References](#reference-documentation)\n\n## Overview\n\nAn `Entity<T>` is a handle to state of type `T`, providing safe access and updates.\n\n**Key Methods:**\n- `entity.read(cx)` → `&T` - Read-only access\n- `entity.read_with(cx, |state, cx| ...)` → `R` - Read with closure\n- `entity.update(cx, |state, cx| ...)` → `R` - Mutable update\n- `entity.downgrade()` → `WeakEntity<T>` - Create weak reference\n- `entity.entity_id()` → `EntityId` - Unique identifier\n\n**Entity Types:**\n- **`Entity<T>`**: Strong reference (increases ref count)\n- **`WeakEntity<T>`**: Weak reference (doesn't prevent cleanup, returns `Result`)\n\n## Quick Start\n\n### Creating and Using Entities\n\n```rust\n// Create entity\nlet counter = cx.new(|cx| Counter { count: 0 });\n\n// Read state\nlet count = counter.read(cx).count;\n\n// Update state\ncounter.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify(); // Trigger re-render\n});\n\n// Weak reference (for closures/callbacks)\nlet weak = counter.downgrade();\nlet _ = weak.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify();\n});\n```\n\n### In Components\n\n```rust\nstruct MyComponent {\n    shared_state: Entity<SharedData>,\n}\n\nimpl MyComponent {\n    fn new(cx: &mut App) -> Entity<Self> {\n        let shared = cx.new(|_| SharedData::default());\n\n        cx.new(|cx| Self {\n            shared_state: shared,\n        })\n    }\n\n    fn update_shared(&mut self, cx: &mut Context<Self>) {\n        self.shared_state.update(cx, |state, cx| {\n            state.value = 42;\n            cx.notify();\n        });\n    }\n}\n```\n\n### Async Operations\n\nWhen calling `cx.spawn` from `Context<Self>`, the closure receives `(WeakEntity<Self>, &mut AsyncApp)`:\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx: &mut AsyncApp| {\n            let data = fetch_from_api().await;\n\n            // Update entity safely via the weak reference\n            let _ = this.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n```\n\n## Core Principles\n\n### Always Use Weak References in Closures\n\n```rust\n// ✅ Good: Weak reference prevents retain cycles\nlet weak = cx.entity().downgrade();\ncallback(move || {\n    let _ = weak.update(cx, |state, cx| cx.notify());\n});\n\n// ❌ Bad: Strong reference may cause memory leak\nlet strong = cx.entity();\ncallback(move || {\n    strong.update(cx, |state, cx| cx.notify());\n});\n```\n\n### Use Inner Context\n\n```rust\n// ✅ Good: Use inner cx from closure\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Correct\n});\n\n// ❌ Bad: Use outer cx (multiple borrow error)\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong!\n});\n```\n\n### Avoid Nested Entity Updates\n\nNested `entity.update(cx, …)` calls are dangerous. The default posture is: **do not nest them**. The sub-cases below clarify when a panic is guaranteed vs. merely possible.\n\n**Same entity → always panics.**  \nGPUI locks an entity for the entire duration of its update or render pass. Re-entering that same lock panics immediately:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: updating entity_a from inside entity_a's own update\nentity_a.update(cx, |state, cx| {\n    entity_a.update(cx, |_, _| {}); // PANIC — same lock\n});\n```\n\n**Different entity → generally safe, but indirect cycles still panic.**  \nEach entity has its own lock, so updating `entity_b` from within `entity_a`'s update normally succeeds. However, if `entity_b`'s callback reaches back into `entity_a` — directly or through a chain — GPUI will attempt to re-acquire `entity_a`'s lock and panic.\n\n```rust\n// ✅ Usually fine: different entities, no cycle\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, _| {}); // OK — different lock\n});\n\n// ❌ Panic: indirect cycle back to entity_a\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, cx| {\n        entity_a.update(cx, |_, _| {}); // PANIC — entity_a is still locked\n    });\n});\n```\n\nWhen in doubt, flatten the call sequence rather than nesting: finish the outer update, then update the second entity from outside.\n\n**`defer_in` does not bypass the lock.** `cx.defer_in(window, callback)` schedules `callback` to run on the current entity — meaning GPUI re-acquires the entity's lock to execute it. The re-entrancy rules apply equally inside the deferred callback:\n\n```rust\n// ❌ Panic: defer_in re-locks entity_a; calling entity_a.update inside re-enters\nimpl SomeDelegate for MyAdapter {\n    fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n        cx.defer_in(window, |list_state, window, cx| {\n            // list_state is locked for this callback!\n            parent.update(cx, |this, cx| {\n                this.list.update(cx, |_, _| {}); // PANIC — list is already locked above\n            });\n        });\n    }\n}\n\n// ✅ Fix: use the direct &mut reference the callback provides\nimpl SomeDelegate for MyAdapter {\n    fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n        cx.defer_in(window, |list_state, window, cx| {\n            // Access list data directly — no entity lock needed\n            list_state.delegate_mut().some_hook();\n\n            // Update the *parent* entity — different lock, safe\n            parent.update(cx, |this, cx| { /* … */ });\n\n            // Sync list state directly after parent update\n            list_state.delegate_mut().update_snapshot(new_val);\n        });\n    }\n}\n```\n\n**Snapshot pattern for render callbacks.** `render_item` (and any other rendering hook) runs inside the entity's render pass. It must never call `entity.read(cx)` or `entity.update(cx, …)` on any external entity. Instead, keep a plain `snapshot` field updated eagerly from *outside* render after every mutation:\n\n```rust\n// ❌ Panic in render_item — ListState is already locked\nfn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<ListState<Self>>) -> … {\n    let checked = parent_entity.read(cx).selection.contains(&ix); // PANIC\n}\n\n// ✅ Read from a plain snapshot field — no entity access\nfn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<ListState<Self>>) -> … {\n    let checked = self.selection_snapshot.iter().any(|(sel_ix, _)| sel_ix == &ix);\n}\n```\n\n## Common Use Cases\n\n1. **Component State**: Internal state that needs reactivity\n2. **Shared State**: State shared between multiple components\n3. **Parent-Child**: Coordinating between related components (use weak refs)\n4. **Async State**: Managing state that changes from async operations\n5. **Observations**: Reacting to changes in other entities\n\n## Reference Documentation\n\n- **API**: See [entity-api.md](entity-api.md) — entity types, methods, lifecycle, error handling\n- **Patterns**: See [entity-patterns.md](entity-patterns.md) — model-view, cross-entity communication, observer\n- **Best Practices**: See [entity-best-practices.md](entity-best-practices.md) — pitfalls, memory, performance, async\n- **Advanced**: See [entity-advanced.md](entity-advanced.md) — collections, registry, debounce, state machines\n","skills/gpui-kit/references/gpui/event.md":"# Events & Subscriptions\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Patterns](#common-patterns) · [subscribe_in](#subscribe_in--subscription-with-window-access) · [observe_window_activation](#observe_window_activation) · [observe_global](#observe_global) · [Subscription Lifetime](#subscription-lifetime) · [Best Practices](#best-practices)\n\n## Overview\n\nGPUI provides event system for component coordination:\n\n**Event Mechanisms:**\n- **Custom Events**: Define and emit type-safe events\n- **Observations**: React to entity state changes\n- **Subscriptions**: Listen to events from other entities\n- **Global Events**: App-wide event handling\n\n## Quick Start\n\n### Define and Emit Events\n\n```rust\n#[derive(Clone)]\nenum MyEvent {\n    DataUpdated(String),\n    ActionTriggered,\n}\n\nimpl MyComponent {\n    fn update_data(&mut self, data: String, cx: &mut Context<Self>) {\n        self.data = data.clone();\n\n        // Emit event\n        cx.emit(MyEvent::DataUpdated(data));\n        cx.notify();\n    }\n}\n```\n\n### Subscribe to Events\n\n```rust\nimpl Listener {\n    fn new(source: Entity<MyComponent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Subscribe to events\n            cx.subscribe(&source, |this, emitter, event: &MyEvent, cx| {\n                match event {\n                    MyEvent::DataUpdated(data) => {\n                        this.handle_update(data.clone(), cx);\n                    }\n                    MyEvent::ActionTriggered => {\n                        this.handle_action(cx);\n                    }\n                }\n            }).detach();\n\n            Self { source }\n        })\n    }\n}\n```\n\n### Observe Entity Changes\n\n```rust\nimpl Observer {\n    fn new(target: Entity<Target>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observe entity for any changes\n            cx.observe(&target, |this, observed, cx| {\n                // Called when observed.update() calls cx.notify()\n                println!(\"Target changed\");\n                cx.notify();\n            }).detach();\n\n            Self { target }\n        })\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Parent-Child Communication\n\n```rust\n// Parent emits events\nimpl Parent {\n    fn notify_children(&mut self, cx: &mut Context<Self>) {\n        cx.emit(ParentEvent::Updated);\n        cx.notify();\n    }\n}\n\n// Children subscribe\nimpl Child {\n    fn new(parent: Entity<Parent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            cx.subscribe(&parent, |this, parent, event, cx| {\n                this.handle_parent_event(event, cx);\n            }).detach();\n\n            Self { parent }\n        })\n    }\n}\n```\n\n### 2. Global Event Broadcasting\n\n```rust\nstruct EventBus {\n    listeners: Vec<WeakEntity<dyn Listener>>,\n}\n\nimpl EventBus {\n    fn broadcast(&mut self, event: GlobalEvent, cx: &mut Context<Self>) {\n        self.listeners.retain(|weak| {\n            weak.update(cx, |listener, cx| {\n                listener.on_event(&event, cx);\n            }).is_ok()\n        });\n    }\n}\n```\n\n### 3. Observer Pattern\n\n```rust\ncx.observe(&entity, |this, observed, cx| {\n    // React to any state change\n    let state = observed.read(cx);\n    this.sync_with_state(state, cx);\n}).detach();\n```\n\n## subscribe_in — Subscription with Window Access\n\nUse when the subscription callback needs `&mut Window`:\n\n```rust\n// Store subscriptions to keep them alive\nstruct MyComponent {\n    _subscriptions: Vec<Subscription>,\n}\n\nimpl MyComponent {\n    fn new(input: &Entity<InputState>, window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let _subscriptions = vec![\n            cx.subscribe_in(input, window, |this, state, event, window, cx| {\n                match event {\n                    InputEvent::PressEnter { .. } => this.on_submit(window, cx),\n                    InputEvent::Change => {\n                        let val = state.read(cx).value();\n                        this.on_change(val, cx);\n                    }\n                    _ => {}\n                }\n            }),\n        ];\n        Self { _subscriptions }\n    }\n}\n```\n\n`subscribe` vs `subscribe_in`:\n- `cx.subscribe(&entity, |this, source, event, cx|)` — no window\n- `cx.subscribe_in(&entity, window, |this, source, event, window, cx|)` — window access\n\n## observe_window_activation\n\n```rust\nlet _sub = cx.observe_window_activation(window, |this, window, cx| {\n    if window.is_window_active() {\n        this.start_polling(cx);\n    } else {\n        this.stop_polling(cx);\n    }\n});\n```\n\n## observe_global\n\n```rust\ncx.observe_global::<Theme>(|cx| {\n    cx.notify(); // Re-render when theme changes\n});\n```\n\n## Subscription Lifetime\n\nSubscriptions are cancelled when dropped. Two ways to keep alive:\n\n```rust\n// 1. .detach() — lives until entity is dropped\ncx.subscribe(&entity, |this, _, event, cx| {\n    // ...\n}).detach();\n\n// 2. Store in struct — cancelled when struct drops\nstruct MyView {\n    _subscriptions: Vec<Subscription>,\n}\n// _subscriptions.push(cx.subscribe(...));\n```\n\nUse `.detach()` for permanent subscriptions; store in struct for subscriptions that should stop when the component unmounts.\n\n## Best Practices\n\n### ✅ Detach Subscriptions\n\n```rust\n// ✅ Detach to keep alive\ncx.subscribe(&entity, |this, source, event, cx| {\n    // Handle event\n}).detach();\n```\n\n### ✅ Clean Event Types\n\n```rust\n#[derive(Clone)]\nenum AppEvent {\n    DataChanged { id: usize, value: String },\n    ActionPerformed(ActionType),\n    Error(String),\n}\n```\n\n### ❌ Avoid Event Loops\n\n```rust\n// ❌ Don't create mutual subscriptions\nentity1.subscribe(entity2) → emits event\nentity2.subscribe(entity1) → emits event → infinite loop!\n```\n\n## Reference Documentation\n\n","skills/gpui-kit/references/gpui/focus-handle.md":"# Focus & Keyboard Navigation\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Focus Events](#focus-events) · [Keyboard Navigation](#keyboard-navigation) · [Common Patterns](#common-patterns) · [Best Practices](#best-practices)\n\n## Overview\n\nGPUI's focus system enables keyboard navigation and focus management.\n\n**Key Concepts:**\n- **FocusHandle**: Reference to focusable element\n- **Focus tracking**: Current focused element\n- **Keyboard navigation**: Tab/Shift-Tab between elements\n- **Focus events**: on_focus, on_blur\n\n## Quick Start\n\n### Creating Focus Handles\n\n```rust\nstruct FocusableComponent {\n    focus_handle: FocusHandle,\n}\n\nimpl FocusableComponent {\n    fn new(cx: &mut Context<Self>) -> Self {\n        Self {\n            focus_handle: cx.focus_handle(),\n        }\n    }\n}\n```\n\n### Making Elements Focusable\n\n```rust\nimpl Render for FocusableComponent {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .on_action(cx.listener(Self::on_enter))\n            .child(\"Focusable content\")\n    }\n\n    fn on_enter(&mut self, _: &Enter, cx: &mut Context<Self>) {\n        // Handle Enter key when focused\n        cx.notify();\n    }\n}\n```\n\n### Focus Management\n\n```rust\nimpl MyComponent {\n    fn focus(&mut self, cx: &mut Context<Self>) {\n        self.focus_handle.focus(cx);\n    }\n\n    fn is_focused(&self, cx: &App) -> bool {\n        self.focus_handle.is_focused(cx)\n    }\n\n    fn blur(&mut self, cx: &mut Context<Self>) {\n        cx.blur();\n    }\n}\n```\n\n## Focus Events\n\n### Handling Focus Changes\n\n```rust\nimpl Render for MyInput {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let is_focused = self.focus_handle.is_focused(cx);\n\n        div()\n            .track_focus(&self.focus_handle)\n            .on_focus(cx.listener(|this, _event, cx| {\n                this.on_focus(cx);\n            }))\n            .on_blur(cx.listener(|this, _event, cx| {\n                this.on_blur(cx);\n            }))\n            .when(is_focused, |el| {\n                el.bg(cx.theme().focused_background)\n            })\n            .child(self.render_content())\n    }\n}\n\nimpl MyInput {\n    fn on_focus(&mut self, cx: &mut Context<Self>) {\n        // Handle focus gained\n        cx.notify();\n    }\n\n    fn on_blur(&mut self, cx: &mut Context<Self>) {\n        // Handle focus lost\n        cx.notify();\n    }\n}\n```\n\n## Keyboard Navigation\n\n### Tab Order\n\nA tracked handle is a Tab stop only when the handle says so. `cx.focus_handle()`\nstarts with `tab_stop = false`, and an element's own `.tab_index()` /\n`.tab_stop()` do not apply to a handle passed to `track_focus`: build the handle\nwith the flag.\n\n```rust\n// In the owning entity's constructor:\nlet focus1 = cx.focus_handle().tab_stop(true);          // Tab order: 1\nlet focus2 = cx.focus_handle().tab_stop(true);          // Tab order: 2\nlet hidden = cx.focus_handle();                         // focusable, never a Tab stop\n\ndiv()\n    .child(div().track_focus(&focus1).child(\"first\"))\n    .child(div().track_focus(&focus2).child(\"second\"))\n    .child(div().track_focus(&hidden).child(\"container\"))\n```\n\nThe Tab table is rebuilt every frame from the elements that painted with a\ntracked handle, in tree order (`tab_index` reorders within a `tab_group`). A\nstateless component may create its handle in `render` through keyed state —\n`window.use_keyed_state(id, cx, |_, cx| cx.focus_handle().tab_stop(true))` —\nwhich survives re-renders, so the order stays stable; `Button` does exactly\nthis. A focused element receives `ClickEvent::Keyboard` in `on_click` when\nEnter or Space is released, so a `track_focus` + `on_click` row activates from\nthe keyboard without extra bindings.\n\n### Focus Within Containers\n\n```rust\nimpl Container {\n    fn focus_first(&mut self, cx: &mut Context<Self>) {\n        if let Some(first) = self.children.first() {\n            first.update(cx, |child, cx| {\n                child.focus_handle.focus(cx);\n            });\n        }\n    }\n\n    fn focus_next(&mut self, cx: &mut Context<Self>) {\n        // Custom focus navigation logic\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Auto-focus on Mount\n\n```rust\nimpl MyDialog {\n    fn new(cx: &mut Context<Self>) -> Self {\n        let focus_handle = cx.focus_handle();\n\n        // Focus when created\n        focus_handle.focus(cx);\n\n        Self { focus_handle }\n    }\n}\n```\n\n### 2. Focus Trap (Modal)\n\n```rust\nimpl Modal {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .on_key_down(cx.listener(|this, event: &KeyDownEvent, cx| {\n                if event.key == Key::Tab {\n                    // Keep focus within modal\n                    this.focus_next_in_modal(cx);\n                    cx.stop_propagation();\n                }\n            }))\n            .child(self.render_content())\n    }\n}\n```\n\n### 3. Conditional Focus\n\n```rust\nimpl Searchable {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .when(self.search_active, |el| {\n                el.on_mount(cx.listener(|this, _, cx| {\n                    this.focus_handle.focus(cx);\n                }))\n            })\n            .child(self.search_input())\n    }\n}\n```\n\n### 4. Restore Lost Focus\n\nIf the focused element is no longer rendered (a table swapped for an empty\nstate), key dispatch starts at the dispatch tree's root node, so the view's\n`key_context` bindings and `on_action` handlers stop firing. Register one\n`cx.on_focus_lost` listener per window, usually on the root view, and move\nFocus to `window.focus_lost_restore_target(cx)`: the closest focusable\nancestor that is still rendered. Track the view's own handle on the element\nthat carries its `key_context`, so that element is the ancestor Focus returns\nto.\n\n```rust\nlet focus_lost = cx.on_focus_lost(window, |this, window, cx| {\n    let target = window\n        .focus_lost_restore_target(cx)\n        .unwrap_or_else(|| this.focus_handle.clone());\n    target.focus(window, cx);\n});\n// `this.focus_handle` is the view's tracked handle. Keep `focus_lost:\n// Subscription` on the view; dropping it unregisters.\n```\n\n## Best Practices\n\n### ✅ Track Focus on Interactive Elements\n\n```rust\n// ✅ Good: Track focus for keyboard interaction\ninput()\n    .track_focus(&self.focus_handle)\n    .on_action(cx.listener(Self::on_enter))\n```\n\n### ✅ Provide Visual Focus Indicators\n\nDraw the framework's ring so custom controls match `Button` and `Input`:\n\n```rust\nuse gpui_kit::component::ThemeStyled as _;\n\nlet is_focused = self.focus_handle.is_focused(window);\n\ndiv()\n    .track_focus(&self.focus_handle)\n    .when(is_focused, |el| el.focus_ring_style(window, cx))\n```\n\nThe ring is painted 3px outside the element, so an ancestor with\n`overflow_hidden()` clips it; leave it room or draw the ring inside the element.\n\n### ❌ Don't: Forget to Track Focus\n\n```rust\n// ❌ Bad: No track_focus, keyboard navigation won't work\ndiv()\n    .on_action(cx.listener(Self::on_enter))\n```\n\n","skills/gpui-kit/references/gpui/global.md":"# Global State\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Use Cases](#common-use-cases) · [Best Practices](#best-practices) · [When to Use](#when-to-use)\n\n## Overview\n\nGlobal state in GPUI provides app-wide shared data accessible from any context.\n\n**Key Trait**: `Global` - Implement on types to make them globally accessible\n\n## Quick Start\n\n### Define Global State\n\n```rust\nuse gpui_kit::Global;\n\n#[derive(Clone)]\nstruct AppSettings {\n    theme: Theme,\n    language: String,\n}\n\nimpl Global for AppSettings {}\n```\n\n### Set and Access Globals\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx: &mut App| {\n        // Set global\n        cx.set_global(AppSettings {\n            theme: Theme::Dark,\n            language: \"en\".to_string(),\n        });\n\n        // Access global (read-only)\n        let settings = cx.global::<AppSettings>();\n        println!(\"Theme: {:?}\", settings.theme);\n    });\n}\n```\n\n### Update Globals\n\n```rust\nimpl MyComponent {\n    fn change_theme(&mut self, new_theme: Theme, cx: &mut Context<Self>) {\n        cx.update_global::<AppSettings, _>(|settings, cx| {\n            settings.theme = new_theme;\n            // Global updates don't trigger automatic notifications\n            // Manually notify components that care\n        });\n\n        cx.notify(); // Re-render this component\n    }\n}\n```\n\n## Common Use Cases\n\n### 1. App Configuration\n\n```rust\n#[derive(Clone)]\nstruct AppConfig {\n    api_endpoint: String,\n    max_retries: u32,\n    timeout: Duration,\n}\n\nimpl Global for AppConfig {}\n\n// Set once at startup\ncx.set_global(AppConfig {\n    api_endpoint: \"https://api.example.com\".to_string(),\n    max_retries: 3,\n    timeout: Duration::from_secs(30),\n});\n\n// Access anywhere\nlet config = cx.global::<AppConfig>();\n```\n\n### 2. Feature Flags\n\n```rust\n#[derive(Clone)]\nstruct FeatureFlags {\n    enable_beta_features: bool,\n    enable_analytics: bool,\n}\n\nimpl Global for FeatureFlags {}\n\nimpl MyComponent {\n    fn render_beta_feature(&self, cx: &App) -> Option<impl IntoElement> {\n        let flags = cx.global::<FeatureFlags>();\n\n        if flags.enable_beta_features {\n            Some(div().child(\"Beta feature\"))\n        } else {\n            None\n        }\n    }\n}\n```\n\n### 3. Shared Services\n\n```rust\n#[derive(Clone)]\nstruct ServiceRegistry {\n    http_client: Arc<HttpClient>,\n    logger: Arc<Logger>,\n}\n\nimpl Global for ServiceRegistry {}\n\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let registry = cx.global::<ServiceRegistry>();\n        let client = registry.http_client.clone();\n\n        cx.spawn(async move |cx| {\n            let data = client.get(\"api/data\").await?;\n            // Process data...\n            Ok::<_, anyhow::Error>(())\n        }).detach();\n    }\n}\n```\n\n## Best Practices\n\n### ✅ Use Arc for Shared Resources\n\n```rust\n#[derive(Clone)]\nstruct GlobalState {\n    database: Arc<Database>,  // Cheap to clone\n    cache: Arc<RwLock<Cache>>,\n}\n\nimpl Global for GlobalState {}\n```\n\n### ✅ Immutable by Default\n\nGlobals are read-only by default. Use interior mutability when needed:\n\n```rust\n#[derive(Clone)]\nstruct Counter {\n    count: Arc<AtomicUsize>,\n}\n\nimpl Global for Counter {}\n\nimpl Counter {\n    fn increment(&self) {\n        self.count.fetch_add(1, Ordering::SeqCst);\n    }\n\n    fn get(&self) -> usize {\n        self.count.load(Ordering::SeqCst)\n    }\n}\n```\n\n### ❌ Don't: Overuse Globals\n\n```rust\n// ❌ Bad: Too many globals\ncx.set_global(UserState { ... });\ncx.set_global(CartState { ... });\ncx.set_global(CheckoutState { ... });\n\n// ✅ Good: Use entities for component state\nlet user_entity = cx.new(|_| UserState { ... });\n```\n\n## When to Use\n\n**Use Globals for:**\n- App-wide configuration\n- Feature flags\n- Shared services (HTTP client, logger)\n- Read-only reference data\n\n**Use Entities for:**\n- Component-specific state\n- State that changes frequently\n- State that needs notifications\n\n","skills/gpui-kit/references/gpui/layout-style.md":"# Layout & Styling\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Patterns](#common-patterns) · [Styling Methods](#styling-methods) · [h_flex / v_flex](#h_flex--v_flex-helpers) · [Tailwind Shorthands](#tailwind-style-shorthand) · [Overflow & Scroll](#overflow-and-scroll) · [Absolute Positioning](#absolute-positioning) · [Stacking Order](#stacking-order) · [Theme Integration](#theme-integration) · [Conditional Styling](#conditional-styling) · [Text Styling](#text-styling)\n\n## Overview\n\nGPUI provides CSS-like styling with Rust type safety.\n\n**Key Concepts:**\n\n- Flexbox layout system\n- Styled trait for chaining styles\n- Size units: `px()`, `rems()`, `relative()`\n- Colors, borders, shadows\n\n## Quick Start\n\n### Basic Styling\n\n```rust\nuse gpui_kit::*;\n\ndiv()\n    .w(px(200.))\n    .h(px(100.))\n    .bg(rgb(0x2196F3))\n    .text_color(rgb(0xFFFFFF))\n    .rounded(px(8.))\n    .p(px(16.))\n    .child(\"Styled content\")\n```\n\n### Flexbox Layout\n\n```rust\ndiv()\n    .flex()\n    .flex_row()  // or flex_col() for column\n    .gap(px(8.))\n    .items_center()\n    .justify_between()\n    .children([\n        div().child(\"Item 1\"),\n        div().child(\"Item 2\"),\n        div().child(\"Item 3\"),\n    ])\n```\n\n### Size Units\n\n```rust\ndiv()\n    .w(px(200.))           // Pixels\n    .h(rems(10.))          // Relative to font size\n    .w(relative(0.5))      // 50% of parent\n    .min_w(px(100.))\n    .max_w(px(400.))\n```\n\n## Common Patterns\n\n### Centered Content\n\n```rust\ndiv()\n    .flex()\n    .items_center()\n    .justify_center()\n    .size_full()\n    .child(\"Centered\")\n```\n\n### Card Layout\n\n```rust\ndiv()\n    .w(px(300.))\n    .bg(cx.theme().surface)\n    .rounded(px(8.))\n    .shadow_md()\n    .p(px(16.))\n    .gap(px(12.))\n    .flex()\n    .flex_col()\n    .child(heading())\n    .child(content())\n```\n\n### Responsive Spacing\n\n```rust\ndiv()\n    .p(px(16.))           // Padding all sides\n    .px(px(20.))          // Padding horizontal\n    .py(px(12.))          // Padding vertical\n    .pt(px(8.))           // Padding top\n    .gap(px(8.))          // Gap between children\n```\n\n## Styling Methods\n\n### Dimensions\n\n```rust\n.w(px(200.))              // Width\n.h(px(100.))              // Height\n.size(px(200.))           // Width and height\n.min_w(px(100.))          // Min width\n.max_w(px(400.))          // Max width\n```\n\n### Colors\n\n```rust\n.bg(rgb(0x2196F3))        // Background\n.text_color(rgb(0xFFFFFF)) // Text color\n.border_color(rgb(0x000000)) // Border color\n```\n\n### Borders\n\n```rust\n.border(px(1.))           // Border width\n.rounded(px(8.))          // Border radius\n.rounded_t(px(8.))        // Top corners\n.border_color(rgb(0x000000))\n```\n\n### Spacing\n\n```rust\n.p(px(16.))               // Padding\n.m(px(8.))                // Margin\n.gap(px(8.))              // Gap between flex children\n```\n\n### Flexbox\n\n```rust\n.flex()                   // Enable flexbox\n.flex_row()               // Row direction\n.flex_col()               // Column direction\n.items_center()           // Align items center\n.justify_between()        // Space between items\n.flex_grow_1()              // Grow to fill space\n```\n\n## h_flex / v_flex Helpers\n\n`gpui_kit::component` provides shorthand helpers (import from `gpui_kit::component`):\n\n```rust\nuse gpui_kit::component::{h_flex, v_flex};\n\n// h_flex() = div().flex().flex_row().items_center()\nh_flex()\n    .gap_2()\n    .child(icon)\n    .child(label)\n\n// v_flex() = div().flex().flex_col()\nv_flex()\n    .gap_4()\n    .p_4()\n    .child(input1)\n    .child(input2)\n    .child(submit_btn)\n```\n\nThese are the standard layout primitives in `gpui_kit::component`. Prefer them over raw `div().flex()`.\n\n## Tailwind-style Shorthand\n\nGPUI provides Tailwind-style spacing/sizing shorthands:\n\n```rust\n// Spacing (0=0, 1=4px, 2=8px, 3=12px, 4=16px, ...)\n.p_2()    // padding: 8px\n.px_4()   // padding x: 16px\n.py_3()   // padding y: 12px\n.m_2()    // margin: 8px\n.gap_3()  // gap: 12px\n\n// Size\n.size_full()   // width: 100%, height: 100%\n.size_4()      // width: 16px, height: 16px\n.w_full()      // width: 100%\n.h_full()      // height: 100%\n.flex_1()      // flex: 1 1 0 (fill remaining space)\n.flex_shrink_0() // prevent shrinking\n```\n\n## Overflow and Scroll\n\n```rust\ndiv()\n    .overflow_hidden()          // clip content\n    .overflow_x_hidden()        // clip horizontal\n    .overflow_y_scrollbar()     // show scrollbar on y axis\n    .overflow_scroll()          // scroll both axes\n```\n\n## Absolute Positioning\n\n```rust\ndiv()\n    .relative()                 // position: relative (container)\n    .child(\n        div()\n            .absolute()         // position: absolute\n            .top_0()\n            .right_0()\n            .child(\"badge\")\n    )\n\n// Inset helpers\ndiv().absolute().inset_0()      // top/right/bottom/left: 0 (fill parent)\ndiv().absolute().top(px(8.)).left(px(8.))\n```\n\n## Stacking Order\n\n```rust\ndiv()\n    .relative()\n    .child(content)\n    .child(\n        div()\n            .absolute()\n            .top_0()\n            .right_0()\n            .child(\"badge\")\n    ) // later children are typically painted above earlier siblings\n```\n\nGPUI's general `Styled` API does **not** provide a `z_index(...)` method.\n\nFor normal elements, stacking is usually controlled by:\n\n- Parent/child composition\n- Absolute positioning\n- Render order of siblings (later siblings paint above earlier ones)\n\nIf you see a `z_index(...)` method in this repository, make sure it belongs to the specific component you are using: a component's own ordering API is not a general GPUI `Div` styling method.\n\n## Theme Integration\n\n```rust\ndiv()\n    .bg(cx.theme().surface)\n    .text_color(cx.theme().foreground)\n    .border_color(cx.theme().border)\n    .when(is_hovered, |el| {\n        el.bg(cx.theme().hover)\n    })\n```\n\n## Conditional Styling\n\n```rust\nuse gpui_kit::prelude::FluentBuilder as _;\n\ndiv()\n    .when(is_active, |el| el.bg(cx.theme().primary))\n    .when(!is_active, |el| el.opacity(0.5))\n    .when_some(optional_color.as_ref(), |el, color| el.bg(*color))\n```\n\n## Text Styling\n\n```rust\ndiv()\n    .text_sm()          // font-size: small\n    .text_base()        // font-size: base\n    .text_lg()          // font-size: large\n    .font_bold()        // font-weight: bold\n    .line_height_snug() // tighter line height\n    .truncate()         // overflow: ellipsis, single line\n    .whitespace_nowrap()\n```\n","skills/gpui-kit/references/gpui/test-examples.md":"# Test Examples\n\n**Contents:** [Testing Best Practices](#testing-best-practices) · [Test Organization](#test-organization) · [Setup and Teardown](#setup-and-teardown) · [Assertions](#assertions) · [Performance Testing](#performance-testing) · [Running Tests](#running-tests) · [Basic Test Execution](#basic-test-execution) · [Test Configuration](#test-configuration) · [Advanced Test Execution](#advanced-test-execution) · [CI/CD Integration](#cicd-integration)\n\n## Testing Best Practices\n\n### Test Organization\n\nGroup related tests in modules:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    mod entity_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        fn test_creation() { /* ... */ }\n\n        #[gpui_kit::test]\n        fn test_updates() { /* ... */ }\n    }\n\n    mod async_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        async fn test_async_ops() { /* ... */ }\n    }\n\n    mod distributed_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        fn test_multi_app() { /* ... */ }\n    }\n}\n```\n\n### Setup and Teardown\n\nUse helper functions for common setup:\n\n```rust\nfn create_test_counter(cx: &mut TestAppContext) -> Entity<Counter> {\n    cx.new(|cx| Counter::new(cx))\n}\n\n#[gpui_kit::test]\nfn test_counter_operations(cx: &mut TestAppContext) {\n    let counter = create_test_counter(cx);\n\n    // Test operations\n}\n```\n\n### Assertions\n\nUse descriptive assertions:\n\n```rust\n#[gpui_kit::test]\nfn test_counter_bounds(cx: &mut TestAppContext) {\n    let counter = create_test_counter(cx);\n\n    // Test upper bound\n    for _ in 0..100 {\n        counter.update(cx, |counter, cx| {\n            counter.increment(cx);\n        });\n    }\n\n    let count = counter.read_with(cx, |counter, _| counter.count);\n    assert!(count <= 100, \"Counter should not exceed maximum\");\n\n    // Test lower bound\n    for _ in 0..200 {\n        counter.update(cx, |counter, cx| {\n            counter.decrement(cx);\n        });\n    }\n\n    let count = counter.read_with(cx, |counter, _| counter.count);\n    assert!(count >= 0, \"Counter should not go below minimum\");\n}\n```\n\n### Performance Testing\n\nTest performance characteristics:\n\n```rust\n#[gpui_kit::test]\nfn test_operation_performance(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    let start = std::time::Instant::now();\n\n    // Perform many operations\n    for i in 0..1000 {\n        component.update(cx, |comp, cx| {\n            comp.perform_operation(i, cx);\n        });\n    }\n\n    let elapsed = start.elapsed();\n    assert!(elapsed < Duration::from_millis(100), \"Operations should complete quickly\");\n}\n```\n\n## Running Tests\n\n### Basic Test Execution\n\n```bash\n# Run all tests\ncargo test\n\n# Run specific test\ncargo test test_counter_operations\n\n# Run tests in a specific module\ncargo test entity_tests::\n\n# Run with output\ncargo test -- --nocapture\n```\n\n### Test Configuration\n\nEnable test-support feature for GPUI tests:\n\n```toml\n[features]\ntest-support = [\"gpui/test-support\"]\n```\n\n```bash\ncargo test --features test-support\n```\n\n### Advanced Test Execution\n\n```bash\n# Run tests with iterations for property testing\ncargo test -- --test-threads=1\n\n# Run tests matching a pattern\ncargo test test_async\n\n# Run tests with backtrace on failure\nRUST_BACKTRACE=1 cargo test\n```\n\n### CI/CD Integration\n\nFor continuous integration:\n\n```yaml\n# .github/workflows/test.yml\nname: Tests\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: dtolnay/rust-toolchain@stable\n      - name: Run tests\n        run: cargo test --features test-support\n```\n\nGPUI's testing framework provides deterministic, fast, and comprehensive testing capabilities that mirror real application behavior while providing the control needed for thorough testing of complex UI and async scenarios.","skills/gpui-kit/references/gpui/test-reference.md":"# Test Reference\n\n**Contents:** [Testing Patterns](#testing-patterns) · [Testing Crash-Free State Management (Re-entrancy)](#testing-crash-free-state-management-re-entrancy) · [Property Testing](#property-testing) · [Distributed Systems Testing](#distributed-systems-testing) · [Mocking and Isolation](#mocking-and-isolation)\n\n## Testing Patterns\n\n### Basic Entity Testing\n\nTest entity creation, updates, and reads:\n\n```rust\n#[gpui_kit::test]\nfn test_counter_entity(cx: &mut TestAppContext) {\n    let counter = cx.new(|cx| Counter::new(cx));\n\n    // Test initial state\n    let initial_count = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(initial_count, 0);\n\n    // Test updates\n    counter.update(cx, |counter, cx| {\n        counter.count = 42;\n        cx.notify();\n    });\n\n    let updated_count = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(updated_count, 42);\n}\n```\n\n### Event Testing\n\nTest event emission and handling:\n\n```rust\n#[derive(Clone)]\nstruct ValueChanged {\n    new_value: i32,\n}\n\nimpl EventEmitter<ValueChanged> for MyComponent {}\n\n#[gpui_kit::test]\nfn test_event_emission(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| {\n        let mut comp = MyComponent::default();\n\n        // Subscribe to self\n        cx.subscribe_self(|this, event: &ValueChanged, cx| {\n            this.received_value = event.new_value;\n            cx.notify();\n        });\n\n        comp\n    });\n\n    // Emit event\n    component.update(cx, |_, cx| {\n        cx.emit(ValueChanged { new_value: 123 });\n    });\n\n    // Verify event was handled\n    let received = component.read_with(cx, |comp, _| comp.received_value);\n    assert_eq!(received, 123);\n}\n```\n\n### Action Testing\n\nTest action dispatching and handling:\n\n```rust\nactions!(my_app, [Increment, Decrement]);\n\n#[gpui_kit::test]\nfn test_action_dispatch(cx: &mut TestAppContext) {\n    let window = cx.update(|cx| {\n        cx.open_window(Default::default(), |_, cx| {\n            cx.new(|cx| MyComponent::new(cx))\n        }).unwrap()\n    });\n\n    let mut cx = VisualTestContext::from_window(window.into(), cx);\n    let counter = window.root(&mut cx).unwrap();\n\n    // Dispatch action via focus handle\n    let focus_handle = counter.read_with(&cx, |counter, _| counter.focus_handle.clone());\n    cx.update(|window, cx| {\n        focus_handle.dispatch_action(&Increment, window, cx);\n    });\n\n    let count = counter.read_with(&cx, |counter, _| counter.count);\n    assert_eq!(count, 1);\n}\n```\n\n### Async Testing\n\nTest async operations and background tasks:\n\n```rust\nimpl MyComponent {\n    fn load_data(&self, cx: &mut Context<Self>) -> Task<i32> {\n        cx.spawn(async move |this, cx| {\n            // Simulate async work\n            this.update(cx, |comp, _| comp.loading = true).await;\n            // Return result\n            42\n        })\n    }\n\n    fn background_update(&self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            // Background work\n            this.update(cx, |comp, _| {\n                comp.value += 10;\n            }).await;\n        }).detach();\n    }\n}\n\n#[gpui_kit::test]\nasync fn test_async_operations(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    // Test awaited task\n    let result = component.update(cx, |comp, cx| comp.load_data(cx)).await;\n    assert_eq!(result, 42);\n\n    // Test detached task\n    component.update(cx, |comp, cx| comp.background_update(cx));\n\n    // Detached tasks don't run until you yield\n    let value_before = component.read_with(cx, |comp, _| comp.value);\n    assert_eq!(value_before, 0);\n\n    // Run pending tasks\n    cx.run_until_parked();\n\n    let value_after = component.read_with(cx, |comp, _| comp.value);\n    assert_eq!(value_after, 10);\n}\n```\n\n### Timer Testing\n\nTest timer-based operations:\n\n```rust\nimpl MyComponent {\n    fn delayed_action(&self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            cx.background_executor()\n                .timer(Duration::from_millis(100))\n                .await;\n\n            this.update(cx, |comp, cx| {\n                comp.action_performed = true;\n                cx.notify();\n            }).await;\n        }).detach();\n    }\n}\n\n#[gpui_kit::test]\nasync fn test_timers(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    component.update(cx, |comp, cx| comp.delayed_action(cx));\n\n    // Action shouldn't have completed yet\n    let performed = component.read_with(cx, |comp, _| comp.action_performed);\n    assert!(!performed);\n\n    // Run until parked (timers complete)\n    cx.run_until_parked();\n\n    let performed = component.read_with(cx, |comp, _| comp.action_performed);\n    assert!(performed);\n}\n```\n\n### External I/O Testing\n\nFor tests involving external systems, use `allow_parking()`:\n\n```rust\n#[gpui_kit::test]\nasync fn test_external_io(cx: &mut TestAppContext) {\n    // Allow parking for external I/O\n    cx.executor().allow_parking();\n\n    // Simulate external operation\n    let (tx, rx) = futures::channel::oneshot::channel();\n    std::thread::spawn(move || {\n        std::thread::sleep(Duration::from_millis(10));\n        tx.send(42).ok();\n    });\n\n    let result = rx.await.unwrap();\n    assert_eq!(result, 42);\n}\n```\n\n## Testing Crash-Free State Management (Re-entrancy)\n\nThe most dangerous class of GPUI bugs is **entity re-entrancy**: code that tries to update or read an entity while it is already locked in a render/update pass. These bugs are invisible at compile time — they only panic at runtime, typically when the user clicks something in a list or dropdown.\n\n**Key properties of re-entrancy panics:**\n- Triggered by user interaction (click, key press), not during static rendering.\n- `#[should_panic]` only confirms the bug exists — tests must pass *without* panicking.\n- `Select` commits through `defer_in` after the key or click dispatch returns. Wait for the result with `cx.wait_for` instead of asserting straight after the interaction.\n\nDrive the component the way a user does. `SelectState` keeps its list state `pub(crate)`, so a test outside `gpui-component` opens the menu, presses keys, and observes through `selected_value()`, the element snapshot, and the delegate's own hooks.\n\n### Pattern: Confirm through the real UI\n\n```rust\nuse gpui_kit::test::{TestAppContextExt, TestWindowExt};\nuse gpui_kit::{\n    AnyWindowHandle, AppContext, Bounds, Context, Entity, TestAppContext, Window, WindowBounds,\n    WindowOptions,\n    component::{\n        IndexPath,\n        searchable_list::SearchableListChange,\n        select::{SearchableVec, Select, SelectDelegate, SelectItem, SelectState},\n    },\n    div,\n    prelude::*,\n    px, size,\n};\nuse std::{cell::RefCell, rc::Rc, time::Duration};\n\nstruct Form {\n    language: Entity<SelectState<SearchableVec<&'static str>>>,\n}\n\nimpl Render for Form {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .size_full()\n            .child(Select::new(&self.language).id(\"language\").w(px(240.)))\n    }\n}\n\n#[gpui_kit::test]\nasync fn confirming_from_the_keyboard_commits_the_value(cx: &mut TestAppContext) {\n    cx.update(gpui_kit::init);\n    let mut language = None;\n    let (handle, _view) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let state = cx.new(|cx| {\n                    SelectState::new(\n                        SearchableVec::new(vec![\"Rust\", \"Go\"]),\n                        Some(IndexPath::new(0)),\n                        window,\n                        cx,\n                    )\n                });\n                language = Some(state.clone());\n                let view = cx.new(|_| Form { language: state });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n    let language = language.unwrap();\n\n    // Open the menu, move to \"Go\" and confirm — the same path a user takes.\n    cx.update_window(handle.into(), |_, window, cx| {\n        window.render_frame(cx);\n        window.within(\"language\").click(\"input\", cx);\n        window.press(\"down\", cx);\n        window.press(\"enter\", cx);\n    })\n    .unwrap();\n\n    // Select commits through `defer_in` after the key dispatch returns, so\n    // wait for the closed menu instead of asserting straight away.\n    cx.wait_for(handle.into(), Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n            && window.find(\"language\").value() == Some(\"Go\")\n    })\n    .await;\n\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Go\")));\n}\n```\n\n### Pattern: Record `on_will_change` and `on_confirm`\n\nA recording delegate shows which changes the selection strategy proposed and what was committed. `on_will_change` receives the proposed changes and the selection to edit; the delegate applies them itself (the trait's default applies all of them). It has no `cx`, because it runs while the list entity is borrowed, so put side effects that need `cx` in `on_confirm`.\n\n```rust\ntype Log = Rc<RefCell<Vec<String>>>;\n\n/// Records each hook call; `accept: false` vetoes every change.\nstruct Recording {\n    items: Vec<&'static str>,\n    accept: bool,\n    log: Log,\n}\n\nimpl SelectDelegate for Recording {\n    type Item = &'static str;\n\n    fn items_count(&self, _: usize) -> usize {\n        self.items.len()\n    }\n\n    fn item(&self, ix: IndexPath) -> Option<&Self::Item> {\n        self.items.get(ix.row)\n    }\n\n    fn position<V>(&self, value: &V) -> Option<IndexPath>\n    where\n        Self::Item: SelectItem<Value = V>,\n        V: PartialEq,\n    {\n        self.items\n            .iter()\n            .position(|item| item.value() == value)\n            .map(IndexPath::new)\n    }\n\n    fn on_will_change(\n        &mut self,\n        selection: &mut Vec<(IndexPath, Self::Item)>,\n        changes: &[SearchableListChange],\n    ) {\n        for change in changes {\n            match *change {\n                SearchableListChange::Select { index } => {\n                    self.log.borrow_mut().push(format!(\"select {}\", index.row));\n                    if self.accept\n                        && let Some(item) = self.item(index)\n                    {\n                        selection.push((index, *item));\n                    }\n                }\n                SearchableListChange::Deselect { index } => {\n                    self.log\n                        .borrow_mut()\n                        .push(format!(\"deselect {}\", index.row));\n                    if self.accept {\n                        selection.retain(|(ix, _)| *ix != index);\n                    }\n                }\n            }\n        }\n    }\n\n    fn on_confirm(&mut self, final_selection: &[(IndexPath, Self::Item)]) {\n        let values: Vec<_> = final_selection.iter().map(|(_, item)| *item).collect();\n        self.log.borrow_mut().push(format!(\"confirm {values:?}\"));\n    }\n}\n\nstruct Picker {\n    language: Entity<SelectState<Recording>>,\n}\n\nimpl Render for Picker {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .size_full()\n            .child(Select::new(&self.language).id(\"language\").w(px(240.)))\n    }\n}\n\nfn open_picker(\n    cx: &mut TestAppContext,\n    accept: bool,\n) -> (AnyWindowHandle, Entity<SelectState<Recording>>, Log) {\n    cx.update(gpui_kit::init);\n    let log = Rc::new(RefCell::new(Vec::new()));\n    let mut language = None;\n    let (handle, _view) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let delegate = Recording {\n                    items: vec![\"Rust\", \"Go\"],\n                    accept,\n                    log: log.clone(),\n                };\n                let state =\n                    cx.new(|cx| SelectState::new(delegate, Some(IndexPath::new(0)), window, cx));\n                language = Some(state.clone());\n                let view = cx.new(|_| Picker { language: state });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n    (handle.into(), language.unwrap(), log)\n}\n\nfn confirm_next(cx: &mut TestAppContext, handle: AnyWindowHandle) {\n    cx.update_window(handle, |_, window, cx| {\n        window.render_frame(cx);\n        window.within(\"language\").click(\"input\", cx);\n        window.press(\"down\", cx);\n        window.press(\"enter\", cx);\n    })\n    .unwrap();\n}\n\n#[gpui_kit::test]\nasync fn hooks_fire_in_order_with_the_final_selection(cx: &mut TestAppContext) {\n    let (handle, language, log) = open_picker(cx, true);\n    confirm_next(cx, handle);\n    cx.wait_for(handle, Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n    })\n    .await;\n    // Single selection proposes replacing the old item, then commits once.\n    assert_eq!(\n        *log.borrow(),\n        [\"deselect 0\", \"select 1\", r#\"confirm [\"Go\"]\"#]\n    );\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Go\")));\n}\n```\n\n### Pattern: A vetoing delegate keeps the selection\n\nThe same delegate with `accept: false` applies none of the proposed changes:\n\n```rust\n#[gpui_kit::test]\nasync fn a_vetoing_delegate_keeps_the_selection(cx: &mut TestAppContext) {\n    let (handle, language, log) = open_picker(cx, false);\n    confirm_next(cx, handle);\n    cx.wait_for(handle, Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n    })\n    .await;\n    // The same changes are proposed, but the delegate applied none of them:\n    // `on_confirm` still runs, with the selection the user started from.\n    assert_eq!(*log.borrow(), [\"deselect 0\", \"select 1\", r#\"confirm [\"Rust\"]\"#]);\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Rust\")));\n    cx.update_window(handle, |_, window, _| {\n        assert_eq!(window.find(\"language\").value(), Some(\"Rust\"));\n    })\n    .unwrap();\n}\n```\n\n### Checklist: What to test for each component that uses `defer_in`\n\n- [ ] `confirm` path: no panic, the value is committed, and `selected_value()` agrees with the trigger's `value()`\n- [ ] `cancel` path (Escape, click outside): no panic, selection unchanged, menu closed (`expanded() == Some(false)`)\n- [ ] `on_will_change` veto: selection unchanged; `on_confirm` still runs, with the unchanged selection\n- [ ] `on_will_change` editing the selection: the final selection reflects the delegate's edit\n- [ ] Repeated confirms: each one leaves `selected_value()` matching the displayed value\n- [ ] `render_item` never panics even when called immediately after a mutation\n\n## Property Testing\n\nUse random data to test edge cases:\n\n```rust\n#[gpui_kit::test(iterations = 10)]\nfn test_counter_random_operations(cx: &mut TestAppContext, mut rng: StdRng) {\n    let counter = cx.new(|cx| Counter::new(cx));\n\n    let mut expected = 0i32;\n    for _ in 0..100 {\n        let delta = rng.random_range(-10..=10);\n        expected += delta;\n\n        counter.update(cx, |counter, cx| {\n            counter.count += delta;\n            cx.notify();\n        });\n    }\n\n    let actual = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(actual, expected);\n}\n```\n\n## Distributed Systems Testing\n\nTest multiple app contexts communicating:\n\n```rust\n#[derive(Clone)]\nstruct NetworkMessage {\n    from: String,\n    to: String,\n    data: i32,\n}\n\n#[gpui_kit::test]\nfn test_distributed_apps(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {\n    // Create components in different app contexts\n    let comp_a = cx_a.new(|_| MyComponent::new(\"A\".to_string()));\n    let comp_b = cx_b.new(|_| MyComponent::new(\"B\".to_string()));\n\n    // Simulate message passing\n    comp_a.update(cx_a, |comp, cx| {\n        comp.send_message(\"B\", 42, cx);\n    });\n\n    // Run async operations\n    cx_a.run_until_parked();\n\n    // Verify message received in other context\n    comp_b.update(cx_b, |comp, _| {\n        comp.receive_messages();\n    });\n\n    let messages = comp_b.read_with(cx_b, |comp, _| comp.messages.clone());\n    assert_eq!(messages.len(), 1);\n    assert_eq!(messages[0].data, 42);\n}\n```\n\n### Interleaving Testing\n\nTest concurrent operations with random execution order:\n\n```rust\n#[gpui_kit::test(iterations = 10)]\nfn test_concurrent_operations(\n    cx_a: &mut TestAppContext,\n    cx_b: &mut TestAppContext,\n    mut rng: StdRng,\n) {\n    let comp_a = cx_a.new(|_| MyComponent::new());\n    let comp_b = cx_b.new(|_| MyComponent::new());\n\n    // Perform random operations across contexts\n    for i in 0..20 {\n        if rng.random_bool(0.5) {\n            comp_a.update(cx_a, |comp, cx| {\n                comp.perform_operation(i, cx);\n            });\n        } else {\n            comp_b.update(cx_b, |comp, cx| {\n                comp.perform_operation(i, cx);\n            });\n        }\n    }\n\n    // Run all pending operations\n    cx_a.run_until_parked();\n\n    // Verify final state\n    let state_a = comp_a.read_with(cx_a, |comp, _| comp.state);\n    let state_b = comp_b.read_with(cx_b, |comp, _| comp.state);\n\n    // Assert invariants hold despite execution order\n    assert!(state_a.is_consistent());\n    assert!(state_b.is_consistent());\n}\n```\n\n## Mocking and Isolation\n\n### Network Mocking\n\nCreate mock networks for testing distributed features:\n\n```rust\nstruct MockNetwork {\n    messages: Arc<Mutex<Vec<NetworkMessage>>>,\n}\n\nimpl MockNetwork {\n    fn new() -> Self {\n        Self {\n            messages: Arc::new(Mutex::new(Vec::new())),\n        }\n    }\n\n    fn send(&self, message: NetworkMessage) {\n        self.messages.lock().unwrap().push(message);\n    }\n\n    fn receive_all(&self) -> Vec<NetworkMessage> {\n        self.messages.lock().unwrap().drain(..).collect()\n    }\n}\n\n#[gpui_kit::test]\nfn test_networked_components(cx: &mut TestAppContext) {\n    let network = Arc::new(MockNetwork::new());\n\n    let sender = cx.new(|_| MessageSender::new(network.clone()));\n    let receiver = cx.new(|_| MessageReceiver::new(network));\n\n    // Send message\n    sender.update(cx, |sender, _| {\n        sender.send(\"Hello\");\n    });\n\n    // Receive message\n    receiver.update(cx, |receiver, _| {\n        receiver.receive_all();\n    });\n\n    let received = receiver.read_with(cx, |receiver, _| receiver.messages.clone());\n    assert_eq!(received, vec![\"Hello\"]);\n}\n```","skills/gpui-kit/references/gpui/test.md":"# Testing\n\n**Contents:** [Choose the test level](#choose-the-test-level) · [UI integration workflow](#ui-integration-workflow) · [Complete example](#complete-example) · [Queries and interactions](#queries-and-interactions) · [Frames and async work](#frames-and-async-work) · [Assertion boundaries](#assertion-boundaries) · [Additional resources](#additional-resources)\n\n## UI integration testing\n\nA UI integration test renders real components in a headless window, dispatches\nclicks, keyboard input and scrolling, then checks state, focus, layout and owner\ncallbacks. For example: add a Checkbox UI integration test that proves clicking\ntoggles the owner's value and disabled controls reject the interaction.\nUse this term when describing component interaction coverage.\n`#[gpui_kit::test]` runs the test; `gpui_kit::test` operates and inspects its UI.\n\n## Choose the test level\n\nUse ordinary Rust `#[test]` for pure logic. Use `#[gpui_kit::test]` and\n`TestAppContext` for entities, subscriptions, actions and async tasks; it can\ncreate headless windows too. `VisualTestContext` is available for existing GPUI\nwindow helpers. For an application UI flow, use `gpui_kit::test::TestWindowExt`\non the real `Window` and assert the behavior produced by native events.\n\nImport the Kit types you use explicitly and write `#[gpui_kit::test]`. Avoid `use gpui_kit::*;` in test modules: it imports GPUI’s `test` macro and can shadow Rust’s built-in `#[test]`. Add\n`test-support` to the application's `gpui-kit` development dependency, using\nexactly the same source and version as its normal dependency. The helpers\nrequire a Kit revision that includes them; check the installed API before\nassuming an older published release supports them. No extra testing crate or\nGPUI patch is required.\n\nFor a standalone test package beside a Kit checkout:\n\n```toml\n[package]\nname = \"ui-tests\"\nversion = \"0.1.0\"\nedition = \"2024\"\npublish = false\n\n[dev-dependencies]\ngpui-kit = { path = \"../gpui-kit/crates/kit\", features = [\"test-support\"] }\n```\n\nHeadless tests still need the platform's native build dependencies. Run\n`cargo generate-lockfile` once for the new package, then\n`cargo test --test ui --locked`. In the Kit repository the equivalent command\nis `cargo test -p gpui-kit --features test-support --test ui --locked`.\n\n## UI integration workflow\n\n1. Import the production view and constructor from the application library.\n   Keep state entities and subscriptions owned by that view. Define a view\n   inside a test only for a self-contained example or a deliberate fixture.\n2. Initialize with `cx.update(gpui_kit::init)`, open a headless window of an\n   explicit size through `gpui_kit::open_window`. Its Base `Root` renders\n   the dialog, sheet and notification layers above the view automatically.\n   Do not mount overlay layers in the application view.\n3. Render a frame and locate existing control IDs. Custom native elements opt\n   in with `.id(\"status\").test_support()` through `TestSupportExt`. Place it\n   before `.track_focus(&handle)`; custom wrappers must forward that method\n   to their inner element. Registration adds no layout container.\n4. Dispatch clicks, input and named keys through `TestWindowExt`. Exercise the\n   actual handler path; invoking callbacks or directly setting control state\n   would bypass the behavior being tested.\n5. Assert the initial state, the visible outcome after each meaningful action,\n   and the application result. Include a relevant negative case, such as a\n   disabled control rejecting the interaction or invalid input preventing save.\n6. Run the affected test target and report its result. An uncompiled example or\n   a test which never checks the action's outcome is not completion evidence.\n\n## Complete example\n\nCopy this into `tests/ui.rs`. It follows the Kit integration-test example\nfrom `crates/kit/tests/ui.rs`, with window setup inlined so this reference works\nwithout a repository checkout. In an application, replace that view definition\nwith an import of your production view.\n\n```rust\nuse gpui_kit::test::{TestSupportExt, TestWindowExt};\nuse gpui_kit::{\n    AppContext, Bounds, Context, Entity, SharedString, TestAppContext, Window, WindowBounds,\n    WindowOptions,\n    component::{\n        button::Button,\n        input::{Input, InputState},\n    },\n    div,\n    prelude::*,\n    px, size,\n};\n\nstruct Profile {\n    name: Entity<InputState>,\n    submitted: Option<SharedString>,\n}\n\nimpl Render for Profile {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let status = self.submitted.as_ref().map_or_else(\n            || SharedString::from(\"Not saved\"),\n            |name| SharedString::from(format!(\"Saved: {name}\")),\n        );\n        div()\n            .size_full()\n            .flex()\n            .flex_col()\n            .p_4()\n            .gap_4()\n            .child(Input::new(&self.name).id(\"name\").w(px(240.)))\n            .child(\n                Button::new(\"save\")\n                    .label(\"Save\")\n                    .on_click(cx.listener(|this, _, _, cx| {\n                        this.submitted = Some(this.name.read(cx).value());\n                        cx.notify();\n                    })),\n            )\n            .child(\n                div()\n                    .id(\"status\")\n                    .role(gpui_kit::Role::Status)\n                    .test_support()\n                    .aria_label(status.clone())\n                    .child(status),\n            )\n    }\n}\n\n#[gpui_kit::test]\nfn saves_a_profile_through_the_ui(cx: &mut TestAppContext) {\n    cx.update(gpui_kit::init);\n    let (handle, profile) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let view = cx.new(|cx| Profile {\n                    name: cx.new(|cx| InputState::new(window, cx)),\n                    submitted: None,\n                });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n\n    cx.update_window(handle.into(), |_, window, cx| {\n        window.render_frame(cx);\n        assert_eq!(window.find(\"status\").label(), Some(\"Not saved\"));\n\n        window.click(\"name\", cx);\n        window.input(\"Ada 中文\", cx);\n        let name = window.find(\"name\");\n        assert_eq!(name.focused(), Some(true));\n        assert_eq!(name.value(), Some(\"Ada 中文\"));\n        assert!(name.bounds().size.width > px(0.));\n        // Named keys share the same Window API and refresh the resulting frame.\n        window.press(\"backspace\", cx);\n        assert_eq!(window.find(\"name\").value(), Some(\"Ada 中\"));\n\n        window.click(\"save\", cx);\n        let status = window.find(\"status\");\n        assert!(status.visible());\n        assert_eq!(status.label(), Some(\"Saved: Ada 中\"));\n        assert!(status.bounds().top() >= window.find(\"save\").bounds().bottom());\n    })\n    .unwrap();\n\n    // Verify the application result as well as the native properties.\n    cx.update(|cx| {\n        assert_eq!(profile.read(cx).submitted.as_deref(), Some(\"Ada 中\"));\n    });\n}\n```\n\n## Queries and interactions\n\nImport `TestWindowExt` for queries and interactions from `gpui_kit::test`.\nFor custom registration, import `TestSupportExt`. Use normal Rust assertions with snapshots.\n\n| API | Behavior |\n| --- | --- |\n| `window.find(id)` | Requires a unique observed target; errors list registered paths. |\n| `window.try_find(id)` | Returns `None` when absent; ambiguous IDs still panic. |\n| `window.find_all(id)` | Returns all registered matches, including invisible ones, by current-frame bounds origin (y, then x); equal-origin order is unspecified. Empty when absent. |\n| `window.within(id)` | Resolves a native GPUI identity scope, including an unobserved ancestor. |\n| `click`, `right_click`, `double_click`, `hover` | Dispatch real pointer events at the target center. |\n| `click_at(id, offset, cx)` | Uses an offset from the target bounds' top-left corner. |\n| `window.click_with_modifiers(id, modifiers, cx)` | Centered left click with modifiers; sends modifier changes and restores the previous modifier state afterward. |\n| `window.click_with_options(id, options, cx)` | Combines offset, button, count, and modifiers using `ClickOptions`; restores the previous modifier state afterward. |\n| `scroll(id, delta, cx)` | Dispatches a GPUI `ScrollDelta` wheel event. |\n| `drag_to(from_id, to_id, cx)` | Drags between target centers within the current scope. |\n| `window.drag(from, to, cx)` | Drags between window-local points; use `bounds()` for precise or cross-scope geometry. |\n| `press(key, cx)` | Sends named GPUI keys such as `backspace`, `escape` or `secondary-a`. |\n| `input(text, cx)` | Types Unicode characters at current focus; click the input first. |\n\n`ClickOptions::new()` defaults to one left click at the center without modifiers.\nFor example, `ClickOptions::new().with_offset(point(px(8.), px(8.)))\n.with_button(MouseButton::Right).with_count(2).with_modifiers(Modifiers::shift())`\ncombines a local offset, right double-click, and Shift. Counts must be positive.\nConfigurable clicks preserve caps lock. `find_all` ordering is geometry for the\ncurrent frame, not stable identity, paint order, or business order; filter with\n`visible()` when counting visible matches.\n\nGPUI IDs need only be unique within their native scope. Use\n`window.within(\"dialog\").find(\"name\")` for repeated local IDs. Scoped windows\nalso provide pointer operations, `press` and `input`; keyboard helpers require\nobserved focus inside that scope and recheck it between characters. They do\nnot focus the target or replace its value. For a submenu with another\n`\"popup-menu\"` ID, retain the resolved outer scope before opening the submenu,\nthen query its descendants.\n\n## Inspect accessibility targets and individual events\n\nImport `gpui_kit::test::{TestQueryExt, TestEventExt}` for additional observation\nand event control. `elements()` returns observed elements in the current frame;\n`find_by_label(label)`, `try_find_by_label(label)` and `find_all_by_label(label)`\nmatch exact, case-sensitive native accessibility labels. `find_all_by_role(role)` selects an\nAccessKit `Role`. Results include invisible registrations, ordered by y, then x\nand a path tie-breaker. Required queries panic on absence; all unique queries\npanic on ambiguity. Scoped queries include strict descendants, excluding the\nscope node itself. These queries also work inside `within` and do not discover\nunobserved text or offscreen virtual rows. A label is an accessibility name,\nnot rendered text; use stable IDs when localization changes the name.\nThe pinned GPUI version does not expose an enumeration of anonymous rendered\ntext. Kit therefore has no general rendered-text `HasText` assertion; exact\naccessible-label queries cannot establish that text was actually drawn.\n\nFor gestures whose intermediate state matters, dispatch each step explicitly:\n\n```rust\nuse gpui_kit::test::TestEventExt;\n\nlet start = window.find(\"handle\").bounds().center();\nwindow.pointer_down(start, MouseButton::Left, cx);\nwindow.pointer_move(start + point(px(24.), px(0.)), Some(MouseButton::Left), cx);\n// Assert the state while the pointer is still held.\nwindow.pointer_up(start + point(px(24.), px(0.)), MouseButton::Left, cx);\n```\n\nPositions use window-local pixels. `pointer_move(position, pressed_button, cx)`\nreceives the held button explicitly; these helpers do not remember button state.\n`pointer_down` and `pointer_up` dispatch one click event each. Ordinary click, hover, scroll, drag and individual pointer steps use\nthe window's current modifiers. Configurable clicks temporarily use their\nexplicit modifiers and restore the preceding state afterward. `change_modifiers(modifiers, cx)` changes them and\npreserves caps lock; restore the previous modifiers when the gesture ends.\n`key_down(key, is_held, cx)` and `key_up(key, cx)` allow separate key transitions\nand auto-repeat (`is_held = true`). Key events combine modifiers written in the\nkey string with the window's held modifiers, without changing the retained\nmodifier state. Each step refreshes before dispatch and\ncompletes a frame afterward. These key events do not insert text; use `input`\nfor typing. Leave the window update and wait for deferred results when needed.\n\n## Exercise text composition through an input handler\n\n`gpui_kit::test::TestInput` bridges an explicit GPUI `InputHandler` to a window.\nFor an entity implementing `EntityInputHandler`, construct the adapter with\n`gpui_kit::ElementInputHandler::new(bounds, entity.clone())`, then pass it to\n`TestInput::new(handler, window)`. Keep the entity owned by the\nproduction view and use its actual input geometry. This bridge calls that\nhandler directly; it does not select the focused control or run an OS IME.\n\n`commit_text(text, cx)` commits through `replace_text_in_range`.\n`compose_text(replacement, text, selection, cx)` updates marked text through\n`replace_and_mark_text_in_range`. Replacement and selection ranges use UTF-16\ncode units, not UTF-8 byte offsets; selection is relative to the composed text.\nWith no replacement range, the handler replaces its current marked range or\nselection. Empty composition text cancels preedit according to the handler.\n`marked_text_range(cx)` returns a document-relative range;\n`selected_text_range(cx)` returns `Option<UTF16Selection>`, including direction;\n`unmark_text(cx)` ends marking while retaining its text. Mutation helpers complete a frame after the\nhandler call. They can test composition transitions and commit behavior, while\nplatform candidate windows, focus routing and OS IME integration still need\nnative tests. Use `window.input` for ordinary text typed at the current focus.\n\n## Resize, display scale and clipboard\n\nUse GPUI's existing `TestAppContext::simulate_window_resize(handle, size)` and\n`simulate_window_scale_factor_change(handle, scale)` outside a window update,\nthen call `render_frame` before inspecting layout. Pointer positions remain\nwindow-local logical pixels at every display scale. Assert both preserved\nediting state and resized geometry, then activate a control at its new bounds.\n\nExercise clipboard behavior through production shortcuts (`secondary-c`,\n`secondary-x`, `secondary-v`) and inspect `cx.read_from_clipboard()` when needed.\nThe test platform shares its clipboard across windows; editor state should\nremain window-specific. This verifies the test-platform adapter and application\nbindings, not the operating system's clipboard service.\n\nAfter activating an external Link, inspect `cx.opened_url()` to verify the URL\nreceived by the test platform and assert the application's click callback.\nThis does not establish that a browser opened the destination. The test\nplatform exposes no cursor-style reader; URL and callback assertions do not\nverify the pointer cursor.\n\n## Frames and async work\n\nSnapshots are owned facts from the last completed frame, not live elements.\nFetch a new snapshot after an interaction. Interaction helpers refresh frames;\nafter an external entity update, focus change or resize, call\n`window.render_frame(cx)` before querying.\n\nFor deferred actions, subscriptions or popup updates, leave `update_window`\nso GPUI can process its effects. Use `cx.run_until_parked()` for queued work,\nor import `TestAppContextExt` and await a bounded condition:\n\n```rust\ncx.wait_for(handle.into(), std::time::Duration::from_secs(1), |window, _| {\n    window.try_find(\"dialog\").is_none()\n}).await;\n```\n\n`wait_for` runs outside a borrowed window update and uses GPUI test time.\nProcess a queued action before changing any input that the action is meant to\nvalidate. Otherwise it can read the later input instead of the value at the\nintended test step.\n\nFor timers, check the UI before its deadline as well as after expiration.\nGPUI's non-synced `Animation` uses wall-clock time; advancing the test clock\ndoes not complete it. Use reduced motion when supported, or a bounded wait\nappropriate to that production animation before asserting final geometry.\n\n## Assertion boundaries\n\n- `checked()`, `selected()`, `expanded()`, `value()` and `label()` come from\n  native accessibility properties. `None` means unavailable; masked input\n  deliberately omits its value. Do not supply a second set of test-only state.\n- `disabled()` currently reports `Some(true)` or `None`. To prove a control is\n  enabled, perform the interaction and assert the result. Absence of a flag\n  is not proof that the control accepts input.\n- `focused()` measures the observed native focus scope. Missing bindings are\n  diagnosed when the native element advertises `Action::Focus`; controls\n  without that action can still return `None`. Register the real binding.\n- `bounds()` supports containment, relative position, overlap, scrolling and\n  drag assertions. `visible()` checks geometry, clipping and observed style;\n  it does not prove a target is unobstructed. Real hit testing decides whether\n  a click reaches the control.\n- Native properties can be wrong too. Pair them with real interactions,\n  geometry and the application result. A label is not rendered text, and a\n  correct accessibility value does not establish correct pixels.\n- These tests run in-process. Pixel comparisons need GPUI's separate renderer;\n  packaged-app behavior and full OS IME composition need other coverage. Kit's\n  explicit macOS (Metal) and Linux (WGPU) rendering target is\n  `cargo test -p gpui-kit --features test-support --test rendering --locked`.\n  Linux requires a working WGPU adapter and can use Mesa lavapipe. Windows\n  explicitly skips this target because GPUI 0.3.8 has no Windows headless renderer.\n  Missing renderer support on macOS or Linux fails instead of producing fake images.\n\n## Additional resources\n\n- [Website testing guide](https://gpui-kit.com/docs/test) — bilingual setup,\n  component coverage, platform requirements and CI.\n- [GPUI test examples](test-examples.md) — entity and context patterns.\n- [GPUI test reference](test-reference.md) — re-entrancy and property tests.\n","skills/gpui-kit/references/recipes.md":"# Tested application recipe\n\nThis complete view comes from `examples/ai_recipes/src/settings.rs`. That consumer crate depends only on `gpui-kit`; the same source is compiled and tested by `cargo test -p gpui-kit-recipes`, and `script/check-ai-recipes` keeps this copy identical to it. Pair it with that example's `src/bootstrap.rs`, which installs assets, initializes the library, and wraps the window in `Root`.\n\nThe view owns both input state and subscriptions. Rendering creates only elements. The window's `Root` renders the dialog, sheet and notification layers above the view.\n\n<!-- recipe:settings:start -->\n```rust\nuse gpui_kit::component::{\n    ActiveTheme, IconName, WindowExt,\n    button::Button,\n    checkbox::Checkbox,\n    form::{Field, Form},\n    input::{Input, InputEvent, InputState},\n    radio::RadioGroup,\n    switch::Switch,\n};\nuse gpui_kit::{\n    AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render, SharedString,\n    Styled as _, Subscription, Window, div,\n};\n\npub struct Settings {\n    name: Entity<InputState>,\n    preview: SharedString,\n    changes: usize,\n    enabled: bool,\n    remember: bool,\n    delivery: Option<usize>,\n    _subscriptions: Vec<Subscription>,\n}\n\nimpl Settings {\n    pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let name = cx.new(|cx| InputState::new(window, cx).placeholder(\"Name\"));\n        let subscription = cx.subscribe_in(&name, window, |this, state, event, _, cx| {\n            if matches!(event, InputEvent::Change) {\n                this.preview = state.read(cx).value().to_string().into();\n                this.changes += 1;\n                cx.notify();\n            }\n        });\n        Self {\n            name,\n            preview: \"\".into(),\n            changes: 0,\n            enabled: false,\n            remember: false,\n            delivery: Some(0),\n            _subscriptions: vec![subscription],\n        }\n    }\n\n    pub fn input(&self) -> Entity<InputState> {\n        self.name.clone()\n    }\n\n    pub fn preview(&self) -> &SharedString {\n        &self.preview\n    }\n\n    pub fn changes(&self) -> usize {\n        self.changes\n    }\n}\n\nimpl Render for Settings {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .flex()\n            .flex_col()\n            .size_full()\n            .p_4()\n            .gap_3()\n            .bg(cx.theme().background)\n            .text_color(cx.theme().foreground)\n            .child(\"Profile\")\n            .child(\n                Form::new()\n                    .child(Field::new().label(\"Name\").child(Input::new(&self.name)))\n                    .child(Field::new().label(\"Preview\").child(self.preview.clone()))\n                    .child(\n                        Field::new().label_indent(false).child(\n                            Checkbox::new(\"remember\")\n                                .label(\"Remember name\")\n                                .checked(self.remember)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.remember = *value;\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .child(\n                        Field::new().label_indent(false).child(\n                            Switch::new(\"enabled\")\n                                .label(\"Enable notifications\")\n                                .checked(self.enabled)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.enabled = *value;\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .child(\n                        Field::new().label(\"Delivery\").child(\n                            RadioGroup::new(\"delivery\")\n                                .children([\"Immediately\", \"Daily summary\"])\n                                .selected_index(self.delivery)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.delivery = Some(*value);\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .footer(\n                        Button::new(\"about\")\n                            .label(\"About…\")\n                            .icon(IconName::Info)\n                            .on_click(|_, window, cx| {\n                                window.open_dialog(cx, |dialog, _, _| {\n                                    dialog.title(\"About\").child(\"A complete GPUI Kit window\")\n                                });\n                            }),\n                    ),\n            )\n    }\n}\n```\n<!-- recipe:settings:end -->\n\nFor changes in this repository, run `script/check-ai docs`, `script/check-ai rust`, or `script/check-ai shell` for the relevant verification profile (or `script/check-ai all` for all three), and `cargo test -p gpui-kit-recipes` when a recipe source changes. For a downstream app, compile and test your own consumer, then verify keyboard/focus and visuals in a real window. Automated recipe tests do not establish a model success rate.\n","skills/gpui-kit/references/usage.md":"# gpui-kit Usage Guide\n\n**Contents:** [Setup](#setup) · [Component Types](#component-types) · [Common Components](#common-components) (Button, Input, Select, Checkbox, Icon, Dialog, Notification, Tabs, Tooltip, Form, List) · [Theming](#theming) · [Layout Helpers](#layout-helpers) · [Overlay Layers](#overlay-layers-dialogs-sheets-notifications) · [Shared Traits](#shared-traits)\n\n## Setup\n\nUse the [tested application recipe](recipes.md) for complete examples and their verification command. Store subscription handles on the owning view; binding one to a constructor-local variable alone does not keep it alive after construction.\n\n### 1. Cargo.toml\n\n```toml\n[dependencies]\ngpui-kit = \"0.7\" # re-exports GPUI, platform, base, component and the default icons; Shell is a separate host dependency\n```\n\n### 2. Initialization\n\n```rust\nfn main() {\n    gpui_kit::application()\n        .with_assets(gpui_kit::assets::Assets)\n        .run(move |cx| {\n            gpui_kit::init(cx); // MUST be first\n\n            // Wraps the view in a `Root`, which enables dialogs, sheets,\n            // notifications, tooltips and menus in this window.\n            gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| cx.new(|_| MyApp))\n                .expect(\"Failed to open window\");\n        });\n}\n```\n\nUse `gpui_kit::open_window` for application windows; it mounts `Root` as the window's root view.\n\n---\n\n## Component Types\n\n### Stateless (most components)\n\nUsed directly in `render`, no stored state:\n\n```rust\nuse gpui_kit::component::button::Button;\n\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        Button::new(\"btn\").primary().label(\"Submit\")\n            .on_click(|_, _, _| println!(\"clicked\"))\n    }\n}\n```\n\n### Stateful (Input, Select, Combobox, etc.)\n\nRequire an `Entity<State>` stored in your view:\n\n```rust\nuse gpui_kit::component::input::{Input, InputState};\n\nstruct MyView {\n    name: Entity<InputState>,\n}\n\nimpl MyView {\n    fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        Self {\n            name: cx.new(|cx| InputState::new(window, cx).placeholder(\"Your name\")),\n        }\n    }\n}\n\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        Input::new(&self.name)\n    }\n}\n```\n\n---\n\n## Common Components\n\n### Button\n\n```rust\nuse gpui_kit::component::button::{Button, ButtonGroup};\n\n// Variants\nButton::new(\"btn\").label(\"Default\")\nButton::new(\"btn\").primary().label(\"Primary\")\nButton::new(\"btn\").danger().label(\"Delete\")\nButton::new(\"btn\").warning().label(\"Warning\")\nButton::new(\"btn\").success().label(\"Success\")\nButton::new(\"btn\").ghost().label(\"Ghost\")\nButton::new(\"btn\").link().label(\"Link\")\n\n// States\nButton::new(\"btn\").label(\"Text\").disabled(true)\nButton::new(\"btn\").label(\"Text\").loading(true)\nButton::new(\"btn\").label(\"Text\").selected(true)\n\n// With icon\nButton::new(\"btn\").icon(IconName::Plus).label(\"Add\")\n\n// Sizes\nButton::new(\"btn\").xsmall().label(\"XS\")\nButton::new(\"btn\").small().label(\"S\")\nButton::new(\"btn\").large().label(\"L\")\n\n// Group\nButtonGroup::new(\"group\")\n    .child(Button::new(\"a\").label(\"A\"))\n    .child(Button::new(\"b\").label(\"B\"))\n    .on_click(|indices, _, _| { /* selected indices */ })\n```\n\n### Input\n\n```rust\nuse gpui_kit::component::input::{Input, InputState};\n\n// State setup (in new/init)\nlet input = cx.new(|cx| InputState::new(window, cx)\n    .placeholder(\"Enter text...\")\n    .default_value(\"Hello\")\n);\n\n// Render\nInput::new(&input)\nInput::new(&input).cleanable(true)           // clear button\nInput::new(&input).disabled(true)\nInput::new(&input).prefix(Icon::new(IconName::Search).small())\nInput::new(&input).suffix(Button::new(\"b\").ghost().icon(IconName::X).xsmall())\nInput::new(&input).content_type(InputContentType::Password)\nInput::new(&input).mask_toggle()             // password reveal toggle\nInput::new(&input).appearance(false)         // remove default border/bg\n\n// Reading value\nlet value = input.read(cx).value();\n\n// Keep this subscription in the owning view (for example, `_subscriptions`).\nself._subscriptions.push(cx.subscribe_in(&input, window, |view, state, event, window, cx| {\n    match event {\n        InputEvent::Change => { let v = state.read(cx).value(); }\n        InputEvent::PressEnter { .. } => { /* submit */ }\n        InputEvent::Focus | InputEvent::Blur => {}\n    }\n}));\n```\n\n### Select\n\n```rust\nuse gpui_kit::component::select::{Select, SelectState};\n\n// Simple string list\nlet state = cx.new(|cx| {\n    SelectState::new(vec![\"Apple\", \"Orange\", \"Banana\"], Some(IndexPath::default()), window, cx)\n});\n\n// Render\nSelect::new(&state)\nSelect::new(&state).placeholder(\"Pick one\")\n\n// Reading selection\nlet selected = state.read(cx).selected_item();\n```\n\n### Checkbox / Switch / Radio\n\n```rust\nuse gpui_kit::component::{checkbox::Checkbox, switch::Switch};\n\n// Stateless (controlled)\nCheckbox::new(\"cb\").checked(self.checked)\n    .on_change(cx.listener(|this, checked, _, cx| {\n        this.checked = *checked;\n        cx.notify();\n    }))\n\nSwitch::new(\"sw\").checked(self.enabled)\n    .on_change(cx.listener(|this, checked, _, cx| {\n        this.enabled = *checked;\n        cx.notify();\n    }))\n```\n\n### Icon\n\n```rust\nuse gpui_kit::component::{Icon, IconName};\n\nIcon::new(IconName::Check)\nIcon::new(IconName::Search).small()\nIcon::new(IconName::Plus).large().text_color(cx.theme().primary)\n```\n\n### Dialog\n\n```rust\nuse gpui_kit::component::dialog::{Dialog, DialogAction, DialogClose, DialogFooter};\n\n// Open from window context. `footer` takes an element, not a closure.\n// DialogClose dismisses the dialog, so no manual close call is needed.\nwindow.open_dialog(cx, |dialog, _, _| {\n    dialog\n        .title(\"Export Report\")\n        .child(\"Choose a destination for the exported file.\")\n        .footer(\n            DialogFooter::new()\n                .gap_2()\n                .child(DialogClose::new().child(\n                    Button::new(\"cancel\").label(\"Cancel\").outline(),\n                ))\n                .child(DialogAction::new().child(\n                    Button::new(\"export\").label(\"Export\").primary(),\n                )),\n        )\n});\n```\n\n### AlertDialog\n\nUse `AlertDialog` — not `Dialog` — to confirm a consequential action. It is not\noverlay-closable and has no close button, so the choice must be made. Name the\nobject in the title and the result on the confirming button; see the Design\nGuides for the copy rules.\n\n```rust\nuse gpui_kit::component::button::ButtonVariant;\n\nwindow.open_alert_dialog(cx, |alert, _, _| {\n    alert\n        .title(\"Remove “Roadmap”?\")\n        .description(\"Files on disk aren’t deleted.\")\n        .confirm()\n        .ok_text(\"Remove\")\n        .ok_variant(ButtonVariant::Danger)\n        .on_ok(|_, _, _| true)\n});\n```\n\n`button_props(DialogButtonProps)` takes the same properties as one value; it\noverrides only the fields that value sets, so `confirm` and earlier callbacks\nsurvive it.\n\n### Notification\n\n```rust\n// Simple string message\nwindow.push_notification(\"Saved successfully!\", cx);\n\n// With type variant\nwindow.push_notification(\n    Notification::new(\"Upload complete\").info().message(\"File uploaded\"),\n    cx,\n);\n```\n\n### Tabs\n\n```rust\nuse gpui_kit::component::tab::{Tab, TabBar};\n\nTabBar::new(\"tabs\")\n    .child(Tab::new(\"tab1\").child(\"Overview\"))\n    .child(Tab::new(\"tab2\").child(\"Settings\"))\n    .child(Tab::new(\"tab3\").child(\"Logs\"))\n```\n\n### Tooltip\n\n```rust\n// On any element with .id(), add .tooltip():\ndiv()\n    .id(\"my-btn\")\n    .tooltip(|window, cx| Tooltip::new(\"Delete item\").build(window, cx))\n    .child(\"Delete\")\n\n// Or on a Button directly:\nButton::new(\"btn\").icon(IconName::Trash).tooltip(\"Delete\")\n\n// Component tooltips open after 500 ms; override per trigger,\n// or install `tooltip::TooltipDefaults` to change it app-wide:\nButton::new(\"help\").icon(IconName::Info).tooltip(\"Help\")\n    .tooltip_show_delay(Duration::ZERO)\n```\n\n### Form\n\n```rust\nuse gpui_kit::component::form::{v_form, h_form, field};\n\n// Vertical form\nv_form()\n    .child(field().label(\"Name\").child(Input::new(&self.name)))\n    .child(field().label(\"Email\").child(Input::new(&self.email)))\n    .footer(Button::new(\"submit\").primary().label(\"Submit\"))\n\n// Horizontal label alignment\nh_form()\n    .child(field().label(\"Username\").child(Input::new(&self.username)))\n```\n\n### List (searchable, virtualized)\n\n```rust\nuse gpui_kit::component::list::{List, ListState, ListDelegate, ListItem, ListEvent};\n\n// Implement ListDelegate for your data type, then:\nlet list_state = cx.new(|cx| ListState::new(MyDelegate::new(), window, cx));\n\n// Render\nList::new(&list_state)\n// Keep this subscription in the owning view, alongside list_state.\nself._subscriptions.push(cx.subscribe(&list_state, |this, _, event, cx| {\n    if let ListEvent::Select(index_path) = event {\n        // handle selection\n    }\n}));\n```\n\n---\n\n## Theming\n\n```rust\nuse gpui_kit::component::ActiveTheme as _;\n\n// Access colors\ncx.theme().primary\ncx.theme().background\ncx.theme().foreground\ncx.theme().border\ncx.theme().surface\ncx.theme().muted\ncx.theme().destructive\n\n// Use in styles\ndiv()\n    .bg(cx.theme().surface)\n    .text_color(cx.theme().foreground)\n    .border_color(cx.theme().border)\n```\n\n### Switch Theme\n\n```rust\nuse gpui_kit::component::{Theme, ThemeMode};\n\n// Switch light/dark: loads that mode's registered theme\nTheme::change(ThemeMode::Dark, None, cx);\n// or, as one edit among others\nTheme::update(cx, |theme| theme.mode = ThemeMode::Dark);\n\n// Load a named theme\nTheme::update(cx, |theme| theme.apply_config(&theme_config));\n\n// Edit fields; `update` keeps colors, tokens and the Base projection in step\nTheme::update(cx, |theme| theme.radius = px(8.));\n```\n\n---\n\n## Layout Helpers\n\n`gpui_kit::component` extends GPUI with convenient layout methods:\n\n```rust\nh_flex()    // div().flex().flex_row().items_center()\nv_flex()    // div().flex().flex_col()\n\n// Common patterns\nh_flex().gap_2().items_center()\n    .child(Icon::new(IconName::User))\n    .child(label(\"Username\"))\n\nv_flex().gap_4().p_4()\n    .child(Input::new(&self.name))\n    .child(Input::new(&self.email))\n    .child(Button::new(\"submit\").primary().label(\"Submit\"))\n```\n\n---\n\n## Overlay Layers (Dialogs, Sheets, Notifications)\n\nThe window's `Root` renders dialogs, sheets and notifications above the view, so a window opened with `gpui_kit::open_window` needs nothing else — `window.open_dialog(..)` just works. Applications define their own quit and close-window actions, key bindings, and confirmation flows. `open_window` returns `(AnyWindowHandle, Entity<V>)`. The complete tested consumer recipe is [`examples/ai_recipes/src/bootstrap.rs`](../../../examples/ai_recipes/src/bootstrap.rs).\n\nRoot always mounts all three layers. The former `Root::render_*_layer` methods have been removed; delete their calls from application views when migrating to 0.7.0.\n\n---\n\n## Shared Traits\n\nBuilders return the component so methods can be chained. Constructors follow component families: controls take a stable ID, retained controls take state, and compound parts may take no arguments. See [component conventions](conventions.md).\n\n- `Sizable`: `.xsmall()` / `.small()` / `.medium()` (default) / `.large()`\n- `Disableable`: `.disabled(bool)`\n- `Selectable`: `.selected(bool)`\n- `Styled`: any GPUI style methods (`.w()`, `.bg()`, `.p_2()`, etc.)\n\nFor any component not covered here, fetch its doc from:\n`https://gpui-kit.com/component/{name}.md`\n"},"files":{".agents/commands/release-notes.md":"# Release Notes\n\nWrite release notes using the input supplied by the user: either a tag such\nas `v0.6.2`, or the auto-generated \"## What's Changed\" list copied from the\nGitHub release draft. When no input is supplied, use the `version` in the\nworkspace `Cargo.toml` with a `v` prefix.\n\n## Gather\n\n1. Read the previous release with `gh release view <previous-tag> --json body -q .body`\n   to match its structure, tone, and section names. The previous tag is\n   `git describe --tags --abbrev=0 <tag>^` (or the latest published release\n   when `<tag>` does not exist yet).\n2. If no \"What's Changed\" list was pasted, generate it:\n\n   ```bash\n   gh api repos/longbridge/gpui-kit/releases/generate-notes \\\n     -f tag_name=<tag> -f previous_tag_name=<previous-tag> -q .body\n   ```\n\n   Keep this list, its \"New Contributors\" section, and the \"Full Changelog\"\n   line verbatim; they close the notes.\n3. Read the body of every PR that adds a component, a public API, a platform,\n   or a behavior change, with `gh pr view <n> --json title,body`. Take API\n   names, method names, and `## Breaking Changes` diff blocks from the PR\n   text; never invent a name from the title alone. Fix-only PRs can be\n   summarized from their titles.\n\n## Write\n\nProduce one Markdown document in this shape, in English:\n\n```markdown\n# GPUI Kit <tag>\n\n<Two or three sentences: the headline features first, then what else the\nrelease improves.>\n\n## <Theme>\n\n- **<Feature>**: what a consumer can now do, with the API in backticks.\n  ([#123](https://github.com/longbridge/gpui-kit/pull/123))\n- Fixed ... ([#124](...), [#125](...))\n\n...\n\n## Breaking Changes            <!-- only when a PR has one -->\n\n<One sentence per change naming the PR, then its diff block.>\n\nThank you to everyone who contributed code, documentation, testing, and feedback!\n\n## What's Changed\n<verbatim list>\n\n## New Contributors\n<verbatim list>\n\n**Full Changelog**: <verbatim line>\n```\n\nRules:\n\n- Group by product area, ordered by significance: headline features (new\n  platforms, new components), then editor and text input, Markdown and text\n  rendering, motion, dock, other components (one bold component name per\n  bullet), shell, runtime and platform, documentation and website. Drop a\n  section that has nothing to say; merge small ones.\n- Every bullet cites its PR numbers as `[#n](https://github.com/longbridge/gpui-kit/pull/n)`\n  at the end, in parentheses. Combine PRs that land one change into one bullet.\n- Leave out chores, CI, lockfile refreshes, test-only changes, and a PR that\n  reverts another PR in the same release (leave both out).\n- Bold the feature, not the sentence; write what it does for an application,\n  not what the diff touched.\n- Do not create or edit the GitHub release unless asked. Save the document to\n  the scratchpad and show it, so it can be pasted into the release draft.\n",".claude/commands/release-notes.md":"---\ndescription: Write the GitHub release notes for a gpui-kit version in the established style\nargument-hint: [tag] or the pasted \"What's Changed\" list\n---\n\nRead and follow the shared release-notes workflow in\n`.agents/commands/release-notes.md` (relative to the repository root).\n\nUse the following as the workflow input; if empty, use the shared workflow's\ndefault version:\n\n$ARGUMENTS\n","AGENTS.md":"# AGENTS.md\n\nThis file provides shared guidance for coding agents working in this repository.\nKeep project rules here; `CLAUDE.md` imports this file for Claude Code.\n\n## Canonical Design and Coding Guides\n\nBefore changing UI, interaction, interface language, layout, styling,\ncomponents, or application architecture, read and follow the repository's\ncanonical guides:\n\n- [Design Guides](website/docs/design-guides.md)\n- [Coding Guides](website/docs/coding-guides.md)\n\nThese guides are requirements, not optional inspiration. Do not copy generic\nweb conventions, infer a design system from one existing screen, or add a\ncontrol merely because the underlying feature exists. Preserve the documented\ntask hierarchy, interaction promise, desktop conventions, spacing, alignment,\ntheme tokens, component boundaries, naming, and crate architecture. Review the\nfinished work against both guides before considering it complete.\n\nFor Chinese documentation and UI, apply the terminology rules in Design Guides.\nKeep established framework, component, and API names in their canonical English\nform when translation would reduce precision; write the surrounding Chinese as\nnatural Chinese rather than word-for-word translation.\n\n## Project Overview\n\nGPUI Kit is a Rust desktop application framework built on GPUI, published at <https://gpui-kit.com>. It ships as three crates: `gpui-base` (unstyled behavior and infrastructure), `gpui-shell` (JavaScript extensions for a Rust host), and `gpui-component` (GPUI Component, the styled component library with 60+ cross-platform desktop UI components, inspired by macOS/Windows controls and combined with shadcn/ui design). Applications depend on the umbrella crate `gpui-kit` (`crates/kit`), which pins the matching `gpui-pre-*` snapshot of GPUI and puts GPUI at its root (`use gpui_kit::*;`) with `gpui_kit::platform`, `gpui_kit::base`, `gpui_kit::component` and `gpui_kit::assets` reachable by name, so they never list GPUI itself. `gpui-shell` is not part of `gpui-kit` and is not published yet (its `llrt_*` dependencies are git-only); use it as a git dependency.\n\nThis is a Rust workspace project with the following main crates:\n\n- `crates/kit` - Umbrella crate applications depend on (published as `gpui-kit`)\n- `crates/component` - Core UI component library (published as `gpui-component`)\n- `crates/story` - Gallery application for showcasing and testing components\n- `crates/story-web` - Web version of the story gallery (using WebAssembly)\n- `crates/component-macros` - Procedural macros (`IntoPlot` derive)\n- `crates/assets` - Static assets\n- `crates/webview` - WebView component support\n- `examples/` - Various example applications\n\n## Common Commands\n\n### Development and Testing\n\n```bash\n# Run Story Gallery (component showcase application)\ncargo run\n\n# Run individual examples\ncargo run --example hello_world\ncargo run --example table\n\n# Build the project\ncargo build\n\n# Lint check\ncargo clippy -- --deny warnings\n\n# Format check\ncargo fmt --check\n\n# Spell check\ntypos\n\n# Check for unused dependencies\ncargo machete\n```\n\n### Testing\n\n**Note**: Per user configuration, tests do not need to be run.\n\nFor pure UI visual or sizing adjustments, do not add automated tests solely to\nassert presentation dimensions. Add tests when the change affects behavior,\ninteraction, data flow, or prevents a meaningful regression.\n\n```bash\n# Run all tests\ncargo test --all\n\n# Run tests for a specific crate\ncargo test -p gpui-component\n\n# Run doc tests\ncargo test -p gpui-component --doc\n```\n\n### Performance Profiling\n\n```bash\n# View FPS on macOS (using Metal HUD)\nMTL_HUD_ENABLED=1 cargo run\n\n# Profile performance using samply\nsamply record cargo run\n```\n\n## Core Architecture\n\n### Architecture Refactoring Constraints\n\nThe implemented foundation architecture is documented in\n`docs/ARCHITECTURE.md`, with styling and motion rules in\n`docs/STYLING-AND-MOTION.md`. Preserve these constraints when designing or\nimplementing this architecture:\n\n- Do not modify `gpui-base` unless the user explicitly requests a Base-layer\n  change. By default, implement component behavior and visual styling in\n  `crates/component` or the application layer.\n\n- Keep GPUI Kit as the ecosystem and product brand; `gpui-component` is its\n  styled component layer, alongside `gpui-base` and `gpui-shell`.\n- Name the foundation crate `gpui-base`.\n- Follow the ownership boundary: the framework owns behavior and infrastructure;\n  the application owns component source and visual style.\n- Keep the base layer visually unopinionated. It may provide interaction behavior,\n  accessibility, focus, overlay and popup infrastructure, positioning, animation,\n  virtual lists, dock infrastructure, and semantic design tokens.\n- Theme APIs must expose semantic tokens (colors, spacing, radius, typography, and\n  shadows), not an ever-growing set of component-specific styling fields.\n- Keep source distribution or registry tooling above the `gpui-base` seam; no\n  registry or CLI crate is currently part of the workspace.\n- Preserve 100% backward compatibility for existing consumers, including current\n  imports such as `use gpui_kit::component::button::Button;`.\n\n### Component Initialization\n\nCall `gpui_kit::init(cx)` before opening windows that use styled components.\nIt includes Base initialization and registers Component's window extension.\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx| {\n        gpui_kit::init(cx);\n        gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| {\n            cx.new(|_| MyView)\n        })\n        .expect(\"Failed to open window\");\n    });\n}\n```\n\nBase-only fixtures use GPUI directly and must not depend on Kit or Component.\nApplications and Kit tests use `gpui_kit::open_window` as their window entry point.\n\n### Root View System\n\n`gpui_base::Root` is the top-level view for every window created by\n`gpui_kit::open_window`. The helper belongs only to Kit; Base supplies the Root\nimplementation. `component::Root` re-exports the Base type. Cargo features do not\nselect a different root type.\n\nBase owns content and overlay hosting, keyboard navigation (Tab/Shift-Tab),\nand selection copying. Explicit Component initialization registers per-window\nstate and presentation for dialogs, sheets, notifications, tooltips, menus,\ntouch selection, themes and window chrome. Initialize before creating windows.\n\nThe helper returns the window handle and application content entity. Its builder\nmust return content, not another Root. Overlay layers mount automatically; do not\ncall the removed `Root::render_*_layer` methods. In async contexts call the helper\ninside `cx.update`. Tests should use the same helper and retain its returned\ncontent entity when they need to inspect or update application state. Avoid\nconstructing `Root` directly in application and test startup code.\n\nQuit/close actions, keyboard shortcuts and confirmation flows belong to the application.\n\n### Theme System\n\n- Uses `Theme` global singleton for theme configuration\n- Supports light/dark mode switching\n- Access theme via `ActiveTheme` trait: `cx.theme()`\n- Theme configuration includes:\n  - Colors (`ThemeColor`)\n  - Syntax highlighting theme (`HighlightTheme`)\n  - Font configuration (system font and monospace font)\n  - UI parameters like border radius, shadows\n  - Scrollbar display mode\n\n### Dock System\n\nLayout behavior lives in `crates/base/src/dock`; `crates/component/src/dock` is a\npresentation skin (`DockSkin`) over it. See `docs/ARCHITECTURE.md`.\n\n- **`LayoutTree`**: Pure-data layout tree, the single source of truth.\n  - `NodeKind::Split` / `Tabs`: containers, addressed by `NodeId`\n  - Panels are addressed by `PanelId`; the tree holds no entity handles\n- **`DockArea`**: Owns the center and dock trees, reconciles them into a\n  cache of container entities keyed by `NodeId`\n- **`TabGroup`**: The `Tabs` container entity\n- **`Panel`**: Split at the seam — `gpui_base::dock::Panel` for behavior,\n  `gpui_component::dock::Panel` for presentation; a panel implements both\n- **`PanelRegistry`**: Resolves a persisted `panel_name` back to a panel type\n\nThe Dock system supports:\n\n- Panel drag-and-drop reordering\n- Panel zoom\n- Layout locking\n- Layout serialization/restoration\n\n### Input System\n\nText input system based on Rope data structure:\n\n- **InputState**: Input state management\n- **Rope**: Efficient text storage (from ropey crate)\n- LSP integration support (diagnostics, completion, hover)\n- Syntax highlighting support (Tree-sitter)\n- Multiple input modes:\n  - Regular input (`Input`)\n  - Number input (`NumberInput`)\n  - OTP input (`OtpInput`)\n\n### Component Design Principles\n\n1. **Stateless design**: Use `RenderOnce` trait, components should be stateless when possible\n2. **Size system**: Supports `xs`, `sm`, `md` (default), `lg` sizes via `Sizable` trait.\n3. **Mouse cursor**: Buttons use `default` cursor not `pointer` (desktop app convention), unless it's a link button\n4. **Style system**: Provides CSS-like styling API via `Styled` trait and `ElementExt` extensions\n5. **Base controls are no-style**: Base controls and parts do not install layout,\n   positioning, colors, sizing, gaps, radius, borders, shadows, variants, or animation.\n   Complete presentation belongs to `crates/component` or the application. The deliberate\n   exception is the foundational Base Input frame, which provides only a semantic\n   one-pixel input border and semantic radius baseline; UI/application layers own\n   its background, sizing, padding, typography, adornments, and richer focus style.\n6. **GPUI builder style**: Keep element construction as one fluent builder chain. Express\n   conditions with `when`, `when_some`, `when_none`, and `map`; do not split a chain into a\n   mutable temporary element followed by imperative reassignment when the builder API can\n   express the same operation.\n7. **No `pub` fields on public data types**: A public struct handed across the\n   `gpui-base`/application seam — a state snapshot, capability set, render context, or\n   option set — keeps its fields private, is constructed with a builder, and is read\n   through methods. Adding a `pub` field is a breaking change; adding one behind a builder\n   is not. Setters and readers must not collide: an all-boolean type names setters after\n   the field and readers `is_<adjective>`/`has_<noun>`, never `can_`; a type with\n   non-boolean fields prefixes every setter with `with_` and keeps the field name for\n   readers. Value types whose fields are the definition and cannot grow (`Point`,\n   `Selection`, `Edges`) are exempt. See the \"Public Data Types Across the Seam\" section\n   of `docs/ARCHITECTURE.md`.\n8. **Spell `Context` out**: Name a context type `ComboboxTriggerContext`, never `…Ctx`.\n   `cx` is reserved for GPUI's `App`, `Context<T>`, and `AsyncApp`, so `ctx` for anything\n   else reads as a competing context. A callback receiving both takes the GPUI one as `cx`\n   and names the other after what it holds (`trigger`, `state`).\n\n## Pull Request Reviews\n\nEvery PR review must present its conclusions in this order:\n\n1. Explain the PR's purpose: the problem it addresses and the scope of its changes.\n2. Assess whether the requirement and proposed approach are reasonable.\n3. Report concrete findings, followed by validation performed and its limitations.\n\nDo not start a review with findings alone; include the purpose and reasonableness\nassessment even when no issues are found.\n\n## Code Style\n\n- Follow naming and organization patterns from existing code\n- Reference macOS/Windows control API design for naming\n- AI-generated code must be refactored to match project style\n- Mark AI-generated portions when submitting PRs\n- When creating a PR, inspect previous PR titles in the repository and match\n  that style. Do not blindly use conventional prefixes like `fix:` or `feat:`\n  unless the existing PR title style uses them.\n- When a PR adds, changes or removes public API in any crate, list every item\n  under a `## Public API` section of the description, grouped by crate, with its\n  signature and one line on its purpose (JavaScript methods and TypeScript\n  declarations included). Changes to existing items also go under\n  `## Breaking Changes` with `diff` blocks showing the old and new usage. See\n  PR #2691 and the \"Describe public API changes\" section of `CONTRIBUTING.md`.\n- Avoid `Kind` as a type-name suffix. It says an enum classifies something\n  without saying what it classifies, and carries no meaning a reader could not\n  already infer from `enum`. Name the type after what its variants _are_\n  instead. Keep `Kind` only when no honest name covers the variant set —\n  `NodeKind`'s variants straddle two levels (`Split` is an interior node,\n  `Tabs` is a leaf), and every domain word for the leaf level\n  (`Pane`, most of all) would misdescribe `Split`; a vaguer name is better\n  than a precise wrong one. Prefer confining such a type to `pub(crate)`.\n  This governs new code; existing `Kind` names are not a rewrite target on\n  their own, and names owned by external crates (`CodeActionKind`,\n  `CompletionItemKind`, `WindowKind`) keep their upstream spelling.\n\n## Icon System\n\nThe `Icon` element does not include SVG files by default. You need to:\n\n- Use [Lucide](https://lucide.dev) or other icon libraries\n- Name SVG files according to the `IconName` enum definition (located in `crates/component/src/icon.rs`)\n\n## Dependencies\n\n- GPUI: Git version from Zed repository\n- Tree-sitter: For syntax highlighting\n- Ropey: Rope data structure for text, and `RopeExt` trait with more features.\n- Markdown rendering: `markdown` crate\n- HTML rendering: `html5ever` (basic support)\n- Charts: Built-in chart components\n- LSP: `lsp-types` crate\n\n## Internationalization\n\nUses `rust-i18n` crate.\n\n- Localization files are located in `crates/component/locales/`.\n- Only add `en`, `zh-CN`, `zh-HK` by default.\n- Accessibility (A11y) names and labels may remain in English; localization is\n  not required for these strings. Keep the item's own label when naming a\n  control that acts on it. This exception does not apply to visible UI copy.\n\n## Documentation\n\n- The documentation site source is in `website/`.\n- Site docs have two locales: English (`website/docs/`) and Chinese (`website/zh-CN/docs/`).\n- When modifying any documentation file, always sync changes to both `en` and `zh-CN` versions.\n- `docs/` holds internal architecture specifications (RFC, migration status, reviews).\n  These are single-language and are not published to the site; see `docs/README.md`.\n- `skills/gpui-kit/references/coding-guides.md` and\n  `skills/gpui-kit-design-guides/references/design-guides.md` are verbatim copies\n  of the English `website/docs/` originals, vendored so the skills work after\n  `npx skills add` in a project that does not have this repo. After editing either\n  guide, copy it across:\n\n  ```bash\n  cp website/docs/design-guides.md skills/gpui-kit-design-guides/references/design-guides.md\n  cp website/docs/coding-guides.md skills/gpui-kit/references/coding-guides.md\n  ```\n\n  Never edit the copy directly — edit `website/docs/`.\n\n## Platform Support\n\n- macOS (aarch64, x86_64)\n- Linux (x86_64)\n- Windows (x86_64)\n\nCI runs full test suite on each platform.\n\n## Skills Reference\n\nThis project provides skills for coding agents to assist with common development tasks:\n\n- **gpui-kit** (`skills/gpui-kit/SKILL.md`) - Building applications on the `gpui-kit` crate: setup, component catalog, stateless/stateful patterns, theming, GPUI mechanics (actions, async, contexts, custom elements, entities, events, focus, global state, layout, `ElementId`, testing), and the normative Coding Guides\n- **gpui-kit-design-guides** (`skills/gpui-kit-design-guides/SKILL.md`) - The normative Design Guides; load before any UI, layout, interaction, or interface-copy work\n\nWhen working on tasks related to these areas, read the appropriate `SKILL.md`\nfor specialized guidance and patterns.\n\n## Shared Workflows\n\n- [Release notes](.agents/commands/release-notes.md) - Write release notes from a\n  version tag or a pasted \"What's Changed\" list. Claude Code exposes this workflow\n  through `/release-notes`; other agents can read and follow the shared file.\n\n## Testing Guidelines\n\nSee `.agents/COMPONENT_TEST_RULES.md` for detailed testing principles:\n\n- **Simplicity First**: Focus on complex logic and core functionality, avoid excessive simple tests\n- **Builder Pattern Testing**: Every component should have a `test_*_builder` test covering the builder pattern\n- **Complex Logic Testing**: Test conditional branching, state transitions, and edge cases\n","CLAUDE.md":"# Claude Code\n\n@AGENTS.md\n","docs/ARCHITECTURE.md":"# gpui-base Architecture\n\n## Status and Scope\n\nThis document describes the architecture implemented by `crates/base`. It is a\nsource-derived reference, not a migration plan. Public exports in\n`crates/base/src/lib.rs` and the Rust API documentation remain authoritative for\nindividual methods.\n\n`gpui-base` is the reusable foundation below the styled `gpui-component` crate.\nIt is designed for both of these callers:\n\n- `crates/component`, which adapts base behavior into GPUI Component's complete visual\n  system;\n- applications that build and own a different visual system directly on top of\n  base behavior.\n\n## Architectural Thesis\n\nThe durable rule is:\n\n> Base owns reusable behavior and the geometry required to implement it. The\n> presentation layer owns the product's visual language.\n\n“Headless” does not mean that every base module is a single empty `Div`.\nKeyboard navigation, text editing, popup collision handling, virtualization,\ncalendar grids, resizable panels, and toast stacking require internal structure,\nmeasurement, and retained state. Base owns that complexity when moving it to\ncallers would duplicate difficult behavior.\n\nBase does not own product-level choices such as brand colors, typography,\ncontrol density, borders, radii, icons, variants, or final composition.\n\n## Dependency Direction\n\n```text\n                       application\n                     /             \\\n                    ▼               ▼\n       application-owned UI     gpui-component\n                    \\               /\n                     └──────┬──────┘\n                            ▼\n                        gpui-base\n                            ▼\n                           GPUI\n```\n\nDependencies point downward. `gpui-base` must not import `gpui-component`\nthemes, assets, or façade types. `gpui-component::init` may initialize and theme\nthe base layer, but the base layer must also work when initialized directly.\n\nThere is no Registry or CLI crate in the current workspace. Source distribution\ncan be added above this seam without changing the ownership model, but it is not\npart of the implemented architecture documented here.\n\n## Module Families\n\nThe public surface contains four distinct module families. Treating all of them\nas identical “primitives” hides important interface differences.\n\n### 1. Semantic elements\n\nExamples include Button, Checkbox, Radio, Switch, Toggle, Link, Tabs, Progress,\nAvatar, and the semantic Table parts.\n\nThese modules typically implement GPUI interfaces directly:\n\n```text\nIntoElement\n+ Styled\n+ ParentElement where composition is meaningful\n+ InteractiveElement for interactive roots\n```\n\nThey provide a stable element identity, event normalization, focus behavior,\nkeyboard activation, accessibility semantics, controlled values, and optional\nsemantic-state styles. The caller supplies visible children and presentation.\n\n`Button::new(\"save\")`, for example, receives an `ElementId`, not a label. It has\nno default height, padding, background, border, or radius.\n\n### 2. Compound behavior roots\n\nExamples include Accordion, Dialog, AlertDialog, Sheet, Popover, HoverCard,\nSelect, Combobox, DatePicker, and Popup.\n\nThese modules coordinate multiple parts or application-owned children. Their\ninterfaces encode behavior that would be fragile if every caller rebuilt it:\n\n- open-state requests and change reasons;\n- trigger and content focus transfer;\n- Escape, Confirm, and directional key actions;\n- dismissal ordering;\n- backdrop hit testing;\n- focus trapping;\n- trigger measurement and popup placement.\n\nParts such as `DialogTitle`, `DialogDescription`, and `DialogClose` are explicit\nsemantic seams. Base does not walk arbitrary descendant trees to discover them.\n\n### 3. Stateful systems\n\nExamples include InputState, TextareaState, EditorState, CalendarState, TreeState, SliderState,\nResizableState, OtpState, ColorPickerState, QuestionnaireState, ToastManager, ToastStackState,\nNavStackState, DockArea, and TabGroup.\n\nThese modules retain data because their behavior spans frames or requires\nmeasurement, subscriptions, history, focus, or incremental updates. State is\nusually stored in a GPUI `Entity`, a keyed element state, or an application-owned\nmodel passed back to the element.\n\nStateful systems expose application rendering seams rather than leaking their\nimplementation. Calendar provides a pre-wired `CalendarItem` and semantic\n`CalendarItemState` to an item renderer. Tree owns flattening, expansion,\nselection, keyboard movement, and virtualization while the caller renders each\nvisible `TreeEntry`.\n\n### 4. Infrastructure and utility modules\n\nExamples include Positioner, Scrollbar, VirtualList, FocusTrapElement,\nAutoScroll, motion, History, geometry helpers, measurement, theme tokens, and\nglobal initialization.\n\nThese are deep modules: a small interface hides layout, lifecycle, or data\nstructure complexity used by many controls. Their interface is also their test\nseam; callers should not need to reproduce the hidden algorithm to verify it.\n\n## State Ownership\n\nState ownership follows behavioral needs rather than one universal pattern.\n\n### Controlled values\n\nCheckbox, Radio, Switch, Toggle, Select, and similar roots accept the current\nvalue and report requested changes. They do not silently mutate application\nstate.\n\n```text\napplication value\n      │\n      ▼\nbase element ── activation ──▶ on_change(next_value)\n      ▲                            │\n      └──── next render ───────────┘\n```\n\nCallbacks describe intent. Pointer-originated value changes include the\n`ClickEvent` when modifier keys are useful. Model-driven changes, such as\npagination requests, do not invent a pointer event.\n\n### Handles and explicitly shared state\n\nDialog supports `DialogHandle` for imperative open and close requests while\nstill reporting `DialogChangeReason`. Scrollbar adapters share an underlying\nscroll handle. Toast stack geometry is shared through `ToastStackState`.\n\nHandles coordinate one logical behavior. They must not be reused across\nunrelated viewports or component instances.\n\n### Entity-backed state\n\nComplex modules use `Entity<State>` when they need GPUI observation,\nsubscriptions, focus handles, or incremental notification. The state entity owns\nbehavioral data; the presentation layer still owns how that data looks.\n\n### Keyed element state\n\nSmall pieces of ephemeral state tied to an element identity use\n`window.use_keyed_state`. Stable `ElementId` values are therefore part of the\ninterface, not an implementation detail. Changing an ID can reset focus,\nmeasurement, animation, or open-state bookkeeping.\n\n## Styling Model\n\nBase separates three styling mechanisms:\n\n1. ordinary GPUI `Styled` calls for instance presentation;\n2. typed semantic-state style builders such as checked, selected, or disabled;\n3. GPUI native runtime modifiers such as hover, active, and focus-visible.\n\nThe shared `state_style::resolve_style` function makes semantic precedence\nconsistent across controls. See [Styling and Motion](STYLING-AND-MOTION.md) for\nthe complete contract.\n\nCompound and stateful modules expose explicit presentation seams:\n\n- GPUI `Styled` on the root or part;\n- application-provided children;\n- typed part elements;\n- item renderer callbacks;\n- style refinements for internal virtualized containers;\n- presentation snapshots such as `InputPresentation`.\n\n## Public Data Types Across the Seam\n\nA public struct that crosses the base/application seam must not expose `pub`\nfields. Every field a caller can name is a field that cannot be added later:\nadding one breaks any struct literal, and removing or renaming one breaks every\nreader. The seam types are the ones that grow the most, because each new\ncapability of a control shows up as another flag in the state it hands out.\n\nThe shape to use instead:\n\n- private fields;\n- a builder for construction — `new()` plus one chained setter per field;\n- a reader per field.\n\nSetters and readers must not collide, which decides the naming:\n\n- a type whose fields are all boolean names its setters after the field and its\n  readers `is_<adjective>`/`has_<noun>`, never `can_`, matching how elements\n  read — `CalendarItemState`, `InputContextMenuCapabilities`;\n- a type carrying non-boolean fields prefixes every setter with `with_`, so the\n  readers keep the plain field name — `RenderOptions::with_item_ix` against\n  `RenderOptions::item_ix`. This follows `Sizable::with_size`.\n\nA `with_`-style setter that takes `self` by value also replaces functional\nupdate syntax, which stops compiling once the fields are private:\n\n```rust\n// was: RenderOptions { item_ix, ..*options }\nitem.render_item(&options.with_item_ix(item_ix), window, cx)\n```\n\nA type that is only ever built inside its own module — `InputPresentation` is\nbuilt by `InputBaseState::presentation` and nowhere else — needs the private\nfields and the readers, but not a public builder. Private fields already close\nthe breaking-change hole, and a public builder there would hand out a\nconstruction path the seam does not want. Such a type reads its non-boolean\nfields under the plain field name, which is why it cannot also carry\nfield-named setters.\n\n```rust\nlet capabilities = InputContextMenuCapabilities::new()\n    .code_editor(true)\n    .selection(true);\n\nif capabilities.is_editable() && capabilities.has_selection() { /* ... */ }\n```\n\nDerived answers belong on the type rather than at each call site. When several\nreaders are always combined the same way — `!disabled && !readonly` — publish\nthat combination as its own reader (`is_editable`) so the rule has one\ndefinition and new inputs to it stay invisible to callers.\n\nName such a type in full: `ComboboxTriggerContext`, never `…Ctx`. In a GPUI\ncodebase `cx` is reserved for `App`, `Context<T>`, and `AsyncApp`, so an\nabbreviated `ctx` for anything else reads as a second, competing context. A\ncallback that receives both takes the GPUI one as `cx` and gives the other a\nname describing what it holds.\n\nThis applies to state snapshots (`InputPresentation`, `CalendarItemState`),\ncapability sets (`InputContextMenuCapabilities`), render contexts\n(`ComboboxTriggerContext`), and option sets (`RenderOptions`). It does not\napply to value types whose fields _are_ the definition and cannot grow, such as\n`Point`, `Selection`, `Edges`, `IndexPath`, or `FoldRange`, nor to types that\nmirror an external schema, such as the LSP `Diagnostic`.\n\nDesign-token records (`ColorTokens`, `RadiusTokens`, and the rest of\n`theme_tokens`) still carry `pub` fields. They have the same growth problem, and\nconverting them is tracked separately because every theme in `gpui-component`\nconstructs them.\n\n## Input, Textarea, and Editor Architecture\n\nText editing is intentionally deeper than the semantic elements, but callers do\nnot need to learn the complete editor interface for every text field.\n\n### Public forms\n\nBoth `gpui-base` and `gpui-component` expose three purpose-specific forms:\n\n| Form       | State           | Intended interface                                                                                        |\n| ---------- | --------------- | --------------------------------------------------------------------------------------------------------- |\n| `Input`    | `InputState`    | Single-line values, placeholders, masks, validation, and submission                                       |\n| `Textarea` | `TextareaState` | Ordinary multi-line text, fixed rows, soft wrapping, and optional auto-grow limits                        |\n| `Editor`   | `EditorState`   | Source text, language-aware highlighting, line numbers, folding, search, diagnostics, and LSP integration |\n\n`gpui-base` provides unstyled forms. `gpui-component` adapts the same behavior\ninto the product theme and sizing system. `InputBase` is the foundational frame\nused for input semantics, state styling, accessibility, and application-owned\ncontent; it is not one of the three editing forms.\n\nExisting `gpui-component::Input::new(&Entity<InputState>)` call sites remain the\nsingle-line compatibility path. `InputState` is a real facade, not a type alias\nfor the editing engine: multiline, auto-grow, gutter, folding, diagnostics, and\nLSP configuration are absent from its API. Multi-line code must construct\n`TextareaState` or `EditorState` instead.\n\n### Shared engine\n\n`InputBaseState` owns mechanics shared by all three states:\n\n- Rope-backed text and edit history;\n- cursor, selection, IME, clipboard, and focus;\n- shaping, layout, hit testing, selection and caret painting;\n- auto-scroll, viewport scrolling, and cursor visibility;\n- native text-content integration where supported.\n\nThe implementation under `crates/base/src/input` is organized by responsibility:\n\n- `base/` contains the shared editing engine and foundational mechanics;\n- `input/` contains the single-line control and state facade;\n- `textarea/` contains the multi-line control and state facade;\n- `editor/` contains the editor control and state facade, plus display mapping,\n  highlighting, search, diagnostics, decorations, indentation, and LSP.\n\nThese are implementation folders rather than public Rust module segments. The\nexternal seam remains `gpui_base::input`, with stable re-exports in `mod.rs`.\n\nPurpose-specific state facades configure the shared engine and forward\n`InputEvent` without duplicating those mechanics. `InputState`, `TextareaState`,\nand `EditorState` are distinct GPUI entity types. Their private bridge to\n`InputBaseState` exists for component composition; it is not the application\nAPI.\n\nEditor-only implementation includes indentation, folding, decorations,\ndiagnostics, search, LSP providers, overlays, line-number/gutter painting, and\nsyntax highlighting. Textarea owns rows, soft wrapping, Enter submission, and\nauto-grow policy. Masking, validation, and number stepping remain input-only\nconcepts.\n\n### Presentation and geometry\n\nPresentation is injected through `InputEditorStyle`, highlighter interfaces,\nfold-icon renderers, context-menu adapters, and the higher-level UI forms.\n`gpui-component` supplies editor insets from its size system. Base consumes\nthose insets only as geometry so text, the fixed gutter, and scrollbars share a\ncoordinate system:\n\n- text remains inset from the frame;\n- vertical and horizontal scrollbars terminate at the frame edge;\n- the gutter background covers the complete fixed column, including top,\n  bottom, and leading insets;\n- editor focus does not add the single-line input focus-border treatment.\n\nThis keeps product values in the presentation layer while keeping coupled text,\ngutter, and scrollbar geometry local to the editing engine.\n\n### Input groups\n\n`gpui-component::input::InputGroup` composes one `Input` or `Textarea` with typed\naddons and buttons in a shared frame. It owns no editing state: the control is\nthe ordinary styled `Input`, rendered without its own border, background and\nfocus ring, so every capability the input gains — paste hooks, touch\nselection, native menus, accessibility — reaches a group without being\nmirrored. `InputGroup` owns the outer border, radius, focus and error\ntreatment, and four logical addon regions; `InputGroupButton` wraps a `Button`\nwith compact presentation and sizes through `Sizable`. Textarea viewport\ngeometry remains with the editing engine. Validation appearance is\ncaller-controlled, separately from edit acceptance.\n\nPlatform-specific behavior is isolated behind adapters. For example, folding is\ndisabled on WebAssembly, time uses `web_time` where needed, and native text\ncontent support is conditionally compiled.\n\n## Text Rendering for External Components\n\n`gpui_base::text::editor_host` adapts the same renderer used by `TextView`.\nIt is a rendering boundary for externally owned rich-text components, not an\nediting engine. The host projects its own document into `BlockNode` values;\nBase owns shaping, wrapping, inline-object layout and geometry. The host owns\ndocument identity and revisions, editing semantics, commands, history, selection,\nfocus, accessibility integration, native input and scrolling policy.\n\n### Identity and lifecycle\n\nThere are two independent identities. A stable GPUI element ID scopes retained\nrender state; `BlockNode::render_with_id` provides that scope for top-level\nblocks. Leaf keys identify geometry and decorations within one collection.\nKeys must be unique in that collection. Cloning the AST shares runtime state;\ncalling `with_leaf_key` detaches the leaf's runtime text/selection state so\nrekeying a clone does not rename the original leaf. Independently rendered\ninstances need distinct keys.\n\nRun `collect_leaf_geometry` around child prepaint, not rendering or painting.\nThe scope is synchronous, nests with isolation and restores its predecessor\nduring unwinding. Only prepainted leaves are reported. A virtualized or cached\nsubtree that does not prepaint is absent; a missing entry does not remove a leaf\nfrom the host document.\n\n`LeafGeometry` copies bounds and retains immutable shaped lines. It does not\nretain mutable `TextLayout` handles. A later frame cannot change an existing\nsnapshot, but that snapshot describes only its original content, typography,\nwidth and scroll offset. Hosts must associate geometry with their own document\nrevision and replace it when those inputs change.\n\n### Coordinates and presentation\n\nLeaf offsets are UTF-8 bytes. Each inline image or custom inline node occupies\none U+FFFC (three bytes), independent of its fallback text. Window coordinates\nare logical pixels, before display scaling. Hard breaks and empty lines retain\ncaret positions, including the final empty line. Native input APIs that use\nUTF-16 require conversion in the host.\n\nDecorations are ordered half-open byte ranges. Text decorations paint behind\nglyphs. Any nonempty overlap with an atom decorates its entire box, over the\ncontent, so an opaque image can show its selected state. The host supplies the\ncolor and should use translucency for an atom overlay. Empty ranges paint\nnothing. Decorations do not change layout.\n\n`RenderContext::new` accepts local presentation without application globals;\n`from_app` uses TextView defaults. A host can override syntax highlighting,\nimage resolution and link activation locally. Reference links need definitions\nfrom the entire document, including blocks outside the viewport. Register them\nthrough `with_link_reference`.\n\n### Evolution boundary\n\nKeep the sink, layout caches, flow fragments and shaping implementations private.\nThe public AST is a projection into the renderer, not a canonical editor model\nor persistence format. Do not add editor-specific document operations, history,\ncollaboration or serializer policy to Base merely to serve one consumer.\n\nThis boundary currently supports horizontal text rendered through TextView's\nblock flow. It is not a complete contract for every future editor. In particular,\na future extension for visual navigation must represent caret affinity at soft\nwraps and bidirectional runs; a byte index alone is insufficient. Per-position\ncaret metrics and range rectangles should be designed together with that\ncontract, not inferred from one leaf-wide line height. Pagination, arbitrary\nblock-level widgets, native accessibility text ranges and vertical writing need\ntheir own demonstrated requirements and contract tests before being promised.\n\nThe newly public `BlockNode` enum is non-exhaustive so variants may be added.\nIts existing named variant fields still constrain changes to those variants;\nnon-exhaustiveness is not permission to rename fields or add required fields.\nPrefer new private-field option types and additive constructors when extending\nthe seam. Preserve existing public types and import paths; a pre-1.0 disclaimer\ndoes not replace this project's compatibility requirement.\n\n## Overlay and Positioning Architecture\n\nOverlay modules separate lifecycle from placement and presentation.\n\n### Positioner\n\n`Positioner` is the shared placement implementation. It supports:\n\n- side placement with preferred-side selection, flipping, alignment, offset,\n  and viewport clamping;\n- corner placement compatible with anchored trigger geometry, with viewport\n  clamping but no side flip.\n\nPopup measures its trigger during prepaint, stores the captured bounds in keyed\nstate, and renders positioned content through a deferred element on the next\nframe. Tooltip reuses Positioner rather than maintaining another collision\nalgorithm.\n\n### Modal hosts\n\nDialog and Sheet create viewport-sized hosts. They own focus trapping, keyboard\nactions, backdrop or overlay dismissal, and callback ordering. They do not own\nthe final popup or panel placement: the application styles the supplied popup or\nsurface as centered, right-aligned, bottom-aligned, or another product-specific\nlayout.\n\nOverlay visuals and overlay hit targets are separate layers. The surface is\npainted above the dismissal target so a click inside content does not dismiss\nthe modal.\n\n## Scrolling and Virtualization\n\n`ScrollbarHandle` is the seam between scrolling implementations and the shared\nScrollbar element. An adapter reports:\n\n- viewport bounds;\n- current offset;\n- content size;\n- offset updates;\n- optional drag lifecycle notifications.\n\nAdapters exist for GPUI `ScrollHandle`, `UniformListScrollHandle`, and\n`ListState`, plus base `VirtualListScrollHandle`.\n\nScrollbar normally overlays the viewport reported by its handle. Two explicit\nalternatives support deeper widgets:\n\n- `viewport_bounds` supplies custom-painted bounds, as the editor does;\n- `viewport_from_layout` uses same-frame layout bounds, as DataTable does when\n  excluding fixed headers and columns.\n\nVirtualList owns variable-size item layout, visible-range calculation, content\nmasking, deferred scroll-to-item requests, and clamped offsets. The caller owns\nitem sizes and renders only the requested range. Tree builds on GPUI's uniform\nlist because its visible entries share a row height.\n\n`ScrollableMask` owns wheel dispatch, not scrolling. GPUI's own overflow\nlistener runs in the bubble phase and never stops propagation, so a scroll area\nnested inside another one cannot win: `gpui::list` registers its listener after\nits items paint, and bubble runs in reverse registration order. The mask is a\nsibling of the scrolled element that consumes axis-dominant wheel events in the\ncapture phase, locks each gesture to the axis it started on, and stays inert\nwhile occluded. Edge semantics differ per axis, matching platform scrollers: a\nvertical mask chains to the ancestor at the edge, a horizontal one keeps\nconsuming. `horizontal_scroll_area` is the paired viewport and mask, used by the\nMarkdown scrolling table. A Markdown code block whose style sets `overflow.y` to\n`Overflow::Scroll` pairs its viewport with a vertical mask and a `Scrollbar`.\n\nA plain mouse wheel has only a vertical axis, which a native horizontal scroller\nwith a locked axis ignores. `ScrollableMask::vertical_wheel` sits over such a\nscroller and handles only that wheel: its lines move the scroller sideways and,\nat the edge, chain to the ancestor; trackpad gestures and horizontal wheels go\non to the scroller with its axis lock and bounce. TabBar, the attachment row,\nthe app menu bar and a horizontal `Scrollable` use it. The mask is pinned to its\nparent's top-left corner, so it covers the parent in a row as in a column.\n\nOne handle represents one logical viewport. Sharing a handle between nested or\nunrelated scroll areas causes offsets, hitboxes, and scrollbar geometry to\ninterfere.\n\n## Dock Layout Architecture\n\n`crates/base/src/dock` owns the layout tree, persistence, drag hit-testing,\nresize arithmetic, the active-panel state machine, zoom, focus, and the panel\nregistry. `crates/component/src/dock` is a skin: `DockSkin` implements the renderer\ntraits below to supply the tab bar, toolbar, drop-indicator, and dock-toggle\nappearance. A `DockArea` built without a renderer still docks, drags, and\npersists — it draws no chrome at all.\n\n### The layout tree\n\n`PaneTree` is the single source of truth for one region — the center, or\none of the left/bottom/right docks. It stores no GPUI entity handles:\ncontainers are addressed by `NodeId`, panels by `PanelId` (the panel entity's\n`EntityId`), and a container's `NodeKind` is one of `Split` or `Tabs`. There\nis no leaf variant, so a panel can only ever live inside a `Tabs` node — the\ninvariant a runtime assertion checked in the old implementation is expressed\nin the type instead.\n\n`NodeKind` stays private. Callers read a node through the borrowed `PaneRef`\nprojection and never construct one directly; every mutation goes through\n`PaneTree`'s edit methods (`insert_panel`, `remove_panel`, `move_panel`,\n`split`, `set_active`, `set_sizes`), each\nof which runs `normalize` before returning. When base needs a fact about a\npanel — its name, its visibility, its dump — it asks a `PanelSource` rather\nthan the entity directly, which is what makes the layout algebra testable as\npure functions with no `TestAppContext`.\n\nBuilding a layout is entity-free too: `DockLayout` (`h_split`, `v_split`,\n`tabs`, chained with `.child(...)`, `.panel_view(...)`, and\n`.active_index(...)`) produces a tree rather than\nconstructing containers. `DockArea::set_center` and `set_dock` reconcile a\n`DockLayout` into live entities when it is installed.\n\nPanels go in wrapped: `gpui_component::dock::panel_handle(panel)` is what\ncarries a panel's presentation across the renderer seam, and every entry point\ntakes one — `DockLayout::panel_view` when describing a layout,\n`DockArea::add_panel_view` when adding to a live one, and\nthe closure a `register_panel` builder returns.\n\n```rust,ignore\nlet center = DockLayout::h_split()\n    .child(DockLayout::tabs().panel_view(panel_handle(files), cx), Some(px(240.)))\n    .child(DockLayout::tabs().panel_view(panel_handle(editor), cx), None);\ndock_area.update(cx, |area, cx| area.set_center(center, window, cx));\n```\n\nBase's own `DockLayout::panel` and `DockArea::add_panel`\ntake a bare `Entity<P>` instead. They are the base-only forms: the panel docks,\ndrags and persists exactly the same, but base stores the bare entity and the\nskin cannot recover presentation from it, so **every tab draws the panel's\n`panel_name` where its title belongs**. The only signal is a one-off\n`tracing::warn!`. Use them only when there is no skin over the dock at all.\n\n### Normalization\n\nOne post-order pass, repeated to a fixpoint, replaces the mutually recursive\nparent-pointer collapse the old `StackPanel`/`TabPanel` pair used:\n\n1. An empty `Tabs` or `Split` is removed from its parent; the root\n   is exempt.\n2. A `Split` with one child is replaced by that child, which keeps its own\n   `NodeId` and inherits the split's slot size.\n3. A `Split` containing a `Split` of the same axis splices the inner\n   children into the outer node.\n4. `active_ix` is clamped to the panel count.\n5. Root shape is enforced per `RootKind` — the center's root is always a\n   `Split`, so an empty center still serializes as a stack; a dock's root is\n   unconstrained.\n\n`normalize` is idempotent and needs no parent pointers or deferred work: the\ntree is self-consistent the instant an edit operation returns.\n\n### Reconciliation\n\n`DockArea` holds the tree plus a cache of container and panel entities keyed\nby `NodeId` and `PanelId`. After any edit that reports a change, it walks the\ntree, creates an entity for each container id the cache does not yet have,\ndrops cache entries for ids no longer present — calling `on_removed` on the\npanels that departed — pushes sizes and `active_ix` into the surviving\nentities, and emits `DockEvent::LayoutChanged`.\n\nBecause `NodeId` survives every edit operation and every `normalize` rule, a\nsteady-state reconciliation pass creates and drops nothing: only genuinely\nnew or dead containers churn. That is what keeps a drag from resetting the\nstate of panels it did not touch.\n\n### Rendering seam\n\n`TabGroup` owns the panel list mirrored from the tree, the active index, the\nfocus handle, drag-and-drop hit state, and the zoom flag; it renders a\nskeleton and delegates all appearance to a `TabGroupRenderer`.\n`DockAreaRenderer` does the same for the area frame and the docks. Base\nattaches the drag source, drop-target hit testing, keyboard actions, and focus\nhandling — a renderer implementation never sees a drag event, only resolved\nstate through `TabGroupContext` and `DockContext`.\n\n`Panel` splits at the seam the same way: `gpui_base::dock::Panel` covers\nbehavior (`panel_name`, `visible`, `closable`, `zoomable`, `set_active`,\n`set_zoomed`, `on_added_to`, `on_removed`, `dump`), and\n`gpui_component::dock::Panel` extends it with presentation (`title`,\n`tab_name`, `toolbar_buttons`, `dropdown_menu`, `zoom_control`). A panel type\nimplements both.\n\n## Theme Projection\n\nThe base `Theme` contains:\n\n- `SemanticThemeTokens` for colors, radius, spacing, typography, and shadows;\n- global Scrollbar defaults;\n- the minimal Resizable handle colors required by its infrastructure.\n\nSemantic tokens describe roles and scales, never component names. They do not\nautomatically style base controls. A presentation layer reads and applies them.\n\n`gpui-component` projects its active theme into the base theme during\ninitialization and theme changes. Direct base users can mutate\n`gpui_base::Theme::global_mut(cx)` themselves.\n\n## Motion and Lifecycle\n\nOrdinary semantic controls do not install product motion. The generic\n`motion::transition` function manages keyed interpolation, timing, reversal,\nanimation frames, and reduced-motion behavior while the caller chooses the\nanimated property.\n\nSome deep behavior modules own configurable motion that is inseparable from\ntheir layout lifecycle. `ToastStack`, for example, owns stack expansion,\ncollapse, measurement, and overlap motion through `ToastMotion`. Its child\n`Toast` remains an unstyled semantic root, and the application owns toast\ncontent and visual styling.\n\nThis distinction is intentional:\n\n- product decoration and choreography belong to presentation;\n- motion required to keep a deep behavioral layout coherent may live in that\n  module and must be configurable.\n\n## Initialization\n\nCall `gpui_base::init(cx)` before constructing base controls. Initialization:\n\n- installs the base global theme if absent;\n- initializes shared global state;\n- reads the operating system's reduced-motion preference into\n  `App::set_reduce_motion` (see `reduce_motion.rs` for the per-platform\n  sources and the rule that an application's own setting wins);\n- registers key bindings and infrastructure for dialog, focus traps, popover,\n  sheet, combobox, color picker, select, number input, input, and tree.\n\nApplications that call `gpui_component::init(cx)` must not initialize base a\nsecond time; the styled crate includes base initialization.\n\n## Relationship to `gpui-component`\n\n`gpui-component` is a presentation adapter and compatibility layer above base.\nIt may:\n\n- map its Theme into base tokens and infrastructure defaults;\n- wrap base elements with labels, icons, sizes, variants, and product layout;\n- provide application-specific popup menus, LSP views, and native integrations;\n- preserve historical public interfaces while delegating behavior to base.\n\nThe migration of a UI control to a base module is complete only when behavior,\nfocus, keyboard interaction, accessibility, overlay geometry, and visual output\nremain correct. Sharing a type name or compiling an adapter is not sufficient.\n\n## Design Invariants\n\nChanges to `gpui-base` should preserve these invariants:\n\n1. Base remains independent of `gpui-component` presentation and assets.\n2. Reusable behavior is implemented once behind the lowest useful interface.\n3. Applications can replace the visual language without reimplementing the\n   behavior module.\n4. Behavioral geometry stays with the module that must keep it correct.\n5. Controlled elements report intent and do not own application values.\n6. Stable element identity is documented wherever keyed state is used.\n7. Pointer and keyboard paths converge on the same semantic action.\n8. Accessibility is behavior, not optional decoration.\n9. Overlay coordinates, paint order, and hitboxes use one viewport model.\n10. One scroll handle represents one logical viewport.\n11. Platform differences are isolated behind explicit adapters or conditional\n    implementations.\n12. Public types that cross the seam keep their fields private, are built with a\n    builder, and are read through methods, so a new field is not a breaking\n    change.\n13. Long-lived architectural facts belong here; progress logs and temporary\n    reviews belong in issues and pull requests.\n","skills/gpui-kit-design-guides/SKILL.md":"---\nname: gpui-kit-design-guides\ndescription: The normative Design Guides for GPUI Kit desktop applications. Read in full before designing or changing any screen, layout, spacing, visual hierarchy, color, density, component choice, interaction state, overlay, motion, data-heavy view, or interface copy in a GPUI Kit (gpui-kit / gpui-component) application, and before reviewing UI work for design quality. Also use when asked what the design rules are, or whether a UI decision follows them.\n---\n\n# GPUI Kit Design Guides\n\nThe guide is [references/design-guides.md](references/design-guides.md). It is\na requirement, not inspiration. Read the guide file itself before doing UI\nwork. Do not answer from this page, from an existing screen in the codebase, or\nfrom training data.\n\nIf the file is missing, fetch `https://gpui-kit.com/docs/design-guides.md`.\nThe guide is a verbatim copy of that page, so its link to `./coding-guides.md`\nmeans the Coding Guides in the `gpui-kit` skill (or `https://gpui-kit.com/docs/coding-guides.md`).\n\n## How to read it\n\nRead the whole guide for a new screen or a redesign. For a narrow change, read\n\"Design thesis\" and \"Start from the task\" first, then the section for the\nchange. Sections, in order (`grep -n '^## ' references/design-guides.md`):\n\n| Section                              | Read when                                                              |\n| ------------------------------------ | ---------------------------------------------------------------------- |\n| Design thesis                        | Always                                                                 |\n| Learning from Shadcn                 | Choosing what to borrow from web component libraries                   |\n| Start from the task                  | Always; task hierarchy, interaction promise, what to leave out         |\n| Visual language                      | Color, typography, spacing, radius, borders, elevation, density, icons |\n| Layout patterns                      | Window structure, sidebars, toolbars, panels, forms, resizable regions |\n| Components and composition           | Picking a component, composing parts, when to build a new one          |\n| Interaction states                   | Hover, focus, pressed, selected, disabled, loading, validation, danger |\n| Feedback and overlays                | Dialog, sheet, popover, menu, notification, tooltip, dismissal, focus  |\n| Motion                               | Any animation or transition                                            |\n| Designing data-heavy interfaces      | Tables, lists, trees, dashboards, dense inspectors                     |\n| Interface language                   | Any user-facing text: labels, buttons, titles, errors, empty states    |\n| Internationalization and platform fit | Multi-locale copy, Chinese terminology, macOS/Windows conventions     |\n| Guidance for AI-generated interfaces | Always when an agent produces UI                                       |\n| Accessibility checklist              | Before finishing                                                       |\n| Design review checklist              | Before finishing; run every item against the work                     |\n\n## Non-negotiables\n\nA floor, not a substitute for the guide.\n\n- **Desktop before web convention.** Keyboard access, window chrome, menus,\n  dense data views, resizable regions, persistent navigation.\n- **`Button` vs `Link`.** `Button` for every in-app command, `ghost` or\n  `outline` when it should read quietly. `Link` only for external URLs and\n  email addresses.\n- **Tokens before values.** No raw hex or `rgb(...)`; use `cx.theme()`\n  semantic tokens and rem-based helpers. Any spacing number quoted in the guide\n  is the current default scale, not a literal to repeat.\n- **State must be visible.** Hover, focus, selection, disabled, loading,\n  validation, and destructive states each need distinct, consistent treatment.\n- **Overlays.** Escape dismisses the topmost surface and returns focus to its\n  trigger.\n- **Copy.** Name the object and the verb: `Delete \"Roadmap\"?` with a `Delete`\n  button, not `Are you sure?` with `OK`.\n\nFinish by running the Design review checklist against the work.\n","skills/gpui-kit-design-guides/references/design-guides.md":"---\ntitle: Design Guides\ndescription: Product and interaction design guidance for GPUI Kit applications\norder: -12\n---\n\n# Design Guides\n\nUse this guide before choosing components or writing layout code. It records\nthe product judgment accumulated through years of GPUI Kit desktop work:\nan interface should feel native, restrained, precise, and understandable\nwithout guesswork.\n\nThis is a normative guide. **Must** identifies a correctness or ecosystem\nconstraint, **should** is the default that needs a concrete reason to override,\nand **may** is an optional technique. Component API documentation remains the\nauthority for individual methods.\n\nThe rules build on behavior in `gpui-base`, the GPUI Component theme and\ncomponent system, and familiar desktop interaction. <a href=\"https://ui.shadcn.com/docs\" target=\"_blank\" rel=\"noopener noreferrer\">shadcn/ui</a> contributes useful\nmethods—open code, composition, and dependable defaults—but does not determine\nhow a GPUI application should look. When influences conflict, preserve GPUI's\nlifecycle constraints and the interaction people already understand.\n\n## Design thesis\n\nBuild interfaces that feel native, quiet, and precise. Let content, hierarchy,\nand interaction carry the experience; decoration should support them rather\nthan compete with them.\n\n1. **Clarity before personality.** Make the primary task and next action clear\n   before adding brand expression.\n2. **Composition before invention.** Start with established components and\n   compose them into product-specific workflows. Create a new primitive only\n   when its behavior is genuinely new.\n3. **Tokens before values.** Colors, radii, typography, and spacing should form\n   a system. Avoid isolated literals that cannot respond to themes. See\n   [Style](./style) for GPUI's styling API.\n4. **Desktop before web convention.** Preserve keyboard access, window chrome,\n   menus, dense data views, resizable regions, and persistent navigation where\n   the task benefits from them.\n5. **State must be visible.** Hover, focus, selection, disabled, loading,\n   validation, and destructive states need distinct and consistent treatment.\n6. **Geometry explains containment.** Radii, insets, and boundaries should\n   describe one coherent hierarchy, even where surfaces overlap.\n7. **Feedback reflects reality.** Loading, tooltips, and motion should clarify\n   a real state or transition, not add ceremony to an immediate action.\n\n## Learning from Shadcn\n\nShadcn's most useful contribution is not a particular border color. It is a\nway of building a system:\n\n- own the top layer of the interface instead of fighting a sealed abstraction;\n- compose small, predictable parts into product-specific components;\n- provide defaults that already form one visual language;\n- keep the code and composition legible to both people and AI;\n- separate behavior primitives from the styled layer.\n\nGPUI Kit applies those ideas through a Rust library and the split between\n`gpui-base` and `gpui-component`. Applications normally compose or wrap the\npublished components; contributors move genuinely reusable behavior into Base\nand keep visual policy above it.\n\nDo not copy these web assumptions blindly:\n\n| Web habit | Native GPUI default |\n| --- | --- |\n| Pointing-hand cursor on every button | Default arrow cursor; pointing hand for links |\n| Page navigation as the main structure | Persistent windows, panes, sidebars, tabs, and menus |\n| Browser focus and scrolling as a fallback | Explicit focus ownership and region-owned scrolling |\n| Mobile-first single column | Resizable desktop shell with a defined minimum window size |\n| Hover-revealed critical actions | Keyboard- and pointer-reachable actions that do not depend on hover |\n| A row of hover-only icon buttons | A visible primary action plus `DropdownMenu` or `ContextMenu` for secondary commands |\n| Link-styled text for application commands | `Button`, `outline`, or `ghost`; Link only for URLs, web resources, or email addresses |\n| Large touch density everywhere | Medium density by default; compact only where information work benefits |\n| CSS overrides across descendants | Typed builders, semantic parts, and application composition |\n\n## Start from the task\n\nBefore drawing a screen, write down:\n\n- the user's primary task;\n- the object being viewed or changed;\n- the actions that must remain immediately available;\n- the information required to make a decision;\n- empty, loading, error, offline, read-only, and permission-denied states;\n- the keyboard path through the workflow.\n\nOrganize the window around those answers. Do not begin with a dashboard grid or\na component catalogue. A good desktop interface exposes the user's mental\nmodel: documents, accounts, projects, messages, settings, or another stable\nobject—not the internal service architecture.\n\nDesign the primary task before distributing controls. Its visual weight,\nlocation, and information depth should match its importance to the product. A\ncore result must not be reduced to a small count, an icon in a corner, or a\nweak footer action while secondary content consumes the page. When a result set\nis the product's main value, consider a summary region or card that exposes the\ncount, representative results, meaningful state, and a clear next action.\n\nFor every proposed action, name its visible object, current state, scope, and\nresult. If the interface does not show or clearly imply those things, the\naction is premature. Do not expose a capability merely because the backend has\nit; first design how the object enters the user's mental model.\n\n## Visual language\n\n### Hierarchy\n\nPrefer a small number of clear levels:\n\n- **window or page title** identifies the current object or workspace;\n- **section title** separates meaningful regions;\n- **body text** carries the work;\n- **muted text** provides secondary metadata and help;\n- **labels** identify controls and values.\n\nUse size, weight, spacing, and separators before adding color or containers.\nAvoid nesting cards inside cards: most desktop regions need only a background,\na hairline boundary, and intentional spacing.\n\nEvaluate hierarchy across the whole feature, not component by component. Hide\naccent color and decoration during review: the primary task, current selection,\nresult summary, and next action should still be obvious from structure. A\nscreen that contains individually plausible controls can still fail when they\ndo not form one reading order and one decision path.\n\nTreat emphasis as a limited budget. A local surface needs one clear focal point,\nnot a field of competing highlights. If everything is colored, badged, bold,\nboxed, or promoted to an alert, nothing reads as important. Establish priority\nwith structure and proximity first; spend stronger color and components only\nwhere a distinction changes what the user notices or does.\n\n### Color and themes\n\nRead colors from `cx.theme()` and use them by semantic role:\n\n- `background` and `foreground` for the main surface and text;\n- `group_box`, `popover`, `sidebar`, and their foreground tokens for their\n  named surfaces;\n- `muted` and `muted_foreground` for supporting information;\n- `primary` for the principal action or selection emphasis;\n- `danger`, `warning`, `success`, and `info` only for their meanings;\n- `border`, `input`, and focus-ring tokens for structure and interaction.\n\nDo not use a semantic status color as decoration. Do not encode meaning by\ncolor alone. Verify every custom surface in light and dark themes and with\ncustom theme values; never assume that foreground is black or background is\nwhite.\n\nUse Badge for a short state, count, or classification that benefits from rapid\nscanning—not for every label, metadata value, filter, or section title. Keep\nmost badges neutral; reserve semantic variants for states that truly carry\nsuccess, warning, danger, or informational meaning. A row of multicolored\nbadges is usually a missing hierarchy or grouping decision.\n\nApplication UI should not contain raw hex, `rgb`/`rgba`, or `hsla` colors.\nResolve colors from `cx.theme()` by semantic role. If the required role does\nnot exist, define it in the product's theme/token layer rather than embedding a\npalette value at the call site. Raw colors belong only inside theme definitions\nor in audited data/raster content whose color is itself the data.\n\n### Radius, spacing, and density\n\nUse a finite radius scale, as with type and control sizes. Choose from the\ntheme's named tiers (`sm`, `md`, `lg`, `xl`, and larger surface tiers) instead\nof inventing a radius for each element. Large containers may use a softer tier\nthan the controls they contain; compact controls and overlays use tighter\ntiers. For an ordinary rectangle, the radius should remain visibly smaller\nthan half its shorter side. Use `radius_full()` only for intentional circles\nand pills; a tooltip must not become a capsule by accident.\n\nNested surfaces should read as concentric shapes. Use\n`inner radius ≈ max(0, outer radius − gap)` to choose the closest suitable\ntheme tier; the visible band should remain even through the turn. Add a\nnamed application token if a repeated composition needs an intermediate\nvalue. A segmented control is one silhouette: its end segments follow the container's inner\ncorners, its middle segments remain square, and each boundary has one divider\nof consistent thickness.\n\n<img class=\"alignment-light\" src=\"/radius-hierarchy.svg?v=20260923-easing\" alt=\"Light theme chat composer: the inset surface, both buttons, and placeholder spacing change together; red guide circles show their shared corner center.\">\n<img class=\"alignment-dark\" src=\"/radius-hierarchy-dark.svg?v=20260923-easing\" alt=\"Dark theme chat composer: the inset surface, both buttons, and placeholder spacing change together; red guide circles show their shared corner center.\">\n\nA radius must govern the entire visible surface, not just its border. Exposed\ncorners remain transparent to the surface behind them; child backgrounds,\nselection fills, and scrolling content must also follow the boundary. In GPUI,\ndo not assume a rounded parent clips its descendants. Give inner surfaces their\nown radius or an appropriate clip, then inspect the composition against a\ncontrasting background in both themes. Preserve outward focus rings when\nchoosing a clip.\n\nUse a compact spacing scale and repeat it. Related label/control pairs should\nbe closer than separate groups; separate groups should be closer than separate\nsections. Prefer component sizes (`xsmall`, `small`, default medium, `large`)\nover one-off heights. Use compact variants for toolbars and data-dense screens,\nnot to squeeze an unclear layout into less space.\n\nThe shared semantic scale is intentionally small: spacing progresses through\nroughly 2, 4, 8, 12, 16, 24, and 32 pixels, while typography stays near 12,\n14, 16, 18, and 20 pixels. Treat these as relationships rather than permission\nto scatter their current values through feature code. GPUI Component currently\nprojects a fixed default `SpacingTokens` scale from its global `Theme`; unlike\ncolors and radii, `Theme::apply_semantic_tokens` does not persist a custom\nspacing scale. An application that needs different spacing must own that full\ntoken snapshot and use it consistently in its application components.\n\n### Spatial grammar\n\nSpacing expresses relationship. Choose a gap from the semantic scale by asking\nwhat the two things mean to each other:\n\n| Relationship | Typical token | Current scale | Examples |\n| --- | --- | --- | --- |\n| Optical correction | `xxs` | 2 px | icon baseline, compact separator |\n| Parts of one control | `xs` | 4 px | menu icon/label, title/description |\n| Closely related controls | `sm` | 8 px | button icon/label, dialog actions |\n| One content group | `md` | 12 px | notification columns, compact form rows |\n| Separate groups in one section | `lg` | 16 px | panel padding, form groups |\n| Separate sections | `xl` | 24 px | major blocks in a page or inspector |\n| Major region boundary | `xxl` | 32 px | empty-state breathing room, page bands |\n\nThese values describe the current default scale, not literals to repeat. Use\n`cx.theme().spacing_tokens()` or the corresponding GPUI scale helpers for the\necosystem default. A product-owned scale should preserve the ordering and\nrelationships and must be passed through the application's own design-system\ncontext rather than assumed to persist in the global GPUI Component theme.\n\nUse these rules when resolving horizontal and vertical space:\n\n1. **Inside before outside.** A component's padding belongs to the component;\n   the gap between components belongs to their parent.\n2. **Vertical rhythm shows grouping.** The gap between a title and its\n   description is smaller than the gap from that description to the next\n   section. Equal gaps imply equal relationships.\n3. **Horizontal space supports scanning.** Repeated rows keep icons, labels,\n   values, badges, and trailing actions on stable columns.\n4. **Leading and trailing are semantic.** Think in reading-order edges even\n   when the current API uses left/right; this keeps future RTL adaptation\n   possible.\n5. **Do not double padding.** A card placed in an already padded panel should\n   not automatically add another full panel inset.\n6. **Use optical alignment sparingly.** A one- or two-pixel correction is valid\n   for icon or glyph geometry, but document why it differs from the scale.\n\nCommon compositions in the current system illustrate the relationships:\n\n- button contents use 4 px at small sizes and 8 px at normal sizes;\n- dialog headers and footers use an 8 px internal gap;\n- compact list and menu rows use 4 px vertical and 8–12 px horizontal padding;\n- sheet headers use about 16 px leading and 12 px trailing space, leaving room\n  for a close affordance, while footers use 16 px horizontal and 12 px vertical\n  space;\n- notifications use 16 px horizontal padding and a 12 px column gap because\n  icon, message, and action are distinct groups.\n\nDo not treat these as copy-and-paste recipes for every surface. They reveal the\nsystem: controls are tighter internally, rows optimize scanning, and\ncontainers spend more space at their boundary than between their contents.\n\n### Proportion and layer hierarchy\n\nStart with content requirements, then set proportions. Avoid arbitrary halves\nwhen one pane has a clearly different role.\n\n- A navigation sidebar should be wide enough for stable labels but visibly\n  subordinate to the work area. Give it a minimum, preferred, and maximum\n  width rather than a percentage alone.\n- In master–detail layouts, let the collection remain scannable and give the\n  detail pane the surplus. A roughly one-third/two-thirds starting point is\n  often useful, but content constraints are authoritative.\n- Inspectors and auxiliary sheets should not cover the primary object by\n  default. They should be resizable or dismissible when their content grows.\n- Dialog width comes from the decision: short confirmation, medium form, or a\n  dedicated window/page for complex work. Do not enlarge a dialog simply to\n  create whitespace.\n- Reserve the strongest elevation for the topmost decision layer. Within a\n  layer, use background and hairlines—not successively larger shadows—to show\n  hierarchy.\n\nDefine three size constraints for every major region: the minimum at which its\ntask still works, a comfortable default, and how it consumes surplus. Persist\nuser-controlled splits when they represent workflow preference, and clamp\nrestored values against the current window.\n\n### Alignment details\n\nAlignment is a structural system, not a final polish pass. Establish a small\nset of alignment spines for each surface: shared leading and trailing edges,\ntext baselines, center lines, and fixed functional lanes. Elements at the same\nlevel should attach to the same spine from top to bottom or leading to trailing,\neven when they are different component types.\n\n<img class=\"alignment-light\" src=\"/alignment-spines.svg?v=20260822-4\" alt=\"Alignment spines across a desktop surface\">\n<img class=\"alignment-dark\" src=\"/alignment-spines-dark.svg?v=20260822-4\" alt=\"Alignment spines across a desktop surface\">\n\nVertical red lines sit beside shared edges or control centers for content,\nstatus, time, and trailing actions. Horizontal lines sit beneath text baselines\nor pass through a row center to show bottom and vertical-center alignment. The\ncompact comparison isolates a one-rendered-pixel drift that must be corrected\nat its structural owner.\n\n- Give sibling regions a shared content inset. A heading, toolbar, list row,\n  empty state, and footer that describe the same level should not each invent a\n  slightly different leading edge.\n- Repeat column geometry through the whole region. Headers, rows, summaries,\n  loading states, and inline editors should reserve the same lanes for identity,\n  metadata, status, numbers, and actions.\n- Align related controls across rows and sections. Form labels, fields,\n  descriptions, and validation messages should reveal a stable vertical grid\n  when the page is scanned from top to bottom.\n- Keep horizontal bands coherent. Items sharing a toolbar, title bar, status\n  bar, or row should use one baseline or center line instead of individually\n  tuned offsets.\n- Introduce indentation only for real hierarchy, containment, or disclosure.\n  Decorative indentation makes siblings look subordinate and breaks the\n  surface's reading line.\n- When a nested level ends, return exactly to the parent spine. Do not let\n  accumulated padding drift across nested containers.\n- Preserve the spine through optional content. Missing icons, badges,\n  descriptions, or trailing actions must not move the remaining labels; use\n  intentional slots or lanes when cross-row comparison matters.\n- Align major regions with one another where their hierarchy matches. Sidebar\n  headers, content titles, split panes, toolbars, and bottom bars need not share\n  every coordinate, but coincident levels should form visible continuous lines.\n\nNot every edge should align. A child can indent, a primary value can lead its\nsupporting metadata, and a destructive decision can gain separation. Such\nexceptions must communicate hierarchy or meaning; they must not result from\nuncoordinated component padding. Start with the shared spine, then make the\nexception explicit.\n\nTreat exact alignment and repeated gaps as quality invariants. When two edges\nor spaces are intended to be equal, a one-rendered-pixel difference is a defect,\nnot an acceptable optical approximation. Inspect resolved bounds with a\nmeasurement tool at representative window sizes, zoom levels, and display scale\nfactors. Compare coordinates and distances; do not approve alignment only from\na casual screenshot.\n\nThe rendered-pixel tolerance is a verification rule, not permission to patch\nthe code with raw pixel offsets. Equal relationships should resolve from the\nsame `rem` helper, spacing token, grid definition, or shared component inset.\nFix the common owner when they differ. Account for fractional layout and device\nrounding so intended spines land on the same physical pixel instead of drifting\nat particular zoom levels.\n\n- Align text by baselines, not by bounding-box centers, when mixed sizes share\n  a row.\n- Center icons in a fixed slot so labels do not move when icons differ in\n  intrinsic width.\n- Right-align comparable numbers; left-align prose and identifiers unless the\n  locale requires otherwise.\n- Keep trailing row actions and disclosure indicators in fixed-width lanes.\n- Align form controls by their interactive frame, not by help text below them.\n- Use `justify_between` only when the two sides truly own opposite edges; it\n  should not disguise missing structure in the middle.\n- Hairlines belong on the boundary owner. Two adjacent regions must not each\n  draw the same separator.\n- A scrollbar belongs to the region that scrolls and sits against that panel,\n  editor, or window's trailing edge. Content padding may inset text and rows;\n  it must not pull the scrollbar into the middle of the surface. Reserve a\n  deliberate scrollbar gutter when content needs clearance.\n\n### Density tiers\n\nMedium is the ecosystem default. Change density for the whole local context,\nnot one isolated control:\n\n- **comfortable / large:** onboarding, sparse forms, prominent decisions;\n- **standard / medium:** most application chrome and workflows;\n- **compact / small:** toolbars, menus, tables, and repeated professional data;\n- **extra compact / xsmall:** exceptional high-density utilities, never the\n  automatic choice for an entire application.\n\nThe current controls demonstrate a bounded scale rather than arbitrary sizing:\nbuttons commonly move through approximately 20, 24, and 32 px frames; input\nand data controls may extend to about 44 px at large size; table rows use about\n26, 30, 32, and 40 px. Use the component's `Size` API so typography, icon,\npadding, and hit target change together. A custom height that changes only the\nouter box is usually incomplete.\n\n### Zoom, base font, and `rem`\n\nA well-designed `rem` system preserves hierarchy while the interface zooms.\nZoom is successful when the relationship between title and body, control and\nicon, inner and outer spacing, primary and secondary regions still feels the\nsame at every scale—not merely when every object becomes larger.\n\nGPUI Component adopts the relative-scale idea familiar from <a href=\"https://tailwindcss.com/docs/theme\" target=\"_blank\" rel=\"noopener noreferrer\">Tailwind CSS</a>. The\ntheme's base `font_size` becomes the window's `rem` through `Root`, and GPUI\nscale helpers such as `text_sm()`, `gap_2()`, `p_4()`, `h_8()`, and `size_4()`\nresolve against it. This gives typography, spacing, controls, and icons one\nshared zoom axis.\n\nDesign in ratios:\n\n- type steps keep the same hierarchy around the base body size;\n- spacing steps keep the same grouping relationships around the type;\n- control frames, icons, and hit targets scale with their labels;\n- pane minima and comfortable widths account for the scaled content;\n- corner radii and focus treatment remain optically consistent with the\n  control frame.\n\nDo not implement zoom by changing text size alone. A larger label inside a\nfixed-height button, a larger document inside fixed pane minima, or larger rows\ninside a stale virtual-list measurement destroys the original rhythm and can\nclip content. Conversely, multiplying every physical pixel—including\nhairlines—can make the interface visually heavy.\n\nAs a rule, application layout should not call `px(...)` directly. Use GPUI's\nrem-based scale helpers (`p_2`, `gap_3`, `w_64`, `text_sm`, and related\nbuilders) or semantic component sizes. Use fixed pixels only when the value\nrepresents a physical or raster boundary:\na one-device-pixel hairline, platform window inset, bitmap dimension, minimum\nhit-test tolerance, or geometry that must match an external surface. These are\naudited, documented exceptions. Product spacing, typography, icon size, and\nordinary control geometry stay on the relative scale.\n\nTest interface zoom at several base-font values, not just the default. Verify\nhierarchy, wrapping, truncation, minimum window size, pane resizing, focus-ring\nclearance, popup placement, and virtualized row measurement. Also distinguish\ninterface zoom from Dock's panel zoom: Dock zoom makes one container fill its\narea while retaining its chrome; it does not change `rem` or application scale.\n\n### Surfaces and elevation\n\nUse elevation to explain stacking, not importance. The base window surface is\nflat; separators and background contrast define its regions. Popovers, menus,\ndialogs, and notifications may use progressively stronger shadows because they\nsit above other content. Do not put a shadow on every card.\n\nAll surfaces of the same kind should share one treatment. GPUI Component, for\nexample, deliberately gives popup families one themed popover surface so\nPopover, Select, Combobox, DatePicker, and menus do not drift apart. When an\napplication invents another anchored surface, reuse that semantic treatment\ninstead of approximating it with unrelated border and shadow literals.\n\n### Typography and icons\n\nUse the platform UI font for interface text and monospace only for code,\nidentifiers, shortcuts, and aligned numeric data. Keep body text readable and\navoid excessive uppercase or letter spacing, especially for CJK text.\n\nUse one icon family in a product. Icons supplement labels; they should not\nreplace unfamiliar actions with guesswork. Icon-only buttons always need an\naccessible name. Their visual explanation follows the tooltip policy below.\nUse filled or colored icons to communicate a state, not merely to make a\ntoolbar lively.\n\n## Layout patterns\n\n### Choose a stable shell\n\nMost applications should use one of these shells:\n\n- **single workspace:** toolbar or title bar above one primary view;\n- **sidebar workspace:** persistent navigation beside a changing detail view;\n- **master–detail:** resizable collection and detail panes;\n- **document workspace:** tabs or a dock area for multiple long-lived objects;\n- **utility window:** one focused task with a short, fixed action path.\n\nKeep global navigation stable while content changes. Give the primary work area\nthe remaining space with `flex_1()` and `min_w_0()` / `min_h_0()` where\noverflowing children must shrink. Use `Scrollable`, `VirtualList`, `Table`, or\n`DockArea` for their intended behavior instead of rebuilding scrolling or pane\nmanagement from nested `div`s.\n\nThe title bar is window chrome first. Preserve its drag region and avoid\nbinding ordinary title clicks to infrequent editing commands. Rename belongs\nbehind an explicit object command, with a keyboard path where appropriate.\n\n### Responsive desktop windows\n\nDesktop does not mean fixed-size. Decide what happens as a window narrows:\n\n1. preserve the primary task;\n2. allow resizable regions to reach a documented minimum;\n3. collapse secondary labels or inspectors;\n4. move low-frequency actions into a menu;\n5. scroll only the region whose content actually overflows.\n\nDo not hide an action without providing another path to it. Avoid making the\nentire window scroll when only a list or document body should scroll.\n\nGPUI flex layouts have the same intrinsic-size pressure found in other layout\nsystems: a `flex_1()` child may still refuse to shrink around long content.\nDesign and implementation must agree on which panes may shrink, truncate, wrap,\nor scroll. A clipped region also clips an outward focus ring; never trade away\nkeyboard visibility merely to simplify overflow.\n\n### Forms and settings\n\nUse a visible label for each field and place help or validation next to the\nfield it describes. Align related fields, but do not force long labels into a\nnarrow fixed column. Use the appropriate control: `Checkbox` for independent\nchoices, `RadioGroup` for a small visible set, `Select` for a longer set, and\n`Switch` for a setting that takes effect immediately.\n\nDisable submission while an operation is in flight, keep the user's input, and\nshow the result near the action. Reserve dialogs for short, focused decisions;\nuse a full page or sheet for workflows that need exploration or many fields.\n\nA loading treatment must represent actual waiting. Switching between settings\npanels whose content is already available should be immediate; a skeleton is\nappropriate only while content is genuinely loading and its shape is known.\n\n## Components and composition\n\nFollow the Shadcn principle that components are building material rather than a\nsealed design system. GPUI Component supplies coherent defaults, while the\napplication owns composition and product semantics.\n\n- Use component variants by meaning. Primary is reserved for the explicit\n  default commit in a decision area—normally the action invoked by Enter. A\n  lone, frequent, or desirable action is not automatically primary. An `Add`\n  command in a management toolbar normally uses a default Button; a form's\n  default `Create` commit may use primary. Use `danger` for destructive\n  commitment and `ghost` for quiet toolbar actions.\n- Prefer explicit compound parts and render callbacks over styling arbitrary\n  descendants.\n- Keep a repeated pattern consistent across the product. Wrap it in an\n  application component when it carries domain language or policy.\n- Use the standard component for its semantic role. A menu, dropdown menu,\n  popover, select, and command palette are not interchangeable boxes; each owns\n  different selection, focus, keyboard, dismissal, and layout contracts.\n- Preserve the component family's geometry. Menu rows share vertical and\n  horizontal padding, height, icon and checkmark slots, separators, radius, and\n  state treatment. Do not imitate one menu with a custom popup whose spacing\n  only approximates the system.\n- Do not wrap a library component merely to rename every method or freeze all\n  of its capabilities.\n- Move reusable behavior without product styling to `gpui-base`; keep themed,\n  opinionated presentation in GPUI Component or the application.\n\n## Interaction states\n\n### Make the result understandable before the click\n\nA control should predict its result. Use familiar desktop controls and\nplacement so people can act without learning the interface first. Its label\nnames the action and object, its state shows availability, and its feedback\nconfirms the same outcome.\n\nDo not label a Button `Save` if it opens a configuration flow, or `Delete` if\nit only removes an item from a group. Name the scope when context does not make\nit clear. Respond immediately to activation, prevent duplicate submission\nduring longer work, and show the result near the object that changed. Add a\nsuccess message only when the result itself is not visible.\n\nEvery interactive control should be designed for:\n\n| State | Design requirement |\n| --- | --- |\n| Rest | Clear affordance without visual noise |\n| Hover | Subtle pointer feedback, never the only cue |\n| Pressed | Immediate press feedback |\n| Open / pressed | Persistent feedback while an attached popup is open |\n| Focus visible | High-contrast keyboard focus ring |\n| Selected / checked | Persistent state distinct from hover |\n| Disabled | Lower emphasis and no misleading hover/pressed response |\n| Loading | Preserve context, prevent duplicate action, explain long waits |\n| Error | State what happened and how to recover |\n\nUse GPUI's focus system and Actions for commands that should work from the\nkeyboard. Match familiar desktop shortcuts, expose shortcuts in menus or\ntooltips, and keep focus in a logical place after opening or dismissing an\noverlay.\n\nSelection is part of the information model, not optional polish. Tabs,\nsegmented choices, selectable rows, filters, and navigation destinations must\nshow a persistent selected state. A Button that owns a dropdown must remain\nvisibly pressed or open until the popup closes; hover alone cannot explain the\nrelationship between trigger and surface.\n\nIn a segmented control, the selected fill and unselected surface must share\nthe container's silhouette. Neither may square off an end corner or make a\nboundary appear heavier than its peers.\n\nShow a selected navigation item, list row, or tab through the item's own\nsurface: a selected fill, stronger foreground, or heavier weight. Do not add a\nleading-edge bar or one-sided border as the selection marker. It is a web\ntemplate habit, not a desktop convention; it breaks the item's rounded\nsilhouette and adds a second, competing edge to a column that already aligns\non its text.\n\nFor destructive actions, distinguish between reversible and irreversible work.\nPrefer undo or a temporary notification for reversible changes. Use an\n`AlertDialog` when the consequence is serious and cannot be undone; name the\nspecific object and consequence in the confirmation copy.\n\n### Pointer conventions\n\nUse the default arrow cursor for buttons, checkboxes, menu items, tabs, and\nother native controls. Use a pointing hand for links and content that behaves\nas a link. Use text, resize, grab, and prohibited cursors only when they\ndescribe the active manipulation. A cursor reinforces an affordance; it does\nnot replace the control's visible state or accessible role.\n\nKeep hover effects modest because keyboard and accessibility interaction has no\nhover. Do not reveal the only copy of a destructive or essential action on\nhover. Contextual row actions may become quieter at rest if the same commands\nremain available through selection, keyboard, or a context menu.\n\n### Prefer desktop command surfaces over hover toolbars\n\nUse command frequency and scope to choose where an action lives:\n\n- keep the primary or frequent action visible as a labeled Button or familiar\n  toolbar control;\n- put secondary actions for the current region behind a visible\n  `DropdownMenu` trigger;\n- put commands that act on the object under the pointer in a `ContextMenu`;\n- expose the same important command through an [Action](./action)/[key binding](./keybinding) when it has a\n  natural keyboard form;\n- use a hover-revealed icon only as a shortcut to a command that remains\n  reachable elsewhere.\n\nThis is more than a visual preference. GPUI Component's menu system already\nowns directional keyboard navigation, confirmation and cancellation, disabled\nitems, separators, submenus, shortcut presentation, focus transfer and\nrestoration, and nested-menu dismissal. A custom strip of hover buttons must\nrebuild those behaviors and is invisible to keyboard-only and many assistive\ntechnology workflows.\n\nChoose `DropdownMenu` when users need a visible indication that more commands\nexist—for example a toolbar overflow, document actions, or account menu. Choose\n`ContextMenu` for selection- or object-scoped commands such as rename,\nduplicate, reveal, or remove. The context menu must not be the only way to\nperform an essential command; provide a menu-bar, toolbar, keyboard, or detail\nview path as appropriate.\n\nDo not put every action into a menu to make a screen look minimal. Discovery\nand speed matter: the main action stays visible, dangerous items remain clearly\nlabeled and separated, and a menu item should use the same verb, icon, shortcut,\nenabled state, and result everywhere it appears.\n\n### Button means application action; Link means external resource\n\nUse a Button when activation changes application state, confirms a decision,\nopens a tool, submits data, or runs a command. Choose its treatment by local\nhierarchy:\n\n- primary Button for the one emphasized commitment in a decision area;\n- default Button for ordinary visible actions;\n- outline Button when an action needs a clear boundary with less emphasis;\n- ghost Button for familiar, low-emphasis toolbar and inline actions;\n- icon Button only for a well-known symbol, with an accessible name and a\n  tooltip when meaning or scope is unclear.\n\nDo not assign primary because a Button is the only action on screen, because it\nis placed at the top right, or because the team wants more clicks. Primary\ncommunicates default commitment and keyboard behavior. If activation is merely\nan ordinary command such as adding an item, opening a tool, or refreshing a\nview, use a default, outline, or ghost Button according to its local hierarchy.\n\nUse an underlined Link only for an external resource target: a URL, web page,\nonline documentation, or email address. It uses the pointing-hand cursor\nbecause its contract is leaving the current application context for that\nresource. Do not use Link styling to make a functional command look quiet. A\nlink-shaped Delete, Save, Refresh, Add, Open-menu, or in-app navigation action\nhides the control's affordance and exposes the wrong accessibility role.\n\n“View” does not make an in-app destination a Link. A full report, analysis,\ndetails panel, or local record still opens through a Button, row, card, tab, or\ndisclosure control. Use concise context-aware labels such as `Full analysis`\nwhen the containing card already establishes what opens; reserve underlining\nfor a resource that actually opens in a browser or mail client.\n\nAll internal navigation—sidebar rows, tabs, breadcrumbs, list items, opening a\nlocal view, or switching workspaces—must use the corresponding native component\nor a Button/Action. Visual emphasis is chosen through Button variant or the\nnavigation component's selected state, never by lying about semantics.\n\n## Feedback and overlays\n\nChoose the smallest surface that fits the decision:\n\n- tooltip: a short explanation or shortcut;\n- popover: contextual controls that do not interrupt the task;\n- menu: a compact list of actions;\n- notification: asynchronous status that does not require a decision;\n- dialog: a focused decision or short form;\n- alert dialog: explicit confirmation of a consequential action;\n- sheet: supplementary work that benefits from more persistent space.\n\nA tooltip supplies missing meaning; it does not restate an obvious action.\nReserve it for an unfamiliar symbol, ambiguous scope, or a useful shortcut\nthat is otherwise hidden. Repeated, recognizable commands such as Copy and\nDownload in a message footer need accessible names and keyboard access, but\ntheir hover labels add interruption rather than clarity.\n\nAn Alert interrupts the visual hierarchy even when it does not open a modal.\nUse it for important, exceptional information that needs attention in the\ncurrent task, not as a decorated container for ordinary descriptions, tips, or\nempty space. Prefer inline help, muted text, or a normal section when the\ncontent does not require immediate notice or action.\n\nAvoid stacking overlays. Escape should dismiss the topmost dismissible layer,\nand focus should return to the trigger or the next logical target.\n\nAn overlay action must refer to an object or state the overlay actually shows.\nFor example, expose `Clear history` only when a distinct recent-history section\nis visible and contains entries. Search results, recent items, and favorites\nare different collections; label and separate them instead of merging them\ninto one unexplained list. Hide an inapplicable action or disable it with a\nuseful reason—do not park an ambiguous trash icon in a footer.\n\nFooter space is not a catch-all for capabilities that lacked a place in the\ndesign. A footer may present shortcuts, status, or actions that apply to the\nwhole surface, but each item must answer: what is its object, why is it\navailable now, what scope does it affect, and what visible state changes after\nactivation?\n\n## Motion\n\nMotion explains change; it is not ambient decoration. Use short transitions for\nappearance, dismissal, expansion, and spatial continuity. Avoid animating large\nlayout changes when opacity or transform communicates the same relationship.\nHonor reduced-motion preferences, never require animation to understand state,\nand do not add a default animation to every component.\n\nMotion policy belongs to the styled or application layer. Base may own the\nlifecycle mechanism or geometry needed for a transition, but it should not\ndecide that every product fades or slides. Give independently animated values\nstable identity, and make interruption reverse smoothly from the currently\nsampled value rather than restarting from an old endpoint.\n\nMotion follows the continuity of the interaction. While a pointer or scroll\nposition moves among related targets, keep the preview surface stable and\nupdate its content or position in place. Dismiss it only after the interaction\nends; repeated fade-out and re-entry on each update reads as flicker.\n\n## Designing data-heavy interfaces\n\nDense does not mean cramped. In tables, trees, command palettes, editors, and\ndocks:\n\n- keep headers and primary row identity visually stable;\n- align comparable values and use tabular numerals where appropriate;\n- distinguish focus, hover, active row, and multi-selection;\n- keep sorting and filtering visible and reversible;\n- preserve selection by domain identity across filtering and reordering;\n- virtualize large collections without changing keyboard semantics;\n- use progressive disclosure for secondary columns and inspectors;\n- provide a useful empty state that explains the next action.\n\nChoose a table for comparison across consistent fields, a list for scanning\nheterogeneous items, a tree for real hierarchy, and a dock only when users need\nto arrange long-lived tools or documents. Do not use a complex data component\nas a visual style.\n\n## Interface language\n\nWords are part of the interface architecture. Write the vocabulary for a\nfeature as a system—destinations, objects, commands, states, and outcomes—not as\nisolated translations of implementation features. Prefer the shortest wording\nthat remains accurate in its actual context.\n\n### Let context carry context\n\nDo not repeat information that the surrounding surface already establishes. A\nsidebar destination is usually the object or domain itself: use `Users`, not\n`User Management`; `Shortcuts`, not `Shortcut Configuration Management`. A\ncolumn whose rows already contain actions can omit a generic `Operation`\nheading. A dialog titled `Delete “Roadmap”?` does not need body text that asks\nthe same question again.\n\nThis is context economy, not deletion for its own sake. Add text when it changes\nthe decision: identify the affected scope, an irreversible consequence, an\nunusual prerequisite, or a way to recover. Every extra word should answer a\nquestion the current layout does not already answer.\n\nUse nouns for destinations and objects (`Users`, `Appearance`, `Orders`), verbs\nfor commands (`Save`, `Duplicate`, `Export`), and adjectives or short phrases\nfor states (`Offline`, `Up to date`, `Pending review`). Avoid wrappers such as\n`Management`, `Module`, `Page`, `Function`, `Operation`, and `System` unless the\nword distinguishes a real domain concept.\n\n### Write each language, do not translate its shape\n\nStart from shared intent, hierarchy, and terminology, then compose each locale\nas natural interface language. Do not preserve the source language's word\norder, number of words, politeness filler, or grammatical category. English\n`Users` can express a Chinese feature concept that would literally expand to\n“user management”; fidelity means preserving purpose, not preserving tokens.\n\nRemove words supplied by the enclosing information architecture. Inside a\n`Settings` surface, a destination is often simply `Account`, not `Account\nSettings` and never the unnatural singular `Account Setting`. The correct\nEnglish label is chosen from its role and neighbors, not from the standalone\nsource phrase.\n\nMaintain a small product lexicon for recurring objects, commands, and states.\nUse the same term in the toolbar, menu, context menu, dialog, shortcut search,\nand documentation unless the context genuinely changes its meaning. Review\ncopy in the rendered surface: neighboring labels often reveal repetition or\ninconsistent scope that a locale file cannot.\n\nIn localized technical writing, preserve an established framework term when a\ntranslation would be less precise. Keep API identifiers in their original form\nand format them as code. Do not retain ordinary foreign words merely to sound\ntechnical. Explain a retained term on first use when needed, then use the same\nform throughout the interface, documentation, and API examples.\n\nIn documentation, use the exact English name for a named API, component,\nsource file, or guide in link text, including localized pages. For example,\nwrite `Font`, `Render`, `Input element`, and `Plot label` rather than translating\ntheir names or adding a redundant `GPUI Kit` prefix. Keep surrounding explanations in the\npage's language. Link only the named target; place words such as “source”\noutside the link when they describe why it is cited.\n\nIn a technical comparison table shared across locales, keep capability names,\nframework names, API names, and model names in their established English form.\nTranslate the explanation around the table, not its technical labels. Common\ninterface words with an established local name may still be localized outside\nthat comparison context.\n\n### Buttons and confirmation dialogs\n\nButton labels are short by default—usually one or two words—and describe the\nresult, not the gesture or the component. Prefer `Save`, `Move`, or `Delete` to\n`Click to save`, `Perform move`, or `Confirm deletion`. Use `Cancel` consistently\nfor the action that leaves without committing. Reserve `OK` for acknowledging\npurely informational content.\n\nShort is a default, not a character limit. A deliberately longer label is\nbetter when its words expose a consequence or distinguish choices that users\ncould otherwise confuse, for example `Delete from this group` versus `Delete\neverywhere`, or `Restart without saving`. Length must buy decision-critical\ninformation; it must not restate the dialog title or body.\n\nUse the most specific concise result as the confirmation label when possible:\n\n| Context | Weak | Prefer |\n| --- | --- | --- |\n| Delete dialog | `Yes`, `Sure`, `Confirm deletion` | `Delete` |\n| Unsaved changes | `Confirm`, `Yes` | `Discard changes` |\n| Pure acknowledgement | `Confirm operation` | `OK` or `Done` |\n| Complex consent whose result has no clear verb | `Yes` | `Confirm` |\n\n`Confirm` is a useful fallback when the surrounding dialog fully names a\ncomplex commitment and no shorter result verb is accurate. It should not\nreplace a clear command. `Sure` is conversational rather than a stable English\ncommand and is too ambiguous for the standard vocabulary.\n\nA confirmation dialog should form one compact decision:\n\n- title: the decision or condition, such as `Delete “Roadmap”?`;\n- body: only new scope, consequence, or recovery information;\n- actions: `Cancel` and the result, such as `Delete`;\n- destructive styling: applied to the destructive result, not substituted for\n  precise wording.\n\nAvoid generic titles such as `Notice`, `Warning`, `Error`, and `Confirmation`\nwhen the actual condition can be named. Avoid ritual phrases such as “Are you\nsure you want to…”, “Would you like to…”, “Please note that…”, and “successfully”\nwhen the structure or state already communicates them. Courtesy should come\nfrom a calm, respectful tone, not repeated `please`.\n\n### Capitalization, punctuation, and symbols\n\nUse sentence case for English UI by default: `Reset layout`, not `Reset Layout`\nor `RESET LAYOUT`. Preserve proper nouns and established acronyms. Follow a\nplatform convention such as title case for native menu commands only when the\nplatform integration benefits from it, and apply that convention consistently\nwithin the component class.\n\nALL CAPS can provide restrained typographic emphasis for very short section\nlabels, eyebrows, statuses, established acronyms, and code-like identifiers.\nIts compact shape and measured tracking can form a level similar to bold type,\nbut it does not belong on Buttons, long headings, sentences, or dense lists. Do\nnot combine uppercase, strong color, and bold weight in the same region, and do\nnot transform every string automatically: product names, acronyms, and localized\ncontent must preserve their intended casing.\n\nLabels, buttons, menu items, tabs, headings, placeholders, and short states do\nnot take a final period. Complete explanatory, warning, and error sentences do.\nAvoid exclamation marks in routine success and failure messages. In Chinese,\nuse full-width punctuation in sentences and omit terminal punctuation from\nshort control labels by the same semantic rule.\n\nUse the single ellipsis character (`…`), not three periods. Append it to every\nButton or MenuItem that opens a dialog, sheet, or separate window, and to a\ncommand that requires more input or choices before it can complete, such as\n`Settings…` or `Export…`. An immediately executed command does not take an\nellipsis. Use an indeterminate progress indicator, not decorative dots, to\ncommunicate ongoing work.\n\nErrors should say what happened and, when useful, the next recovery action.\nSuccess feedback should name the resulting state only when that state is not\nalready visible. Prefer `Couldn’t save. Check your connection and try again.`\nto a technical code or a long apology; omit a `Saved successfully` toast when\nthe document visibly becomes saved.\n\n## Internationalization and platform fit\n\nAccessibility (A11y) names and labels may remain in English; localization is\nnot required for these strings. Keep the item's own label when naming a control\nthat acts on it, even when that label is localized. This exception does not\napply to visible UI copy.\n\nCopy must survive expansion, CJK typography, and different shortcut notation.\nDo not size a control from one English label. Keep text out of raster assets,\navoid concatenating translated fragments, and let labels wrap or truncate only\nwhere the product defines a recovery path such as a tooltip.\n\nRespect platform differences that carry meaning: Command versus Control,\nnative window decorations, system appearance, scrollbar behavior, menus, and\nnotification capabilities. Keep the product's information architecture stable\nacross platforms, but do not erase familiar platform behavior for superficial\npixel equality.\n\n## Guidance for AI-generated interfaces\n\nAn AI changing a GPUI interface should first inspect the nearest feature,\ntheme tokens, and component documentation. It should state the primary task,\nstate owner, component composition, and keyboard path before generating code.\nIt must not infer an API from React/Shadcn examples or invent a GPUI method\nbecause the name seems plausible.\n\nAI output is incomplete until a human can explain why the hierarchy, density,\ncomponent choice, and exceptional literal values belong in this product. A\nvisually plausible screenshot is not proof: keyboard behavior, focus, dynamic\ncontent, themes, resizing, and failure states are part of the design.\n\n## Accessibility checklist\n\nBefore considering a screen complete, verify that:\n\n- every action is reachable and operable by keyboard;\n- focus or\n\n<!-- [TRUNCATED AT 50KB] -->","skills/gpui-kit/SKILL.md":"---\nname: gpui-kit\ndescription: 'How to build desktop applications with GPUI Kit, the Rust framework published as the gpui-kit crate (GPUI plus gpui_kit::component, gpui_kit::base, gpui_kit::assets). Use when setting up a gpui-kit app, choosing or using a component (Button, Input, Select, Dialog, Sheet, Tabs, Sidebar, List, DataTable, Tree, Chart, etc.), handling component state, theming, or window overlays, and for GPUI mechanics: actions and keybindings, async tasks, contexts, custom elements, entities, events, focus, global state, layout and styling, ElementId, and tests including UI integration testing. Holds the normative Coding Guides: read them before any architecture, state-ownership, public API, naming, or testing decision. Pairs with the gpui-kit-design-guides skill for the Design Guides.'\n---\n\n# GPUI Kit\n\nApplications depend on one crate, `gpui-kit`. GPUI is `use gpui_kit::*;`, and\neach layer is reachable by name: `gpui_kit::component` (styled components),\n`gpui_kit::base` (unstyled behavior), `gpui_kit::assets` (default icons),\n`gpui_kit::platform`.\n\nStart with [component-family conventions](references/conventions.md) to choose the constructor, state owner, event, and layout contract for the task. Learn the family once, then verify the specific component supports the capability.\n\nFor a complete compiled view with retained state, subscriptions, and overlay\nlayers, read [the tested application recipe](references/recipes.md).\n\n## Read the Guides First\n\nTwo guides hold the rules this skill assumes. They are requirements, not\ninspiration. Read the guide file itself; do not answer from this page, from a\nsimilar file in the codebase, or from training data.\n\n| Guide                                                  | Read before                                                                                                                   |\n| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |\n| Design Guides, skill `gpui-kit-design-guides`          | Choosing components, layout, spacing, hierarchy, color, density, interaction states, overlays, motion, interface copy          |\n| [Coding Guides](references/coding-guides.md)           | Crate layering, `RenderOnce` vs `Entity<T>`, state ownership, `ElementId`, events, focus, async, public API, naming, testing |\n\nRead the Design Guides first when the change has a visible surface: code\nstructure preserves product intent, it does not replace it. If the design\nskill is not installed, fetch `https://gpui-kit.com/docs/design-guides.md`.\nThe coding guide is a verbatim copy of `https://gpui-kit.com/docs/coding-guides.md`,\nso its links to `./design-guides.md` and `./getting-started.md` mean the design\nskill and `https://gpui-kit.com/docs/getting-started.md`.\n\n### Coding Guides section map\n\nRead the whole guide for a new crate, module, or feature. For a narrow change,\nread \"Architecture at a glance\" and \"Rules for coding agents\" first, then the\nsection for the change (`grep -n '^## ' references/coding-guides.md`).\n\n| Section                              | Read when                                                              |\n| ------------------------------------ | ---------------------------------------------------------------------- |\n| Architecture at a glance             | Always; crate layering, ownership boundary                             |\n| Bootstrap and root ownership         | `main`, `init`, `Root`, window creation, app-level state               |\n| Understand GPUI's phases and contexts | Anything touching `App`, `Window`, `Context<T>`, render vs update      |\n| Choose the right unit                | Deciding `RenderOnce` vs `Entity<T>` vs custom `Element`               |\n| State ownership                      | Where a piece of state lives, who mutates it, `Entity<State>` handles  |\n| Stable identity                      | `ElementId`, lists, repeated elements, keyed state                     |\n| Rendering and composition            | `render`, builder chains, `when`/`map`, child composition              |\n| Behavior and presentation boundary   | `gpui-base` vs `gpui-component` vs application code                    |\n| Theme and styling                    | `cx.theme()`, tokens, `Styled`, sizes, variants                        |\n| Events, actions, and focus           | `cx.emit`, `subscribe`, `actions!`, keybindings, `FocusHandle`         |\n| Async work and side effects          | `cx.spawn`, `background_spawn`, `Task`, I/O, timers                    |\n| Layout, measurement, and scrolling   | Flex layout, sizing, `overflow`, scroll handles, measuring             |\n| Lists, tables, and large data        | `VirtualList`, `List`, `DataTable`, delegates, large collections       |\n| Public API design                    | Anything `pub`: builders, private fields, setter and reader naming     |\n| Platform and capability boundaries   | macOS/Windows/Linux/wasm differences, feature gates                    |\n| File and naming conventions          | New files, modules, type and method names, `Kind` suffix, `Context`    |\n| Testing strategy                     | What to test, `#[gpui_kit::test]`, `TestAppContext`                    |\n| Performance rules                    | Render cost, allocation, re-render triggers                            |\n| Common failure modes                 | Before finishing; invented APIs, state in render, index ids            |\n| Rules for coding agents              | Always when an agent writes code                                       |\n| Implementation checklist             | Before finishing; run every item against the work                     |\n\n### Non-negotiables\n\nA floor, not a substitute for the guides.\n\n- **Never invent an API.** Search the current source for the real signature.\n  Do not translate a React, CSS, or older-GPUI example by analogy; a\n  plausible-looking method that does not exist is the most common failure.\n- **One dependency.** Applications depend on `gpui-kit` alone. GPUI is\n  `use gpui_kit::*;`; the layers are `gpui_kit::component`, `gpui_kit::base`,\n  `gpui_kit::assets`, `gpui_kit::platform`.\n- **Framework owns behavior, application owns presentation.** Do not put\n  colors, sizing, or layout in `gpui-base`; do not put interaction behavior in\n  application styling code.\n- **Stable identity.** Repeated elements need domain-derived `ElementId`s, not\n  list indexes.\n- **No `pub` fields across the seam.** Public data types use builders and\n  reader methods.\n- **Spell `Context` out.** `cx` is GPUI's; name anything else after what it\n  holds.\n\n## Documentation\n\n- **Find a task/component page**: use `https://gpui-kit.com/llms.txt`, then load its Markdown page.\n- **Full reference**: `https://gpui-kit.com/llms-full.txt` is available when broad reference is actually needed\n- **Per-component API**: fetch `https://gpui-kit.com/component/{name}.md`,\n  e.g. `button.md`, `input.md`, `select.md`, `dialog.md`, `data-table.md`\n- **Any site page** can be fetched as Markdown by appending `.md` to the URL\n\n## Quick Reference\n\nSetup and examples: [references/usage.md](references/usage.md).\n\n```rust\nuse gpui_kit::*;\n\ngpui_kit::application()\n    .with_assets(gpui_kit::assets::Assets)\n    .run(|cx| {\n        gpui_kit::init(cx);                       // first, before anything else\n        gpui_kit::open_window(options, cx, |window, cx| {\n            cx.new(|cx| AppView::new(window, cx))\n        })\n        .expect(\"failed to open window\");\n    });\n```\n\n- **Stateless** (`RenderOnce`): build in `render`:\n  `Button::new(\"save\").primary().label(\"Save\").on_click(|_, _, _| {})`\n- **Stateful**: hold `Entity<State>` in the view, pass a reference in `render`:\n  `let input = cx.new(|cx| InputState::new(window, cx));` then `Input::new(&self.input)`\n- **Sizes**: `.xsmall()` `.small()` `.medium()` (default) `.large()`\n- **Theme**: `cx.theme().primary` · `.background` · `.foreground` · `.border` · `.muted`\n- **Overlays**: `window.open_dialog(...)`, `open_sheet(...)`, `push_notification(...)`\n  via `gpui_kit::component::WindowExt`\n\n## Component Catalog\n\nImport paths are relative to `gpui_kit::component::`, so `input::{Input, InputState}`\nmeans `use gpui_kit::component::input::{Input, InputState};`. For the full API\nfetch the component's `.md` doc.\n\n### Input & Form\n\n| Component     | Import                                          | Notes                                        |\n| ------------- | ----------------------------------------------- | -------------------------------------------- |\n| `Input`       | `input::{Input, InputState}`                    | Stateful. Text, password, mask, validation   |\n| `Textarea`    | `input::{Textarea, TextareaState}`              | Stateful. Multi-line text                    |\n| `Editor`      | `input::{Editor, EditorState}`                  | Stateful. Code editor, `tree-sitter` feature |\n| `NumberInput` | `input::{NumberInput, NumberInputEvent}`        | Stateful. Numeric with step                  |\n| `OtpInput`    | `input::OtpInput`                               | Stateful. One-time password                  |\n| `SpeechButton` | `speech::{SpeechButton, SpeechState}`          | Stateful. Dictation, `speech` feature        |\n| `Select`      | `select::{Select, SelectState}`                 | Stateful. Dropdown picker                    |\n| `Combobox`    | `combobox::{Combobox, ComboboxState}`           | Stateful. Searchable select                  |\n| `Checkbox`    | `checkbox::Checkbox`                            | Stateless. `on_click` receives `&bool`       |\n| `Switch`      | `switch::Switch`                                | Stateless. Toggle                            |\n| `Radio`       | `radio::{Radio, RadioGroup}`                    | Stateless.                                   |\n| `Slider`      | `slider::{Slider, SliderState}`                 | Stateful.                                    |\n| `Toggle`      | `button::Toggle`                                | Stateless.                                   |\n| `Rating`      | `rating::Rating`                                | Stateless.                                   |\n| `Stepper`     | `stepper::Stepper`                              | Stateless. Multi-step progress               |\n| `ColorPicker` | `color_picker::{ColorPicker, ColorPickerState}` | Stateful.                                    |\n| `DatePicker`  | `date_picker::{DatePicker, DatePickerState}`    | Stateful.                                    |\n| `TimeField`   | `time_field::{TimeField, TimeFieldState}`       | Stateful. Time of day, 24/12-hour            |\n| `Calendar`    | `calendar::{Calendar, CalendarState}`           | Stateful. Inline month view                  |\n| `Form`        | `form::{v_form, h_form, field}`                 | Layout container for form fields             |\n\n### Display & Feedback\n\n| Component   | Import                                    | Notes                                 |\n| ----------- | ----------------------------------------- | ------------------------------------- |\n| `Button`    | `button::{Button, ButtonGroup}`           | Stateless. Primary UI action          |\n| `Icon`      | `{Icon, IconName}`                        | Stateless. Lucide icons               |\n| `Badge`     | `badge::Badge`                            | Stateless.                            |\n| `Tag`       | `tag::Tag`                                | Stateless. Closable tags              |\n| `Avatar`    | `avatar::Avatar`                          | Stateless.                            |\n| `Label`     | `label::Label`                            | Stateless. Form label                 |\n| `Kbd`       | `kbd::Kbd`                                | Stateless. Keyboard key display       |\n| `Alert`     | `alert::Alert`                            | Stateless. Info/success/warning/error |\n| `Spinner`   | `spinner::Spinner`                        | Stateless. Loading indicator          |\n| `Skeleton`  | `skeleton::Skeleton`                      | Stateless. Loading placeholder        |\n| `Shimmer`   | `shimmer::{ShimmerText, ShimmerStyle}`    | Stateless. Streaming-text shimmer     |\n| `Marker`    | `marker::{Marker, MarkerVariant}`         | Stateless. Inline status marker       |\n| `Progress`  | `progress::{Progress, ProgressCircle}`    | Stateless.                            |\n| `Tooltip`   | `tooltip::Tooltip`                        | Via `.tooltip()` on elements          |\n| `HoverCard` | `hover_card::{HoverCard, HoverCardState}` | Stateful.                             |\n| `Clipboard` | `clipboard::Clipboard`                    | Stateless. Copy button                |\n| `TextView`  | `text::TextView`                          | `TextView::markdown(id, text)`, HTML too |\n| Image       | `gpui_kit::{img, ImageSource, ObjectFit}` | GPUI's `img()` element                |\n\n### Overlay & Popups\n\n| Component        | Import                                            | Notes                                    |\n| ---------------- | ------------------------------------------------- | ---------------------------------------- |\n| `Dialog`         | `dialog::Dialog` + `WindowExt`                    | Via `window.open_dialog(...)`            |\n| `AlertDialog`    | `WindowExt`                                       | Via `window.open_alert_dialog(...)`      |\n| `Sheet`          | `sheet::Sheet` + `WindowExt`                      | Side panel, via `window.open_sheet(...)` |\n| `Notification`   | `notification::Notification` + `WindowExt`        | Via `window.push_notification(...)`      |\n| `Popover`        | `popover::Popover`                                | Floating overlay                         |\n| `Menu`           | `menu::{PopupMenu, DropdownMenu}`                 | Context menus                            |\n| `DropdownButton` | `button::DropdownButton`                          | Button with dropdown menu                |\n| `Command`        | `command::{Command, CommandState, CommandGroup}`  | Stateful. Command palette                |\n| Focus trap       | `FocusTrapElement`                                | `.focus_trap(id, &handle)` on a container; `Dialog` and `Sheet` have it built in |\n\n### Navigation & Layout\n\n| Component         | Import                                                                   | Notes                     |\n| ----------------- | ------------------------------------------------------------------------ | ------------------------- |\n| `Tabs` / `TabBar` | `tab::{Tab, TabBar}`                                                     | Tabbed interface          |\n| `Sidebar`         | `sidebar::{Sidebar, SidebarMenu, ...}`                                   | App navigation panel      |\n| `TitleBar`        | `TitleBar`                                                               | Window title bar          |\n| `StatusBar`       | `status_bar::StatusBar`                                                  | Window status bar         |\n| `Breadcrumb`      | `breadcrumb::Breadcrumb`                                                 | Navigation breadcrumb     |\n| `Pagination`      | `pagination::Pagination`                                                 | Page navigation           |\n| `Accordion`       | `accordion::Accordion`                                                   | Collapsible sections      |\n| `Collapsible`     | `collapsible::Collapsible`                                               | Single collapsible        |\n| `GroupBox`        | `group_box::GroupBox`                                                    | Labeled container         |\n| `Resizable`       | `resizable::{h_resizable, v_resizable, resizable_panel, ResizableState}` | Draggable split panes     |\n| `ResizeHandle`    | `resizable::{resize_handle, HandleEdge}`                                 | Standalone resize edge    |\n| `Scrollbar`       | `scroll::Scrollbar`                                                      | Custom scrollbar          |\n\n### Data Display\n\n| Component         | Import                                          | Notes                         |\n| ----------------- | ----------------------------------------------- | ----------------------------- |\n| `DataTable`       | `table::{DataTable, TableState, TableDelegate}` | Stateful. Full-featured table |\n| `Diff`            | `diff::{Diff, DiffState, DiffFile}`           | Retained state, `RenderOnce` element. Readonly unified/Git diff display of one or more files, merge conflicts and source files; application supplies the patch |\n| `Table`           | `table::{Table, ...}`                           | Simpler table                 |\n| `VirtualList`     | `{v_virtual_list, h_virtual_list}`              | High-perf large lists         |\n| `List`            | `list::{List, ListState, ListDelegate}`         | Stateful. Searchable list     |\n| `Tree`            | `tree::{Tree, TreeState, TreeItem, TreeEntry}`  | Stateful. Hierarchy           |\n| `DescriptionList` | `description_list::DescriptionList`             | Key-value pairs               |\n| `Settings`        | `setting::Settings`                             | Settings panel                |\n\n### Chat & Messaging\n\n| Component         | Import                                                   | Notes                                 |\n| ----------------- | -------------------------------------------------------- | ------------------------------------- |\n| `Message`         | `message::{Message, MessageContent, MessageAlignment}`   | Stateless. Chat message row           |\n| `Bubble`          | `bubble::{Bubble, BubbleContent, BubbleVariant}`         | Stateless. Message bubble             |\n| `Attachment`      | `attachment::{Attachment, AttachmentContent, ...}`       | Stateless. File/media attachment card |\n| `MessageScroller` | `message_scroller::{MessageScroller, MessageScrollerState}` | Stateful. Auto-scrolling message list |\n\n### Charts\n\n| Component | Import                                                          | Notes                          |\n| --------- | --------------------------------------------------------------- | ------------------------------ |\n| `Chart`   | `chart::{AreaChart, BarChart, LineChart, PieChart, RadarChart}` | Bar, line, area, pie charts    |\n| `Plot`    | `plot::Plot`                                                    | `#[derive(IntoPlot)]` for data |\n\n## Testing\n\n**UI integration testing** means rendering real components in headless windows,\nsimulating input, and checking state, focus, layout and owner callbacks. Use\n`#[gpui_kit::test]` to run tests and `gpui_kit::test` to operate and inspect the UI.\nWhen asked to add component interaction coverage, describe it as UI integration testing.\n\nFor unit tests, GPUI context tests or UI integration tests, read\n[Testing](references/gpui/test.md). It includes dependency setup, a complete\nrunnable UI flow, scoped native interactions, frame/async handling and the\nlimits of accessibility and geometry assertions. Use the production view and\nverify the action's outcome through normal Rust assertions.\n\n## GPUI References\n\nLoad the file for the mechanism the task touches. Each file starts with a\ncontents line.\n\n| Topic                       | File                                                   | Load when                                                       |\n| --------------------------- | ------------------------------------------------------ | --------------------------------------------------------------- |\n| Actions & keybindings       | [action.md](references/gpui/action.md)                 | `actions!`, `bind_keys`, `on_action`, `key_context`             |\n| Async & background tasks    | [async.md](references/gpui/async.md)                   | `cx.spawn`, `background_spawn`, `Task`, async I/O               |\n| Context management          | [context.md](references/gpui/context.md)               | `App`, `Window`, `Context<T>`, `AsyncApp`                       |\n| Custom elements (low-level) | [element.md](references/gpui/element.md)               | `Element` trait, `request_layout`, `prepaint`, `paint`          |\n| Entity state                | [entity.md](references/gpui/entity.md)                 | `Entity<T>`, `WeakEntity`, state management                     |\n| Events & subscriptions      | [event.md](references/gpui/event.md)                   | `cx.emit`, `cx.subscribe`, `cx.observe`                         |\n| Focus & keyboard nav        | [focus-handle.md](references/gpui/focus-handle.md)     | `FocusHandle`, `track_focus`, Tab navigation                    |\n| Global state                | [global.md](references/gpui/global.md)                 | `Global` trait, `cx.set_global`, app-wide config                |\n| Layout & styling            | [layout-style.md](references/gpui/layout-style.md)     | `div()`, `h_flex()`, `v_flex()`, flexbox, overflow, positioning |\n| ElementId                   | [element-id.md](references/gpui/element-id.md)         | `ElementId`, `.id()`, uniqueness rules, stateful elements       |\n| Testing                     | [test.md](references/gpui/test.md)                     | `#[gpui_kit::test]`, `TestAppContext`, `VisualTestContext`      |\n\nDeep dives, for when the topic file is not enough:\n\n- **Element trait**: [element-api.md](references/gpui/element-api.md) (complete API, hitbox, events) ·\n  [element-patterns.md](references/gpui/element-patterns.md) (text, interactive, container, composite) ·\n  [element-examples.md](references/gpui/element-examples.md) (full examples) ·\n  [element-best-practices.md](references/gpui/element-best-practices.md) (performance, state, pitfalls) ·\n  [element-advanced.md](references/gpui/element-advanced.md) (custom layouts, async updates, virtual lists)\n- **Entities**: [entity-api.md](references/gpui/entity-api.md) (complete API, lifecycle) ·\n  [entity-patterns.md](references/gpui/entity-patterns.md) (model-view, cross-entity, observer) ·\n  [entity-best-practices.md](references/gpui/entity-best-practices.md) (memory, performance) ·\n  [entity-advanced.md](references/gpui/entity-advanced.md) (collections, registry, debounce, state machines)\n- **Testing**: [test-examples.md](references/gpui/test-examples.md) (organization, setup, assertions, running tests) ·\n  [test-reference.md](references/gpui/test-reference.md) (re-entrancy, property tests, mocking)\n","skills/gpui-kit/references/coding-guides.md":"---\ntitle: Coding Guides\ndescription: Architecture and coding conventions for maintainable GPUI Kit applications\norder: -13\n---\n\n# Coding Guides\n\nThis guide describes the application architecture and code patterns that have\nproved durable in GPUI Kit. It is written for both engineers and coding\nagents. Read [Design Guides](./design-guides.md) first: code structure should\npreserve product intent, not replace it.\n\nThis is a normative guide. **Must** marks lifecycle, correctness, or ecosystem\nconstraints; **should** is the default architecture and requires a concrete\nreason to depart from it. Current source and API docs remain authoritative for\nexact signatures.\n\n## Architecture at a glance\n\n<img class=\"architecture-light\" src=\"/application-layers-light.svg?v=20260822-16\" alt=\"GPUI application architecture layers\">\n<img class=\"architecture-dark\" src=\"/application-layers-dark.svg?v=20260822-16\" alt=\"GPUI application architecture layers\">\n\nDependencies point downward. Higher layers own domain meaning and orchestration;\nlower layers own reusable presentation or behavior. Do not make a reusable\ncomponent depend on an application screen, or make `gpui-base` depend on a\ntheme from GPUI Component.\n\nUse these boundaries:\n\n- **app shell:** compose windows and feature crates while keeping feature logic out;\n- **feature crate:** keep one capability's model, services, views, commands, dialogs,\n  and workflow behind one public boundary;\n- **app component:** a repeated domain-aware pattern;\n- **gpui-component:** themed, general-purpose UI;\n- **gpui-base:** reusable behavior and geometry without product presentation.\n\n### Organize large applications by capability\n\nIn a large Rust application, a feature should usually be a crate, not another\nfile in a global `views`, `models`, or `modals` directory. Keep the model,\nviews, commands, dialogs, and workflow for one capability together. A dialog\nthat edits a workspace belongs to the workspace feature; only the reusable\ndialog primitive belongs to the UI library.\n\n```text\ncrates/\n├── app/\n│   └── src/main.rs             # Compose windows and features\n├── workspace/\n│   └── src/\n│       ├── lib.rs              # The feature's public boundary\n│       ├── model.rs\n│       ├── commands.rs\n│       ├── workspace_view.rs\n│       └── rename_dialog.rs\n├── search/\n│   └── src/\n│       ├── lib.rs\n│       ├── model.rs\n│       ├── commands.rs\n│       ├── search_view.rs\n│       └── filters.rs\n├── settings/\n│   └── src/\n│       ├── lib.rs\n│       ├── model.rs\n│       ├── settings_view.rs\n│       └── account_dialog.rs\n└── shared/\n    └── src/\n        ├── lib.rs\n        └── recent_items.rs     # A stable capability with multiple owners\n```\n\nDo not invert this into global `models/`, `views/`, `modals/`, and `commands/`\ndirectories. Those folders classify files by implementation role while\nscattering every feature across the application.\n\nThe application shell composes feature crates but contains little feature\nlogic. A feature may depend on stable shared capabilities and UI foundations;\nit must not depend on the shell or reach into a sibling feature's internals.\nWhen two features need to communicate, prefer an explicit command, event, data\ntype, or small shared service over a dependency between their views. Extract a\nshared crate only after the capability has a coherent name and more than one\nreal owner.\n\nCrate boundaries are engineering boundaries. They let Cargo rebuild and test a\nsmaller dependency subgraph, make ownership visible in `Cargo.toml`, and limit\nthe review and regression surface of a change. They also make removal honest:\na feature that cannot be detached without searching through global view and\nmodal directories was never isolated.\n\nDo not create a crate for every screen or helper. Split where a capability has\nits own state and lifecycle, a stable public seam, or enough implementation to\nbenefit from independent compilation and tests. Keep dependencies acyclic and\npointing toward smaller, more stable crates.\n\n## Bootstrap and root ownership\n\nInitialize GPUI Component once, before creating component-backed views, and put\n`Root` at the first level of each window:\n\n```rust\napp.run(move |cx| {\n    gpui_kit::init(cx);\n\n    gpui_kit::open_window(WindowOptions::default(), cx, |window, cx| {\n        cx.new(|cx| Workspace::new(window, cx))\n    })\n    .expect(\"failed to open window\");\n});\n```\n\n`Root` coordinates window-level component facilities such as overlays and\nnotifications. Do not create a separate root for each page inside one window.\nIt also coordinates modal focus restoration, focus traps, tooltip/menu layers,\nand window-scoped text selection. Bypassing it can produce behavior that looks\ncorrect at rest but fails when overlays nest or focus changes quickly.\n\n## Understand GPUI's phases and contexts\n\nGPUI is retained state with declarative rendering. An entity survives across\nframes; the element tree returned by `render` is a fresh description of the\ncurrent frame. Keep that distinction explicit.\n\n- `Context<Self>` mutates the current entity, creates listeners tied to it,\n  emits its events, and notifies its observers.\n- `App` gives access to application globals and entity reads/updates without\n  implying ownership by the rendered element.\n- `Window` owns focus, actions, input dispatch, element-keyed state,\n  measurement, and animation-frame requests for that window.\n- layout, prepaint, and paint are later phases; use their hooks only when\n  resolved geometry is genuinely required.\n\nNever retain `&mut Window`, `&mut App`, or `&mut Context<_>` beyond the call in\nwhich it is provided. Retain typed handles—`Entity`, `WeakEntity`,\n`FocusHandle`, scroll handles, or domain IDs—instead.\n\n## Choose the right unit\n\n### Use `RenderOnce` for value-like elements\n\nUse a `RenderOnce`/`IntoElement` component when all inputs can be supplied by\nthe caller and the element does not need to retain application state between\nframes. This is the normal choice for presentational wrappers and small\ncontrols.\n\n```rust\n#[derive(IntoElement)]\nstruct EmptyState {\n    title: SharedString,\n}\n\nimpl RenderOnce for EmptyState {\n    fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {\n        div()\n            .v_flex()\n            .gap_2()\n            .items_center()\n            .text_color(cx.theme().muted_foreground)\n            .child(self.title)\n    }\n}\n```\n\n### Use `Entity<T>` for retained behavior\n\nUse an entity-backed `Render` view when behavior spans frames or needs\nobservation, subscriptions, focus, async work, history, measurement, or\nincremental updates. Store entities in an owning view rather than recreating\nthem in `render`.\n\n```rust\nstruct SearchView {\n    query: Entity<InputState>,\n}\n\nimpl SearchView {\n    fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let query = cx.new(|cx| InputState::new(window, cx).placeholder(\"Search…\"));\n        Self { query }\n    }\n}\n```\n\nDo not turn every visual fragment into an entity. Entity boundaries have\nlifecycle and coordination costs; use them where retained identity matters.\n\n### Elements, views, and behavior systems are different\n\nDo not force every component into one template. The ecosystem contains:\n\n- semantic elements such as Button, Checkbox, Link, and Tabs;\n- compound behavior roots such as Dialog, Popover, Select, and Combobox;\n- entity-backed systems such as Input, Table, Tree, Dock, and notifications;\n- infrastructure such as positioning, virtualization, scrolling, focus traps,\n  motion, history, and measurement.\n\nAn element may be internally complex and still be value-like to its caller. A\nstateful system may expose render callbacks so applications own presentation\nwithout reimplementing behavior. Choose the public seam from the behavior,\nnot from how many `div`s appear in its renderer.\n\n## State ownership\n\nPut each state in the narrowest owner that can keep it correct:\n\n- domain state belongs to a model or feature view;\n- transient view state belongs to the view that renders it;\n- reusable behavioral state belongs to the component state designed for it;\n- tiny element-local state may use GPUI keyed element state;\n- shared application services may be stored as GPUI globals.\n\nPrefer controlled values for ordinary selection and toggles: pass the current\nvalue into the component, receive a requested change, update the owner, and\nrender again. A callback reports intent; it should not create a second hidden\nsource of truth.\n\n```rust\nCheckbox::new(\"show-hidden\")\n    .checked(self.show_hidden)\n    .label(\"Show hidden files\")\n    .on_click(cx.listener(|this, checked, _, cx| {\n        this.show_hidden = *checked;\n        cx.notify();\n    }))\n```\n\nCall `cx.notify()` after a mutation that changes rendering. Use `cx.emit(...)`\nfor a semantic event that an owner should handle, and `cx.subscribe(...)` or\n`cx.observe(...)` when the lifetime should follow an entity. Keep returned\nsubscriptions alive when the API requires it.\n\nDo not notify merely because a value was read or derived. Avoid unconditional\nnotification from `render`; it schedules another render and can create a\npermanent redraw loop. When several fields form one invariant, update them\ntogether and notify once. A reusable state type that cannot receive a context\nshould make that limitation explicit and require its owner to emit/notify.\n\n### Avoid state feedback loops\n\nText input, selection, filters, and controlled popups commonly have two paths:\nan external owner updates the value, and user interaction requests a new value.\nDo not send an owner-supplied value back through the user callback during sync.\nTrack the origin or compare coherent snapshots so each logical change is\nreported once. Make callbacks re-entrancy-safe when a callback can synchronously\nclose, replace, or update the component that invoked it.\n\n## Stable identity\n\nAn `ElementId` is part of behavior. It gives an element stable identity and keys\nelement-local or component state. A component may also use it as one input to\nits own focus, measurement, or animation identity; focus and scrolling are\notherwise owned by their dedicated handles.\n\n- Use stable domain IDs for rows, tabs, tree nodes, and repeated controls.\n- Namespace child IDs with their owning object when the same control repeats.\n- Never derive identity from a translated label or a mutable list index when\n  items can be inserted or reordered.\n- Do not generate a fresh random ID during `render`.\n\n```rust\nButton::new((\"delete-project\", project.id))\n    .danger()\n    .label(\"Delete\")\n```\n\nA changed ID means a changed UI identity. Treat that reset as deliberate.\n\nThe same rule applies to transition channels, overlay tokens, scroll handles,\nand persistence IDs. If two independently retained behaviors share a key, they\ncan overwrite each other's state; if one behavior changes keys every frame, it\nnever accumulates state.\n\n## Rendering and composition\n\nKeep `render` declarative: read current state, derive presentation values, and\ncompose elements. Move domain operations, parsing, and non-trivial mutation to\nnamed methods or services.\n\n```rust\nimpl Render for ProjectView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .v_flex()\n            .size_full()\n            .child(self.render_toolbar(cx))\n            .child(self.render_content(cx))\n    }\n}\n```\n\nExtract a render helper when it names a meaningful region and reduces the\namount of state a reader must hold at once. Extract a new component when the\nregion has its own reusable contract or retained lifecycle—not merely because\na builder chain is long.\n\nUse GPUI Component's fluent traits consistently (`Sizable`, `Disableable`,\n`Selectable`, and component-specific builders). Prefer `.when(...)` and\n`.when_some(...)` for small conditional refinements; use ordinary Rust control\nflow when branches represent substantially different interfaces.\n\nCompose from the standard semantic component before building a custom surface.\nDo not reproduce a menu, select, dropdown, or command palette from generic\n`div`s merely to match one screenshot. Reusing the component preserves its\nitem geometry, focus transfer, keyboard navigation, selection, disabled state,\ndismissal, and accessibility contract. If the standard component cannot\nexpress a recurring valid pattern, improve its explicit API instead of styling\narbitrary descendants at each call site.\n\nRender callbacks supplied by application code should be side-effect-free. A\nlist item renderer, menu builder, or dock panel renderer may run whenever its\nowner needs to measure or redraw. It must not perform a business operation,\nappend data, or register an unbounded subscription.\n\n## Behavior and presentation boundary\n\nThe durable Base rule is:\n\n> Base owns reusable behavior and the geometry required to implement it. The\n> presentation layer owns the product's visual language.\n\n“Headless” does not mean “one empty `div`.” Popup collision, keyboard\nnavigation, editing, virtualization, resize arithmetic, focus trapping, and\ndock reconciliation require internal structure and state. Moving that work to\nevery caller would not create flexibility; it would duplicate fragile\nbehavior.\n\nConversely, Base must not choose brand colors, typography, density, final\nicons, component variants, or application composition. Expose presentation\nthrough `Styled`, typed semantic-state styles, explicit parts, child slots, and\nitem renderers. Do not inspect arbitrary descendants to discover titles,\ndescriptions, or close buttons—make semantic parts explicit.\n\n## Theme and styling\n\nRead semantic values from the active theme and apply layout with GPUI's\n`Styled` methods:\n\n```rust\ndiv()\n    .bg(cx.theme().background)\n    .text_color(cx.theme().foreground)\n    .border_1()\n    .border_color(cx.theme().border)\n    .rounded(cx.theme().radius)\n```\n\nRules:\n\n- do not hard-code product colors, corner radii, spacing, or control geometry;\n- application code must not introduce raw hex, `rgb`/`rgba`, or `hsla`; read a\n  semantic color from `cx.theme()` or add the missing role to the product theme;\n- application layout should use GPUI's rem-based scale helpers (`p_2()`,\n  `gap_3()`, `w_64()`, `text_sm()`) instead of direct `px(...)` values;\n- use semantic tokens for meaning, not palette position;\n- keep state-independent geometry in the ordinary builder chain;\n- use GPUI `hover`, `active`, `focus`, and `focus_visible` modifiers for\n  runtime interaction states;\n- use a component's semantic state styles for checked, selected, pressed, or\n  disabled appearance;\n- keep popup ownership in explicit state so its trigger can render the open or\n  pressed appearance until dismissal;\n- guard hover/active refinements when a disabled control must not react;\n- keep component variants few and meaningful rather than adding a variant for\n  every call site.\n- bind primary styling to the decision area's real default commit and Enter\n  action; do not derive it from action count, frequency, or toolbar position.\n- keep Badge and Alert variants semantic and scarce. Ordinary metadata stays\n  neutral; do not map every enum case or section to a different color merely\n  because a variant exists.\n\nThe effective precedence is instance style, active semantic value states,\ndisabled state, then GPUI runtime interaction refinements. Later layers only\nreplace fields they set.\n\nPrefer `Theme::semantic_tokens()` for new application-owned presentation. The\nsemantic token surface contains generic color roles plus radius, spacing,\ntypography, and shadow scales; it deliberately avoids component names. Legacy\ncomponent-specific theme values still exist for compatibility but should not\nbecome the extension point for every application widget.\n\nThere is one current ownership caveat: `Theme::spacing_tokens()` projects the\ndefault scale, and `Theme::apply_semantic_tokens(...)` does not store custom\nspacing or elevation scales. An application that customizes those scales must\nretain its own `SemanticThemeTokens` (or narrower design-system state) and make\nthat state available to its components. Do not write a custom spacing snapshot\ninto the global theme and expect a later `cx.theme().semantic_tokens()` call to\nreturn it.\n\nEdit the global GPUI Component theme through `Theme::update(cx, |theme| ...)`.\nThe theme keeps the same colors twice (`colors` as solid colors, `tokens` as\nrenderable backgrounds that may carry a gradient) and the Base layer holds a\nprojection for its scrollbars and resize handles; `update` brings all three\nback in step after the closure and refreshes every window. An edit through\n`Theme::global_mut(cx)` updates only the field you touched — a sidebar can then\npaint its text from the new colors and its background from the old tokens —\nso it owns the rest: derive `tokens` from `colors`, call `Theme::sync_base(cx)`,\nrefresh the windows. `Theme::change(...)` performs the projection as part of a\ncomplete theme change.\n\nAn outward focus ring needs physical room. An ancestor with\n`overflow_hidden()` clips it. Prefer layouts that leave room; if a product must\nclip heavily, use the theme's focus-ring policy and retain the focused border\ninstead of silently hiding all keyboard focus.\n\n### Base font is the application zoom control\n\nThe Component Root plugin calls `window.set_rem_size(cx.theme().font_size)` from\nits `prepare` hook before the Root surface is rendered. Therefore the theme's\nbase font is not only body typography; it is the reference length for the\napplication's rem-based design scale. This deliberately follows the useful part\nof Tailwind's model: named type, spacing, and size steps share one relative base\ninstead of becoming unrelated pixel constants.\n\nChange zoom by updating the base font and refreshing the window:\n\n```rust\nTheme::update(cx, |theme| theme.font_size = px(18.));\n```\n\nThe base font itself is a pixel value because it anchors the scale. Descendant\napplication UI should normally use relative helpers—`text_sm()`, `gap_2()`,\n`px_3()`, `h_8()`, `size_4()`—so type, whitespace, controls, and icons respond\ntogether. A custom component that combines rem-based text with fixed-pixel\npadding or icon geometry must document why that part should not zoom.\n\nTreat every direct `px(...)` and raw color constructor in application UI as a\nreview finding. Accept it only for a documented physical/platform boundary,\nmeasured runtime geometry, raster/data color, or the theme/token definition\nitself. Convenience and matching a screenshot are not valid exceptions.\n\nAnything cached from resolved layout must include `window.rem_size()` in its\ninvalidation key, directly or through a revision that changes with it. This\nincludes wrapped row heights, text shaping/layout, virtual-list measurement,\npopup and dialog geometry, icon sizing derived from text, and custom canvas\nmetrics. The Command component's variable-height rows are an ecosystem example:\nthey remeasure when rem changes because the same fixed width wraps differently\nat a larger base font.\n\nDo not confuse this application zoom with Dock panel zoom. Dock zoom is a\nstateful layout operation that makes one tab group fill the DockArea\nwhile keeping the container chrome and the way back out. It must not modify the\nwindow rem size.\n\n## Events, actions, and focus\n\nUse pointer callbacks for pointer-specific behavior. Use GPUI Actions for\ncommands that should support key bindings, menus, or dispatch from multiple\ninputs. Keep action handlers close to the view that owns the command.\n\nModel one logical desktop command once. A toolbar Button, `DropdownMenu` item,\n`ContextMenu` item, menu-bar item, and key binding should dispatch the same\nAction or call the same owner method instead of copying five mutations. Derive\ntheir label, icon, shortcut, and enabled state from one command policy where\npractical, so the entry points cannot disagree. The menu owns navigation and\ndismissal; the feature owner still owns whether the command is allowed and\nwhat it does.\n\nPreserve semantic roles in the element choice. Use `Button` for commands even\nwhen the desired treatment is quiet—select `outline`, `ghost`, or an icon\npresentation instead of replacing it with `Link`. GPUI Kit applications\nreserve `Link` for targets opened by a browser or mail client, such as a URL,\nweb document, or email address. Use the relevant navigation component for an\nin-app destination and `Button`/`Action` for a command. This is a product\nconvention, not a limitation of `gpui_kit::base::Link`, whose `open_with` seam can\nroute a destination elsewhere.\n\nOnly stop propagation when a nested interaction must prevent its parent from\nhandling the same event. Blanket propagation stops break menus, selection,\ndragging, and window-level commands in ways that are difficult to diagnose.\n\nBind keys before building the menu bar. `cx.set_menus` reads the keymap at\nthe moment it is called and bakes each item's shortcut into the native menu,\nso a binding registered afterwards never shows next to its menu item and the\nitem does not react to the key. Call `cx.bind_keys` first, then\n`cx.set_menus`; if the keymap changes later (a user keymap file, a locale\nswitch that rebuilds the menus), call `cx.set_menus` again.\n\nMake focus ownership explicit:\n\n- retain a `FocusHandle` in the entity that owns keyboard interaction;\n- register key contexts and actions on the appropriate focused region;\n- transfer focus when opening an overlay and restore it on dismissal;\n- render a visible `focus_visible` state;\n- do not request focus unconditionally from `render`.\n\nA tracked handle is a Tab stop only when it says so: build it with\n`cx.focus_handle().tab_stop(true)` (or `.tab_index(n)`), because the element's\nown `tab_index`/`tab_stop` settings do not apply to a handle passed to\n`track_focus`. A stateless component may create that handle in `render`\nthrough `window.use_keyed_state(id, cx, |_, cx| cx.focus_handle().tab_stop(true))`;\nthe keyed state survives re-renders, so the Tab order is stable — this is\nwhat `Button` does.\n\nAttach a `key_context` and its `on_action` handlers to the same focused region.\nBindings are contextual: a registered Action without the intended focus path\nis not a working keyboard interaction. Composite widgets should implement the\ncomplete navigation model—arrow movement, Home/End or page movement where\nappropriate, confirmation, cancellation, and Tab behavior—rather than a few\nisolated shortcuts.\n\nModal surfaces must trap focus and restore the previous valid focus target on\ndismissal. Nested overlays dismiss from the top. Handle rapid close/open\nsequences without restoring focus through an intermediate, already-closing\nsurface.\n\n## Async work and side effects\n\nStart async work from an event, lifecycle hook, or named method—not as an\nunconditional side effect of `render`. Capture weak entities when work should\nnot keep a closed view alive. When the task completes, update state through the\nGPUI context, handle the case where the entity or window no longer exists, and\nnotify once after the coherent state change.\n\nRepresent async operations with explicit states such as idle, loading, loaded,\nand failed. Preserve usable previous data during refresh when possible. Prevent\nduplicate destructive submissions and surface recoverable errors in the UI;\ndo not rely on logs as user feedback.\n\nUse background executors for expensive parsing or computation, but keep GPUI\nentity mutation on the appropriate application context. Results can arrive\nafter the request, document, view, or selection has changed; attach a revision\nor identity and reject stale work rather than applying it to new state.\n\n## Layout, measurement, and scrolling\n\n`h_flex` centres its children on the cross axis; `v_flex` leaves flexbox's\ndefault, `stretch`. This matches Zed's `h_flex`, and it is what a row of\ncontrols wants, so a row of icon and label says nothing. It is not what a row\nof full-height columns wants: a column placed in a bare `h_flex` does not fill\nthe row's height, so a column taller than the row is centred and its top —\ncommonly a header — is clipped off the top of the window, with nothing near the\ncolumn to say why. A row whose children are columns says `items_stretch()`:\n\n```rust\nh_flex()\n    .items_stretch()\n    .size_full()\n    .child(sidebar)\n    .child(content)\n```\n\nMost UI should use GPUI layout rather than measuring itself. Measurement is a\ndeep behavior tool for popups, virtualization, editors, resize handles, charts,\nand similar components whose correctness depends on resolved geometry.\n\n- Put measurement and geometry in the layer that owns the behavior.\n- Observe bounds in prepaint only when ordinary layout cannot express the\n  relationship.\n- Never mutate unrelated application state every prepaint.\n- Treat measured data as frame- or revision-scoped; it can become stale after\n  typography, rem size, width, theme, or content changes.\n- Centralize shared geometry such as popup flipping and viewport clamping so\n  every overlay follows the same edge policy.\n\nFor alignment invariants, prefer construction over correction: sibling regions\nshould consume the same spacing token or shared inset instead of repeating\nequivalent literals. Add geometry assertions or visual regression coverage for\ncritical repeated edges, columns, and gaps. Exercise more than the default\nwindow: rem zoom and display scaling can turn fractional coordinates into a\none-physical-pixel drift even when the default screenshot looks aligned.\n\nMeasure the resolved result when reviewing precision, but do not encode a\nmeasured correction as a raw `px(...)` nudge. Trace the mismatch to duplicated\npadding, nested insets, border ownership, font metrics, or rounding, then fix\nthe structural owner.\n\n`h_flex()` and `v_flex()` are not mirror images: `h_flex()` centers its\nchildren on the cross axis, `v_flex()` leaves them stretching. A column placed\nin a row therefore takes its content's height, not the row's, and a column\ntaller than the row is centered — its header is pushed off the top edge and\nclipped. Give a full-height column `h_full()`, or give the row `items_start()`\nor `items_stretch()`, whenever the child owns a header, a footer, or a scroll\nregion that must resolve against the row's height.\n\nEvery scrollable region must have one owner. In flex layouts, apply\n`min_w_0()` or `min_h_0()` to the flexible child that is allowed to shrink.\nA flex item only drops its content-based automatic minimum size when its own\noverflow is not visible, so an ordinary flexible child refuses to shrink around\nlong content until you say so. `Scrollable` handles this for its own wrapper,\nbut a plain `div` between it and the flex container still needs the minimum\nreleased. Avoid accidental nested scrolling; route wheel input to the intended\naxis and preserve platform/wasm differences when an API is not portable.\n\nAttach `Scrollable` to the element that owns the full panel, editor, or window\nviewport so its scrollbar resolves against the region edge. Put content inset\ninside that scroll owner rather than wrapping the scroll owner in a padded\ncontainer. A scrollbar floating between content and the panel boundary usually\nreveals the wrong scroll owner or padding on the wrong layer.\n\n## Lists, tables, and large data\n\nUse virtualization when data can grow beyond a small, bounded collection. Keep\nrow identity separate from visible position and avoid cloning the full data set\non every render. Let a stateful list or table own navigation, selection, scroll\ncoordination, and visible-range calculation while item renderers own row\npresentation.\n\nSeparate:\n\n- source data and domain IDs;\n- filtering/sorting state;\n- selection state;\n- viewport/scroll state;\n- row rendering.\n\nThis keeps updates local and prevents the view tree from becoming the data\nmodel.\n\nVirtualization is a behavioral contract, not just a performance switch. Item\nmeasurement must be invalidated when width, typography, rem size, or row\ncontent changes. Keyboard selection and scroll-to-item must operate in model\ncoordinates even when most elements do not exist in the current frame.\n\n## Public API design\n\nFor reusable components:\n\n- constructors should establish valid defaults;\n- builders take and return `Self` and use domain language;\n- callbacks describe requested changes and include pointer events only when\n  modifiers or pointer details are meaningful;\n- evolvable behavioral seams use private fields, builders for construction,\n  and readers for inspection;\n- boolean readers use `is_` or `has_` where a same-named builder exists;\n- non-boolean setters use `with_` when readers need the plain field name;\n- explicit compound parts are preferable to inspecting arbitrary descendants;\n- adding reusable behavior must not force a product-level visual choice.\n\nPrivate fields are the default for behavioral state that must evolve without\nbreaking callers. Public fields are appropriate for deliberately record-like\nconfiguration, theme tokens, geometry, and serialized schemas. Every public\nstruct with public fields must carry `#[non_exhaustive]`. Provide constructors,\n`Default`, or builders so callers can create values without exhaustive struct\nliterals. This preserves the ability to add fields without breaking callers.\nApply this rule to new types and public API changes; unrelated existing types\ncan be migrated separately.\n\nKeep public module paths stable while reorganizing internals: use a module seam\nwith deliberate re-exports so folders can change without forcing downstream\nimports to change. Prefer platform control terminology and established project\nnaming over web-framework vocabulary.\n\n## Platform and capability boundaries\n\nDo not assume every native or web target supports the same facility. Window\ndecorations, accessibility bridges, system notifications, clipboard behavior,\nscroll gestures, fonts, and timing can differ. Put platform-specific code\nbehind a narrow capability seam and define the fallback behavior.\n\nA platform branch must preserve the semantic contract even if presentation\ndiffers. For example, a system notification may have different retraction\nsupport, but the application still needs a coherent delivery state. Test both\nthe shared state machine and the platform adapter where possible.\n\n## File and naming conventions\n\n- Name views and entities after product concepts: `ProjectList`,\n  `ProjectEditor`, `SettingsState`.\n- Name event handlers after intent: `confirm_delete`, `open_project`,\n  `on_query_changed`.\n- Keep one main responsibility per module; split a file when state ownership or\n  lifecycle can no longer be understood without reading unrelated behavior.\n- Keep component module, state, events, and focused tests together when they\n  change together.\n- Document invariants and surprising lifecycle constraints; do not narrate\n  obvious builder calls.\n- Use `rustfmt` and satisfy the workspace's Clippy rules. Avoid broad `allow`\n  attributes that conceal unrelated warnings.\n\n### Vocabulary is part of the API\n\nUse the same word for the same concept across components. Before naming a new\nmethod, search GPUI, `gpui-base`, and GPUI Component for the established term;\nprefer macOS/Windows control terminology where the ecosystem has no precedent.\nLocalized documentation preserves exact API identifiers and established UI\nframework terms when translation would reduce precision. Format identifiers as\ncode, explain retained terms when needed, and do not mix languages merely to\nmake ordinary prose sound technical.\n\n| Concept | Naming pattern | Example |\n| --- | --- | --- |\n| Value-like rendered control | noun | `Button`, `Checkbox`, `Tab` |\n| Retained behavioral model | `<Control>State` | `InputState`, `TableState` |\n| Imperative shared reference | `<Control>Handle` | `DialogHandle`, scroll handle |\n| Semantic notification | `<Control>Event` | `TableEvent`, `SelectEvent` |\n| Keyboard command | verb or intent noun | `Confirm`, `Cancel`, `SelectNext` |\n| Pluggable data/behavior owner | `<Role>Delegate` / `<Role>Provider` | `TableDelegate`, `CompletionProvider` |\n| Application-supplied presentation | `render_<part>` or `<part>_renderer` | `render_item` |\n| Construction | `new`, or a semantic constructor | `new`, `horizontal`, `vertical` |\n| Fluent property | noun/adjective | `label`, `disabled`, `selected`, `placement` |\n| General non-boolean replacement builder | `with_<field>` | `with_size`, `with_mode` |\n| In-place mutation | `set_<field>` | `set_items`, `set_selected_index` |\n| Boolean reader | `is_<adjective>` / `has_<noun>` | `is_open`, `is_closable`, `has_selection` |\n| Plain value reader | field noun | `placement`, `selected_value` |\n| Callback registration | `on_<event or intent>` | `on_click`, `on_open_change` |\n| Rendering a named region | `render_<region>` | `render_toolbar`, `render_content` |\n\nFor new APIs, fluent builders omit `set_` because they consume and return\n`Self`; mutation through `&mut self` uses `set_`. Preserve established public\nnames when changing them would cause needless churn. Existing builder names\nsuch as `set_position` are compatibility exceptions, not patterns for new APIs.\n\nA boolean reader is either `has_<noun>`, when the value holds something, or\n`is_<adjective>`, when it describes a state or a permission. Reach for the\nadjective whenever the action has one: `is_closable` over `can_close`,\n`is_zoomable` over `can_zoom`, `is_copyable` over `can_copy`. When the action\nis a verb phrase with no adjective form, name the thing it needs instead:\n`has_definition`, not `can_go_to_definition`. Do not add new `can_` readers.\n\nBoolean builders may use the field name (`disabled(bool)`) while their readers\nuse `is_disabled()`. For a public seam struct containing non-boolean fields,\nuse `with_item_ix(...)` for construction and `item_ix()` for reading so setter\nand getter names never collide. Prefer `_ix` for new local or internal\nzero-based indices, preserve established public terms such as `selected_index`,\nand do not introduce `_idx`. If callers never construct the seam value, do not\npublish a builder merely for symmetry.\n\n### Let the enclosing name carry the context\n\nA name is read inside something. A field is read inside its type and a parameter\ninside its method, so neither repeats what encloses it: `with_item_ix(ix)`, not\n`with_item_ix(item_ix)`.\n\nKeep one type's fields at the same level of abbreviation. A single field spelled\nout in full becomes the odd one out, and a reader goes looking for the\ndistinction that made it different. Because a builder is named `with_<field>`,\nshortening a field shortens its builder with it and the pair stays matched.\n\nShorten only where the enclosing name really does disambiguate. When a short\nform is also the established term for a *different* quantity elsewhere in the\necosystem, say which one you mean in the doc comment rather than lengthening the\nidentifier — the doc is read at the call, and it can explain what a longer name\ncould only hint at.\n\n### Use precise domain words\n\n- **selected** is persistent membership or the active item; **focused** is the\n  current keyboard target; **hovered** is pointer presence; **confirmed** is an\n  activation result. Never use them interchangeably.\n- **open/close** describes an overlay or disclosure state; **show/hide** is for\n  transient presentation requests; **expand/collapse** describes structure.\n- **disabled** prevents interaction; **readonly** permits navigation and\n  selection but prevents editing; **loading** prevents duplicate work while an\n  operation is pending. Spell the state `readonly` — one word, as the\n  `readonly(bool)` builder and `is_readonly()` reader do — in identifiers,\n  interface labels, and documentation alike; never `read-only` or `read only`.\n- **index** is a current positional coordinate; **id** is stable identity;\n  `IndexPath` represents hierarchical position. Do not persist or key\n  reorderable data by index.\n- **value** is controlled domain data; **presentation** is a read-only snapshot\n  prepared for rendering; **state** is retained behavior.\n- **placement** is a side or anchor policy; **position** is resolved geometry.\n- **size** is a semantic control tier; **width/height/bounds** are geometry.\n- **child/children** follows GPUI composition; named slots such as `header`,\n  `footer`, `trigger`, and `content` carry additional semantics.\n\nAvoid vague public names such as `data`, `item2`, `handle_action`, `update_ui`,\n`process`, `manager`, or `config` when a narrower domain term exists. `Manager`\nis appropriate only when a type truly coordinates a collection or lifecycle,\nas `ToastManager` does.\n\n### Type and module style\n\n- Rust types and Actions use `UpperCamelCase`; modules, functions, methods,\n  fields, and local variables use `snake_case`; constants use\n  `SCREAMING_SNAKE_CASE`.\n- A module named after a component owns its public seam. Internal folders may\n  split state, element, geometry, platform adapter, and tests without leaking\n  those folder names into imports.\n- Use singular module names for one component concept and established\n  ecosystem names for families (`input`, `table`, `dock`).\n- Suffix type-erased wrappers with `Any` only when they erase a real type\n  boundary, such as `AnyInputState` or `AnyElement`.\n- Suffix identifiers with `Id`, zero-based indices with `ix`, and collections\n  with meaningful plurals. Do not alternate `idx`, `index`, and `ix` in one\n  subsystem.\n- Name predicates positively when possible. A positive `enabled`/`visible`\n  contract is easier to compose than multiple negatives, but preserve\n  established API terms such as `disabled` where they match control semantics.\n\n### Callback and event wording\n\nUse `on_click` only for a genuine click-level contract. A controlled semantic\nprimitive in Base should prefer `on_change(next_value, ...)`; a styled\ncompatibility component may retain `on_click` when pointer details or existing\nAPI expectations matter. Do not invent a `ClickEvent` for a model-driven\nchange.\n\nName before/after lifecycle hooks precisely. `on_will_change` can veto or\nprepare; `on_change` observes a requested/current value contract; `on_confirm`\ncommits a choice; `on_dismiss` closes a transient surface. Document whether a\ncallback runs before internal state changes, after them, or instead of them,\nand whether it may synchronously re-enter the component.\n\n### Documentation and copy style\n\nPublic docs should begin with what a type does and who owns its state. Examples\nmust use current, compilable APIs and show stable IDs. Document defaults,\nplatform limitations, focus behavior, callback ordering, and any requirement\nto call `notify`, `emit`, or a theme synchronization method.\n\nFollow the [interface-language rules](./design-guides.md#interface-language) for\nlabels, commands, confirmation dialogs, capitalization, and ellipses. Keep one\ncanonical term for each domain object, command, and state.\n\nTranslation keys describe stable intent (`dialog.delete_project.title`), not a\nsource-language sentence or a screen coordinate. Never assemble a sentence\nfrom translated fragments or reuse one key for meanings that happen to share\nthe same English text.\n\nLocalize intent, not syntax. Give every locale control over word order,\npluralization, punctuation, and the amount of context it needs. Review strings\ninside the component and with realistic data. Tests or linting should catch\nmissing keys, unintended CJK text in English resources, three-dot ellipses,\nunreviewed ALL CAPS, and inconsistent fixed terms; human review still decides\nwhether repetition is justified by context. Verify every string inside its\ncomponent with realistic content, text expansion, and application zoom.\n\n## Testing strategy\n\nTest at the lowest layer that can prove the behavior:\n\n1. pure tests for state transitions, geometry, parsing, and ordering;\n2. GPUI context tests for entities, events, and subscriptions;\n3. `VisualTestContext` interaction tests for focus, keyboard, pointer, layout,\n   and rendered state;\n4. example or application smoke tests for complete workflows.\n\nFor an interactive component, cover the semantic contract rather than its\nimplementation details: pointer and keyboard activation, controlled value\nchanges, disabled behavior, focus movement, event count/order, stable identity,\nand important empty or failure states. Add a regression test before fixing a\nbug whenever the failure can be reproduced deterministically.\n\nFor UI behavior that depends on the real window system, test through the\naccessibility tree by role, label, value, enabled state, focus, and selection.\nRe-read the tree after every state-changing action because element indexes are\nsnapshots. Use screenshots for visual facts the semantic tree cannot express;\nuse coordinate input only as a fallback. Report automated and manual evidence\nseparately.\n\n## Performance rules\n\n- Do not mutate state or notify unconditionally in `render`.\n- Avoid rebuilding entities, subscriptions, focus handles, and expensive data\n  structures per frame.\n- Notify the narrowest owning entity after a coherent state change.\n- Virtualize long collections and render only the visible range.\n- Avoid cloning large strings or collections solely to satisfy a closure;\n  capture stable handles or shared data.\n- Measure before adding caches. A cache must have a clear invalidation owner.\n- Keep animation work bounded and honor reduced motion.\n\n## Common failure modes\n\nAvoid these patterns:\n\n- one entity containing the entire application's unrelated state;\n- business logic and network requests embedded in a long `render` method;\n- random or index-based `ElementId` values for reorderable content;\n- literal colors and radii that break custom themes;\n- custom clickable `div`s where a semantic component already supplies focus,\n  keyboard, disabled, and accessibility behavior;\n- duplicated local state that drifts from a controlled model value;\n- `cx.notify()` loops caused by mutation during every render;\n- nested scroll containers without explicit ownership;\n- a new component variant for a one-off screen;\n- confirmation dialogs for reversible, low-risk actions;\n- tests that call internal methods but never exercise keyboard or pointer\n  behavior.\n\n## Rules for coding agents\n\nBefore editing, an agent must read the nearest implementation, its tests, the\nre-export seam, and the relevant component documentation. It must search the\ncurrent source for signatures instead of translating a React, CSS, or old GPUI\nexample by analogy.\n\nFor each change, the agent should be able to name:\n\n1. the behavior owner and presentation owner;\n2. the retained identity and state lifecycle;\n3. the pointer, keyboard, focus, and accessibility contract;\n4. the layout and overflow owner;\n5. the theme tokens and intentional exceptions;\n6. the test that would fail if the behavior regressed.\n\nGenerated code must be reviewed and tested by a person. “Compiles” is not a UI\nquality bar, and a broad refactor that merely makes generated code look tidy is\nnot a substitute for matching the repository's architecture.\n\n## Implementation checklist\n\nBefore opening a change for review, confirm that:\n\n- state and side-effect ownership are explicit;\n- `RenderOnce` versus `Entity<T>` is chosen deliberately;\n- repeated elements have stable domain-based IDs;\n- theme tokens and component sizes replace isolated visual literals;\n- keyboard actions, focus, disabled state, and overlays work together;\n- loading, empty, error, and cancellation paths are represented;\n- long data sets use an appropriate virtualized component;\n- public API additions preserve dependency direction and encapsulation;\n- tests prove behavior at the appropriate layer;\n- formatting, Clippy, targeted tests, and relevant examples pass.\n\nSee [Getting Started](./getting-started.md) for application setup and the\ncomponent pages for current API details.\n","skills/gpui-kit/references/conventions.md":"# Component-family conventions\n\nUse this page to predict a component's shape before reading its detailed API. These conventions describe Rust GPUI Component. JavaScript uses its host's generated catalog; a Rust method is not automatically a JavaScript method.\n\n## Choose the family\n\n| Task | Family and constructor | State owner | Event or composition |\n| --- | --- | --- | --- |\n| Execute a command | `Button::new(\"save\")` | Application owns the operation | `on_click` receives a click event |\n| Change a boolean | `Checkbox::new(\"remember\")`, `Switch::new(\"enabled\")`, `Radio::new(\"choice\")` | Application supplies `checked(bool)` | `on_change` receives the requested `&bool` |\n| Choose one radio option | `RadioGroup::new(\"delivery\")` | Application supplies `selected_index(Option<usize>)` | `on_change` receives the requested `&usize` |\n| Edit retained text | `Input::new(&self.input)` | View retains `Entity<InputState>` | Retain the subscription; handle `InputEvent` |\n| Display a supplied patch | `Diff::new(&self.diff)` | View retains `Entity<DiffState>`; application parses supplied unified/Git diff with `DiffFile::parse`; one state shows all files | Readonly `RenderOnce` element; retain subscriptions to `DiffEvent` when needed |\n| Lay out fields | `Form::new()` | Children retain their own state | `child(Field)`, `columns`, `label_layout`, `footer` |\n| Supply a compound part | `Field::new()`, `Tab::new()` | Containing component owns placement/selection | Read the parent's accepted child type |\n\nConstructors establish the component family's ownership model. Do not infer that every `new` takes an ID or that every `child` accepts an arbitrary element. Keep domain IDs stable when controls are reordered. Positional selection APIs remain positional; applications map them to domain identity when needed.\n\n## A value request is different from a command\n\nFor Checkbox, Switch, Radio, and RadioGroup, use the same owner-update pattern:\n\n```rust\nSwitch::new(\"enabled\")\n    .checked(self.enabled)\n    .on_change(cx.listener(|this, next, _, cx| {\n        this.enabled = *next;\n        cx.notify();\n    }))\n```\n\nReplace Switch with Checkbox or Radio without changing the boolean callback shape. Radio represents selecting an option; its activation semantics still differ from toggling a Switch. RadioGroup supplies an index, so its owner stores `Some(*next)` instead.\n\n`on_change` requests a value; it does not mutate your application model. Existing `on_click` calls on these four controls remain valid compatibility aliases. Both names set one handler, and the last call wins. Use `Button::on_click` for commands. Retained controls such as Input keep their existing event/subscription API because the state entity, rather than a transient builder, owns their changes.\n\n## Form layout has independent decisions\n\n| Decision | API | Default |\n| --- | --- | --- |\n| Label above or beside its control | `label_layout(Axis::Vertical / Horizontal)` | Above |\n| Number of field columns | `columns(count)` | One |\n| A field spanning several columns | `Field::col_span(count)` | One |\n| Commands after the fields | `footer(element)` | No footer; supplied footer spans all columns and aligns to the trailing edge |\n\n`Form::horizontal()` and `h_form()` mean labels beside controls. They do not put all fields into one horizontal row. `Form::vertical()`, `v_form()`, and `layout(Axis)` remain supported.\n\n```rust\nForm::new()\n    .label_layout(Axis::Horizontal)\n    .columns(2)\n    .child(Field::new().label(\"Name\").child(Input::new(&self.name)))\n    .child(Field::new().label(\"Email\").child(Input::new(&self.email)))\n    .footer(Button::new(\"save\").label(\"Save\"))\n```\n\nThe footer supplies layout only: attach the save action to the Button. Form does not own submission, validation, responsive breakpoints, or data persistence. Choose column count for the available width. Put multiple action buttons in one supplied action row with a shared gap. Keep field descriptions with their Field so they follow its alignment.\n\n## Import capabilities explicitly\n\nComponents live in their component modules. Common capabilities may be extension traits, not inherent methods: import `ButtonVariants` for button variants, `Sizable` for size tiers, `Disableable` for supported disabled builders, `ActiveTheme` for theme access, and `WindowExt` for window overlays. Do not infer that every component supports every trait.\n\nUse the [complete application recipe](recipes.md) for imports, retained ownership, initialization, Root, and overlay layers. For a narrow task, load its component page and the relevant section of the coding/design guides; a component catalog is not a required reading sequence.\n\n## Verify the convention transfer\n\nWhen transferring a pattern to another family member, check that it compiles, receives the expected requested value, preserves controlled state after redraw, and behaves correctly when disabled. For Form, check label orientation independently of column count and keep footer geometry outside the field grid's individual cells.\n\nIn this repository, `cargo test -p gpui-kit-recipes` compiles the external-style consumer and runs its interaction tests, and `script/check-ai rust` runs the control-family event and compatibility tests and Form geometry tests. These are deterministic contract checks, not measured AI first-attempt success rates.\n","skills/gpui-kit/references/gpui/action.md":"# Actions & Keybindings\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Key Formats](#key-formats) · [Menu Bar Shortcuts](#menu-bar-shortcuts) · [Action Naming](#action-naming) · [Context-Aware Bindings](#context-aware-bindings) · [Best Practices](#best-practices)\n\n## Overview\n\nActions provide declarative keyboard-driven UI interactions in GPUI.\n\n**Key Concepts:**\n- Define actions with `actions!` macro or `#[derive(Action)]`\n- Bind keys with `cx.bind_keys()`\n- Handle with `.on_action()` on elements\n- Context-aware via `key_context()`\n\n## Quick Start\n\n### Simple Actions\n\n```rust\nuse gpui_kit::actions;\n\nactions!(editor, [MoveUp, MoveDown, Save, Quit]);\n\nconst CONTEXT: &str = \"Editor\";\n\npub fn init(cx: &mut App) {\n    cx.bind_keys([\n        KeyBinding::new(\"up\", MoveUp, Some(CONTEXT)),\n        KeyBinding::new(\"down\", MoveDown, Some(CONTEXT)),\n        KeyBinding::new(\"cmd-s\", Save, Some(CONTEXT)),\n        KeyBinding::new(\"cmd-q\", Quit, Some(CONTEXT)),\n    ]);\n}\n\nimpl Render for Editor {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .key_context(CONTEXT)\n            .on_action(cx.listener(Self::move_up))\n            .on_action(cx.listener(Self::move_down))\n            .on_action(cx.listener(Self::save))\n    }\n}\n\nimpl Editor {\n    fn move_up(&mut self, _: &MoveUp, cx: &mut Context<Self>) {\n        // Handle move up\n        cx.notify();\n    }\n\n    fn move_down(&mut self, _: &MoveDown, cx: &mut Context<Self>) {\n        cx.notify();\n    }\n\n    fn save(&mut self, _: &Save, cx: &mut Context<Self>) {\n        // Save logic\n        cx.notify();\n    }\n}\n```\n\n### Actions with Parameters\n\n```rust\n#[derive(Clone, PartialEq, Action, Deserialize)]\n#[action(namespace = editor)]\npub struct InsertText {\n    pub text: String,\n}\n\n#[derive(Action, Clone, PartialEq, Eq, Deserialize)]\n#[action(namespace = editor, no_json)]\npub struct Digit(pub u8);\n\ncx.bind_keys([\n    KeyBinding::new(\"0\", Digit(0), Some(CONTEXT)),\n    KeyBinding::new(\"1\", Digit(1), Some(CONTEXT)),\n    // ...\n]);\n\nimpl Editor {\n    fn on_digit(&mut self, action: &Digit, cx: &mut Context<Self>) {\n        self.insert_digit(action.0, cx);\n    }\n}\n```\n\n## Key Formats\n\n```rust\n// Modifiers\n\"cmd-s\"         // Command (macOS) / Ctrl (Windows/Linux)\n\"ctrl-c\"        // Control\n\"alt-f\"         // Alt\n\"shift-tab\"     // Shift\n\"cmd-ctrl-f\"    // Multiple modifiers\n\n// Keys\n\"a-z\", \"0-9\"    // Letters and numbers\n\"f1-f12\"        // Function keys\n\"up\", \"down\", \"left\", \"right\"\n\"enter\", \"escape\", \"space\", \"tab\"\n\"backspace\", \"delete\"\n\"-\", \"=\", \"[\", \"]\", etc.  // Special characters\n```\n\n## Menu Bar Shortcuts\n\n`cx.set_menus` reads the keymap **at the moment it is called** and bakes each\nitem's shortcut into the native menu. A key bound afterwards never appears next\nto its menu item, and the item does not react to that key. There is no event to\nhook: bind first, then build the menus, and rebuild them when the keymap\nchanges.\n\n```rust\npub fn init(cx: &mut App) {\n    // 1. Bindings first — the menu items copy their shortcuts from these.\n    cx.bind_keys([\n        KeyBinding::new(\"cmd-n\", NewChat, None),\n        KeyBinding::new(\"cmd-,\", OpenSettings, None),\n        KeyBinding::new(\"cmd-q\", Quit, None),\n    ]);\n\n    // 2. Then the menu bar.\n    cx.set_menus(vec![Menu {\n        name: \"File\".into(),\n        items: vec![\n            MenuItem::action(\"New Chat\", NewChat),\n            MenuItem::action(\"Settings…\", OpenSettings),\n            MenuItem::separator(),\n            MenuItem::action(\"Quit\", Quit),\n        ],\n    }]);\n}\n```\n\nCall `cx.set_menus` again after anything that changes bindings or labels: a\nuser keymap file loaded later, a locale switch that renames the items. `Undo`,\n`Redo`, `Cut`, `Copy`, `Paste` need no `on_action` of your own — give the item\nan `OsAction` and the platform forwards it to the focused text control.\n\n## Action Naming\n\nPrefer verb-noun pattern:\n\n```rust\nactions!([\n    OpenFile,      // ✅ Good\n    CloseWindow,   // ✅ Good\n    ToggleSidebar, // ✅ Good\n    Save,          // ✅ Good (common exception)\n]);\n```\n\n## Context-Aware Bindings\n\n```rust\nconst EDITOR_CONTEXT: &str = \"Editor\";\nconst MODAL_CONTEXT: &str = \"Modal\";\n\n// Same key, different contexts\ncx.bind_keys([\n    KeyBinding::new(\"escape\", CloseModal, Some(MODAL_CONTEXT)),\n    KeyBinding::new(\"escape\", ClearSelection, Some(EDITOR_CONTEXT)),\n]);\n\n// Set context on element\ndiv()\n    .key_context(EDITOR_CONTEXT)\n    .child(editor_content)\n```\n\n## Best Practices\n\n### ✅ Use Contexts\n\n```rust\n// ✅ Good: Context-aware\ndiv()\n    .key_context(\"MyComponent\")\n    .on_action(cx.listener(Self::handle))\n```\n\n### ✅ Name Actions Clearly\n\n```rust\n// ✅ Good: Clear intent\nactions!([\n    SaveDocument,\n    CloseTab,\n    TogglePreview,\n]);\n```\n\n### ✅ Handle with Listeners\n\n```rust\n// ✅ Good: Proper handler naming\nimpl MyComponent {\n    fn on_action_save(&mut self, _: &Save, cx: &mut Context<Self>) {\n        // Handle save\n        cx.notify();\n    }\n}\n\ndiv().on_action(cx.listener(Self::on_action_save))\n```\n\n","skills/gpui-kit/references/gpui/async.md":"# Async & Background Tasks\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Core Patterns](#core-patterns) · [Common Pitfalls](#common-pitfalls)\n\n## Overview\n\nGPUI provides integrated async runtime for foreground UI updates and background computation.\n\n**Key Concepts:**\n\n- **Foreground tasks**: UI thread, can update entities (`cx.spawn`)\n- **Background tasks**: Worker threads, CPU-intensive work (`cx.background_spawn`)\n- All entity updates happen on foreground thread\n\n## Quick Start\n\n### Foreground Tasks (UI Updates)\n\nWhen spawned from `Context<Self>`, the closure receives `(WeakEntity<Self>, &mut AsyncApp)`:\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx: &mut AsyncApp| {\n            // Runs on UI thread, can await and update entities\n            let data = fetch_from_api().await;\n\n            this.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            }).ok();\n        }).detach();\n    }\n}\n```\n\nWhen spawned from `&mut App` (not inside an entity), the closure receives only `(cx: &mut AsyncApp)`:\n\n```rust\ncx.spawn(async move |cx: &mut AsyncApp| {\n    // No entity reference\n}).detach();\n```\n\n### Spawn with Window Context (spawn_in)\n\nUse `spawn_in` when the task also needs window access (`update_in`):\n\n```rust\nimpl MyComponent {\n    fn animate(&mut self, window: &mut Window, cx: &mut Context<Self>) {\n        cx.spawn_in(window, async move |this, cx| {\n            // cx here is AsyncWindowContext\n            this.update_in(cx, |state, window, cx| {\n                // Can access window here\n                state.frame += 1;\n                cx.notify();\n            }).ok();\n        }).detach();\n    }\n}\n```\n\n### Background Tasks (Heavy Work)\n\n```rust\nimpl MyComponent {\n    fn process_file(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            // Runs on background thread, CPU-intensive\n            let result = cx\n                .background_spawn(async move { heavy_computation() })\n                .await;\n\n            // Back on the foreground to update UI\n            this.update(cx, |state, cx| {\n                state.result = result;\n                cx.notify();\n            }).ok();\n        })\n        .detach();\n    }\n}\n```\n\n### Task Management\n\n```rust\nstruct MyView {\n    _task: Task<()>,  // Prefix with _ if stored but not accessed\n}\n\nimpl MyView {\n    fn new(cx: &mut Context<Self>) -> Self {\n        let _task = cx.spawn(async move |this, cx: &mut AsyncApp| {\n            // Task automatically cancelled when dropped\n            loop {\n                cx.background_executor().timer(Duration::from_secs(1)).await;\n\n                this.update(cx, |state, cx| {\n                    state.tick();\n                    cx.notify();\n                }).ok();\n            }\n        });\n\n        Self { _task }\n    }\n}\n```\n\n## Core Patterns\n\n### 1. Async Data Fetching (from Context<Self>)\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    let data = fetch_data().await?;\n    this.update(cx, |state, cx| {\n        state.data = Some(data);\n        cx.notify();\n    })?;\n    Ok::<_, anyhow::Error>(())\n}).detach();\n```\n\n### 2. Background Computation + UI Update\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    let result = cx.background_spawn(async move { heavy_work() }).await;\n    this.update(cx, |state, cx| {\n        state.result = result;\n        cx.notify();\n    }).ok();\n})\n.detach();\n```\n\n### 3. Periodic Tasks\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    loop {\n        cx.background_executor().timer(Duration::from_secs(5)).await;\n\n        this.update(cx, |state, cx| {\n            state.tick();\n            cx.notify();\n        }).ok();\n    }\n}).detach();\n```\n\n### 4. Task Cancellation\n\nTasks are automatically cancelled when dropped. Store in struct to keep alive.\n\n## Common Pitfalls\n\n### ❌ Don't: Use `defer_in` and then update the same entity through its handle\n\n`cx.defer_in(window, callback)` schedules `callback` to run **on the current entity** — GPUI re-acquires that entity's lock to execute it. Calling `entity.update(cx, …)` on the *same* entity from within the deferred callback re-enters the lock and panics:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: list entity is locked for the defer_in; calling list.update re-enters\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        parent.update(cx, |this, cx| {\n            this.inner_list.update(cx, |_, _| {}); // PANIC if inner_list == the deferred entity\n        });\n    });\n}\n```\n\n```rust\n// ✅ Correct: use the direct &mut reference — no lock needed\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // Access list data directly through the &mut reference\n        list_state.delegate_mut().some_method();\n\n        // Update a *different* entity — fine, different lock\n        parent.update(cx, |this, cx| { /* … */ });\n\n        // Sync list state directly after parent update — no lock needed\n        list_state.delegate_mut().update_snapshot(new_val);\n    });\n}\n```\n\nThe rule: inside a `defer_in` callback, **never call `entity.update(cx, …)` or `entity.read(cx)` on the entity the `defer_in` was scheduled on**. Use the `&mut Entity` direct reference the callback provides instead.\n\n### ❌ Don't: Update entities from background tasks\n\n```rust\n// ❌ Wrong: Can't update entities from background thread\ncx.background_spawn(async move {\n    entity.update(cx, |state, cx| { // Compile error!\n        state.data = data;\n    });\n});\n```\n\n### ✅ Do: Await the background task inside a foreground task\n\n```rust\n// ✅ Correct: the foreground task awaits the background result\ncx.spawn(async move |this, cx| {\n    let data = cx.background_spawn(async move { load_data() }).await;\n    this.update(cx, |state, cx| {\n        state.data = data;\n        cx.notify();\n    }).ok();\n})\n.detach();\n```\n\nGPUI has no `Task::then`. Await the background task inside `cx.spawn`. The\nclosure receives `(WeakEntity<Self>, &mut AsyncApp)`, not the background result.\n\n","skills/gpui-kit/references/gpui/context.md":"# Context Management\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Operations](#common-operations) · [Context Hierarchy](#context-hierarchy) · [cx.listener](#cxlistener--binding-callbacks-to-self) · [subscribe_in](#subscribe_in--subscribe-with-window-access) · [observe_window_activation](#observe_window_activation) · [observe_global](#observe_global) · [defer / defer_in](#defer-and-defer_in) · [Naming Convention](#context-naming-convention)\n\n## Overview\n\nGPUI uses different context types for different scenarios:\n\n**Context Types:**\n- **`App`**: Global app state, entity creation\n- **`Window`**: Window-specific operations, painting, layout\n- **`Context<T>`**: Entity-specific context for component `T`\n- **`AsyncApp`**: Async context for foreground tasks\n- **`AsyncWindowContext`**: Async context with window access\n\n## Quick Start\n\n### Context<T> - Component Context\n\n```rust\nimpl MyComponent {\n    fn update_state(&mut self, cx: &mut Context<Self>) {\n        self.value = 42;\n        cx.notify(); // Trigger re-render\n\n        // Spawn async task\n        cx.spawn(async move |cx| {\n            // Async work\n        }).detach();\n\n        // Get current entity\n        let entity = cx.entity();\n    }\n}\n```\n\n### App - Global Context\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx: &mut App| {\n        gpui_kit::init(cx);\n\n        // Create entities\n        let entity = cx.new(|cx| MyState::default());\n\n        // Open windows (wraps the view in a `Root`)\n        gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| cx.new(|_| MyView))\n            .expect(\"failed to open window\");\n    });\n}\n```\n\n### Window - Window Context\n\n```rust\nimpl Render for MyView {\n    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        // Window operations\n        let is_focused = window.is_window_focused();\n        let bounds = window.bounds();\n\n        div().child(\"Content\")\n    }\n}\n```\n\n### AsyncApp - Async Context\n\n```rust\ncx.spawn(async move |cx: &mut AsyncApp| {\n    let data = fetch_data().await;\n\n    entity.update(cx, |state, inner_cx| {\n        state.data = data;\n        inner_cx.notify();\n    }).ok();\n}).detach();\n```\n\n## Common Operations\n\n### Entity Operations\n\n```rust\n// Create entity\nlet entity = cx.new(|cx| MyState::default());\n\n// Update entity\nentity.update(cx, |state, cx| {\n    state.value = 42;\n    cx.notify();\n});\n\n// Read entity\nlet value = entity.read(cx).value;\n```\n\n### Notifications and Events\n\n```rust\n// Trigger re-render\ncx.notify();\n\n// Emit event\ncx.emit(MyEvent::Updated);\n\n// Observe entity\ncx.observe(&entity, |this, observed, cx| {\n    // React to changes\n}).detach();\n\n// Subscribe to events\ncx.subscribe(&entity, |this, source, event, cx| {\n    // Handle event\n}).detach();\n```\n\n### Window Operations\n\n```rust\n// Window state\nlet focused = window.is_window_focused();\nlet bounds = window.bounds();\nlet scale = window.scale_factor();\n\n// Close window\nwindow.remove_window();\n```\n\n### Async Operations\n\n```rust\n// Spawn foreground task\ncx.spawn(async move |cx| {\n    // Async work with entity access\n}).detach();\n\n// Spawn background task\ncx.background_spawn(async move {\n    // Heavy computation\n}).detach();\n```\n\n## Context Hierarchy\n\n```\nApp (Global)\n  └─ Window (Per-window)\n       └─ Context<T> (Per-component)\n            └─ AsyncApp (In async tasks)\n                 └─ AsyncWindowContext (Async + Window)\n```\n\n## cx.listener — Binding Callbacks to Self\n\n`cx.listener` creates a callback that borrows `&mut self` (the current entity). Use it for `on_click`, `on_action`, and other element event handlers:\n\n```rust\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .on_action(cx.listener(Self::on_save))\n            .child(\n                Button::new(\"btn\")\n                    .on_click(cx.listener(|this, _event, _window, cx| {\n                        this.count += 1;\n                        cx.notify();\n                    }))\n            )\n    }\n}\n\nimpl MyView {\n    fn on_save(&mut self, _: &Save, _window: &mut Window, cx: &mut Context<Self>) {\n        cx.notify();\n    }\n}\n```\n\n`cx.listener(Self::method)` is equivalent to creating a closure that calls `self.method(...)`.\n\n## subscribe_in — Subscribe with Window Access\n\nUse `subscribe_in` (instead of `subscribe`) when the callback needs `&mut Window`:\n\n```rust\nlet _subscription = cx.subscribe_in(&input, window, |this, state, event, window, cx| {\n    match event {\n        InputEvent::Change => {\n            let val = state.read(cx).value();\n            this.on_input_change(val, window, cx);\n        }\n        _ => {}\n    }\n});\n// Store _subscription in struct to keep it alive\n```\n\n`subscribe` vs `subscribe_in`:\n- `subscribe(&entity, |this, source, event, cx|)` — no window access\n- `subscribe_in(&entity, window, |this, source, event, window, cx|)` — has window access\n\n## observe_window_activation\n\nReact when the window gains or loses focus:\n\n```rust\nlet _sub = cx.observe_window_activation(window, |this, window, cx| {\n    if window.is_window_active() {\n        this.resume(cx);\n    } else {\n        this.pause(cx);\n    }\n});\n```\n\n## observe_global\n\nReact when a global value changes:\n\n```rust\ncx.observe_global::<Theme>(|cx| {\n    // Theme changed — react\n    cx.notify();\n});\n```\n\n## defer and defer_in\n\nSchedule work after the current update completes:\n\n```rust\n// defer: runs after current App update, no window access\ncx.defer(|cx| {\n    // Runs after current entity update is done\n});\n\n// defer_in: runs after update, with window access\ncx.defer_in(window, |this, window, cx| {\n    // Can access window here\n    // CAUTION: never call entity.update(cx) on *this same entity* inside defer_in\n    // — it re-enters the lock and panics. Use the &mut self reference directly.\n    this.some_method(window, cx);\n});\n```\n\n## Context Naming Convention\n\nAlways name contexts `cx` regardless of type:\n\n```rust\nfn new(window: &mut Window, cx: &mut App) {}             // cx = App\nimpl Render for View {\n    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) {}  // cx = Context<Self>\n}\ncx.spawn(async move |this, cx: &mut AsyncApp| {})         // cx = AsyncApp\n```\n","skills/gpui-kit/references/gpui/element-advanced.md":"# Advanced Element Patterns\n\n**Contents:** [Custom Layout Algorithms](#custom-layout-algorithms) · [Element Composition with Traits](#element-composition-with-traits) · [Async Element Updates](#async-element-updates) · [Element Memoization](#element-memoization) · [Virtual List Pattern](#virtual-list-pattern)\n\n## Custom Layout Algorithms\n\nImplementing custom layout algorithms not supported by GPUI's built-in layouts.\n\n### Masonry Layout (Pinterest-Style)\n\n```rust\npub struct MasonryLayout {\n    id: ElementId,\n    columns: usize,\n    gap: Pixels,\n    children: Vec<AnyElement>,\n}\n\nstruct MasonryLayoutState {\n    column_layouts: Vec<Vec<LayoutId>>,\n    column_heights: Vec<Pixels>,\n}\n\nstruct MasonryPaintState {\n    child_bounds: Vec<Bounds<Pixels>>,\n}\n\nimpl Element for MasonryLayout {\n    type RequestLayoutState = MasonryLayoutState;\n    type PrepaintState = MasonryPaintState;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, MasonryLayoutState) {\n        // Initialize columns\n        let mut columns: Vec<Vec<LayoutId>> = vec![Vec::new(); self.columns];\n        let mut column_heights = vec![px(0.); self.columns];\n\n        // Distribute children across columns\n        for child in &mut self.children {\n            let (child_layout_id, _) = child.request_layout(\n                global_id,\n                inspector_id,\n                window,\n                cx\n            );\n\n            let child_size = window.layout_bounds(child_layout_id).size;\n\n            // Find shortest column\n            let min_column_idx = column_heights\n                .iter()\n                .enumerate()\n                .min_by(|a, b| a.1.partial_cmp(b.1).unwrap())\n                .unwrap()\n                .0;\n\n            // Add child to shortest column\n            columns[min_column_idx].push(child_layout_id);\n            column_heights[min_column_idx] += child_size.height + self.gap;\n        }\n\n        // Calculate total layout size\n        let column_width = px(200.); // Fixed column width\n        let total_width = column_width * self.columns as f32\n            + self.gap * (self.columns - 1) as f32;\n        let total_height = column_heights.iter()\n            .max_by(|a, b| a.partial_cmp(b).unwrap())\n            .copied()\n            .unwrap_or(px(0.));\n\n        let layout_id = window.request_layout(\n            Style {\n                size: size(total_width, total_height),\n                ..default()\n            },\n            columns.iter().flatten().copied().collect(),\n            cx\n        );\n\n        (layout_id, MasonryLayoutState {\n            column_layouts: columns,\n            column_heights,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut MasonryLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> MasonryPaintState {\n        let column_width = px(200.);\n        let mut child_bounds = Vec::new();\n\n        // Position children in columns\n        for (col_idx, column) in layout_state.column_layouts.iter().enumerate() {\n            let x_offset = bounds.left()\n                + (column_width + self.gap) * col_idx as f32;\n            let mut y_offset = bounds.top();\n\n            for (child_idx, layout_id) in column.iter().enumerate() {\n                let child_size = window.layout_bounds(*layout_id).size;\n                let child_bound = Bounds::new(\n                    point(x_offset, y_offset),\n                    size(column_width, child_size.height)\n                );\n\n                self.children[child_idx].prepaint(\n                    global_id,\n                    inspector_id,\n                    child_bound,\n                    window,\n                    cx\n                );\n\n                child_bounds.push(child_bound);\n                y_offset += child_size.height + self.gap;\n            }\n        }\n\n        MasonryPaintState { child_bounds }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        _bounds: Bounds<Pixels>,\n        _layout_state: &mut MasonryLayoutState,\n        paint_state: &mut MasonryPaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        for (child, bounds) in self.children.iter_mut().zip(&paint_state.child_bounds) {\n            child.paint(global_id, inspector_id, *bounds, window, cx);\n        }\n    }\n}\n```\n\n### Circular Layout\n\n```rust\npub struct CircularLayout {\n    id: ElementId,\n    radius: Pixels,\n    children: Vec<AnyElement>,\n}\n\nimpl Element for CircularLayout {\n    type RequestLayoutState = Vec<LayoutId>;\n    type PrepaintState = Vec<Bounds<Pixels>>;\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Vec<LayoutId>) {\n        let child_layouts: Vec<_> = self.children\n            .iter_mut()\n            .map(|child| child.request_layout(global_id, inspector_id, window, cx).0)\n            .collect();\n\n        let diameter = self.radius * 2.;\n        let layout_id = window.request_layout(\n            Style {\n                size: size(diameter, diameter),\n                ..default()\n            },\n            child_layouts.clone(),\n            cx\n        );\n\n        (layout_id, child_layouts)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_ids: &mut Vec<LayoutId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Vec<Bounds<Pixels>> {\n        let center = bounds.center();\n        let angle_step = 2.0 * std::f32::consts::PI / self.children.len() as f32;\n\n        let mut child_bounds = Vec::new();\n\n        for (i, (child, layout_id)) in self.children.iter_mut()\n            .zip(layout_ids.iter())\n            .enumerate()\n        {\n            let angle = angle_step * i as f32;\n            let child_size = window.layout_bounds(*layout_id).size;\n\n            // Position child on circle\n            let x = center.x + self.radius * angle.cos() - child_size.width / 2.;\n            let y = center.y + self.radius * angle.sin() - child_size.height / 2.;\n\n            let child_bound = Bounds::new(point(x, y), child_size);\n\n            child.prepaint(global_id, inspector_id, child_bound, window, cx);\n            child_bounds.push(child_bound);\n        }\n\n        child_bounds\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        _bounds: Bounds<Pixels>,\n        _layout_ids: &mut Vec<LayoutId>,\n        child_bounds: &mut Vec<Bounds<Pixels>>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        for (child, bounds) in self.children.iter_mut().zip(child_bounds) {\n            child.paint(global_id, inspector_id, *bounds, window, cx);\n        }\n    }\n}\n```\n\n## Element Composition with Traits\n\nCreate reusable behaviors via traits for element composition.\n\n### Hoverable Trait\n\n```rust\npub trait Hoverable: Element {\n    fn on_hover<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static;\n\n    fn on_hover_end<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static;\n}\n\n// Implementation for custom element\npub struct HoverableElement {\n    id: ElementId,\n    content: AnyElement,\n    hover_handlers: Vec<Box<dyn Fn(&mut Window, &mut App)>>,\n    hover_end_handlers: Vec<Box<dyn Fn(&mut Window, &mut App)>>,\n    was_hovered: bool,\n}\n\nimpl Hoverable for HoverableElement {\n    fn on_hover<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static\n    {\n        self.hover_handlers.push(Box::new(f));\n        self\n    }\n\n    fn on_hover_end<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static\n    {\n        self.hover_end_handlers.push(Box::new(f));\n        self\n    }\n}\n\nimpl Element for HoverableElement {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = Hitbox;\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout: &mut LayoutId,\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let is_hovered = hitbox.is_hovered(window);\n\n        // Trigger hover events\n        if is_hovered && !self.was_hovered {\n            for handler in &self.hover_handlers {\n                handler(window, cx);\n            }\n        } else if !is_hovered && self.was_hovered {\n            for handler in &self.hover_end_handlers {\n                handler(window, cx);\n            }\n        }\n\n        self.was_hovered = is_hovered;\n\n        // Paint content\n        self.content.paint(bounds, window, cx);\n    }\n\n    // ... other methods\n}\n```\n\n### Clickable Trait\n\n```rust\npub trait Clickable: Element {\n    fn on_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static;\n\n    fn on_double_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static;\n}\n\npub struct ClickableElement {\n    id: ElementId,\n    content: AnyElement,\n    click_handlers: Vec<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    double_click_handlers: Vec<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    last_click_time: Option<Instant>,\n}\n\nimpl Clickable for ClickableElement {\n    fn on_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static\n    {\n        self.click_handlers.push(Box::new(f));\n        self\n    }\n\n    fn on_double_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static\n    {\n        self.double_click_handlers.push(Box::new(f));\n        self\n    }\n}\n```\n\n## Async Element Updates\n\nElements that update based on async operations.\n\n```rust\npub struct AsyncElement {\n    id: ElementId,\n    state: Entity<AsyncState>,\n    loading: bool,\n    data: Option<String>,\n}\n\npub struct AsyncState {\n    loading: bool,\n    data: Option<String>,\n}\n\nimpl Element for AsyncElement {\n    type RequestLayoutState = ();\n    type PrepaintState = Hitbox;\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout: &mut (),\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Display loading or data\n        if self.loading {\n            // Paint loading indicator\n            self.paint_loading(bounds, window, cx);\n        } else if let Some(data) = &self.data {\n            // Paint data\n            self.paint_data(data, bounds, window, cx);\n        }\n\n        // Trigger async update on click\n        window.on_mouse_event({\n            let state = self.state.clone();\n            let hitbox = hitbox.clone();\n\n            move |event: &MouseUpEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Spawn async task\n                    cx.spawn({\n                        let state = state.clone();\n                        async move {\n                            // Perform async operation\n                            let result = fetch_data_async().await;\n\n                            // Update state on completion\n                            state.update(cx, |state, cx| {\n                                state.loading = false;\n                                state.data = Some(result);\n                                cx.notify();\n                            });\n                        }\n                    }).detach();\n\n                    // Set loading state immediately\n                    state.update(cx, |state, cx| {\n                        state.loading = true;\n                        cx.notify();\n                    });\n\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n\n    // ... other methods\n}\n\nasync fn fetch_data_async() -> String {\n    // Simulate async operation\n    tokio::time::sleep(Duration::from_secs(1)).await;\n    \"Data loaded!\".to_string()\n}\n```\n\n## Element Memoization\n\nOptimize performance by memoizing expensive element computations.\n\n```rust\npub struct MemoizedElement<T: PartialEq + Clone + 'static> {\n    id: ElementId,\n    value: T,\n    render_fn: Box<dyn Fn(&T) -> AnyElement>,\n    cached_element: Option<AnyElement>,\n    last_value: Option<T>,\n}\n\nimpl<T: PartialEq + Clone + 'static> MemoizedElement<T> {\n    pub fn new<F>(id: ElementId, value: T, render_fn: F) -> Self\n    where\n        F: Fn(&T) -> AnyElement + 'static,\n    {\n        Self {\n            id,\n            value,\n            render_fn: Box::new(render_fn),\n            cached_element: None,\n            last_value: None,\n        }\n    }\n}\n\nimpl<T: PartialEq + Clone + 'static> Element for MemoizedElement<T> {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = ();\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, LayoutId) {\n        // Check if value changed\n        if self.last_value.as_ref() != Some(&self.value) || self.cached_element.is_none() {\n            // Recompute element\n            self.cached_element = Some((self.render_fn)(&self.value));\n            self.last_value = Some(self.value.clone());\n        }\n\n        // Request layout for cached element\n        let (layout_id, _) = self.cached_element\n            .as_mut()\n            .unwrap()\n            .request_layout(global_id, inspector_id, window, cx);\n\n        (layout_id, layout_id)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout_id: &mut LayoutId,\n        window: &mut Window,\n        cx: &mut App\n    ) -> () {\n        self.cached_element\n            .as_mut()\n            .unwrap()\n            .prepaint(global_id, inspector_id, bounds, window, cx);\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout_id: &mut LayoutId,\n        _: &mut (),\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        self.cached_element\n            .as_mut()\n            .unwrap()\n            .paint(global_id, inspector_id, bounds, window, cx);\n    }\n}\n\n// Usage\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    MemoizedElement::new(\n        ElementId::Name(\"memoized\".into()),\n        self.expensive_value.clone(),\n        |value| {\n            // Expensive rendering function only called when value changes\n            div().child(format!(\"Computed: {}\", value))\n        }\n    )\n}\n```\n\n## Virtual List Pattern\n\nEfficiently render large lists by only rendering visible items.\n\n```rust\npub struct VirtualList {\n    id: ElementId,\n    item_count: usize,\n    item_height: Pixels,\n    viewport_height: Pixels,\n    scroll_offset: Pixels,\n    render_item: Box<dyn Fn(usize) -> AnyElement>,\n}\n\nstruct VirtualListState {\n    visible_range: Range<usize>,\n    visible_item_layouts: Vec<LayoutId>,\n}\n\nimpl Element for VirtualList {\n    type RequestLayoutState = VirtualListState;\n    type PrepaintState = Hitbox;\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, VirtualListState) {\n        // Calculate visible range\n        let start_idx = (self.scroll_offset / self.item_height).floor() as usize;\n        let end_idx = ((self.scroll_offset + self.viewport_height) / self.item_height)\n            .ceil() as usize;\n        let visible_range = start_idx..end_idx.min(self.item_count);\n\n        // Request layout only for visible items\n        let visible_item_layouts: Vec<_> = visible_range.clone()\n            .map(|i| {\n                let mut item = (self.render_item)(i);\n                item.request_layout(global_id, inspector_id, window, cx).0\n            })\n            .collect();\n\n        let total_height = self.item_height * self.item_count as f32;\n        let layout_id = window.request_layout(\n            Style {\n                size: size(relative(1.0), self.viewport_height),\n                overflow: Overflow::Hidden,\n                ..default()\n            },\n            visible_item_layouts.clone(),\n            cx\n        );\n\n        (layout_id, VirtualListState {\n            visible_range,\n            visible_item_layouts,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        state: &mut VirtualListState,\n        window: &mut Window,\n        _cx: &mut App\n    ) -> Hitbox {\n        // Prepaint visible items at correct positions\n        for (i, layout_id) in state.visible_item_layouts.iter().enumerate() {\n            let item_idx = state.visible_range.start + i;\n            let y = item_idx as f32 * self.item_height - self.scroll_offset;\n            let item_bounds = Bounds::new(\n                point(bounds.left(), bounds.top() + y),\n                size(bounds.width(), self.item_height)\n            );\n\n            // Prepaint if visible\n            if item_bounds.intersects(&bounds) {\n                // Prepaint item...\n            }\n        }\n\n        window.insert_hitbox(bounds, HitboxBehavior::Normal)\n    }\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        state: &mut VirtualListState,\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint visible items\n        for (i, _layout_id) in state.visible_item_layouts.iter().enumerate() {\n            let item_idx = state.visible_range.start + i;\n            let y = item_idx as f32 * self.item_height - self.scroll_offset;\n            let item_bounds = Bounds::new(\n                point(bounds.left(), bounds.top() + y),\n                size(bounds.width(), self.item_height)\n            );\n\n            if item_bounds.intersects(&bounds) {\n                let mut item = (self.render_item)(item_idx);\n                item.paint(item_bounds, window, cx);\n            }\n        }\n\n        // Handle scroll\n        window.on_mouse_event({\n            let hitbox = hitbox.clone();\n            let total_height = self.item_height * self.item_count as f32;\n\n            move |event: &ScrollWheelEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    self.scroll_offset -= event.delta.y;\n                    self.scroll_offset = self.scroll_offset\n                        .max(px(0.))\n                        .min(total_height - self.viewport_height);\n                    cx.notify();\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\n// Usage: Efficiently render 10,000 items\nlet virtual_list = VirtualList {\n    id: ElementId::Name(\"large-list\".into()),\n    item_count: 10_000,\n    item_height: px(40.),\n    viewport_height: px(400.),\n    scroll_offset: px(0.),\n    render_item: Box::new(|index| {\n        div().child(format!(\"Item {}\", index))\n    }),\n};\n```\n\nThese advanced patterns enable sophisticated element implementations while maintaining performance and code quality.\n","skills/gpui-kit/references/gpui/element-api.md":"# Element API Reference\n\n**Contents:** [Element Trait Structure](#element-trait-structure) · [Associated Types](#associated-types) · [Methods](#methods) · [IntoElement Integration](#intoelement-integration) · [Layout System Integration](#layout-system-integration) · [Hitbox System](#hitbox-system) · [Event Handling](#event-handling) · [Cursor Styles](#cursor-styles)\n\n## Element Trait Structure\n\nThe `Element` trait requires implementing three associated types and five methods:\n\n```rust\npub trait Element: 'static + IntoElement {\n    type RequestLayoutState: 'static;\n    type PrepaintState: 'static;\n\n    fn id(&self) -> Option<ElementId>;\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>>;\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App,\n    ) -> (LayoutId, Self::RequestLayoutState);\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        request_layout: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App,\n    ) -> Self::PrepaintState;\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        request_layout: &mut Self::RequestLayoutState,\n        prepaint: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App,\n    );\n}\n```\n\n## Associated Types\n\n### RequestLayoutState\n\nData passed from `request_layout` to `prepaint` and `paint` phases.\n\n**Usage:**\n- Store layout calculations (styled text, child layout IDs)\n- Cache expensive computations\n- Pass child state between phases\n\n**Examples:**\n```rust\n// Simple: no state needed\ntype RequestLayoutState = ();\n\n// Single value\ntype RequestLayoutState = StyledText;\n\n// Multiple values\ntype RequestLayoutState = (StyledText, Vec<ChildLayout>);\n\n// Complex struct\npub struct MyLayoutState {\n    pub styled_text: StyledText,\n    pub child_layouts: Vec<(LayoutId, ChildState)>,\n    pub computed_bounds: Bounds<Pixels>,\n}\ntype RequestLayoutState = MyLayoutState;\n```\n\n### PrepaintState\n\nData passed from `prepaint` to `paint` phase.\n\n**Usage:**\n- Store hitboxes for interaction\n- Cache visual bounds\n- Store prepaint results\n\n**Examples:**\n```rust\n// Simple: just a hitbox\ntype PrepaintState = Hitbox;\n\n// Optional hitbox\ntype PrepaintState = Option<Hitbox>;\n\n// Multiple values\ntype PrepaintState = (Hitbox, Vec<Bounds<Pixels>>);\n\n// Complex struct\npub struct MyPaintState {\n    pub hitbox: Hitbox,\n    pub child_bounds: Vec<Bounds<Pixels>>,\n    pub visible_range: Range<usize>,\n}\ntype PrepaintState = MyPaintState;\n```\n\n## Methods\n\n### id()\n\nReturns optional unique identifier for debugging and inspection.\n\n```rust\nfn id(&self) -> Option<ElementId> {\n    Some(self.id.clone())\n}\n\n// Or if no ID needed\nfn id(&self) -> Option<ElementId> {\n    None\n}\n```\n\n### source_location()\n\nReturns source location for debugging. Usually returns `None` unless debugging is needed.\n\n```rust\nfn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n    None\n}\n```\n\n### request_layout()\n\nCalculates sizes and positions for the element tree.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Returns:**\n- `(LayoutId, Self::RequestLayoutState)`: Layout ID and state for next phases\n\n**Responsibilities:**\n1. Calculate child layouts by calling `child.request_layout()`\n2. Create own layout using `window.request_layout()`\n3. Return layout ID and state to pass to next phases\n\n**Example:**\n```rust\nfn request_layout(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    window: &mut Window,\n    cx: &mut App,\n) -> (LayoutId, Self::RequestLayoutState) {\n    // 1. Calculate child layouts\n    let child_layout_id = self.child.request_layout(\n        global_id,\n        inspector_id,\n        window,\n        cx\n    ).0;\n\n    // 2. Create own layout\n    let layout_id = window.request_layout(\n        Style {\n            size: size(px(200.), px(100.)),\n            ..default()\n        },\n        vec![child_layout_id],\n        cx\n    );\n\n    // 3. Return layout ID and state\n    (layout_id, MyLayoutState { child_layout_id })\n}\n```\n\n### prepaint()\n\nPrepares for painting by creating hitboxes and computing final bounds.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `bounds`: Final bounds calculated by layout engine\n- `request_layout`: Mutable reference to layout state\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Returns:**\n- `Self::PrepaintState`: State for paint phase\n\n**Responsibilities:**\n1. Compute final child bounds based on layout bounds\n2. Call `child.prepaint()` for all children\n3. Create hitboxes using `window.insert_hitbox()`\n4. Return state for paint phase\n\n**Example:**\n```rust\nfn prepaint(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    bounds: Bounds<Pixels>,\n    request_layout: &mut Self::RequestLayoutState,\n    window: &mut Window,\n    cx: &mut App,\n) -> Self::PrepaintState {\n    // 1. Compute child bounds\n    let child_bounds = bounds; // or calculated subset\n\n    // 2. Prepaint children\n    self.child.prepaint(\n        global_id,\n        inspector_id,\n        child_bounds,\n        &mut request_layout.child_state,\n        window,\n        cx\n    );\n\n    // 3. Create hitboxes\n    let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n    // 4. Return paint state\n    MyPaintState { hitbox }\n}\n```\n\n### paint()\n\nRenders the element and handles interactions.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `bounds`: Final bounds for rendering\n- `request_layout`: Mutable reference to layout state\n- `prepaint`: Mutable reference to prepaint state\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Responsibilities:**\n1. Paint children first (bottom to top)\n2. Paint own content (backgrounds, borders, etc.)\n3. Set up interactions (mouse events, cursor styles)\n\n**Example:**\n```rust\nfn paint(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    bounds: Bounds<Pixels>,\n    request_layout: &mut Self::RequestLayoutState,\n    prepaint: &mut Self::PrepaintState,\n    window: &mut Window,\n    cx: &mut App,\n) {\n    // 1. Paint children first\n    self.child.paint(\n        global_id,\n        inspector_id,\n        child_bounds,\n        &mut request_layout.child_state,\n        &mut prepaint.child_paint_state,\n        window,\n        cx\n    );\n\n    // 2. Paint own content\n    window.paint_quad(paint_quad(\n        bounds,\n        Anchor::all(px(4.)),\n        cx.theme().background,\n    ));\n\n    // 3. Set up interactions\n    window.on_mouse_event({\n        let hitbox = prepaint.hitbox.clone();\n        move |event: &MouseDownEvent, phase, window, cx| {\n            if hitbox.is_hovered(window) && phase.bubble() {\n                // Handle click\n                cx.stop_propagation();\n            }\n        }\n    });\n\n    window.set_cursor_style(CursorStyle::PointingHand, &prepaint.hitbox);\n}\n```\n\n## IntoElement Integration\n\nElements must also implement `IntoElement` to be used as children:\n\n```rust\nimpl IntoElement for MyElement {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n```\n\nThis allows your custom element to be used directly in the element tree:\n\n```rust\ndiv()\n    .child(MyElement::new()) // Works because of IntoElement\n```\n\n## Common Parameters\n\n### Global and Inspector IDs\n\nBoth are optional identifiers used for debugging and inspection:\n- `global_id`: Unique identifier across entire app\n- `inspector_id`: Identifier for dev tools/inspector\n\nUsually passed through to children without modification.\n\n### Window and Context\n\n- `window: &mut Window`: Window-specific operations (painting, hitboxes, events)\n- `cx: &mut App`: App-wide operations (spawning tasks, accessing globals)\n\n## Layout System Integration\n\n### window.request_layout()\n\nCreates a layout node with specified style and children:\n\n```rust\nlet layout_id = window.request_layout(\n    Style {\n        size: size(px(200.), px(100.)),\n        flex: Flex::Column,\n        gap: px(8.),\n        ..default()\n    },\n    vec![child1_layout_id, child2_layout_id],\n    cx\n);\n```\n\n### Bounds<Pixels>\n\nRepresents rectangular region:\n\n```rust\npub struct Bounds<T> {\n    pub origin: Point<T>,\n    pub size: Size<T>,\n}\n\n// Create bounds\nlet bounds = Bounds::new(\n    point(px(10.), px(20.)),\n    size(px(100.), px(50.))\n);\n\n// Access properties\nbounds.left()    // origin.x\nbounds.top()     // origin.y\nbounds.right()   // origin.x + size.width\nbounds.bottom()  // origin.y + size.height\nbounds.center()  // center point\n```\n\n## Hitbox System\n\n### Creating Hitboxes\n\n```rust\n// Normal hitbox (blocks events)\nlet hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n// Transparent hitbox (passes events through)\nlet hitbox = window.insert_hitbox(bounds, HitboxBehavior::Transparent);\n```\n\n### Using Hitboxes\n\n```rust\n// Check if hovered\nif hitbox.is_hovered(window) {\n    // ...\n}\n\n// Set cursor style\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n\n// Use in event handlers\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    if hitbox.is_hovered(window) && phase.bubble() {\n        // Handle event\n    }\n});\n```\n\n## Event Handling\n\n### Mouse Events\n\n```rust\n// Mouse down\nwindow.on_mouse_event(move |event: &MouseDownEvent, phase, window, cx| {\n    if phase.bubble() && bounds.contains(&event.position) {\n        // Handle mouse down\n        cx.stop_propagation(); // Prevent bubbling\n    }\n});\n\n// Mouse up\nwindow.on_mouse_event(move |event: &MouseUpEvent, phase, window, cx| {\n    // Handle mouse up\n});\n\n// Mouse move\nwindow.on_mouse_event(move |event: &MouseMoveEvent, phase, window, cx| {\n    // Handle mouse move\n});\n\n// Scroll\nwindow.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {\n    // Handle scroll\n});\n```\n\n### Event Phase\n\nEvents go through two phases:\n- **Capture**: Top-down (parent → child)\n- **Bubble**: Bottom-up (child → parent)\n\n```rust\nmove |event, phase, window, cx| {\n    if phase.capture() {\n        // Handle in capture phase\n    } else if phase.bubble() {\n        // Handle in bubble phase\n    }\n\n    cx.stop_propagation(); // Stop event from continuing\n}\n```\n\n## Cursor Styles\n\nAvailable cursor styles:\n\n```rust\nCursorStyle::Arrow\nCursorStyle::IBeam           // Text selection\nCursorStyle::PointingHand    // Clickable\nCursorStyle::ResizeLeft\nCursorStyle::ResizeRight\nCursorStyle::ResizeUp\nCursorStyle::ResizeDown\nCursorStyle::ResizeLeftRight\nCursorStyle::ResizeUpDown\nCursorStyle::Crosshair\nCursorStyle::OperationNotAllowed\n```\n\nUsage:\n\n```rust\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n```\n","skills/gpui-kit/references/gpui/element-best-practices.md":"# Element Best Practices\n\n**Contents:** [State Management](#state-management) · [Performance Considerations](#performance-considerations) · [Interaction Handling](#interaction-handling) · [Layout Strategies](#layout-strategies) · [Error Handling](#error-handling) · [Testing Element Implementations](#testing-element-implementations) · [Common Pitfalls](#common-pitfalls) · [Performance Checklist](#performance-checklist)\n\n## State Management\n\n### Using Associated Types Effectively\n\n**Good:** Use associated types to pass meaningful data between phases\n\n```rust\n// Good: Structured state with type safety\ntype RequestLayoutState = (StyledText, Vec<ChildLayout>);\ntype PrepaintState = (Hitbox, Vec<ChildBounds>);\n```\n\n**Bad:** Using empty state when you need data\n\n```rust\n// Bad: No state when you need to pass data\ntype RequestLayoutState = ();\ntype PrepaintState = ();\n// Now you can't pass layout info to paint phase!\n```\n\n### Managing Complex State\n\nFor elements with complex state, create dedicated structs:\n\n```rust\n// Good: Dedicated struct for complex state\npub struct TextElementState {\n    pub styled_text: StyledText,\n    pub text_layout: TextLayout,\n    pub child_states: Vec<ChildState>,\n}\n\ntype RequestLayoutState = TextElementState;\n```\n\n**Benefits:**\n- Clear documentation of state structure\n- Easy to extend\n- Type-safe access\n\n### State Lifecycle\n\n**Golden Rule:** State flows in one direction through the phases\n\n```\nrequest_layout → RequestLayoutState →\nprepaint → PrepaintState →\npaint\n```\n\n**Don't:**\n- Store state in the element struct that should be in associated types\n- Try to mutate element state in paint phase (use `cx.notify()` to schedule re-render)\n- Pass mutable references across phase boundaries\n\n## Performance Considerations\n\n### Minimize Allocations in Paint Phase\n\n**Critical:** Paint phase is called every frame during animations. Minimize allocations.\n\n**Good:** Pre-allocate in `request_layout` or `prepaint`\n\n```rust\nimpl Element for MyElement {\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Vec<StyledText>)\n    {\n        // Allocate once during layout\n        let styled_texts = self.children\n            .iter()\n            .map(|child| StyledText::new(child.text.clone()))\n            .collect();\n\n        (layout_id, styled_texts)\n    }\n\n    fn paint(&mut self, .., styled_texts: &mut Vec<StyledText>, ..) {\n        // Just use pre-allocated styled_texts\n        for text in styled_texts {\n            text.paint(..);\n        }\n    }\n}\n```\n\n**Bad:** Allocate in `paint` phase\n\n```rust\nfn paint(&mut self, ..) {\n    // Bad: Allocation in paint phase!\n    let styled_texts: Vec<_> = self.children\n        .iter()\n        .map(|child| StyledText::new(child.text.clone()))\n        .collect();\n}\n```\n\n### Cache Expensive Computations\n\nUse memoization for expensive operations:\n\n```rust\npub struct CachedElement {\n    // Cache key\n    last_text: Option<SharedString>,\n    last_width: Option<Pixels>,\n\n    // Cached result\n    cached_layout: Option<TextLayout>,\n}\n\nimpl Element for CachedElement {\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, TextLayout)\n    {\n        let current_width = window.bounds().width();\n\n        // Check if cache is valid\n        if self.last_text.as_ref() != Some(&self.text)\n            || self.last_width != Some(current_width)\n            || self.cached_layout.is_none()\n        {\n            // Recompute expensive layout\n            self.cached_layout = Some(self.compute_text_layout(current_width));\n            self.last_text = Some(self.text.clone());\n            self.last_width = Some(current_width);\n        }\n\n        // Use cached layout\n        let layout = self.cached_layout.as_ref().unwrap();\n        (layout_id, layout.clone())\n    }\n}\n```\n\n### Lazy Child Rendering\n\nOnly render visible children in scrollable containers:\n\n```rust\nfn paint(&mut self, .., bounds: Bounds<Pixels>, paint_state: &mut Self::PrepaintState, ..) {\n    for (i, child) in self.children.iter_mut().enumerate() {\n        let child_bounds = paint_state.child_bounds[i];\n\n        // Only paint visible children\n        if self.is_visible(&child_bounds, &bounds) {\n            child.paint(..);\n        }\n    }\n}\n\nfn is_visible(&self, child_bounds: &Bounds<Pixels>, container_bounds: &Bounds<Pixels>) -> bool {\n    child_bounds.bottom() >= container_bounds.top() &&\n    child_bounds.top() <= container_bounds.bottom()\n}\n```\n\n## Interaction Handling\n\n### Proper Event Bubbling\n\nAlways check phase and bounds before handling events:\n\n```rust\nfn paint(&mut self, .., window: &mut Window, cx: &mut App) {\n    window.on_mouse_event({\n        let hitbox = self.hitbox.clone();\n        move |event: &MouseDownEvent, phase, window, cx| {\n            // Check phase first\n            if !phase.bubble() {\n                return;\n            }\n\n            // Check if event is within bounds\n            if !hitbox.is_hovered(window) {\n                return;\n            }\n\n            // Handle event\n            self.handle_click(event);\n\n            // Stop propagation if handled\n            cx.stop_propagation();\n        }\n    });\n}\n```\n\n**Don't forget:**\n- Check `phase.bubble()` or `phase.capture()` as appropriate\n- Check hitbox hover state or bounds\n- Call `cx.stop_propagation()` if you handle the event\n\n### Hitbox Management\n\nCreate hitboxes in `prepaint` phase, not `paint`:\n\n**Good:**\n\n```rust\nfn prepaint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) -> Hitbox {\n    // Create hitbox in prepaint\n    window.insert_hitbox(bounds, HitboxBehavior::Normal)\n}\n\nfn paint(&mut self, .., hitbox: &mut Hitbox, window: &mut Window, ..) {\n    // Use hitbox in paint\n    window.set_cursor_style(CursorStyle::PointingHand, hitbox);\n}\n```\n\n**Hitbox Behaviors:**\n\n```rust\n// Normal: Blocks events from passing through\nHitboxBehavior::Normal\n\n// Transparent: Allows events to pass through to elements below\nHitboxBehavior::Transparent\n```\n\n### Cursor Style Guidelines\n\nSet appropriate cursor styles for interactivity cues:\n\n```rust\n// Text selection\nwindow.set_cursor_style(CursorStyle::IBeam, &hitbox);\n\n// Clickable elements (desktop convention: use default, not pointing hand)\nwindow.set_cursor_style(CursorStyle::Arrow, &hitbox);\n\n// Links (web convention: use pointing hand)\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n\n// Resizable edges\nwindow.set_cursor_style(CursorStyle::ResizeLeftRight, &hitbox);\n```\n\n**Desktop vs Web Convention:**\n- Desktop apps: Use `Arrow` for buttons\n- Web apps: Use `PointingHand` for links only\n\n## Layout Strategies\n\n### Fixed Size Elements\n\nFor elements with known, unchanging size:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App) -> (LayoutId, ()) {\n    let layout_id = window.request_layout(\n        Style {\n            size: size(px(200.), px(100.)),\n            ..default()\n        },\n        vec![], // No children\n        cx\n    );\n    (layout_id, ())\n}\n```\n\n### Content-Based Sizing\n\nFor elements sized by their content:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Size<Pixels>)\n{\n    // Measure content\n    let text_bounds = self.measure_text(window);\n    let padding = px(16.);\n\n    let layout_id = window.request_layout(\n        Style {\n            size: size(\n                text_bounds.width() + padding * 2.,\n                text_bounds.height() + padding * 2.,\n            ),\n            ..default()\n        },\n        vec![],\n        cx\n    );\n\n    (layout_id, text_bounds)\n}\n```\n\n### Flexible Layouts\n\nFor elements that adapt to available space:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Vec<LayoutId>)\n{\n    let mut child_layout_ids = Vec::new();\n\n    for child in &mut self.children {\n        let (layout_id, _) = child.request_layout(window, cx);\n        child_layout_ids.push(layout_id);\n    }\n\n    let layout_id = window.request_layout(\n        Style {\n            flex_direction: FlexDirection::Row,\n            gap: px(8.),\n            size: Size {\n                width: relative(1.0),  // Fill parent width\n                height: auto(),        // Auto height\n            },\n            ..default()\n        },\n        child_layout_ids.clone(),\n        cx\n    );\n\n    (layout_id, child_layout_ids)\n}\n```\n\n## Error Handling\n\n### Graceful Degradation\n\nHandle errors gracefully, don't panic:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Option<TextLayout>)\n{\n    // Try to create styled text\n    match StyledText::new(self.text.clone()).request_layout(None, None, window, cx) {\n        Ok((layout_id, text_layout)) => {\n            (layout_id, Some(text_layout))\n        }\n        Err(e) => {\n            // Log error\n            eprintln!(\"Failed to layout text: {}\", e);\n\n            // Fallback to simple text\n            let fallback_text = StyledText::new(\"(Error loading text)\".into());\n            let (layout_id, _) = fallback_text.request_layout(None, None, window, cx);\n            (layout_id, None)\n        }\n    }\n}\n```\n\n### Defensive Bounds Checking\n\nAlways validate bounds and indices:\n\n```rust\nfn paint_selection(&self, selection: &Selection, text_layout: &TextLayout, ..) {\n    // Validate selection bounds\n    let start = selection.start.min(self.text.len());\n    let end = selection.end.min(self.text.len());\n\n    if start >= end {\n        return; // Invalid selection\n    }\n\n    let rects = text_layout.rects_for_range(start..end);\n    // Paint selection...\n}\n```\n\n## Testing Element Implementations\n\n### Layout Tests\n\nTest that layout calculations are correct:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use gpui_kit::TestAppContext;\n\n    #[gpui_kit::test]\n    fn test_element_layout(cx: &mut TestAppContext) {\n        cx.update(|cx| {\n            let mut window = cx.open_window(Default::default(), |_, _| ()).unwrap();\n\n            window.update(cx, |window, cx| {\n                let mut element = MyElement::new();\n                let (layout_id, layout_state) = element.request_layout(\n                    None,\n                    None,\n                    window,\n                    cx\n                );\n\n                // Assert layout properties\n                let bounds = window.layout_bounds(layout_id);\n                assert_eq!(bounds.size.width, px(200.));\n                assert_eq!(bounds.size.height, px(100.));\n            });\n        });\n    }\n}\n```\n\n### Interaction Tests\n\nTest that interactions work correctly:\n\n```rust\n#[gpui_kit::test]\nfn test_element_click(cx: &mut TestAppContext) {\n    cx.update(|cx| {\n        let mut window = cx.open_window(Default::default(), |_, cx| {\n            cx.new(|_| MyElement::new())\n        }).unwrap();\n\n        window.update(cx, |window, cx| {\n            let view = window.root_view().unwrap();\n\n            // Simulate click\n            let position = point(px(10.), px(10.));\n            window.dispatch_event(MouseDownEvent {\n                position,\n                button: MouseButton::Left,\n                modifiers: Modifiers::default(),\n            });\n\n            // Assert element responded\n            view.read(cx).assert_clicked();\n        });\n    });\n}\n```\n\n## Common Pitfalls\n\n### ❌ Storing Layout State in Element Struct\n\n**Bad:**\n\n```rust\npub struct MyElement {\n    id: ElementId,\n    // Bad: This should be in RequestLayoutState\n    cached_layout: Option<TextLayout>,\n}\n```\n\n**Good:**\n\n```rust\npub struct MyElement {\n    id: ElementId,\n    text: SharedString,\n}\n\ntype RequestLayoutState = TextLayout; // Good: State in associated type\n```\n\n### ❌ Mutating Element in Paint Phase\n\n**Bad:**\n\n```rust\nfn paint(&mut self, ..) {\n    self.counter += 1; // Bad: Mutating element in paint\n}\n```\n\n**Good:**\n\n```rust\nfn paint(&mut self, .., window: &mut Window, cx: &mut App) {\n    window.on_mouse_event(move |event, phase, window, cx| {\n        if phase.bubble() {\n            self.counter += 1;\n            cx.notify(); // Schedule re-render\n        }\n    });\n}\n```\n\n### ❌ Creating Hitboxes in Paint Phase\n\n**Bad:**\n\n```rust\nfn paint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) {\n    // Bad: Creating hitbox in paint\n    let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n}\n```\n\n**Good:**\n\n```rust\nfn prepaint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) -> Hitbox {\n    // Good: Creating hitbox in prepaint\n    window.insert_hitbox(bounds, HitboxBehavior::Normal)\n}\n```\n\n### ❌ Ignoring Event Phase\n\n**Bad:**\n\n```rust\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    // Bad: Not checking phase\n    self.handle_click(event);\n});\n```\n\n**Good:**\n\n```rust\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    // Good: Checking phase\n    if !phase.bubble() {\n        return;\n    }\n    self.handle_click(event);\n});\n```\n\n## Performance Checklist\n\nBefore shipping an element implementation, verify:\n\n- [ ] No allocations in `paint` phase (except event handlers)\n- [ ] Expensive computations are cached/memoized\n- [ ] Only visible children are rendered in scrollable containers\n- [ ] Hitboxes created in `prepaint`, not `paint`\n- [ ] Event handlers check phase and bounds\n- [ ] Layout state is passed through associated types, not stored in element\n- [ ] Element implements proper error handling with fallbacks\n- [ ] Tests cover layout calculations and interactions\n","skills/gpui-kit/references/gpui/element-examples.md":"# Element Implementation Examples\n\nComplete examples of implementing custom elements for various scenarios.\n\n## Table of Contents\n\n1. [Simple Text Element](#simple-text-element)\n2. [Interactive Element with Selection](#interactive-element-with-selection)\n3. [Complex Element with Child Management](#complex-element-with-child-management)\n\n## Simple Text Element\n\nA basic text element with syntax highlighting support.\n\n```rust\npub struct SimpleText {\n    id: ElementId,\n    text: SharedString,\n    highlights: Vec<(Range<usize>, HighlightStyle)>,\n}\n\nimpl IntoElement for SimpleText {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for SimpleText {\n    type RequestLayoutState = StyledText;\n    type PrepaintState = Hitbox;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        // Create styled text with highlights\n        let mut runs = Vec::new();\n        let mut ix = 0;\n\n        for (range, highlight) in &self.highlights {\n            // Add unstyled text before highlight\n            if ix < range.start {\n                runs.push(window.text_style().to_run(range.start - ix));\n            }\n\n            // Add highlighted text\n            runs.push(\n                window.text_style()\n                    .highlight(*highlight)\n                    .to_run(range.len())\n            );\n            ix = range.end;\n        }\n\n        // Add remaining unstyled text\n        if ix < self.text.len() {\n            runs.push(window.text_style().to_run(self.text.len() - ix));\n        }\n\n        let styled_text = StyledText::new(self.text.clone()).with_runs(runs);\n        let (layout_id, _) = styled_text.request_layout(\n            global_id,\n            inspector_id,\n            window,\n            cx\n        );\n\n        (layout_id, styled_text)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        styled_text: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Self::PrepaintState {\n        // Prepaint the styled text\n        styled_text.prepaint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            window,\n            cx\n        );\n\n        // Create hitbox for interaction\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        hitbox\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        styled_text: &mut Self::RequestLayoutState,\n        hitbox: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint the styled text\n        styled_text.paint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            &mut (),\n            window,\n            cx\n        );\n\n        // Set cursor style for text\n        window.set_cursor_style(CursorStyle::IBeam, hitbox);\n    }\n}\n```\n\n## Interactive Element with Selection\n\nA text element that supports text selection via mouse interaction.\n\n```rust\n#[derive(Clone)]\npub struct Selection {\n    pub start: usize,\n    pub end: usize,\n}\n\npub struct SelectableText {\n    id: ElementId,\n    text: SharedString,\n    selectable: bool,\n    selection: Option<Selection>,\n}\n\nimpl IntoElement for SelectableText {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for SelectableText {\n    type RequestLayoutState = TextLayout;\n    type PrepaintState = Option<Hitbox>;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        let styled_text = StyledText::new(self.text.clone());\n        let (layout_id, _) = styled_text.request_layout(\n            global_id,\n            inspector_id,\n            window,\n            cx\n        );\n\n        // Extract text layout for selection painting\n        let text_layout = styled_text.layout().clone();\n\n        (layout_id, text_layout)\n    }\n\n    fn prepaint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _text_layout: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        _cx: &mut App\n    ) -> Self::PrepaintState {\n        // Only create hitbox if selectable\n        if self.selectable {\n            Some(window.insert_hitbox(bounds, HitboxBehavior::Normal))\n        } else {\n            None\n        }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        text_layout: &mut Self::RequestLayoutState,\n        hitbox: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint text\n        let styled_text = StyledText::new(self.text.clone());\n        styled_text.paint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            &mut (),\n            window,\n            cx\n        );\n\n        // Paint selection if any\n        if let Some(selection) = &self.selection {\n            Self::paint_selection(selection, text_layout, &bounds, window, cx);\n        }\n\n        // Handle mouse events for selection\n        if let Some(hitbox) = hitbox {\n            window.set_cursor_style(CursorStyle::IBeam, hitbox);\n\n            // Mouse down to start selection\n            window.on_mouse_event({\n                let bounds = bounds.clone();\n                move |event: &MouseDownEvent, phase, window, cx| {\n                    if bounds.contains(&event.position) && phase.bubble() {\n                        // Start selection at mouse position\n                        let char_index = Self::position_to_index(\n                            event.position,\n                            &bounds,\n                            text_layout\n                        );\n                        self.selection = Some(Selection {\n                            start: char_index,\n                            end: char_index,\n                        });\n                        cx.notify();\n                        cx.stop_propagation();\n                    }\n                }\n            });\n\n            // Mouse drag to extend selection\n            window.on_mouse_event({\n                let bounds = bounds.clone();\n                move |event: &MouseMoveEvent, phase, window, cx| {\n                    if let Some(selection) = &mut self.selection {\n                        if phase.bubble() {\n                            let char_index = Self::position_to_index(\n                                event.position,\n                                &bounds,\n                                text_layout\n                            );\n                            selection.end = char_index;\n                            cx.notify();\n                        }\n                    }\n                }\n            });\n        }\n    }\n}\n\nimpl SelectableText {\n    fn paint_selection(\n        selection: &Selection,\n        text_layout: &TextLayout,\n        bounds: &Bounds<Pixels>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Calculate selection bounds from text layout\n        let selection_rects = text_layout.rects_for_range(\n            selection.start..selection.end\n        );\n\n        // Paint selection background\n        for rect in selection_rects {\n            window.paint_quad(paint_quad(\n                Bounds::new(\n                    point(bounds.left() + rect.origin.x, bounds.top() + rect.origin.y),\n                    rect.size\n                ),\n                Anchor::default(),\n                cx.theme().selection_background,\n            ));\n        }\n    }\n\n    fn position_to_index(\n        position: Point<Pixels>,\n        bounds: &Bounds<Pixels>,\n        text_layout: &TextLayout\n    ) -> usize {\n        // Convert screen position to character index\n        let relative_pos = point(\n            position.x - bounds.left(),\n            position.y - bounds.top()\n        );\n        text_layout.index_for_position(relative_pos)\n    }\n}\n```\n\n## Complex Element with Child Management\n\nA container element that manages multiple children with scrolling support.\n\n```rust\npub struct ComplexElement {\n    id: ElementId,\n    children: Vec<Box<dyn Element<RequestLayoutState = (), PrepaintState = ()>>>,\n    scrollable: bool,\n    scroll_offset: Point<Pixels>,\n}\n\nstruct ComplexLayoutState {\n    child_layouts: Vec<LayoutId>,\n    total_height: Pixels,\n}\n\nstruct ComplexPaintState {\n    child_bounds: Vec<Bounds<Pixels>>,\n    hitbox: Hitbox,\n}\n\nimpl IntoElement for ComplexElement {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for ComplexElement {\n    type RequestLayoutState = ComplexLayoutState;\n    type PrepaintState = ComplexPaintState;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        let mut child_layouts = Vec::new();\n        let mut total_height = px(0.);\n\n        // Request layout for all children\n        for child in &mut self.children {\n            let (child_layout_id, _) = child.request_layout(\n                global_id,\n                inspector_id,\n                window,\n                cx\n            );\n            child_layouts.push(child_layout_id);\n\n            // Get child size from layout\n            let child_size = window.layout_bounds(child_layout_id).size();\n            total_height += child_size.height;\n        }\n\n        // Create container layout\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: FlexDirection::Column,\n                gap: px(8.),\n                size: Size {\n                    width: relative(1.0),\n                    height: if self.scrollable {\n                        // Fixed height for scrollable\n                        px(400.)\n                    } else {\n                        // Auto height for non-scrollable\n                        total_height\n                    },\n                },\n                ..default()\n            },\n            child_layouts.clone(),\n            cx\n        );\n\n        (layout_id, ComplexLayoutState {\n            child_layouts,\n            total_height,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Self::PrepaintState {\n        let mut child_bounds = Vec::new();\n        let mut y_offset = self.scroll_offset.y;\n\n        // Calculate child bounds and prepaint children\n        for (child, layout_id) in self.children.iter_mut()\n            .zip(&layout_state.child_layouts)\n        {\n            let child_size = window.layout_bounds(*layout_id).size();\n            let child_bound = Bounds::new(\n                point(bounds.left(), bounds.top() + y_offset),\n                child_size\n            );\n\n            // Only prepaint visible children\n            if self.is_visible(&child_bound, &bounds) {\n                child.prepaint(\n                    global_id,\n                    inspector_id,\n                    child_bound,\n                    &mut (),\n                    window,\n                    cx\n                );\n            }\n\n            child_bounds.push(child_bound);\n            y_offset += child_size.height + px(8.); // gap\n        }\n\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n        ComplexPaintState {\n            child_bounds,\n            hitbox,\n        }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut Self::RequestLayoutState,\n        paint_state: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint background\n        window.paint_quad(paint_quad(\n            bounds,\n            Anchor::all(px(4.)),\n            cx.theme().background,\n        ));\n\n        // Paint visible children only\n        for (i, child) in self.children.iter_mut().enumerate() {\n            let child_bounds = paint_state.child_bounds[i];\n\n            if self.is_visible(&child_bounds, &bounds) {\n                child.paint(\n                    global_id,\n                    inspector_id,\n                    child_bounds,\n                    &mut (),\n                    &mut (),\n                    window,\n                    cx\n                );\n            }\n        }\n\n        // Paint scrollbar if scrollable\n        if self.scrollable {\n            self.paint_scrollbar(bounds, layout_state, window, cx);\n        }\n\n        // Handle scroll events\n        if self.scrollable {\n            window.on_mouse_event({\n                let hitbox = paint_state.hitbox.clone();\n                let total_height = layout_state.total_height;\n                let visible_height = bounds.size.height;\n\n                move |event: &ScrollWheelEvent, phase, window, cx| {\n                    if hitbox.is_hovered(window) && phase.bubble() {\n                        // Update scroll offset\n                        self.scroll_offset.y -= event.delta.y;\n\n                        // Clamp scroll offset\n                        let max_scroll = (total_height - visible_height).max(px(0.));\n                        self.scroll_offset.y = self.scroll_offset.y\n                            .max(px(0.))\n                            .min(max_scroll);\n\n                        cx.notify();\n                        cx.stop_propagation();\n                    }\n                }\n            });\n        }\n    }\n}\n\nimpl ComplexElement {\n    fn is_visible(&self, child_bounds: &Bounds<Pixels>, container_bounds: &Bounds<Pixels>) -> bool {\n        // Check if child is within visible area\n        child_bounds.bottom() >= container_bounds.top() &&\n        child_bounds.top() <= container_bounds.bottom()\n    }\n\n    fn paint_scrollbar(\n        &self,\n        bounds: Bounds<Pixels>,\n        layout_state: &ComplexLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let scrollbar_width = px(8.);\n        let visible_height = bounds.size.height;\n        let total_height = layout_state.total_height;\n\n        if total_height <= visible_height {\n            return; // No need for scrollbar\n        }\n\n        // Calculate scrollbar position and size\n        let scroll_ratio = self.scroll_offset.y / (total_height - visible_height);\n        let thumb_height = (visible_height / total_height) * visible_height;\n        let thumb_y = scroll_ratio * (visible_height - thumb_height);\n\n        // Paint scrollbar track\n        let track_bounds = Bounds::new(\n            point(bounds.right() - scrollbar_width, bounds.top()),\n            size(scrollbar_width, visible_height)\n        );\n        window.paint_quad(paint_quad(\n            track_bounds,\n            Anchor::default(),\n            cx.theme().scrollbar_track,\n        ));\n\n        // Paint scrollbar thumb\n        let thumb_bounds = Bounds::new(\n            point(bounds.right() - scrollbar_width, bounds.top() + thumb_y),\n            size(scrollbar_width, thumb_height)\n        );\n        window.paint_quad(paint_quad(\n            thumb_bounds,\n            Anchor::all(px(4.)),\n            cx.theme().scrollbar_thumb,\n        ));\n    }\n}\n```\n\n## Usage Examples\n\n### Using SimpleText\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    div()\n        .child(SimpleText {\n            id: ElementId::Name(\"code-text\".into()),\n            text: \"fn main() { println!(\\\"Hello\\\"); }\".into(),\n            highlights: vec![\n                (0..2, HighlightStyle::keyword()),\n                (3..7, HighlightStyle::function()),\n            ],\n        })\n}\n```\n\n### Using SelectableText\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    div()\n        .child(SelectableText {\n            id: ElementId::Name(\"selectable-text\".into()),\n            text: \"Select this text with your mouse\".into(),\n            selectable: true,\n            selection: self.current_selection.clone(),\n        })\n}\n```\n\n### Using ComplexElement\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    let children: Vec<Box<dyn Element<_, _>>> = self.items\n        .iter()\n        .map(|item| Box::new(div().child(item.name.clone())) as Box<_>)\n        .collect();\n\n    div()\n        .child(ComplexElement {\n            id: ElementId::Name(\"scrollable-list\".into()),\n            children,\n            scrollable: true,\n            scroll_offset: self.scroll_offset,\n        })\n}\n```\n","skills/gpui-kit/references/gpui/element-id.md":"# ElementId\n\n`ElementId` is a unique identifier for a GPUI element. It is required for elements that need:\n- Mouse event handling (`on_click`, `on_hover`, etc.)\n- State storage via `window.use_keyed_state`\n- Interaction tracking\n\n## Making an Element Stateful\n\nCall `.id()` on a `div()` to create a `Stateful<Div>`:\n\n```rust\ndiv().id(\"my-element\")          // ElementId from &str\ndiv().id(42usize)               // ElementId from usize\ndiv().id(ElementId::from(idx))  // Explicit\n```\n\nWithout `.id()`, a div cannot receive mouse events or store state.\n\n## Accepted Types\n\n```rust\nimpl Into<ElementId> for &str      // \"my-id\"\nimpl Into<ElementId> for String    // String::from(\"my-id\")\nimpl Into<ElementId> for usize     // 0, 1, 2, ...\nimpl Into<ElementId> for u64\nimpl Into<ElementId> for SharedString\n```\n\n## Uniqueness Rules\n\nIDs must be unique within the same **stateful parent's scope** — not globally. GPUI builds a `GlobalElementId` by chaining parent IDs:\n\n```rust\ndiv().id(\"app\").child(\n    div().id(\"list1\").children(vec![\n        div().id(1usize).child(\"Item 1\"),  // GlobalId: [\"app\", \"list1\", 1]\n        div().id(2usize).child(\"Item 2\"),  // GlobalId: [\"app\", \"list1\", 2]\n    ])\n).child(\n    div().id(\"list2\").children(vec![\n        div().id(1usize).child(\"Item 1\"),  // GlobalId: [\"app\", \"list2\", 1] — no conflict\n    ])\n)\n```\n\nItems in different parent scopes can reuse simple IDs (integers, short strings).\n\n## In Component Structs\n\nComponents always store `id: ElementId` and pass it in `new()`:\n\n```rust\n#[derive(IntoElement)]\npub struct Button {\n    id: ElementId,\n    base: Stateful<Div>,\n    // ...\n}\n\nimpl Button {\n    pub fn new(id: impl Into<ElementId>) -> Self {\n        let id = id.into();\n        Self {\n            id: id.clone(),\n            base: div().id(id),  // id applied to base\n            // ...\n        }\n    }\n}\n\nimpl RenderOnce for Button {\n    fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {\n        self.base  // already has .id() applied\n            .on_click(/* ... */)\n    }\n}\n```\n\n## Usage at Call Sites\n\n```rust\n// Use unique string IDs for named components\nButton::new(\"save-btn\").label(\"Save\")\nButton::new(\"cancel-btn\").label(\"Cancel\")\n\n// Use index-based IDs in lists\nfor (i, item) in items.iter().enumerate() {\n    div().id(i)  // unique within this parent\n}\n\n// Use descriptive IDs for debugging\nInput::new(\"search-input\")\nSelect::new(\"country-select\")\n```\n","skills/gpui-kit/references/gpui/element-patterns.md":"# Common Element Patterns\n\n**Contents:** [Text Rendering Elements](#text-rendering-elements) · [Container Elements](#container-elements) · [Interactive Elements](#interactive-elements) · [Composite Elements](#composite-elements) · [Scrollable Elements](#scrollable-elements) · [Pattern Selection Guide](#pattern-selection-guide)\n\n## Text Rendering Elements\n\nElements that display and manipulate text content.\n\n### Pattern Characteristics\n\n- Use `StyledText` for text layout and rendering\n- Handle text selection in `paint` phase with hitbox interaction\n- Create hitboxes for text interaction in `prepaint`\n- Support text highlighting and custom styling via runs\n\n### Implementation Template\n\n```rust\npub struct TextElement {\n    id: ElementId,\n    text: SharedString,\n    style: TextStyle,\n}\n\nimpl Element for TextElement {\n    type RequestLayoutState = StyledText;\n    type PrepaintState = Hitbox;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, StyledText)\n    {\n        let styled_text = StyledText::new(self.text.clone())\n            .with_style(self.style);\n        let (layout_id, _) = styled_text.request_layout(None, None, window, cx);\n        (layout_id, styled_text)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, styled_text: &mut StyledText,\n                window: &mut Window, cx: &mut App) -> Hitbox\n    {\n        styled_text.prepaint(None, None, bounds, &mut (), window, cx);\n        window.insert_hitbox(bounds, HitboxBehavior::Normal)\n    }\n\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, styled_text: &mut StyledText,\n             hitbox: &mut Hitbox, window: &mut Window, cx: &mut App)\n    {\n        styled_text.paint(None, None, bounds, &mut (), &mut (), window, cx);\n        window.set_cursor_style(CursorStyle::IBeam, hitbox);\n    }\n}\n```\n\n### Use Cases\n\n- Code editors with syntax highlighting\n- Rich text displays\n- Labels with custom formatting\n- Selectable text areas\n\n## Container Elements\n\nElements that manage and layout child elements.\n\n### Pattern Characteristics\n\n- Manage child element layouts and positions\n- Handle scrolling and clipping when needed\n- Implement flex/grid-like layouts\n- Coordinate child interactions and event delegation\n\n### Implementation Template\n\n```rust\npub struct ContainerElement {\n    id: ElementId,\n    children: Vec<AnyElement>,\n    direction: FlexDirection,\n    gap: Pixels,\n}\n\nimpl Element for ContainerElement {\n    type RequestLayoutState = Vec<LayoutId>;\n    type PrepaintState = Vec<Bounds<Pixels>>;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Vec<LayoutId>)\n    {\n        let child_layout_ids: Vec<_> = self.children\n            .iter_mut()\n            .map(|child| child.request_layout(window, cx).0)\n            .collect();\n\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: self.direction,\n                gap: self.gap,\n                ..default()\n            },\n            child_layout_ids.clone(),\n            cx\n        );\n\n        (layout_id, child_layout_ids)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout_ids: &mut Vec<LayoutId>,\n                window: &mut Window, cx: &mut App) -> Vec<Bounds<Pixels>>\n    {\n        let mut child_bounds = Vec::new();\n\n        for (child, layout_id) in self.children.iter_mut().zip(layout_ids.iter()) {\n            let child_bound = window.layout_bounds(*layout_id);\n            child.prepaint(child_bound, window, cx);\n            child_bounds.push(child_bound);\n        }\n\n        child_bounds\n    }\n\n    fn paint(&mut self, .., child_bounds: &mut Vec<Bounds<Pixels>>,\n             window: &mut Window, cx: &mut App)\n    {\n        for (child, bounds) in self.children.iter_mut().zip(child_bounds.iter()) {\n            child.paint(*bounds, window, cx);\n        }\n    }\n}\n```\n\n### Use Cases\n\n- Panels and split views\n- List containers\n- Grid layouts\n- Tab containers\n\n## Interactive Elements\n\nElements that respond to user input (mouse, keyboard, touch).\n\n### Pattern Characteristics\n\n- Create appropriate hitboxes for interaction areas\n- Handle mouse/keyboard/touch events properly\n- Manage focus and cursor styles\n- Support hover, active, and disabled states\n\n### Implementation Template\n\n```rust\npub struct InteractiveElement {\n    id: ElementId,\n    content: AnyElement,\n    on_click: Option<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    hover_style: Option<Style>,\n}\n\nimpl Element for InteractiveElement {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = (Hitbox, bool); // hitbox and is_hovered\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, LayoutId)\n    {\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        (content_layout, content_layout)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, content_layout: &mut LayoutId,\n                window: &mut Window, cx: &mut App) -> (Hitbox, bool)\n    {\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        let is_hovered = hitbox.is_hovered(window);\n\n        self.content.prepaint(bounds, window, cx);\n\n        (hitbox, is_hovered)\n    }\n\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, content_layout: &mut LayoutId,\n             prepaint: &mut (Hitbox, bool), window: &mut Window, cx: &mut App)\n    {\n        let (hitbox, is_hovered) = prepaint;\n\n        // Paint hover background if hovered\n        if *is_hovered {\n            if let Some(hover_style) = &self.hover_style {\n                window.paint_quad(paint_quad(\n                    bounds,\n                    Anchor::all(px(4.)),\n                    hover_style.background_color.unwrap_or(cx.theme().hover),\n                ));\n            }\n        }\n\n        // Paint content\n        self.content.paint(bounds, window, cx);\n\n        // Handle click\n        if let Some(on_click) = self.on_click.as_ref() {\n            window.on_mouse_event({\n                let on_click = on_click.clone();\n                let hitbox = hitbox.clone();\n                move |event: &MouseUpEvent, phase, window, cx| {\n                    if hitbox.is_hovered(window) && phase.bubble() {\n                        on_click(event, window, cx);\n                        cx.stop_propagation();\n                    }\n                }\n            });\n        }\n\n        // Set cursor style\n        window.set_cursor_style(CursorStyle::PointingHand, hitbox);\n    }\n}\n```\n\n### Use Cases\n\n- Buttons\n- Links\n- Clickable cards\n- Drag handles\n- Menu items\n\n## Composite Elements\n\nElements that combine multiple child elements with complex coordination.\n\n### Pattern Characteristics\n\n- Combine multiple child elements with different types\n- Manage complex state across children\n- Coordinate animations and transitions\n- Handle focus delegation between children\n\n### Implementation Template\n\n```rust\npub struct CompositeElement {\n    id: ElementId,\n    header: AnyElement,\n    content: AnyElement,\n    footer: Option<AnyElement>,\n}\n\nstruct CompositeLayoutState {\n    header_layout: LayoutId,\n    content_layout: LayoutId,\n    footer_layout: Option<LayoutId>,\n}\n\nstruct CompositePaintState {\n    header_bounds: Bounds<Pixels>,\n    content_bounds: Bounds<Pixels>,\n    footer_bounds: Option<Bounds<Pixels>>,\n}\n\nimpl Element for CompositeElement {\n    type RequestLayoutState = CompositeLayoutState;\n    type PrepaintState = CompositePaintState;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, CompositeLayoutState)\n    {\n        let (header_layout, _) = self.header.request_layout(window, cx);\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        let footer_layout = self.footer.as_mut()\n            .map(|f| f.request_layout(window, cx).0);\n\n        let mut children = vec![header_layout, content_layout];\n        if let Some(footer) = footer_layout {\n            children.push(footer);\n        }\n\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: FlexDirection::Column,\n                size: Size {\n                    width: relative(1.0),\n                    height: auto(),\n                },\n                ..default()\n            },\n            children,\n            cx\n        );\n\n        (layout_id, CompositeLayoutState {\n            header_layout,\n            content_layout,\n            footer_layout,\n        })\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut CompositeLayoutState,\n                window: &mut Window, cx: &mut App) -> CompositePaintState\n    {\n        let header_bounds = window.layout_bounds(layout.header_layout);\n        let content_bounds = window.layout_bounds(layout.content_layout);\n        let footer_bounds = layout.footer_layout\n            .map(|id| window.layout_bounds(id));\n\n        self.header.prepaint(header_bounds, window, cx);\n        self.content.prepaint(content_bounds, window, cx);\n        if let (Some(footer), Some(bounds)) = (&mut self.footer, footer_bounds) {\n            footer.prepaint(bounds, window, cx);\n        }\n\n        CompositePaintState {\n            header_bounds,\n            content_bounds,\n            footer_bounds,\n        }\n    }\n\n    fn paint(&mut self, .., paint_state: &mut CompositePaintState,\n             window: &mut Window, cx: &mut App)\n    {\n        self.header.paint(paint_state.header_bounds, window, cx);\n        self.content.paint(paint_state.content_bounds, window, cx);\n        if let (Some(footer), Some(bounds)) = (&mut self.footer, paint_state.footer_bounds) {\n            footer.paint(bounds, window, cx);\n        }\n    }\n}\n```\n\n### Use Cases\n\n- Dialog boxes (header + content + footer)\n- Cards with multiple sections\n- Form layouts\n- Panels with toolbars\n\n## Scrollable Elements\n\nElements with scrollable content areas.\n\n### Pattern Characteristics\n\n- Manage scroll state (offset, velocity)\n- Handle scroll events (wheel, drag, touch)\n- Paint scrollbars (track and thumb)\n- Clip content to visible area\n\n### Implementation Template\n\n```rust\npub struct ScrollableElement {\n    id: ElementId,\n    content: AnyElement,\n    scroll_offset: Point<Pixels>,\n    content_size: Size<Pixels>,\n}\n\nstruct ScrollPaintState {\n    hitbox: Hitbox,\n    visible_bounds: Bounds<Pixels>,\n}\n\nimpl Element for ScrollableElement {\n    type RequestLayoutState = (LayoutId, Size<Pixels>);\n    type PrepaintState = ScrollPaintState;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, (LayoutId, Size<Pixels>))\n    {\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        let content_size = window.layout_bounds(content_layout).size;\n\n        let layout_id = window.request_layout(\n            Style {\n                size: Size {\n                    width: relative(1.0),\n                    height: px(400.), // Fixed viewport height\n                },\n                overflow: Overflow::Hidden,\n                ..default()\n            },\n            vec![content_layout],\n            cx\n        );\n\n        (layout_id, (content_layout, content_size))\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut (LayoutId, Size<Pixels>),\n                window: &mut Window, cx: &mut App) -> ScrollPaintState\n    {\n        let (content_layout, content_size) = layout;\n\n        // Calculate content bounds with scroll offset\n        let content_bounds = Bounds::new(\n            point(bounds.left(), bounds.top() - self.scroll_offset.y),\n            *content_size\n        );\n\n        self.content.prepaint(content_bounds, window, cx);\n\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n        ScrollPaintState {\n            hitbox,\n            visible_bounds: bounds,\n        }\n    }\n\n    fn paint(&mut self, .., layout: &mut (LayoutId, Size<Pixels>),\n             paint_state: &mut ScrollPaintState, window: &mut Window, cx: &mut App)\n    {\n        let (_, content_size) = layout;\n\n        // Paint content\n        self.content.paint(paint_state.visible_bounds, window, cx);\n\n        // Paint scrollbar\n        self.paint_scrollbar(paint_state.visible_bounds, *content_size, window, cx);\n\n        // Handle scroll events\n        window.on_mouse_event({\n            let hitbox = paint_state.hitbox.clone();\n            let content_height = content_size.height;\n            let visible_height = paint_state.visible_bounds.size.height;\n\n            move |event: &ScrollWheelEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Update scroll offset\n                    self.scroll_offset.y -= event.delta.y;\n\n                    // Clamp to valid range\n                    let max_scroll = (content_height - visible_height).max(px(0.));\n                    self.scroll_offset.y = self.scroll_offset.y\n                        .max(px(0.))\n                        .min(max_scroll);\n\n                    cx.notify();\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\nimpl ScrollableElement {\n    fn paint_scrollbar(\n        &self,\n        bounds: Bounds<Pixels>,\n        content_size: Size<Pixels>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let visible_height = bounds.size.height;\n        let content_height = content_size.height;\n\n        if content_height <= visible_height {\n            return; // No scrollbar needed\n        }\n\n        let scrollbar_width = px(8.);\n\n        // Calculate thumb position and size\n        let scroll_ratio = self.scroll_offset.y / (content_height - visible_height);\n        let thumb_height = (visible_height / content_height) * visible_height;\n        let thumb_y = scroll_ratio * (visible_height - thumb_height);\n\n        // Paint track\n        window.paint_quad(paint_quad(\n            Bounds::new(\n                point(bounds.right() - scrollbar_width, bounds.top()),\n                size(scrollbar_width, visible_height)\n            ),\n            Anchor::default(),\n            cx.theme().scrollbar_track,\n        ));\n\n        // Paint thumb\n        window.paint_quad(paint_quad(\n            Bounds::new(\n                point(bounds.right() - scrollbar_width, bounds.top() + thumb_y),\n                size(scrollbar_width, thumb_height)\n            ),\n            Anchor::all(px(4.)),\n            cx.theme().scrollbar_thumb,\n        ));\n    }\n}\n```\n\n### Use Cases\n\n- Scrollable lists\n- Code editors with large files\n- Long-form text content\n- Image galleries\n\n## Pattern Selection Guide\n\n| Need | Pattern | Complexity |\n|------|---------|------------|\n| Display styled text | Text Rendering | Low |\n| Layout multiple children | Container | Low-Medium |\n| Handle clicks/hovers | Interactive | Medium |\n| Complex multi-part UI | Composite | Medium-High |\n| Large content with scrolling | Scrollable | High |\n\nChoose the simplest pattern that meets your requirements, then extend as needed.\n","skills/gpui-kit/references/gpui/element.md":"# Custom Elements\n\n**Contents:** [When to Use](#when-to-use) · [Quick Start](#quick-start) · [Core Concepts](#core-concepts) · [Reference Documentation](#reference-documentation)\n\n## When to Use\n\nUse the low-level `Element` trait when:\n- Need fine-grained control over layout calculation\n- Building complex, performance-critical components\n- Implementing custom layout algorithms (masonry, circular, etc.)\n- High-level `Render`/`RenderOnce` APIs are insufficient\n\n**Prefer `Render`/`RenderOnce` for:** Simple components, standard layouts, declarative UI\n\n## Quick Start\n\nThe `Element` trait provides direct control over three rendering phases:\n\n```rust\nimpl Element for MyElement {\n    type RequestLayoutState = MyLayoutState;  // Data passed to later phases\n    type PrepaintState = MyPaintState;        // Data for painting\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    // Phase 1: Calculate sizes and positions\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Self::RequestLayoutState)\n    {\n        let layout_id = window.request_layout(\n            Style { size: size(px(200.), px(100.)), ..default() },\n            vec![],\n            cx\n        );\n        (layout_id, MyLayoutState { /* ... */ })\n    }\n\n    // Phase 2: Create hitboxes, prepare for painting\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,\n                window: &mut Window, cx: &mut App) -> Self::PrepaintState\n    {\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        MyPaintState { hitbox }\n    }\n\n    // Phase 3: Render and handle interactions\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,\n             paint_state: &mut Self::PrepaintState, window: &mut Window, cx: &mut App)\n    {\n        window.paint_quad(paint_quad(bounds, Anchor::all(px(4.)), cx.theme().background));\n\n        window.on_mouse_event({\n            let hitbox = paint_state.hitbox.clone();\n            move |event: &MouseDownEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Handle interaction\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\n// Enable element to be used as child\nimpl IntoElement for MyElement {\n    type Element = Self;\n    fn into_element(self) -> Self::Element { self }\n}\n```\n\n## Core Concepts\n\n### Three-Phase Rendering\n\n1. **request_layout**: Calculate sizes and positions, return layout ID and state\n2. **prepaint**: Create hitboxes, compute final bounds, prepare for painting\n3. **paint**: Render element, set up interactions (mouse events, cursor styles)\n\n### State Flow\n\n```\nRequestLayoutState → PrepaintState → paint\n```\n\nState flows in one direction through associated types, passed as mutable references between phases.\n\n### Key Operations\n\n- **Layout**: `window.request_layout(style, children, cx)` - Create layout node\n- **Hitboxes**: `window.insert_hitbox(bounds, behavior)` - Create interaction area\n- **Painting**: `window.paint_quad(...)` - Render visual content\n- **Events**: `window.on_mouse_event(handler)` - Handle user input\n\n## Reference Documentation\n\n### Complete API Documentation\n- **API**: See [element-api.md](element-api.md) — associated types, hitbox system, event handling, cursor styles\n- **Examples**: See [element-examples.md](element-examples.md) — text, interactive, complex elements\n- **Patterns**: See [element-patterns.md](element-patterns.md) — text, container, interactive, composite, scrollable\n- **Best Practices**: See [element-best-practices.md](element-best-practices.md) — performance, state, common pitfalls\n- **Advanced**: See [element-advanced.md](element-advanced.md) — masonry/circular layouts, memoization, virtual lists\n","skills/gpui-kit/references/gpui/entity-advanced.md":"# Advanced Entity Patterns\n\n**Contents:** [Entity Collections Management](#entity-collections-management) · [Conditional Update Patterns](#conditional-update-patterns) · [Entity State Machine Pattern](#entity-state-machine-pattern) · [Entity Proxy Pattern](#entity-proxy-pattern) · [Cascading Updates Pattern](#cascading-updates-pattern) · [Entity Snapshot Pattern](#entity-snapshot-pattern) · [Entity Transaction Pattern](#entity-transaction-pattern) · [Entity Pool Pattern](#entity-pool-pattern)\n\n## Entity Collections Management\n\n### Dynamic Collection with Cleanup\n\n```rust\nstruct EntityCollection<T> {\n    strong_refs: Vec<Entity<T>>,\n    weak_refs: Vec<WeakEntity<T>>,\n}\n\nimpl<T> EntityCollection<T> {\n    fn new() -> Self {\n        Self {\n            strong_refs: Vec::new(),\n            weak_refs: Vec::new(),\n        }\n    }\n\n    fn add(&mut self, entity: Entity<T>, cx: &mut App) {\n        self.strong_refs.push(entity.clone());\n        self.weak_refs.push(entity.downgrade());\n    }\n\n    fn remove(&mut self, entity_id: EntityId, cx: &mut App) {\n        self.strong_refs.retain(|e| e.entity_id() != entity_id);\n        self.weak_refs.retain(|w| {\n            w.upgrade()\n                .map(|e| e.entity_id() != entity_id)\n                .unwrap_or(false)\n        });\n    }\n\n    fn cleanup_invalid(&mut self, cx: &mut App) {\n        self.weak_refs.retain(|weak| weak.upgrade().is_some());\n    }\n\n    fn for_each<F>(&self, cx: &mut App, mut f: F)\n    where\n        F: FnMut(&Entity<T>, &mut App),\n    {\n        for entity in &self.strong_refs {\n            f(entity, cx);\n        }\n    }\n\n    fn for_each_weak<F>(&mut self, cx: &mut App, mut f: F)\n    where\n        F: FnMut(Entity<T>, &mut App),\n    {\n        self.weak_refs.retain(|weak| {\n            if let Some(entity) = weak.upgrade() {\n                f(entity, cx);\n                true\n            } else {\n                false // Remove invalid weak references\n            }\n        });\n    }\n}\n```\n\n### Entity Registry Pattern\n\n```rust\nuse std::collections::HashMap;\n\nstruct EntityRegistry<T> {\n    entities: HashMap<EntityId, WeakEntity<T>>,\n}\n\nimpl<T> EntityRegistry<T> {\n    fn new() -> Self {\n        Self {\n            entities: HashMap::new(),\n        }\n    }\n\n    fn register(&mut self, entity: &Entity<T>) {\n        self.entities.insert(entity.entity_id(), entity.downgrade());\n    }\n\n    fn unregister(&mut self, entity_id: EntityId) {\n        self.entities.remove(&entity_id);\n    }\n\n    fn get(&self, entity_id: EntityId) -> Option<Entity<T>> {\n        self.entities.get(&entity_id)?.upgrade()\n    }\n\n    fn cleanup(&mut self) {\n        self.entities.retain(|_, weak| weak.upgrade().is_some());\n    }\n\n    fn count(&self) -> usize {\n        self.entities.len()\n    }\n\n    fn all_entities(&self) -> Vec<Entity<T>> {\n        self.entities\n            .values()\n            .filter_map(|weak| weak.upgrade())\n            .collect()\n    }\n}\n```\n\n## Conditional Update Patterns\n\n### Debounced Updates\n\n```rust\nuse std::time::{Duration, Instant};\n\nstruct DebouncedEntity<T> {\n    entity: Entity<T>,\n    last_update: Instant,\n    debounce_duration: Duration,\n    pending_update: Option<Box<dyn FnOnce(&mut T, &mut Context<T>)>>,\n}\n\nimpl<T: 'static> DebouncedEntity<T> {\n    fn new(entity: Entity<T>, debounce_ms: u64) -> Self {\n        Self {\n            entity,\n            last_update: Instant::now(),\n            debounce_duration: Duration::from_millis(debounce_ms),\n            pending_update: None,\n        }\n    }\n\n    fn update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: FnOnce(&mut T, &mut Context<T>) + 'static,\n    {\n        let now = Instant::now();\n        let elapsed = now.duration_since(self.last_update);\n\n        if elapsed >= self.debounce_duration {\n            // Execute immediately\n            self.entity.update(cx, update_fn);\n            self.last_update = now;\n            self.pending_update = None;\n        } else {\n            // Store for later\n            self.pending_update = Some(Box::new(update_fn));\n\n            // Schedule execution\n            let entity = self.entity.clone();\n            let delay = self.debounce_duration - elapsed;\n\n            cx.spawn(async move |cx| {\n                tokio::time::sleep(delay).await;\n\n                if let Some(update) = self.pending_update.take() {\n                    entity.update(cx, |state, inner_cx| {\n                        update(state, inner_cx);\n                    });\n                }\n            }).detach();\n        }\n    }\n}\n```\n\n### Throttled Updates\n\n```rust\nstruct ThrottledEntity<T> {\n    entity: Entity<T>,\n    last_update: Instant,\n    throttle_duration: Duration,\n}\n\nimpl<T: 'static> ThrottledEntity<T> {\n    fn new(entity: Entity<T>, throttle_ms: u64) -> Self {\n        Self {\n            entity,\n            last_update: Instant::now(),\n            throttle_duration: Duration::from_millis(throttle_ms),\n        }\n    }\n\n    fn try_update<F>(&mut self, cx: &mut App, update_fn: F) -> bool\n    where\n        F: FnOnce(&mut T, &mut Context<T>),\n    {\n        let now = Instant::now();\n        let elapsed = now.duration_since(self.last_update);\n\n        if elapsed >= self.throttle_duration {\n            self.entity.update(cx, update_fn);\n            self.last_update = now;\n            true\n        } else {\n            false // Update throttled\n        }\n    }\n}\n```\n\n## Entity State Machine Pattern\n\n```rust\nenum AppState {\n    Idle,\n    Loading,\n    Loaded(String),\n    Error(String),\n}\n\nstruct StateMachine {\n    state: AppState,\n}\n\nimpl StateMachine {\n    fn new() -> Self {\n        Self {\n            state: AppState::Idle,\n        }\n    }\n\n    fn start_loading(&mut self, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Idle | AppState::Error(_)) {\n            self.state = AppState::Loading;\n            cx.notify();\n\n            let weak_entity = cx.entity().downgrade();\n\n            cx.spawn(async move |cx| {\n                let result = perform_load().await;\n\n                let _ = weak_entity.update(cx, |state, cx| {\n                    match result {\n                        Ok(data) => state.on_load_success(data, cx),\n                        Err(e) => state.on_load_error(e.to_string(), cx),\n                    }\n                });\n            }).detach();\n        }\n    }\n\n    fn on_load_success(&mut self, data: String, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Loading) {\n            self.state = AppState::Loaded(data);\n            cx.notify();\n        }\n    }\n\n    fn on_load_error(&mut self, error: String, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Loading) {\n            self.state = AppState::Error(error);\n            cx.notify();\n        }\n    }\n\n    fn reset(&mut self, cx: &mut Context<Self>) {\n        self.state = AppState::Idle;\n        cx.notify();\n    }\n}\n\nasync fn perform_load() -> Result<String, anyhow::Error> {\n    // Actual load implementation\n    Ok(\"Data\".to_string())\n}\n```\n\n## Entity Proxy Pattern\n\n```rust\nstruct EntityProxy<T> {\n    entity: WeakEntity<T>,\n}\n\nimpl<T> EntityProxy<T> {\n    fn new(entity: &Entity<T>) -> Self {\n        Self {\n            entity: entity.downgrade(),\n        }\n    }\n\n    fn with<F, R>(&self, cx: &mut App, f: F) -> Result<R, anyhow::Error>\n    where\n        F: FnOnce(&T, &App) -> R,\n    {\n        self.entity.read_with(cx, f)\n    }\n\n    fn update<F, R>(&self, cx: &mut App, f: F) -> Result<R, anyhow::Error>\n    where\n        F: FnOnce(&mut T, &mut Context<T>) -> R,\n    {\n        self.entity.update(cx, f)\n    }\n\n    fn is_valid(&self, cx: &App) -> bool {\n        self.entity.upgrade().is_some()\n    }\n}\n```\n\n## Cascading Updates Pattern\n\n```rust\nstruct CascadingUpdater {\n    entities: Vec<WeakEntity<UpdateTarget>>,\n}\n\nimpl CascadingUpdater {\n    fn new() -> Self {\n        Self {\n            entities: Vec::new(),\n        }\n    }\n\n    fn add_target(&mut self, entity: &Entity<UpdateTarget>) {\n        self.entities.push(entity.downgrade());\n    }\n\n    fn cascade_update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: Fn(&mut UpdateTarget, &mut Context<UpdateTarget>) + Clone,\n    {\n        // Update all entities in sequence\n        self.entities.retain(|weak| {\n            if let Ok(_) = weak.update(cx, |state, inner_cx| {\n                update_fn.clone()(state, inner_cx);\n            }) {\n                true // Keep valid entity\n            } else {\n                false // Remove invalid entity\n            }\n        });\n    }\n}\n\nstruct UpdateTarget {\n    value: i32,\n}\n```\n\n## Entity Snapshot Pattern\n\n```rust\nuse serde::{Serialize, Deserialize};\n\n#[derive(Clone, Serialize, Deserialize)]\nstruct EntitySnapshot {\n    data: String,\n    timestamp: u64,\n}\n\nstruct SnapshotableEntity {\n    data: String,\n    snapshots: Vec<EntitySnapshot>,\n}\n\nimpl SnapshotableEntity {\n    fn new(data: String) -> Self {\n        Self {\n            data,\n            snapshots: Vec::new(),\n        }\n    }\n\n    fn take_snapshot(&mut self, cx: &mut Context<Self>) {\n        let snapshot = EntitySnapshot {\n            data: self.data.clone(),\n            timestamp: current_timestamp(),\n        };\n        self.snapshots.push(snapshot);\n        cx.notify();\n    }\n\n    fn restore_snapshot(&mut self, index: usize, cx: &mut Context<Self>) -> Result<(), String> {\n        if let Some(snapshot) = self.snapshots.get(index) {\n            self.data = snapshot.data.clone();\n            cx.notify();\n            Ok(())\n        } else {\n            Err(\"Invalid snapshot index\".to_string())\n        }\n    }\n\n    fn clear_old_snapshots(&mut self, keep_last: usize, cx: &mut Context<Self>) {\n        if self.snapshots.len() > keep_last {\n            self.snapshots.drain(0..self.snapshots.len() - keep_last);\n            cx.notify();\n        }\n    }\n}\n\nfn current_timestamp() -> u64 {\n    use std::time::{SystemTime, UNIX_EPOCH};\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .unwrap()\n        .as_secs()\n}\n```\n\n## Entity Transaction Pattern\n\n```rust\nstruct Transaction<T> {\n    entity: Entity<T>,\n    original_state: Option<T>,\n}\n\nimpl<T: Clone> Transaction<T> {\n    fn begin(entity: Entity<T>, cx: &mut App) -> Self {\n        let original_state = entity.read(cx).clone();\n\n        Self {\n            entity,\n            original_state: Some(original_state),\n        }\n    }\n\n    fn update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: FnOnce(&mut T, &mut Context<T>),\n    {\n        self.entity.update(cx, update_fn);\n    }\n\n    fn commit(mut self, cx: &mut App) {\n        self.original_state = None; // Don't rollback\n        self.entity.update(cx, |_, cx| {\n            cx.notify();\n        });\n    }\n\n    fn rollback(mut self, cx: &mut App) {\n        if let Some(original) = self.original_state.take() {\n            self.entity.update(cx, |state, cx| {\n                *state = original;\n                cx.notify();\n            });\n        }\n    }\n}\n\nimpl<T> Drop for Transaction<T> {\n    fn drop(&mut self) {\n        // Auto-rollback if not committed\n        if self.original_state.is_some() {\n            eprintln!(\"Warning: Transaction dropped without commit\");\n        }\n    }\n}\n\n// Usage\nfn perform_transaction(entity: Entity<MyState>, cx: &mut App) -> Result<(), String> {\n    let mut tx = Transaction::begin(entity, cx);\n\n    tx.update(cx, |state, cx| {\n        state.value = 42;\n    });\n\n    if validate_state(&tx.entity, cx)? {\n        tx.commit(cx);\n        Ok(())\n    } else {\n        tx.rollback(cx);\n        Err(\"Validation failed\".to_string())\n    }\n}\n```\n\n## Entity Pool Pattern\n\n```rust\nstruct EntityPool<T> {\n    available: Vec<Entity<T>>,\n    in_use: Vec<WeakEntity<T>>,\n    factory: Box<dyn Fn(&mut App) -> Entity<T>>,\n}\n\nimpl<T: 'static> EntityPool<T> {\n    fn new<F>(factory: F) -> Self\n    where\n        F: Fn(&mut App) -> Entity<T> + 'static,\n    {\n        Self {\n            available: Vec::new(),\n            in_use: Vec::new(),\n            factory: Box::new(factory),\n        }\n    }\n\n    fn acquire(&mut self, cx: &mut App) -> Entity<T> {\n        let entity = if let Some(entity) = self.available.pop() {\n            entity\n        } else {\n            (self.factory)(cx)\n        };\n\n        self.in_use.push(entity.downgrade());\n        entity\n    }\n\n    fn release(&mut self, entity: Entity<T>, cx: &mut App) {\n        // Reset entity state if needed\n        entity.update(cx, |state, cx| {\n            // Reset logic here\n            cx.notify();\n        });\n\n        self.available.push(entity);\n        self.cleanup_in_use();\n    }\n\n    fn cleanup_in_use(&mut self) {\n        self.in_use.retain(|weak| weak.upgrade().is_some());\n    }\n\n    fn pool_size(&self) -> (usize, usize) {\n        (self.available.len(), self.in_use.len())\n    }\n}\n```\n\nThese advanced patterns provide powerful abstractions for managing complex entity scenarios while maintaining code quality and performance.\n","skills/gpui-kit/references/gpui/entity-api.md":"# Entity API Reference\n\n**Contents:** [Entity Types](#entity-types) · [Entity Creation](#entity-creation) · [Entity Operations](#entity-operations) · [Context Methods](#context-methods-for-entities) · [Async Operations](#async-operations) · [Entity Lifecycle](#entity-lifecycle) · [EntityId](#entityid) · [Error Handling](#error-handling) · [Type Conversions](#type-conversions)\n\n## Entity Types\n\n### Entity<T>\n\nA strong reference to state of type `T`.\n\n**Methods:**\n- `entity_id()` → `EntityId` - Returns unique identifier\n- `downgrade()` → `WeakEntity<T>` - Creates weak reference\n- `read(cx)` → `&T` - Immutable access to state\n- `read_with(cx, |state, cx| ...)` → `R` - Read with closure, returns closure result\n- `update(cx, |state, cx| ...)` → `R` - Mutable update with `Context<T>`, returns closure result\n- `update_in(cx, |state, window, cx| ...)` → `R` - Update with `Window` access (requires `AsyncWindowContext` or `VisualTestContext`)\n\n**Important Notes:**\n- Trying to update an entity while it's already being updated will panic\n- Within closures, use the inner `cx` provided to avoid multiple borrow issues\n- With async contexts, return values are wrapped in `anyhow::Result`\n\n### WeakEntity<T>\n\nA weak reference to state of type `T`.\n\n**Methods:**\n- `upgrade()` → `Option<Entity<T>>` - Convert to strong reference if still alive\n- `read_with(cx, |state, cx| ...)` → `Result<R>` - Read if entity exists\n- `update(cx, |state, cx| ...)` → `Result<R>` - Update if entity exists\n- `update_in(cx, |state, window, cx| ...)` → `Result<R>` - Update with window if entity exists\n\n**Use Cases:**\n- Avoid circular dependencies between entities\n- Store references in closures/callbacks without preventing cleanup\n- Optional relationships between components\n\n**Important:** All operations return `Result` since the entity may no longer exist.\n\n### AnyEntity\n\nDynamically-typed entity handle for storing entities of different types.\n\n### AnyWeakEntity\n\nDynamically-typed weak entity handle.\n\n## Entity Creation\n\n### cx.new()\n\nCreate new entity with initial state.\n\n```rust\nlet entity = cx.new(|cx| MyState {\n    count: 0,\n    name: \"Default\".to_string(),\n});\n```\n\n**Parameters:**\n- `cx: &mut App` or other context type\n- Closure receiving `&mut Context<T>` returning initial state `T`\n\n**Returns:** `Entity<T>`\n\n## Entity Operations\n\n### Reading State\n\n#### read()\n\nDirect read-only access to state.\n\n```rust\nlet count = my_entity.read(cx).count;\n```\n\n**Use when:** Simple field access, no context operations needed.\n\n#### read_with()\n\nRead with context access in closure.\n\n```rust\nlet count = my_entity.read_with(cx, |state, cx| {\n    // Can access both state and context\n    state.count\n});\n\n// Return multiple values\nlet (count, theme) = my_entity.read_with(cx, |state, cx| {\n    (state.count, cx.theme().clone())\n});\n```\n\n**Use when:** Need context operations, multiple return values, complex logic.\n\n### Updating State\n\n#### update()\n\nMutable update with `Context<T>`.\n\n```rust\nmy_entity.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify(); // Trigger re-render\n});\n```\n\n**Available Operations:**\n- `cx.notify()` - Trigger re-render\n- `cx.entity()` - Get current entity\n- `cx.emit(event)` - Emit event\n- `cx.spawn(task)` - Spawn async task\n- Other `Context<T>` methods\n\n#### update_in()\n\nUpdate with both `Window` and `Context<T>` access.\n\n```rust\nmy_entity.update_in(cx, |state, window, cx| {\n    state.focused = window.is_window_focused();\n    cx.notify();\n});\n```\n\n**Requires:** `AsyncWindowContext` or `VisualTestContext`\n\n**Use when:** Need window-specific operations like focus state, window bounds, etc.\n\n## Context Methods for Entities\n\n### cx.entity()\n\nGet current entity being updated.\n\n```rust\nimpl MyComponent {\n    fn some_method(&mut self, cx: &mut Context<Self>) {\n        let current_entity = cx.entity();  // Entity<MyComponent>\n        let weak = current_entity.downgrade();\n    }\n}\n```\n\n### cx.observe()\n\nObserve entity for changes.\n\n```rust\ncx.observe(&entity, |this, observed_entity, cx| {\n    // Called when observed_entity.update() calls cx.notify()\n    println!(\"Entity changed\");\n}).detach();\n```\n\n**Returns:** `Subscription` - Call `.detach()` to make permanent\n\n### cx.subscribe()\n\nSubscribe to events from entity.\n\n```rust\ncx.subscribe(&entity, |this, emitter, event: &SomeEvent, cx| {\n    // Called when emitter emits SomeEvent\n    match event {\n        SomeEvent::DataChanged => {\n            cx.notify();\n        }\n    }\n}).detach();\n```\n\n**Returns:** `Subscription` - Call `.detach()` to make permanent\n\n### cx.observe_new_entities()\n\nRegister callback for new entities of a type.\n\n```rust\ncx.observe_new_entities::<MyState>(|entity, cx| {\n    println!(\"New entity created: {:?}\", entity.entity_id());\n}).detach();\n```\n\n## Async Operations\n\n### cx.spawn()\n\nSpawn foreground task (UI thread).\n\n```rust\ncx.spawn(async move |this, cx| {\n    // `this`: WeakEntity<T>\n    // `cx`: &mut AsyncApp\n\n    let result = some_async_work().await;\n\n    // Update entity safely\n    let _ = this.update(cx, |state, cx| {\n        state.data = result;\n        cx.notify();\n    });\n}).detach();\n```\n\n**Note:** Always use weak entity reference in spawned tasks to prevent retain cycles.\n\n### cx.background_spawn()\n\nSpawn background task (background thread).\n\n```rust\ncx.background_spawn(async move {\n    // Long-running computation\n    let result = heavy_computation().await;\n    // Cannot directly update entities here\n    // Use channels or spawn foreground task to update\n}).detach();\n```\n\n## Entity Lifecycle\n\n### Creation\n\nEntities are created via `cx.new()` and immediately registered in the app.\n\n### Reference Counting\n\n- `Entity<T>` is a strong reference (increases reference count)\n- `WeakEntity<T>` is a weak reference (does not increase reference count)\n- Cloning `Entity<T>` increases reference count\n\n### Disposal\n\nEntities are automatically disposed when all strong references are dropped.\n\n```rust\n{\n    let entity = cx.new(|cx| MyState::default());\n    // entity exists\n} // entity dropped here if no other strong references exist\n```\n\n**Memory Leak Prevention:**\n- Use `WeakEntity` in closures/callbacks\n- Use `WeakEntity` for parent-child relationships\n- Avoid circular strong references\n\n## EntityId\n\nEvery entity has a unique identifier.\n\n```rust\nlet id: EntityId = entity.entity_id();\n\n// EntityIds can be compared\nif entity1.entity_id() == entity2.entity_id() {\n    // Same entity\n}\n```\n\n**Use Cases:**\n- Debugging and logging\n- Entity comparison without borrowing\n- Hash maps keyed by entity\n\n## Error Handling\n\n### WeakEntity Operations\n\nAll `WeakEntity` operations return `Result`:\n\n```rust\nlet weak = entity.downgrade();\n\n// Handle potential failure\nmatch weak.read_with(cx, |state, cx| state.count) {\n    Ok(count) => println!(\"Count: {}\", count),\n    Err(e) => eprintln!(\"Entity no longer exists: {}\", e),\n}\n\n// Or use Result combinators\nlet _ = weak.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify();\n}).ok(); // Ignore errors\n```\n\n### Update Panics\n\nNested updates on the same entity will panic:\n\n```rust\n// ❌ Will panic\nentity.update(cx, |state1, cx| {\n    entity.update(cx, |state2, cx| {\n        // Panic: entity already borrowed\n    });\n});\n```\n\n**Solution:** Perform updates sequentially or use different entities.\n\n## Type Conversions\n\n### Entity → WeakEntity\n\n```rust\nlet entity: Entity<T> = cx.new(|cx| T::default());\nlet weak: WeakEntity<T> = entity.downgrade();\n```\n\n### WeakEntity → Entity\n\n```rust\nlet weak: WeakEntity<T> = entity.downgrade();\nlet strong: Option<Entity<T>> = weak.upgrade();\n```\n\n### AnyEntity\n\n```rust\nlet any: AnyEntity = entity.into();\nlet typed: Option<Entity<T>> = any.downcast::<T>();\n```\n\n## Best Practice Guidelines\n\n### Always Use Inner cx\n\n```rust\n// ✅ Good: Use inner cx\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Use inner_cx, not outer cx\n});\n\n// ❌ Bad: Use outer cx\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong! Multiple borrow error\n});\n```\n\n### Weak References in Closures\n\n```rust\n// ✅ Good: Weak reference\nlet weak = cx.entity().downgrade();\ncallback(move || {\n    let _ = weak.update(cx, |state, cx| {\n        cx.notify();\n    });\n});\n\n// ❌ Bad: Strong reference (retain cycle)\nlet strong = cx.entity();\ncallback(move || {\n    strong.update(cx, |state, cx| {\n        // May never be dropped\n        cx.notify();\n    });\n});\n```\n\n### Sequential Updates\n\n```rust\n// ✅ Good: Sequential updates\nentity1.update(cx, |state, cx| { /* ... */ });\nentity2.update(cx, |state, cx| { /* ... */ });\n\n// ❌ Bad: Nested updates\nentity1.update(cx, |_, cx| {\n    entity2.update(cx, |_, cx| {\n        // May panic if entities are related\n    });\n});\n```\n","skills/gpui-kit/references/gpui/entity-best-practices.md":"# Entity Best Practices\n\n**Contents:** [Avoiding Common Pitfalls](#avoiding-common-pitfalls) · [Performance Optimization](#performance-optimization) · [Entity Lifecycle Management](#entity-lifecycle-management) · [Entity Observation Best Practices](#entity-observation-best-practices) · [Async Best Practices](#async-best-practices) · [Testing Best Practices](#testing-best-practices) · [Performance Checklist](#performance-checklist)\n\n## Avoiding Common Pitfalls\n\n### Avoid Re-entrant Entity Access (Same Entity)\n\n**Problem:** GPUI locks an entity for the entire duration of its render or update pass. Any attempt to `read` or `update` that *same* entity while the lock is held panics:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: entity_a updated from within entity_a's own update\nentity_a.update(cx, |_, cx| {\n    entity_a.update(cx, |_, _| {}); // PANIC\n});\n\n// ✅ Fine: updating a *different* entity from within an update\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, _| {}); // OK — different lock\n});\n```\n\n**Note:** Updating two *different* entities in a nested fashion is safe. The restriction is strictly about re-entering the *same* entity's lock.\n\n### `defer_in` Re-locks the Entity — Same Rules Apply\n\n`cx.defer_in(window, callback)` schedules `callback` to run *on the entity the context refers to*. GPUI re-acquires that entity's lock to execute the deferred callback, so the re-entrancy rules apply equally inside it:\n\n```rust\n// ❌ Panic: defer_in runs with ListState locked; calling list.update re-enters\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // list_state IS locked for this entire callback!\n        parent.update(cx, |this, cx| {\n            this.list.update(cx, |_, _| {}); // PANIC — re-enters ListState lock\n        });\n    });\n}\n```\n\n**Fix:** Use the direct `&mut` reference the callback provides instead of going through the entity handle:\n\n```rust\n// ✅ Correct: direct mutable access — no lock needed\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // Step 1: call hooks directly through list_state (no entity lock)\n        list_state.delegate_mut().on_will_change(&mut op, &snapshot);\n\n        // Step 2: update the parent entity — different lock, safe\n        let new_sel = parent.update(cx, |this, cx| {\n            this.state.apply_change(op);\n            cx.notify();\n            this.state.selection.clone() // return data needed for step 3\n        });\n\n        // Step 3: sync list state directly — no entity lock\n        if let Ok(sel) = new_sel {\n            list_state.delegate_mut().update_snapshot(sel.clone());\n            list_state.delegate_mut().on_confirm(&sel);\n        }\n    });\n}\n```\n\n### Render Callbacks Must Not Access External Entities\n\n`render_item` and any other rendering hook runs inside the entity's render pass. Calling `entity.read(cx)` or `entity.update(cx, …)` on an external entity (which may itself be in a render/update pass) panics with the same re-entrancy error.\n\n**Fix:** Keep a plain `snapshot` field updated eagerly from outside render after every mutation:\n\n```rust\n// ❌ Panic — called during ListState render; external entity access re-enters\nfn render_item(&mut self, ix: IndexPath, …) -> … {\n    let checked = parent.read(cx).selection.contains(&ix); // PANIC\n}\n\n// ✅ Read from snapshot field — no entity access at all\nfn render_item(&mut self, ix: IndexPath, …) -> … {\n    let checked = self.selection_snapshot.iter().any(|(sel_ix, _)| sel_ix == &ix);\n}\n// After every mutation from outside render:\nlist.update(cx, |l, _| l.delegate_mut().update_snapshot(new_snapshot));\n```\n\n### Use Weak References in Closures\n\n**Problem:** Strong references in closures can create retain cycles and memory leaks.\n\n```rust\n// ❌ Bad: Strong reference creates retain cycle\nimpl MyComponent {\n    fn setup_callback(&mut self, cx: &mut Context<Self>) {\n        let entity = cx.entity(); // Strong reference\n\n        some_callback(move || {\n            entity.update(cx, |state, cx| {\n                // This closure holds a strong reference\n                // If the closure itself is retained by the entity, memory leak!\n                cx.notify();\n            });\n        });\n    }\n}\n```\n\n**Solution:** Use weak references in closures.\n\n```rust\n// ✅ Good: Weak reference prevents retain cycle\nimpl MyComponent {\n    fn setup_callback(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade(); // Weak reference\n\n        some_callback(move || {\n            // Safe: weak reference doesn't prevent cleanup\n            let _ = weak_entity.update(cx, |state, cx| {\n                cx.notify();\n            });\n        });\n    }\n}\n```\n\n### Use Inner Context in Closures\n\n**Problem:** Using outer context causes multiple borrow errors.\n\n```rust\n// ❌ Bad: Using outer cx causes borrow issues\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong! Using outer cx\n    cx.spawn(...); // Multiple borrow error\n});\n```\n\n**Solution:** Always use the inner context provided to the closure.\n\n```rust\n// ✅ Good: Use inner cx\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Correct\n    inner_cx.spawn(...); // Works fine\n});\n```\n\n### Entity as Props - Use Weak References\n\n**Problem:** Strong entity references in props can create ownership issues.\n\n```rust\n// ❌ Questionable: Strong reference in child\nstruct ChildComponent {\n    parent: Entity<ParentComponent>, // Strong reference\n}\n```\n\n**Better:** Use weak references for parent relationships.\n\n```rust\n// ✅ Good: Weak reference prevents issues\nstruct ChildComponent {\n    parent: WeakEntity<ParentComponent>, // Weak reference\n}\n\nimpl ChildComponent {\n    fn notify_parent(&mut self, cx: &mut Context<Self>) {\n        // Check if parent still exists\n        if let Ok(_) = self.parent.update(cx, |parent_state, cx| {\n            // Update parent\n            cx.notify();\n        }) {\n            // Parent successfully updated\n        }\n    }\n}\n```\n\n## Performance Optimization\n\n### Minimize cx.notify() Calls\n\nEach `cx.notify()` triggers a re-render. Batch updates when possible.\n\n```rust\n// ❌ Bad: Multiple notifications\nimpl MyComponent {\n    fn update_multiple_fields(&mut self, cx: &mut Context<Self>) {\n        self.field1 = new_value1;\n        cx.notify(); // Unnecessary intermediate notification\n\n        self.field2 = new_value2;\n        cx.notify(); // Unnecessary intermediate notification\n\n        self.field3 = new_value3;\n        cx.notify();\n    }\n}\n```\n\n```rust\n// ✅ Good: Single notification after all updates\nimpl MyComponent {\n    fn update_multiple_fields(&mut self, cx: &mut Context<Self>) {\n        self.field1 = new_value1;\n        self.field2 = new_value2;\n        self.field3 = new_value3;\n        cx.notify(); // Single notification\n    }\n}\n```\n\n### Conditional Updates\n\nOnly notify when state actually changes.\n\n```rust\nimpl MyComponent {\n    fn set_value(&mut self, new_value: i32, cx: &mut Context<Self>) {\n        if self.value != new_value {\n            self.value = new_value;\n            cx.notify(); // Only notify if changed\n        }\n    }\n}\n```\n\n### Use read_with for Complex Operations\n\nPrefer `read_with` over separate `read` calls.\n\n```rust\n// ❌ Less efficient: Multiple borrows\nlet state_ref = entity.read(cx);\nlet value1 = state_ref.field1;\nlet value2 = state_ref.field2;\n// state_ref borrowed for entire scope\n\n// ✅ More efficient: Single borrow with closure\nlet (value1, value2) = entity.read_with(cx, |state, cx| {\n    (state.field1, state.field2)\n});\n```\n\n### Avoid Excessive Entity Creation\n\nCreating entities has overhead. Reuse when appropriate.\n\n```rust\n// ❌ Bad: Creating entity per item in render\nimpl Render for MyList {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div().children(\n            self.items.iter().map(|item| {\n                // Don't create entities in render!\n                let entity = cx.new(|_| item.clone());\n                ItemView { entity }\n            })\n        )\n    }\n}\n```\n\n```rust\n// ✅ Good: Create entities once, reuse\nstruct MyList {\n    item_entities: Vec<Entity<Item>>,\n}\n\nimpl MyList {\n    fn add_item(&mut self, item: Item, cx: &mut Context<Self>) {\n        let entity = cx.new(|_| item);\n        self.item_entities.push(entity);\n        cx.notify();\n    }\n}\n```\n\n## Entity Lifecycle Management\n\n### Clean Up Weak References\n\nPeriodically clean up invalid weak references from collections.\n\n```rust\nstruct Container {\n    weak_children: Vec<WeakEntity<Child>>,\n}\n\nimpl Container {\n    fn cleanup_invalid_children(&mut self, cx: &mut Context<Self>) {\n        // Remove weak references that are no longer valid\n        let before_count = self.weak_children.len();\n        self.weak_children.retain(|weak| weak.upgrade().is_some());\n        let after_count = self.weak_children.len();\n\n        if before_count != after_count {\n            cx.notify(); // Notify if list changed\n        }\n    }\n}\n```\n\n### Entity Cloning and Sharing\n\nUnderstand that cloning `Entity<T>` increases reference count.\n\n```rust\n// Each clone increases the reference count\nlet entity1: Entity<MyState> = cx.new(|_| MyState::default());\nlet entity2 = entity1.clone(); // Reference count: 2\nlet entity3 = entity1.clone(); // Reference count: 3\n\n// Entity is dropped only when all references are dropped\ndrop(entity1); // Reference count: 2\ndrop(entity2); // Reference count: 1\ndrop(entity3); // Reference count: 0, entity is deallocated\n```\n\n### Proper Resource Cleanup\n\nImplement cleanup in `Drop` or explicit cleanup methods.\n\n```rust\nstruct ManagedResource {\n    handle: Option<FileHandle>,\n}\n\nimpl ManagedResource {\n    fn close(&mut self, cx: &mut Context<Self>) {\n        if let Some(handle) = self.handle.take() {\n            // Explicit cleanup\n            handle.close();\n            cx.notify();\n        }\n    }\n}\n\nimpl Drop for ManagedResource {\n    fn drop(&mut self) {\n        // Automatic cleanup when entity is dropped\n        if let Some(handle) = self.handle.take() {\n            handle.close();\n        }\n    }\n}\n```\n\n## Entity Observation Best Practices\n\n### Detach Subscriptions Appropriately\n\nCall `.detach()` on subscriptions you want to keep alive.\n\n```rust\nimpl MyComponent {\n    fn new(other_entity: Entity<OtherComponent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observer will live as long as both entities exist\n            cx.observe(&other_entity, |this, observed, cx| {\n                // Handle changes\n                cx.notify();\n            }).detach(); // Important: detach to make permanent\n\n            Self { /* fields */ }\n        })\n    }\n}\n```\n\n### Avoid Observation Cycles\n\nDon't create mutual observation between entities.\n\n```rust\n// ❌ Bad: Mutual observation can cause infinite loops\nentity1.update(cx, |_, cx| {\n    cx.observe(&entity2, |_, _, cx| {\n        cx.notify(); // May trigger entity2's observer\n    }).detach();\n});\n\nentity2.update(cx, |_, cx| {\n    cx.observe(&entity1, |_, _, cx| {\n        cx.notify(); // May trigger entity1's observer → infinite loop\n    }).detach();\n});\n```\n\n## Async Best Practices\n\n### Always Use Weak References in Async Tasks\n\n```rust\n// ✅ Good: Weak reference in spawned task\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            let data = fetch_from_api().await;\n\n            // Entity may have been dropped during fetch\n            let _ = weak_entity.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n```\n\n### Handle Async Errors Gracefully\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            match fetch_from_api().await {\n                Ok(data) => {\n                    let _ = weak_entity.update(cx, |state, cx| {\n                        state.data = Some(data);\n                        state.error = None;\n                        cx.notify();\n                    });\n                }\n                Err(e) => {\n                    let _ = weak_entity.update(cx, |state, cx| {\n                        state.error = Some(e.to_string());\n                        cx.notify();\n                    });\n                }\n            }\n        }).detach();\n    }\n}\n```\n\n### Cancellation Patterns\n\nImplement cancellation for long-running tasks.\n\n```rust\nstruct DataFetcher {\n    current_task: Option<Task<()>>,\n    data: Option<String>,\n}\n\nimpl DataFetcher {\n    fn fetch_data(&mut self, url: String, cx: &mut Context<Self>) {\n        // Cancel previous task\n        self.current_task = None; // Dropping task cancels it\n\n        let weak_entity = cx.entity().downgrade();\n\n        let task = cx.spawn(async move |cx| {\n            let data = fetch_from_url(&url).await?;\n\n            let _ = weak_entity.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n\n            Ok::<(), anyhow::Error>(())\n        });\n\n        self.current_task = Some(task);\n    }\n}\n```\n\n## Testing Best Practices\n\n### Use TestAppContext for Entity Tests\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use gpui_kit::TestAppContext;\n\n    #[gpui_kit::test]\n    fn test_entity_update(cx: &mut TestAppContext) {\n        let entity = cx.new(|_| MyState { count: 0 });\n\n        entity.update(cx, |state, cx| {\n            state.count += 1;\n            assert_eq!(state.count, 1);\n        });\n\n        let count = entity.read(cx).count;\n        assert_eq!(count, 1);\n    }\n}\n```\n\n### Test Entity Observation\n\n```rust\n#[gpui_kit::test]\nfn test_entity_observation(cx: &mut TestAppContext) {\n    let observed = cx.new(|_| MyState { value: 0 });\n    let observer = cx.new(|cx| Observer::new(observed.clone(), cx));\n\n    // Update observed entity\n    observed.update(cx, |state, cx| {\n        state.value = 42;\n        cx.notify();\n    });\n\n    // Verify observer was notified\n    observer.read(cx).assert_observed();\n}\n```\n\n## Performance Checklist\n\nBefore shipping entity-based code, verify:\n\n- [ ] No strong references in closures/callbacks (use `WeakEntity`)\n- [ ] No nested entity updates (use sequential updates)\n- [ ] Using inner `cx` in update closures\n- [ ] Batching updates before calling `cx.notify()`\n- [ ] Cleaning up invalid weak references periodically\n- [ ] Using `read_with` for complex read operations\n- [ ] Properly detaching subscriptions and observers\n- [ ] Using weak references in async tasks\n- [ ] No observation cycles between entities\n- [ ] Proper error handling in async operations\n- [ ] Resource cleanup in `Drop` or explicit methods\n- [ ] Tests cover entity lifecycle and interactions\n","skills/gpui-kit/references/gpui/entity-patterns.md":"# Entity Patterns\n\n**Contents:** [Application Scenarios](#application-scenarios) · [Common Patterns](#common-patterns) · [Pattern Selection Guide](#pattern-selection-guide)\n\n## Application Scenarios\n\n### Model-View Separation\n\nSeparate business logic (model) from UI (view) using entities.\n\n```rust\nstruct CounterModel {\n    count: usize,\n    listeners: Vec<Box<dyn Fn(usize)>>,\n}\n\nstruct CounterView {\n    model: Entity<CounterModel>,\n}\n\nimpl CounterModel {\n    fn increment(&mut self, cx: &mut Context<Self>) {\n        self.count += 1;\n\n        // Notify listeners\n        for listener in &self.listeners {\n            listener(self.count);\n        }\n\n        cx.notify();\n    }\n\n    fn decrement(&mut self, cx: &mut Context<Self>) {\n        if self.count > 0 {\n            self.count -= 1;\n            cx.notify();\n        }\n    }\n}\n\nimpl CounterView {\n    fn new(cx: &mut App) -> Entity<Self> {\n        let model = cx.new(|_cx| CounterModel {\n            count: 0,\n            listeners: Vec::new(),\n        });\n\n        cx.new(|cx| Self { model })\n    }\n\n    fn increment_count(&mut self, cx: &mut Context<Self>) {\n        self.model.update(cx, |model, cx| {\n            model.increment(cx);\n        });\n    }\n}\n\nimpl Render for CounterView {\n    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let count = self.model.read(cx).count;\n\n        div()\n            .child(format!(\"Count: {}\", count))\n            .child(\n                Button::new(\"increment\")\n                    .label(\"Increment\")\n                    .on_click(cx.listener(|this, _, cx| {\n                        this.increment_count(cx);\n                    }))\n            )\n    }\n}\n```\n\n### Component State Management\n\nManaging complex component state with entities.\n\n```rust\nstruct TodoList {\n    todos: Vec<Todo>,\n    filter: TodoFilter,\n    next_id: usize,\n}\n\nstruct Todo {\n    id: usize,\n    text: String,\n    completed: bool,\n}\n\nenum TodoFilter {\n    All,\n    Active,\n    Completed,\n}\n\nimpl TodoList {\n    fn new() -> Self {\n        Self {\n            todos: Vec::new(),\n            filter: TodoFilter::All,\n            next_id: 0,\n        }\n    }\n\n    fn add_todo(&mut self, text: String, cx: &mut Context<Self>) {\n        self.todos.push(Todo {\n            id: self.next_id,\n            text,\n            completed: false,\n        });\n        self.next_id += 1;\n        cx.notify();\n    }\n\n    fn toggle_todo(&mut self, id: usize, cx: &mut Context<Self>) {\n        if let Some(todo) = self.todos.iter_mut().find(|t| t.id == id) {\n            todo.completed = !todo.completed;\n            cx.notify();\n        }\n    }\n\n    fn remove_todo(&mut self, id: usize, cx: &mut Context<Self>) {\n        self.todos.retain(|t| t.id != id);\n        cx.notify();\n    }\n\n    fn set_filter(&mut self, filter: TodoFilter, cx: &mut Context<Self>) {\n        self.filter = filter;\n        cx.notify();\n    }\n\n    fn visible_todos(&self) -> impl Iterator<Item = &Todo> {\n        self.todos.iter().filter(move |todo| match self.filter {\n            TodoFilter::All => true,\n            TodoFilter::Active => !todo.completed,\n            TodoFilter::Completed => todo.completed,\n        })\n    }\n}\n```\n\n### Cross-Entity Communication\n\nCoordinating state between parent and child entities.\n\n```rust\nstruct ParentComponent {\n    child_entities: Vec<Entity<ChildComponent>>,\n    global_message: String,\n}\n\nstruct ChildComponent {\n    id: usize,\n    message: String,\n    parent: WeakEntity<ParentComponent>,\n}\n\nimpl ParentComponent {\n    fn new(cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| Self {\n            child_entities: Vec::new(),\n            global_message: String::new(),\n        })\n    }\n\n    fn add_child(&mut self, cx: &mut Context<Self>) {\n        let parent_weak = cx.entity().downgrade();\n        let child_id = self.child_entities.len();\n\n        let child = cx.new(|cx| ChildComponent {\n            id: child_id,\n            message: String::new(),\n            parent: parent_weak,\n        });\n\n        self.child_entities.push(child);\n        cx.notify();\n    }\n\n    fn broadcast_message(&mut self, message: String, cx: &mut Context<Self>) {\n        self.global_message = message.clone();\n\n        // Update all children\n        for child in &self.child_entities {\n            child.update(cx, |child_state, cx| {\n                child_state.message = message.clone();\n                cx.notify();\n            });\n        }\n\n        cx.notify();\n    }\n}\n\nimpl ChildComponent {\n    fn notify_parent(&mut self, message: String, cx: &mut Context<Self>) {\n        if let Ok(_) = self.parent.update(cx, |parent_state, cx| {\n            parent_state.global_message = format!(\"Child {}: {}\", self.id, message);\n            cx.notify();\n        }) {\n            // Parent successfully notified\n        }\n    }\n}\n```\n\n### Async Operations with Entities\n\nManaging async state updates.\n\n```rust\nstruct DataLoader {\n    loading: bool,\n    data: Option<String>,\n    error: Option<String>,\n}\n\nimpl DataLoader {\n    fn new() -> Self {\n        Self {\n            loading: false,\n            data: None,\n            error: None,\n        }\n    }\n\n    fn load_data(&mut self, cx: &mut Context<Self>) {\n        // Set loading state\n        self.loading = true;\n        self.error = None;\n        cx.notify();\n\n        // Get weak reference for async task\n        let entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            // Simulate async operation\n            tokio::time::sleep(Duration::from_secs(2)).await;\n            let result = fetch_data().await;\n\n            // Update entity with result\n            let _ = entity.update(cx, |state, cx| {\n                state.loading = false;\n                match result {\n                    Ok(data) => state.data = Some(data),\n                    Err(e) => state.error = Some(e.to_string()),\n                }\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n\nasync fn fetch_data() -> Result<String, anyhow::Error> {\n    // Actual fetch implementation\n    Ok(\"Fetched data\".to_string())\n}\n```\n\n### Background Task Coordination\n\nUsing background tasks with entity updates.\n\n```rust\nstruct ImageProcessor {\n    images: Vec<ProcessedImage>,\n    processing: bool,\n}\n\nstruct ProcessedImage {\n    path: PathBuf,\n    thumbnail: Option<Vec<u8>>,\n}\n\nimpl ImageProcessor {\n    fn process_images(&mut self, paths: Vec<PathBuf>, cx: &mut Context<Self>) {\n        self.processing = true;\n        cx.notify();\n\n        cx.spawn(async move |this, cx| {\n            let processed = cx\n                .background_spawn(async move {\n                    let mut processed = Vec::new();\n\n                    for path in paths {\n                        // Process image on background thread\n                        let thumbnail = generate_thumbnail(&path).await;\n                        processed.push((path, thumbnail));\n                    }\n\n                    // Send results back to foreground\n                    processed\n                })\n                .await;\n\n            // Update entity on foreground thread\n            let _ = this.update(cx, |state, cx| {\n                for (path, thumbnail) in processed {\n                    state.images.push(ProcessedImage {\n                        path,\n                        thumbnail: Some(thumbnail),\n                    });\n                }\n                state.processing = false;\n                cx.notify();\n            });\n        })\n        .detach();\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Stateful Components\n\nUse entities for components that maintain internal state.\n\n```rust\nstruct StatefulComponent {\n    value: i32,\n    history: Vec<i32>,\n}\n\nimpl StatefulComponent {\n    fn update_value(&mut self, new_value: i32, cx: &mut Context<Self>) {\n        self.history.push(self.value);\n        self.value = new_value;\n        cx.notify();\n    }\n\n    fn undo(&mut self, cx: &mut Context<Self>) {\n        if let Some(prev_value) = self.history.pop() {\n            self.value = prev_value;\n            cx.notify();\n        }\n    }\n}\n```\n\n### 2. Shared State\n\nShare state between multiple components using entities.\n\n```rust\nstruct SharedState {\n    theme: Theme,\n    user: Option<User>,\n}\n\nstruct ComponentA {\n    shared: Entity<SharedState>,\n}\n\nstruct ComponentB {\n    shared: Entity<SharedState>,\n}\n\n// Both components can read/update the same shared state\nimpl ComponentA {\n    fn update_theme(&mut self, theme: Theme, cx: &mut Context<Self>) {\n        self.shared.update(cx, |state, cx| {\n            state.theme = theme;\n            cx.notify();\n        });\n    }\n}\n```\n\n### 3. Event Coordination\n\nUse entities to coordinate events between components.\n\n```rust\nstruct EventCoordinator {\n    listeners: Vec<WeakEntity<dyn EventListener>>,\n}\n\ntrait EventListener {\n    fn on_event(&mut self, event: &AppEvent, cx: &mut App);\n}\n\nimpl EventCoordinator {\n    fn emit_event(&mut self, event: AppEvent, cx: &mut Context<Self>) {\n        // Notify all listeners\n        self.listeners.retain(|weak_listener| {\n            weak_listener.update(cx, |listener, cx| {\n                listener.on_event(&event, cx);\n            }).is_ok()\n        });\n        cx.notify();\n    }\n}\n```\n\n### 4. Async State Management\n\nManage state that changes based on async operations.\n\n```rust\nstruct AsyncState<T> {\n    state: AsyncValue<T>,\n}\n\nenum AsyncValue<T> {\n    Loading,\n    Loaded(T),\n    Error(String),\n}\n\nimpl<T> AsyncState<T> {\n    fn is_loading(&self) -> bool {\n        matches!(self.state, AsyncValue::Loading)\n    }\n\n    fn value(&self) -> Option<&T> {\n        match &self.state {\n            AsyncValue::Loaded(v) => Some(v),\n            _ => None,\n        }\n    }\n}\n```\n\n### 5. Parent-Child Relationships\n\nManage hierarchical relationships with weak references.\n\n```rust\nstruct Parent {\n    children: Vec<Entity<Child>>,\n}\n\nstruct Child {\n    parent: WeakEntity<Parent>,\n    data: String,\n}\n\nimpl Child {\n    fn notify_parent_of_change(&mut self, cx: &mut Context<Self>) {\n        if let Ok(_) = self.parent.update(cx, |parent, cx| {\n            // Parent can react to child change\n            cx.notify();\n        }) {\n            // Successfully notified\n        }\n    }\n}\n```\n\n### 6. Observer Pattern\n\nReact to entity state changes using observers.\n\n```rust\nstruct Observable {\n    value: i32,\n}\n\nstruct Observer {\n    observed: Entity<Observable>,\n}\n\nimpl Observer {\n    fn new(observed: Entity<Observable>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observe the entity\n            cx.observe(&observed, |this, observed_entity, cx| {\n                // React to changes\n                let value = observed_entity.read(cx).value;\n                println!(\"Value changed to: {}\", value);\n            }).detach();\n\n            Self { observed }\n        })\n    }\n}\n```\n\n### 7. Event Subscription\n\nHandle events emitted by other entities.\n\n```rust\n#[derive(Clone)]\nenum DataEvent {\n    Updated,\n    Deleted,\n}\n\nstruct DataSource {\n    data: Vec<String>,\n}\n\nimpl DataSource {\n    fn update_data(&mut self, cx: &mut Context<Self>) {\n        // Update data\n        cx.emit(DataEvent::Updated);\n        cx.notify();\n    }\n}\n\nstruct DataConsumer {\n    source: Entity<DataSource>,\n}\n\nimpl DataConsumer {\n    fn new(source: Entity<DataSource>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Subscribe to events\n            cx.subscribe(&source, |this, source, event: &DataEvent, cx| {\n                match event {\n                    DataEvent::Updated => {\n                        // Handle update\n                        cx.notify();\n                    }\n                    DataEvent::Deleted => {\n                        // Handle deletion\n                    }\n                }\n            }).detach();\n\n            Self { source }\n        })\n    }\n}\n```\n\n### 8. Resource Management\n\nManage external resources with proper cleanup.\n\n```rust\nstruct FileHandle {\n    path: PathBuf,\n    file: Option<File>,\n}\n\nimpl FileHandle {\n    fn open(&mut self, cx: &mut Context<Self>) -> Result<()> {\n        self.file = Some(File::open(&self.path)?);\n        cx.notify();\n        Ok(())\n    }\n\n    fn close(&mut self, cx: &mut Context<Self>) {\n        self.file = None;\n        cx.notify();\n    }\n}\n\nimpl Drop for FileHandle {\n    fn drop(&mut self) {\n        // Cleanup when entity is dropped\n        if let Some(file) = self.file.take() {\n            drop(file);\n        }\n    }\n}\n```\n\n## Pattern Selection Guide\n\n| Need | Pattern | Complexity |\n|------|---------|------------|\n| Component with internal state | Stateful Components | Low |\n| State shared by multiple components | Shared State | Low |\n| Coordinate events between components | Event Coordination | Medium |\n| Handle async data fetching | Async State Management | Medium |\n| Parent-child component hierarchy | Parent-Child Relationships | Medium |\n| React to state changes | Observer Pattern | Medium |\n| Handle custom events | Event Subscription | Medium-High |\n| Manage external resources | Resource Management | High |\n\nChoose the simplest pattern that meets your requirements. Combine patterns as needed for complex scenarios.\n","skills/gpui-kit/references/gpui/entity.md":"# Entity State Management\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Core Principles](#core-principles) · [Common Use Cases](#common-use-cases) · [Extended References](#reference-documentation)\n\n## Overview\n\nAn `Entity<T>` is a handle to state of type `T`, providing safe access and updates.\n\n**Key Methods:**\n- `entity.read(cx)` → `&T` - Read-only access\n- `entity.read_with(cx, |state, cx| ...)` → `R` - Read with closure\n- `entity.update(cx, |state, cx| ...)` → `R` - Mutable update\n- `entity.downgrade()` → `WeakEntity<T>` - Create weak reference\n- `entity.entity_id()` → `EntityId` - Unique identifier\n\n**Entity Types:**\n- **`Entity<T>`**: Strong reference (increases ref count)\n- **`WeakEntity<T>`**: Weak reference (doesn't prevent cleanup, returns `Result`)\n\n## Quick Start\n\n### Creating and Using Entities\n\n```rust\n// Create entity\nlet counter = cx.new(|cx| Counter { count: 0 });\n\n// Read state\nlet count = counter.read(cx).count;\n\n// Update state\ncounter.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify(); // Trigger re-render\n});\n\n// Weak reference (for closures/callbacks)\nlet weak = counter.downgrade();\nlet _ = weak.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify();\n});\n```\n\n### In Components\n\n```rust\nstruct MyComponent {\n    shared_state: Entity<SharedData>,\n}\n\nimpl MyComponent {\n    fn new(cx: &mut App) -> Entity<Self> {\n        let shared = cx.new(|_| SharedData::default());\n\n        cx.new(|cx| Self {\n            shared_state: shared,\n        })\n    }\n\n    fn update_shared(&mut self, cx: &mut Context<Self>) {\n        self.shared_state.update(cx, |state, cx| {\n            state.value = 42;\n            cx.notify();\n        });\n    }\n}\n```\n\n### Async Operations\n\nWhen calling `cx.spawn` from `Context<Self>`, the closure receives `(WeakEntity<Self>, &mut AsyncApp)`:\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx: &mut AsyncApp| {\n            let data = fetch_from_api().await;\n\n            // Update entity safely via the weak reference\n            let _ = this.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n```\n\n## Core Principles\n\n### Always Use Weak References in Closures\n\n```rust\n// ✅ Good: Weak reference prevents retain cycles\nlet weak = cx.entity().downgrade();\ncallback(move || {\n    let _ = weak.update(cx, |state, cx| cx.notify());\n});\n\n// ❌ Bad: Strong reference may cause memory leak\nlet strong = cx.entity();\ncallback(move || {\n    strong.update(cx, |state, cx| cx.notify());\n});\n```\n\n### Use Inner Context\n\n```rust\n// ✅ Good: Use inner cx from closure\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Correct\n});\n\n// ❌ Bad: Use outer cx (multiple borrow error)\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong!\n});\n```\n\n### Avoid Nested Entity Updates\n\nNested `entity.update(cx, …)` calls are dangerous. The default posture is: **do not nest them**. The sub-cases below clarify when a panic is guaranteed vs. merely possible.\n\n**Same entity → always panics.**  \nGPUI locks an entity for the entire duration of its update or render pass. Re-entering that same lock panics immediately:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: updating entity_a from inside entity_a's own update\nentity_a.update(cx, |state, cx| {\n    entity_a.update(cx, |_, _| {}); // PANIC — same lock\n});\n```\n\n**Different entity → generally safe, but indirect cycles still panic.**  \nEach entity has its own lock, so updating `entity_b` from within `entity_a`'s update normally succeeds. However, if `entity_b`'s callback reaches back into `entity_a` — directly or through a chain — GPUI will attempt to re-acquire `entity_a`'s lock and panic.\n\n```rust\n// ✅ Usually fine: different entities, no cycle\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, _| {}); // OK — different lock\n});\n\n// ❌ Panic: indirect cycle back to entity_a\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, cx| {\n        entity_a.update(cx, |_, _| {}); // PANIC — entity_a is still locked\n    });\n});\n```\n\nWhen in doubt, flatten the call sequence rather than nesting: finish the outer update, then update the second entity from outside.\n\n**`defer_in` does not bypass the lock.** `cx.defer_in(window, callback)` schedules `callback` to run on the current entity — meaning GPUI re-acquires the entity's lock to execute it. The re-entrancy rules apply equally inside the deferred callback:\n\n```rust\n// ❌ Panic: defer_in re-locks entity_a; calling entity_a.update inside re-enters\nimpl SomeDelegate for MyAdapter {\n    fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n        cx.defer_in(window, |list_state, window, cx| {\n            // list_state is locked for this callback!\n            parent.update(cx, |this, cx| {\n                this.list.update(cx, |_, _| {}); // PANIC — list is already locked above\n            });\n        });\n    }\n}\n\n// ✅ Fix: use the direct &mut reference the callback provides\nimpl SomeDelegate for MyAdapter {\n    fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n        cx.defer_in(window, |list_state, window, cx| {\n            // Access list data directly — no entity lock needed\n            list_state.delegate_mut().some_hook();\n\n            // Update the *parent* entity — different lock, safe\n            parent.update(cx, |this, cx| { /* … */ });\n\n            // Sync list state directly after parent update\n            list_state.delegate_mut().update_snapshot(new_val);\n        });\n    }\n}\n```\n\n**Snapshot pattern for render callbacks.** `render_item` (and any other rendering hook) runs inside the entity's render pass. It must never call `entity.read(cx)` or `entity.update(cx, …)` on any external entity. Instead, keep a plain `snapshot` field updated eagerly from *outside* render after every mutation:\n\n```rust\n// ❌ Panic in render_item — ListState is already locked\nfn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<ListState<Self>>) -> … {\n    let checked = parent_entity.read(cx).selection.contains(&ix); // PANIC\n}\n\n// ✅ Read from a plain snapshot field — no entity access\nfn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<ListState<Self>>) -> … {\n    let checked = self.selection_snapshot.iter().any(|(sel_ix, _)| sel_ix == &ix);\n}\n```\n\n## Common Use Cases\n\n1. **Component State**: Internal state that needs reactivity\n2. **Shared State**: State shared between multiple components\n3. **Parent-Child**: Coordinating between related components (use weak refs)\n4. **Async State**: Managing state that changes from async operations\n5. **Observations**: Reacting to changes in other entities\n\n## Reference Documentation\n\n- **API**: See [entity-api.md](entity-api.md) — entity types, methods, lifecycle, error handling\n- **Patterns**: See [entity-patterns.md](entity-patterns.md) — model-view, cross-entity communication, observer\n- **Best Practices**: See [entity-best-practices.md](entity-best-practices.md) — pitfalls, memory, performance, async\n- **Advanced**: See [entity-advanced.md](entity-advanced.md) — collections, registry, debounce, state machines\n","skills/gpui-kit/references/gpui/event.md":"# Events & Subscriptions\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Patterns](#common-patterns) · [subscribe_in](#subscribe_in--subscription-with-window-access) · [observe_window_activation](#observe_window_activation) · [observe_global](#observe_global) · [Subscription Lifetime](#subscription-lifetime) · [Best Practices](#best-practices)\n\n## Overview\n\nGPUI provides event system for component coordination:\n\n**Event Mechanisms:**\n- **Custom Events**: Define and emit type-safe events\n- **Observations**: React to entity state changes\n- **Subscriptions**: Listen to events from other entities\n- **Global Events**: App-wide event handling\n\n## Quick Start\n\n### Define and Emit Events\n\n```rust\n#[derive(Clone)]\nenum MyEvent {\n    DataUpdated(String),\n    ActionTriggered,\n}\n\nimpl MyComponent {\n    fn update_data(&mut self, data: String, cx: &mut Context<Self>) {\n        self.data = data.clone();\n\n        // Emit event\n        cx.emit(MyEvent::DataUpdated(data));\n        cx.notify();\n    }\n}\n```\n\n### Subscribe to Events\n\n```rust\nimpl Listener {\n    fn new(source: Entity<MyComponent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Subscribe to events\n            cx.subscribe(&source, |this, emitter, event: &MyEvent, cx| {\n                match event {\n                    MyEvent::DataUpdated(data) => {\n                        this.handle_update(data.clone(), cx);\n                    }\n                    MyEvent::ActionTriggered => {\n                        this.handle_action(cx);\n                    }\n                }\n            }).detach();\n\n            Self { source }\n        })\n    }\n}\n```\n\n### Observe Entity Changes\n\n```rust\nimpl Observer {\n    fn new(target: Entity<Target>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observe entity for any changes\n            cx.observe(&target, |this, observed, cx| {\n                // Called when observed.update() calls cx.notify()\n                println!(\"Target changed\");\n                cx.notify();\n            }).detach();\n\n            Self { target }\n        })\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Parent-Child Communication\n\n```rust\n// Parent emits events\nimpl Parent {\n    fn notify_children(&mut self, cx: &mut Context<Self>) {\n        cx.emit(ParentEvent::Updated);\n        cx.notify();\n    }\n}\n\n// Children subscribe\nimpl Child {\n    fn new(parent: Entity<Parent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            cx.subscribe(&parent, |this, parent, event, cx| {\n                this.handle_parent_event(event, cx);\n            }).detach();\n\n            Self { parent }\n        })\n    }\n}\n```\n\n### 2. Global Event Broadcasting\n\n```rust\nstruct EventBus {\n    listeners: Vec<WeakEntity<dyn Listener>>,\n}\n\nimpl EventBus {\n    fn broadcast(&mut self, event: GlobalEvent, cx: &mut Context<Self>) {\n        self.listeners.retain(|weak| {\n            weak.update(cx, |listener, cx| {\n                listener.on_event(&event, cx);\n            }).is_ok()\n        });\n    }\n}\n```\n\n### 3. Observer Pattern\n\n```rust\ncx.observe(&entity, |this, observed, cx| {\n    // React to any state change\n    let state = observed.read(cx);\n    this.sync_with_state(state, cx);\n}).detach();\n```\n\n## subscribe_in — Subscription with Window Access\n\nUse when the subscription callback needs `&mut Window`:\n\n```rust\n// Store subscriptions to keep them alive\nstruct MyComponent {\n    _subscriptions: Vec<Subscription>,\n}\n\nimpl MyComponent {\n    fn new(input: &Entity<InputState>, window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let _subscriptions = vec![\n            cx.subscribe_in(input, window, |this, state, event, window, cx| {\n                match event {\n                    InputEvent::PressEnter { .. } => this.on_submit(window, cx),\n                    InputEvent::Change => {\n                        let val = state.read(cx).value();\n                        this.on_change(val, cx);\n                    }\n                    _ => {}\n                }\n            }),\n        ];\n        Self { _subscriptions }\n    }\n}\n```\n\n`subscribe` vs `subscribe_in`:\n- `cx.subscribe(&entity, |this, source, event, cx|)` — no window\n- `cx.subscribe_in(&entity, window, |this, source, event, window, cx|)` — window access\n\n## observe_window_activation\n\n```rust\nlet _sub = cx.observe_window_activation(window, |this, window, cx| {\n    if window.is_window_active() {\n        this.start_polling(cx);\n    } else {\n        this.stop_polling(cx);\n    }\n});\n```\n\n## observe_global\n\n```rust\ncx.observe_global::<Theme>(|cx| {\n    cx.notify(); // Re-render when theme changes\n});\n```\n\n## Subscription Lifetime\n\nSubscriptions are cancelled when dropped. Two ways to keep alive:\n\n```rust\n// 1. .detach() — lives until entity is dropped\ncx.subscribe(&entity, |this, _, event, cx| {\n    // ...\n}).detach();\n\n// 2. Store in struct — cancelled when struct drops\nstruct MyView {\n    _subscriptions: Vec<Subscription>,\n}\n// _subscriptions.push(cx.subscribe(...));\n```\n\nUse `.detach()` for permanent subscriptions; store in struct for subscriptions that should stop when the component unmounts.\n\n## Best Practices\n\n### ✅ Detach Subscriptions\n\n```rust\n// ✅ Detach to keep alive\ncx.subscribe(&entity, |this, source, event, cx| {\n    // Handle event\n}).detach();\n```\n\n### ✅ Clean Event Types\n\n```rust\n#[derive(Clone)]\nenum AppEvent {\n    DataChanged { id: usize, value: String },\n    ActionPerformed(ActionType),\n    Error(String),\n}\n```\n\n### ❌ Avoid Event Loops\n\n```rust\n// ❌ Don't create mutual subscriptions\nentity1.subscribe(entity2) → emits event\nentity2.subscribe(entity1) → emits event → infinite loop!\n```\n\n## Reference Documentation\n\n","skills/gpui-kit/references/gpui/focus-handle.md":"# Focus & Keyboard Navigation\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Focus Events](#focus-events) · [Keyboard Navigation](#keyboard-navigation) · [Common Patterns](#common-patterns) · [Best Practices](#best-practices)\n\n## Overview\n\nGPUI's focus system enables keyboard navigation and focus management.\n\n**Key Concepts:**\n- **FocusHandle**: Reference to focusable element\n- **Focus tracking**: Current focused element\n- **Keyboard navigation**: Tab/Shift-Tab between elements\n- **Focus events**: on_focus, on_blur\n\n## Quick Start\n\n### Creating Focus Handles\n\n```rust\nstruct FocusableComponent {\n    focus_handle: FocusHandle,\n}\n\nimpl FocusableComponent {\n    fn new(cx: &mut Context<Self>) -> Self {\n        Self {\n            focus_handle: cx.focus_handle(),\n        }\n    }\n}\n```\n\n### Making Elements Focusable\n\n```rust\nimpl Render for FocusableComponent {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .on_action(cx.listener(Self::on_enter))\n            .child(\"Focusable content\")\n    }\n\n    fn on_enter(&mut self, _: &Enter, cx: &mut Context<Self>) {\n        // Handle Enter key when focused\n        cx.notify();\n    }\n}\n```\n\n### Focus Management\n\n```rust\nimpl MyComponent {\n    fn focus(&mut self, cx: &mut Context<Self>) {\n        self.focus_handle.focus(cx);\n    }\n\n    fn is_focused(&self, cx: &App) -> bool {\n        self.focus_handle.is_focused(cx)\n    }\n\n    fn blur(&mut self, cx: &mut Context<Self>) {\n        cx.blur();\n    }\n}\n```\n\n## Focus Events\n\n### Handling Focus Changes\n\n```rust\nimpl Render for MyInput {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let is_focused = self.focus_handle.is_focused(cx);\n\n        div()\n            .track_focus(&self.focus_handle)\n            .on_focus(cx.listener(|this, _event, cx| {\n                this.on_focus(cx);\n            }))\n            .on_blur(cx.listener(|this, _event, cx| {\n                this.on_blur(cx);\n            }))\n            .when(is_focused, |el| {\n                el.bg(cx.theme().focused_background)\n            })\n            .child(self.render_content())\n    }\n}\n\nimpl MyInput {\n    fn on_focus(&mut self, cx: &mut Context<Self>) {\n        // Handle focus gained\n        cx.notify();\n    }\n\n    fn on_blur(&mut self, cx: &mut Context<Self>) {\n        // Handle focus lost\n        cx.notify();\n    }\n}\n```\n\n## Keyboard Navigation\n\n### Tab Order\n\nA tracked handle is a Tab stop only when the handle says so. `cx.focus_handle()`\nstarts with `tab_stop = false`, and an element's own `.tab_index()` /\n`.tab_stop()` do not apply to a handle passed to `track_focus`: build the handle\nwith the flag.\n\n```rust\n// In the owning entity's constructor:\nlet focus1 = cx.focus_handle().tab_stop(true);          // Tab order: 1\nlet focus2 = cx.focus_handle().tab_stop(true);          // Tab order: 2\nlet hidden = cx.focus_handle();                         // focusable, never a Tab stop\n\ndiv()\n    .child(div().track_focus(&focus1).child(\"first\"))\n    .child(div().track_focus(&focus2).child(\"second\"))\n    .child(div().track_focus(&hidden).child(\"container\"))\n```\n\nThe Tab table is rebuilt every frame from the elements that painted with a\ntracked handle, in tree order (`tab_index` reorders within a `tab_group`). A\nstateless component may create its handle in `render` through keyed state —\n`window.use_keyed_state(id, cx, |_, cx| cx.focus_handle().tab_stop(true))` —\nwhich survives re-renders, so the order stays stable; `Button` does exactly\nthis. A focused element receives `ClickEvent::Keyboard` in `on_click` when\nEnter or Space is released, so a `track_focus` + `on_click` row activates from\nthe keyboard without extra bindings.\n\n### Focus Within Containers\n\n```rust\nimpl Container {\n    fn focus_first(&mut self, cx: &mut Context<Self>) {\n        if let Some(first) = self.children.first() {\n            first.update(cx, |child, cx| {\n                child.focus_handle.focus(cx);\n            });\n        }\n    }\n\n    fn focus_next(&mut self, cx: &mut Context<Self>) {\n        // Custom focus navigation logic\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Auto-focus on Mount\n\n```rust\nimpl MyDialog {\n    fn new(cx: &mut Context<Self>) -> Self {\n        let focus_handle = cx.focus_handle();\n\n        // Focus when created\n        focus_handle.focus(cx);\n\n        Self { focus_handle }\n    }\n}\n```\n\n### 2. Focus Trap (Modal)\n\n```rust\nimpl Modal {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .on_key_down(cx.listener(|this, event: &KeyDownEvent, cx| {\n                if event.key == Key::Tab {\n                    // Keep focus within modal\n                    this.focus_next_in_modal(cx);\n                    cx.stop_propagation();\n                }\n            }))\n            .child(self.render_content())\n    }\n}\n```\n\n### 3. Conditional Focus\n\n```rust\nimpl Searchable {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .when(self.search_active, |el| {\n                el.on_mount(cx.listener(|this, _, cx| {\n                    this.focus_handle.focus(cx);\n                }))\n            })\n            .child(self.search_input())\n    }\n}\n```\n\n### 4. Restore Lost Focus\n\nIf the focused element is no longer rendered (a table swapped for an empty\nstate), key dispatch starts at the dispatch tree's root node, so the view's\n`key_context` bindings and `on_action` handlers stop firing. Register one\n`cx.on_focus_lost` listener per window, usually on the root view, and move\nFocus to `window.focus_lost_restore_target(cx)`: the closest focusable\nancestor that is still rendered. Track the view's own handle on the element\nthat carries its `key_context`, so that element is the ancestor Focus returns\nto.\n\n```rust\nlet focus_lost = cx.on_focus_lost(window, |this, window, cx| {\n    let target = window\n        .focus_lost_restore_target(cx)\n        .unwrap_or_else(|| this.focus_handle.clone());\n    target.focus(window, cx);\n});\n// `this.focus_handle` is the view's tracked handle. Keep `focus_lost:\n// Subscription` on the view; dropping it unregisters.\n```\n\n## Best Practices\n\n### ✅ Track Focus on Interactive Elements\n\n```rust\n// ✅ Good: Track focus for keyboard interaction\ninput()\n    .track_focus(&self.focus_handle)\n    .on_action(cx.listener(Self::on_enter))\n```\n\n### ✅ Provide Visual Focus Indicators\n\nDraw the framework's ring so custom controls match `Button` and `Input`:\n\n```rust\nuse gpui_kit::component::ThemeStyled as _;\n\nlet is_focused = self.focus_handle.is_focused(window);\n\ndiv()\n    .track_focus(&self.focus_handle)\n    .when(is_focused, |el| el.focus_ring_style(window, cx))\n```\n\nThe ring is painted 3px outside the element, so an ancestor with\n`overflow_hidden()` clips it; leave it room or draw the ring inside the element.\n\n### ❌ Don't: Forget to Track Focus\n\n```rust\n// ❌ Bad: No track_focus, keyboard navigation won't work\ndiv()\n    .on_action(cx.listener(Self::on_enter))\n```\n\n","skills/gpui-kit/references/gpui/global.md":"# Global State\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Use Cases](#common-use-cases) · [Best Practices](#best-practices) · [When to Use](#when-to-use)\n\n## Overview\n\nGlobal state in GPUI provides app-wide shared data accessible from any context.\n\n**Key Trait**: `Global` - Implement on types to make them globally accessible\n\n## Quick Start\n\n### Define Global State\n\n```rust\nuse gpui_kit::Global;\n\n#[derive(Clone)]\nstruct AppSettings {\n    theme: Theme,\n    language: String,\n}\n\nimpl Global for AppSettings {}\n```\n\n### Set and Access Globals\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx: &mut App| {\n        // Set global\n        cx.set_global(AppSettings {\n            theme: Theme::Dark,\n            language: \"en\".to_string(),\n        });\n\n        // Access global (read-only)\n        let settings = cx.global::<AppSettings>();\n        println!(\"Theme: {:?}\", settings.theme);\n    });\n}\n```\n\n### Update Globals\n\n```rust\nimpl MyComponent {\n    fn change_theme(&mut self, new_theme: Theme, cx: &mut Context<Self>) {\n        cx.update_global::<AppSettings, _>(|settings, cx| {\n            settings.theme = new_theme;\n            // Global updates don't trigger automatic notifications\n            // Manually notify components that care\n        });\n\n        cx.notify(); // Re-render this component\n    }\n}\n```\n\n## Common Use Cases\n\n### 1. App Configuration\n\n```rust\n#[derive(Clone)]\nstruct AppConfig {\n    api_endpoint: String,\n    max_retries: u32,\n    timeout: Duration,\n}\n\nimpl Global for AppConfig {}\n\n// Set once at startup\ncx.set_global(AppConfig {\n    api_endpoint: \"https://api.example.com\".to_string(),\n    max_retries: 3,\n    timeout: Duration::from_secs(30),\n});\n\n// Access anywhere\nlet config = cx.global::<AppConfig>();\n```\n\n### 2. Feature Flags\n\n```rust\n#[derive(Clone)]\nstruct FeatureFlags {\n    enable_beta_features: bool,\n    enable_analytics: bool,\n}\n\nimpl Global for FeatureFlags {}\n\nimpl MyComponent {\n    fn render_beta_feature(&self, cx: &App) -> Option<impl IntoElement> {\n        let flags = cx.global::<FeatureFlags>();\n\n        if flags.enable_beta_features {\n            Some(div().child(\"Beta feature\"))\n        } else {\n            None\n        }\n    }\n}\n```\n\n### 3. Shared Services\n\n```rust\n#[derive(Clone)]\nstruct ServiceRegistry {\n    http_client: Arc<HttpClient>,\n    logger: Arc<Logger>,\n}\n\nimpl Global for ServiceRegistry {}\n\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let registry = cx.global::<ServiceRegistry>();\n        let client = registry.http_client.clone();\n\n        cx.spawn(async move |cx| {\n            let data = client.get(\"api/data\").await?;\n            // Process data...\n            Ok::<_, anyhow::Error>(())\n        }).detach();\n    }\n}\n```\n\n## Best Practices\n\n### ✅ Use Arc for Shared Resources\n\n```rust\n#[derive(Clone)]\nstruct GlobalState {\n    database: Arc<Database>,  // Cheap to clone\n    cache: Arc<RwLock<Cache>>,\n}\n\nimpl Global for GlobalState {}\n```\n\n### ✅ Immutable by Default\n\nGlobals are read-only by default. Use interior mutability when needed:\n\n```rust\n#[derive(Clone)]\nstruct Counter {\n    count: Arc<AtomicUsize>,\n}\n\nimpl Global for Counter {}\n\nimpl Counter {\n    fn increment(&self) {\n        self.count.fetch_add(1, Ordering::SeqCst);\n    }\n\n    fn get(&self) -> usize {\n        self.count.load(Ordering::SeqCst)\n    }\n}\n```\n\n### ❌ Don't: Overuse Globals\n\n```rust\n// ❌ Bad: Too many globals\ncx.set_global(UserState { ... });\ncx.set_global(CartState { ... });\ncx.set_global(CheckoutState { ... });\n\n// ✅ Good: Use entities for component state\nlet user_entity = cx.new(|_| UserState { ... });\n```\n\n## When to Use\n\n**Use Globals for:**\n- App-wide configuration\n- Feature flags\n- Shared services (HTTP client, logger)\n- Read-only reference data\n\n**Use Entities for:**\n- Component-specific state\n- State that changes frequently\n- State that needs notifications\n\n","skills/gpui-kit/references/gpui/layout-style.md":"# Layout & Styling\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Patterns](#common-patterns) · [Styling Methods](#styling-methods) · [h_flex / v_flex](#h_flex--v_flex-helpers) · [Tailwind Shorthands](#tailwind-style-shorthand) · [Overflow & Scroll](#overflow-and-scroll) · [Absolute Positioning](#absolute-positioning) · [Stacking Order](#stacking-order) · [Theme Integration](#theme-integration) · [Conditional Styling](#conditional-styling) · [Text Styling](#text-styling)\n\n## Overview\n\nGPUI provides CSS-like styling with Rust type safety.\n\n**Key Concepts:**\n\n- Flexbox layout system\n- Styled trait for chaining styles\n- Size units: `px()`, `rems()`, `relative()`\n- Colors, borders, shadows\n\n## Quick Start\n\n### Basic Styling\n\n```rust\nuse gpui_kit::*;\n\ndiv()\n    .w(px(200.))\n    .h(px(100.))\n    .bg(rgb(0x2196F3))\n    .text_color(rgb(0xFFFFFF))\n    .rounded(px(8.))\n    .p(px(16.))\n    .child(\"Styled content\")\n```\n\n### Flexbox Layout\n\n```rust\ndiv()\n    .flex()\n    .flex_row()  // or flex_col() for column\n    .gap(px(8.))\n    .items_center()\n    .justify_between()\n    .children([\n        div().child(\"Item 1\"),\n        div().child(\"Item 2\"),\n        div().child(\"Item 3\"),\n    ])\n```\n\n### Size Units\n\n```rust\ndiv()\n    .w(px(200.))           // Pixels\n    .h(rems(10.))          // Relative to font size\n    .w(relative(0.5))      // 50% of parent\n    .min_w(px(100.))\n    .max_w(px(400.))\n```\n\n## Common Patterns\n\n### Centered Content\n\n```rust\ndiv()\n    .flex()\n    .items_center()\n    .justify_center()\n    .size_full()\n    .child(\"Centered\")\n```\n\n### Card Layout\n\n```rust\ndiv()\n    .w(px(300.))\n    .bg(cx.theme().surface)\n    .rounded(px(8.))\n    .shadow_md()\n    .p(px(16.))\n    .gap(px(12.))\n    .flex()\n    .flex_col()\n    .child(heading())\n    .child(content())\n```\n\n### Responsive Spacing\n\n```rust\ndiv()\n    .p(px(16.))           // Padding all sides\n    .px(px(20.))          // Padding horizontal\n    .py(px(12.))          // Padding vertical\n    .pt(px(8.))           // Padding top\n    .gap(px(8.))          // Gap between children\n```\n\n## Styling Methods\n\n### Dimensions\n\n```rust\n.w(px(200.))              // Width\n.h(px(100.))              // Height\n.size(px(200.))           // Width and height\n.min_w(px(100.))          // Min width\n.max_w(px(400.))          // Max width\n```\n\n### Colors\n\n```rust\n.bg(rgb(0x2196F3))        // Background\n.text_color(rgb(0xFFFFFF)) // Text color\n.border_color(rgb(0x000000)) // Border color\n```\n\n### Borders\n\n```rust\n.border(px(1.))           // Border width\n.rounded(px(8.))          // Border radius\n.rounded_t(px(8.))        // Top corners\n.border_color(rgb(0x000000))\n```\n\n### Spacing\n\n```rust\n.p(px(16.))               // Padding\n.m(px(8.))                // Margin\n.gap(px(8.))              // Gap between flex children\n```\n\n### Flexbox\n\n```rust\n.flex()                   // Enable flexbox\n.flex_row()               // Row direction\n.flex_col()               // Column direction\n.items_center()           // Align items center\n.justify_between()        // Space between items\n.flex_grow_1()              // Grow to fill space\n```\n\n## h_flex / v_flex Helpers\n\n`gpui_kit::component` provides shorthand helpers (import from `gpui_kit::component`):\n\n```rust\nuse gpui_kit::component::{h_flex, v_flex};\n\n// h_flex() = div().flex().flex_row().items_center()\nh_flex()\n    .gap_2()\n    .child(icon)\n    .child(label)\n\n// v_flex() = div().flex().flex_col()\nv_flex()\n    .gap_4()\n    .p_4()\n    .child(input1)\n    .child(input2)\n    .child(submit_btn)\n```\n\nThese are the standard layout primitives in `gpui_kit::component`. Prefer them over raw `div().flex()`.\n\n## Tailwind-style Shorthand\n\nGPUI provides Tailwind-style spacing/sizing shorthands:\n\n```rust\n// Spacing (0=0, 1=4px, 2=8px, 3=12px, 4=16px, ...)\n.p_2()    // padding: 8px\n.px_4()   // padding x: 16px\n.py_3()   // padding y: 12px\n.m_2()    // margin: 8px\n.gap_3()  // gap: 12px\n\n// Size\n.size_full()   // width: 100%, height: 100%\n.size_4()      // width: 16px, height: 16px\n.w_full()      // width: 100%\n.h_full()      // height: 100%\n.flex_1()      // flex: 1 1 0 (fill remaining space)\n.flex_shrink_0() // prevent shrinking\n```\n\n## Overflow and Scroll\n\n```rust\ndiv()\n    .overflow_hidden()          // clip content\n    .overflow_x_hidden()        // clip horizontal\n    .overflow_y_scrollbar()     // show scrollbar on y axis\n    .overflow_scroll()          // scroll both axes\n```\n\n## Absolute Positioning\n\n```rust\ndiv()\n    .relative()                 // position: relative (container)\n    .child(\n        div()\n            .absolute()         // position: absolute\n            .top_0()\n            .right_0()\n            .child(\"badge\")\n    )\n\n// Inset helpers\ndiv().absolute().inset_0()      // top/right/bottom/left: 0 (fill parent)\ndiv().absolute().top(px(8.)).left(px(8.))\n```\n\n## Stacking Order\n\n```rust\ndiv()\n    .relative()\n    .child(content)\n    .child(\n        div()\n            .absolute()\n            .top_0()\n            .right_0()\n            .child(\"badge\")\n    ) // later children are typically painted above earlier siblings\n```\n\nGPUI's general `Styled` API does **not** provide a `z_index(...)` method.\n\nFor normal elements, stacking is usually controlled by:\n\n- Parent/child composition\n- Absolute positioning\n- Render order of siblings (later siblings paint above earlier ones)\n\nIf you see a `z_index(...)` method in this repository, make sure it belongs to the specific component you are using: a component's own ordering API is not a general GPUI `Div` styling method.\n\n## Theme Integration\n\n```rust\ndiv()\n    .bg(cx.theme().surface)\n    .text_color(cx.theme().foreground)\n    .border_color(cx.theme().border)\n    .when(is_hovered, |el| {\n        el.bg(cx.theme().hover)\n    })\n```\n\n## Conditional Styling\n\n```rust\nuse gpui_kit::prelude::FluentBuilder as _;\n\ndiv()\n    .when(is_active, |el| el.bg(cx.theme().primary))\n    .when(!is_active, |el| el.opacity(0.5))\n    .when_some(optional_color.as_ref(), |el, color| el.bg(*color))\n```\n\n## Text Styling\n\n```rust\ndiv()\n    .text_sm()          // font-size: small\n    .text_base()        // font-size: base\n    .text_lg()          // font-size: large\n    .font_bold()        // font-weight: bold\n    .line_height_snug() // tighter line height\n    .truncate()         // overflow: ellipsis, single line\n    .whitespace_nowrap()\n```\n","skills/gpui-kit/references/gpui/test-examples.md":"# Test Examples\n\n**Contents:** [Testing Best Practices](#testing-best-practices) · [Test Organization](#test-organization) · [Setup and Teardown](#setup-and-teardown) · [Assertions](#assertions) · [Performance Testing](#performance-testing) · [Running Tests](#running-tests) · [Basic Test Execution](#basic-test-execution) · [Test Configuration](#test-configuration) · [Advanced Test Execution](#advanced-test-execution) · [CI/CD Integration](#cicd-integration)\n\n## Testing Best Practices\n\n### Test Organization\n\nGroup related tests in modules:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    mod entity_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        fn test_creation() { /* ... */ }\n\n        #[gpui_kit::test]\n        fn test_updates() { /* ... */ }\n    }\n\n    mod async_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        async fn test_async_ops() { /* ... */ }\n    }\n\n    mod distributed_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        fn test_multi_app() { /* ... */ }\n    }\n}\n```\n\n### Setup and Teardown\n\nUse helper functions for common setup:\n\n```rust\nfn create_test_counter(cx: &mut TestAppContext) -> Entity<Counter> {\n    cx.new(|cx| Counter::new(cx))\n}\n\n#[gpui_kit::test]\nfn test_counter_operations(cx: &mut TestAppContext) {\n    let counter = create_test_counter(cx);\n\n    // Test operations\n}\n```\n\n### Assertions\n\nUse descriptive assertions:\n\n```rust\n#[gpui_kit::test]\nfn test_counter_bounds(cx: &mut TestAppContext) {\n    let counter = create_test_counter(cx);\n\n    // Test upper bound\n    for _ in 0..100 {\n        counter.update(cx, |counter, cx| {\n            counter.increment(cx);\n        });\n    }\n\n    let count = counter.read_with(cx, |counter, _| counter.count);\n    assert!(count <= 100, \"Counter should not exceed maximum\");\n\n    // Test lower bound\n    for _ in 0..200 {\n        counter.update(cx, |counter, cx| {\n            counter.decrement(cx);\n        });\n    }\n\n    let count = counter.read_with(cx, |counter, _| counter.count);\n    assert!(count >= 0, \"Counter should not go below minimum\");\n}\n```\n\n### Performance Testing\n\nTest performance characteristics:\n\n```rust\n#[gpui_kit::test]\nfn test_operation_performance(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    let start = std::time::Instant::now();\n\n    // Perform many operations\n    for i in 0..1000 {\n        component.update(cx, |comp, cx| {\n            comp.perform_operation(i, cx);\n        });\n    }\n\n    let elapsed = start.elapsed();\n    assert!(elapsed < Duration::from_millis(100), \"Operations should complete quickly\");\n}\n```\n\n## Running Tests\n\n### Basic Test Execution\n\n```bash\n# Run all tests\ncargo test\n\n# Run specific test\ncargo test test_counter_operations\n\n# Run tests in a specific module\ncargo test entity_tests::\n\n# Run with output\ncargo test -- --nocapture\n```\n\n### Test Configuration\n\nEnable test-support feature for GPUI tests:\n\n```toml\n[features]\ntest-support = [\"gpui/test-support\"]\n```\n\n```bash\ncargo test --features test-support\n```\n\n### Advanced Test Execution\n\n```bash\n# Run tests with iterations for property testing\ncargo test -- --test-threads=1\n\n# Run tests matching a pattern\ncargo test test_async\n\n# Run tests with backtrace on failure\nRUST_BACKTRACE=1 cargo test\n```\n\n### CI/CD Integration\n\nFor continuous integration:\n\n```yaml\n# .github/workflows/test.yml\nname: Tests\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: dtolnay/rust-toolchain@stable\n      - name: Run tests\n        run: cargo test --features test-support\n```\n\nGPUI's testing framework provides deterministic, fast, and comprehensive testing capabilities that mirror real application behavior while providing the control needed for thorough testing of complex UI and async scenarios.","skills/gpui-kit/references/gpui/test-reference.md":"# Test Reference\n\n**Contents:** [Testing Patterns](#testing-patterns) · [Testing Crash-Free State Management (Re-entrancy)](#testing-crash-free-state-management-re-entrancy) · [Property Testing](#property-testing) · [Distributed Systems Testing](#distributed-systems-testing) · [Mocking and Isolation](#mocking-and-isolation)\n\n## Testing Patterns\n\n### Basic Entity Testing\n\nTest entity creation, updates, and reads:\n\n```rust\n#[gpui_kit::test]\nfn test_counter_entity(cx: &mut TestAppContext) {\n    let counter = cx.new(|cx| Counter::new(cx));\n\n    // Test initial state\n    let initial_count = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(initial_count, 0);\n\n    // Test updates\n    counter.update(cx, |counter, cx| {\n        counter.count = 42;\n        cx.notify();\n    });\n\n    let updated_count = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(updated_count, 42);\n}\n```\n\n### Event Testing\n\nTest event emission and handling:\n\n```rust\n#[derive(Clone)]\nstruct ValueChanged {\n    new_value: i32,\n}\n\nimpl EventEmitter<ValueChanged> for MyComponent {}\n\n#[gpui_kit::test]\nfn test_event_emission(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| {\n        let mut comp = MyComponent::default();\n\n        // Subscribe to self\n        cx.subscribe_self(|this, event: &ValueChanged, cx| {\n            this.received_value = event.new_value;\n            cx.notify();\n        });\n\n        comp\n    });\n\n    // Emit event\n    component.update(cx, |_, cx| {\n        cx.emit(ValueChanged { new_value: 123 });\n    });\n\n    // Verify event was handled\n    let received = component.read_with(cx, |comp, _| comp.received_value);\n    assert_eq!(received, 123);\n}\n```\n\n### Action Testing\n\nTest action dispatching and handling:\n\n```rust\nactions!(my_app, [Increment, Decrement]);\n\n#[gpui_kit::test]\nfn test_action_dispatch(cx: &mut TestAppContext) {\n    let window = cx.update(|cx| {\n        cx.open_window(Default::default(), |_, cx| {\n            cx.new(|cx| MyComponent::new(cx))\n        }).unwrap()\n    });\n\n    let mut cx = VisualTestContext::from_window(window.into(), cx);\n    let counter = window.root(&mut cx).unwrap();\n\n    // Dispatch action via focus handle\n    let focus_handle = counter.read_with(&cx, |counter, _| counter.focus_handle.clone());\n    cx.update(|window, cx| {\n        focus_handle.dispatch_action(&Increment, window, cx);\n    });\n\n    let count = counter.read_with(&cx, |counter, _| counter.count);\n    assert_eq!(count, 1);\n}\n```\n\n### Async Testing\n\nTest async operations and background tasks:\n\n```rust\nimpl MyComponent {\n    fn load_data(&self, cx: &mut Context<Self>) -> Task<i32> {\n        cx.spawn(async move |this, cx| {\n            // Simulate async work\n            this.update(cx, |comp, _| comp.loading = true).await;\n            // Return result\n            42\n        })\n    }\n\n    fn background_update(&self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            // Background work\n            this.update(cx, |comp, _| {\n                comp.value += 10;\n            }).await;\n        }).detach();\n    }\n}\n\n#[gpui_kit::test]\nasync fn test_async_operations(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    // Test awaited task\n    let result = component.update(cx, |comp, cx| comp.load_data(cx)).await;\n    assert_eq!(result, 42);\n\n    // Test detached task\n    component.update(cx, |comp, cx| comp.background_update(cx));\n\n    // Detached tasks don't run until you yield\n    let value_before = component.read_with(cx, |comp, _| comp.value);\n    assert_eq!(value_before, 0);\n\n    // Run pending tasks\n    cx.run_until_parked();\n\n    let value_after = component.read_with(cx, |comp, _| comp.value);\n    assert_eq!(value_after, 10);\n}\n```\n\n### Timer Testing\n\nTest timer-based operations:\n\n```rust\nimpl MyComponent {\n    fn delayed_action(&self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            cx.background_executor()\n                .timer(Duration::from_millis(100))\n                .await;\n\n            this.update(cx, |comp, cx| {\n                comp.action_performed = true;\n                cx.notify();\n            }).await;\n        }).detach();\n    }\n}\n\n#[gpui_kit::test]\nasync fn test_timers(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    component.update(cx, |comp, cx| comp.delayed_action(cx));\n\n    // Action shouldn't have completed yet\n    let performed = component.read_with(cx, |comp, _| comp.action_performed);\n    assert!(!performed);\n\n    // Run until parked (timers complete)\n    cx.run_until_parked();\n\n    let performed = component.read_with(cx, |comp, _| comp.action_performed);\n    assert!(performed);\n}\n```\n\n### External I/O Testing\n\nFor tests involving external systems, use `allow_parking()`:\n\n```rust\n#[gpui_kit::test]\nasync fn test_external_io(cx: &mut TestAppContext) {\n    // Allow parking for external I/O\n    cx.executor().allow_parking();\n\n    // Simulate external operation\n    let (tx, rx) = futures::channel::oneshot::channel();\n    std::thread::spawn(move || {\n        std::thread::sleep(Duration::from_millis(10));\n        tx.send(42).ok();\n    });\n\n    let result = rx.await.unwrap();\n    assert_eq!(result, 42);\n}\n```\n\n## Testing Crash-Free State Management (Re-entrancy)\n\nThe most dangerous class of GPUI bugs is **entity re-entrancy**: code that tries to update or read an entity while it is already locked in a render/update pass. These bugs are invisible at compile time — they only panic at runtime, typically when the user clicks something in a list or dropdown.\n\n**Key properties of re-entrancy panics:**\n- Triggered by user interaction (click, key press), not during static rendering.\n- `#[should_panic]` only confirms the bug exists — tests must pass *without* panicking.\n- `Select` commits through `defer_in` after the key or click dispatch returns. Wait for the result with `cx.wait_for` instead of asserting straight after the interaction.\n\nDrive the component the way a user does. `SelectState` keeps its list state `pub(crate)`, so a test outside `gpui-component` opens the menu, presses keys, and observes through `selected_value()`, the element snapshot, and the delegate's own hooks.\n\n### Pattern: Confirm through the real UI\n\n```rust\nuse gpui_kit::test::{TestAppContextExt, TestWindowExt};\nuse gpui_kit::{\n    AnyWindowHandle, AppContext, Bounds, Context, Entity, TestAppContext, Window, WindowBounds,\n    WindowOptions,\n    component::{\n        IndexPath,\n        searchable_list::SearchableListChange,\n        select::{SearchableVec, Select, SelectDelegate, SelectItem, SelectState},\n    },\n    div,\n    prelude::*,\n    px, size,\n};\nuse std::{cell::RefCell, rc::Rc, time::Duration};\n\nstruct Form {\n    language: Entity<SelectState<SearchableVec<&'static str>>>,\n}\n\nimpl Render for Form {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .size_full()\n            .child(Select::new(&self.language).id(\"language\").w(px(240.)))\n    }\n}\n\n#[gpui_kit::test]\nasync fn confirming_from_the_keyboard_commits_the_value(cx: &mut TestAppContext) {\n    cx.update(gpui_kit::init);\n    let mut language = None;\n    let (handle, _view) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let state = cx.new(|cx| {\n                    SelectState::new(\n                        SearchableVec::new(vec![\"Rust\", \"Go\"]),\n                        Some(IndexPath::new(0)),\n                        window,\n                        cx,\n                    )\n                });\n                language = Some(state.clone());\n                let view = cx.new(|_| Form { language: state });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n    let language = language.unwrap();\n\n    // Open the menu, move to \"Go\" and confirm — the same path a user takes.\n    cx.update_window(handle.into(), |_, window, cx| {\n        window.render_frame(cx);\n        window.within(\"language\").click(\"input\", cx);\n        window.press(\"down\", cx);\n        window.press(\"enter\", cx);\n    })\n    .unwrap();\n\n    // Select commits through `defer_in` after the key dispatch returns, so\n    // wait for the closed menu instead of asserting straight away.\n    cx.wait_for(handle.into(), Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n            && window.find(\"language\").value() == Some(\"Go\")\n    })\n    .await;\n\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Go\")));\n}\n```\n\n### Pattern: Record `on_will_change` and `on_confirm`\n\nA recording delegate shows which changes the selection strategy proposed and what was committed. `on_will_change` receives the proposed changes and the selection to edit; the delegate applies them itself (the trait's default applies all of them). It has no `cx`, because it runs while the list entity is borrowed, so put side effects that need `cx` in `on_confirm`.\n\n```rust\ntype Log = Rc<RefCell<Vec<String>>>;\n\n/// Records each hook call; `accept: false` vetoes every change.\nstruct Recording {\n    items: Vec<&'static str>,\n    accept: bool,\n    log: Log,\n}\n\nimpl SelectDelegate for Recording {\n    type Item = &'static str;\n\n    fn items_count(&self, _: usize) -> usize {\n        self.items.len()\n    }\n\n    fn item(&self, ix: IndexPath) -> Option<&Self::Item> {\n        self.items.get(ix.row)\n    }\n\n    fn position<V>(&self, value: &V) -> Option<IndexPath>\n    where\n        Self::Item: SelectItem<Value = V>,\n        V: PartialEq,\n    {\n        self.items\n            .iter()\n            .position(|item| item.value() == value)\n            .map(IndexPath::new)\n    }\n\n    fn on_will_change(\n        &mut self,\n        selection: &mut Vec<(IndexPath, Self::Item)>,\n        changes: &[SearchableListChange],\n    ) {\n        for change in changes {\n            match *change {\n                SearchableListChange::Select { index } => {\n                    self.log.borrow_mut().push(format!(\"select {}\", index.row));\n                    if self.accept\n                        && let Some(item) = self.item(index)\n                    {\n                        selection.push((index, *item));\n                    }\n                }\n                SearchableListChange::Deselect { index } => {\n                    self.log\n                        .borrow_mut()\n                        .push(format!(\"deselect {}\", index.row));\n                    if self.accept {\n                        selection.retain(|(ix, _)| *ix != index);\n                    }\n                }\n            }\n        }\n    }\n\n    fn on_confirm(&mut self, final_selection: &[(IndexPath, Self::Item)]) {\n        let values: Vec<_> = final_selection.iter().map(|(_, item)| *item).collect();\n        self.log.borrow_mut().push(format!(\"confirm {values:?}\"));\n    }\n}\n\nstruct Picker {\n    language: Entity<SelectState<Recording>>,\n}\n\nimpl Render for Picker {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .size_full()\n            .child(Select::new(&self.language).id(\"language\").w(px(240.)))\n    }\n}\n\nfn open_picker(\n    cx: &mut TestAppContext,\n    accept: bool,\n) -> (AnyWindowHandle, Entity<SelectState<Recording>>, Log) {\n    cx.update(gpui_kit::init);\n    let log = Rc::new(RefCell::new(Vec::new()));\n    let mut language = None;\n    let (handle, _view) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let delegate = Recording {\n                    items: vec![\"Rust\", \"Go\"],\n                    accept,\n                    log: log.clone(),\n                };\n                let state =\n                    cx.new(|cx| SelectState::new(delegate, Some(IndexPath::new(0)), window, cx));\n                language = Some(state.clone());\n                let view = cx.new(|_| Picker { language: state });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n    (handle.into(), language.unwrap(), log)\n}\n\nfn confirm_next(cx: &mut TestAppContext, handle: AnyWindowHandle) {\n    cx.update_window(handle, |_, window, cx| {\n        window.render_frame(cx);\n        window.within(\"language\").click(\"input\", cx);\n        window.press(\"down\", cx);\n        window.press(\"enter\", cx);\n    })\n    .unwrap();\n}\n\n#[gpui_kit::test]\nasync fn hooks_fire_in_order_with_the_final_selection(cx: &mut TestAppContext) {\n    let (handle, language, log) = open_picker(cx, true);\n    confirm_next(cx, handle);\n    cx.wait_for(handle, Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n    })\n    .await;\n    // Single selection proposes replacing the old item, then commits once.\n    assert_eq!(\n        *log.borrow(),\n        [\"deselect 0\", \"select 1\", r#\"confirm [\"Go\"]\"#]\n    );\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Go\")));\n}\n```\n\n### Pattern: A vetoing delegate keeps the selection\n\nThe same delegate with `accept: false` applies none of the proposed changes:\n\n```rust\n#[gpui_kit::test]\nasync fn a_vetoing_delegate_keeps_the_selection(cx: &mut TestAppContext) {\n    let (handle, language, log) = open_picker(cx, false);\n    confirm_next(cx, handle);\n    cx.wait_for(handle, Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n    })\n    .await;\n    // The same changes are proposed, but the delegate applied none of them:\n    // `on_confirm` still runs, with the selection the user started from.\n    assert_eq!(*log.borrow(), [\"deselect 0\", \"select 1\", r#\"confirm [\"Rust\"]\"#]);\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Rust\")));\n    cx.update_window(handle, |_, window, _| {\n        assert_eq!(window.find(\"language\").value(), Some(\"Rust\"));\n    })\n    .unwrap();\n}\n```\n\n### Checklist: What to test for each component that uses `defer_in`\n\n- [ ] `confirm` path: no panic, the value is committed, and `selected_value()` agrees with the trigger's `value()`\n- [ ] `cancel` path (Escape, click outside): no panic, selection unchanged, menu closed (`expanded() == Some(false)`)\n- [ ] `on_will_change` veto: selection unchanged; `on_confirm` still runs, with the unchanged selection\n- [ ] `on_will_change` editing the selection: the final selection reflects the delegate's edit\n- [ ] Repeated confirms: each one leaves `selected_value()` matching the displayed value\n- [ ] `render_item` never panics even when called immediately after a mutation\n\n## Property Testing\n\nUse random data to test edge cases:\n\n```rust\n#[gpui_kit::test(iterations = 10)]\nfn test_counter_random_operations(cx: &mut TestAppContext, mut rng: StdRng) {\n    let counter = cx.new(|cx| Counter::new(cx));\n\n    let mut expected = 0i32;\n    for _ in 0..100 {\n        let delta = rng.random_range(-10..=10);\n        expected += delta;\n\n        counter.update(cx, |counter, cx| {\n            counter.count += delta;\n            cx.notify();\n        });\n    }\n\n    let actual = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(actual, expected);\n}\n```\n\n## Distributed Systems Testing\n\nTest multiple app contexts communicating:\n\n```rust\n#[derive(Clone)]\nstruct NetworkMessage {\n    from: String,\n    to: String,\n    data: i32,\n}\n\n#[gpui_kit::test]\nfn test_distributed_apps(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {\n    // Create components in different app contexts\n    let comp_a = cx_a.new(|_| MyComponent::new(\"A\".to_string()));\n    let comp_b = cx_b.new(|_| MyComponent::new(\"B\".to_string()));\n\n    // Simulate message passing\n    comp_a.update(cx_a, |comp, cx| {\n        comp.send_message(\"B\", 42, cx);\n    });\n\n    // Run async operations\n    cx_a.run_until_parked();\n\n    // Verify message received in other context\n    comp_b.update(cx_b, |comp, _| {\n        comp.receive_messages();\n    });\n\n    let messages = comp_b.read_with(cx_b, |comp, _| comp.messages.clone());\n    assert_eq!(messages.len(), 1);\n    assert_eq!(messages[0].data, 42);\n}\n```\n\n### Interleaving Testing\n\nTest concurrent operations with random execution order:\n\n```rust\n#[gpui_kit::test(iterations = 10)]\nfn test_concurrent_operations(\n    cx_a: &mut TestAppContext,\n    cx_b: &mut TestAppContext,\n    mut rng: StdRng,\n) {\n    let comp_a = cx_a.new(|_| MyComponent::new());\n    let comp_b = cx_b.new(|_| MyComponent::new());\n\n    // Perform random operations across contexts\n    for i in 0..20 {\n        if rng.random_bool(0.5) {\n            comp_a.update(cx_a, |comp, cx| {\n                comp.perform_operation(i, cx);\n            });\n        } else {\n            comp_b.update(cx_b, |comp, cx| {\n                comp.perform_operation(i, cx);\n            });\n        }\n    }\n\n    // Run all pending operations\n    cx_a.run_until_parked();\n\n    // Verify final state\n    let state_a = comp_a.read_with(cx_a, |comp, _| comp.state);\n    let state_b = comp_b.read_with(cx_b, |comp, _| comp.state);\n\n    // Assert invariants hold despite execution order\n    assert!(state_a.is_consistent());\n    assert!(state_b.is_consistent());\n}\n```\n\n## Mocking and Isolation\n\n### Network Mocking\n\nCreate mock networks for testing distributed features:\n\n```rust\nstruct MockNetwork {\n    messages: Arc<Mutex<Vec<NetworkMessage>>>,\n}\n\nimpl MockNetwork {\n    fn new() -> Self {\n        Self {\n            messages: Arc::new(Mutex::new(Vec::new())),\n        }\n    }\n\n    fn send(&self, message: NetworkMessage) {\n        self.messages.lock().unwrap().push(message);\n    }\n\n    fn receive_all(&self) -> Vec<NetworkMessage> {\n        self.messages.lock().unwrap().drain(..).collect()\n    }\n}\n\n#[gpui_kit::test]\nfn test_networked_components(cx: &mut TestAppContext) {\n    let network = Arc::new(MockNetwork::new());\n\n    let sender = cx.new(|_| MessageSender::new(network.clone()));\n    let receiver = cx.new(|_| MessageReceiver::new(network));\n\n    // Send message\n    sender.update(cx, |sender, _| {\n        sender.send(\"Hello\");\n    });\n\n    // Receive message\n    receiver.update(cx, |receiver, _| {\n        receiver.receive_all();\n    });\n\n    let received = receiver.read_with(cx, |receiver, _| receiver.messages.clone());\n    assert_eq!(received, vec![\"Hello\"]);\n}\n```","skills/gpui-kit/references/gpui/test.md":"# Testing\n\n**Contents:** [Choose the test level](#choose-the-test-level) · [UI integration workflow](#ui-integration-workflow) · [Complete example](#complete-example) · [Queries and interactions](#queries-and-interactions) · [Frames and async work](#frames-and-async-work) · [Assertion boundaries](#assertion-boundaries) · [Additional resources](#additional-resources)\n\n## UI integration testing\n\nA UI integration test renders real components in a headless window, dispatches\nclicks, keyboard input and scrolling, then checks state, focus, layout and owner\ncallbacks. For example: add a Checkbox UI integration test that proves clicking\ntoggles the owner's value and disabled controls reject the interaction.\nUse this term when describing component interaction coverage.\n`#[gpui_kit::test]` runs the test; `gpui_kit::test` operates and inspects its UI.\n\n## Choose the test level\n\nUse ordinary Rust `#[test]` for pure logic. Use `#[gpui_kit::test]` and\n`TestAppContext` for entities, subscriptions, actions and async tasks; it can\ncreate headless windows too. `VisualTestContext` is available for existing GPUI\nwindow helpers. For an application UI flow, use `gpui_kit::test::TestWindowExt`\non the real `Window` and assert the behavior produced by native events.\n\nImport the Kit types you use explicitly and write `#[gpui_kit::test]`. Avoid `use gpui_kit::*;` in test modules: it imports GPUI’s `test` macro and can shadow Rust’s built-in `#[test]`. Add\n`test-support` to the application's `gpui-kit` development dependency, using\nexactly the same source and version as its normal dependency. The helpers\nrequire a Kit revision that includes them; check the installed API before\nassuming an older published release supports them. No extra testing crate or\nGPUI patch is required.\n\nFor a standalone test package beside a Kit checkout:\n\n```toml\n[package]\nname = \"ui-tests\"\nversion = \"0.1.0\"\nedition = \"2024\"\npublish = false\n\n[dev-dependencies]\ngpui-kit = { path = \"../gpui-kit/crates/kit\", features = [\"test-support\"] }\n```\n\nHeadless tests still need the platform's native build dependencies. Run\n`cargo generate-lockfile` once for the new package, then\n`cargo test --test ui --locked`. In the Kit repository the equivalent command\nis `cargo test -p gpui-kit --features test-support --test ui --locked`.\n\n## UI integration workflow\n\n1. Import the production view and constructor from the application library.\n   Keep state entities and subscriptions owned by that view. Define a view\n   inside a test only for a self-contained example or a deliberate fixture.\n2. Initialize with `cx.update(gpui_kit::init)`, open a headless window of an\n   explicit size through `gpui_kit::open_window`. Its Base `Root` renders\n   the dialog, sheet and notification layers above the view automatically.\n   Do not mount overlay layers in the application view.\n3. Render a frame and locate existing control IDs. Custom native elements opt\n   in with `.id(\"status\").test_support()` through `TestSupportExt`. Place it\n   before `.track_focus(&handle)`; custom wrappers must forward that method\n   to their inner element. Registration adds no layout container.\n4. Dispatch clicks, input and named keys through `TestWindowExt`. Exercise the\n   actual handler path; invoking callbacks or directly setting control state\n   would bypass the behavior being tested.\n5. Assert the initial state, the visible outcome after each meaningful action,\n   and the application result. Include a relevant negative case, such as a\n   disabled control rejecting the interaction or invalid input preventing save.\n6. Run the affected test target and report its result. An uncompiled example or\n   a test which never checks the action's outcome is not completion evidence.\n\n## Complete example\n\nCopy this into `tests/ui.rs`. It follows the Kit integration-test example\nfrom `crates/kit/tests/ui.rs`, with window setup inlined so this reference works\nwithout a repository checkout. In an application, replace that view definition\nwith an import of your production view.\n\n```rust\nuse gpui_kit::test::{TestSupportExt, TestWindowExt};\nuse gpui_kit::{\n    AppContext, Bounds, Context, Entity, SharedString, TestAppContext, Window, WindowBounds,\n    WindowOptions,\n    component::{\n        button::Button,\n        input::{Input, InputState},\n    },\n    div,\n    prelude::*,\n    px, size,\n};\n\nstruct Profile {\n    name: Entity<InputState>,\n    submitted: Option<SharedString>,\n}\n\nimpl Render for Profile {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let status = self.submitted.as_ref().map_or_else(\n            || SharedString::from(\"Not saved\"),\n            |name| SharedString::from(format!(\"Saved: {name}\")),\n        );\n        div()\n            .size_full()\n            .flex()\n            .flex_col()\n            .p_4()\n            .gap_4()\n            .child(Input::new(&self.name).id(\"name\").w(px(240.)))\n            .child(\n                Button::new(\"save\")\n                    .label(\"Save\")\n                    .on_click(cx.listener(|this, _, _, cx| {\n                        this.submitted = Some(this.name.read(cx).value());\n                        cx.notify();\n                    })),\n            )\n            .child(\n                div()\n                    .id(\"status\")\n                    .role(gpui_kit::Role::Status)\n                    .test_support()\n                    .aria_label(status.clone())\n                    .child(status),\n            )\n    }\n}\n\n#[gpui_kit::test]\nfn saves_a_profile_through_the_ui(cx: &mut TestAppContext) {\n    cx.update(gpui_kit::init);\n    let (handle, profile) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let view = cx.new(|cx| Profile {\n                    name: cx.new(|cx| InputState::new(window, cx)),\n                    submitted: None,\n                });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n\n    cx.update_window(handle.into(), |_, window, cx| {\n        window.render_frame(cx);\n        assert_eq!(window.find(\"status\").label(), Some(\"Not saved\"));\n\n        window.click(\"name\", cx);\n        window.input(\"Ada 中文\", cx);\n        let name = window.find(\"name\");\n        assert_eq!(name.focused(), Some(true));\n        assert_eq!(name.value(), Some(\"Ada 中文\"));\n        assert!(name.bounds().size.width > px(0.));\n        // Named keys share the same Window API and refresh the resulting frame.\n        window.press(\"backspace\", cx);\n        assert_eq!(window.find(\"name\").value(), Some(\"Ada 中\"));\n\n        window.click(\"save\", cx);\n        let status = window.find(\"status\");\n        assert!(status.visible());\n        assert_eq!(status.label(), Some(\"Saved: Ada 中\"));\n        assert!(status.bounds().top() >= window.find(\"save\").bounds().bottom());\n    })\n    .unwrap();\n\n    // Verify the application result as well as the native properties.\n    cx.update(|cx| {\n        assert_eq!(profile.read(cx).submitted.as_deref(), Some(\"Ada 中\"));\n    });\n}\n```\n\n## Queries and interactions\n\nImport `TestWindowExt` for queries and interactions from `gpui_kit::test`.\nFor custom registration, import `TestSupportExt`. Use normal Rust assertions with snapshots.\n\n| API | Behavior |\n| --- | --- |\n| `window.find(id)` | Requires a unique observed target; errors list registered paths. |\n| `window.try_find(id)` | Returns `None` when absent; ambiguous IDs still panic. |\n| `window.find_all(id)` | Returns all registered matches, including invisible ones, by current-frame bounds origin (y, then x); equal-origin order is unspecified. Empty when absent. |\n| `window.within(id)` | Resolves a native GPUI identity scope, including an unobserved ancestor. |\n| `click`, `right_click`, `double_click`, `hover` | Dispatch real pointer events at the target center. |\n| `click_at(id, offset, cx)` | Uses an offset from the target bounds' top-left corner. |\n| `window.click_with_modifiers(id, modifiers, cx)` | Centered left click with modifiers; sends modifier changes and restores the previous modifier state afterward. |\n| `window.click_with_options(id, options, cx)` | Combines offset, button, count, and modifiers using `ClickOptions`; restores the previous modifier state afterward. |\n| `scroll(id, delta, cx)` | Dispatches a GPUI `ScrollDelta` wheel event. |\n| `drag_to(from_id, to_id, cx)` | Drags between target centers within the current scope. |\n| `window.drag(from, to, cx)` | Drags between window-local points; use `bounds()` for precise or cross-scope geometry. |\n| `press(key, cx)` | Sends named GPUI keys such as `backspace`, `escape` or `secondary-a`. |\n| `input(text, cx)` | Types Unicode characters at current focus; click the input first. |\n\n`ClickOptions::new()` defaults to one left click at the center without modifiers.\nFor example, `ClickOptions::new().with_offset(point(px(8.), px(8.)))\n.with_button(MouseButton::Right).with_count(2).with_modifiers(Modifiers::shift())`\ncombines a local offset, right double-click, and Shift. Counts must be positive.\nConfigurable clicks preserve caps lock. `find_all` ordering is geometry for the\ncurrent frame, not stable identity, paint order, or business order; filter with\n`visible()` when counting visible matches.\n\nGPUI IDs need only be unique within their native scope. Use\n`window.within(\"dialog\").find(\"name\")` for repeated local IDs. Scoped windows\nalso provide pointer operations, `press` and `input`; keyboard helpers require\nobserved focus inside that scope and recheck it between characters. They do\nnot focus the target or replace its value. For a submenu with another\n`\"popup-menu\"` ID, retain the resolved outer scope before opening the submenu,\nthen query its descendants.\n\n## Inspect accessibility targets and individual events\n\nImport `gpui_kit::test::{TestQueryExt, TestEventExt}` for additional observation\nand event control. `elements()` returns observed elements in the current frame;\n`find_by_label(label)`, `try_find_by_label(label)` and `find_all_by_label(label)`\nmatch exact, case-sensitive native accessibility labels. `find_all_by_role(role)` selects an\nAccessKit `Role`. Results include invisible registrations, ordered by y, then x\nand a path tie-breaker. Required queries panic on absence; all unique queries\npanic on ambiguity. Scoped queries include strict descendants, excluding the\nscope node itself. These queries also work inside `within` and do not discover\nunobserved text or offscreen virtual rows. A label is an accessibility name,\nnot rendered text; use stable IDs when localization changes the name.\nThe pinned GPUI version does not expose an enumeration of anonymous rendered\ntext. Kit therefore has no general rendered-text `HasText` assertion; exact\naccessible-label queries cannot establish that text was actually drawn.\n\nFor gestures whose intermediate state matters, dispatch each step explicitly:\n\n```rust\nuse gpui_kit::test::TestEventExt;\n\nlet start = window.find(\"handle\").bounds().center();\nwindow.pointer_down(start, MouseButton::Left, cx);\nwindow.pointer_move(start + point(px(24.), px(0.)), Some(MouseButton::Left), cx);\n// Assert the state while the pointer is still held.\nwindow.pointer_up(start + point(px(24.), px(0.)), MouseButton::Left, cx);\n```\n\nPositions use window-local pixels. `pointer_move(position, pressed_button, cx)`\nreceives the held button explicitly; these helpers do not remember button state.\n`pointer_down` and `pointer_up` dispatch one click event each. Ordinary click, hover, scroll, drag and individual pointer steps use\nthe window's current modifiers. Configurable clicks temporarily use their\nexplicit modifiers and restore the preceding state afterward. `change_modifiers(modifiers, cx)` changes them and\npreserves caps lock; restore the previous modifiers when the gesture ends.\n`key_down(key, is_held, cx)` and `key_up(key, cx)` allow separate key transitions\nand auto-repeat (`is_held = true`). Key events combine modifiers written in the\nkey string with the window's held modifiers, without changing the retained\nmodifier state. Each step refreshes before dispatch and\ncompletes a frame afterward. These key events do not insert text; use `input`\nfor typing. Leave the window update and wait for deferred results when needed.\n\n## Exercise text composition through an input handler\n\n`gpui_kit::test::TestInput` bridges an explicit GPUI `InputHandler` to a window.\nFor an entity implementing `EntityInputHandler`, construct the adapter with\n`gpui_kit::ElementInputHandler::new(bounds, entity.clone())`, then pass it to\n`TestInput::new(handler, window)`. Keep the entity owned by the\nproduction view and use its actual input geometry. This bridge calls that\nhandler directly; it does not select the focused control or run an OS IME.\n\n`commit_text(text, cx)` commits through `replace_text_in_range`.\n`compose_text(replacement, text, selection, cx)` updates marked text through\n`replace_and_mark_text_in_range`. Replacement and selection ranges use UTF-16\ncode units, not UTF-8 byte offsets; selection is relative to the composed text.\nWith no replacement range, the handler replaces its current marked range or\nselection. Empty composition text cancels preedit according to the handler.\n`marked_text_range(cx)` returns a document-relative range;\n`selected_text_range(cx)` returns `Option<UTF16Selection>`, including direction;\n`unmark_text(cx)` ends marking while retaining its text. Mutation helpers complete a frame after the\nhandler call. They can test composition transitions and commit behavior, while\nplatform candidate windows, focus routing and OS IME integration still need\nnative tests. Use `window.input` for ordinary text typed at the current focus.\n\n## Resize, display scale and clipboard\n\nUse GPUI's existing `TestAppContext::simulate_window_resize(handle, size)` and\n`simulate_window_scale_factor_change(handle, scale)` outside a window update,\nthen call `render_frame` before inspecting layout. Pointer positions remain\nwindow-local logical pixels at every display scale. Assert both preserved\nediting state and resized geometry, then activate a control at its new bounds.\n\nExercise clipboard behavior through production shortcuts (`secondary-c`,\n`secondary-x`, `secondary-v`) and inspect `cx.read_from_clipboard()` when needed.\nThe test platform shares its clipboard across windows; editor state should\nremain window-specific. This verifies the test-platform adapter and application\nbindings, not the operating system's clipboard service.\n\nAfter activating an external Link, inspect `cx.opened_url()` to verify the URL\nreceived by the test platform and assert the application's click callback.\nThis does not establish that a browser opened the destination. The test\nplatform exposes no cursor-style reader; URL and callback assertions do not\nverify the pointer cursor.\n\n## Frames and async work\n\nSnapshots are owned facts from the last completed frame, not live elements.\nFetch a new snapshot after an interaction. Interaction helpers refresh frames;\nafter an external entity update, focus change or resize, call\n`window.render_frame(cx)` before querying.\n\nFor deferred actions, subscriptions or popup updates, leave `update_window`\nso GPUI can process its effects. Use `cx.run_until_parked()` for queued work,\nor import `TestAppContextExt` and await a bounded condition:\n\n```rust\ncx.wait_for(handle.into(), std::time::Duration::from_secs(1), |window, _| {\n    window.try_find(\"dialog\").is_none()\n}).await;\n```\n\n`wait_for` runs outside a borrowed window update and uses GPUI test time.\nProcess a queued action before changing any input that the action is meant to\nvalidate. Otherwise it can read the later input instead of the value at the\nintended test step.\n\nFor timers, check the UI before its deadline as well as after expiration.\nGPUI's non-synced `Animation` uses wall-clock time; advancing the test clock\ndoes not complete it. Use reduced motion when supported, or a bounded wait\nappropriate to that production animation before asserting final geometry.\n\n## Assertion boundaries\n\n- `checked()`, `selected()`, `expanded()`, `value()` and `label()` come from\n  native accessibility properties. `None` means unavailable; masked input\n  deliberately omits its value. Do not supply a second set of test-only state.\n- `disabled()` currently reports `Some(true)` or `None`. To prove a control is\n  enabled, perform the interaction and assert the result. Absence of a flag\n  is not proof that the control accepts input.\n- `focused()` measures the observed native focus scope. Missing bindings are\n  diagnosed when the native element advertises `Action::Focus`; controls\n  without that action can still return `None`. Register the real binding.\n- `bounds()` supports containment, relative position, overlap, scrolling and\n  drag assertions. `visible()` checks geometry, clipping and observed style;\n  it does not prove a target is unobstructed. Real hit testing decides whether\n  a click reaches the control.\n- Native properties can be wrong too. Pair them with real interactions,\n  geometry and the application result. A label is not rendered text, and a\n  correct accessibility value does not establish correct pixels.\n- These tests run in-process. Pixel comparisons need GPUI's separate renderer;\n  packaged-app behavior and full OS IME composition need other coverage. Kit's\n  explicit macOS (Metal) and Linux (WGPU) rendering target is\n  `cargo test -p gpui-kit --features test-support --test rendering --locked`.\n  Linux requires a working WGPU adapter and can use Mesa lavapipe. Windows\n  explicitly skips this target because GPUI 0.3.8 has no Windows headless renderer.\n  Missing renderer support on macOS or Linux fails instead of producing fake images.\n\n## Additional resources\n\n- [Website testing guide](https://gpui-kit.com/docs/test) — bilingual setup,\n  component coverage, platform requirements and CI.\n- [GPUI test examples](test-examples.md) — entity and context patterns.\n- [GPUI test reference](test-reference.md) — re-entrancy and property tests.\n","skills/gpui-kit/references/recipes.md":"# Tested application recipe\n\nThis complete view comes from `examples/ai_recipes/src/settings.rs`. That consumer crate depends only on `gpui-kit`; the same source is compiled and tested by `cargo test -p gpui-kit-recipes`, and `script/check-ai-recipes` keeps this copy identical to it. Pair it with that example's `src/bootstrap.rs`, which installs assets, initializes the library, and wraps the window in `Root`.\n\nThe view owns both input state and subscriptions. Rendering creates only elements. The window's `Root` renders the dialog, sheet and notification layers above the view.\n\n<!-- recipe:settings:start -->\n```rust\nuse gpui_kit::component::{\n    ActiveTheme, IconName, WindowExt,\n    button::Button,\n    checkbox::Checkbox,\n    form::{Field, Form},\n    input::{Input, InputEvent, InputState},\n    radio::RadioGroup,\n    switch::Switch,\n};\nuse gpui_kit::{\n    AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render, SharedString,\n    Styled as _, Subscription, Window, div,\n};\n\npub struct Settings {\n    name: Entity<InputState>,\n    preview: SharedString,\n    changes: usize,\n    enabled: bool,\n    remember: bool,\n    delivery: Option<usize>,\n    _subscriptions: Vec<Subscription>,\n}\n\nimpl Settings {\n    pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let name = cx.new(|cx| InputState::new(window, cx).placeholder(\"Name\"));\n        let subscription = cx.subscribe_in(&name, window, |this, state, event, _, cx| {\n            if matches!(event, InputEvent::Change) {\n                this.preview = state.read(cx).value().to_string().into();\n                this.changes += 1;\n                cx.notify();\n            }\n        });\n        Self {\n            name,\n            preview: \"\".into(),\n            changes: 0,\n            enabled: false,\n            remember: false,\n            delivery: Some(0),\n            _subscriptions: vec![subscription],\n        }\n    }\n\n    pub fn input(&self) -> Entity<InputState> {\n        self.name.clone()\n    }\n\n    pub fn preview(&self) -> &SharedString {\n        &self.preview\n    }\n\n    pub fn changes(&self) -> usize {\n        self.changes\n    }\n}\n\nimpl Render for Settings {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .flex()\n            .flex_col()\n            .size_full()\n            .p_4()\n            .gap_3()\n            .bg(cx.theme().background)\n            .text_color(cx.theme().foreground)\n            .child(\"Profile\")\n            .child(\n                Form::new()\n                    .child(Field::new().label(\"Name\").child(Input::new(&self.name)))\n                    .child(Field::new().label(\"Preview\").child(self.preview.clone()))\n                    .child(\n                        Field::new().label_indent(false).child(\n                            Checkbox::new(\"remember\")\n                                .label(\"Remember name\")\n                                .checked(self.remember)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.remember = *value;\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .child(\n                        Field::new().label_indent(false).child(\n                            Switch::new(\"enabled\")\n                                .label(\"Enable notifications\")\n                                .checked(self.enabled)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.enabled = *value;\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .child(\n                        Field::new().label(\"Delivery\").child(\n                            RadioGroup::new(\"delivery\")\n                                .children([\"Immediately\", \"Daily summary\"])\n                                .selected_index(self.delivery)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.delivery = Some(*value);\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .footer(\n                        Button::new(\"about\")\n                            .label(\"About…\")\n                            .icon(IconName::Info)\n                            .on_click(|_, window, cx| {\n                                window.open_dialog(cx, |dialog, _, _| {\n                                    dialog.title(\"About\").child(\"A complete GPUI Kit window\")\n                                });\n                            }),\n                    ),\n            )\n    }\n}\n```\n<!-- recipe:settings:end -->\n\nFor changes in this repository, run `script/check-ai docs`, `script/check-ai rust`, or `script/check-ai shell` for the relevant verification profile (or `script/check-ai all` for all three), and `cargo test -p gpui-kit-recipes` when a recipe source changes. For a downstream app, compile and test your own consumer, then verify keyboard/focus and visuals in a real window. Automated recipe tests do not establish a model success rate.\n","skills/gpui-kit/references/usage.md":"# gpui-kit Usage Guide\n\n**Contents:** [Setup](#setup) · [Component Types](#component-types) · [Common Components](#common-components) (Button, Input, Select, Checkbox, Icon, Dialog, Notification, Tabs, Tooltip, Form, List) · [Theming](#theming) · [Layout Helpers](#layout-helpers) · [Overlay Layers](#overlay-layers-dialogs-sheets-notifications) · [Shared Traits](#shared-traits)\n\n## Setup\n\nUse the [tested application recipe](recipes.md) for complete examples and their verification command. Store subscription handles on the owning view; binding one to a constructor-local variable alone does not keep it alive after construction.\n\n### 1. Cargo.toml\n\n```toml\n[dependencies]\ngpui-kit = \"0.7\" # re-exports GPUI, platform, base, component and the default icons; Shell is a separate host dependency\n```\n\n### 2. Initialization\n\n```rust\nfn main() {\n    gpui_kit::application()\n        .with_assets(gpui_kit::assets::Assets)\n        .run(move |cx| {\n            gpui_kit::init(cx); // MUST be first\n\n            // Wraps the view in a `Root`, which enables dialogs, sheets,\n            // notifications, tooltips and menus in this window.\n            gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| cx.new(|_| MyApp))\n                .expect(\"Failed to open window\");\n        });\n}\n```\n\nUse `gpui_kit::open_window` for application windows; it mounts `Root` as the window's root view.\n\n---\n\n## Component Types\n\n### Stateless (most components)\n\nUsed directly in `render`, no stored state:\n\n```rust\nuse gpui_kit::component::button::Button;\n\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        Button::new(\"btn\").primary().label(\"Submit\")\n            .on_click(|_, _, _| println!(\"clicked\"))\n    }\n}\n```\n\n### Stateful (Input, Select, Combobox, etc.)\n\nRequire an `Entity<State>` stored in your view:\n\n```rust\nuse gpui_kit::component::input::{Input, InputState};\n\nstruct MyView {\n    name: Entity<InputState>,\n}\n\nimpl MyView {\n    fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        Self {\n            name: cx.new(|cx| InputState::new(window, cx).placeholder(\"Your name\")),\n        }\n    }\n}\n\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        Input::new(&self.name)\n    }\n}\n```\n\n---\n\n## Common Components\n\n### Button\n\n```rust\nuse gpui_kit::component::button::{Button, ButtonGroup};\n\n// Variants\nButton::new(\"btn\").label(\"Default\")\nButton::new(\"btn\").primary().label(\"Primary\")\nButton::new(\"btn\").danger().label(\"Delete\")\nButton::new(\"btn\").warning().label(\"Warning\")\nButton::new(\"btn\").success().label(\"Success\")\nButton::new(\"btn\").ghost().label(\"Ghost\")\nButton::new(\"btn\").link().label(\"Link\")\n\n// States\nButton::new(\"btn\").label(\"Text\").disabled(true)\nButton::new(\"btn\").label(\"Text\").loading(true)\nButton::new(\"btn\").label(\"Text\").selected(true)\n\n// With icon\nButton::new(\"btn\").icon(IconName::Plus).label(\"Add\")\n\n// Sizes\nButton::new(\"btn\").xsmall().label(\"XS\")\nButton::new(\"btn\").small().label(\"S\")\nButton::new(\"btn\").large().label(\"L\")\n\n// Group\nButtonGroup::new(\"group\")\n    .child(Button::new(\"a\").label(\"A\"))\n    .child(Button::new(\"b\").label(\"B\"))\n    .on_click(|indices, _, _| { /* selected indices */ })\n```\n\n### Input\n\n```rust\nuse gpui_kit::component::input::{Input, InputState};\n\n// State setup (in new/init)\nlet input = cx.new(|cx| InputState::new(window, cx)\n    .placeholder(\"Enter text...\")\n    .default_value(\"Hello\")\n);\n\n// Render\nInput::new(&input)\nInput::new(&input).cleanable(true)           // clear button\nInput::new(&input).disabled(true)\nInput::new(&input).prefix(Icon::new(IconName::Search).small())\nInput::new(&input).suffix(Button::new(\"b\").ghost().icon(IconName::X).xsmall())\nInput::new(&input).content_type(InputContentType::Password)\nInput::new(&input).mask_toggle()             // password reveal toggle\nInput::new(&input).appearance(false)         // remove default border/bg\n\n// Reading value\nlet value = input.read(cx).value();\n\n// Keep this subscription in the owning view (for example, `_subscriptions`).\nself._subscriptions.push(cx.subscribe_in(&input, window, |view, state, event, window, cx| {\n    match event {\n        InputEvent::Change => { let v = state.read(cx).value(); }\n        InputEvent::PressEnter { .. } => { /* submit */ }\n        InputEvent::Focus | InputEvent::Blur => {}\n    }\n}));\n```\n\n### Select\n\n```rust\nuse gpui_kit::component::select::{Select, SelectState};\n\n// Simple string list\nlet state = cx.new(|cx| {\n    SelectState::new(vec![\"Apple\", \"Orange\", \"Banana\"], Some(IndexPath::default()), window, cx)\n});\n\n// Render\nSelect::new(&state)\nSelect::new(&state).placeholder(\"Pick one\")\n\n// Reading selection\nlet selected = state.read(cx).selected_item();\n```\n\n### Checkbox / Switch / Radio\n\n```rust\nuse gpui_kit::component::{checkbox::Checkbox, switch::Switch};\n\n// Stateless (controlled)\nCheckbox::new(\"cb\").checked(self.checked)\n    .on_change(cx.listener(|this, checked, _, cx| {\n        this.checked = *checked;\n        cx.notify();\n    }))\n\nSwitch::new(\"sw\").checked(self.enabled)\n    .on_change(cx.listener(|this, checked, _, cx| {\n        this.enabled = *checked;\n        cx.notify();\n    }))\n```\n\n### Icon\n\n```rust\nuse gpui_kit::component::{Icon, IconName};\n\nIcon::new(IconName::Check)\nIcon::new(IconName::Search).small()\nIcon::new(IconName::Plus).large().text_color(cx.theme().primary)\n```\n\n### Dialog\n\n```rust\nuse gpui_kit::component::dialog::{Dialog, DialogAction, DialogClose, DialogFooter};\n\n// Open from window context. `footer` takes an element, not a closure.\n// DialogClose dismisses the dialog, so no manual close call is needed.\nwindow.open_dialog(cx, |dialog, _, _| {\n    dialog\n        .title(\"Export Report\")\n        .child(\"Choose a destination for the exported file.\")\n        .footer(\n            DialogFooter::new()\n                .gap_2()\n                .child(DialogClose::new().child(\n                    Button::new(\"cancel\").label(\"Cancel\").outline(),\n                ))\n                .child(DialogAction::new().child(\n                    Button::new(\"export\").label(\"Export\").primary(),\n                )),\n        )\n});\n```\n\n### AlertDialog\n\nUse `AlertDialog` — not `Dialog` — to confirm a consequential action. It is not\noverlay-closable and has no close button, so the choice must be made. Name the\nobject in the title and the result on the confirming button; see the Design\nGuides for the copy rules.\n\n```rust\nuse gpui_kit::component::button::ButtonVariant;\n\nwindow.open_alert_dialog(cx, |alert, _, _| {\n    alert\n        .title(\"Remove “Roadmap”?\")\n        .description(\"Files on disk aren’t deleted.\")\n        .confirm()\n        .ok_text(\"Remove\")\n        .ok_variant(ButtonVariant::Danger)\n        .on_ok(|_, _, _| true)\n});\n```\n\n`button_props(DialogButtonProps)` takes the same properties as one value; it\noverrides only the fields that value sets, so `confirm` and earlier callbacks\nsurvive it.\n\n### Notification\n\n```rust\n// Simple string message\nwindow.push_notification(\"Saved successfully!\", cx);\n\n// With type variant\nwindow.push_notification(\n    Notification::new(\"Upload complete\").info().message(\"File uploaded\"),\n    cx,\n);\n```\n\n### Tabs\n\n```rust\nuse gpui_kit::component::tab::{Tab, TabBar};\n\nTabBar::new(\"tabs\")\n    .child(Tab::new(\"tab1\").child(\"Overview\"))\n    .child(Tab::new(\"tab2\").child(\"Settings\"))\n    .child(Tab::new(\"tab3\").child(\"Logs\"))\n```\n\n### Tooltip\n\n```rust\n// On any element with .id(), add .tooltip():\ndiv()\n    .id(\"my-btn\")\n    .tooltip(|window, cx| Tooltip::new(\"Delete item\").build(window, cx))\n    .child(\"Delete\")\n\n// Or on a Button directly:\nButton::new(\"btn\").icon(IconName::Trash).tooltip(\"Delete\")\n\n// Component tooltips open after 500 ms; override per trigger,\n// or install `tooltip::TooltipDefaults` to change it app-wide:\nButton::new(\"help\").icon(IconName::Info).tooltip(\"Help\")\n    .tooltip_show_delay(Duration::ZERO)\n```\n\n### Form\n\n```rust\nuse gpui_kit::component::form::{v_form, h_form, field};\n\n// Vertical form\nv_form()\n    .child(field().label(\"Name\").child(Input::new(&self.name)))\n    .child(field().label(\"Email\").child(Input::new(&self.email)))\n    .footer(Button::new(\"submit\").primary().label(\"Submit\"))\n\n// Horizontal label alignment\nh_form()\n    .child(field().label(\"Username\").child(Input::new(&self.username)))\n```\n\n### List (searchable, virtualized)\n\n```rust\nuse gpui_kit::component::list::{List, ListState, ListDelegate, ListItem, ListEvent};\n\n// Implement ListDelegate for your data type, then:\nlet list_state = cx.new(|cx| ListState::new(MyDelegate::new(), window, cx));\n\n// Render\nList::new(&list_state)\n// Keep this subscription in the owning view, alongside list_state.\nself._subscriptions.push(cx.subscribe(&list_state, |this, _, event, cx| {\n    if let ListEvent::Select(index_path) = event {\n        // handle selection\n    }\n}));\n```\n\n---\n\n## Theming\n\n```rust\nuse gpui_kit::component::ActiveTheme as _;\n\n// Access colors\ncx.theme().primary\ncx.theme().background\ncx.theme().foreground\ncx.theme().border\ncx.theme().surface\ncx.theme().muted\ncx.theme().destructive\n\n// Use in styles\ndiv()\n    .bg(cx.theme().surface)\n    .text_color(cx.theme().foreground)\n    .border_color(cx.theme().border)\n```\n\n### Switch Theme\n\n```rust\nuse gpui_kit::component::{Theme, ThemeMode};\n\n// Switch light/dark: loads that mode's registered theme\nTheme::change(ThemeMode::Dark, None, cx);\n// or, as one edit among others\nTheme::update(cx, |theme| theme.mode = ThemeMode::Dark);\n\n// Load a named theme\nTheme::update(cx, |theme| theme.apply_config(&theme_config));\n\n// Edit fields; `update` keeps colors, tokens and the Base projection in step\nTheme::update(cx, |theme| theme.radius = px(8.));\n```\n\n---\n\n## Layout Helpers\n\n`gpui_kit::component` extends GPUI with convenient layout methods:\n\n```rust\nh_flex()    // div().flex().flex_row().items_center()\nv_flex()    // div().flex().flex_col()\n\n// Common patterns\nh_flex().gap_2().items_center()\n    .child(Icon::new(IconName::User))\n    .child(label(\"Username\"))\n\nv_flex().gap_4().p_4()\n    .child(Input::new(&self.name))\n    .child(Input::new(&self.email))\n    .child(Button::new(\"submit\").primary().label(\"Submit\"))\n```\n\n---\n\n## Overlay Layers (Dialogs, Sheets, Notifications)\n\nThe window's `Root` renders dialogs, sheets and notifications above the view, so a window opened with `gpui_kit::open_window` needs nothing else — `window.open_dialog(..)` just works. Applications define their own quit and close-window actions, key bindings, and confirmation flows. `open_window` returns `(AnyWindowHandle, Entity<V>)`. The complete tested consumer recipe is [`examples/ai_recipes/src/bootstrap.rs`](../../../examples/ai_recipes/src/bootstrap.rs).\n\nRoot always mounts all three layers. The former `Root::render_*_layer` methods have been removed; delete their calls from application views when migrating to 0.7.0.\n\n---\n\n## Shared Traits\n\nBuilders return the component so methods can be chained. Constructors follow component families: controls take a stable ID, retained controls take state, and compound parts may take no arguments. See [component conventions](conventions.md).\n\n- `Sizable`: `.xsmall()` / `.small()` / `.medium()` (default) / `.large()`\n- `Disableable`: `.disabled(bool)`\n- `Selectable`: `.selected(bool)`\n- `Styled`: any GPUI style methods (`.w()`, `.bg()`, `.p_2()`, etc.)\n\nFor any component not covered here, fetch its doc from:\n`https://gpui-kit.com/component/{name}.md`\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AGENTS.md\n\nThis file provides shared guidance for coding agents working in this repository.\nKeep project rules here; `CLAUDE.md` imports this file for Claude Code.\n\n## Canonical Design and Coding Guides\n\nBefore changing UI, interaction, interface language, layout, styling,\ncomponents, or application architecture, read and follow the repository's\ncanonical guides:\n\n- [Design Guides](website/docs/design-guides.md)\n- [Coding Guides](website/docs/coding-guides.md)\n\nThese guides are requirements, not optional inspiration. Do not copy generic\nweb conventions, infer a design system from one existing screen, or add a\ncontrol merely because the underlying feature exists. Preserve the documented\ntask hierarchy, interaction promise, desktop conventions, spacing, alignment,\ntheme tokens, component boundaries, naming, and crate architecture. Review the\nfinished work against both guides before considering it complete.\n\nFor Chinese documentation and UI, apply the terminology rules in Design Guides.\nKeep established framework, component, and API names in their canonical English\nform when translation would reduce precision; write the surrounding Chinese as\nnatural Chinese rather than word-for-word translation.\n\n## Project Overview\n\nGPUI Kit is a Rust desktop application framework built on GPUI, published at <https://gpui-kit.com>. It ships as three crates: `gpui-base` (unstyled behavior and infrastructure), `gpui-shell` (JavaScript extensions for a Rust host), and `gpui-component` (GPUI Component, the styled component library with 60+ cross-platform desktop UI components, inspired by macOS/Windows controls and combined with shadcn/ui design). Applications depend on the umbrella crate `gpui-kit` (`crates/kit`), which pins the matching `gpui-pre-*` snapshot of GPUI and puts GPUI at its root (`use gpui_kit::*;`) with `gpui_kit::platform`, `gpui_kit::base`, `gpui_kit::component` and `gpui_kit::assets` reachable by name, so they never list GPUI itself. `gpui-shell` is not part of `gpui-kit` and is not published yet (its `llrt_*` dependencies are git-only); use it as a git dependency.\n\nThis is a Rust workspace project with the following main crates:\n\n- `crates/kit` - Umbrella crate applications depend on (published as `gpui-kit`)\n- `crates/component` - Core UI component library (published as `gpui-component`)\n- `crates/story` - Gallery application for showcasing and testing components\n- `crates/story-web` - Web version of the story gallery (using WebAssembly)\n- `crates/component-macros` - Procedural macros (`IntoPlot` derive)\n- `crates/assets` - Static assets\n- `crates/webview` - WebView component support\n- `examples/` - Various example applications\n\n## Common Commands\n\n### Development and Testing\n\n```bash\n# Run Story Gallery (component showcase application)\ncargo run\n\n# Run individual examples\ncargo run --example hello_world\ncargo run --example table\n\n# Build the project\ncargo build\n\n# Lint check\ncargo clippy -- --deny warnings\n\n# Format check\ncargo fmt --check\n\n# Spell check\ntypos\n\n# Check for unused dependencies\ncargo machete\n```\n\n### Testing\n\n**Note**: Per user configuration, tests do not need to be run.\n\nFor pure UI visual or sizing adjustments, do not add automated tests solely to\nassert presentation dimensions. Add tests when the change affects behavior,\ninteraction, data flow, or prevents a meaningful regression.\n\n```bash\n# Run all tests\ncargo test --all\n\n# Run tests for a specific crate\ncargo test -p gpui-component\n\n# Run doc tests\ncargo test -p gpui-component --doc\n```\n\n### Performance Profiling\n\n```bash\n# View FPS on macOS (using Metal HUD)\nMTL_HUD_ENABLED=1 cargo run\n\n# Profile performance using samply\nsamply record cargo run\n```\n\n## Core Architecture\n\n### Architecture Refactoring Constraints\n\nThe implemented foundation architecture is documented in\n`docs/ARCHITECTURE.md`, with styling and motion rules in\n`docs/STYLING-AND-MOTION.md`. Preserve these constraints when designing or\nimplementing this architecture:\n\n- Do not modify `gpui-base` unless the user explicitly requests a Base-layer\n  change. By default, implement component behavior and visual styling in\n  `crates/component` or the application layer.\n\n- Keep GPUI Kit as the ecosystem and product brand; `gpui-component` is its\n  styled component layer, alongside `gpui-base` and `gpui-shell`.\n- Name the foundation crate `gpui-base`.\n- Follow the ownership boundary: the framework owns behavior and infrastructure;\n  the application owns component source and visual style.\n- Keep the base layer visually unopinionated. It may provide interaction behavior,\n  accessibility, focus, overlay and popup infrastructure, positioning, animation,\n  virtual lists, dock infrastructure, and semantic design tokens.\n- Theme APIs must expose semantic tokens (colors, spacing, radius, typography, and\n  shadows), not an ever-growing set of component-specific styling fields.\n- Keep source distribution or registry tooling above the `gpui-base` seam; no\n  registry or CLI crate is currently part of the workspace.\n- Preserve 100% backward compatibility for existing consumers, including current\n  imports such as `use gpui_kit::component::button::Button;`.\n\n### Component Initialization\n\nCall `gpui_kit::init(cx)` before opening windows that use styled components.\nIt includes Base initialization and registers Component's window extension.\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx| {\n        gpui_kit::init(cx);\n        gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| {\n            cx.new(|_| MyView)\n        })\n        .expect(\"Failed to open window\");\n    });\n}\n```\n\nBase-only fixtures use GPUI directly and must not depend on Kit or Component.\nApplications and Kit tests use `gpui_kit::open_window` as their window entry point.\n\n### Root View System\n\n`gpui_base::Root` is the top-level view for every window created by\n`gpui_kit::open_window`. The helper belongs only to Kit; Base supplies the Root\nimplementation. `component::Root` re-exports the Base type. Cargo features do not\nselect a different root type.\n\nBase owns content and overlay hosting, keyboard navigation (Tab/Shift-Tab),\nand selection copying. Explicit Component initialization registers per-window\nstate and presentation for dialogs, sheets, notifications, tooltips, menus,\ntouch selection, themes and window chrome. Initialize before creating windows.\n\nThe helper returns the window handle and application content entity. Its builder\nmust return content, not another Root. Overlay layers mount automatically; do not\ncall the removed `Root::render_*_layer` methods. In async contexts call the helper\ninside `cx.update`. Tests should use the same helper and retain its returned\ncontent entity when they need to inspect or update application state. Avoid\nconstructing `Root` directly in application and test startup code.\n\nQuit/close actions, keyboard shortcuts and confirmation flows belong to the application.\n\n### Theme System\n\n- Uses `Theme` global singleton for theme configuration\n- Supports light/dark mode switching\n- Access theme via `ActiveTheme` trait: `cx.theme()`\n- Theme configuration includes:\n  - Colors (`ThemeColor`)\n  - Syntax highlighting theme (`HighlightTheme`)\n  - Font configuration (system font and monospace font)\n  - UI parameters like border radius, shadows\n  - Scrollbar display mode\n\n### Dock System\n\nLayout behavior lives in `crates/base/src/dock`; `crates/component/src/dock` is a\npresentation skin (`DockSkin`) over it. See `docs/ARCHITECTURE.md`.\n\n- **`LayoutTree`**: Pure-data layout tree, the single source of truth.\n  - `NodeKind::Split` / `Tabs`: containers, addressed by `NodeId`\n  - Panels are addressed by `PanelId`; the tree holds no entity handles\n- **`DockArea`**: Owns the center and dock trees, reconciles them into a\n  cache of container entities keyed by `NodeId`\n- **`TabGroup`**: The `Tabs` container entity\n- **`Panel`**: Split at the seam — `gpui_base::dock::Panel` for behavior,\n  `gpui_component::dock::Panel` for presentation; a panel implements both\n- **`PanelRegistry`**: Resolves a persisted `panel_name` back to a panel type\n\nThe Dock system supports:\n\n- Panel drag-and-drop reordering\n- Panel zoom\n- Layout locking\n- Layout serialization/restoration\n\n### Input System\n\nText input system based on Rope data structure:\n\n- **InputState**: Input state management\n- **Rope**: Efficient text storage (from ropey crate)\n- LSP integration support (diagnostics, completion, hover)\n- Syntax highlighting support (Tree-sitter)\n- Multiple input modes:\n  - Regular input (`Input`)\n  - Number input (`NumberInput`)\n  - OTP input (`OtpInput`)\n\n### Component Design Principles\n\n1. **Stateless design**: Use `RenderOnce` trait, components should be stateless when possible\n2. **Size system**: Supports `xs`, `sm`, `md` (default), `lg` sizes via `Sizable` trait.\n3. **Mouse cursor**: Buttons use `default` cursor not `pointer` (desktop app convention), unless it's a link button\n4. **Style system**: Provides CSS-like styling API via `Styled` trait and `ElementExt` extensions\n5. **Base controls are no-style**: Base controls and parts do not install layout,\n   positioning, colors, sizing, gaps, radius, borders, shadows, variants, or animation.\n   Complete presentation belongs to `crates/component` or the application. The deliberate\n   exception is the foundational Base Input frame, which provides only a semantic\n   one-pixel input border and semantic radius baseline; UI/application layers own\n   its background, sizing, padding, typography, adornments, and richer focus style.\n6. **GPUI builder style**: Keep element construction as one fluent builder chain. Express\n   conditions with `when`, `when_some`, `when_none`, and `map`; do not split a chain into a\n   mutable temporary element followed by imperative reassignment when the builder API can\n   express the same operation.\n7. **No `pub` fields on public data types**: A public struct handed across the\n   `gpui-base`/application seam — a state snapshot, capability set, render context, or\n   option set — keeps its fields private, is constructed with a builder, and is read\n   through methods. Adding a `pub` field is a breaking change; adding one behind a builder\n   is not. Setters and readers must not collide: an all-boolean type names setters after\n   the field and readers `is_<adjective>`/`has_<noun>`, never `can_`; a type with\n   non-boolean fields prefixes every setter with `with_` and keeps the field name for\n   readers. Value types whose fields are the definition and cannot grow (`Point`,\n   `Selection`, `Edges`) are exempt. See the \"Public Data Types Across the Seam\" section\n   of `docs/ARCHITECTURE.md`.\n8. **Spell `Context` out**: Name a context type `ComboboxTriggerContext`, never `…Ctx`.\n   `cx` is reserved for GPUI's `App`, `Context<T>`, and `AsyncApp`, so `ctx` for anything\n   else reads as a competing context. A callback receiving both takes the GPUI one as `cx`\n   and names the other after what it holds (`trigger`, `state`).\n\n## Pull Request Reviews\n\nEvery PR review must present its conclusions in this order:\n\n1. Explain the PR's purpose: the problem it addresses and the scope of its changes.\n2. Assess whether the requirement and proposed approach are reasonable.\n3. Report concrete findings, followed by validation performed and its limitations.\n\nDo not start a review with findings alone; include the purpose and reasonableness\nassessment even when no issues are found.\n\n## Code Style\n\n- Follow naming and organization patterns from existing code\n- Reference macOS/Windows control API design for naming\n- AI-generated code must be refactored to match project style\n- Mark AI-generated portions when submitting PRs\n- When creating a PR, inspect previous PR titles in the repository and match\n  that style. Do not blindly use conventional prefixes like `fix:` or `feat:`\n  unless the existing PR title style uses them.\n- When a PR adds, changes or removes public API in any crate, list every item\n  under a `## Public API` section of the description, grouped by crate, with its\n  signature and one line on its purpose (JavaScript methods and TypeScript\n  declarations included). Changes to existing items also go under\n  `## Breaking Changes` with `diff` blocks showing the old and new usage. See\n  PR #2691 and the \"Describe public API changes\" section of `CONTRIBUTING.md`.\n- Avoid `Kind` as a type-name suffix. It says an enum classifies something\n  without saying what it classifies, and carries no meaning a reader could not\n  already infer from `enum`. Name the type after what its variants _are_\n  instead. Keep `Kind` only when no honest name covers the variant set —\n  `NodeKind`'s variants straddle two levels (`Split` is an interior node,\n  `Tabs` is a leaf), and every domain word for the leaf level\n  (`Pane`, most of all) would misdescribe `Split`; a vaguer name is better\n  than a precise wrong one. Prefer confining such a type to `pub(crate)`.\n  This governs new code; existing `Kind` names are not a rewrite target on\n  their own, and names owned by external crates (`CodeActionKind`,\n  `CompletionItemKind`, `WindowKind`) keep their upstream spelling.\n\n## Icon System\n\nThe `Icon` element does not include SVG files by default. You need to:\n\n- Use [Lucide](https://lucide.dev) or other icon libraries\n- Name SVG files according to the `IconName` enum definition (located in `crates/component/src/icon.rs`)\n\n## Dependencies\n\n- GPUI: Git version from Zed repository\n- Tree-sitter: For syntax highlighting\n- Ropey: Rope data structure for text, and `RopeExt` trait with more features.\n- Markdown rendering: `markdown` crate\n- HTML rendering: `html5ever` (basic support)\n- Charts: Built-in chart components\n- LSP: `lsp-types` crate\n\n## Internationalization\n\nUses `rust-i18n` crate.\n\n- Localization files are located in `crates/component/locales/`.\n- Only add `en`, `zh-CN`, `zh-HK` by default.\n- Accessibility (A11y) names and labels may remain in English; localization is\n  not required for these strings. Keep the item's own label when naming a\n  control that acts on it. This exception does not apply to visible UI copy.\n\n## Documentation\n\n- The documentation site source is in `website/`.\n- Site docs have two locales: English (`website/docs/`) and Chinese (`website/zh-CN/docs/`).\n- When modifying any documentation file, always sync changes to both `en` and `zh-CN` versions.\n- `docs/` holds internal architecture specifications (RFC, migration status, reviews).\n  These are single-language and are not published to the site; see `docs/README.md`.\n- `skills/gpui-kit/references/coding-guides.md` and\n  `skills/gpui-kit-design-guides/references/design-guides.md` are verbatim copies\n  of the English `website/docs/` originals, vendored so the skills work after\n  `npx skills add` in a project that does not have this repo. After editing either\n  guide, copy it across:\n\n  ```bash\n  cp website/docs/design-guides.md skills/gpui-kit-design-guides/references/design-guides.md\n  cp website/docs/coding-guides.md skills/gpui-kit/references/coding-guides.md\n  ```\n\n  Never edit the copy directly — edit `website/docs/`.\n\n## Platform Support\n\n- macOS (aarch64, x86_64)\n- Linux (x86_64)\n- Windows (x86_64)\n\nCI runs full test suite on each platform.\n\n## Skills Reference\n\nThis project provides skills for coding agents to assist with common development tasks:\n\n- **gpui-kit** (`skills/gpui-kit/SKILL.md`) - Building applications on the `gpui-kit` crate: setup, component catalog, stateless/stateful patterns, theming, GPUI mechanics (actions, async, contexts, custom elements, entities, events, focus, global state, layout, `ElementId`, testing), and the normative Coding Guides\n- **gpui-kit-design-guides** (`skills/gpui-kit-design-guides/SKILL.md`) - The normative Design Guides; load before any UI, layout, interaction, or interface-copy work\n\nWhen working on tasks related to these areas, read the appropriate `SKILL.md`\nfor specialized guidance and patterns.\n\n## Shared Workflows\n\n- [Release notes](.agents/commands/release-notes.md) - Write release notes from a\n  version tag or a pasted \"What's Changed\" list. Claude Code exposes this workflow\n  through `/release-notes`; other agents can read and follow the shared file.\n\n## Testing Guidelines\n\nSee `.agents/COMPONENT_TEST_RULES.md` for detailed testing principles:\n\n- **Simplicity First**: Focus on complex logic and core functionality, avoid excessive simple tests\n- **Builder Pattern Testing**: Every component should have a `test_*_builder` test covering the builder pattern\n- **Complex Logic Testing**: Test conditional branching, state transitions, and edge cases\n","isInternal":false,"tokens":3818,"sizeBytes":16599},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# Claude Code\n\n@AGENTS.md\n","isInternal":false,"tokens":9,"sizeBytes":26},{"name":"design-guides.md","path":"skills/gpui-kit-design-guides/references/design-guides.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit-design-guides/references/design-guides.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"---\ntitle: Design Guides\ndescription: Product and interaction design guidance for GPUI Kit applications\norder: -12\n---\n\n# Design Guides\n\nUse this guide before choosing components or writing layout code. It records\nthe product judgment accumulated through years of GPUI Kit desktop work:\nan interface should feel native, restrained, precise, and understandable\nwithout guesswork.\n\nThis is a normative guide. **Must** identifies a correctness or ecosystem\nconstraint, **should** is the default that needs a concrete reason to override,\nand **may** is an optional technique. Component API documentation remains the\nauthority for individual methods.\n\nThe rules build on behavior in `gpui-base`, the GPUI Component theme and\ncomponent system, and familiar desktop interaction. <a href=\"https://ui.shadcn.com/docs\" target=\"_blank\" rel=\"noopener noreferrer\">shadcn/ui</a> contributes useful\nmethods—open code, composition, and dependable defaults—but does not determine\nhow a GPUI application should look. When influences conflict, preserve GPUI's\nlifecycle constraints and the interaction people already understand.\n\n## Design thesis\n\nBuild interfaces that feel native, quiet, and precise. Let content, hierarchy,\nand interaction carry the experience; decoration should support them rather\nthan compete with them.\n\n1. **Clarity before personality.** Make the primary task and next action clear\n   before adding brand expression.\n2. **Composition before invention.** Start with established components and\n   compose them into product-specific workflows. Create a new primitive only\n   when its behavior is genuinely new.\n3. **Tokens before values.** Colors, radii, typography, and spacing should form\n   a system. Avoid isolated literals that cannot respond to themes. See\n   [Style](./style) for GPUI's styling API.\n4. **Desktop before web convention.** Preserve keyboard access, window chrome,\n   menus, dense data views, resizable regions, and persistent navigation where\n   the task benefits from them.\n5. **State must be visible.** Hover, focus, selection, disabled, loading,\n   validation, and destructive states need distinct and consistent treatment.\n6. **Geometry explains containment.** Radii, insets, and boundaries should\n   describe one coherent hierarchy, even where surfaces overlap.\n7. **Feedback reflects reality.** Loading, tooltips, and motion should clarify\n   a real state or transition, not add ceremony to an immediate action.\n\n## Learning from Shadcn\n\nShadcn's most useful contribution is not a particular border color. It is a\nway of building a system:\n\n- own the top layer of the interface instead of fighting a sealed abstraction;\n- compose small, predictable parts into product-specific components;\n- provide defaults that already form one visual language;\n- keep the code and composition legible to both people and AI;\n- separate behavior primitives from the styled layer.\n\nGPUI Kit applies those ideas through a Rust library and the split between\n`gpui-base` and `gpui-component`. Applications normally compose or wrap the\npublished components; contributors move genuinely reusable behavior into Base\nand keep visual policy above it.\n\nDo not copy these web assumptions blindly:\n\n| Web habit | Native GPUI default |\n| --- | --- |\n| Pointing-hand cursor on every button | Default arrow cursor; pointing hand for links |\n| Page navigation as the main structure | Persistent windows, panes, sidebars, tabs, and menus |\n| Browser focus and scrolling as a fallback | Explicit focus ownership and region-owned scrolling |\n| Mobile-first single column | Resizable desktop shell with a defined minimum window size |\n| Hover-revealed critical actions | Keyboard- and pointer-reachable actions that do not depend on hover |\n| A row of hover-only icon buttons | A visible primary action plus `DropdownMenu` or `ContextMenu` for secondary commands |\n| Link-styled text for application commands | `Button`, `outline`, or `ghost`; Link only for URLs, web resources, or email addresses |\n| Large touch density everywhere | Medium density by default; compact only where information work benefits |\n| CSS overrides across descendants | Typed builders, semantic parts, and application composition |\n\n## Start from the task\n\nBefore drawing a screen, write down:\n\n- the user's primary task;\n- the object being viewed or changed;\n- the actions that must remain immediately available;\n- the information required to make a decision;\n- empty, loading, error, offline, read-only, and permission-denied states;\n- the keyboard path through the workflow.\n\nOrganize the window around those answers. Do not begin with a dashboard grid or\na component catalogue. A good desktop interface exposes the user's mental\nmodel: documents, accounts, projects, messages, settings, or another stable\nobject—not the internal service architecture.\n\nDesign the primary task before distributing controls. Its visual weight,\nlocation, and information depth should match its importance to the product. A\ncore result must not be reduced to a small count, an icon in a corner, or a\nweak footer action while secondary content consumes the page. When a result set\nis the product's main value, consider a summary region or card that exposes the\ncount, representative results, meaningful state, and a clear next action.\n\nFor every proposed action, name its visible object, current state, scope, and\nresult. If the interface does not show or clearly imply those things, the\naction is premature. Do not expose a capability merely because the backend has\nit; first design how the object enters the user's mental model.\n\n## Visual language\n\n### Hierarchy\n\nPrefer a small number of clear levels:\n\n- **window or page title** identifies the current object or workspace;\n- **section title** separates meaningful regions;\n- **body text** carries the work;\n- **muted text** provides secondary metadata and help;\n- **labels** identify controls and values.\n\nUse size, weight, spacing, and separators before adding color or containers.\nAvoid nesting cards inside cards: most desktop regions need only a background,\na hairline boundary, and intentional spacing.\n\nEvaluate hierarchy across the whole feature, not component by component. Hide\naccent color and decoration during review: the primary task, current selection,\nresult summary, and next action should still be obvious from structure. A\nscreen that contains individually plausible controls can still fail when they\ndo not form one reading order and one decision path.\n\nTreat emphasis as a limited budget. A local surface needs one clear focal point,\nnot a field of competing highlights. If everything is colored, badged, bold,\nboxed, or promoted to an alert, nothing reads as important. Establish priority\nwith structure and proximity first; spend stronger color and components only\nwhere a distinction changes what the user notices or does.\n\n### Color and themes\n\nRead colors from `cx.theme()` and use them by semantic role:\n\n- `background` and `foreground` for the main surface and text;\n- `group_box`, `popover`, `sidebar`, and their foreground tokens for their\n  named surfaces;\n- `muted` and `muted_foreground` for supporting information;\n- `primary` for the principal action or selection emphasis;\n- `danger`, `warning`, `success`, and `info` only for their meanings;\n- `border`, `input`, and focus-ring tokens for structure and interaction.\n\nDo not use a semantic status color as decoration. Do not encode meaning by\ncolor alone. Verify every custom surface in light and dark themes and with\ncustom theme values; never assume that foreground is black or background is\nwhite.\n\nUse Badge for a short state, count, or classification that benefits from rapid\nscanning—not for every label, metadata value, filter, or section title. Keep\nmost badges neutral; reserve semantic variants for states that truly carry\nsuccess, warning, danger, or informational meaning. A row of multicolored\nbadges is usually a missing hierarchy or grouping decision.\n\nApplication UI should not contain raw hex, `rgb`/`rgba`, or `hsla` colors.\nResolve colors from `cx.theme()` by semantic role. If the required role does\nnot exist, define it in the product's theme/token layer rather than embedding a\npalette value at the call site. Raw colors belong only inside theme definitions\nor in audited data/raster content whose color is itself the data.\n\n### Radius, spacing, and density\n\nUse a finite radius scale, as with type and control sizes. Choose from the\ntheme's named tiers (`sm`, `md`, `lg`, `xl`, and larger surface tiers) instead\nof inventing a radius for each element. Large containers may use a softer tier\nthan the controls they contain; compact controls and overlays use tighter\ntiers. For an ordinary rectangle, the radius should remain visibly smaller\nthan half its shorter side. Use `radius_full()` only for intentional circles\nand pills; a tooltip must not become a capsule by accident.\n\nNested surfaces should read as concentric shapes. Use\n`inner radius ≈ max(0, outer radius − gap)` to choose the closest suitable\ntheme tier; the visible band should remain even through the turn. Add a\nnamed application token if a repeated composition needs an intermediate\nvalue. A segmented control is one silhouette: its end segments follow the container's inner\ncorners, its middle segments remain square, and each boundary has one divider\nof consistent thickness.\n\n<img class=\"alignment-light\" src=\"/radius-hierarchy.svg?v=20260923-easing\" alt=\"Light theme chat composer: the inset surface, both buttons, and placeholder spacing change together; red guide circles show their shared corner center.\">\n<img class=\"alignment-dark\" src=\"/radius-hierarchy-dark.svg?v=20260923-easing\" alt=\"Dark theme chat composer: the inset surface, both buttons, and placeholder spacing change together; red guide circles show their shared corner center.\">\n\nA radius must govern the entire visible surface, not just its border. Exposed\ncorners remain transparent to the surface behind them; child backgrounds,\nselection fills, and scrolling content must also follow the boundary. In GPUI,\ndo not assume a rounded parent clips its descendants. Give inner surfaces their\nown radius or an appropriate clip, then inspect the composition against a\ncontrasting background in both themes. Preserve outward focus rings when\nchoosing a clip.\n\nUse a compact spacing scale and repeat it. Related label/control pairs should\nbe closer than separate groups; separate groups should be closer than separate\nsections. Prefer component sizes (`xsmall`, `small`, default medium, `large`)\nover one-off heights. Use compact variants for toolbars and data-dense screens,\nnot to squeeze an unclear layout into less space.\n\nThe shared semantic scale is intentionally small: spacing progresses through\nroughly 2, 4, 8, 12, 16, 24, and 32 pixels, while typography stays near 12,\n14, 16, 18, and 20 pixels. Treat these as relationships rather than permission\nto scatter their current values through feature code. GPUI Component currently\nprojects a fixed default `SpacingTokens` scale from its global `Theme`; unlike\ncolors and radii, `Theme::apply_semantic_tokens` does not persist a custom\nspacing scale. An application that needs different spacing must own that full\ntoken snapshot and use it consistently in its application components.\n\n### Spatial grammar\n\nSpacing expresses relationship. Choose a gap from the semantic scale by asking\nwhat the two things mean to each other:\n\n| Relationship | Typical token | Current scale | Examples |\n| --- | --- | --- | --- |\n| Optical correction | `xxs` | 2 px | icon baseline, compact separator |\n| Parts of one control | `xs` | 4 px | menu icon/label, title/description |\n| Closely related controls | `sm` | 8 px | button icon/label, dialog actions |\n| One content group | `md` | 12 px | notification columns, compact form rows |\n| Separate groups in one section | `lg` | 16 px | panel padding, form groups |\n| Separate sections | `xl` | 24 px | major blocks in a page or inspector |\n| Major region boundary | `xxl` | 32 px | empty-state breathing room, page bands |\n\nThese values describe the current default scale, not literals to repeat. Use\n`cx.theme().spacing_tokens()` or the corresponding GPUI scale helpers for the\necosystem default. A product-owned scale should preserve the ordering and\nrelationships and must be passed through the application's own design-system\ncontext rather than assumed to persist in the global GPUI Component theme.\n\nUse these rules when resolving horizontal and vertical space:\n\n1. **Inside before outside.** A component's padding belongs to the component;\n   the gap between components belongs to their parent.\n2. **Vertical rhythm shows grouping.** The gap between a title and its\n   description is smaller than the gap from that description to the next\n   section. Equal gaps imply equal relationships.\n3. **Horizontal space supports scanning.** Repeated rows keep icons, labels,\n   values, badges, and trailing actions on stable columns.\n4. **Leading and trailing are semantic.** Think in reading-order edges even\n   when the current API uses left/right; this keeps future RTL adaptation\n   possible.\n5. **Do not double padding.** A card placed in an already padded panel should\n   not automatically add another full panel inset.\n6. **Use optical alignment sparingly.** A one- or two-pixel correction is valid\n   for icon or glyph geometry, but document why it differs from the scale.\n\nCommon compositions in the current system illustrate the relationships:\n\n- button contents use 4 px at small sizes and 8 px at normal sizes;\n- dialog headers and footers use an 8 px internal gap;\n- compact list and menu rows use 4 px vertical and 8–12 px horizontal padding;\n- sheet headers use about 16 px leading and 12 px trailing space, leaving room\n  for a close affordance, while footers use 16 px horizontal and 12 px vertical\n  space;\n- notifications use 16 px horizontal padding and a 12 px column gap because\n  icon, message, and action are distinct groups.\n\nDo not treat these as copy-and-paste recipes for every surface. They reveal the\nsystem: controls are tighter internally, rows optimize scanning, and\ncontainers spend more space at their boundary than between their contents.\n\n### Proportion and layer hierarchy\n\nStart with content requirements, then set proportions. Avoid arbitrary halves\nwhen one pane has a clearly different role.\n\n- A navigation sidebar should be wide enough for stable labels but visibly\n  subordinate to the work area. Give it a minimum, preferred, and maximum\n  width rather than a percentage alone.\n- In master–detail layouts, let the collection remain scannable and give the\n  detail pane the surplus. A roughly one-third/two-thirds starting point is\n  often useful, but content constraints are authoritative.\n- Inspectors and auxiliary sheets should not cover the primary object by\n  default. They should be resizable or dismissible when their content grows.\n- Dialog width comes from the decision: short confirmation, medium form, or a\n  dedicated window/page for complex work. Do not enlarge a dialog simply to\n  create whitespace.\n- Reserve the strongest elevation for the topmost decision layer. Within a\n  layer, use background and hairlines—not successively larger shadows—to show\n  hierarchy.\n\nDefine three size constraints for every major region: the minimum at which its\ntask still works, a comfortable default, and how it consumes surplus. Persist\nuser-controlled splits when they represent workflow preference, and clamp\nrestored values against the current window.\n\n### Alignment details\n\nAlignment is a structural system, not a final polish pass. Establish a small\nset of alignment spines for each surface: shared leading and trailing edges,\ntext baselines, center lines, and fixed functional lanes. Elements at the same\nlevel should attach to the same spine from top to bottom or leading to trailing,\neven when they are different component types.\n\n<img class=\"alignment-light\" src=\"/alignment-spines.svg?v=20260822-4\" alt=\"Alignment spines across a desktop surface\">\n<img class=\"alignment-dark\" src=\"/alignment-spines-dark.svg?v=20260822-4\" alt=\"Alignment spines across a desktop surface\">\n\nVertical red lines sit beside shared edges or control centers for content,\nstatus, time, and trailing actions. Horizontal lines sit beneath text baselines\nor pass through a row center to show bottom and vertical-center alignment. The\ncompact comparison isolates a one-rendered-pixel drift that must be corrected\nat its structural owner.\n\n- Give sibling regions a shared content inset. A heading, toolbar, list row,\n  empty state, and footer that describe the same level should not each invent a\n  slightly different leading edge.\n- Repeat column geometry through the whole region. Headers, rows, summaries,\n  loading states, and inline editors should reserve the same lanes for identity,\n  metadata, status, numbers, and actions.\n- Align related controls across rows and sections. Form labels, fields,\n  descriptions, and validation messages should reveal a stable vertical grid\n  when the page is scanned from top to bottom.\n- Keep horizontal bands coherent. Items sharing a toolbar, title bar, status\n  bar, or row should use one baseline or center line instead of individually\n  tuned offsets.\n- Introduce indentation only for real hierarchy, containment, or disclosure.\n  Decorative indentation makes siblings look subordinate and breaks the\n  surface's reading line.\n- When a nested level ends, return exactly to the parent spine. Do not let\n  accumulated padding drift across nested containers.\n- Preserve the spine through optional content. Missing icons, badges,\n  descriptions, or trailing actions must not move the remaining labels; use\n  intentional slots or lanes when cross-row comparison matters.\n- Align major regions with one another where their hierarchy matches. Sidebar\n  headers, content titles, split panes, toolbars, and bottom bars need not share\n  every coordinate, but coincident levels should form visible continuous lines.\n\nNot every edge should align. A child can indent, a primary value can lead its\nsupporting metadata, and a destructive decision can gain separation. Such\nexceptions must communicate hierarchy or meaning; they must not result from\nuncoordinated component padding. Start with the shared spine, then make the\nexception explicit.\n\nTreat exact alignment and repeated gaps as quality invariants. When two edges\nor spaces are intended to be equal, a one-rendered-pixel difference is a defect,\nnot an acceptable optical approximation. Inspect resolved bounds with a\nmeasurement tool at representative window sizes, zoom levels, and display scale\nfactors. Compare coordinates and distances; do not approve alignment only from\na casual screenshot.\n\nThe rendered-pixel tolerance is a verification rule, not permission to patch\nthe code with raw pixel offsets. Equal relationships should resolve from the\nsame `rem` helper, spacing token, grid definition, or shared component inset.\nFix the common owner when they differ. Account for fractional layout and device\nrounding so intended spines land on the same physical pixel instead of drifting\nat particular zoom levels.\n\n- Align text by baselines, not by bounding-box centers, when mixed sizes share\n  a row.\n- Center icons in a fixed slot so labels do not move when icons differ in\n  intrinsic width.\n- Right-align comparable numbers; left-align prose and identifiers unless the\n  locale requires otherwise.\n- Keep trailing row actions and disclosure indicators in fixed-width lanes.\n- Align form controls by their interactive frame, not by help text below them.\n- Use `justify_between` only when the two sides truly own opposite edges; it\n  should not disguise missing structure in the middle.\n- Hairlines belong on the boundary owner. Two adjacent regions must not each\n  draw the same separator.\n- A scrollbar belongs to the region that scrolls and sits against that panel,\n  editor, or window's trailing edge. Content padding may inset text and rows;\n  it must not pull the scrollbar into the middle of the surface. Reserve a\n  deliberate scrollbar gutter when content needs clearance.\n\n### Density tiers\n\nMedium is the ecosystem default. Change density for the whole local context,\nnot one isolated control:\n\n- **comfortable / large:** onboarding, sparse forms, prominent decisions;\n- **standard / medium:** most application chrome and workflows;\n- **compact / small:** toolbars, menus, tables, and repeated professional data;\n- **extra compact / xsmall:** exceptional high-density utilities, never the\n  automatic choice for an entire application.\n\nThe current controls demonstrate a bounded scale rather than arbitrary sizing:\nbuttons commonly move through approximately 20, 24, and 32 px frames; input\nand data controls may extend to about 44 px at large size; table rows use about\n26, 30, 32, and 40 px. Use the component's `Size` API so typography, icon,\npadding, and hit target change together. A custom height that changes only the\nouter box is usually incomplete.\n\n### Zoom, base font, and `rem`\n\nA well-designed `rem` system preserves hierarchy while the interface zooms.\nZoom is successful when the relationship between title and body, control and\nicon, inner and outer spacing, primary and secondary regions still feels the\nsame at every scale—not merely when every object becomes larger.\n\nGPUI Component adopts the relative-scale idea familiar from <a href=\"https://tailwindcss.com/docs/theme\" target=\"_blank\" rel=\"noopener noreferrer\">Tailwind CSS</a>. The\ntheme's base `font_size` becomes the window's `rem` through `Root`, and GPUI\nscale helpers such as `text_sm()`, `gap_2()`, `p_4()`, `h_8()`, and `size_4()`\nresolve against it. This gives typography, spacing, controls, and icons one\nshared zoom axis.\n\nDesign in ratios:\n\n- type steps keep the same hierarchy around the base body size;\n- spacing steps keep the same grouping relationships around the type;\n- control frames, icons, and hit targets scale with their labels;\n- pane minima and comfortable widths account for the scaled content;\n- corner radii and focus treatment remain optically consistent with the\n  control frame.\n\nDo not implement zoom by changing text size alone. A larger label inside a\nfixed-height button, a larger document inside fixed pane minima, or larger rows\ninside a stale virtual-list measurement destroys the original rhythm and can\nclip content. Conversely, multiplying every physical pixel—including\nhairlines—can make the interface visually heavy.\n\nAs a rule, application layout should not call `px(...)` directly. Use GPUI's\nrem-based scale helpers (`p_2`, `gap_3`, `w_64`, `text_sm`, and related\nbuilders) or semantic component sizes. Use fixed pixels only when the value\nrepresents a physical or raster boundary:\na one-device-pixel hairline, platform window inset, bitmap dimension, minimum\nhit-test tolerance, or geometry that must match an external surface. These are\naudited, documented exceptions. Product spacing, typography, icon size, and\nordinary control geometry stay on the relative scale.\n\nTest interface zoom at several base-font values, not just the default. Verify\nhierarchy, wrapping, truncation, minimum window size, pane resizing, focus-ring\nclearance, popup placement, and virtualized row measurement. Also distinguish\ninterface zoom from Dock's panel zoom: Dock zoom makes one container fill its\narea while retaining its chrome; it does not change `rem` or application scale.\n\n### Surfaces and elevation\n\nUse elevation to explain stacking, not importance. The base window surface is\nflat; separators and background contrast define its regions. Popovers, menus,\ndialogs, and notifications may use progressively stronger shadows because they\nsit above other content. Do not put a shadow on every card.\n\nAll surfaces of the same kind should share one treatment. GPUI Component, for\nexample, deliberately gives popup families one themed popover surface so\nPopover, Select, Combobox, DatePicker, and menus do not drift apart. When an\napplication invents another anchored surface, reuse that semantic treatment\ninstead of approximating it with unrelated border and shadow literals.\n\n### Typography and icons\n\nUse the platform UI font for interface text and monospace only for code,\nidentifiers, shortcuts, and aligned numeric data. Keep body text readable and\navoid excessive uppercase or letter spacing, especially for CJK text.\n\nUse one icon family in a product. Icons supplement labels; they should not\nreplace unfamiliar actions with guesswork. Icon-only buttons always need an\naccessible name. Their visual explanation follows the tooltip policy below.\nUse filled or colored icons to communicate a state, not merely to make a\ntoolbar lively.\n\n## Layout patterns\n\n### Choose a stable shell\n\nMost applications should use one of these shells:\n\n- **single workspace:** toolbar or title bar above one primary view;\n- **sidebar workspace:** persistent navigation beside a changing detail view;\n- **master–detail:** resizable collection and detail panes;\n- **document workspace:** tabs or a dock area for multiple long-lived objects;\n- **utility window:** one focused task with a short, fixed action path.\n\nKeep global navigation stable while content changes. Give the primary work area\nthe remaining space with `flex_1()` and `min_w_0()` / `min_h_0()` where\noverflowing children must shrink. Use `Scrollable`, `VirtualList`, `Table`, or\n`DockArea` for their intended behavior instead of rebuilding scrolling or pane\nmanagement from nested `div`s.\n\nThe title bar is window chrome first. Preserve its drag region and avoid\nbinding ordinary title clicks to infrequent editing commands. Rename belongs\nbehind an explicit object command, with a keyboard path where appropriate.\n\n### Responsive desktop windows\n\nDesktop does not mean fixed-size. Decide what happens as a window narrows:\n\n1. preserve the primary task;\n2. allow resizable regions to reach a documented minimum;\n3. collapse secondary labels or inspectors;\n4. move low-frequency actions into a menu;\n5. scroll only the region whose content actually overflows.\n\nDo not hide an action without providing another path to it. Avoid making the\nentire window scroll when only a list or document body should scroll.\n\nGPUI flex layouts have the same intrinsic-size pressure found in other layout\nsystems: a `flex_1()` child may still refuse to shrink around long content.\nDesign and implementation must agree on which panes may shrink, truncate, wrap,\nor scroll. A clipped region also clips an outward focus ring; never trade away\nkeyboard visibility merely to simplify overflow.\n\n### Forms and settings\n\nUse a visible label for each field and place help or validation next to the\nfield it describes. Align related fields, but do not force long labels into a\nnarrow fixed column. Use the appropriate control: `Checkbox` for independent\nchoices, `RadioGroup` for a small visible set, `Select` for a longer set, and\n`Switch` for a setting that takes effect immediately.\n\nDisable submission while an operation is in flight, keep the user's input, and\nshow the result near the action. Reserve dialogs for short, focused decisions;\nuse a full page or sheet for workflows that need exploration or many fields.\n\nA loading treatment must represent actual waiting. Switching between settings\npanels whose content is already available should be immediate; a skeleton is\nappropriate only while content is genuinely loading and its shape is known.\n\n## Components and composition\n\nFollow the Shadcn principle that components are building material rather than a\nsealed design system. GPUI Component supplies coherent defaults, while the\napplication owns composition and product semantics.\n\n- Use component variants by meaning. Primary is reserved for the explicit\n  default commit in a decision area—normally the action invoked by Enter. A\n  lone, frequent, or desirable action is not automatically primary. An `Add`\n  command in a management toolbar normally uses a default Button; a form's\n  default `Create` commit may use primary. Use `danger` for destructive\n  commitment and `ghost` for quiet toolbar actions.\n- Prefer explicit compound parts and render callbacks over styling arbitrary\n  descendants.\n- Keep a repeated pattern consistent across the product. Wrap it in an\n  application component when it carries domain language or policy.\n- Use the standard component for its semantic role. A menu, dropdown menu,\n  popover, select, and command palette are not interchangeable boxes; each owns\n  different selection, focus, keyboard, dismissal, and layout contracts.\n- Preserve the component family's geometry. Menu rows share vertical and\n  horizontal padding, height, icon and checkmark slots, separators, radius, and\n  state treatment. Do not imitate one menu with a custom popup whose spacing\n  only approximates the system.\n- Do not wrap a library component merely to rename every method or freeze all\n  of its capabilities.\n- Move reusable behavior without product styling to `gpui-base`; keep themed,\n  opinionated presentation in GPUI Component or the application.\n\n## Interaction states\n\n### Make the result understandable before the click\n\nA control should predict its result. Use familiar desktop controls and\nplacement so people can act without learning the interface first. Its label\nnames the action and object, its state shows availability, and its feedback\nconfirms the same outcome.\n\nDo not label a Button `Save` if it opens a configuration flow, or `Delete` if\nit only removes an item from a group. Name the scope when context does not make\nit clear. Respond immediately to activation, prevent duplicate submission\nduring longer work, and show the result near the object that changed. Add a\nsuccess message only when the result itself is not visible.\n\nEvery interactive control should be designed for:\n\n| State | Design requirement |\n| --- | --- |\n| Rest | Clear affordance without visual noise |\n| Hover | Subtle pointer feedback, never the only cue |\n| Pressed | Immediate press feedback |\n| Open / pressed | Persistent feedback while an attached popup is open |\n| Focus visible | High-contrast keyboard focus ring |\n| Selected / checked | Persistent state distinct from hover |\n| Disabled | Lower emphasis and no misleading hover/pressed response |\n| Loading | Preserve context, prevent duplicate action, explain long waits |\n| Error | State what happened and how to recover |\n\nUse GPUI's focus system and Actions for commands that should work from the\nkeyboard. Match familiar desktop shortcuts, expose shortcuts in menus or\ntooltips, and keep focus in a logical place after opening or dismissing an\noverlay.\n\nSelection is part of the information model, not optional polish. Tabs,\nsegmented choices, selectable rows, filters, and navigation destinations must\nshow a persistent selected state. A Button that owns a dropdown must remain\nvisibly pressed or open until the popup closes; hover alone cannot explain the\nrelationship between trigger and surface.\n\nIn a segmented control, the selected fill and unselected surface must share\nthe container's silhouette. Neither may square off an end corner or make a\nboundary appear heavier than its peers.\n\nShow a selected navigation item, list row, or tab through the item's own\nsurface: a selected fill, stronger foreground, or heavier weight. Do not add a\nleading-edge bar or one-sided border as the selection marker. It is a web\ntemplate habit, not a desktop convention; it breaks the item's rounded\nsilhouette and adds a second, competing edge to a column that already aligns\non its text.\n\nFor destructive actions, distinguish between reversible and irreversible work.\nPrefer undo or a temporary notification for reversible changes. Use an\n`AlertDialog` when the consequence is serious and cannot be undone; name the\nspecific object and consequence in the confirmation copy.\n\n### Pointer conventions\n\nUse the default arrow cursor for buttons, checkboxes, menu items, tabs, and\nother native controls. Use a pointing hand for links and content that behaves\nas a link. Use text, resize, grab, and prohibited cursors only when they\ndescribe the active manipulation. A cursor reinforces an affordance; it does\nnot replace the control's visible state or accessible role.\n\nKeep hover effects modest because keyboard and accessibility interaction has no\nhover. Do not reveal the only copy of a destructive or essential action on\nhover. Contextual row actions may become quieter at rest if the same commands\nremain available through selection, keyboard, or a context menu.\n\n### Prefer desktop command surfaces over hover toolbars\n\nUse command frequency and scope to choose where an action lives:\n\n- keep the primary or frequent action visible as a labeled Button or familiar\n  toolbar control;\n- put secondary actions for the current region behind a visible\n  `DropdownMenu` trigger;\n- put commands that act on the object under the pointer in a `ContextMenu`;\n- expose the same important command through an [Action](./action)/[key binding](./keybinding) when it has a\n  natural keyboard form;\n- use a hover-revealed icon only as a shortcut to a command that remains\n  reachable elsewhere.\n\nThis is more than a visual preference. GPUI Component's menu system already\nowns directional keyboard navigation, confirmation and cancellation, disabled\nitems, separators, submenus, shortcut presentation, focus transfer and\nrestoration, and nested-menu dismissal. A custom strip of hover buttons must\nrebuild those behaviors and is invisible to keyboard-only and many assistive\ntechnology workflows.\n\nChoose `DropdownMenu` when users need a visible indication that more commands\nexist—for example a toolbar overflow, document actions, or account menu. Choose\n`ContextMenu` for selection- or object-scoped commands such as rename,\nduplicate, reveal, or remove. The context menu must not be the only way to\nperform an essential command; provide a menu-bar, toolbar, keyboard, or detail\nview path as appropriate.\n\nDo not put every action into a menu to make a screen look minimal. Discovery\nand speed matter: the main action stays visible, dangerous items remain clearly\nlabeled and separated, and a menu item should use the same verb, icon, shortcut,\nenabled state, and result everywhere it appears.\n\n### Button means application action; Link means external resource\n\nUse a Button when activation changes application state, confirms a decision,\nopens a tool, submits data, or runs a command. Choose its treatment by local\nhierarchy:\n\n- primary Button for the one emphasized commitment in a decision area;\n- default Button for ordinary visible actions;\n- outline Button when an action needs a clear boundary with less emphasis;\n- ghost Button for familiar, low-emphasis toolbar and inline actions;\n- icon Button only for a well-known symbol, with an accessible name and a\n  tooltip when meaning or scope is unclear.\n\nDo not assign primary because a Button is the only action on screen, because it\nis placed at the top right, or because the team wants more clicks. Primary\ncommunicates default commitment and keyboard behavior. If activation is merely\nan ordinary command such as adding an item, opening a tool, or refreshing a\nview, use a default, outline, or ghost Button according to its local hierarchy.\n\nUse an underlined Link only for an external resource target: a URL, web page,\nonline documentation, or email address. It uses the pointing-hand cursor\nbecause its contract is leaving the current application context for that\nresource. Do not use Link styling to make a functional command look quiet. A\nlink-shaped Delete, Save, Refresh, Add, Open-menu, or in-app navigation action\nhides the control's affordance and exposes the wrong accessibility role.\n\n“View” does not make an in-app destination a Link. A full report, analysis,\ndetails panel, or local record still opens through a Button, row, card, tab, or\ndisclosure control. Use concise context-aware labels such as `Full analysis`\nwhen the containing card already establishes what opens; reserve underlining\nfor a resource that actually opens in a browser or mail client.\n\nAll internal navigation—sidebar rows, tabs, breadcrumbs, list items, opening a\nlocal view, or switching workspaces—must use the corresponding native component\nor a Button/Action. Visual emphasis is chosen through Button variant or the\nnavigation component's selected state, never by lying about semantics.\n\n## Feedback and overlays\n\nChoose the smallest surface that fits the decision:\n\n- tooltip: a short explanation or shortcut;\n- popover: contextual controls that do not interrupt the task;\n- menu: a compact list of actions;\n- notification: asynchronous status that does not require a decision;\n- dialog: a focused decision or short form;\n- alert dialog: explicit confirmation of a consequential action;\n- sheet: supplementary work that benefits from more persistent space.\n\nA tooltip supplies missing meaning; it does not restate an obvious action.\nReserve it for an unfamiliar symbol, ambiguous scope, or a useful shortcut\nthat is otherwise hidden. Repeated, recognizable commands such as Copy and\nDownload in a message footer need accessible names and keyboard access, but\ntheir hover labels add interruption rather than clarity.\n\nAn Alert interrupts the visual hierarchy even when it does not open a modal.\nUse it for important, exceptional information that needs attention in the\ncurrent task, not as a decorated container for ordinary descriptions, tips, or\nempty space. Prefer inline help, muted text, or a normal section when the\ncontent does not require immediate notice or action.\n\nAvoid stacking overlays. Escape should dismiss the topmost dismissible layer,\nand focus should return to the trigger or the next logical target.\n\nAn overlay action must refer to an object or state the overlay actually shows.\nFor example, expose `Clear history` only when a distinct recent-history section\nis visible and contains entries. Search results, recent items, and favorites\nare different collections; label and separate them instead of merging them\ninto one unexplained list. Hide an inapplicable action or disable it with a\nuseful reason—do not park an ambiguous trash icon in a footer.\n\nFooter space is not a catch-all for capabilities that lacked a place in the\ndesign. A footer may present shortcuts, status, or actions that apply to the\nwhole surface, but each item must answer: what is its object, why is it\navailable now, what scope does it affect, and what visible state changes after\nactivation?\n\n## Motion\n\nMotion explains change; it is not ambient decoration. Use short transitions for\nappearance, dismissal, expansion, and spatial continuity. Avoid animating large\nlayout changes when opacity or transform communicates the same relationship.\nHonor reduced-motion preferences, never require animation to understand state,\nand do not add a default animation to every component.\n\nMotion policy belongs to the styled or application layer. Base may own the\nlifecycle mechanism or geometry needed for a transition, but it should not\ndecide that every product fades or slides. Give independently animated values\nstable identity, and make interruption reverse smoothly from the currently\nsampled value rather than restarting from an old endpoint.\n\nMotion follows the continuity of the interaction. While a pointer or scroll\nposition moves among related targets, keep the preview surface stable and\nupdate its content or position in place. Dismiss it only after the interaction\nends; repeated fade-out and re-entry on each update reads as flicker.\n\n## Designing data-heavy interfaces\n\nDense does not mean cramped. In tables, trees, command palettes, editors, and\ndocks:\n\n- keep headers and primary row identity visually stable;\n- align comparable values and use tabular numerals where appropriate;\n- distinguish focus, hover, active row, and multi-selection;\n- keep sorting and filtering visible and reversible;\n- preserve selection by domain identity across filtering and reordering;\n- virtualize large collections without changing keyboard semantics;\n- use progressive disclosure for secondary columns and inspectors;\n- provide a useful empty state that explains the next action.\n\nChoose a table for comparison across consistent fields, a list for scanning\nheterogeneous items, a tree for real hierarchy, and a dock only when users need\nto arrange long-lived tools or documents. Do not use a complex data component\nas a visual style.\n\n## Interface language\n\nWords are part of the interface architecture. Write the vocabulary for a\nfeature as a system—destinations, objects, commands, states, and outcomes—not as\nisolated translations of implementation features. Prefer the shortest wording\nthat remains accurate in its actual context.\n\n### Let context carry context\n\nDo not repeat information that the surrounding surface already establishes. A\nsidebar destination is usually the object or domain itself: use `Users`, not\n`User Management`; `Shortcuts`, not `Shortcut Configuration Management`. A\ncolumn whose rows already contain actions can omit a generic `Operation`\nheading. A dialog titled `Delete “Roadmap”?` does not need body text that asks\nthe same question again.\n\nThis is context economy, not deletion for its own sake. Add text when it changes\nthe decision: identify the affected scope, an irreversible consequence, an\nunusual prerequisite, or a way to recover. Every extra word should answer a\nquestion the current layout does not already answer.\n\nUse nouns for destinations and objects (`Users`, `Appearance`, `Orders`), verbs\nfor commands (`Save`, `Duplicate`, `Export`), and adjectives or short phrases\nfor states (`Offline`, `Up to date`, `Pending review`). Avoid wrappers such as\n`Management`, `Module`, `Page`, `Function`, `Operation`, and `System` unless the\nword distinguishes a real domain concept.\n\n### Write each language, do not translate its shape\n\nStart from shared intent, hierarchy, and terminology, then compose each locale\nas natural interface language. Do not preserve the source language's word\norder, number of words, politeness filler, or grammatical category. English\n`Users` can express a Chinese feature concept that would literally expand to\n“user management”; fidelity means preserving purpose, not preserving tokens.\n\nRemove words supplied by the enclosing information architecture. Inside a\n`Settings` surface, a destination is often simply `Account`, not `Account\nSettings` and never the unnatural singular `Account Setting`. The correct\nEnglish label is chosen from its role and neighbors, not from the standalone\nsource phrase.\n\nMaintain a small product lexicon for recurring objects, commands, and states.\nUse the same term in the toolbar, menu, context menu, dialog, shortcut search,\nand documentation unless the context genuinely changes its meaning. Review\ncopy in the rendered surface: neighboring labels often reveal repetition or\ninconsistent scope that a locale file cannot.\n\nIn localized technical writing, preserve an established framework term when a\ntranslation would be less precise. Keep API identifiers in their original form\nand format them as code. Do not retain ordinary foreign words merely to sound\ntechnical. Explain a retained term on first use when needed, then use the same\nform throughout the interface, documentation, and API examples.\n\nIn documentation, use the exact English name for a named API, component,\nsource file, or guide in link text, including localized pages. For example,\nwrite `Font`, `Render`, `Input element`, and `Plot label` rather than translating\ntheir names or adding a redundant `GPUI Kit` prefix. Keep surrounding explanations in the\npage's language. Link only the named target; place words such as “source”\noutside the link when they describe why it is cited.\n\nIn a technical comparison table shared across locales, keep capability names,\nframework names, API names, and model names in their established English form.\nTranslate the explanation around the table, not its technical labels. Common\ninterface words with an established local name may still be localized outside\nthat comparison context.\n\n### Buttons and confirmation dialogs\n\nButton labels are short by default—usually one or two words—and describe the\nresult, not the gesture or the component. Prefer `Save`, `Move`, or `Delete` to\n`Click to save`, `Perform move`, or `Confirm deletion`. Use `Cancel` consistently\nfor the action that leaves without committing. Reserve `OK` for acknowledging\npurely informational content.\n\nShort is a default, not a character limit. A deliberately longer label is\nbetter when its words expose a consequence or distinguish choices that users\ncould otherwise confuse, for example `Delete from this group` versus `Delete\neverywhere`, or `Restart without saving`. Length must buy decision-critical\ninformation; it must not restate the dialog title or body.\n\nUse the most specific concise result as the confirmation label when possible:\n\n| Context | Weak | Prefer |\n| --- | --- | --- |\n| Delete dialog | `Yes`, `Sure`, `Confirm deletion` | `Delete` |\n| Unsaved changes | `Confirm`, `Yes` | `Discard changes` |\n| Pure acknowledgement | `Confirm operation` | `OK` or `Done` |\n| Complex consent whose result has no clear verb | `Yes` | `Confirm` |\n\n`Confirm` is a useful fallback when the surrounding dialog fully names a\ncomplex commitment and no shorter result verb is accurate. It should not\nreplace a clear command. `Sure` is conversational rather than a stable English\ncommand and is too ambiguous for the standard vocabulary.\n\nA confirmation dialog should form one compact decision:\n\n- title: the decision or condition, such as `Delete “Roadmap”?`;\n- body: only new scope, consequence, or recovery information;\n- actions: `Cancel` and the result, such as `Delete`;\n- destructive styling: applied to the destructive result, not substituted for\n  precise wording.\n\nAvoid generic titles such as `Notice`, `Warning`, `Error`, and `Confirmation`\nwhen the actual condition can be named. Avoid ritual phrases such as “Are you\nsure you want to…”, “Would you like to…”, “Please note that…”, and “successfully”\nwhen the structure or state already communicates them. Courtesy should come\nfrom a calm, respectful tone, not repeated `please`.\n\n### Capitalization, punctuation, and symbols\n\nUse sentence case for English UI by default: `Reset layout`, not `Reset Layout`\nor `RESET LAYOUT`. Preserve proper nouns and established acronyms. Follow a\nplatform convention such as title case for native menu commands only when the\nplatform integration benefits from it, and apply that convention consistently\nwithin the component class.\n\nALL CAPS can provide restrained typographic emphasis for very short section\nlabels, eyebrows, statuses, established acronyms, and code-like identifiers.\nIts compact shape and measured tracking can form a level similar to bold type,\nbut it does not belong on Buttons, long headings, sentences, or dense lists. Do\nnot combine uppercase, strong color, and bold weight in the same region, and do\nnot transform every string automatically: product names, acronyms, and localized\ncontent must preserve their intended casing.\n\nLabels, buttons, menu items, tabs, headings, placeholders, and short states do\nnot take a final period. Complete explanatory, warning, and error sentences do.\nAvoid exclamation marks in routine success and failure messages. In Chinese,\nuse full-width punctuation in sentences and omit terminal punctuation from\nshort control labels by the same semantic rule.\n\nUse the single ellipsis character (`…`), not three periods. Append it to every\nButton or MenuItem that opens a dialog, sheet, or separate window, and to a\ncommand that requires more input or choices before it can complete, such as\n`Settings…` or `Export…`. An immediately executed command does not take an\nellipsis. Use an indeterminate progress indicator, not decorative dots, to\ncommunicate ongoing work.\n\nErrors should say what happened and, when useful, the next recovery action.\nSuccess feedback should name the resulting state only when that state is not\nalready visible. Prefer `Couldn’t save. Check your connection and try again.`\nto a technical code or a long apology; omit a `Saved successfully` toast when\nthe document visibly becomes saved.\n\n## Internationalization and platform fit\n\nAccessibility (A11y) names and labels may remain in English; localization is\nnot required for these strings. Keep the item's own label when naming a control\nthat acts on it, even when that label is localized. This exception does not\napply to visible UI copy.\n\nCopy must survive expansion, CJK typography, and different shortcut notation.\nDo not size a control from one English label. Keep text out of raster assets,\navoid concatenating translated fragments, and let labels wrap or truncate only\nwhere the product defines a recovery path such as a tooltip.\n\nRespect platform differences that carry meaning: Command versus Control,\nnative window decorations, system appearance, scrollbar behavior, menus, and\nnotification capabilities. Keep the product's information architecture stable\nacross platforms, but do not erase familiar platform behavior for superficial\npixel equality.\n\n## Guidance for AI-generated interfaces\n\nAn AI changing a GPUI interface should first inspect the nearest feature,\ntheme tokens, and component documentation. It should state the primary task,\nstate owner, component composition, and keyboard path before generating code.\nIt must not infer an API from React/Shadcn examples or invent a GPUI method\nbecause the name seems plausible.\n\nAI output is incomplete until a human can explain why the hierarchy, density,\ncomponent choice, and exceptional literal values belong in this product. A\nvisually plausible screenshot is not proof: keyboard behavior, focus, dynamic\ncontent, themes, resizing, and failure states are part of the design.\n\n## Accessibility checklist\n\nBefore considering a screen complete, verify that:\n\n- every action is reachable and operable by keyboard;\n- focus or\n\n<!-- [TRUNCATED AT 50KB] -->","frontmatter":{"title":"Design Guides","description":"Product and interaction design guidance for GPUI Kit applications","order":-12},"isInternal":false,"tokens":10244,"sizeBytes":50126},{"name":"SKILL.md","path":"skills/gpui-kit-design-guides/SKILL.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit-design-guides/SKILL.md","title":"gpui-kit-design-guides","category":"anthropic-skill","format":"markdown","content":"---\nname: gpui-kit-design-guides\ndescription: The normative Design Guides for GPUI Kit desktop applications. Read in full before designing or changing any screen, layout, spacing, visual hierarchy, color, density, component choice, interaction state, overlay, motion, data-heavy view, or interface copy in a GPUI Kit (gpui-kit / gpui-component) application, and before reviewing UI work for design quality. Also use when asked what the design rules are, or whether a UI decision follows them.\n---\n\n# GPUI Kit Design Guides\n\nThe guide is [references/design-guides.md](references/design-guides.md). It is\na requirement, not inspiration. Read the guide file itself before doing UI\nwork. Do not answer from this page, from an existing screen in the codebase, or\nfrom training data.\n\nIf the file is missing, fetch `https://gpui-kit.com/docs/design-guides.md`.\nThe guide is a verbatim copy of that page, so its link to `./coding-guides.md`\nmeans the Coding Guides in the `gpui-kit` skill (or `https://gpui-kit.com/docs/coding-guides.md`).\n\n## How to read it\n\nRead the whole guide for a new screen or a redesign. For a narrow change, read\n\"Design thesis\" and \"Start from the task\" first, then the section for the\nchange. Sections, in order (`grep -n '^## ' references/design-guides.md`):\n\n| Section                              | Read when                                                              |\n| ------------------------------------ | ---------------------------------------------------------------------- |\n| Design thesis                        | Always                                                                 |\n| Learning from Shadcn                 | Choosing what to borrow from web component libraries                   |\n| Start from the task                  | Always; task hierarchy, interaction promise, what to leave out         |\n| Visual language                      | Color, typography, spacing, radius, borders, elevation, density, icons |\n| Layout patterns                      | Window structure, sidebars, toolbars, panels, forms, resizable regions |\n| Components and composition           | Picking a component, composing parts, when to build a new one          |\n| Interaction states                   | Hover, focus, pressed, selected, disabled, loading, validation, danger |\n| Feedback and overlays                | Dialog, sheet, popover, menu, notification, tooltip, dismissal, focus  |\n| Motion                               | Any animation or transition                                            |\n| Designing data-heavy interfaces      | Tables, lists, trees, dashboards, dense inspectors                     |\n| Interface language                   | Any user-facing text: labels, buttons, titles, errors, empty states    |\n| Internationalization and platform fit | Multi-locale copy, Chinese terminology, macOS/Windows conventions     |\n| Guidance for AI-generated interfaces | Always when an agent produces UI                                       |\n| Accessibility checklist              | Before finishing                                                       |\n| Design review checklist              | Before finishing; run every item against the work                     |\n\n## Non-negotiables\n\nA floor, not a substitute for the guide.\n\n- **Desktop before web convention.** Keyboard access, window chrome, menus,\n  dense data views, resizable regions, persistent navigation.\n- **`Button` vs `Link`.** `Button` for every in-app command, `ghost` or\n  `outline` when it should read quietly. `Link` only for external URLs and\n  email addresses.\n- **Tokens before values.** No raw hex or `rgb(...)`; use `cx.theme()`\n  semantic tokens and rem-based helpers. Any spacing number quoted in the guide\n  is the current default scale, not a literal to repeat.\n- **State must be visible.** Hover, focus, selection, disabled, loading,\n  validation, and destructive states each need distinct, consistent treatment.\n- **Overlays.** Escape dismisses the topmost surface and returns focus to its\n  trigger.\n- **Copy.** Name the object and the verb: `Delete \"Roadmap\"?` with a `Delete`\n  button, not `Are you sure?` with `OK`.\n\nFinish by running the Design review checklist against the work.\n","frontmatter":{"name":"gpui-kit-design-guides","description":"The normative Design Guides for GPUI Kit desktop applications. Read in full before designing or changing any screen, layout, spacing, visual hierarchy, color, density, component choice, interaction state, overlay, motion, data-heavy view, or interface copy in a GPUI Kit (gpui-kit / gpui-component) application, and before reviewing UI work for design quality. Also use when asked what the design rules are, or whether a UI decision follows them."},"isInternal":false,"tokens":835,"sizeBytes":4219},{"name":"coding-guides.md","path":"skills/gpui-kit/references/coding-guides.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/coding-guides.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"---\ntitle: Coding Guides\ndescription: Architecture and coding conventions for maintainable GPUI Kit applications\norder: -13\n---\n\n# Coding Guides\n\nThis guide describes the application architecture and code patterns that have\nproved durable in GPUI Kit. It is written for both engineers and coding\nagents. Read [Design Guides](./design-guides.md) first: code structure should\npreserve product intent, not replace it.\n\nThis is a normative guide. **Must** marks lifecycle, correctness, or ecosystem\nconstraints; **should** is the default architecture and requires a concrete\nreason to depart from it. Current source and API docs remain authoritative for\nexact signatures.\n\n## Architecture at a glance\n\n<img class=\"architecture-light\" src=\"/application-layers-light.svg?v=20260822-16\" alt=\"GPUI application architecture layers\">\n<img class=\"architecture-dark\" src=\"/application-layers-dark.svg?v=20260822-16\" alt=\"GPUI application architecture layers\">\n\nDependencies point downward. Higher layers own domain meaning and orchestration;\nlower layers own reusable presentation or behavior. Do not make a reusable\ncomponent depend on an application screen, or make `gpui-base` depend on a\ntheme from GPUI Component.\n\nUse these boundaries:\n\n- **app shell:** compose windows and feature crates while keeping feature logic out;\n- **feature crate:** keep one capability's model, services, views, commands, dialogs,\n  and workflow behind one public boundary;\n- **app component:** a repeated domain-aware pattern;\n- **gpui-component:** themed, general-purpose UI;\n- **gpui-base:** reusable behavior and geometry without product presentation.\n\n### Organize large applications by capability\n\nIn a large Rust application, a feature should usually be a crate, not another\nfile in a global `views`, `models`, or `modals` directory. Keep the model,\nviews, commands, dialogs, and workflow for one capability together. A dialog\nthat edits a workspace belongs to the workspace feature; only the reusable\ndialog primitive belongs to the UI library.\n\n```text\ncrates/\n├── app/\n│   └── src/main.rs             # Compose windows and features\n├── workspace/\n│   └── src/\n│       ├── lib.rs              # The feature's public boundary\n│       ├── model.rs\n│       ├── commands.rs\n│       ├── workspace_view.rs\n│       └── rename_dialog.rs\n├── search/\n│   └── src/\n│       ├── lib.rs\n│       ├── model.rs\n│       ├── commands.rs\n│       ├── search_view.rs\n│       └── filters.rs\n├── settings/\n│   └── src/\n│       ├── lib.rs\n│       ├── model.rs\n│       ├── settings_view.rs\n│       └── account_dialog.rs\n└── shared/\n    └── src/\n        ├── lib.rs\n        └── recent_items.rs     # A stable capability with multiple owners\n```\n\nDo not invert this into global `models/`, `views/`, `modals/`, and `commands/`\ndirectories. Those folders classify files by implementation role while\nscattering every feature across the application.\n\nThe application shell composes feature crates but contains little feature\nlogic. A feature may depend on stable shared capabilities and UI foundations;\nit must not depend on the shell or reach into a sibling feature's internals.\nWhen two features need to communicate, prefer an explicit command, event, data\ntype, or small shared service over a dependency between their views. Extract a\nshared crate only after the capability has a coherent name and more than one\nreal owner.\n\nCrate boundaries are engineering boundaries. They let Cargo rebuild and test a\nsmaller dependency subgraph, make ownership visible in `Cargo.toml`, and limit\nthe review and regression surface of a change. They also make removal honest:\na feature that cannot be detached without searching through global view and\nmodal directories was never isolated.\n\nDo not create a crate for every screen or helper. Split where a capability has\nits own state and lifecycle, a stable public seam, or enough implementation to\nbenefit from independent compilation and tests. Keep dependencies acyclic and\npointing toward smaller, more stable crates.\n\n## Bootstrap and root ownership\n\nInitialize GPUI Component once, before creating component-backed views, and put\n`Root` at the first level of each window:\n\n```rust\napp.run(move |cx| {\n    gpui_kit::init(cx);\n\n    gpui_kit::open_window(WindowOptions::default(), cx, |window, cx| {\n        cx.new(|cx| Workspace::new(window, cx))\n    })\n    .expect(\"failed to open window\");\n});\n```\n\n`Root` coordinates window-level component facilities such as overlays and\nnotifications. Do not create a separate root for each page inside one window.\nIt also coordinates modal focus restoration, focus traps, tooltip/menu layers,\nand window-scoped text selection. Bypassing it can produce behavior that looks\ncorrect at rest but fails when overlays nest or focus changes quickly.\n\n## Understand GPUI's phases and contexts\n\nGPUI is retained state with declarative rendering. An entity survives across\nframes; the element tree returned by `render` is a fresh description of the\ncurrent frame. Keep that distinction explicit.\n\n- `Context<Self>` mutates the current entity, creates listeners tied to it,\n  emits its events, and notifies its observers.\n- `App` gives access to application globals and entity reads/updates without\n  implying ownership by the rendered element.\n- `Window` owns focus, actions, input dispatch, element-keyed state,\n  measurement, and animation-frame requests for that window.\n- layout, prepaint, and paint are later phases; use their hooks only when\n  resolved geometry is genuinely required.\n\nNever retain `&mut Window`, `&mut App`, or `&mut Context<_>` beyond the call in\nwhich it is provided. Retain typed handles—`Entity`, `WeakEntity`,\n`FocusHandle`, scroll handles, or domain IDs—instead.\n\n## Choose the right unit\n\n### Use `RenderOnce` for value-like elements\n\nUse a `RenderOnce`/`IntoElement` component when all inputs can be supplied by\nthe caller and the element does not need to retain application state between\nframes. This is the normal choice for presentational wrappers and small\ncontrols.\n\n```rust\n#[derive(IntoElement)]\nstruct EmptyState {\n    title: SharedString,\n}\n\nimpl RenderOnce for EmptyState {\n    fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {\n        div()\n            .v_flex()\n            .gap_2()\n            .items_center()\n            .text_color(cx.theme().muted_foreground)\n            .child(self.title)\n    }\n}\n```\n\n### Use `Entity<T>` for retained behavior\n\nUse an entity-backed `Render` view when behavior spans frames or needs\nobservation, subscriptions, focus, async work, history, measurement, or\nincremental updates. Store entities in an owning view rather than recreating\nthem in `render`.\n\n```rust\nstruct SearchView {\n    query: Entity<InputState>,\n}\n\nimpl SearchView {\n    fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let query = cx.new(|cx| InputState::new(window, cx).placeholder(\"Search…\"));\n        Self { query }\n    }\n}\n```\n\nDo not turn every visual fragment into an entity. Entity boundaries have\nlifecycle and coordination costs; use them where retained identity matters.\n\n### Elements, views, and behavior systems are different\n\nDo not force every component into one template. The ecosystem contains:\n\n- semantic elements such as Button, Checkbox, Link, and Tabs;\n- compound behavior roots such as Dialog, Popover, Select, and Combobox;\n- entity-backed systems such as Input, Table, Tree, Dock, and notifications;\n- infrastructure such as positioning, virtualization, scrolling, focus traps,\n  motion, history, and measurement.\n\nAn element may be internally complex and still be value-like to its caller. A\nstateful system may expose render callbacks so applications own presentation\nwithout reimplementing behavior. Choose the public seam from the behavior,\nnot from how many `div`s appear in its renderer.\n\n## State ownership\n\nPut each state in the narrowest owner that can keep it correct:\n\n- domain state belongs to a model or feature view;\n- transient view state belongs to the view that renders it;\n- reusable behavioral state belongs to the component state designed for it;\n- tiny element-local state may use GPUI keyed element state;\n- shared application services may be stored as GPUI globals.\n\nPrefer controlled values for ordinary selection and toggles: pass the current\nvalue into the component, receive a requested change, update the owner, and\nrender again. A callback reports intent; it should not create a second hidden\nsource of truth.\n\n```rust\nCheckbox::new(\"show-hidden\")\n    .checked(self.show_hidden)\n    .label(\"Show hidden files\")\n    .on_click(cx.listener(|this, checked, _, cx| {\n        this.show_hidden = *checked;\n        cx.notify();\n    }))\n```\n\nCall `cx.notify()` after a mutation that changes rendering. Use `cx.emit(...)`\nfor a semantic event that an owner should handle, and `cx.subscribe(...)` or\n`cx.observe(...)` when the lifetime should follow an entity. Keep returned\nsubscriptions alive when the API requires it.\n\nDo not notify merely because a value was read or derived. Avoid unconditional\nnotification from `render`; it schedules another render and can create a\npermanent redraw loop. When several fields form one invariant, update them\ntogether and notify once. A reusable state type that cannot receive a context\nshould make that limitation explicit and require its owner to emit/notify.\n\n### Avoid state feedback loops\n\nText input, selection, filters, and controlled popups commonly have two paths:\nan external owner updates the value, and user interaction requests a new value.\nDo not send an owner-supplied value back through the user callback during sync.\nTrack the origin or compare coherent snapshots so each logical change is\nreported once. Make callbacks re-entrancy-safe when a callback can synchronously\nclose, replace, or update the component that invoked it.\n\n## Stable identity\n\nAn `ElementId` is part of behavior. It gives an element stable identity and keys\nelement-local or component state. A component may also use it as one input to\nits own focus, measurement, or animation identity; focus and scrolling are\notherwise owned by their dedicated handles.\n\n- Use stable domain IDs for rows, tabs, tree nodes, and repeated controls.\n- Namespace child IDs with their owning object when the same control repeats.\n- Never derive identity from a translated label or a mutable list index when\n  items can be inserted or reordered.\n- Do not generate a fresh random ID during `render`.\n\n```rust\nButton::new((\"delete-project\", project.id))\n    .danger()\n    .label(\"Delete\")\n```\n\nA changed ID means a changed UI identity. Treat that reset as deliberate.\n\nThe same rule applies to transition channels, overlay tokens, scroll handles,\nand persistence IDs. If two independently retained behaviors share a key, they\ncan overwrite each other's state; if one behavior changes keys every frame, it\nnever accumulates state.\n\n## Rendering and composition\n\nKeep `render` declarative: read current state, derive presentation values, and\ncompose elements. Move domain operations, parsing, and non-trivial mutation to\nnamed methods or services.\n\n```rust\nimpl Render for ProjectView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .v_flex()\n            .size_full()\n            .child(self.render_toolbar(cx))\n            .child(self.render_content(cx))\n    }\n}\n```\n\nExtract a render helper when it names a meaningful region and reduces the\namount of state a reader must hold at once. Extract a new component when the\nregion has its own reusable contract or retained lifecycle—not merely because\na builder chain is long.\n\nUse GPUI Component's fluent traits consistently (`Sizable`, `Disableable`,\n`Selectable`, and component-specific builders). Prefer `.when(...)` and\n`.when_some(...)` for small conditional refinements; use ordinary Rust control\nflow when branches represent substantially different interfaces.\n\nCompose from the standard semantic component before building a custom surface.\nDo not reproduce a menu, select, dropdown, or command palette from generic\n`div`s merely to match one screenshot. Reusing the component preserves its\nitem geometry, focus transfer, keyboard navigation, selection, disabled state,\ndismissal, and accessibility contract. If the standard component cannot\nexpress a recurring valid pattern, improve its explicit API instead of styling\narbitrary descendants at each call site.\n\nRender callbacks supplied by application code should be side-effect-free. A\nlist item renderer, menu builder, or dock panel renderer may run whenever its\nowner needs to measure or redraw. It must not perform a business operation,\nappend data, or register an unbounded subscription.\n\n## Behavior and presentation boundary\n\nThe durable Base rule is:\n\n> Base owns reusable behavior and the geometry required to implement it. The\n> presentation layer owns the product's visual language.\n\n“Headless” does not mean “one empty `div`.” Popup collision, keyboard\nnavigation, editing, virtualization, resize arithmetic, focus trapping, and\ndock reconciliation require internal structure and state. Moving that work to\nevery caller would not create flexibility; it would duplicate fragile\nbehavior.\n\nConversely, Base must not choose brand colors, typography, density, final\nicons, component variants, or application composition. Expose presentation\nthrough `Styled`, typed semantic-state styles, explicit parts, child slots, and\nitem renderers. Do not inspect arbitrary descendants to discover titles,\ndescriptions, or close buttons—make semantic parts explicit.\n\n## Theme and styling\n\nRead semantic values from the active theme and apply layout with GPUI's\n`Styled` methods:\n\n```rust\ndiv()\n    .bg(cx.theme().background)\n    .text_color(cx.theme().foreground)\n    .border_1()\n    .border_color(cx.theme().border)\n    .rounded(cx.theme().radius)\n```\n\nRules:\n\n- do not hard-code product colors, corner radii, spacing, or control geometry;\n- application code must not introduce raw hex, `rgb`/`rgba`, or `hsla`; read a\n  semantic color from `cx.theme()` or add the missing role to the product theme;\n- application layout should use GPUI's rem-based scale helpers (`p_2()`,\n  `gap_3()`, `w_64()`, `text_sm()`) instead of direct `px(...)` values;\n- use semantic tokens for meaning, not palette position;\n- keep state-independent geometry in the ordinary builder chain;\n- use GPUI `hover`, `active`, `focus`, and `focus_visible` modifiers for\n  runtime interaction states;\n- use a component's semantic state styles for checked, selected, pressed, or\n  disabled appearance;\n- keep popup ownership in explicit state so its trigger can render the open or\n  pressed appearance until dismissal;\n- guard hover/active refinements when a disabled control must not react;\n- keep component variants few and meaningful rather than adding a variant for\n  every call site.\n- bind primary styling to the decision area's real default commit and Enter\n  action; do not derive it from action count, frequency, or toolbar position.\n- keep Badge and Alert variants semantic and scarce. Ordinary metadata stays\n  neutral; do not map every enum case or section to a different color merely\n  because a variant exists.\n\nThe effective precedence is instance style, active semantic value states,\ndisabled state, then GPUI runtime interaction refinements. Later layers only\nreplace fields they set.\n\nPrefer `Theme::semantic_tokens()` for new application-owned presentation. The\nsemantic token surface contains generic color roles plus radius, spacing,\ntypography, and shadow scales; it deliberately avoids component names. Legacy\ncomponent-specific theme values still exist for compatibility but should not\nbecome the extension point for every application widget.\n\nThere is one current ownership caveat: `Theme::spacing_tokens()` projects the\ndefault scale, and `Theme::apply_semantic_tokens(...)` does not store custom\nspacing or elevation scales. An application that customizes those scales must\nretain its own `SemanticThemeTokens` (or narrower design-system state) and make\nthat state available to its components. Do not write a custom spacing snapshot\ninto the global theme and expect a later `cx.theme().semantic_tokens()` call to\nreturn it.\n\nEdit the global GPUI Component theme through `Theme::update(cx, |theme| ...)`.\nThe theme keeps the same colors twice (`colors` as solid colors, `tokens` as\nrenderable backgrounds that may carry a gradient) and the Base layer holds a\nprojection for its scrollbars and resize handles; `update` brings all three\nback in step after the closure and refreshes every window. An edit through\n`Theme::global_mut(cx)` updates only the field you touched — a sidebar can then\npaint its text from the new colors and its background from the old tokens —\nso it owns the rest: derive `tokens` from `colors`, call `Theme::sync_base(cx)`,\nrefresh the windows. `Theme::change(...)` performs the projection as part of a\ncomplete theme change.\n\nAn outward focus ring needs physical room. An ancestor with\n`overflow_hidden()` clips it. Prefer layouts that leave room; if a product must\nclip heavily, use the theme's focus-ring policy and retain the focused border\ninstead of silently hiding all keyboard focus.\n\n### Base font is the application zoom control\n\nThe Component Root plugin calls `window.set_rem_size(cx.theme().font_size)` from\nits `prepare` hook before the Root surface is rendered. Therefore the theme's\nbase font is not only body typography; it is the reference length for the\napplication's rem-based design scale. This deliberately follows the useful part\nof Tailwind's model: named type, spacing, and size steps share one relative base\ninstead of becoming unrelated pixel constants.\n\nChange zoom by updating the base font and refreshing the window:\n\n```rust\nTheme::update(cx, |theme| theme.font_size = px(18.));\n```\n\nThe base font itself is a pixel value because it anchors the scale. Descendant\napplication UI should normally use relative helpers—`text_sm()`, `gap_2()`,\n`px_3()`, `h_8()`, `size_4()`—so type, whitespace, controls, and icons respond\ntogether. A custom component that combines rem-based text with fixed-pixel\npadding or icon geometry must document why that part should not zoom.\n\nTreat every direct `px(...)` and raw color constructor in application UI as a\nreview finding. Accept it only for a documented physical/platform boundary,\nmeasured runtime geometry, raster/data color, or the theme/token definition\nitself. Convenience and matching a screenshot are not valid exceptions.\n\nAnything cached from resolved layout must include `window.rem_size()` in its\ninvalidation key, directly or through a revision that changes with it. This\nincludes wrapped row heights, text shaping/layout, virtual-list measurement,\npopup and dialog geometry, icon sizing derived from text, and custom canvas\nmetrics. The Command component's variable-height rows are an ecosystem example:\nthey remeasure when rem changes because the same fixed width wraps differently\nat a larger base font.\n\nDo not confuse this application zoom with Dock panel zoom. Dock zoom is a\nstateful layout operation that makes one tab group fill the DockArea\nwhile keeping the container chrome and the way back out. It must not modify the\nwindow rem size.\n\n## Events, actions, and focus\n\nUse pointer callbacks for pointer-specific behavior. Use GPUI Actions for\ncommands that should support key bindings, menus, or dispatch from multiple\ninputs. Keep action handlers close to the view that owns the command.\n\nModel one logical desktop command once. A toolbar Button, `DropdownMenu` item,\n`ContextMenu` item, menu-bar item, and key binding should dispatch the same\nAction or call the same owner method instead of copying five mutations. Derive\ntheir label, icon, shortcut, and enabled state from one command policy where\npractical, so the entry points cannot disagree. The menu owns navigation and\ndismissal; the feature owner still owns whether the command is allowed and\nwhat it does.\n\nPreserve semantic roles in the element choice. Use `Button` for commands even\nwhen the desired treatment is quiet—select `outline`, `ghost`, or an icon\npresentation instead of replacing it with `Link`. GPUI Kit applications\nreserve `Link` for targets opened by a browser or mail client, such as a URL,\nweb document, or email address. Use the relevant navigation component for an\nin-app destination and `Button`/`Action` for a command. This is a product\nconvention, not a limitation of `gpui_kit::base::Link`, whose `open_with` seam can\nroute a destination elsewhere.\n\nOnly stop propagation when a nested interaction must prevent its parent from\nhandling the same event. Blanket propagation stops break menus, selection,\ndragging, and window-level commands in ways that are difficult to diagnose.\n\nBind keys before building the menu bar. `cx.set_menus` reads the keymap at\nthe moment it is called and bakes each item's shortcut into the native menu,\nso a binding registered afterwards never shows next to its menu item and the\nitem does not react to the key. Call `cx.bind_keys` first, then\n`cx.set_menus`; if the keymap changes later (a user keymap file, a locale\nswitch that rebuilds the menus), call `cx.set_menus` again.\n\nMake focus ownership explicit:\n\n- retain a `FocusHandle` in the entity that owns keyboard interaction;\n- register key contexts and actions on the appropriate focused region;\n- transfer focus when opening an overlay and restore it on dismissal;\n- render a visible `focus_visible` state;\n- do not request focus unconditionally from `render`.\n\nA tracked handle is a Tab stop only when it says so: build it with\n`cx.focus_handle().tab_stop(true)` (or `.tab_index(n)`), because the element's\nown `tab_index`/`tab_stop` settings do not apply to a handle passed to\n`track_focus`. A stateless component may create that handle in `render`\nthrough `window.use_keyed_state(id, cx, |_, cx| cx.focus_handle().tab_stop(true))`;\nthe keyed state survives re-renders, so the Tab order is stable — this is\nwhat `Button` does.\n\nAttach a `key_context` and its `on_action` handlers to the same focused region.\nBindings are contextual: a registered Action without the intended focus path\nis not a working keyboard interaction. Composite widgets should implement the\ncomplete navigation model—arrow movement, Home/End or page movement where\nappropriate, confirmation, cancellation, and Tab behavior—rather than a few\nisolated shortcuts.\n\nModal surfaces must trap focus and restore the previous valid focus target on\ndismissal. Nested overlays dismiss from the top. Handle rapid close/open\nsequences without restoring focus through an intermediate, already-closing\nsurface.\n\n## Async work and side effects\n\nStart async work from an event, lifecycle hook, or named method—not as an\nunconditional side effect of `render`. Capture weak entities when work should\nnot keep a closed view alive. When the task completes, update state through the\nGPUI context, handle the case where the entity or window no longer exists, and\nnotify once after the coherent state change.\n\nRepresent async operations with explicit states such as idle, loading, loaded,\nand failed. Preserve usable previous data during refresh when possible. Prevent\nduplicate destructive submissions and surface recoverable errors in the UI;\ndo not rely on logs as user feedback.\n\nUse background executors for expensive parsing or computation, but keep GPUI\nentity mutation on the appropriate application context. Results can arrive\nafter the request, document, view, or selection has changed; attach a revision\nor identity and reject stale work rather than applying it to new state.\n\n## Layout, measurement, and scrolling\n\n`h_flex` centres its children on the cross axis; `v_flex` leaves flexbox's\ndefault, `stretch`. This matches Zed's `h_flex`, and it is what a row of\ncontrols wants, so a row of icon and label says nothing. It is not what a row\nof full-height columns wants: a column placed in a bare `h_flex` does not fill\nthe row's height, so a column taller than the row is centred and its top —\ncommonly a header — is clipped off the top of the window, with nothing near the\ncolumn to say why. A row whose children are columns says `items_stretch()`:\n\n```rust\nh_flex()\n    .items_stretch()\n    .size_full()\n    .child(sidebar)\n    .child(content)\n```\n\nMost UI should use GPUI layout rather than measuring itself. Measurement is a\ndeep behavior tool for popups, virtualization, editors, resize handles, charts,\nand similar components whose correctness depends on resolved geometry.\n\n- Put measurement and geometry in the layer that owns the behavior.\n- Observe bounds in prepaint only when ordinary layout cannot express the\n  relationship.\n- Never mutate unrelated application state every prepaint.\n- Treat measured data as frame- or revision-scoped; it can become stale after\n  typography, rem size, width, theme, or content changes.\n- Centralize shared geometry such as popup flipping and viewport clamping so\n  every overlay follows the same edge policy.\n\nFor alignment invariants, prefer construction over correction: sibling regions\nshould consume the same spacing token or shared inset instead of repeating\nequivalent literals. Add geometry assertions or visual regression coverage for\ncritical repeated edges, columns, and gaps. Exercise more than the default\nwindow: rem zoom and display scaling can turn fractional coordinates into a\none-physical-pixel drift even when the default screenshot looks aligned.\n\nMeasure the resolved result when reviewing precision, but do not encode a\nmeasured correction as a raw `px(...)` nudge. Trace the mismatch to duplicated\npadding, nested insets, border ownership, font metrics, or rounding, then fix\nthe structural owner.\n\n`h_flex()` and `v_flex()` are not mirror images: `h_flex()` centers its\nchildren on the cross axis, `v_flex()` leaves them stretching. A column placed\nin a row therefore takes its content's height, not the row's, and a column\ntaller than the row is centered — its header is pushed off the top edge and\nclipped. Give a full-height column `h_full()`, or give the row `items_start()`\nor `items_stretch()`, whenever the child owns a header, a footer, or a scroll\nregion that must resolve against the row's height.\n\nEvery scrollable region must have one owner. In flex layouts, apply\n`min_w_0()` or `min_h_0()` to the flexible child that is allowed to shrink.\nA flex item only drops its content-based automatic minimum size when its own\noverflow is not visible, so an ordinary flexible child refuses to shrink around\nlong content until you say so. `Scrollable` handles this for its own wrapper,\nbut a plain `div` between it and the flex container still needs the minimum\nreleased. Avoid accidental nested scrolling; route wheel input to the intended\naxis and preserve platform/wasm differences when an API is not portable.\n\nAttach `Scrollable` to the element that owns the full panel, editor, or window\nviewport so its scrollbar resolves against the region edge. Put content inset\ninside that scroll owner rather than wrapping the scroll owner in a padded\ncontainer. A scrollbar floating between content and the panel boundary usually\nreveals the wrong scroll owner or padding on the wrong layer.\n\n## Lists, tables, and large data\n\nUse virtualization when data can grow beyond a small, bounded collection. Keep\nrow identity separate from visible position and avoid cloning the full data set\non every render. Let a stateful list or table own navigation, selection, scroll\ncoordination, and visible-range calculation while item renderers own row\npresentation.\n\nSeparate:\n\n- source data and domain IDs;\n- filtering/sorting state;\n- selection state;\n- viewport/scroll state;\n- row rendering.\n\nThis keeps updates local and prevents the view tree from becoming the data\nmodel.\n\nVirtualization is a behavioral contract, not just a performance switch. Item\nmeasurement must be invalidated when width, typography, rem size, or row\ncontent changes. Keyboard selection and scroll-to-item must operate in model\ncoordinates even when most elements do not exist in the current frame.\n\n## Public API design\n\nFor reusable components:\n\n- constructors should establish valid defaults;\n- builders take and return `Self` and use domain language;\n- callbacks describe requested changes and include pointer events only when\n  modifiers or pointer details are meaningful;\n- evolvable behavioral seams use private fields, builders for construction,\n  and readers for inspection;\n- boolean readers use `is_` or `has_` where a same-named builder exists;\n- non-boolean setters use `with_` when readers need the plain field name;\n- explicit compound parts are preferable to inspecting arbitrary descendants;\n- adding reusable behavior must not force a product-level visual choice.\n\nPrivate fields are the default for behavioral state that must evolve without\nbreaking callers. Public fields are appropriate for deliberately record-like\nconfiguration, theme tokens, geometry, and serialized schemas. Every public\nstruct with public fields must carry `#[non_exhaustive]`. Provide constructors,\n`Default`, or builders so callers can create values without exhaustive struct\nliterals. This preserves the ability to add fields without breaking callers.\nApply this rule to new types and public API changes; unrelated existing types\ncan be migrated separately.\n\nKeep public module paths stable while reorganizing internals: use a module seam\nwith deliberate re-exports so folders can change without forcing downstream\nimports to change. Prefer platform control terminology and established project\nnaming over web-framework vocabulary.\n\n## Platform and capability boundaries\n\nDo not assume every native or web target supports the same facility. Window\ndecorations, accessibility bridges, system notifications, clipboard behavior,\nscroll gestures, fonts, and timing can differ. Put platform-specific code\nbehind a narrow capability seam and define the fallback behavior.\n\nA platform branch must preserve the semantic contract even if presentation\ndiffers. For example, a system notification may have different retraction\nsupport, but the application still needs a coherent delivery state. Test both\nthe shared state machine and the platform adapter where possible.\n\n## File and naming conventions\n\n- Name views and entities after product concepts: `ProjectList`,\n  `ProjectEditor`, `SettingsState`.\n- Name event handlers after intent: `confirm_delete`, `open_project`,\n  `on_query_changed`.\n- Keep one main responsibility per module; split a file when state ownership or\n  lifecycle can no longer be understood without reading unrelated behavior.\n- Keep component module, state, events, and focused tests together when they\n  change together.\n- Document invariants and surprising lifecycle constraints; do not narrate\n  obvious builder calls.\n- Use `rustfmt` and satisfy the workspace's Clippy rules. Avoid broad `allow`\n  attributes that conceal unrelated warnings.\n\n### Vocabulary is part of the API\n\nUse the same word for the same concept across components. Before naming a new\nmethod, search GPUI, `gpui-base`, and GPUI Component for the established term;\nprefer macOS/Windows control terminology where the ecosystem has no precedent.\nLocalized documentation preserves exact API identifiers and established UI\nframework terms when translation would reduce precision. Format identifiers as\ncode, explain retained terms when needed, and do not mix languages merely to\nmake ordinary prose sound technical.\n\n| Concept | Naming pattern | Example |\n| --- | --- | --- |\n| Value-like rendered control | noun | `Button`, `Checkbox`, `Tab` |\n| Retained behavioral model | `<Control>State` | `InputState`, `TableState` |\n| Imperative shared reference | `<Control>Handle` | `DialogHandle`, scroll handle |\n| Semantic notification | `<Control>Event` | `TableEvent`, `SelectEvent` |\n| Keyboard command | verb or intent noun | `Confirm`, `Cancel`, `SelectNext` |\n| Pluggable data/behavior owner | `<Role>Delegate` / `<Role>Provider` | `TableDelegate`, `CompletionProvider` |\n| Application-supplied presentation | `render_<part>` or `<part>_renderer` | `render_item` |\n| Construction | `new`, or a semantic constructor | `new`, `horizontal`, `vertical` |\n| Fluent property | noun/adjective | `label`, `disabled`, `selected`, `placement` |\n| General non-boolean replacement builder | `with_<field>` | `with_size`, `with_mode` |\n| In-place mutation | `set_<field>` | `set_items`, `set_selected_index` |\n| Boolean reader | `is_<adjective>` / `has_<noun>` | `is_open`, `is_closable`, `has_selection` |\n| Plain value reader | field noun | `placement`, `selected_value` |\n| Callback registration | `on_<event or intent>` | `on_click`, `on_open_change` |\n| Rendering a named region | `render_<region>` | `render_toolbar`, `render_content` |\n\nFor new APIs, fluent builders omit `set_` because they consume and return\n`Self`; mutation through `&mut self` uses `set_`. Preserve established public\nnames when changing them would cause needless churn. Existing builder names\nsuch as `set_position` are compatibility exceptions, not patterns for new APIs.\n\nA boolean reader is either `has_<noun>`, when the value holds something, or\n`is_<adjective>`, when it describes a state or a permission. Reach for the\nadjective whenever the action has one: `is_closable` over `can_close`,\n`is_zoomable` over `can_zoom`, `is_copyable` over `can_copy`. When the action\nis a verb phrase with no adjective form, name the thing it needs instead:\n`has_definition`, not `can_go_to_definition`. Do not add new `can_` readers.\n\nBoolean builders may use the field name (`disabled(bool)`) while their readers\nuse `is_disabled()`. For a public seam struct containing non-boolean fields,\nuse `with_item_ix(...)` for construction and `item_ix()` for reading so setter\nand getter names never collide. Prefer `_ix` for new local or internal\nzero-based indices, preserve established public terms such as `selected_index`,\nand do not introduce `_idx`. If callers never construct the seam value, do not\npublish a builder merely for symmetry.\n\n### Let the enclosing name carry the context\n\nA name is read inside something. A field is read inside its type and a parameter\ninside its method, so neither repeats what encloses it: `with_item_ix(ix)`, not\n`with_item_ix(item_ix)`.\n\nKeep one type's fields at the same level of abbreviation. A single field spelled\nout in full becomes the odd one out, and a reader goes looking for the\ndistinction that made it different. Because a builder is named `with_<field>`,\nshortening a field shortens its builder with it and the pair stays matched.\n\nShorten only where the enclosing name really does disambiguate. When a short\nform is also the established term for a *different* quantity elsewhere in the\necosystem, say which one you mean in the doc comment rather than lengthening the\nidentifier — the doc is read at the call, and it can explain what a longer name\ncould only hint at.\n\n### Use precise domain words\n\n- **selected** is persistent membership or the active item; **focused** is the\n  current keyboard target; **hovered** is pointer presence; **confirmed** is an\n  activation result. Never use them interchangeably.\n- **open/close** describes an overlay or disclosure state; **show/hide** is for\n  transient presentation requests; **expand/collapse** describes structure.\n- **disabled** prevents interaction; **readonly** permits navigation and\n  selection but prevents editing; **loading** prevents duplicate work while an\n  operation is pending. Spell the state `readonly` — one word, as the\n  `readonly(bool)` builder and `is_readonly()` reader do — in identifiers,\n  interface labels, and documentation alike; never `read-only` or `read only`.\n- **index** is a current positional coordinate; **id** is stable identity;\n  `IndexPath` represents hierarchical position. Do not persist or key\n  reorderable data by index.\n- **value** is controlled domain data; **presentation** is a read-only snapshot\n  prepared for rendering; **state** is retained behavior.\n- **placement** is a side or anchor policy; **position** is resolved geometry.\n- **size** is a semantic control tier; **width/height/bounds** are geometry.\n- **child/children** follows GPUI composition; named slots such as `header`,\n  `footer`, `trigger`, and `content` carry additional semantics.\n\nAvoid vague public names such as `data`, `item2`, `handle_action`, `update_ui`,\n`process`, `manager`, or `config` when a narrower domain term exists. `Manager`\nis appropriate only when a type truly coordinates a collection or lifecycle,\nas `ToastManager` does.\n\n### Type and module style\n\n- Rust types and Actions use `UpperCamelCase`; modules, functions, methods,\n  fields, and local variables use `snake_case`; constants use\n  `SCREAMING_SNAKE_CASE`.\n- A module named after a component owns its public seam. Internal folders may\n  split state, element, geometry, platform adapter, and tests without leaking\n  those folder names into imports.\n- Use singular module names for one component concept and established\n  ecosystem names for families (`input`, `table`, `dock`).\n- Suffix type-erased wrappers with `Any` only when they erase a real type\n  boundary, such as `AnyInputState` or `AnyElement`.\n- Suffix identifiers with `Id`, zero-based indices with `ix`, and collections\n  with meaningful plurals. Do not alternate `idx`, `index`, and `ix` in one\n  subsystem.\n- Name predicates positively when possible. A positive `enabled`/`visible`\n  contract is easier to compose than multiple negatives, but preserve\n  established API terms such as `disabled` where they match control semantics.\n\n### Callback and event wording\n\nUse `on_click` only for a genuine click-level contract. A controlled semantic\nprimitive in Base should prefer `on_change(next_value, ...)`; a styled\ncompatibility component may retain `on_click` when pointer details or existing\nAPI expectations matter. Do not invent a `ClickEvent` for a model-driven\nchange.\n\nName before/after lifecycle hooks precisely. `on_will_change` can veto or\nprepare; `on_change` observes a requested/current value contract; `on_confirm`\ncommits a choice; `on_dismiss` closes a transient surface. Document whether a\ncallback runs before internal state changes, after them, or instead of them,\nand whether it may synchronously re-enter the component.\n\n### Documentation and copy style\n\nPublic docs should begin with what a type does and who owns its state. Examples\nmust use current, compilable APIs and show stable IDs. Document defaults,\nplatform limitations, focus behavior, callback ordering, and any requirement\nto call `notify`, `emit`, or a theme synchronization method.\n\nFollow the [interface-language rules](./design-guides.md#interface-language) for\nlabels, commands, confirmation dialogs, capitalization, and ellipses. Keep one\ncanonical term for each domain object, command, and state.\n\nTranslation keys describe stable intent (`dialog.delete_project.title`), not a\nsource-language sentence or a screen coordinate. Never assemble a sentence\nfrom translated fragments or reuse one key for meanings that happen to share\nthe same English text.\n\nLocalize intent, not syntax. Give every locale control over word order,\npluralization, punctuation, and the amount of context it needs. Review strings\ninside the component and with realistic data. Tests or linting should catch\nmissing keys, unintended CJK text in English resources, three-dot ellipses,\nunreviewed ALL CAPS, and inconsistent fixed terms; human review still decides\nwhether repetition is justified by context. Verify every string inside its\ncomponent with realistic content, text expansion, and application zoom.\n\n## Testing strategy\n\nTest at the lowest layer that can prove the behavior:\n\n1. pure tests for state transitions, geometry, parsing, and ordering;\n2. GPUI context tests for entities, events, and subscriptions;\n3. `VisualTestContext` interaction tests for focus, keyboard, pointer, layout,\n   and rendered state;\n4. example or application smoke tests for complete workflows.\n\nFor an interactive component, cover the semantic contract rather than its\nimplementation details: pointer and keyboard activation, controlled value\nchanges, disabled behavior, focus movement, event count/order, stable identity,\nand important empty or failure states. Add a regression test before fixing a\nbug whenever the failure can be reproduced deterministically.\n\nFor UI behavior that depends on the real window system, test through the\naccessibility tree by role, label, value, enabled state, focus, and selection.\nRe-read the tree after every state-changing action because element indexes are\nsnapshots. Use screenshots for visual facts the semantic tree cannot express;\nuse coordinate input only as a fallback. Report automated and manual evidence\nseparately.\n\n## Performance rules\n\n- Do not mutate state or notify unconditionally in `render`.\n- Avoid rebuilding entities, subscriptions, focus handles, and expensive data\n  structures per frame.\n- Notify the narrowest owning entity after a coherent state change.\n- Virtualize long collections and render only the visible range.\n- Avoid cloning large strings or collections solely to satisfy a closure;\n  capture stable handles or shared data.\n- Measure before adding caches. A cache must have a clear invalidation owner.\n- Keep animation work bounded and honor reduced motion.\n\n## Common failure modes\n\nAvoid these patterns:\n\n- one entity containing the entire application's unrelated state;\n- business logic and network requests embedded in a long `render` method;\n- random or index-based `ElementId` values for reorderable content;\n- literal colors and radii that break custom themes;\n- custom clickable `div`s where a semantic component already supplies focus,\n  keyboard, disabled, and accessibility behavior;\n- duplicated local state that drifts from a controlled model value;\n- `cx.notify()` loops caused by mutation during every render;\n- nested scroll containers without explicit ownership;\n- a new component variant for a one-off screen;\n- confirmation dialogs for reversible, low-risk actions;\n- tests that call internal methods but never exercise keyboard or pointer\n  behavior.\n\n## Rules for coding agents\n\nBefore editing, an agent must read the nearest implementation, its tests, the\nre-export seam, and the relevant component documentation. It must search the\ncurrent source for signatures instead of translating a React, CSS, or old GPUI\nexample by analogy.\n\nFor each change, the agent should be able to name:\n\n1. the behavior owner and presentation owner;\n2. the retained identity and state lifecycle;\n3. the pointer, keyboard, focus, and accessibility contract;\n4. the layout and overflow owner;\n5. the theme tokens and intentional exceptions;\n6. the test that would fail if the behavior regressed.\n\nGenerated code must be reviewed and tested by a person. “Compiles” is not a UI\nquality bar, and a broad refactor that merely makes generated code look tidy is\nnot a substitute for matching the repository's architecture.\n\n## Implementation checklist\n\nBefore opening a change for review, confirm that:\n\n- state and side-effect ownership are explicit;\n- `RenderOnce` versus `Entity<T>` is chosen deliberately;\n- repeated elements have stable domain-based IDs;\n- theme tokens and component sizes replace isolated visual literals;\n- keyboard actions, focus, disabled state, and overlays work together;\n- loading, empty, error, and cancellation paths are represented;\n- long data sets use an appropriate virtualized component;\n- public API additions preserve dependency direction and encapsulation;\n- tests prove behavior at the appropriate layer;\n- formatting, Clippy, targeted tests, and relevant examples pass.\n\nSee [Getting Started](./getting-started.md) for application setup and the\ncomponent pages for current API details.\n","frontmatter":{"title":"Coding Guides","description":"Architecture and coding conventions for maintainable GPUI Kit applications","order":-13},"isInternal":false,"tokens":9325,"sizeBytes":44090},{"name":"conventions.md","path":"skills/gpui-kit/references/conventions.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/conventions.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Component-family conventions\n\nUse this page to predict a component's shape before reading its detailed API. These conventions describe Rust GPUI Component. JavaScript uses its host's generated catalog; a Rust method is not automatically a JavaScript method.\n\n## Choose the family\n\n| Task | Family and constructor | State owner | Event or composition |\n| --- | --- | --- | --- |\n| Execute a command | `Button::new(\"save\")` | Application owns the operation | `on_click` receives a click event |\n| Change a boolean | `Checkbox::new(\"remember\")`, `Switch::new(\"enabled\")`, `Radio::new(\"choice\")` | Application supplies `checked(bool)` | `on_change` receives the requested `&bool` |\n| Choose one radio option | `RadioGroup::new(\"delivery\")` | Application supplies `selected_index(Option<usize>)` | `on_change` receives the requested `&usize` |\n| Edit retained text | `Input::new(&self.input)` | View retains `Entity<InputState>` | Retain the subscription; handle `InputEvent` |\n| Display a supplied patch | `Diff::new(&self.diff)` | View retains `Entity<DiffState>`; application parses supplied unified/Git diff with `DiffFile::parse`; one state shows all files | Readonly `RenderOnce` element; retain subscriptions to `DiffEvent` when needed |\n| Lay out fields | `Form::new()` | Children retain their own state | `child(Field)`, `columns`, `label_layout`, `footer` |\n| Supply a compound part | `Field::new()`, `Tab::new()` | Containing component owns placement/selection | Read the parent's accepted child type |\n\nConstructors establish the component family's ownership model. Do not infer that every `new` takes an ID or that every `child` accepts an arbitrary element. Keep domain IDs stable when controls are reordered. Positional selection APIs remain positional; applications map them to domain identity when needed.\n\n## A value request is different from a command\n\nFor Checkbox, Switch, Radio, and RadioGroup, use the same owner-update pattern:\n\n```rust\nSwitch::new(\"enabled\")\n    .checked(self.enabled)\n    .on_change(cx.listener(|this, next, _, cx| {\n        this.enabled = *next;\n        cx.notify();\n    }))\n```\n\nReplace Switch with Checkbox or Radio without changing the boolean callback shape. Radio represents selecting an option; its activation semantics still differ from toggling a Switch. RadioGroup supplies an index, so its owner stores `Some(*next)` instead.\n\n`on_change` requests a value; it does not mutate your application model. Existing `on_click` calls on these four controls remain valid compatibility aliases. Both names set one handler, and the last call wins. Use `Button::on_click` for commands. Retained controls such as Input keep their existing event/subscription API because the state entity, rather than a transient builder, owns their changes.\n\n## Form layout has independent decisions\n\n| Decision | API | Default |\n| --- | --- | --- |\n| Label above or beside its control | `label_layout(Axis::Vertical / Horizontal)` | Above |\n| Number of field columns | `columns(count)` | One |\n| A field spanning several columns | `Field::col_span(count)` | One |\n| Commands after the fields | `footer(element)` | No footer; supplied footer spans all columns and aligns to the trailing edge |\n\n`Form::horizontal()` and `h_form()` mean labels beside controls. They do not put all fields into one horizontal row. `Form::vertical()`, `v_form()`, and `layout(Axis)` remain supported.\n\n```rust\nForm::new()\n    .label_layout(Axis::Horizontal)\n    .columns(2)\n    .child(Field::new().label(\"Name\").child(Input::new(&self.name)))\n    .child(Field::new().label(\"Email\").child(Input::new(&self.email)))\n    .footer(Button::new(\"save\").label(\"Save\"))\n```\n\nThe footer supplies layout only: attach the save action to the Button. Form does not own submission, validation, responsive breakpoints, or data persistence. Choose column count for the available width. Put multiple action buttons in one supplied action row with a shared gap. Keep field descriptions with their Field so they follow its alignment.\n\n## Import capabilities explicitly\n\nComponents live in their component modules. Common capabilities may be extension traits, not inherent methods: import `ButtonVariants` for button variants, `Sizable` for size tiers, `Disableable` for supported disabled builders, `ActiveTheme` for theme access, and `WindowExt` for window overlays. Do not infer that every component supports every trait.\n\nUse the [complete application recipe](recipes.md) for imports, retained ownership, initialization, Root, and overlay layers. For a narrow task, load its component page and the relevant section of the coding/design guides; a component catalog is not a required reading sequence.\n\n## Verify the convention transfer\n\nWhen transferring a pattern to another family member, check that it compiles, receives the expected requested value, preserves controlled state after redraw, and behaves correctly when disabled. For Form, check label orientation independently of column count and keep footer geometry outside the field grid's individual cells.\n\nIn this repository, `cargo test -p gpui-kit-recipes` compiles the external-style consumer and runs its interaction tests, and `script/check-ai rust` runs the control-family event and compatibility tests and Form geometry tests. These are deterministic contract checks, not measured AI first-attempt success rates.\n","isInternal":false,"tokens":1146,"sizeBytes":5362},{"name":"action.md","path":"skills/gpui-kit/references/gpui/action.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/action.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Actions & Keybindings\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Key Formats](#key-formats) · [Menu Bar Shortcuts](#menu-bar-shortcuts) · [Action Naming](#action-naming) · [Context-Aware Bindings](#context-aware-bindings) · [Best Practices](#best-practices)\n\n## Overview\n\nActions provide declarative keyboard-driven UI interactions in GPUI.\n\n**Key Concepts:**\n- Define actions with `actions!` macro or `#[derive(Action)]`\n- Bind keys with `cx.bind_keys()`\n- Handle with `.on_action()` on elements\n- Context-aware via `key_context()`\n\n## Quick Start\n\n### Simple Actions\n\n```rust\nuse gpui_kit::actions;\n\nactions!(editor, [MoveUp, MoveDown, Save, Quit]);\n\nconst CONTEXT: &str = \"Editor\";\n\npub fn init(cx: &mut App) {\n    cx.bind_keys([\n        KeyBinding::new(\"up\", MoveUp, Some(CONTEXT)),\n        KeyBinding::new(\"down\", MoveDown, Some(CONTEXT)),\n        KeyBinding::new(\"cmd-s\", Save, Some(CONTEXT)),\n        KeyBinding::new(\"cmd-q\", Quit, Some(CONTEXT)),\n    ]);\n}\n\nimpl Render for Editor {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .key_context(CONTEXT)\n            .on_action(cx.listener(Self::move_up))\n            .on_action(cx.listener(Self::move_down))\n            .on_action(cx.listener(Self::save))\n    }\n}\n\nimpl Editor {\n    fn move_up(&mut self, _: &MoveUp, cx: &mut Context<Self>) {\n        // Handle move up\n        cx.notify();\n    }\n\n    fn move_down(&mut self, _: &MoveDown, cx: &mut Context<Self>) {\n        cx.notify();\n    }\n\n    fn save(&mut self, _: &Save, cx: &mut Context<Self>) {\n        // Save logic\n        cx.notify();\n    }\n}\n```\n\n### Actions with Parameters\n\n```rust\n#[derive(Clone, PartialEq, Action, Deserialize)]\n#[action(namespace = editor)]\npub struct InsertText {\n    pub text: String,\n}\n\n#[derive(Action, Clone, PartialEq, Eq, Deserialize)]\n#[action(namespace = editor, no_json)]\npub struct Digit(pub u8);\n\ncx.bind_keys([\n    KeyBinding::new(\"0\", Digit(0), Some(CONTEXT)),\n    KeyBinding::new(\"1\", Digit(1), Some(CONTEXT)),\n    // ...\n]);\n\nimpl Editor {\n    fn on_digit(&mut self, action: &Digit, cx: &mut Context<Self>) {\n        self.insert_digit(action.0, cx);\n    }\n}\n```\n\n## Key Formats\n\n```rust\n// Modifiers\n\"cmd-s\"         // Command (macOS) / Ctrl (Windows/Linux)\n\"ctrl-c\"        // Control\n\"alt-f\"         // Alt\n\"shift-tab\"     // Shift\n\"cmd-ctrl-f\"    // Multiple modifiers\n\n// Keys\n\"a-z\", \"0-9\"    // Letters and numbers\n\"f1-f12\"        // Function keys\n\"up\", \"down\", \"left\", \"right\"\n\"enter\", \"escape\", \"space\", \"tab\"\n\"backspace\", \"delete\"\n\"-\", \"=\", \"[\", \"]\", etc.  // Special characters\n```\n\n## Menu Bar Shortcuts\n\n`cx.set_menus` reads the keymap **at the moment it is called** and bakes each\nitem's shortcut into the native menu. A key bound afterwards never appears next\nto its menu item, and the item does not react to that key. There is no event to\nhook: bind first, then build the menus, and rebuild them when the keymap\nchanges.\n\n```rust\npub fn init(cx: &mut App) {\n    // 1. Bindings first — the menu items copy their shortcuts from these.\n    cx.bind_keys([\n        KeyBinding::new(\"cmd-n\", NewChat, None),\n        KeyBinding::new(\"cmd-,\", OpenSettings, None),\n        KeyBinding::new(\"cmd-q\", Quit, None),\n    ]);\n\n    // 2. Then the menu bar.\n    cx.set_menus(vec![Menu {\n        name: \"File\".into(),\n        items: vec![\n            MenuItem::action(\"New Chat\", NewChat),\n            MenuItem::action(\"Settings…\", OpenSettings),\n            MenuItem::separator(),\n            MenuItem::action(\"Quit\", Quit),\n        ],\n    }]);\n}\n```\n\nCall `cx.set_menus` again after anything that changes bindings or labels: a\nuser keymap file loaded later, a locale switch that renames the items. `Undo`,\n`Redo`, `Cut`, `Copy`, `Paste` need no `on_action` of your own — give the item\nan `OsAction` and the platform forwards it to the focused text control.\n\n## Action Naming\n\nPrefer verb-noun pattern:\n\n```rust\nactions!([\n    OpenFile,      // ✅ Good\n    CloseWindow,   // ✅ Good\n    ToggleSidebar, // ✅ Good\n    Save,          // ✅ Good (common exception)\n]);\n```\n\n## Context-Aware Bindings\n\n```rust\nconst EDITOR_CONTEXT: &str = \"Editor\";\nconst MODAL_CONTEXT: &str = \"Modal\";\n\n// Same key, different contexts\ncx.bind_keys([\n    KeyBinding::new(\"escape\", CloseModal, Some(MODAL_CONTEXT)),\n    KeyBinding::new(\"escape\", ClearSelection, Some(EDITOR_CONTEXT)),\n]);\n\n// Set context on element\ndiv()\n    .key_context(EDITOR_CONTEXT)\n    .child(editor_content)\n```\n\n## Best Practices\n\n### ✅ Use Contexts\n\n```rust\n// ✅ Good: Context-aware\ndiv()\n    .key_context(\"MyComponent\")\n    .on_action(cx.listener(Self::handle))\n```\n\n### ✅ Name Actions Clearly\n\n```rust\n// ✅ Good: Clear intent\nactions!([\n    SaveDocument,\n    CloseTab,\n    TogglePreview,\n]);\n```\n\n### ✅ Handle with Listeners\n\n```rust\n// ✅ Good: Proper handler naming\nimpl MyComponent {\n    fn on_action_save(&mut self, _: &Save, cx: &mut Context<Self>) {\n        // Handle save\n        cx.notify();\n    }\n}\n\ndiv().on_action(cx.listener(Self::on_action_save))\n```\n\n","isInternal":false,"tokens":1347,"sizeBytes":5091},{"name":"async.md","path":"skills/gpui-kit/references/gpui/async.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/async.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Async & Background Tasks\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Core Patterns](#core-patterns) · [Common Pitfalls](#common-pitfalls)\n\n## Overview\n\nGPUI provides integrated async runtime for foreground UI updates and background computation.\n\n**Key Concepts:**\n\n- **Foreground tasks**: UI thread, can update entities (`cx.spawn`)\n- **Background tasks**: Worker threads, CPU-intensive work (`cx.background_spawn`)\n- All entity updates happen on foreground thread\n\n## Quick Start\n\n### Foreground Tasks (UI Updates)\n\nWhen spawned from `Context<Self>`, the closure receives `(WeakEntity<Self>, &mut AsyncApp)`:\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx: &mut AsyncApp| {\n            // Runs on UI thread, can await and update entities\n            let data = fetch_from_api().await;\n\n            this.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            }).ok();\n        }).detach();\n    }\n}\n```\n\nWhen spawned from `&mut App` (not inside an entity), the closure receives only `(cx: &mut AsyncApp)`:\n\n```rust\ncx.spawn(async move |cx: &mut AsyncApp| {\n    // No entity reference\n}).detach();\n```\n\n### Spawn with Window Context (spawn_in)\n\nUse `spawn_in` when the task also needs window access (`update_in`):\n\n```rust\nimpl MyComponent {\n    fn animate(&mut self, window: &mut Window, cx: &mut Context<Self>) {\n        cx.spawn_in(window, async move |this, cx| {\n            // cx here is AsyncWindowContext\n            this.update_in(cx, |state, window, cx| {\n                // Can access window here\n                state.frame += 1;\n                cx.notify();\n            }).ok();\n        }).detach();\n    }\n}\n```\n\n### Background Tasks (Heavy Work)\n\n```rust\nimpl MyComponent {\n    fn process_file(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            // Runs on background thread, CPU-intensive\n            let result = cx\n                .background_spawn(async move { heavy_computation() })\n                .await;\n\n            // Back on the foreground to update UI\n            this.update(cx, |state, cx| {\n                state.result = result;\n                cx.notify();\n            }).ok();\n        })\n        .detach();\n    }\n}\n```\n\n### Task Management\n\n```rust\nstruct MyView {\n    _task: Task<()>,  // Prefix with _ if stored but not accessed\n}\n\nimpl MyView {\n    fn new(cx: &mut Context<Self>) -> Self {\n        let _task = cx.spawn(async move |this, cx: &mut AsyncApp| {\n            // Task automatically cancelled when dropped\n            loop {\n                cx.background_executor().timer(Duration::from_secs(1)).await;\n\n                this.update(cx, |state, cx| {\n                    state.tick();\n                    cx.notify();\n                }).ok();\n            }\n        });\n\n        Self { _task }\n    }\n}\n```\n\n## Core Patterns\n\n### 1. Async Data Fetching (from Context<Self>)\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    let data = fetch_data().await?;\n    this.update(cx, |state, cx| {\n        state.data = Some(data);\n        cx.notify();\n    })?;\n    Ok::<_, anyhow::Error>(())\n}).detach();\n```\n\n### 2. Background Computation + UI Update\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    let result = cx.background_spawn(async move { heavy_work() }).await;\n    this.update(cx, |state, cx| {\n        state.result = result;\n        cx.notify();\n    }).ok();\n})\n.detach();\n```\n\n### 3. Periodic Tasks\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    loop {\n        cx.background_executor().timer(Duration::from_secs(5)).await;\n\n        this.update(cx, |state, cx| {\n            state.tick();\n            cx.notify();\n        }).ok();\n    }\n}).detach();\n```\n\n### 4. Task Cancellation\n\nTasks are automatically cancelled when dropped. Store in struct to keep alive.\n\n## Common Pitfalls\n\n### ❌ Don't: Use `defer_in` and then update the same entity through its handle\n\n`cx.defer_in(window, callback)` schedules `callback` to run **on the current entity** — GPUI re-acquires that entity's lock to execute it. Calling `entity.update(cx, …)` on the *same* entity from within the deferred callback re-enters the lock and panics:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: list entity is locked for the defer_in; calling list.update re-enters\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        parent.update(cx, |this, cx| {\n            this.inner_list.update(cx, |_, _| {}); // PANIC if inner_list == the deferred entity\n        });\n    });\n}\n```\n\n```rust\n// ✅ Correct: use the direct &mut reference — no lock needed\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // Access list data directly through the &mut reference\n        list_state.delegate_mut().some_method();\n\n        // Update a *different* entity — fine, different lock\n        parent.update(cx, |this, cx| { /* … */ });\n\n        // Sync list state directly after parent update — no lock needed\n        list_state.delegate_mut().update_snapshot(new_val);\n    });\n}\n```\n\nThe rule: inside a `defer_in` callback, **never call `entity.update(cx, …)` or `entity.read(cx)` on the entity the `defer_in` was scheduled on**. Use the `&mut Entity` direct reference the callback provides instead.\n\n### ❌ Don't: Update entities from background tasks\n\n```rust\n// ❌ Wrong: Can't update entities from background thread\ncx.background_spawn(async move {\n    entity.update(cx, |state, cx| { // Compile error!\n        state.data = data;\n    });\n});\n```\n\n### ✅ Do: Await the background task inside a foreground task\n\n```rust\n// ✅ Correct: the foreground task awaits the background result\ncx.spawn(async move |this, cx| {\n    let data = cx.background_spawn(async move { load_data() }).await;\n    this.update(cx, |state, cx| {\n        state.data = data;\n        cx.notify();\n    }).ok();\n})\n.detach();\n```\n\nGPUI has no `Task::then`. Await the background task inside `cx.spawn`. The\nclosure receives `(WeakEntity<Self>, &mut AsyncApp)`, not the background result.\n\n","isInternal":false,"tokens":1507,"sizeBytes":6328},{"name":"context.md","path":"skills/gpui-kit/references/gpui/context.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/context.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Context Management\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Operations](#common-operations) · [Context Hierarchy](#context-hierarchy) · [cx.listener](#cxlistener--binding-callbacks-to-self) · [subscribe_in](#subscribe_in--subscribe-with-window-access) · [observe_window_activation](#observe_window_activation) · [observe_global](#observe_global) · [defer / defer_in](#defer-and-defer_in) · [Naming Convention](#context-naming-convention)\n\n## Overview\n\nGPUI uses different context types for different scenarios:\n\n**Context Types:**\n- **`App`**: Global app state, entity creation\n- **`Window`**: Window-specific operations, painting, layout\n- **`Context<T>`**: Entity-specific context for component `T`\n- **`AsyncApp`**: Async context for foreground tasks\n- **`AsyncWindowContext`**: Async context with window access\n\n## Quick Start\n\n### Context<T> - Component Context\n\n```rust\nimpl MyComponent {\n    fn update_state(&mut self, cx: &mut Context<Self>) {\n        self.value = 42;\n        cx.notify(); // Trigger re-render\n\n        // Spawn async task\n        cx.spawn(async move |cx| {\n            // Async work\n        }).detach();\n\n        // Get current entity\n        let entity = cx.entity();\n    }\n}\n```\n\n### App - Global Context\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx: &mut App| {\n        gpui_kit::init(cx);\n\n        // Create entities\n        let entity = cx.new(|cx| MyState::default());\n\n        // Open windows (wraps the view in a `Root`)\n        gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| cx.new(|_| MyView))\n            .expect(\"failed to open window\");\n    });\n}\n```\n\n### Window - Window Context\n\n```rust\nimpl Render for MyView {\n    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        // Window operations\n        let is_focused = window.is_window_focused();\n        let bounds = window.bounds();\n\n        div().child(\"Content\")\n    }\n}\n```\n\n### AsyncApp - Async Context\n\n```rust\ncx.spawn(async move |cx: &mut AsyncApp| {\n    let data = fetch_data().await;\n\n    entity.update(cx, |state, inner_cx| {\n        state.data = data;\n        inner_cx.notify();\n    }).ok();\n}).detach();\n```\n\n## Common Operations\n\n### Entity Operations\n\n```rust\n// Create entity\nlet entity = cx.new(|cx| MyState::default());\n\n// Update entity\nentity.update(cx, |state, cx| {\n    state.value = 42;\n    cx.notify();\n});\n\n// Read entity\nlet value = entity.read(cx).value;\n```\n\n### Notifications and Events\n\n```rust\n// Trigger re-render\ncx.notify();\n\n// Emit event\ncx.emit(MyEvent::Updated);\n\n// Observe entity\ncx.observe(&entity, |this, observed, cx| {\n    // React to changes\n}).detach();\n\n// Subscribe to events\ncx.subscribe(&entity, |this, source, event, cx| {\n    // Handle event\n}).detach();\n```\n\n### Window Operations\n\n```rust\n// Window state\nlet focused = window.is_window_focused();\nlet bounds = window.bounds();\nlet scale = window.scale_factor();\n\n// Close window\nwindow.remove_window();\n```\n\n### Async Operations\n\n```rust\n// Spawn foreground task\ncx.spawn(async move |cx| {\n    // Async work with entity access\n}).detach();\n\n// Spawn background task\ncx.background_spawn(async move {\n    // Heavy computation\n}).detach();\n```\n\n## Context Hierarchy\n\n```\nApp (Global)\n  └─ Window (Per-window)\n       └─ Context<T> (Per-component)\n            └─ AsyncApp (In async tasks)\n                 └─ AsyncWindowContext (Async + Window)\n```\n\n## cx.listener — Binding Callbacks to Self\n\n`cx.listener` creates a callback that borrows `&mut self` (the current entity). Use it for `on_click`, `on_action`, and other element event handlers:\n\n```rust\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .on_action(cx.listener(Self::on_save))\n            .child(\n                Button::new(\"btn\")\n                    .on_click(cx.listener(|this, _event, _window, cx| {\n                        this.count += 1;\n                        cx.notify();\n                    }))\n            )\n    }\n}\n\nimpl MyView {\n    fn on_save(&mut self, _: &Save, _window: &mut Window, cx: &mut Context<Self>) {\n        cx.notify();\n    }\n}\n```\n\n`cx.listener(Self::method)` is equivalent to creating a closure that calls `self.method(...)`.\n\n## subscribe_in — Subscribe with Window Access\n\nUse `subscribe_in` (instead of `subscribe`) when the callback needs `&mut Window`:\n\n```rust\nlet _subscription = cx.subscribe_in(&input, window, |this, state, event, window, cx| {\n    match event {\n        InputEvent::Change => {\n            let val = state.read(cx).value();\n            this.on_input_change(val, window, cx);\n        }\n        _ => {}\n    }\n});\n// Store _subscription in struct to keep it alive\n```\n\n`subscribe` vs `subscribe_in`:\n- `subscribe(&entity, |this, source, event, cx|)` — no window access\n- `subscribe_in(&entity, window, |this, source, event, window, cx|)` — has window access\n\n## observe_window_activation\n\nReact when the window gains or loses focus:\n\n```rust\nlet _sub = cx.observe_window_activation(window, |this, window, cx| {\n    if window.is_window_active() {\n        this.resume(cx);\n    } else {\n        this.pause(cx);\n    }\n});\n```\n\n## observe_global\n\nReact when a global value changes:\n\n```rust\ncx.observe_global::<Theme>(|cx| {\n    // Theme changed — react\n    cx.notify();\n});\n```\n\n## defer and defer_in\n\nSchedule work after the current update completes:\n\n```rust\n// defer: runs after current App update, no window access\ncx.defer(|cx| {\n    // Runs after current entity update is done\n});\n\n// defer_in: runs after update, with window access\ncx.defer_in(window, |this, window, cx| {\n    // Can access window here\n    // CAUTION: never call entity.update(cx) on *this same entity* inside defer_in\n    // — it re-enters the lock and panics. Use the &mut self reference directly.\n    this.some_method(window, cx);\n});\n```\n\n## Context Naming Convention\n\nAlways name contexts `cx` regardless of type:\n\n```rust\nfn new(window: &mut Window, cx: &mut App) {}             // cx = App\nimpl Render for View {\n    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) {}  // cx = Context<Self>\n}\ncx.spawn(async move |this, cx: &mut AsyncApp| {})         // cx = AsyncApp\n```\n","isInternal":false,"tokens":1556,"sizeBytes":6303},{"name":"element-advanced.md","path":"skills/gpui-kit/references/gpui/element-advanced.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/element-advanced.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Advanced Element Patterns\n\n**Contents:** [Custom Layout Algorithms](#custom-layout-algorithms) · [Element Composition with Traits](#element-composition-with-traits) · [Async Element Updates](#async-element-updates) · [Element Memoization](#element-memoization) · [Virtual List Pattern](#virtual-list-pattern)\n\n## Custom Layout Algorithms\n\nImplementing custom layout algorithms not supported by GPUI's built-in layouts.\n\n### Masonry Layout (Pinterest-Style)\n\n```rust\npub struct MasonryLayout {\n    id: ElementId,\n    columns: usize,\n    gap: Pixels,\n    children: Vec<AnyElement>,\n}\n\nstruct MasonryLayoutState {\n    column_layouts: Vec<Vec<LayoutId>>,\n    column_heights: Vec<Pixels>,\n}\n\nstruct MasonryPaintState {\n    child_bounds: Vec<Bounds<Pixels>>,\n}\n\nimpl Element for MasonryLayout {\n    type RequestLayoutState = MasonryLayoutState;\n    type PrepaintState = MasonryPaintState;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, MasonryLayoutState) {\n        // Initialize columns\n        let mut columns: Vec<Vec<LayoutId>> = vec![Vec::new(); self.columns];\n        let mut column_heights = vec![px(0.); self.columns];\n\n        // Distribute children across columns\n        for child in &mut self.children {\n            let (child_layout_id, _) = child.request_layout(\n                global_id,\n                inspector_id,\n                window,\n                cx\n            );\n\n            let child_size = window.layout_bounds(child_layout_id).size;\n\n            // Find shortest column\n            let min_column_idx = column_heights\n                .iter()\n                .enumerate()\n                .min_by(|a, b| a.1.partial_cmp(b.1).unwrap())\n                .unwrap()\n                .0;\n\n            // Add child to shortest column\n            columns[min_column_idx].push(child_layout_id);\n            column_heights[min_column_idx] += child_size.height + self.gap;\n        }\n\n        // Calculate total layout size\n        let column_width = px(200.); // Fixed column width\n        let total_width = column_width * self.columns as f32\n            + self.gap * (self.columns - 1) as f32;\n        let total_height = column_heights.iter()\n            .max_by(|a, b| a.partial_cmp(b).unwrap())\n            .copied()\n            .unwrap_or(px(0.));\n\n        let layout_id = window.request_layout(\n            Style {\n                size: size(total_width, total_height),\n                ..default()\n            },\n            columns.iter().flatten().copied().collect(),\n            cx\n        );\n\n        (layout_id, MasonryLayoutState {\n            column_layouts: columns,\n            column_heights,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut MasonryLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> MasonryPaintState {\n        let column_width = px(200.);\n        let mut child_bounds = Vec::new();\n\n        // Position children in columns\n        for (col_idx, column) in layout_state.column_layouts.iter().enumerate() {\n            let x_offset = bounds.left()\n                + (column_width + self.gap) * col_idx as f32;\n            let mut y_offset = bounds.top();\n\n            for (child_idx, layout_id) in column.iter().enumerate() {\n                let child_size = window.layout_bounds(*layout_id).size;\n                let child_bound = Bounds::new(\n                    point(x_offset, y_offset),\n                    size(column_width, child_size.height)\n                );\n\n                self.children[child_idx].prepaint(\n                    global_id,\n                    inspector_id,\n                    child_bound,\n                    window,\n                    cx\n                );\n\n                child_bounds.push(child_bound);\n                y_offset += child_size.height + self.gap;\n            }\n        }\n\n        MasonryPaintState { child_bounds }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        _bounds: Bounds<Pixels>,\n        _layout_state: &mut MasonryLayoutState,\n        paint_state: &mut MasonryPaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        for (child, bounds) in self.children.iter_mut().zip(&paint_state.child_bounds) {\n            child.paint(global_id, inspector_id, *bounds, window, cx);\n        }\n    }\n}\n```\n\n### Circular Layout\n\n```rust\npub struct CircularLayout {\n    id: ElementId,\n    radius: Pixels,\n    children: Vec<AnyElement>,\n}\n\nimpl Element for CircularLayout {\n    type RequestLayoutState = Vec<LayoutId>;\n    type PrepaintState = Vec<Bounds<Pixels>>;\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Vec<LayoutId>) {\n        let child_layouts: Vec<_> = self.children\n            .iter_mut()\n            .map(|child| child.request_layout(global_id, inspector_id, window, cx).0)\n            .collect();\n\n        let diameter = self.radius * 2.;\n        let layout_id = window.request_layout(\n            Style {\n                size: size(diameter, diameter),\n                ..default()\n            },\n            child_layouts.clone(),\n            cx\n        );\n\n        (layout_id, child_layouts)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_ids: &mut Vec<LayoutId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Vec<Bounds<Pixels>> {\n        let center = bounds.center();\n        let angle_step = 2.0 * std::f32::consts::PI / self.children.len() as f32;\n\n        let mut child_bounds = Vec::new();\n\n        for (i, (child, layout_id)) in self.children.iter_mut()\n            .zip(layout_ids.iter())\n            .enumerate()\n        {\n            let angle = angle_step * i as f32;\n            let child_size = window.layout_bounds(*layout_id).size;\n\n            // Position child on circle\n            let x = center.x + self.radius * angle.cos() - child_size.width / 2.;\n            let y = center.y + self.radius * angle.sin() - child_size.height / 2.;\n\n            let child_bound = Bounds::new(point(x, y), child_size);\n\n            child.prepaint(global_id, inspector_id, child_bound, window, cx);\n            child_bounds.push(child_bound);\n        }\n\n        child_bounds\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        _bounds: Bounds<Pixels>,\n        _layout_ids: &mut Vec<LayoutId>,\n        child_bounds: &mut Vec<Bounds<Pixels>>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        for (child, bounds) in self.children.iter_mut().zip(child_bounds) {\n            child.paint(global_id, inspector_id, *bounds, window, cx);\n        }\n    }\n}\n```\n\n## Element Composition with Traits\n\nCreate reusable behaviors via traits for element composition.\n\n### Hoverable Trait\n\n```rust\npub trait Hoverable: Element {\n    fn on_hover<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static;\n\n    fn on_hover_end<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static;\n}\n\n// Implementation for custom element\npub struct HoverableElement {\n    id: ElementId,\n    content: AnyElement,\n    hover_handlers: Vec<Box<dyn Fn(&mut Window, &mut App)>>,\n    hover_end_handlers: Vec<Box<dyn Fn(&mut Window, &mut App)>>,\n    was_hovered: bool,\n}\n\nimpl Hoverable for HoverableElement {\n    fn on_hover<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static\n    {\n        self.hover_handlers.push(Box::new(f));\n        self\n    }\n\n    fn on_hover_end<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static\n    {\n        self.hover_end_handlers.push(Box::new(f));\n        self\n    }\n}\n\nimpl Element for HoverableElement {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = Hitbox;\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout: &mut LayoutId,\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let is_hovered = hitbox.is_hovered(window);\n\n        // Trigger hover events\n        if is_hovered && !self.was_hovered {\n            for handler in &self.hover_handlers {\n                handler(window, cx);\n            }\n        } else if !is_hovered && self.was_hovered {\n            for handler in &self.hover_end_handlers {\n                handler(window, cx);\n            }\n        }\n\n        self.was_hovered = is_hovered;\n\n        // Paint content\n        self.content.paint(bounds, window, cx);\n    }\n\n    // ... other methods\n}\n```\n\n### Clickable Trait\n\n```rust\npub trait Clickable: Element {\n    fn on_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static;\n\n    fn on_double_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static;\n}\n\npub struct ClickableElement {\n    id: ElementId,\n    content: AnyElement,\n    click_handlers: Vec<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    double_click_handlers: Vec<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    last_click_time: Option<Instant>,\n}\n\nimpl Clickable for ClickableElement {\n    fn on_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static\n    {\n        self.click_handlers.push(Box::new(f));\n        self\n    }\n\n    fn on_double_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static\n    {\n        self.double_click_handlers.push(Box::new(f));\n        self\n    }\n}\n```\n\n## Async Element Updates\n\nElements that update based on async operations.\n\n```rust\npub struct AsyncElement {\n    id: ElementId,\n    state: Entity<AsyncState>,\n    loading: bool,\n    data: Option<String>,\n}\n\npub struct AsyncState {\n    loading: bool,\n    data: Option<String>,\n}\n\nimpl Element for AsyncElement {\n    type RequestLayoutState = ();\n    type PrepaintState = Hitbox;\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout: &mut (),\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Display loading or data\n        if self.loading {\n            // Paint loading indicator\n            self.paint_loading(bounds, window, cx);\n        } else if let Some(data) = &self.data {\n            // Paint data\n            self.paint_data(data, bounds, window, cx);\n        }\n\n        // Trigger async update on click\n        window.on_mouse_event({\n            let state = self.state.clone();\n            let hitbox = hitbox.clone();\n\n            move |event: &MouseUpEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Spawn async task\n                    cx.spawn({\n                        let state = state.clone();\n                        async move {\n                            // Perform async operation\n                            let result = fetch_data_async().await;\n\n                            // Update state on completion\n                            state.update(cx, |state, cx| {\n                                state.loading = false;\n                                state.data = Some(result);\n                                cx.notify();\n                            });\n                        }\n                    }).detach();\n\n                    // Set loading state immediately\n                    state.update(cx, |state, cx| {\n                        state.loading = true;\n                        cx.notify();\n                    });\n\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n\n    // ... other methods\n}\n\nasync fn fetch_data_async() -> String {\n    // Simulate async operation\n    tokio::time::sleep(Duration::from_secs(1)).await;\n    \"Data loaded!\".to_string()\n}\n```\n\n## Element Memoization\n\nOptimize performance by memoizing expensive element computations.\n\n```rust\npub struct MemoizedElement<T: PartialEq + Clone + 'static> {\n    id: ElementId,\n    value: T,\n    render_fn: Box<dyn Fn(&T) -> AnyElement>,\n    cached_element: Option<AnyElement>,\n    last_value: Option<T>,\n}\n\nimpl<T: PartialEq + Clone + 'static> MemoizedElement<T> {\n    pub fn new<F>(id: ElementId, value: T, render_fn: F) -> Self\n    where\n        F: Fn(&T) -> AnyElement + 'static,\n    {\n        Self {\n            id,\n            value,\n            render_fn: Box::new(render_fn),\n            cached_element: None,\n            last_value: None,\n        }\n    }\n}\n\nimpl<T: PartialEq + Clone + 'static> Element for MemoizedElement<T> {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = ();\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, LayoutId) {\n        // Check if value changed\n        if self.last_value.as_ref() != Some(&self.value) || self.cached_element.is_none() {\n            // Recompute element\n            self.cached_element = Some((self.render_fn)(&self.value));\n            self.last_value = Some(self.value.clone());\n        }\n\n        // Request layout for cached element\n        let (layout_id, _) = self.cached_element\n            .as_mut()\n            .unwrap()\n            .request_layout(global_id, inspector_id, window, cx);\n\n        (layout_id, layout_id)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout_id: &mut LayoutId,\n        window: &mut Window,\n        cx: &mut App\n    ) -> () {\n        self.cached_element\n            .as_mut()\n            .unwrap()\n            .prepaint(global_id, inspector_id, bounds, window, cx);\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout_id: &mut LayoutId,\n        _: &mut (),\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        self.cached_element\n            .as_mut()\n            .unwrap()\n            .paint(global_id, inspector_id, bounds, window, cx);\n    }\n}\n\n// Usage\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    MemoizedElement::new(\n        ElementId::Name(\"memoized\".into()),\n        self.expensive_value.clone(),\n        |value| {\n            // Expensive rendering function only called when value changes\n            div().child(format!(\"Computed: {}\", value))\n        }\n    )\n}\n```\n\n## Virtual List Pattern\n\nEfficiently render large lists by only rendering visible items.\n\n```rust\npub struct VirtualList {\n    id: ElementId,\n    item_count: usize,\n    item_height: Pixels,\n    viewport_height: Pixels,\n    scroll_offset: Pixels,\n    render_item: Box<dyn Fn(usize) -> AnyElement>,\n}\n\nstruct VirtualListState {\n    visible_range: Range<usize>,\n    visible_item_layouts: Vec<LayoutId>,\n}\n\nimpl Element for VirtualList {\n    type RequestLayoutState = VirtualListState;\n    type PrepaintState = Hitbox;\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, VirtualListState) {\n        // Calculate visible range\n        let start_idx = (self.scroll_offset / self.item_height).floor() as usize;\n        let end_idx = ((self.scroll_offset + self.viewport_height) / self.item_height)\n            .ceil() as usize;\n        let visible_range = start_idx..end_idx.min(self.item_count);\n\n        // Request layout only for visible items\n        let visible_item_layouts: Vec<_> = visible_range.clone()\n            .map(|i| {\n                let mut item = (self.render_item)(i);\n                item.request_layout(global_id, inspector_id, window, cx).0\n            })\n            .collect();\n\n        let total_height = self.item_height * self.item_count as f32;\n        let layout_id = window.request_layout(\n            Style {\n                size: size(relative(1.0), self.viewport_height),\n                overflow: Overflow::Hidden,\n                ..default()\n            },\n            visible_item_layouts.clone(),\n            cx\n        );\n\n        (layout_id, VirtualListState {\n            visible_range,\n            visible_item_layouts,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        state: &mut VirtualListState,\n        window: &mut Window,\n        _cx: &mut App\n    ) -> Hitbox {\n        // Prepaint visible items at correct positions\n        for (i, layout_id) in state.visible_item_layouts.iter().enumerate() {\n            let item_idx = state.visible_range.start + i;\n            let y = item_idx as f32 * self.item_height - self.scroll_offset;\n            let item_bounds = Bounds::new(\n                point(bounds.left(), bounds.top() + y),\n                size(bounds.width(), self.item_height)\n            );\n\n            // Prepaint if visible\n            if item_bounds.intersects(&bounds) {\n                // Prepaint item...\n            }\n        }\n\n        window.insert_hitbox(bounds, HitboxBehavior::Normal)\n    }\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        state: &mut VirtualListState,\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint visible items\n        for (i, _layout_id) in state.visible_item_layouts.iter().enumerate() {\n            let item_idx = state.visible_range.start + i;\n            let y = item_idx as f32 * self.item_height - self.scroll_offset;\n            let item_bounds = Bounds::new(\n                point(bounds.left(), bounds.top() + y),\n                size(bounds.width(), self.item_height)\n            );\n\n            if item_bounds.intersects(&bounds) {\n                let mut item = (self.render_item)(item_idx);\n                item.paint(item_bounds, window, cx);\n            }\n        }\n\n        // Handle scroll\n        window.on_mouse_event({\n            let hitbox = hitbox.clone();\n            let total_height = self.item_height * self.item_count as f32;\n\n            move |event: &ScrollWheelEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    self.scroll_offset -= event.delta.y;\n                    self.scroll_offset = self.scroll_offset\n                        .max(px(0.))\n                        .min(total_height - self.viewport_height);\n                    cx.notify();\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\n// Usage: Efficiently render 10,000 items\nlet virtual_list = VirtualList {\n    id: ElementId::Name(\"large-list\".into()),\n    item_count: 10_000,\n    item_height: px(40.),\n    viewport_height: px(400.),\n    scroll_offset: px(0.),\n    render_item: Box::new(|index| {\n        div().child(format!(\"Item {}\", index))\n    }),\n};\n```\n\nThese advanced patterns enable sophisticated element implementations while maintaining performance and code quality.\n","isInternal":false,"tokens":4672,"sizeBytes":20530},{"name":"element-api.md","path":"skills/gpui-kit/references/gpui/element-api.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/element-api.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Element API Reference\n\n**Contents:** [Element Trait Structure](#element-trait-structure) · [Associated Types](#associated-types) · [Methods](#methods) · [IntoElement Integration](#intoelement-integration) · [Layout System Integration](#layout-system-integration) · [Hitbox System](#hitbox-system) · [Event Handling](#event-handling) · [Cursor Styles](#cursor-styles)\n\n## Element Trait Structure\n\nThe `Element` trait requires implementing three associated types and five methods:\n\n```rust\npub trait Element: 'static + IntoElement {\n    type RequestLayoutState: 'static;\n    type PrepaintState: 'static;\n\n    fn id(&self) -> Option<ElementId>;\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>>;\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App,\n    ) -> (LayoutId, Self::RequestLayoutState);\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        request_layout: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App,\n    ) -> Self::PrepaintState;\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        request_layout: &mut Self::RequestLayoutState,\n        prepaint: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App,\n    );\n}\n```\n\n## Associated Types\n\n### RequestLayoutState\n\nData passed from `request_layout` to `prepaint` and `paint` phases.\n\n**Usage:**\n- Store layout calculations (styled text, child layout IDs)\n- Cache expensive computations\n- Pass child state between phases\n\n**Examples:**\n```rust\n// Simple: no state needed\ntype RequestLayoutState = ();\n\n// Single value\ntype RequestLayoutState = StyledText;\n\n// Multiple values\ntype RequestLayoutState = (StyledText, Vec<ChildLayout>);\n\n// Complex struct\npub struct MyLayoutState {\n    pub styled_text: StyledText,\n    pub child_layouts: Vec<(LayoutId, ChildState)>,\n    pub computed_bounds: Bounds<Pixels>,\n}\ntype RequestLayoutState = MyLayoutState;\n```\n\n### PrepaintState\n\nData passed from `prepaint` to `paint` phase.\n\n**Usage:**\n- Store hitboxes for interaction\n- Cache visual bounds\n- Store prepaint results\n\n**Examples:**\n```rust\n// Simple: just a hitbox\ntype PrepaintState = Hitbox;\n\n// Optional hitbox\ntype PrepaintState = Option<Hitbox>;\n\n// Multiple values\ntype PrepaintState = (Hitbox, Vec<Bounds<Pixels>>);\n\n// Complex struct\npub struct MyPaintState {\n    pub hitbox: Hitbox,\n    pub child_bounds: Vec<Bounds<Pixels>>,\n    pub visible_range: Range<usize>,\n}\ntype PrepaintState = MyPaintState;\n```\n\n## Methods\n\n### id()\n\nReturns optional unique identifier for debugging and inspection.\n\n```rust\nfn id(&self) -> Option<ElementId> {\n    Some(self.id.clone())\n}\n\n// Or if no ID needed\nfn id(&self) -> Option<ElementId> {\n    None\n}\n```\n\n### source_location()\n\nReturns source location for debugging. Usually returns `None` unless debugging is needed.\n\n```rust\nfn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n    None\n}\n```\n\n### request_layout()\n\nCalculates sizes and positions for the element tree.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Returns:**\n- `(LayoutId, Self::RequestLayoutState)`: Layout ID and state for next phases\n\n**Responsibilities:**\n1. Calculate child layouts by calling `child.request_layout()`\n2. Create own layout using `window.request_layout()`\n3. Return layout ID and state to pass to next phases\n\n**Example:**\n```rust\nfn request_layout(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    window: &mut Window,\n    cx: &mut App,\n) -> (LayoutId, Self::RequestLayoutState) {\n    // 1. Calculate child layouts\n    let child_layout_id = self.child.request_layout(\n        global_id,\n        inspector_id,\n        window,\n        cx\n    ).0;\n\n    // 2. Create own layout\n    let layout_id = window.request_layout(\n        Style {\n            size: size(px(200.), px(100.)),\n            ..default()\n        },\n        vec![child_layout_id],\n        cx\n    );\n\n    // 3. Return layout ID and state\n    (layout_id, MyLayoutState { child_layout_id })\n}\n```\n\n### prepaint()\n\nPrepares for painting by creating hitboxes and computing final bounds.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `bounds`: Final bounds calculated by layout engine\n- `request_layout`: Mutable reference to layout state\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Returns:**\n- `Self::PrepaintState`: State for paint phase\n\n**Responsibilities:**\n1. Compute final child bounds based on layout bounds\n2. Call `child.prepaint()` for all children\n3. Create hitboxes using `window.insert_hitbox()`\n4. Return state for paint phase\n\n**Example:**\n```rust\nfn prepaint(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    bounds: Bounds<Pixels>,\n    request_layout: &mut Self::RequestLayoutState,\n    window: &mut Window,\n    cx: &mut App,\n) -> Self::PrepaintState {\n    // 1. Compute child bounds\n    let child_bounds = bounds; // or calculated subset\n\n    // 2. Prepaint children\n    self.child.prepaint(\n        global_id,\n        inspector_id,\n        child_bounds,\n        &mut request_layout.child_state,\n        window,\n        cx\n    );\n\n    // 3. Create hitboxes\n    let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n    // 4. Return paint state\n    MyPaintState { hitbox }\n}\n```\n\n### paint()\n\nRenders the element and handles interactions.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `bounds`: Final bounds for rendering\n- `request_layout`: Mutable reference to layout state\n- `prepaint`: Mutable reference to prepaint state\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Responsibilities:**\n1. Paint children first (bottom to top)\n2. Paint own content (backgrounds, borders, etc.)\n3. Set up interactions (mouse events, cursor styles)\n\n**Example:**\n```rust\nfn paint(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    bounds: Bounds<Pixels>,\n    request_layout: &mut Self::RequestLayoutState,\n    prepaint: &mut Self::PrepaintState,\n    window: &mut Window,\n    cx: &mut App,\n) {\n    // 1. Paint children first\n    self.child.paint(\n        global_id,\n        inspector_id,\n        child_bounds,\n        &mut request_layout.child_state,\n        &mut prepaint.child_paint_state,\n        window,\n        cx\n    );\n\n    // 2. Paint own content\n    window.paint_quad(paint_quad(\n        bounds,\n        Anchor::all(px(4.)),\n        cx.theme().background,\n    ));\n\n    // 3. Set up interactions\n    window.on_mouse_event({\n        let hitbox = prepaint.hitbox.clone();\n        move |event: &MouseDownEvent, phase, window, cx| {\n            if hitbox.is_hovered(window) && phase.bubble() {\n                // Handle click\n                cx.stop_propagation();\n            }\n        }\n    });\n\n    window.set_cursor_style(CursorStyle::PointingHand, &prepaint.hitbox);\n}\n```\n\n## IntoElement Integration\n\nElements must also implement `IntoElement` to be used as children:\n\n```rust\nimpl IntoElement for MyElement {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n```\n\nThis allows your custom element to be used directly in the element tree:\n\n```rust\ndiv()\n    .child(MyElement::new()) // Works because of IntoElement\n```\n\n## Common Parameters\n\n### Global and Inspector IDs\n\nBoth are optional identifiers used for debugging and inspection:\n- `global_id`: Unique identifier across entire app\n- `inspector_id`: Identifier for dev tools/inspector\n\nUsually passed through to children without modification.\n\n### Window and Context\n\n- `window: &mut Window`: Window-specific operations (painting, hitboxes, events)\n- `cx: &mut App`: App-wide operations (spawning tasks, accessing globals)\n\n## Layout System Integration\n\n### window.request_layout()\n\nCreates a layout node with specified style and children:\n\n```rust\nlet layout_id = window.request_layout(\n    Style {\n        size: size(px(200.), px(100.)),\n        flex: Flex::Column,\n        gap: px(8.),\n        ..default()\n    },\n    vec![child1_layout_id, child2_layout_id],\n    cx\n);\n```\n\n### Bounds<Pixels>\n\nRepresents rectangular region:\n\n```rust\npub struct Bounds<T> {\n    pub origin: Point<T>,\n    pub size: Size<T>,\n}\n\n// Create bounds\nlet bounds = Bounds::new(\n    point(px(10.), px(20.)),\n    size(px(100.), px(50.))\n);\n\n// Access properties\nbounds.left()    // origin.x\nbounds.top()     // origin.y\nbounds.right()   // origin.x + size.width\nbounds.bottom()  // origin.y + size.height\nbounds.center()  // center point\n```\n\n## Hitbox System\n\n### Creating Hitboxes\n\n```rust\n// Normal hitbox (blocks events)\nlet hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n// Transparent hitbox (passes events through)\nlet hitbox = window.insert_hitbox(bounds, HitboxBehavior::Transparent);\n```\n\n### Using Hitboxes\n\n```rust\n// Check if hovered\nif hitbox.is_hovered(window) {\n    // ...\n}\n\n// Set cursor style\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n\n// Use in event handlers\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    if hitbox.is_hovered(window) && phase.bubble() {\n        // Handle event\n    }\n});\n```\n\n## Event Handling\n\n### Mouse Events\n\n```rust\n// Mouse down\nwindow.on_mouse_event(move |event: &MouseDownEvent, phase, window, cx| {\n    if phase.bubble() && bounds.contains(&event.position) {\n        // Handle mouse down\n        cx.stop_propagation(); // Prevent bubbling\n    }\n});\n\n// Mouse up\nwindow.on_mouse_event(move |event: &MouseUpEvent, phase, window, cx| {\n    // Handle mouse up\n});\n\n// Mouse move\nwindow.on_mouse_event(move |event: &MouseMoveEvent, phase, window, cx| {\n    // Handle mouse move\n});\n\n// Scroll\nwindow.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {\n    // Handle scroll\n});\n```\n\n### Event Phase\n\nEvents go through two phases:\n- **Capture**: Top-down (parent → child)\n- **Bubble**: Bottom-up (child → parent)\n\n```rust\nmove |event, phase, window, cx| {\n    if phase.capture() {\n        // Handle in capture phase\n    } else if phase.bubble() {\n        // Handle in bubble phase\n    }\n\n    cx.stop_propagation(); // Stop event from continuing\n}\n```\n\n## Cursor Styles\n\nAvailable cursor styles:\n\n```rust\nCursorStyle::Arrow\nCursorStyle::IBeam           // Text selection\nCursorStyle::PointingHand    // Clickable\nCursorStyle::ResizeLeft\nCursorStyle::ResizeRight\nCursorStyle::ResizeUp\nCursorStyle::ResizeDown\nCursorStyle::ResizeLeftRight\nCursorStyle::ResizeUpDown\nCursorStyle::Crosshair\nCursorStyle::OperationNotAllowed\n```\n\nUsage:\n\n```rust\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n```\n","isInternal":false,"tokens":2743,"sizeBytes":11279},{"name":"element-best-practices.md","path":"skills/gpui-kit/references/gpui/element-best-practices.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/element-best-practices.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Element Best Practices\n\n**Contents:** [State Management](#state-management) · [Performance Considerations](#performance-considerations) · [Interaction Handling](#interaction-handling) · [Layout Strategies](#layout-strategies) · [Error Handling](#error-handling) · [Testing Element Implementations](#testing-element-implementations) · [Common Pitfalls](#common-pitfalls) · [Performance Checklist](#performance-checklist)\n\n## State Management\n\n### Using Associated Types Effectively\n\n**Good:** Use associated types to pass meaningful data between phases\n\n```rust\n// Good: Structured state with type safety\ntype RequestLayoutState = (StyledText, Vec<ChildLayout>);\ntype PrepaintState = (Hitbox, Vec<ChildBounds>);\n```\n\n**Bad:** Using empty state when you need data\n\n```rust\n// Bad: No state when you need to pass data\ntype RequestLayoutState = ();\ntype PrepaintState = ();\n// Now you can't pass layout info to paint phase!\n```\n\n### Managing Complex State\n\nFor elements with complex state, create dedicated structs:\n\n```rust\n// Good: Dedicated struct for complex state\npub struct TextElementState {\n    pub styled_text: StyledText,\n    pub text_layout: TextLayout,\n    pub child_states: Vec<ChildState>,\n}\n\ntype RequestLayoutState = TextElementState;\n```\n\n**Benefits:**\n- Clear documentation of state structure\n- Easy to extend\n- Type-safe access\n\n### State Lifecycle\n\n**Golden Rule:** State flows in one direction through the phases\n\n```\nrequest_layout → RequestLayoutState →\nprepaint → PrepaintState →\npaint\n```\n\n**Don't:**\n- Store state in the element struct that should be in associated types\n- Try to mutate element state in paint phase (use `cx.notify()` to schedule re-render)\n- Pass mutable references across phase boundaries\n\n## Performance Considerations\n\n### Minimize Allocations in Paint Phase\n\n**Critical:** Paint phase is called every frame during animations. Minimize allocations.\n\n**Good:** Pre-allocate in `request_layout` or `prepaint`\n\n```rust\nimpl Element for MyElement {\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Vec<StyledText>)\n    {\n        // Allocate once during layout\n        let styled_texts = self.children\n            .iter()\n            .map(|child| StyledText::new(child.text.clone()))\n            .collect();\n\n        (layout_id, styled_texts)\n    }\n\n    fn paint(&mut self, .., styled_texts: &mut Vec<StyledText>, ..) {\n        // Just use pre-allocated styled_texts\n        for text in styled_texts {\n            text.paint(..);\n        }\n    }\n}\n```\n\n**Bad:** Allocate in `paint` phase\n\n```rust\nfn paint(&mut self, ..) {\n    // Bad: Allocation in paint phase!\n    let styled_texts: Vec<_> = self.children\n        .iter()\n        .map(|child| StyledText::new(child.text.clone()))\n        .collect();\n}\n```\n\n### Cache Expensive Computations\n\nUse memoization for expensive operations:\n\n```rust\npub struct CachedElement {\n    // Cache key\n    last_text: Option<SharedString>,\n    last_width: Option<Pixels>,\n\n    // Cached result\n    cached_layout: Option<TextLayout>,\n}\n\nimpl Element for CachedElement {\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, TextLayout)\n    {\n        let current_width = window.bounds().width();\n\n        // Check if cache is valid\n        if self.last_text.as_ref() != Some(&self.text)\n            || self.last_width != Some(current_width)\n            || self.cached_layout.is_none()\n        {\n            // Recompute expensive layout\n            self.cached_layout = Some(self.compute_text_layout(current_width));\n            self.last_text = Some(self.text.clone());\n            self.last_width = Some(current_width);\n        }\n\n        // Use cached layout\n        let layout = self.cached_layout.as_ref().unwrap();\n        (layout_id, layout.clone())\n    }\n}\n```\n\n### Lazy Child Rendering\n\nOnly render visible children in scrollable containers:\n\n```rust\nfn paint(&mut self, .., bounds: Bounds<Pixels>, paint_state: &mut Self::PrepaintState, ..) {\n    for (i, child) in self.children.iter_mut().enumerate() {\n        let child_bounds = paint_state.child_bounds[i];\n\n        // Only paint visible children\n        if self.is_visible(&child_bounds, &bounds) {\n            child.paint(..);\n        }\n    }\n}\n\nfn is_visible(&self, child_bounds: &Bounds<Pixels>, container_bounds: &Bounds<Pixels>) -> bool {\n    child_bounds.bottom() >= container_bounds.top() &&\n    child_bounds.top() <= container_bounds.bottom()\n}\n```\n\n## Interaction Handling\n\n### Proper Event Bubbling\n\nAlways check phase and bounds before handling events:\n\n```rust\nfn paint(&mut self, .., window: &mut Window, cx: &mut App) {\n    window.on_mouse_event({\n        let hitbox = self.hitbox.clone();\n        move |event: &MouseDownEvent, phase, window, cx| {\n            // Check phase first\n            if !phase.bubble() {\n                return;\n            }\n\n            // Check if event is within bounds\n            if !hitbox.is_hovered(window) {\n                return;\n            }\n\n            // Handle event\n            self.handle_click(event);\n\n            // Stop propagation if handled\n            cx.stop_propagation();\n        }\n    });\n}\n```\n\n**Don't forget:**\n- Check `phase.bubble()` or `phase.capture()` as appropriate\n- Check hitbox hover state or bounds\n- Call `cx.stop_propagation()` if you handle the event\n\n### Hitbox Management\n\nCreate hitboxes in `prepaint` phase, not `paint`:\n\n**Good:**\n\n```rust\nfn prepaint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) -> Hitbox {\n    // Create hitbox in prepaint\n    window.insert_hitbox(bounds, HitboxBehavior::Normal)\n}\n\nfn paint(&mut self, .., hitbox: &mut Hitbox, window: &mut Window, ..) {\n    // Use hitbox in paint\n    window.set_cursor_style(CursorStyle::PointingHand, hitbox);\n}\n```\n\n**Hitbox Behaviors:**\n\n```rust\n// Normal: Blocks events from passing through\nHitboxBehavior::Normal\n\n// Transparent: Allows events to pass through to elements below\nHitboxBehavior::Transparent\n```\n\n### Cursor Style Guidelines\n\nSet appropriate cursor styles for interactivity cues:\n\n```rust\n// Text selection\nwindow.set_cursor_style(CursorStyle::IBeam, &hitbox);\n\n// Clickable elements (desktop convention: use default, not pointing hand)\nwindow.set_cursor_style(CursorStyle::Arrow, &hitbox);\n\n// Links (web convention: use pointing hand)\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n\n// Resizable edges\nwindow.set_cursor_style(CursorStyle::ResizeLeftRight, &hitbox);\n```\n\n**Desktop vs Web Convention:**\n- Desktop apps: Use `Arrow` for buttons\n- Web apps: Use `PointingHand` for links only\n\n## Layout Strategies\n\n### Fixed Size Elements\n\nFor elements with known, unchanging size:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App) -> (LayoutId, ()) {\n    let layout_id = window.request_layout(\n        Style {\n            size: size(px(200.), px(100.)),\n            ..default()\n        },\n        vec![], // No children\n        cx\n    );\n    (layout_id, ())\n}\n```\n\n### Content-Based Sizing\n\nFor elements sized by their content:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Size<Pixels>)\n{\n    // Measure content\n    let text_bounds = self.measure_text(window);\n    let padding = px(16.);\n\n    let layout_id = window.request_layout(\n        Style {\n            size: size(\n                text_bounds.width() + padding * 2.,\n                text_bounds.height() + padding * 2.,\n            ),\n            ..default()\n        },\n        vec![],\n        cx\n    );\n\n    (layout_id, text_bounds)\n}\n```\n\n### Flexible Layouts\n\nFor elements that adapt to available space:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Vec<LayoutId>)\n{\n    let mut child_layout_ids = Vec::new();\n\n    for child in &mut self.children {\n        let (layout_id, _) = child.request_layout(window, cx);\n        child_layout_ids.push(layout_id);\n    }\n\n    let layout_id = window.request_layout(\n        Style {\n            flex_direction: FlexDirection::Row,\n            gap: px(8.),\n            size: Size {\n                width: relative(1.0),  // Fill parent width\n                height: auto(),        // Auto height\n            },\n            ..default()\n        },\n        child_layout_ids.clone(),\n        cx\n    );\n\n    (layout_id, child_layout_ids)\n}\n```\n\n## Error Handling\n\n### Graceful Degradation\n\nHandle errors gracefully, don't panic:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Option<TextLayout>)\n{\n    // Try to create styled text\n    match StyledText::new(self.text.clone()).request_layout(None, None, window, cx) {\n        Ok((layout_id, text_layout)) => {\n            (layout_id, Some(text_layout))\n        }\n        Err(e) => {\n            // Log error\n            eprintln!(\"Failed to layout text: {}\", e);\n\n            // Fallback to simple text\n            let fallback_text = StyledText::new(\"(Error loading text)\".into());\n            let (layout_id, _) = fallback_text.request_layout(None, None, window, cx);\n            (layout_id, None)\n        }\n    }\n}\n```\n\n### Defensive Bounds Checking\n\nAlways validate bounds and indices:\n\n```rust\nfn paint_selection(&self, selection: &Selection, text_layout: &TextLayout, ..) {\n    // Validate selection bounds\n    let start = selection.start.min(self.text.len());\n    let end = selection.end.min(self.text.len());\n\n    if start >= end {\n        return; // Invalid selection\n    }\n\n    let rects = text_layout.rects_for_range(start..end);\n    // Paint selection...\n}\n```\n\n## Testing Element Implementations\n\n### Layout Tests\n\nTest that layout calculations are correct:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use gpui_kit::TestAppContext;\n\n    #[gpui_kit::test]\n    fn test_element_layout(cx: &mut TestAppContext) {\n        cx.update(|cx| {\n            let mut window = cx.open_window(Default::default(), |_, _| ()).unwrap();\n\n            window.update(cx, |window, cx| {\n                let mut element = MyElement::new();\n                let (layout_id, layout_state) = element.request_layout(\n                    None,\n                    None,\n                    window,\n                    cx\n                );\n\n                // Assert layout properties\n                let bounds = window.layout_bounds(layout_id);\n                assert_eq!(bounds.size.width, px(200.));\n                assert_eq!(bounds.size.height, px(100.));\n            });\n        });\n    }\n}\n```\n\n### Interaction Tests\n\nTest that interactions work correctly:\n\n```rust\n#[gpui_kit::test]\nfn test_element_click(cx: &mut TestAppContext) {\n    cx.update(|cx| {\n        let mut window = cx.open_window(Default::default(), |_, cx| {\n            cx.new(|_| MyElement::new())\n        }).unwrap();\n\n        window.update(cx, |window, cx| {\n            let view = window.root_view().unwrap();\n\n            // Simulate click\n            let position = point(px(10.), px(10.));\n            window.dispatch_event(MouseDownEvent {\n                position,\n                button: MouseButton::Left,\n                modifiers: Modifiers::default(),\n            });\n\n            // Assert element responded\n            view.read(cx).assert_clicked();\n        });\n    });\n}\n```\n\n## Common Pitfalls\n\n### ❌ Storing Layout State in Element Struct\n\n**Bad:**\n\n```rust\npub struct MyElement {\n    id: ElementId,\n    // Bad: This should be in RequestLayoutState\n    cached_layout: Option<TextLayout>,\n}\n```\n\n**Good:**\n\n```rust\npub struct MyElement {\n    id: ElementId,\n    text: SharedString,\n}\n\ntype RequestLayoutState = TextLayout; // Good: State in associated type\n```\n\n### ❌ Mutating Element in Paint Phase\n\n**Bad:**\n\n```rust\nfn paint(&mut self, ..) {\n    self.counter += 1; // Bad: Mutating element in paint\n}\n```\n\n**Good:**\n\n```rust\nfn paint(&mut self, .., window: &mut Window, cx: &mut App) {\n    window.on_mouse_event(move |event, phase, window, cx| {\n        if phase.bubble() {\n            self.counter += 1;\n            cx.notify(); // Schedule re-render\n        }\n    });\n}\n```\n\n### ❌ Creating Hitboxes in Paint Phase\n\n**Bad:**\n\n```rust\nfn paint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) {\n    // Bad: Creating hitbox in paint\n    let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n}\n```\n\n**Good:**\n\n```rust\nfn prepaint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) -> Hitbox {\n    // Good: Creating hitbox in prepaint\n    window.insert_hitbox(bounds, HitboxBehavior::Normal)\n}\n```\n\n### ❌ Ignoring Event Phase\n\n**Bad:**\n\n```rust\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    // Bad: Not checking phase\n    self.handle_click(event);\n});\n```\n\n**Good:**\n\n```rust\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    // Good: Checking phase\n    if !phase.bubble() {\n        return;\n    }\n    self.handle_click(event);\n});\n```\n\n## Performance Checklist\n\nBefore shipping an element implementation, verify:\n\n- [ ] No allocations in `paint` phase (except event handlers)\n- [ ] Expensive computations are cached/memoized\n- [ ] Only visible children are rendered in scrollable containers\n- [ ] Hitboxes created in `prepaint`, not `paint`\n- [ ] Event handlers check phase and bounds\n- [ ] Layout state is passed through associated types, not stored in element\n- [ ] Element implements proper error handling with fallbacks\n- [ ] Tests cover layout calculations and interactions\n","isInternal":false,"tokens":3166,"sizeBytes":13488},{"name":"element-examples.md","path":"skills/gpui-kit/references/gpui/element-examples.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/element-examples.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Element Implementation Examples\n\nComplete examples of implementing custom elements for various scenarios.\n\n## Table of Contents\n\n1. [Simple Text Element](#simple-text-element)\n2. [Interactive Element with Selection](#interactive-element-with-selection)\n3. [Complex Element with Child Management](#complex-element-with-child-management)\n\n## Simple Text Element\n\nA basic text element with syntax highlighting support.\n\n```rust\npub struct SimpleText {\n    id: ElementId,\n    text: SharedString,\n    highlights: Vec<(Range<usize>, HighlightStyle)>,\n}\n\nimpl IntoElement for SimpleText {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for SimpleText {\n    type RequestLayoutState = StyledText;\n    type PrepaintState = Hitbox;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        // Create styled text with highlights\n        let mut runs = Vec::new();\n        let mut ix = 0;\n\n        for (range, highlight) in &self.highlights {\n            // Add unstyled text before highlight\n            if ix < range.start {\n                runs.push(window.text_style().to_run(range.start - ix));\n            }\n\n            // Add highlighted text\n            runs.push(\n                window.text_style()\n                    .highlight(*highlight)\n                    .to_run(range.len())\n            );\n            ix = range.end;\n        }\n\n        // Add remaining unstyled text\n        if ix < self.text.len() {\n            runs.push(window.text_style().to_run(self.text.len() - ix));\n        }\n\n        let styled_text = StyledText::new(self.text.clone()).with_runs(runs);\n        let (layout_id, _) = styled_text.request_layout(\n            global_id,\n            inspector_id,\n            window,\n            cx\n        );\n\n        (layout_id, styled_text)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        styled_text: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Self::PrepaintState {\n        // Prepaint the styled text\n        styled_text.prepaint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            window,\n            cx\n        );\n\n        // Create hitbox for interaction\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        hitbox\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        styled_text: &mut Self::RequestLayoutState,\n        hitbox: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint the styled text\n        styled_text.paint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            &mut (),\n            window,\n            cx\n        );\n\n        // Set cursor style for text\n        window.set_cursor_style(CursorStyle::IBeam, hitbox);\n    }\n}\n```\n\n## Interactive Element with Selection\n\nA text element that supports text selection via mouse interaction.\n\n```rust\n#[derive(Clone)]\npub struct Selection {\n    pub start: usize,\n    pub end: usize,\n}\n\npub struct SelectableText {\n    id: ElementId,\n    text: SharedString,\n    selectable: bool,\n    selection: Option<Selection>,\n}\n\nimpl IntoElement for SelectableText {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for SelectableText {\n    type RequestLayoutState = TextLayout;\n    type PrepaintState = Option<Hitbox>;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        let styled_text = StyledText::new(self.text.clone());\n        let (layout_id, _) = styled_text.request_layout(\n            global_id,\n            inspector_id,\n            window,\n            cx\n        );\n\n        // Extract text layout for selection painting\n        let text_layout = styled_text.layout().clone();\n\n        (layout_id, text_layout)\n    }\n\n    fn prepaint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _text_layout: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        _cx: &mut App\n    ) -> Self::PrepaintState {\n        // Only create hitbox if selectable\n        if self.selectable {\n            Some(window.insert_hitbox(bounds, HitboxBehavior::Normal))\n        } else {\n            None\n        }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        text_layout: &mut Self::RequestLayoutState,\n        hitbox: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint text\n        let styled_text = StyledText::new(self.text.clone());\n        styled_text.paint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            &mut (),\n            window,\n            cx\n        );\n\n        // Paint selection if any\n        if let Some(selection) = &self.selection {\n            Self::paint_selection(selection, text_layout, &bounds, window, cx);\n        }\n\n        // Handle mouse events for selection\n        if let Some(hitbox) = hitbox {\n            window.set_cursor_style(CursorStyle::IBeam, hitbox);\n\n            // Mouse down to start selection\n            window.on_mouse_event({\n                let bounds = bounds.clone();\n                move |event: &MouseDownEvent, phase, window, cx| {\n                    if bounds.contains(&event.position) && phase.bubble() {\n                        // Start selection at mouse position\n                        let char_index = Self::position_to_index(\n                            event.position,\n                            &bounds,\n                            text_layout\n                        );\n                        self.selection = Some(Selection {\n                            start: char_index,\n                            end: char_index,\n                        });\n                        cx.notify();\n                        cx.stop_propagation();\n                    }\n                }\n            });\n\n            // Mouse drag to extend selection\n            window.on_mouse_event({\n                let bounds = bounds.clone();\n                move |event: &MouseMoveEvent, phase, window, cx| {\n                    if let Some(selection) = &mut self.selection {\n                        if phase.bubble() {\n                            let char_index = Self::position_to_index(\n                                event.position,\n                                &bounds,\n                                text_layout\n                            );\n                            selection.end = char_index;\n                            cx.notify();\n                        }\n                    }\n                }\n            });\n        }\n    }\n}\n\nimpl SelectableText {\n    fn paint_selection(\n        selection: &Selection,\n        text_layout: &TextLayout,\n        bounds: &Bounds<Pixels>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Calculate selection bounds from text layout\n        let selection_rects = text_layout.rects_for_range(\n            selection.start..selection.end\n        );\n\n        // Paint selection background\n        for rect in selection_rects {\n            window.paint_quad(paint_quad(\n                Bounds::new(\n                    point(bounds.left() + rect.origin.x, bounds.top() + rect.origin.y),\n                    rect.size\n                ),\n                Anchor::default(),\n                cx.theme().selection_background,\n            ));\n        }\n    }\n\n    fn position_to_index(\n        position: Point<Pixels>,\n        bounds: &Bounds<Pixels>,\n        text_layout: &TextLayout\n    ) -> usize {\n        // Convert screen position to character index\n        let relative_pos = point(\n            position.x - bounds.left(),\n            position.y - bounds.top()\n        );\n        text_layout.index_for_position(relative_pos)\n    }\n}\n```\n\n## Complex Element with Child Management\n\nA container element that manages multiple children with scrolling support.\n\n```rust\npub struct ComplexElement {\n    id: ElementId,\n    children: Vec<Box<dyn Element<RequestLayoutState = (), PrepaintState = ()>>>,\n    scrollable: bool,\n    scroll_offset: Point<Pixels>,\n}\n\nstruct ComplexLayoutState {\n    child_layouts: Vec<LayoutId>,\n    total_height: Pixels,\n}\n\nstruct ComplexPaintState {\n    child_bounds: Vec<Bounds<Pixels>>,\n    hitbox: Hitbox,\n}\n\nimpl IntoElement for ComplexElement {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for ComplexElement {\n    type RequestLayoutState = ComplexLayoutState;\n    type PrepaintState = ComplexPaintState;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        let mut child_layouts = Vec::new();\n        let mut total_height = px(0.);\n\n        // Request layout for all children\n        for child in &mut self.children {\n            let (child_layout_id, _) = child.request_layout(\n                global_id,\n                inspector_id,\n                window,\n                cx\n            );\n            child_layouts.push(child_layout_id);\n\n            // Get child size from layout\n            let child_size = window.layout_bounds(child_layout_id).size();\n            total_height += child_size.height;\n        }\n\n        // Create container layout\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: FlexDirection::Column,\n                gap: px(8.),\n                size: Size {\n                    width: relative(1.0),\n                    height: if self.scrollable {\n                        // Fixed height for scrollable\n                        px(400.)\n                    } else {\n                        // Auto height for non-scrollable\n                        total_height\n                    },\n                },\n                ..default()\n            },\n            child_layouts.clone(),\n            cx\n        );\n\n        (layout_id, ComplexLayoutState {\n            child_layouts,\n            total_height,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Self::PrepaintState {\n        let mut child_bounds = Vec::new();\n        let mut y_offset = self.scroll_offset.y;\n\n        // Calculate child bounds and prepaint children\n        for (child, layout_id) in self.children.iter_mut()\n            .zip(&layout_state.child_layouts)\n        {\n            let child_size = window.layout_bounds(*layout_id).size();\n            let child_bound = Bounds::new(\n                point(bounds.left(), bounds.top() + y_offset),\n                child_size\n            );\n\n            // Only prepaint visible children\n            if self.is_visible(&child_bound, &bounds) {\n                child.prepaint(\n                    global_id,\n                    inspector_id,\n                    child_bound,\n                    &mut (),\n                    window,\n                    cx\n                );\n            }\n\n            child_bounds.push(child_bound);\n            y_offset += child_size.height + px(8.); // gap\n        }\n\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n        ComplexPaintState {\n            child_bounds,\n            hitbox,\n        }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut Self::RequestLayoutState,\n        paint_state: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint background\n        window.paint_quad(paint_quad(\n            bounds,\n            Anchor::all(px(4.)),\n            cx.theme().background,\n        ));\n\n        // Paint visible children only\n        for (i, child) in self.children.iter_mut().enumerate() {\n            let child_bounds = paint_state.child_bounds[i];\n\n            if self.is_visible(&child_bounds, &bounds) {\n                child.paint(\n                    global_id,\n                    inspector_id,\n                    child_bounds,\n                    &mut (),\n                    &mut (),\n                    window,\n                    cx\n                );\n            }\n        }\n\n        // Paint scrollbar if scrollable\n        if self.scrollable {\n            self.paint_scrollbar(bounds, layout_state, window, cx);\n        }\n\n        // Handle scroll events\n        if self.scrollable {\n            window.on_mouse_event({\n                let hitbox = paint_state.hitbox.clone();\n                let total_height = layout_state.total_height;\n                let visible_height = bounds.size.height;\n\n                move |event: &ScrollWheelEvent, phase, window, cx| {\n                    if hitbox.is_hovered(window) && phase.bubble() {\n                        // Update scroll offset\n                        self.scroll_offset.y -= event.delta.y;\n\n                        // Clamp scroll offset\n                        let max_scroll = (total_height - visible_height).max(px(0.));\n                        self.scroll_offset.y = self.scroll_offset.y\n                            .max(px(0.))\n                            .min(max_scroll);\n\n                        cx.notify();\n                        cx.stop_propagation();\n                    }\n                }\n            });\n        }\n    }\n}\n\nimpl ComplexElement {\n    fn is_visible(&self, child_bounds: &Bounds<Pixels>, container_bounds: &Bounds<Pixels>) -> bool {\n        // Check if child is within visible area\n        child_bounds.bottom() >= container_bounds.top() &&\n        child_bounds.top() <= container_bounds.bottom()\n    }\n\n    fn paint_scrollbar(\n        &self,\n        bounds: Bounds<Pixels>,\n        layout_state: &ComplexLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let scrollbar_width = px(8.);\n        let visible_height = bounds.size.height;\n        let total_height = layout_state.total_height;\n\n        if total_height <= visible_height {\n            return; // No need for scrollbar\n        }\n\n        // Calculate scrollbar position and size\n        let scroll_ratio = self.scroll_offset.y / (total_height - visible_height);\n        let thumb_height = (visible_height / total_height) * visible_height;\n        let thumb_y = scroll_ratio * (visible_height - thumb_height);\n\n        // Paint scrollbar track\n        let track_bounds = Bounds::new(\n            point(bounds.right() - scrollbar_width, bounds.top()),\n            size(scrollbar_width, visible_height)\n        );\n        window.paint_quad(paint_quad(\n            track_bounds,\n            Anchor::default(),\n            cx.theme().scrollbar_track,\n        ));\n\n        // Paint scrollbar thumb\n        let thumb_bounds = Bounds::new(\n            point(bounds.right() - scrollbar_width, bounds.top() + thumb_y),\n            size(scrollbar_width, thumb_height)\n        );\n        window.paint_quad(paint_quad(\n            thumb_bounds,\n            Anchor::all(px(4.)),\n            cx.theme().scrollbar_thumb,\n        ));\n    }\n}\n```\n\n## Usage Examples\n\n### Using SimpleText\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    div()\n        .child(SimpleText {\n            id: ElementId::Name(\"code-text\".into()),\n            text: \"fn main() { println!(\\\"Hello\\\"); }\".into(),\n            highlights: vec![\n                (0..2, HighlightStyle::keyword()),\n                (3..7, HighlightStyle::function()),\n            ],\n        })\n}\n```\n\n### Using SelectableText\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    div()\n        .child(SelectableText {\n            id: ElementId::Name(\"selectable-text\".into()),\n            text: \"Select this text with your mouse\".into(),\n            selectable: true,\n            selection: self.current_selection.clone(),\n        })\n}\n```\n\n### Using ComplexElement\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    let children: Vec<Box<dyn Element<_, _>>> = self.items\n        .iter()\n        .map(|item| Box::new(div().child(item.name.clone())) as Box<_>)\n        .collect();\n\n    div()\n        .child(ComplexElement {\n            id: ElementId::Name(\"scrollable-list\".into()),\n            children,\n            scrollable: true,\n            scroll_offset: self.scroll_offset,\n        })\n}\n```\n","isInternal":false,"tokens":3685,"sizeBytes":18087},{"name":"element-id.md","path":"skills/gpui-kit/references/gpui/element-id.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/element-id.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# ElementId\n\n`ElementId` is a unique identifier for a GPUI element. It is required for elements that need:\n- Mouse event handling (`on_click`, `on_hover`, etc.)\n- State storage via `window.use_keyed_state`\n- Interaction tracking\n\n## Making an Element Stateful\n\nCall `.id()` on a `div()` to create a `Stateful<Div>`:\n\n```rust\ndiv().id(\"my-element\")          // ElementId from &str\ndiv().id(42usize)               // ElementId from usize\ndiv().id(ElementId::from(idx))  // Explicit\n```\n\nWithout `.id()`, a div cannot receive mouse events or store state.\n\n## Accepted Types\n\n```rust\nimpl Into<ElementId> for &str      // \"my-id\"\nimpl Into<ElementId> for String    // String::from(\"my-id\")\nimpl Into<ElementId> for usize     // 0, 1, 2, ...\nimpl Into<ElementId> for u64\nimpl Into<ElementId> for SharedString\n```\n\n## Uniqueness Rules\n\nIDs must be unique within the same **stateful parent's scope** — not globally. GPUI builds a `GlobalElementId` by chaining parent IDs:\n\n```rust\ndiv().id(\"app\").child(\n    div().id(\"list1\").children(vec![\n        div().id(1usize).child(\"Item 1\"),  // GlobalId: [\"app\", \"list1\", 1]\n        div().id(2usize).child(\"Item 2\"),  // GlobalId: [\"app\", \"list1\", 2]\n    ])\n).child(\n    div().id(\"list2\").children(vec![\n        div().id(1usize).child(\"Item 1\"),  // GlobalId: [\"app\", \"list2\", 1] — no conflict\n    ])\n)\n```\n\nItems in different parent scopes can reuse simple IDs (integers, short strings).\n\n## In Component Structs\n\nComponents always store `id: ElementId` and pass it in `new()`:\n\n```rust\n#[derive(IntoElement)]\npub struct Button {\n    id: ElementId,\n    base: Stateful<Div>,\n    // ...\n}\n\nimpl Button {\n    pub fn new(id: impl Into<ElementId>) -> Self {\n        let id = id.into();\n        Self {\n            id: id.clone(),\n            base: div().id(id),  // id applied to base\n            // ...\n        }\n    }\n}\n\nimpl RenderOnce for Button {\n    fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {\n        self.base  // already has .id() applied\n            .on_click(/* ... */)\n    }\n}\n```\n\n## Usage at Call Sites\n\n```rust\n// Use unique string IDs for named components\nButton::new(\"save-btn\").label(\"Save\")\nButton::new(\"cancel-btn\").label(\"Cancel\")\n\n// Use index-based IDs in lists\nfor (i, item) in items.iter().enumerate() {\n    div().id(i)  // unique within this parent\n}\n\n// Use descriptive IDs for debugging\nInput::new(\"search-input\")\nSelect::new(\"country-select\")\n```\n","isInternal":false,"tokens":666,"sizeBytes":2433},{"name":"element-patterns.md","path":"skills/gpui-kit/references/gpui/element-patterns.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/element-patterns.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Common Element Patterns\n\n**Contents:** [Text Rendering Elements](#text-rendering-elements) · [Container Elements](#container-elements) · [Interactive Elements](#interactive-elements) · [Composite Elements](#composite-elements) · [Scrollable Elements](#scrollable-elements) · [Pattern Selection Guide](#pattern-selection-guide)\n\n## Text Rendering Elements\n\nElements that display and manipulate text content.\n\n### Pattern Characteristics\n\n- Use `StyledText` for text layout and rendering\n- Handle text selection in `paint` phase with hitbox interaction\n- Create hitboxes for text interaction in `prepaint`\n- Support text highlighting and custom styling via runs\n\n### Implementation Template\n\n```rust\npub struct TextElement {\n    id: ElementId,\n    text: SharedString,\n    style: TextStyle,\n}\n\nimpl Element for TextElement {\n    type RequestLayoutState = StyledText;\n    type PrepaintState = Hitbox;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, StyledText)\n    {\n        let styled_text = StyledText::new(self.text.clone())\n            .with_style(self.style);\n        let (layout_id, _) = styled_text.request_layout(None, None, window, cx);\n        (layout_id, styled_text)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, styled_text: &mut StyledText,\n                window: &mut Window, cx: &mut App) -> Hitbox\n    {\n        styled_text.prepaint(None, None, bounds, &mut (), window, cx);\n        window.insert_hitbox(bounds, HitboxBehavior::Normal)\n    }\n\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, styled_text: &mut StyledText,\n             hitbox: &mut Hitbox, window: &mut Window, cx: &mut App)\n    {\n        styled_text.paint(None, None, bounds, &mut (), &mut (), window, cx);\n        window.set_cursor_style(CursorStyle::IBeam, hitbox);\n    }\n}\n```\n\n### Use Cases\n\n- Code editors with syntax highlighting\n- Rich text displays\n- Labels with custom formatting\n- Selectable text areas\n\n## Container Elements\n\nElements that manage and layout child elements.\n\n### Pattern Characteristics\n\n- Manage child element layouts and positions\n- Handle scrolling and clipping when needed\n- Implement flex/grid-like layouts\n- Coordinate child interactions and event delegation\n\n### Implementation Template\n\n```rust\npub struct ContainerElement {\n    id: ElementId,\n    children: Vec<AnyElement>,\n    direction: FlexDirection,\n    gap: Pixels,\n}\n\nimpl Element for ContainerElement {\n    type RequestLayoutState = Vec<LayoutId>;\n    type PrepaintState = Vec<Bounds<Pixels>>;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Vec<LayoutId>)\n    {\n        let child_layout_ids: Vec<_> = self.children\n            .iter_mut()\n            .map(|child| child.request_layout(window, cx).0)\n            .collect();\n\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: self.direction,\n                gap: self.gap,\n                ..default()\n            },\n            child_layout_ids.clone(),\n            cx\n        );\n\n        (layout_id, child_layout_ids)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout_ids: &mut Vec<LayoutId>,\n                window: &mut Window, cx: &mut App) -> Vec<Bounds<Pixels>>\n    {\n        let mut child_bounds = Vec::new();\n\n        for (child, layout_id) in self.children.iter_mut().zip(layout_ids.iter()) {\n            let child_bound = window.layout_bounds(*layout_id);\n            child.prepaint(child_bound, window, cx);\n            child_bounds.push(child_bound);\n        }\n\n        child_bounds\n    }\n\n    fn paint(&mut self, .., child_bounds: &mut Vec<Bounds<Pixels>>,\n             window: &mut Window, cx: &mut App)\n    {\n        for (child, bounds) in self.children.iter_mut().zip(child_bounds.iter()) {\n            child.paint(*bounds, window, cx);\n        }\n    }\n}\n```\n\n### Use Cases\n\n- Panels and split views\n- List containers\n- Grid layouts\n- Tab containers\n\n## Interactive Elements\n\nElements that respond to user input (mouse, keyboard, touch).\n\n### Pattern Characteristics\n\n- Create appropriate hitboxes for interaction areas\n- Handle mouse/keyboard/touch events properly\n- Manage focus and cursor styles\n- Support hover, active, and disabled states\n\n### Implementation Template\n\n```rust\npub struct InteractiveElement {\n    id: ElementId,\n    content: AnyElement,\n    on_click: Option<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    hover_style: Option<Style>,\n}\n\nimpl Element for InteractiveElement {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = (Hitbox, bool); // hitbox and is_hovered\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, LayoutId)\n    {\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        (content_layout, content_layout)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, content_layout: &mut LayoutId,\n                window: &mut Window, cx: &mut App) -> (Hitbox, bool)\n    {\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        let is_hovered = hitbox.is_hovered(window);\n\n        self.content.prepaint(bounds, window, cx);\n\n        (hitbox, is_hovered)\n    }\n\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, content_layout: &mut LayoutId,\n             prepaint: &mut (Hitbox, bool), window: &mut Window, cx: &mut App)\n    {\n        let (hitbox, is_hovered) = prepaint;\n\n        // Paint hover background if hovered\n        if *is_hovered {\n            if let Some(hover_style) = &self.hover_style {\n                window.paint_quad(paint_quad(\n                    bounds,\n                    Anchor::all(px(4.)),\n                    hover_style.background_color.unwrap_or(cx.theme().hover),\n                ));\n            }\n        }\n\n        // Paint content\n        self.content.paint(bounds, window, cx);\n\n        // Handle click\n        if let Some(on_click) = self.on_click.as_ref() {\n            window.on_mouse_event({\n                let on_click = on_click.clone();\n                let hitbox = hitbox.clone();\n                move |event: &MouseUpEvent, phase, window, cx| {\n                    if hitbox.is_hovered(window) && phase.bubble() {\n                        on_click(event, window, cx);\n                        cx.stop_propagation();\n                    }\n                }\n            });\n        }\n\n        // Set cursor style\n        window.set_cursor_style(CursorStyle::PointingHand, hitbox);\n    }\n}\n```\n\n### Use Cases\n\n- Buttons\n- Links\n- Clickable cards\n- Drag handles\n- Menu items\n\n## Composite Elements\n\nElements that combine multiple child elements with complex coordination.\n\n### Pattern Characteristics\n\n- Combine multiple child elements with different types\n- Manage complex state across children\n- Coordinate animations and transitions\n- Handle focus delegation between children\n\n### Implementation Template\n\n```rust\npub struct CompositeElement {\n    id: ElementId,\n    header: AnyElement,\n    content: AnyElement,\n    footer: Option<AnyElement>,\n}\n\nstruct CompositeLayoutState {\n    header_layout: LayoutId,\n    content_layout: LayoutId,\n    footer_layout: Option<LayoutId>,\n}\n\nstruct CompositePaintState {\n    header_bounds: Bounds<Pixels>,\n    content_bounds: Bounds<Pixels>,\n    footer_bounds: Option<Bounds<Pixels>>,\n}\n\nimpl Element for CompositeElement {\n    type RequestLayoutState = CompositeLayoutState;\n    type PrepaintState = CompositePaintState;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, CompositeLayoutState)\n    {\n        let (header_layout, _) = self.header.request_layout(window, cx);\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        let footer_layout = self.footer.as_mut()\n            .map(|f| f.request_layout(window, cx).0);\n\n        let mut children = vec![header_layout, content_layout];\n        if let Some(footer) = footer_layout {\n            children.push(footer);\n        }\n\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: FlexDirection::Column,\n                size: Size {\n                    width: relative(1.0),\n                    height: auto(),\n                },\n                ..default()\n            },\n            children,\n            cx\n        );\n\n        (layout_id, CompositeLayoutState {\n            header_layout,\n            content_layout,\n            footer_layout,\n        })\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut CompositeLayoutState,\n                window: &mut Window, cx: &mut App) -> CompositePaintState\n    {\n        let header_bounds = window.layout_bounds(layout.header_layout);\n        let content_bounds = window.layout_bounds(layout.content_layout);\n        let footer_bounds = layout.footer_layout\n            .map(|id| window.layout_bounds(id));\n\n        self.header.prepaint(header_bounds, window, cx);\n        self.content.prepaint(content_bounds, window, cx);\n        if let (Some(footer), Some(bounds)) = (&mut self.footer, footer_bounds) {\n            footer.prepaint(bounds, window, cx);\n        }\n\n        CompositePaintState {\n            header_bounds,\n            content_bounds,\n            footer_bounds,\n        }\n    }\n\n    fn paint(&mut self, .., paint_state: &mut CompositePaintState,\n             window: &mut Window, cx: &mut App)\n    {\n        self.header.paint(paint_state.header_bounds, window, cx);\n        self.content.paint(paint_state.content_bounds, window, cx);\n        if let (Some(footer), Some(bounds)) = (&mut self.footer, paint_state.footer_bounds) {\n            footer.paint(bounds, window, cx);\n        }\n    }\n}\n```\n\n### Use Cases\n\n- Dialog boxes (header + content + footer)\n- Cards with multiple sections\n- Form layouts\n- Panels with toolbars\n\n## Scrollable Elements\n\nElements with scrollable content areas.\n\n### Pattern Characteristics\n\n- Manage scroll state (offset, velocity)\n- Handle scroll events (wheel, drag, touch)\n- Paint scrollbars (track and thumb)\n- Clip content to visible area\n\n### Implementation Template\n\n```rust\npub struct ScrollableElement {\n    id: ElementId,\n    content: AnyElement,\n    scroll_offset: Point<Pixels>,\n    content_size: Size<Pixels>,\n}\n\nstruct ScrollPaintState {\n    hitbox: Hitbox,\n    visible_bounds: Bounds<Pixels>,\n}\n\nimpl Element for ScrollableElement {\n    type RequestLayoutState = (LayoutId, Size<Pixels>);\n    type PrepaintState = ScrollPaintState;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, (LayoutId, Size<Pixels>))\n    {\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        let content_size = window.layout_bounds(content_layout).size;\n\n        let layout_id = window.request_layout(\n            Style {\n                size: Size {\n                    width: relative(1.0),\n                    height: px(400.), // Fixed viewport height\n                },\n                overflow: Overflow::Hidden,\n                ..default()\n            },\n            vec![content_layout],\n            cx\n        );\n\n        (layout_id, (content_layout, content_size))\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut (LayoutId, Size<Pixels>),\n                window: &mut Window, cx: &mut App) -> ScrollPaintState\n    {\n        let (content_layout, content_size) = layout;\n\n        // Calculate content bounds with scroll offset\n        let content_bounds = Bounds::new(\n            point(bounds.left(), bounds.top() - self.scroll_offset.y),\n            *content_size\n        );\n\n        self.content.prepaint(content_bounds, window, cx);\n\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n        ScrollPaintState {\n            hitbox,\n            visible_bounds: bounds,\n        }\n    }\n\n    fn paint(&mut self, .., layout: &mut (LayoutId, Size<Pixels>),\n             paint_state: &mut ScrollPaintState, window: &mut Window, cx: &mut App)\n    {\n        let (_, content_size) = layout;\n\n        // Paint content\n        self.content.paint(paint_state.visible_bounds, window, cx);\n\n        // Paint scrollbar\n        self.paint_scrollbar(paint_state.visible_bounds, *content_size, window, cx);\n\n        // Handle scroll events\n        window.on_mouse_event({\n            let hitbox = paint_state.hitbox.clone();\n            let content_height = content_size.height;\n            let visible_height = paint_state.visible_bounds.size.height;\n\n            move |event: &ScrollWheelEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Update scroll offset\n                    self.scroll_offset.y -= event.delta.y;\n\n                    // Clamp to valid range\n                    let max_scroll = (content_height - visible_height).max(px(0.));\n                    self.scroll_offset.y = self.scroll_offset.y\n                        .max(px(0.))\n                        .min(max_scroll);\n\n                    cx.notify();\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\nimpl ScrollableElement {\n    fn paint_scrollbar(\n        &self,\n        bounds: Bounds<Pixels>,\n        content_size: Size<Pixels>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let visible_height = bounds.size.height;\n        let content_height = content_size.height;\n\n        if content_height <= visible_height {\n            return; // No scrollbar needed\n        }\n\n        let scrollbar_width = px(8.);\n\n        // Calculate thumb position and size\n        let scroll_ratio = self.scroll_offset.y / (content_height - visible_height);\n        let thumb_height = (visible_height / content_height) * visible_height;\n        let thumb_y = scroll_ratio * (visible_height - thumb_height);\n\n        // Paint track\n        window.paint_quad(paint_quad(\n            Bounds::new(\n                point(bounds.right() - scrollbar_width, bounds.top()),\n                size(scrollbar_width, visible_height)\n            ),\n            Anchor::default(),\n            cx.theme().scrollbar_track,\n        ));\n\n        // Paint thumb\n        window.paint_quad(paint_quad(\n            Bounds::new(\n                point(bounds.right() - scrollbar_width, bounds.top() + thumb_y),\n                size(scrollbar_width, thumb_height)\n            ),\n            Anchor::all(px(4.)),\n            cx.theme().scrollbar_thumb,\n        ));\n    }\n}\n```\n\n### Use Cases\n\n- Scrollable lists\n- Code editors with large files\n- Long-form text content\n- Image galleries\n\n## Pattern Selection Guide\n\n| Need | Pattern | Complexity |\n|------|---------|------------|\n| Display styled text | Text Rendering | Low |\n| Layout multiple children | Container | Low-Medium |\n| Handle clicks/hovers | Interactive | Medium |\n| Complex multi-part UI | Composite | Medium-High |\n| Large content with scrolling | Scrollable | High |\n\nChoose the simplest pattern that meets your requirements, then extend as needed.\n","isInternal":false,"tokens":3265,"sizeBytes":15041},{"name":"element.md","path":"skills/gpui-kit/references/gpui/element.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/element.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Custom Elements\n\n**Contents:** [When to Use](#when-to-use) · [Quick Start](#quick-start) · [Core Concepts](#core-concepts) · [Reference Documentation](#reference-documentation)\n\n## When to Use\n\nUse the low-level `Element` trait when:\n- Need fine-grained control over layout calculation\n- Building complex, performance-critical components\n- Implementing custom layout algorithms (masonry, circular, etc.)\n- High-level `Render`/`RenderOnce` APIs are insufficient\n\n**Prefer `Render`/`RenderOnce` for:** Simple components, standard layouts, declarative UI\n\n## Quick Start\n\nThe `Element` trait provides direct control over three rendering phases:\n\n```rust\nimpl Element for MyElement {\n    type RequestLayoutState = MyLayoutState;  // Data passed to later phases\n    type PrepaintState = MyPaintState;        // Data for painting\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    // Phase 1: Calculate sizes and positions\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Self::RequestLayoutState)\n    {\n        let layout_id = window.request_layout(\n            Style { size: size(px(200.), px(100.)), ..default() },\n            vec![],\n            cx\n        );\n        (layout_id, MyLayoutState { /* ... */ })\n    }\n\n    // Phase 2: Create hitboxes, prepare for painting\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,\n                window: &mut Window, cx: &mut App) -> Self::PrepaintState\n    {\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        MyPaintState { hitbox }\n    }\n\n    // Phase 3: Render and handle interactions\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,\n             paint_state: &mut Self::PrepaintState, window: &mut Window, cx: &mut App)\n    {\n        window.paint_quad(paint_quad(bounds, Anchor::all(px(4.)), cx.theme().background));\n\n        window.on_mouse_event({\n            let hitbox = paint_state.hitbox.clone();\n            move |event: &MouseDownEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Handle interaction\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\n// Enable element to be used as child\nimpl IntoElement for MyElement {\n    type Element = Self;\n    fn into_element(self) -> Self::Element { self }\n}\n```\n\n## Core Concepts\n\n### Three-Phase Rendering\n\n1. **request_layout**: Calculate sizes and positions, return layout ID and state\n2. **prepaint**: Create hitboxes, compute final bounds, prepare for painting\n3. **paint**: Render element, set up interactions (mouse events, cursor styles)\n\n### State Flow\n\n```\nRequestLayoutState → PrepaintState → paint\n```\n\nState flows in one direction through associated types, passed as mutable references between phases.\n\n### Key Operations\n\n- **Layout**: `window.request_layout(style, children, cx)` - Create layout node\n- **Hitboxes**: `window.insert_hitbox(bounds, behavior)` - Create interaction area\n- **Painting**: `window.paint_quad(...)` - Render visual content\n- **Events**: `window.on_mouse_event(handler)` - Handle user input\n\n## Reference Documentation\n\n### Complete API Documentation\n- **API**: See [element-api.md](element-api.md) — associated types, hitbox system, event handling, cursor styles\n- **Examples**: See [element-examples.md](element-examples.md) — text, interactive, complex elements\n- **Patterns**: See [element-patterns.md](element-patterns.md) — text, container, interactive, composite, scrollable\n- **Best Practices**: See [element-best-practices.md](element-best-practices.md) — performance, state, common pitfalls\n- **Advanced**: See [element-advanced.md](element-advanced.md) — masonry/circular layouts, memoization, virtual lists\n","isInternal":false,"tokens":932,"sizeBytes":3978},{"name":"entity-advanced.md","path":"skills/gpui-kit/references/gpui/entity-advanced.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/entity-advanced.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Advanced Entity Patterns\n\n**Contents:** [Entity Collections Management](#entity-collections-management) · [Conditional Update Patterns](#conditional-update-patterns) · [Entity State Machine Pattern](#entity-state-machine-pattern) · [Entity Proxy Pattern](#entity-proxy-pattern) · [Cascading Updates Pattern](#cascading-updates-pattern) · [Entity Snapshot Pattern](#entity-snapshot-pattern) · [Entity Transaction Pattern](#entity-transaction-pattern) · [Entity Pool Pattern](#entity-pool-pattern)\n\n## Entity Collections Management\n\n### Dynamic Collection with Cleanup\n\n```rust\nstruct EntityCollection<T> {\n    strong_refs: Vec<Entity<T>>,\n    weak_refs: Vec<WeakEntity<T>>,\n}\n\nimpl<T> EntityCollection<T> {\n    fn new() -> Self {\n        Self {\n            strong_refs: Vec::new(),\n            weak_refs: Vec::new(),\n        }\n    }\n\n    fn add(&mut self, entity: Entity<T>, cx: &mut App) {\n        self.strong_refs.push(entity.clone());\n        self.weak_refs.push(entity.downgrade());\n    }\n\n    fn remove(&mut self, entity_id: EntityId, cx: &mut App) {\n        self.strong_refs.retain(|e| e.entity_id() != entity_id);\n        self.weak_refs.retain(|w| {\n            w.upgrade()\n                .map(|e| e.entity_id() != entity_id)\n                .unwrap_or(false)\n        });\n    }\n\n    fn cleanup_invalid(&mut self, cx: &mut App) {\n        self.weak_refs.retain(|weak| weak.upgrade().is_some());\n    }\n\n    fn for_each<F>(&self, cx: &mut App, mut f: F)\n    where\n        F: FnMut(&Entity<T>, &mut App),\n    {\n        for entity in &self.strong_refs {\n            f(entity, cx);\n        }\n    }\n\n    fn for_each_weak<F>(&mut self, cx: &mut App, mut f: F)\n    where\n        F: FnMut(Entity<T>, &mut App),\n    {\n        self.weak_refs.retain(|weak| {\n            if let Some(entity) = weak.upgrade() {\n                f(entity, cx);\n                true\n            } else {\n                false // Remove invalid weak references\n            }\n        });\n    }\n}\n```\n\n### Entity Registry Pattern\n\n```rust\nuse std::collections::HashMap;\n\nstruct EntityRegistry<T> {\n    entities: HashMap<EntityId, WeakEntity<T>>,\n}\n\nimpl<T> EntityRegistry<T> {\n    fn new() -> Self {\n        Self {\n            entities: HashMap::new(),\n        }\n    }\n\n    fn register(&mut self, entity: &Entity<T>) {\n        self.entities.insert(entity.entity_id(), entity.downgrade());\n    }\n\n    fn unregister(&mut self, entity_id: EntityId) {\n        self.entities.remove(&entity_id);\n    }\n\n    fn get(&self, entity_id: EntityId) -> Option<Entity<T>> {\n        self.entities.get(&entity_id)?.upgrade()\n    }\n\n    fn cleanup(&mut self) {\n        self.entities.retain(|_, weak| weak.upgrade().is_some());\n    }\n\n    fn count(&self) -> usize {\n        self.entities.len()\n    }\n\n    fn all_entities(&self) -> Vec<Entity<T>> {\n        self.entities\n            .values()\n            .filter_map(|weak| weak.upgrade())\n            .collect()\n    }\n}\n```\n\n## Conditional Update Patterns\n\n### Debounced Updates\n\n```rust\nuse std::time::{Duration, Instant};\n\nstruct DebouncedEntity<T> {\n    entity: Entity<T>,\n    last_update: Instant,\n    debounce_duration: Duration,\n    pending_update: Option<Box<dyn FnOnce(&mut T, &mut Context<T>)>>,\n}\n\nimpl<T: 'static> DebouncedEntity<T> {\n    fn new(entity: Entity<T>, debounce_ms: u64) -> Self {\n        Self {\n            entity,\n            last_update: Instant::now(),\n            debounce_duration: Duration::from_millis(debounce_ms),\n            pending_update: None,\n        }\n    }\n\n    fn update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: FnOnce(&mut T, &mut Context<T>) + 'static,\n    {\n        let now = Instant::now();\n        let elapsed = now.duration_since(self.last_update);\n\n        if elapsed >= self.debounce_duration {\n            // Execute immediately\n            self.entity.update(cx, update_fn);\n            self.last_update = now;\n            self.pending_update = None;\n        } else {\n            // Store for later\n            self.pending_update = Some(Box::new(update_fn));\n\n            // Schedule execution\n            let entity = self.entity.clone();\n            let delay = self.debounce_duration - elapsed;\n\n            cx.spawn(async move |cx| {\n                tokio::time::sleep(delay).await;\n\n                if let Some(update) = self.pending_update.take() {\n                    entity.update(cx, |state, inner_cx| {\n                        update(state, inner_cx);\n                    });\n                }\n            }).detach();\n        }\n    }\n}\n```\n\n### Throttled Updates\n\n```rust\nstruct ThrottledEntity<T> {\n    entity: Entity<T>,\n    last_update: Instant,\n    throttle_duration: Duration,\n}\n\nimpl<T: 'static> ThrottledEntity<T> {\n    fn new(entity: Entity<T>, throttle_ms: u64) -> Self {\n        Self {\n            entity,\n            last_update: Instant::now(),\n            throttle_duration: Duration::from_millis(throttle_ms),\n        }\n    }\n\n    fn try_update<F>(&mut self, cx: &mut App, update_fn: F) -> bool\n    where\n        F: FnOnce(&mut T, &mut Context<T>),\n    {\n        let now = Instant::now();\n        let elapsed = now.duration_since(self.last_update);\n\n        if elapsed >= self.throttle_duration {\n            self.entity.update(cx, update_fn);\n            self.last_update = now;\n            true\n        } else {\n            false // Update throttled\n        }\n    }\n}\n```\n\n## Entity State Machine Pattern\n\n```rust\nenum AppState {\n    Idle,\n    Loading,\n    Loaded(String),\n    Error(String),\n}\n\nstruct StateMachine {\n    state: AppState,\n}\n\nimpl StateMachine {\n    fn new() -> Self {\n        Self {\n            state: AppState::Idle,\n        }\n    }\n\n    fn start_loading(&mut self, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Idle | AppState::Error(_)) {\n            self.state = AppState::Loading;\n            cx.notify();\n\n            let weak_entity = cx.entity().downgrade();\n\n            cx.spawn(async move |cx| {\n                let result = perform_load().await;\n\n                let _ = weak_entity.update(cx, |state, cx| {\n                    match result {\n                        Ok(data) => state.on_load_success(data, cx),\n                        Err(e) => state.on_load_error(e.to_string(), cx),\n                    }\n                });\n            }).detach();\n        }\n    }\n\n    fn on_load_success(&mut self, data: String, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Loading) {\n            self.state = AppState::Loaded(data);\n            cx.notify();\n        }\n    }\n\n    fn on_load_error(&mut self, error: String, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Loading) {\n            self.state = AppState::Error(error);\n            cx.notify();\n        }\n    }\n\n    fn reset(&mut self, cx: &mut Context<Self>) {\n        self.state = AppState::Idle;\n        cx.notify();\n    }\n}\n\nasync fn perform_load() -> Result<String, anyhow::Error> {\n    // Actual load implementation\n    Ok(\"Data\".to_string())\n}\n```\n\n## Entity Proxy Pattern\n\n```rust\nstruct EntityProxy<T> {\n    entity: WeakEntity<T>,\n}\n\nimpl<T> EntityProxy<T> {\n    fn new(entity: &Entity<T>) -> Self {\n        Self {\n            entity: entity.downgrade(),\n        }\n    }\n\n    fn with<F, R>(&self, cx: &mut App, f: F) -> Result<R, anyhow::Error>\n    where\n        F: FnOnce(&T, &App) -> R,\n    {\n        self.entity.read_with(cx, f)\n    }\n\n    fn update<F, R>(&self, cx: &mut App, f: F) -> Result<R, anyhow::Error>\n    where\n        F: FnOnce(&mut T, &mut Context<T>) -> R,\n    {\n        self.entity.update(cx, f)\n    }\n\n    fn is_valid(&self, cx: &App) -> bool {\n        self.entity.upgrade().is_some()\n    }\n}\n```\n\n## Cascading Updates Pattern\n\n```rust\nstruct CascadingUpdater {\n    entities: Vec<WeakEntity<UpdateTarget>>,\n}\n\nimpl CascadingUpdater {\n    fn new() -> Self {\n        Self {\n            entities: Vec::new(),\n        }\n    }\n\n    fn add_target(&mut self, entity: &Entity<UpdateTarget>) {\n        self.entities.push(entity.downgrade());\n    }\n\n    fn cascade_update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: Fn(&mut UpdateTarget, &mut Context<UpdateTarget>) + Clone,\n    {\n        // Update all entities in sequence\n        self.entities.retain(|weak| {\n            if let Ok(_) = weak.update(cx, |state, inner_cx| {\n                update_fn.clone()(state, inner_cx);\n            }) {\n                true // Keep valid entity\n            } else {\n                false // Remove invalid entity\n            }\n        });\n    }\n}\n\nstruct UpdateTarget {\n    value: i32,\n}\n```\n\n## Entity Snapshot Pattern\n\n```rust\nuse serde::{Serialize, Deserialize};\n\n#[derive(Clone, Serialize, Deserialize)]\nstruct EntitySnapshot {\n    data: String,\n    timestamp: u64,\n}\n\nstruct SnapshotableEntity {\n    data: String,\n    snapshots: Vec<EntitySnapshot>,\n}\n\nimpl SnapshotableEntity {\n    fn new(data: String) -> Self {\n        Self {\n            data,\n            snapshots: Vec::new(),\n        }\n    }\n\n    fn take_snapshot(&mut self, cx: &mut Context<Self>) {\n        let snapshot = EntitySnapshot {\n            data: self.data.clone(),\n            timestamp: current_timestamp(),\n        };\n        self.snapshots.push(snapshot);\n        cx.notify();\n    }\n\n    fn restore_snapshot(&mut self, index: usize, cx: &mut Context<Self>) -> Result<(), String> {\n        if let Some(snapshot) = self.snapshots.get(index) {\n            self.data = snapshot.data.clone();\n            cx.notify();\n            Ok(())\n        } else {\n            Err(\"Invalid snapshot index\".to_string())\n        }\n    }\n\n    fn clear_old_snapshots(&mut self, keep_last: usize, cx: &mut Context<Self>) {\n        if self.snapshots.len() > keep_last {\n            self.snapshots.drain(0..self.snapshots.len() - keep_last);\n            cx.notify();\n        }\n    }\n}\n\nfn current_timestamp() -> u64 {\n    use std::time::{SystemTime, UNIX_EPOCH};\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .unwrap()\n        .as_secs()\n}\n```\n\n## Entity Transaction Pattern\n\n```rust\nstruct Transaction<T> {\n    entity: Entity<T>,\n    original_state: Option<T>,\n}\n\nimpl<T: Clone> Transaction<T> {\n    fn begin(entity: Entity<T>, cx: &mut App) -> Self {\n        let original_state = entity.read(cx).clone();\n\n        Self {\n            entity,\n            original_state: Some(original_state),\n        }\n    }\n\n    fn update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: FnOnce(&mut T, &mut Context<T>),\n    {\n        self.entity.update(cx, update_fn);\n    }\n\n    fn commit(mut self, cx: &mut App) {\n        self.original_state = None; // Don't rollback\n        self.entity.update(cx, |_, cx| {\n            cx.notify();\n        });\n    }\n\n    fn rollback(mut self, cx: &mut App) {\n        if let Some(original) = self.original_state.take() {\n            self.entity.update(cx, |state, cx| {\n                *state = original;\n                cx.notify();\n            });\n        }\n    }\n}\n\nimpl<T> Drop for Transaction<T> {\n    fn drop(&mut self) {\n        // Auto-rollback if not committed\n        if self.original_state.is_some() {\n            eprintln!(\"Warning: Transaction dropped without commit\");\n        }\n    }\n}\n\n// Usage\nfn perform_transaction(entity: Entity<MyState>, cx: &mut App) -> Result<(), String> {\n    let mut tx = Transaction::begin(entity, cx);\n\n    tx.update(cx, |state, cx| {\n        state.value = 42;\n    });\n\n    if validate_state(&tx.entity, cx)? {\n        tx.commit(cx);\n        Ok(())\n    } else {\n        tx.rollback(cx);\n        Err(\"Validation failed\".to_string())\n    }\n}\n```\n\n## Entity Pool Pattern\n\n```rust\nstruct EntityPool<T> {\n    available: Vec<Entity<T>>,\n    in_use: Vec<WeakEntity<T>>,\n    factory: Box<dyn Fn(&mut App) -> Entity<T>>,\n}\n\nimpl<T: 'static> EntityPool<T> {\n    fn new<F>(factory: F) -> Self\n    where\n        F: Fn(&mut App) -> Entity<T> + 'static,\n    {\n        Self {\n            available: Vec::new(),\n            in_use: Vec::new(),\n            factory: Box::new(factory),\n        }\n    }\n\n    fn acquire(&mut self, cx: &mut App) -> Entity<T> {\n        let entity = if let Some(entity) = self.available.pop() {\n            entity\n        } else {\n            (self.factory)(cx)\n        };\n\n        self.in_use.push(entity.downgrade());\n        entity\n    }\n\n    fn release(&mut self, entity: Entity<T>, cx: &mut App) {\n        // Reset entity state if needed\n        entity.update(cx, |state, cx| {\n            // Reset logic here\n            cx.notify();\n        });\n\n        self.available.push(entity);\n        self.cleanup_in_use();\n    }\n\n    fn cleanup_in_use(&mut self) {\n        self.in_use.retain(|weak| weak.upgrade().is_some());\n    }\n\n    fn pool_size(&self) -> (usize, usize) {\n        (self.available.len(), self.in_use.len())\n    }\n}\n```\n\nThese advanced patterns provide powerful abstractions for managing complex entity scenarios while maintaining code quality and performance.\n","isInternal":false,"tokens":3054,"sizeBytes":12924},{"name":"entity-api.md","path":"skills/gpui-kit/references/gpui/entity-api.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/entity-api.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Entity API Reference\n\n**Contents:** [Entity Types](#entity-types) · [Entity Creation](#entity-creation) · [Entity Operations](#entity-operations) · [Context Methods](#context-methods-for-entities) · [Async Operations](#async-operations) · [Entity Lifecycle](#entity-lifecycle) · [EntityId](#entityid) · [Error Handling](#error-handling) · [Type Conversions](#type-conversions)\n\n## Entity Types\n\n### Entity<T>\n\nA strong reference to state of type `T`.\n\n**Methods:**\n- `entity_id()` → `EntityId` - Returns unique identifier\n- `downgrade()` → `WeakEntity<T>` - Creates weak reference\n- `read(cx)` → `&T` - Immutable access to state\n- `read_with(cx, |state, cx| ...)` → `R` - Read with closure, returns closure result\n- `update(cx, |state, cx| ...)` → `R` - Mutable update with `Context<T>`, returns closure result\n- `update_in(cx, |state, window, cx| ...)` → `R` - Update with `Window` access (requires `AsyncWindowContext` or `VisualTestContext`)\n\n**Important Notes:**\n- Trying to update an entity while it's already being updated will panic\n- Within closures, use the inner `cx` provided to avoid multiple borrow issues\n- With async contexts, return values are wrapped in `anyhow::Result`\n\n### WeakEntity<T>\n\nA weak reference to state of type `T`.\n\n**Methods:**\n- `upgrade()` → `Option<Entity<T>>` - Convert to strong reference if still alive\n- `read_with(cx, |state, cx| ...)` → `Result<R>` - Read if entity exists\n- `update(cx, |state, cx| ...)` → `Result<R>` - Update if entity exists\n- `update_in(cx, |state, window, cx| ...)` → `Result<R>` - Update with window if entity exists\n\n**Use Cases:**\n- Avoid circular dependencies between entities\n- Store references in closures/callbacks without preventing cleanup\n- Optional relationships between components\n\n**Important:** All operations return `Result` since the entity may no longer exist.\n\n### AnyEntity\n\nDynamically-typed entity handle for storing entities of different types.\n\n### AnyWeakEntity\n\nDynamically-typed weak entity handle.\n\n## Entity Creation\n\n### cx.new()\n\nCreate new entity with initial state.\n\n```rust\nlet entity = cx.new(|cx| MyState {\n    count: 0,\n    name: \"Default\".to_string(),\n});\n```\n\n**Parameters:**\n- `cx: &mut App` or other context type\n- Closure receiving `&mut Context<T>` returning initial state `T`\n\n**Returns:** `Entity<T>`\n\n## Entity Operations\n\n### Reading State\n\n#### read()\n\nDirect read-only access to state.\n\n```rust\nlet count = my_entity.read(cx).count;\n```\n\n**Use when:** Simple field access, no context operations needed.\n\n#### read_with()\n\nRead with context access in closure.\n\n```rust\nlet count = my_entity.read_with(cx, |state, cx| {\n    // Can access both state and context\n    state.count\n});\n\n// Return multiple values\nlet (count, theme) = my_entity.read_with(cx, |state, cx| {\n    (state.count, cx.theme().clone())\n});\n```\n\n**Use when:** Need context operations, multiple return values, complex logic.\n\n### Updating State\n\n#### update()\n\nMutable update with `Context<T>`.\n\n```rust\nmy_entity.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify(); // Trigger re-render\n});\n```\n\n**Available Operations:**\n- `cx.notify()` - Trigger re-render\n- `cx.entity()` - Get current entity\n- `cx.emit(event)` - Emit event\n- `cx.spawn(task)` - Spawn async task\n- Other `Context<T>` methods\n\n#### update_in()\n\nUpdate with both `Window` and `Context<T>` access.\n\n```rust\nmy_entity.update_in(cx, |state, window, cx| {\n    state.focused = window.is_window_focused();\n    cx.notify();\n});\n```\n\n**Requires:** `AsyncWindowContext` or `VisualTestContext`\n\n**Use when:** Need window-specific operations like focus state, window bounds, etc.\n\n## Context Methods for Entities\n\n### cx.entity()\n\nGet current entity being updated.\n\n```rust\nimpl MyComponent {\n    fn some_method(&mut self, cx: &mut Context<Self>) {\n        let current_entity = cx.entity();  // Entity<MyComponent>\n        let weak = current_entity.downgrade();\n    }\n}\n```\n\n### cx.observe()\n\nObserve entity for changes.\n\n```rust\ncx.observe(&entity, |this, observed_entity, cx| {\n    // Called when observed_entity.update() calls cx.notify()\n    println!(\"Entity changed\");\n}).detach();\n```\n\n**Returns:** `Subscription` - Call `.detach()` to make permanent\n\n### cx.subscribe()\n\nSubscribe to events from entity.\n\n```rust\ncx.subscribe(&entity, |this, emitter, event: &SomeEvent, cx| {\n    // Called when emitter emits SomeEvent\n    match event {\n        SomeEvent::DataChanged => {\n            cx.notify();\n        }\n    }\n}).detach();\n```\n\n**Returns:** `Subscription` - Call `.detach()` to make permanent\n\n### cx.observe_new_entities()\n\nRegister callback for new entities of a type.\n\n```rust\ncx.observe_new_entities::<MyState>(|entity, cx| {\n    println!(\"New entity created: {:?}\", entity.entity_id());\n}).detach();\n```\n\n## Async Operations\n\n### cx.spawn()\n\nSpawn foreground task (UI thread).\n\n```rust\ncx.spawn(async move |this, cx| {\n    // `this`: WeakEntity<T>\n    // `cx`: &mut AsyncApp\n\n    let result = some_async_work().await;\n\n    // Update entity safely\n    let _ = this.update(cx, |state, cx| {\n        state.data = result;\n        cx.notify();\n    });\n}).detach();\n```\n\n**Note:** Always use weak entity reference in spawned tasks to prevent retain cycles.\n\n### cx.background_spawn()\n\nSpawn background task (background thread).\n\n```rust\ncx.background_spawn(async move {\n    // Long-running computation\n    let result = heavy_computation().await;\n    // Cannot directly update entities here\n    // Use channels or spawn foreground task to update\n}).detach();\n```\n\n## Entity Lifecycle\n\n### Creation\n\nEntities are created via `cx.new()` and immediately registered in the app.\n\n### Reference Counting\n\n- `Entity<T>` is a strong reference (increases reference count)\n- `WeakEntity<T>` is a weak reference (does not increase reference count)\n- Cloning `Entity<T>` increases reference count\n\n### Disposal\n\nEntities are automatically disposed when all strong references are dropped.\n\n```rust\n{\n    let entity = cx.new(|cx| MyState::default());\n    // entity exists\n} // entity dropped here if no other strong references exist\n```\n\n**Memory Leak Prevention:**\n- Use `WeakEntity` in closures/callbacks\n- Use `WeakEntity` for parent-child relationships\n- Avoid circular strong references\n\n## EntityId\n\nEvery entity has a unique identifier.\n\n```rust\nlet id: EntityId = entity.entity_id();\n\n// EntityIds can be compared\nif entity1.entity_id() == entity2.entity_id() {\n    // Same entity\n}\n```\n\n**Use Cases:**\n- Debugging and logging\n- Entity comparison without borrowing\n- Hash maps keyed by entity\n\n## Error Handling\n\n### WeakEntity Operations\n\nAll `WeakEntity` operations return `Result`:\n\n```rust\nlet weak = entity.downgrade();\n\n// Handle potential failure\nmatch weak.read_with(cx, |state, cx| state.count) {\n    Ok(count) => println!(\"Count: {}\", count),\n    Err(e) => eprintln!(\"Entity no longer exists: {}\", e),\n}\n\n// Or use Result combinators\nlet _ = weak.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify();\n}).ok(); // Ignore errors\n```\n\n### Update Panics\n\nNested updates on the same entity will panic:\n\n```rust\n// ❌ Will panic\nentity.update(cx, |state1, cx| {\n    entity.update(cx, |state2, cx| {\n        // Panic: entity already borrowed\n    });\n});\n```\n\n**Solution:** Perform updates sequentially or use different entities.\n\n## Type Conversions\n\n### Entity → WeakEntity\n\n```rust\nlet entity: Entity<T> = cx.new(|cx| T::default());\nlet weak: WeakEntity<T> = entity.downgrade();\n```\n\n### WeakEntity → Entity\n\n```rust\nlet weak: WeakEntity<T> = entity.downgrade();\nlet strong: Option<Entity<T>> = weak.upgrade();\n```\n\n### AnyEntity\n\n```rust\nlet any: AnyEntity = entity.into();\nlet typed: Option<Entity<T>> = any.downcast::<T>();\n```\n\n## Best Practice Guidelines\n\n### Always Use Inner cx\n\n```rust\n// ✅ Good: Use inner cx\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Use inner_cx, not outer cx\n});\n\n// ❌ Bad: Use outer cx\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong! Multiple borrow error\n});\n```\n\n### Weak References in Closures\n\n```rust\n// ✅ Good: Weak reference\nlet weak = cx.entity().downgrade();\ncallback(move || {\n    let _ = weak.update(cx, |state, cx| {\n        cx.notify();\n    });\n});\n\n// ❌ Bad: Strong reference (retain cycle)\nlet strong = cx.entity();\ncallback(move || {\n    strong.update(cx, |state, cx| {\n        // May never be dropped\n        cx.notify();\n    });\n});\n```\n\n### Sequential Updates\n\n```rust\n// ✅ Good: Sequential updates\nentity1.update(cx, |state, cx| { /* ... */ });\nentity2.update(cx, |state, cx| { /* ... */ });\n\n// ❌ Bad: Nested updates\nentity1.update(cx, |_, cx| {\n    entity2.update(cx, |_, cx| {\n        // May panic if entities are related\n    });\n});\n```\n","isInternal":false,"tokens":2161,"sizeBytes":8739},{"name":"entity-best-practices.md","path":"skills/gpui-kit/references/gpui/entity-best-practices.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/entity-best-practices.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Entity Best Practices\n\n**Contents:** [Avoiding Common Pitfalls](#avoiding-common-pitfalls) · [Performance Optimization](#performance-optimization) · [Entity Lifecycle Management](#entity-lifecycle-management) · [Entity Observation Best Practices](#entity-observation-best-practices) · [Async Best Practices](#async-best-practices) · [Testing Best Practices](#testing-best-practices) · [Performance Checklist](#performance-checklist)\n\n## Avoiding Common Pitfalls\n\n### Avoid Re-entrant Entity Access (Same Entity)\n\n**Problem:** GPUI locks an entity for the entire duration of its render or update pass. Any attempt to `read` or `update` that *same* entity while the lock is held panics:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: entity_a updated from within entity_a's own update\nentity_a.update(cx, |_, cx| {\n    entity_a.update(cx, |_, _| {}); // PANIC\n});\n\n// ✅ Fine: updating a *different* entity from within an update\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, _| {}); // OK — different lock\n});\n```\n\n**Note:** Updating two *different* entities in a nested fashion is safe. The restriction is strictly about re-entering the *same* entity's lock.\n\n### `defer_in` Re-locks the Entity — Same Rules Apply\n\n`cx.defer_in(window, callback)` schedules `callback` to run *on the entity the context refers to*. GPUI re-acquires that entity's lock to execute the deferred callback, so the re-entrancy rules apply equally inside it:\n\n```rust\n// ❌ Panic: defer_in runs with ListState locked; calling list.update re-enters\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // list_state IS locked for this entire callback!\n        parent.update(cx, |this, cx| {\n            this.list.update(cx, |_, _| {}); // PANIC — re-enters ListState lock\n        });\n    });\n}\n```\n\n**Fix:** Use the direct `&mut` reference the callback provides instead of going through the entity handle:\n\n```rust\n// ✅ Correct: direct mutable access — no lock needed\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // Step 1: call hooks directly through list_state (no entity lock)\n        list_state.delegate_mut().on_will_change(&mut op, &snapshot);\n\n        // Step 2: update the parent entity — different lock, safe\n        let new_sel = parent.update(cx, |this, cx| {\n            this.state.apply_change(op);\n            cx.notify();\n            this.state.selection.clone() // return data needed for step 3\n        });\n\n        // Step 3: sync list state directly — no entity lock\n        if let Ok(sel) = new_sel {\n            list_state.delegate_mut().update_snapshot(sel.clone());\n            list_state.delegate_mut().on_confirm(&sel);\n        }\n    });\n}\n```\n\n### Render Callbacks Must Not Access External Entities\n\n`render_item` and any other rendering hook runs inside the entity's render pass. Calling `entity.read(cx)` or `entity.update(cx, …)` on an external entity (which may itself be in a render/update pass) panics with the same re-entrancy error.\n\n**Fix:** Keep a plain `snapshot` field updated eagerly from outside render after every mutation:\n\n```rust\n// ❌ Panic — called during ListState render; external entity access re-enters\nfn render_item(&mut self, ix: IndexPath, …) -> … {\n    let checked = parent.read(cx).selection.contains(&ix); // PANIC\n}\n\n// ✅ Read from snapshot field — no entity access at all\nfn render_item(&mut self, ix: IndexPath, …) -> … {\n    let checked = self.selection_snapshot.iter().any(|(sel_ix, _)| sel_ix == &ix);\n}\n// After every mutation from outside render:\nlist.update(cx, |l, _| l.delegate_mut().update_snapshot(new_snapshot));\n```\n\n### Use Weak References in Closures\n\n**Problem:** Strong references in closures can create retain cycles and memory leaks.\n\n```rust\n// ❌ Bad: Strong reference creates retain cycle\nimpl MyComponent {\n    fn setup_callback(&mut self, cx: &mut Context<Self>) {\n        let entity = cx.entity(); // Strong reference\n\n        some_callback(move || {\n            entity.update(cx, |state, cx| {\n                // This closure holds a strong reference\n                // If the closure itself is retained by the entity, memory leak!\n                cx.notify();\n            });\n        });\n    }\n}\n```\n\n**Solution:** Use weak references in closures.\n\n```rust\n// ✅ Good: Weak reference prevents retain cycle\nimpl MyComponent {\n    fn setup_callback(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade(); // Weak reference\n\n        some_callback(move || {\n            // Safe: weak reference doesn't prevent cleanup\n            let _ = weak_entity.update(cx, |state, cx| {\n                cx.notify();\n            });\n        });\n    }\n}\n```\n\n### Use Inner Context in Closures\n\n**Problem:** Using outer context causes multiple borrow errors.\n\n```rust\n// ❌ Bad: Using outer cx causes borrow issues\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong! Using outer cx\n    cx.spawn(...); // Multiple borrow error\n});\n```\n\n**Solution:** Always use the inner context provided to the closure.\n\n```rust\n// ✅ Good: Use inner cx\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Correct\n    inner_cx.spawn(...); // Works fine\n});\n```\n\n### Entity as Props - Use Weak References\n\n**Problem:** Strong entity references in props can create ownership issues.\n\n```rust\n// ❌ Questionable: Strong reference in child\nstruct ChildComponent {\n    parent: Entity<ParentComponent>, // Strong reference\n}\n```\n\n**Better:** Use weak references for parent relationships.\n\n```rust\n// ✅ Good: Weak reference prevents issues\nstruct ChildComponent {\n    parent: WeakEntity<ParentComponent>, // Weak reference\n}\n\nimpl ChildComponent {\n    fn notify_parent(&mut self, cx: &mut Context<Self>) {\n        // Check if parent still exists\n        if let Ok(_) = self.parent.update(cx, |parent_state, cx| {\n            // Update parent\n            cx.notify();\n        }) {\n            // Parent successfully updated\n        }\n    }\n}\n```\n\n## Performance Optimization\n\n### Minimize cx.notify() Calls\n\nEach `cx.notify()` triggers a re-render. Batch updates when possible.\n\n```rust\n// ❌ Bad: Multiple notifications\nimpl MyComponent {\n    fn update_multiple_fields(&mut self, cx: &mut Context<Self>) {\n        self.field1 = new_value1;\n        cx.notify(); // Unnecessary intermediate notification\n\n        self.field2 = new_value2;\n        cx.notify(); // Unnecessary intermediate notification\n\n        self.field3 = new_value3;\n        cx.notify();\n    }\n}\n```\n\n```rust\n// ✅ Good: Single notification after all updates\nimpl MyComponent {\n    fn update_multiple_fields(&mut self, cx: &mut Context<Self>) {\n        self.field1 = new_value1;\n        self.field2 = new_value2;\n        self.field3 = new_value3;\n        cx.notify(); // Single notification\n    }\n}\n```\n\n### Conditional Updates\n\nOnly notify when state actually changes.\n\n```rust\nimpl MyComponent {\n    fn set_value(&mut self, new_value: i32, cx: &mut Context<Self>) {\n        if self.value != new_value {\n            self.value = new_value;\n            cx.notify(); // Only notify if changed\n        }\n    }\n}\n```\n\n### Use read_with for Complex Operations\n\nPrefer `read_with` over separate `read` calls.\n\n```rust\n// ❌ Less efficient: Multiple borrows\nlet state_ref = entity.read(cx);\nlet value1 = state_ref.field1;\nlet value2 = state_ref.field2;\n// state_ref borrowed for entire scope\n\n// ✅ More efficient: Single borrow with closure\nlet (value1, value2) = entity.read_with(cx, |state, cx| {\n    (state.field1, state.field2)\n});\n```\n\n### Avoid Excessive Entity Creation\n\nCreating entities has overhead. Reuse when appropriate.\n\n```rust\n// ❌ Bad: Creating entity per item in render\nimpl Render for MyList {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div().children(\n            self.items.iter().map(|item| {\n                // Don't create entities in render!\n                let entity = cx.new(|_| item.clone());\n                ItemView { entity }\n            })\n        )\n    }\n}\n```\n\n```rust\n// ✅ Good: Create entities once, reuse\nstruct MyList {\n    item_entities: Vec<Entity<Item>>,\n}\n\nimpl MyList {\n    fn add_item(&mut self, item: Item, cx: &mut Context<Self>) {\n        let entity = cx.new(|_| item);\n        self.item_entities.push(entity);\n        cx.notify();\n    }\n}\n```\n\n## Entity Lifecycle Management\n\n### Clean Up Weak References\n\nPeriodically clean up invalid weak references from collections.\n\n```rust\nstruct Container {\n    weak_children: Vec<WeakEntity<Child>>,\n}\n\nimpl Container {\n    fn cleanup_invalid_children(&mut self, cx: &mut Context<Self>) {\n        // Remove weak references that are no longer valid\n        let before_count = self.weak_children.len();\n        self.weak_children.retain(|weak| weak.upgrade().is_some());\n        let after_count = self.weak_children.len();\n\n        if before_count != after_count {\n            cx.notify(); // Notify if list changed\n        }\n    }\n}\n```\n\n### Entity Cloning and Sharing\n\nUnderstand that cloning `Entity<T>` increases reference count.\n\n```rust\n// Each clone increases the reference count\nlet entity1: Entity<MyState> = cx.new(|_| MyState::default());\nlet entity2 = entity1.clone(); // Reference count: 2\nlet entity3 = entity1.clone(); // Reference count: 3\n\n// Entity is dropped only when all references are dropped\ndrop(entity1); // Reference count: 2\ndrop(entity2); // Reference count: 1\ndrop(entity3); // Reference count: 0, entity is deallocated\n```\n\n### Proper Resource Cleanup\n\nImplement cleanup in `Drop` or explicit cleanup methods.\n\n```rust\nstruct ManagedResource {\n    handle: Option<FileHandle>,\n}\n\nimpl ManagedResource {\n    fn close(&mut self, cx: &mut Context<Self>) {\n        if let Some(handle) = self.handle.take() {\n            // Explicit cleanup\n            handle.close();\n            cx.notify();\n        }\n    }\n}\n\nimpl Drop for ManagedResource {\n    fn drop(&mut self) {\n        // Automatic cleanup when entity is dropped\n        if let Some(handle) = self.handle.take() {\n            handle.close();\n        }\n    }\n}\n```\n\n## Entity Observation Best Practices\n\n### Detach Subscriptions Appropriately\n\nCall `.detach()` on subscriptions you want to keep alive.\n\n```rust\nimpl MyComponent {\n    fn new(other_entity: Entity<OtherComponent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observer will live as long as both entities exist\n            cx.observe(&other_entity, |this, observed, cx| {\n                // Handle changes\n                cx.notify();\n            }).detach(); // Important: detach to make permanent\n\n            Self { /* fields */ }\n        })\n    }\n}\n```\n\n### Avoid Observation Cycles\n\nDon't create mutual observation between entities.\n\n```rust\n// ❌ Bad: Mutual observation can cause infinite loops\nentity1.update(cx, |_, cx| {\n    cx.observe(&entity2, |_, _, cx| {\n        cx.notify(); // May trigger entity2's observer\n    }).detach();\n});\n\nentity2.update(cx, |_, cx| {\n    cx.observe(&entity1, |_, _, cx| {\n        cx.notify(); // May trigger entity1's observer → infinite loop\n    }).detach();\n});\n```\n\n## Async Best Practices\n\n### Always Use Weak References in Async Tasks\n\n```rust\n// ✅ Good: Weak reference in spawned task\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            let data = fetch_from_api().await;\n\n            // Entity may have been dropped during fetch\n            let _ = weak_entity.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n```\n\n### Handle Async Errors Gracefully\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            match fetch_from_api().await {\n                Ok(data) => {\n                    let _ = weak_entity.update(cx, |state, cx| {\n                        state.data = Some(data);\n                        state.error = None;\n                        cx.notify();\n                    });\n                }\n                Err(e) => {\n                    let _ = weak_entity.update(cx, |state, cx| {\n                        state.error = Some(e.to_string());\n                        cx.notify();\n                    });\n                }\n            }\n        }).detach();\n    }\n}\n```\n\n### Cancellation Patterns\n\nImplement cancellation for long-running tasks.\n\n```rust\nstruct DataFetcher {\n    current_task: Option<Task<()>>,\n    data: Option<String>,\n}\n\nimpl DataFetcher {\n    fn fetch_data(&mut self, url: String, cx: &mut Context<Self>) {\n        // Cancel previous task\n        self.current_task = None; // Dropping task cancels it\n\n        let weak_entity = cx.entity().downgrade();\n\n        let task = cx.spawn(async move |cx| {\n            let data = fetch_from_url(&url).await?;\n\n            let _ = weak_entity.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n\n            Ok::<(), anyhow::Error>(())\n        });\n\n        self.current_task = Some(task);\n    }\n}\n```\n\n## Testing Best Practices\n\n### Use TestAppContext for Entity Tests\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use gpui_kit::TestAppContext;\n\n    #[gpui_kit::test]\n    fn test_entity_update(cx: &mut TestAppContext) {\n        let entity = cx.new(|_| MyState { count: 0 });\n\n        entity.update(cx, |state, cx| {\n            state.count += 1;\n            assert_eq!(state.count, 1);\n        });\n\n        let count = entity.read(cx).count;\n        assert_eq!(count, 1);\n    }\n}\n```\n\n### Test Entity Observation\n\n```rust\n#[gpui_kit::test]\nfn test_entity_observation(cx: &mut TestAppContext) {\n    let observed = cx.new(|_| MyState { value: 0 });\n    let observer = cx.new(|cx| Observer::new(observed.clone(), cx));\n\n    // Update observed entity\n    observed.update(cx, |state, cx| {\n        state.value = 42;\n        cx.notify();\n    });\n\n    // Verify observer was notified\n    observer.read(cx).assert_observed();\n}\n```\n\n## Performance Checklist\n\nBefore shipping entity-based code, verify:\n\n- [ ] No strong references in closures/callbacks (use `WeakEntity`)\n- [ ] No nested entity updates (use sequential updates)\n- [ ] Using inner `cx` in update closures\n- [ ] Batching updates before calling `cx.notify()`\n- [ ] Cleaning up invalid weak references periodically\n- [ ] Using `read_with` for complex read operations\n- [ ] Properly detaching subscriptions and observers\n- [ ] Using weak references in async tasks\n- [ ] No observation cycles between entities\n- [ ] Proper error handling in async operations\n- [ ] Resource cleanup in `Drop` or explicit methods\n- [ ] Tests cover entity lifecycle and interactions\n","isInternal":false,"tokens":3470,"sizeBytes":15095},{"name":"entity-patterns.md","path":"skills/gpui-kit/references/gpui/entity-patterns.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/entity-patterns.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Entity Patterns\n\n**Contents:** [Application Scenarios](#application-scenarios) · [Common Patterns](#common-patterns) · [Pattern Selection Guide](#pattern-selection-guide)\n\n## Application Scenarios\n\n### Model-View Separation\n\nSeparate business logic (model) from UI (view) using entities.\n\n```rust\nstruct CounterModel {\n    count: usize,\n    listeners: Vec<Box<dyn Fn(usize)>>,\n}\n\nstruct CounterView {\n    model: Entity<CounterModel>,\n}\n\nimpl CounterModel {\n    fn increment(&mut self, cx: &mut Context<Self>) {\n        self.count += 1;\n\n        // Notify listeners\n        for listener in &self.listeners {\n            listener(self.count);\n        }\n\n        cx.notify();\n    }\n\n    fn decrement(&mut self, cx: &mut Context<Self>) {\n        if self.count > 0 {\n            self.count -= 1;\n            cx.notify();\n        }\n    }\n}\n\nimpl CounterView {\n    fn new(cx: &mut App) -> Entity<Self> {\n        let model = cx.new(|_cx| CounterModel {\n            count: 0,\n            listeners: Vec::new(),\n        });\n\n        cx.new(|cx| Self { model })\n    }\n\n    fn increment_count(&mut self, cx: &mut Context<Self>) {\n        self.model.update(cx, |model, cx| {\n            model.increment(cx);\n        });\n    }\n}\n\nimpl Render for CounterView {\n    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let count = self.model.read(cx).count;\n\n        div()\n            .child(format!(\"Count: {}\", count))\n            .child(\n                Button::new(\"increment\")\n                    .label(\"Increment\")\n                    .on_click(cx.listener(|this, _, cx| {\n                        this.increment_count(cx);\n                    }))\n            )\n    }\n}\n```\n\n### Component State Management\n\nManaging complex component state with entities.\n\n```rust\nstruct TodoList {\n    todos: Vec<Todo>,\n    filter: TodoFilter,\n    next_id: usize,\n}\n\nstruct Todo {\n    id: usize,\n    text: String,\n    completed: bool,\n}\n\nenum TodoFilter {\n    All,\n    Active,\n    Completed,\n}\n\nimpl TodoList {\n    fn new() -> Self {\n        Self {\n            todos: Vec::new(),\n            filter: TodoFilter::All,\n            next_id: 0,\n        }\n    }\n\n    fn add_todo(&mut self, text: String, cx: &mut Context<Self>) {\n        self.todos.push(Todo {\n            id: self.next_id,\n            text,\n            completed: false,\n        });\n        self.next_id += 1;\n        cx.notify();\n    }\n\n    fn toggle_todo(&mut self, id: usize, cx: &mut Context<Self>) {\n        if let Some(todo) = self.todos.iter_mut().find(|t| t.id == id) {\n            todo.completed = !todo.completed;\n            cx.notify();\n        }\n    }\n\n    fn remove_todo(&mut self, id: usize, cx: &mut Context<Self>) {\n        self.todos.retain(|t| t.id != id);\n        cx.notify();\n    }\n\n    fn set_filter(&mut self, filter: TodoFilter, cx: &mut Context<Self>) {\n        self.filter = filter;\n        cx.notify();\n    }\n\n    fn visible_todos(&self) -> impl Iterator<Item = &Todo> {\n        self.todos.iter().filter(move |todo| match self.filter {\n            TodoFilter::All => true,\n            TodoFilter::Active => !todo.completed,\n            TodoFilter::Completed => todo.completed,\n        })\n    }\n}\n```\n\n### Cross-Entity Communication\n\nCoordinating state between parent and child entities.\n\n```rust\nstruct ParentComponent {\n    child_entities: Vec<Entity<ChildComponent>>,\n    global_message: String,\n}\n\nstruct ChildComponent {\n    id: usize,\n    message: String,\n    parent: WeakEntity<ParentComponent>,\n}\n\nimpl ParentComponent {\n    fn new(cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| Self {\n            child_entities: Vec::new(),\n            global_message: String::new(),\n        })\n    }\n\n    fn add_child(&mut self, cx: &mut Context<Self>) {\n        let parent_weak = cx.entity().downgrade();\n        let child_id = self.child_entities.len();\n\n        let child = cx.new(|cx| ChildComponent {\n            id: child_id,\n            message: String::new(),\n            parent: parent_weak,\n        });\n\n        self.child_entities.push(child);\n        cx.notify();\n    }\n\n    fn broadcast_message(&mut self, message: String, cx: &mut Context<Self>) {\n        self.global_message = message.clone();\n\n        // Update all children\n        for child in &self.child_entities {\n            child.update(cx, |child_state, cx| {\n                child_state.message = message.clone();\n                cx.notify();\n            });\n        }\n\n        cx.notify();\n    }\n}\n\nimpl ChildComponent {\n    fn notify_parent(&mut self, message: String, cx: &mut Context<Self>) {\n        if let Ok(_) = self.parent.update(cx, |parent_state, cx| {\n            parent_state.global_message = format!(\"Child {}: {}\", self.id, message);\n            cx.notify();\n        }) {\n            // Parent successfully notified\n        }\n    }\n}\n```\n\n### Async Operations with Entities\n\nManaging async state updates.\n\n```rust\nstruct DataLoader {\n    loading: bool,\n    data: Option<String>,\n    error: Option<String>,\n}\n\nimpl DataLoader {\n    fn new() -> Self {\n        Self {\n            loading: false,\n            data: None,\n            error: None,\n        }\n    }\n\n    fn load_data(&mut self, cx: &mut Context<Self>) {\n        // Set loading state\n        self.loading = true;\n        self.error = None;\n        cx.notify();\n\n        // Get weak reference for async task\n        let entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            // Simulate async operation\n            tokio::time::sleep(Duration::from_secs(2)).await;\n            let result = fetch_data().await;\n\n            // Update entity with result\n            let _ = entity.update(cx, |state, cx| {\n                state.loading = false;\n                match result {\n                    Ok(data) => state.data = Some(data),\n                    Err(e) => state.error = Some(e.to_string()),\n                }\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n\nasync fn fetch_data() -> Result<String, anyhow::Error> {\n    // Actual fetch implementation\n    Ok(\"Fetched data\".to_string())\n}\n```\n\n### Background Task Coordination\n\nUsing background tasks with entity updates.\n\n```rust\nstruct ImageProcessor {\n    images: Vec<ProcessedImage>,\n    processing: bool,\n}\n\nstruct ProcessedImage {\n    path: PathBuf,\n    thumbnail: Option<Vec<u8>>,\n}\n\nimpl ImageProcessor {\n    fn process_images(&mut self, paths: Vec<PathBuf>, cx: &mut Context<Self>) {\n        self.processing = true;\n        cx.notify();\n\n        cx.spawn(async move |this, cx| {\n            let processed = cx\n                .background_spawn(async move {\n                    let mut processed = Vec::new();\n\n                    for path in paths {\n                        // Process image on background thread\n                        let thumbnail = generate_thumbnail(&path).await;\n                        processed.push((path, thumbnail));\n                    }\n\n                    // Send results back to foreground\n                    processed\n                })\n                .await;\n\n            // Update entity on foreground thread\n            let _ = this.update(cx, |state, cx| {\n                for (path, thumbnail) in processed {\n                    state.images.push(ProcessedImage {\n                        path,\n                        thumbnail: Some(thumbnail),\n                    });\n                }\n                state.processing = false;\n                cx.notify();\n            });\n        })\n        .detach();\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Stateful Components\n\nUse entities for components that maintain internal state.\n\n```rust\nstruct StatefulComponent {\n    value: i32,\n    history: Vec<i32>,\n}\n\nimpl StatefulComponent {\n    fn update_value(&mut self, new_value: i32, cx: &mut Context<Self>) {\n        self.history.push(self.value);\n        self.value = new_value;\n        cx.notify();\n    }\n\n    fn undo(&mut self, cx: &mut Context<Self>) {\n        if let Some(prev_value) = self.history.pop() {\n            self.value = prev_value;\n            cx.notify();\n        }\n    }\n}\n```\n\n### 2. Shared State\n\nShare state between multiple components using entities.\n\n```rust\nstruct SharedState {\n    theme: Theme,\n    user: Option<User>,\n}\n\nstruct ComponentA {\n    shared: Entity<SharedState>,\n}\n\nstruct ComponentB {\n    shared: Entity<SharedState>,\n}\n\n// Both components can read/update the same shared state\nimpl ComponentA {\n    fn update_theme(&mut self, theme: Theme, cx: &mut Context<Self>) {\n        self.shared.update(cx, |state, cx| {\n            state.theme = theme;\n            cx.notify();\n        });\n    }\n}\n```\n\n### 3. Event Coordination\n\nUse entities to coordinate events between components.\n\n```rust\nstruct EventCoordinator {\n    listeners: Vec<WeakEntity<dyn EventListener>>,\n}\n\ntrait EventListener {\n    fn on_event(&mut self, event: &AppEvent, cx: &mut App);\n}\n\nimpl EventCoordinator {\n    fn emit_event(&mut self, event: AppEvent, cx: &mut Context<Self>) {\n        // Notify all listeners\n        self.listeners.retain(|weak_listener| {\n            weak_listener.update(cx, |listener, cx| {\n                listener.on_event(&event, cx);\n            }).is_ok()\n        });\n        cx.notify();\n    }\n}\n```\n\n### 4. Async State Management\n\nManage state that changes based on async operations.\n\n```rust\nstruct AsyncState<T> {\n    state: AsyncValue<T>,\n}\n\nenum AsyncValue<T> {\n    Loading,\n    Loaded(T),\n    Error(String),\n}\n\nimpl<T> AsyncState<T> {\n    fn is_loading(&self) -> bool {\n        matches!(self.state, AsyncValue::Loading)\n    }\n\n    fn value(&self) -> Option<&T> {\n        match &self.state {\n            AsyncValue::Loaded(v) => Some(v),\n            _ => None,\n        }\n    }\n}\n```\n\n### 5. Parent-Child Relationships\n\nManage hierarchical relationships with weak references.\n\n```rust\nstruct Parent {\n    children: Vec<Entity<Child>>,\n}\n\nstruct Child {\n    parent: WeakEntity<Parent>,\n    data: String,\n}\n\nimpl Child {\n    fn notify_parent_of_change(&mut self, cx: &mut Context<Self>) {\n        if let Ok(_) = self.parent.update(cx, |parent, cx| {\n            // Parent can react to child change\n            cx.notify();\n        }) {\n            // Successfully notified\n        }\n    }\n}\n```\n\n### 6. Observer Pattern\n\nReact to entity state changes using observers.\n\n```rust\nstruct Observable {\n    value: i32,\n}\n\nstruct Observer {\n    observed: Entity<Observable>,\n}\n\nimpl Observer {\n    fn new(observed: Entity<Observable>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observe the entity\n            cx.observe(&observed, |this, observed_entity, cx| {\n                // React to changes\n                let value = observed_entity.read(cx).value;\n                println!(\"Value changed to: {}\", value);\n            }).detach();\n\n            Self { observed }\n        })\n    }\n}\n```\n\n### 7. Event Subscription\n\nHandle events emitted by other entities.\n\n```rust\n#[derive(Clone)]\nenum DataEvent {\n    Updated,\n    Deleted,\n}\n\nstruct DataSource {\n    data: Vec<String>,\n}\n\nimpl DataSource {\n    fn update_data(&mut self, cx: &mut Context<Self>) {\n        // Update data\n        cx.emit(DataEvent::Updated);\n        cx.notify();\n    }\n}\n\nstruct DataConsumer {\n    source: Entity<DataSource>,\n}\n\nimpl DataConsumer {\n    fn new(source: Entity<DataSource>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Subscribe to events\n            cx.subscribe(&source, |this, source, event: &DataEvent, cx| {\n                match event {\n                    DataEvent::Updated => {\n                        // Handle update\n                        cx.notify();\n                    }\n                    DataEvent::Deleted => {\n                        // Handle deletion\n                    }\n                }\n            }).detach();\n\n            Self { source }\n        })\n    }\n}\n```\n\n### 8. Resource Management\n\nManage external resources with proper cleanup.\n\n```rust\nstruct FileHandle {\n    path: PathBuf,\n    file: Option<File>,\n}\n\nimpl FileHandle {\n    fn open(&mut self, cx: &mut Context<Self>) -> Result<()> {\n        self.file = Some(File::open(&self.path)?);\n        cx.notify();\n        Ok(())\n    }\n\n    fn close(&mut self, cx: &mut Context<Self>) {\n        self.file = None;\n        cx.notify();\n    }\n}\n\nimpl Drop for FileHandle {\n    fn drop(&mut self) {\n        // Cleanup when entity is dropped\n        if let Some(file) = self.file.take() {\n            drop(file);\n        }\n    }\n}\n```\n\n## Pattern Selection Guide\n\n| Need | Pattern | Complexity |\n|------|---------|------------|\n| Component with internal state | Stateful Components | Low |\n| State shared by multiple components | Shared State | Low |\n| Coordinate events between components | Event Coordination | Medium |\n| Handle async data fetching | Async State Management | Medium |\n| Parent-child component hierarchy | Parent-Child Relationships | Medium |\n| React to state changes | Observer Pattern | Medium |\n| Handle custom events | Event Subscription | Medium-High |\n| Manage external resources | Resource Management | High |\n\nChoose the simplest pattern that meets your requirements. Combine patterns as needed for complex scenarios.\n","isInternal":false,"tokens":2881,"sizeBytes":13189},{"name":"entity.md","path":"skills/gpui-kit/references/gpui/entity.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/entity.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Entity State Management\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Core Principles](#core-principles) · [Common Use Cases](#common-use-cases) · [Extended References](#reference-documentation)\n\n## Overview\n\nAn `Entity<T>` is a handle to state of type `T`, providing safe access and updates.\n\n**Key Methods:**\n- `entity.read(cx)` → `&T` - Read-only access\n- `entity.read_with(cx, |state, cx| ...)` → `R` - Read with closure\n- `entity.update(cx, |state, cx| ...)` → `R` - Mutable update\n- `entity.downgrade()` → `WeakEntity<T>` - Create weak reference\n- `entity.entity_id()` → `EntityId` - Unique identifier\n\n**Entity Types:**\n- **`Entity<T>`**: Strong reference (increases ref count)\n- **`WeakEntity<T>`**: Weak reference (doesn't prevent cleanup, returns `Result`)\n\n## Quick Start\n\n### Creating and Using Entities\n\n```rust\n// Create entity\nlet counter = cx.new(|cx| Counter { count: 0 });\n\n// Read state\nlet count = counter.read(cx).count;\n\n// Update state\ncounter.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify(); // Trigger re-render\n});\n\n// Weak reference (for closures/callbacks)\nlet weak = counter.downgrade();\nlet _ = weak.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify();\n});\n```\n\n### In Components\n\n```rust\nstruct MyComponent {\n    shared_state: Entity<SharedData>,\n}\n\nimpl MyComponent {\n    fn new(cx: &mut App) -> Entity<Self> {\n        let shared = cx.new(|_| SharedData::default());\n\n        cx.new(|cx| Self {\n            shared_state: shared,\n        })\n    }\n\n    fn update_shared(&mut self, cx: &mut Context<Self>) {\n        self.shared_state.update(cx, |state, cx| {\n            state.value = 42;\n            cx.notify();\n        });\n    }\n}\n```\n\n### Async Operations\n\nWhen calling `cx.spawn` from `Context<Self>`, the closure receives `(WeakEntity<Self>, &mut AsyncApp)`:\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx: &mut AsyncApp| {\n            let data = fetch_from_api().await;\n\n            // Update entity safely via the weak reference\n            let _ = this.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n```\n\n## Core Principles\n\n### Always Use Weak References in Closures\n\n```rust\n// ✅ Good: Weak reference prevents retain cycles\nlet weak = cx.entity().downgrade();\ncallback(move || {\n    let _ = weak.update(cx, |state, cx| cx.notify());\n});\n\n// ❌ Bad: Strong reference may cause memory leak\nlet strong = cx.entity();\ncallback(move || {\n    strong.update(cx, |state, cx| cx.notify());\n});\n```\n\n### Use Inner Context\n\n```rust\n// ✅ Good: Use inner cx from closure\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Correct\n});\n\n// ❌ Bad: Use outer cx (multiple borrow error)\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong!\n});\n```\n\n### Avoid Nested Entity Updates\n\nNested `entity.update(cx, …)` calls are dangerous. The default posture is: **do not nest them**. The sub-cases below clarify when a panic is guaranteed vs. merely possible.\n\n**Same entity → always panics.**  \nGPUI locks an entity for the entire duration of its update or render pass. Re-entering that same lock panics immediately:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: updating entity_a from inside entity_a's own update\nentity_a.update(cx, |state, cx| {\n    entity_a.update(cx, |_, _| {}); // PANIC — same lock\n});\n```\n\n**Different entity → generally safe, but indirect cycles still panic.**  \nEach entity has its own lock, so updating `entity_b` from within `entity_a`'s update normally succeeds. However, if `entity_b`'s callback reaches back into `entity_a` — directly or through a chain — GPUI will attempt to re-acquire `entity_a`'s lock and panic.\n\n```rust\n// ✅ Usually fine: different entities, no cycle\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, _| {}); // OK — different lock\n});\n\n// ❌ Panic: indirect cycle back to entity_a\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, cx| {\n        entity_a.update(cx, |_, _| {}); // PANIC — entity_a is still locked\n    });\n});\n```\n\nWhen in doubt, flatten the call sequence rather than nesting: finish the outer update, then update the second entity from outside.\n\n**`defer_in` does not bypass the lock.** `cx.defer_in(window, callback)` schedules `callback` to run on the current entity — meaning GPUI re-acquires the entity's lock to execute it. The re-entrancy rules apply equally inside the deferred callback:\n\n```rust\n// ❌ Panic: defer_in re-locks entity_a; calling entity_a.update inside re-enters\nimpl SomeDelegate for MyAdapter {\n    fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n        cx.defer_in(window, |list_state, window, cx| {\n            // list_state is locked for this callback!\n            parent.update(cx, |this, cx| {\n                this.list.update(cx, |_, _| {}); // PANIC — list is already locked above\n            });\n        });\n    }\n}\n\n// ✅ Fix: use the direct &mut reference the callback provides\nimpl SomeDelegate for MyAdapter {\n    fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n        cx.defer_in(window, |list_state, window, cx| {\n            // Access list data directly — no entity lock needed\n            list_state.delegate_mut().some_hook();\n\n            // Update the *parent* entity — different lock, safe\n            parent.update(cx, |this, cx| { /* … */ });\n\n            // Sync list state directly after parent update\n            list_state.delegate_mut().update_snapshot(new_val);\n        });\n    }\n}\n```\n\n**Snapshot pattern for render callbacks.** `render_item` (and any other rendering hook) runs inside the entity's render pass. It must never call `entity.read(cx)` or `entity.update(cx, …)` on any external entity. Instead, keep a plain `snapshot` field updated eagerly from *outside* render after every mutation:\n\n```rust\n// ❌ Panic in render_item — ListState is already locked\nfn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<ListState<Self>>) -> … {\n    let checked = parent_entity.read(cx).selection.contains(&ix); // PANIC\n}\n\n// ✅ Read from a plain snapshot field — no entity access\nfn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<ListState<Self>>) -> … {\n    let checked = self.selection_snapshot.iter().any(|(sel_ix, _)| sel_ix == &ix);\n}\n```\n\n## Common Use Cases\n\n1. **Component State**: Internal state that needs reactivity\n2. **Shared State**: State shared between multiple components\n3. **Parent-Child**: Coordinating between related components (use weak refs)\n4. **Async State**: Managing state that changes from async operations\n5. **Observations**: Reacting to changes in other entities\n\n## Reference Documentation\n\n- **API**: See [entity-api.md](entity-api.md) — entity types, methods, lifecycle, error handling\n- **Patterns**: See [entity-patterns.md](entity-patterns.md) — model-view, cross-entity communication, observer\n- **Best Practices**: See [entity-best-practices.md](entity-best-practices.md) — pitfalls, memory, performance, async\n- **Advanced**: See [entity-advanced.md](entity-advanced.md) — collections, registry, debounce, state machines\n","isInternal":false,"tokens":1816,"sizeBytes":7413},{"name":"event.md","path":"skills/gpui-kit/references/gpui/event.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/event.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Events & Subscriptions\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Patterns](#common-patterns) · [subscribe_in](#subscribe_in--subscription-with-window-access) · [observe_window_activation](#observe_window_activation) · [observe_global](#observe_global) · [Subscription Lifetime](#subscription-lifetime) · [Best Practices](#best-practices)\n\n## Overview\n\nGPUI provides event system for component coordination:\n\n**Event Mechanisms:**\n- **Custom Events**: Define and emit type-safe events\n- **Observations**: React to entity state changes\n- **Subscriptions**: Listen to events from other entities\n- **Global Events**: App-wide event handling\n\n## Quick Start\n\n### Define and Emit Events\n\n```rust\n#[derive(Clone)]\nenum MyEvent {\n    DataUpdated(String),\n    ActionTriggered,\n}\n\nimpl MyComponent {\n    fn update_data(&mut self, data: String, cx: &mut Context<Self>) {\n        self.data = data.clone();\n\n        // Emit event\n        cx.emit(MyEvent::DataUpdated(data));\n        cx.notify();\n    }\n}\n```\n\n### Subscribe to Events\n\n```rust\nimpl Listener {\n    fn new(source: Entity<MyComponent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Subscribe to events\n            cx.subscribe(&source, |this, emitter, event: &MyEvent, cx| {\n                match event {\n                    MyEvent::DataUpdated(data) => {\n                        this.handle_update(data.clone(), cx);\n                    }\n                    MyEvent::ActionTriggered => {\n                        this.handle_action(cx);\n                    }\n                }\n            }).detach();\n\n            Self { source }\n        })\n    }\n}\n```\n\n### Observe Entity Changes\n\n```rust\nimpl Observer {\n    fn new(target: Entity<Target>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observe entity for any changes\n            cx.observe(&target, |this, observed, cx| {\n                // Called when observed.update() calls cx.notify()\n                println!(\"Target changed\");\n                cx.notify();\n            }).detach();\n\n            Self { target }\n        })\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Parent-Child Communication\n\n```rust\n// Parent emits events\nimpl Parent {\n    fn notify_children(&mut self, cx: &mut Context<Self>) {\n        cx.emit(ParentEvent::Updated);\n        cx.notify();\n    }\n}\n\n// Children subscribe\nimpl Child {\n    fn new(parent: Entity<Parent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            cx.subscribe(&parent, |this, parent, event, cx| {\n                this.handle_parent_event(event, cx);\n            }).detach();\n\n            Self { parent }\n        })\n    }\n}\n```\n\n### 2. Global Event Broadcasting\n\n```rust\nstruct EventBus {\n    listeners: Vec<WeakEntity<dyn Listener>>,\n}\n\nimpl EventBus {\n    fn broadcast(&mut self, event: GlobalEvent, cx: &mut Context<Self>) {\n        self.listeners.retain(|weak| {\n            weak.update(cx, |listener, cx| {\n                listener.on_event(&event, cx);\n            }).is_ok()\n        });\n    }\n}\n```\n\n### 3. Observer Pattern\n\n```rust\ncx.observe(&entity, |this, observed, cx| {\n    // React to any state change\n    let state = observed.read(cx);\n    this.sync_with_state(state, cx);\n}).detach();\n```\n\n## subscribe_in — Subscription with Window Access\n\nUse when the subscription callback needs `&mut Window`:\n\n```rust\n// Store subscriptions to keep them alive\nstruct MyComponent {\n    _subscriptions: Vec<Subscription>,\n}\n\nimpl MyComponent {\n    fn new(input: &Entity<InputState>, window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let _subscriptions = vec![\n            cx.subscribe_in(input, window, |this, state, event, window, cx| {\n                match event {\n                    InputEvent::PressEnter { .. } => this.on_submit(window, cx),\n                    InputEvent::Change => {\n                        let val = state.read(cx).value();\n                        this.on_change(val, cx);\n                    }\n                    _ => {}\n                }\n            }),\n        ];\n        Self { _subscriptions }\n    }\n}\n```\n\n`subscribe` vs `subscribe_in`:\n- `cx.subscribe(&entity, |this, source, event, cx|)` — no window\n- `cx.subscribe_in(&entity, window, |this, source, event, window, cx|)` — window access\n\n## observe_window_activation\n\n```rust\nlet _sub = cx.observe_window_activation(window, |this, window, cx| {\n    if window.is_window_active() {\n        this.start_polling(cx);\n    } else {\n        this.stop_polling(cx);\n    }\n});\n```\n\n## observe_global\n\n```rust\ncx.observe_global::<Theme>(|cx| {\n    cx.notify(); // Re-render when theme changes\n});\n```\n\n## Subscription Lifetime\n\nSubscriptions are cancelled when dropped. Two ways to keep alive:\n\n```rust\n// 1. .detach() — lives until entity is dropped\ncx.subscribe(&entity, |this, _, event, cx| {\n    // ...\n}).detach();\n\n// 2. Store in struct — cancelled when struct drops\nstruct MyView {\n    _subscriptions: Vec<Subscription>,\n}\n// _subscriptions.push(cx.subscribe(...));\n```\n\nUse `.detach()` for permanent subscriptions; store in struct for subscriptions that should stop when the component unmounts.\n\n## Best Practices\n\n### ✅ Detach Subscriptions\n\n```rust\n// ✅ Detach to keep alive\ncx.subscribe(&entity, |this, source, event, cx| {\n    // Handle event\n}).detach();\n```\n\n### ✅ Clean Event Types\n\n```rust\n#[derive(Clone)]\nenum AppEvent {\n    DataChanged { id: usize, value: String },\n    ActionPerformed(ActionType),\n    Error(String),\n}\n```\n\n### ❌ Avoid Event Loops\n\n```rust\n// ❌ Don't create mutual subscriptions\nentity1.subscribe(entity2) → emits event\nentity2.subscribe(entity1) → emits event → infinite loop!\n```\n\n## Reference Documentation\n\n","isInternal":false,"tokens":1303,"sizeBytes":5714},{"name":"focus-handle.md","path":"skills/gpui-kit/references/gpui/focus-handle.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/focus-handle.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Focus & Keyboard Navigation\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Focus Events](#focus-events) · [Keyboard Navigation](#keyboard-navigation) · [Common Patterns](#common-patterns) · [Best Practices](#best-practices)\n\n## Overview\n\nGPUI's focus system enables keyboard navigation and focus management.\n\n**Key Concepts:**\n- **FocusHandle**: Reference to focusable element\n- **Focus tracking**: Current focused element\n- **Keyboard navigation**: Tab/Shift-Tab between elements\n- **Focus events**: on_focus, on_blur\n\n## Quick Start\n\n### Creating Focus Handles\n\n```rust\nstruct FocusableComponent {\n    focus_handle: FocusHandle,\n}\n\nimpl FocusableComponent {\n    fn new(cx: &mut Context<Self>) -> Self {\n        Self {\n            focus_handle: cx.focus_handle(),\n        }\n    }\n}\n```\n\n### Making Elements Focusable\n\n```rust\nimpl Render for FocusableComponent {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .on_action(cx.listener(Self::on_enter))\n            .child(\"Focusable content\")\n    }\n\n    fn on_enter(&mut self, _: &Enter, cx: &mut Context<Self>) {\n        // Handle Enter key when focused\n        cx.notify();\n    }\n}\n```\n\n### Focus Management\n\n```rust\nimpl MyComponent {\n    fn focus(&mut self, cx: &mut Context<Self>) {\n        self.focus_handle.focus(cx);\n    }\n\n    fn is_focused(&self, cx: &App) -> bool {\n        self.focus_handle.is_focused(cx)\n    }\n\n    fn blur(&mut self, cx: &mut Context<Self>) {\n        cx.blur();\n    }\n}\n```\n\n## Focus Events\n\n### Handling Focus Changes\n\n```rust\nimpl Render for MyInput {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let is_focused = self.focus_handle.is_focused(cx);\n\n        div()\n            .track_focus(&self.focus_handle)\n            .on_focus(cx.listener(|this, _event, cx| {\n                this.on_focus(cx);\n            }))\n            .on_blur(cx.listener(|this, _event, cx| {\n                this.on_blur(cx);\n            }))\n            .when(is_focused, |el| {\n                el.bg(cx.theme().focused_background)\n            })\n            .child(self.render_content())\n    }\n}\n\nimpl MyInput {\n    fn on_focus(&mut self, cx: &mut Context<Self>) {\n        // Handle focus gained\n        cx.notify();\n    }\n\n    fn on_blur(&mut self, cx: &mut Context<Self>) {\n        // Handle focus lost\n        cx.notify();\n    }\n}\n```\n\n## Keyboard Navigation\n\n### Tab Order\n\nA tracked handle is a Tab stop only when the handle says so. `cx.focus_handle()`\nstarts with `tab_stop = false`, and an element's own `.tab_index()` /\n`.tab_stop()` do not apply to a handle passed to `track_focus`: build the handle\nwith the flag.\n\n```rust\n// In the owning entity's constructor:\nlet focus1 = cx.focus_handle().tab_stop(true);          // Tab order: 1\nlet focus2 = cx.focus_handle().tab_stop(true);          // Tab order: 2\nlet hidden = cx.focus_handle();                         // focusable, never a Tab stop\n\ndiv()\n    .child(div().track_focus(&focus1).child(\"first\"))\n    .child(div().track_focus(&focus2).child(\"second\"))\n    .child(div().track_focus(&hidden).child(\"container\"))\n```\n\nThe Tab table is rebuilt every frame from the elements that painted with a\ntracked handle, in tree order (`tab_index` reorders within a `tab_group`). A\nstateless component may create its handle in `render` through keyed state —\n`window.use_keyed_state(id, cx, |_, cx| cx.focus_handle().tab_stop(true))` —\nwhich survives re-renders, so the order stays stable; `Button` does exactly\nthis. A focused element receives `ClickEvent::Keyboard` in `on_click` when\nEnter or Space is released, so a `track_focus` + `on_click` row activates from\nthe keyboard without extra bindings.\n\n### Focus Within Containers\n\n```rust\nimpl Container {\n    fn focus_first(&mut self, cx: &mut Context<Self>) {\n        if let Some(first) = self.children.first() {\n            first.update(cx, |child, cx| {\n                child.focus_handle.focus(cx);\n            });\n        }\n    }\n\n    fn focus_next(&mut self, cx: &mut Context<Self>) {\n        // Custom focus navigation logic\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Auto-focus on Mount\n\n```rust\nimpl MyDialog {\n    fn new(cx: &mut Context<Self>) -> Self {\n        let focus_handle = cx.focus_handle();\n\n        // Focus when created\n        focus_handle.focus(cx);\n\n        Self { focus_handle }\n    }\n}\n```\n\n### 2. Focus Trap (Modal)\n\n```rust\nimpl Modal {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .on_key_down(cx.listener(|this, event: &KeyDownEvent, cx| {\n                if event.key == Key::Tab {\n                    // Keep focus within modal\n                    this.focus_next_in_modal(cx);\n                    cx.stop_propagation();\n                }\n            }))\n            .child(self.render_content())\n    }\n}\n```\n\n### 3. Conditional Focus\n\n```rust\nimpl Searchable {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .when(self.search_active, |el| {\n                el.on_mount(cx.listener(|this, _, cx| {\n                    this.focus_handle.focus(cx);\n                }))\n            })\n            .child(self.search_input())\n    }\n}\n```\n\n### 4. Restore Lost Focus\n\nIf the focused element is no longer rendered (a table swapped for an empty\nstate), key dispatch starts at the dispatch tree's root node, so the view's\n`key_context` bindings and `on_action` handlers stop firing. Register one\n`cx.on_focus_lost` listener per window, usually on the root view, and move\nFocus to `window.focus_lost_restore_target(cx)`: the closest focusable\nancestor that is still rendered. Track the view's own handle on the element\nthat carries its `key_context`, so that element is the ancestor Focus returns\nto.\n\n```rust\nlet focus_lost = cx.on_focus_lost(window, |this, window, cx| {\n    let target = window\n        .focus_lost_restore_target(cx)\n        .unwrap_or_else(|| this.focus_handle.clone());\n    target.focus(window, cx);\n});\n// `this.focus_handle` is the view's tracked handle. Keep `focus_lost:\n// Subscription` on the view; dropping it unregisters.\n```\n\n## Best Practices\n\n### ✅ Track Focus on Interactive Elements\n\n```rust\n// ✅ Good: Track focus for keyboard interaction\ninput()\n    .track_focus(&self.focus_handle)\n    .on_action(cx.listener(Self::on_enter))\n```\n\n### ✅ Provide Visual Focus Indicators\n\nDraw the framework's ring so custom controls match `Button` and `Input`:\n\n```rust\nuse gpui_kit::component::ThemeStyled as _;\n\nlet is_focused = self.focus_handle.is_focused(window);\n\ndiv()\n    .track_focus(&self.focus_handle)\n    .when(is_focused, |el| el.focus_ring_style(window, cx))\n```\n\nThe ring is painted 3px outside the element, so an ancestor with\n`overflow_hidden()` clips it; leave it room or draw the ring inside the element.\n\n### ❌ Don't: Forget to Track Focus\n\n```rust\n// ❌ Bad: No track_focus, keyboard navigation won't work\ndiv()\n    .on_action(cx.listener(Self::on_enter))\n```\n\n","isInternal":false,"tokens":1721,"sizeBytes":7212},{"name":"global.md","path":"skills/gpui-kit/references/gpui/global.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/global.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Global State\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Use Cases](#common-use-cases) · [Best Practices](#best-practices) · [When to Use](#when-to-use)\n\n## Overview\n\nGlobal state in GPUI provides app-wide shared data accessible from any context.\n\n**Key Trait**: `Global` - Implement on types to make them globally accessible\n\n## Quick Start\n\n### Define Global State\n\n```rust\nuse gpui_kit::Global;\n\n#[derive(Clone)]\nstruct AppSettings {\n    theme: Theme,\n    language: String,\n}\n\nimpl Global for AppSettings {}\n```\n\n### Set and Access Globals\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx: &mut App| {\n        // Set global\n        cx.set_global(AppSettings {\n            theme: Theme::Dark,\n            language: \"en\".to_string(),\n        });\n\n        // Access global (read-only)\n        let settings = cx.global::<AppSettings>();\n        println!(\"Theme: {:?}\", settings.theme);\n    });\n}\n```\n\n### Update Globals\n\n```rust\nimpl MyComponent {\n    fn change_theme(&mut self, new_theme: Theme, cx: &mut Context<Self>) {\n        cx.update_global::<AppSettings, _>(|settings, cx| {\n            settings.theme = new_theme;\n            // Global updates don't trigger automatic notifications\n            // Manually notify components that care\n        });\n\n        cx.notify(); // Re-render this component\n    }\n}\n```\n\n## Common Use Cases\n\n### 1. App Configuration\n\n```rust\n#[derive(Clone)]\nstruct AppConfig {\n    api_endpoint: String,\n    max_retries: u32,\n    timeout: Duration,\n}\n\nimpl Global for AppConfig {}\n\n// Set once at startup\ncx.set_global(AppConfig {\n    api_endpoint: \"https://api.example.com\".to_string(),\n    max_retries: 3,\n    timeout: Duration::from_secs(30),\n});\n\n// Access anywhere\nlet config = cx.global::<AppConfig>();\n```\n\n### 2. Feature Flags\n\n```rust\n#[derive(Clone)]\nstruct FeatureFlags {\n    enable_beta_features: bool,\n    enable_analytics: bool,\n}\n\nimpl Global for FeatureFlags {}\n\nimpl MyComponent {\n    fn render_beta_feature(&self, cx: &App) -> Option<impl IntoElement> {\n        let flags = cx.global::<FeatureFlags>();\n\n        if flags.enable_beta_features {\n            Some(div().child(\"Beta feature\"))\n        } else {\n            None\n        }\n    }\n}\n```\n\n### 3. Shared Services\n\n```rust\n#[derive(Clone)]\nstruct ServiceRegistry {\n    http_client: Arc<HttpClient>,\n    logger: Arc<Logger>,\n}\n\nimpl Global for ServiceRegistry {}\n\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let registry = cx.global::<ServiceRegistry>();\n        let client = registry.http_client.clone();\n\n        cx.spawn(async move |cx| {\n            let data = client.get(\"api/data\").await?;\n            // Process data...\n            Ok::<_, anyhow::Error>(())\n        }).detach();\n    }\n}\n```\n\n## Best Practices\n\n### ✅ Use Arc for Shared Resources\n\n```rust\n#[derive(Clone)]\nstruct GlobalState {\n    database: Arc<Database>,  // Cheap to clone\n    cache: Arc<RwLock<Cache>>,\n}\n\nimpl Global for GlobalState {}\n```\n\n### ✅ Immutable by Default\n\nGlobals are read-only by default. Use interior mutability when needed:\n\n```rust\n#[derive(Clone)]\nstruct Counter {\n    count: Arc<AtomicUsize>,\n}\n\nimpl Global for Counter {}\n\nimpl Counter {\n    fn increment(&self) {\n        self.count.fetch_add(1, Ordering::SeqCst);\n    }\n\n    fn get(&self) -> usize {\n        self.count.load(Ordering::SeqCst)\n    }\n}\n```\n\n### ❌ Don't: Overuse Globals\n\n```rust\n// ❌ Bad: Too many globals\ncx.set_global(UserState { ... });\ncx.set_global(CartState { ... });\ncx.set_global(CheckoutState { ... });\n\n// ✅ Good: Use entities for component state\nlet user_entity = cx.new(|_| UserState { ... });\n```\n\n## When to Use\n\n**Use Globals for:**\n- App-wide configuration\n- Feature flags\n- Shared services (HTTP client, logger)\n- Read-only reference data\n\n**Use Entities for:**\n- Component-specific state\n- State that changes frequently\n- State that needs notifications\n\n","isInternal":false,"tokens":940,"sizeBytes":3933},{"name":"layout-style.md","path":"skills/gpui-kit/references/gpui/layout-style.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/layout-style.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Layout & Styling\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Patterns](#common-patterns) · [Styling Methods](#styling-methods) · [h_flex / v_flex](#h_flex--v_flex-helpers) · [Tailwind Shorthands](#tailwind-style-shorthand) · [Overflow & Scroll](#overflow-and-scroll) · [Absolute Positioning](#absolute-positioning) · [Stacking Order](#stacking-order) · [Theme Integration](#theme-integration) · [Conditional Styling](#conditional-styling) · [Text Styling](#text-styling)\n\n## Overview\n\nGPUI provides CSS-like styling with Rust type safety.\n\n**Key Concepts:**\n\n- Flexbox layout system\n- Styled trait for chaining styles\n- Size units: `px()`, `rems()`, `relative()`\n- Colors, borders, shadows\n\n## Quick Start\n\n### Basic Styling\n\n```rust\nuse gpui_kit::*;\n\ndiv()\n    .w(px(200.))\n    .h(px(100.))\n    .bg(rgb(0x2196F3))\n    .text_color(rgb(0xFFFFFF))\n    .rounded(px(8.))\n    .p(px(16.))\n    .child(\"Styled content\")\n```\n\n### Flexbox Layout\n\n```rust\ndiv()\n    .flex()\n    .flex_row()  // or flex_col() for column\n    .gap(px(8.))\n    .items_center()\n    .justify_between()\n    .children([\n        div().child(\"Item 1\"),\n        div().child(\"Item 2\"),\n        div().child(\"Item 3\"),\n    ])\n```\n\n### Size Units\n\n```rust\ndiv()\n    .w(px(200.))           // Pixels\n    .h(rems(10.))          // Relative to font size\n    .w(relative(0.5))      // 50% of parent\n    .min_w(px(100.))\n    .max_w(px(400.))\n```\n\n## Common Patterns\n\n### Centered Content\n\n```rust\ndiv()\n    .flex()\n    .items_center()\n    .justify_center()\n    .size_full()\n    .child(\"Centered\")\n```\n\n### Card Layout\n\n```rust\ndiv()\n    .w(px(300.))\n    .bg(cx.theme().surface)\n    .rounded(px(8.))\n    .shadow_md()\n    .p(px(16.))\n    .gap(px(12.))\n    .flex()\n    .flex_col()\n    .child(heading())\n    .child(content())\n```\n\n### Responsive Spacing\n\n```rust\ndiv()\n    .p(px(16.))           // Padding all sides\n    .px(px(20.))          // Padding horizontal\n    .py(px(12.))          // Padding vertical\n    .pt(px(8.))           // Padding top\n    .gap(px(8.))          // Gap between children\n```\n\n## Styling Methods\n\n### Dimensions\n\n```rust\n.w(px(200.))              // Width\n.h(px(100.))              // Height\n.size(px(200.))           // Width and height\n.min_w(px(100.))          // Min width\n.max_w(px(400.))          // Max width\n```\n\n### Colors\n\n```rust\n.bg(rgb(0x2196F3))        // Background\n.text_color(rgb(0xFFFFFF)) // Text color\n.border_color(rgb(0x000000)) // Border color\n```\n\n### Borders\n\n```rust\n.border(px(1.))           // Border width\n.rounded(px(8.))          // Border radius\n.rounded_t(px(8.))        // Top corners\n.border_color(rgb(0x000000))\n```\n\n### Spacing\n\n```rust\n.p(px(16.))               // Padding\n.m(px(8.))                // Margin\n.gap(px(8.))              // Gap between flex children\n```\n\n### Flexbox\n\n```rust\n.flex()                   // Enable flexbox\n.flex_row()               // Row direction\n.flex_col()               // Column direction\n.items_center()           // Align items center\n.justify_between()        // Space between items\n.flex_grow_1()              // Grow to fill space\n```\n\n## h_flex / v_flex Helpers\n\n`gpui_kit::component` provides shorthand helpers (import from `gpui_kit::component`):\n\n```rust\nuse gpui_kit::component::{h_flex, v_flex};\n\n// h_flex() = div().flex().flex_row().items_center()\nh_flex()\n    .gap_2()\n    .child(icon)\n    .child(label)\n\n// v_flex() = div().flex().flex_col()\nv_flex()\n    .gap_4()\n    .p_4()\n    .child(input1)\n    .child(input2)\n    .child(submit_btn)\n```\n\nThese are the standard layout primitives in `gpui_kit::component`. Prefer them over raw `div().flex()`.\n\n## Tailwind-style Shorthand\n\nGPUI provides Tailwind-style spacing/sizing shorthands:\n\n```rust\n// Spacing (0=0, 1=4px, 2=8px, 3=12px, 4=16px, ...)\n.p_2()    // padding: 8px\n.px_4()   // padding x: 16px\n.py_3()   // padding y: 12px\n.m_2()    // margin: 8px\n.gap_3()  // gap: 12px\n\n// Size\n.size_full()   // width: 100%, height: 100%\n.size_4()      // width: 16px, height: 16px\n.w_full()      // width: 100%\n.h_full()      // height: 100%\n.flex_1()      // flex: 1 1 0 (fill remaining space)\n.flex_shrink_0() // prevent shrinking\n```\n\n## Overflow and Scroll\n\n```rust\ndiv()\n    .overflow_hidden()          // clip content\n    .overflow_x_hidden()        // clip horizontal\n    .overflow_y_scrollbar()     // show scrollbar on y axis\n    .overflow_scroll()          // scroll both axes\n```\n\n## Absolute Positioning\n\n```rust\ndiv()\n    .relative()                 // position: relative (container)\n    .child(\n        div()\n            .absolute()         // position: absolute\n            .top_0()\n            .right_0()\n            .child(\"badge\")\n    )\n\n// Inset helpers\ndiv().absolute().inset_0()      // top/right/bottom/left: 0 (fill parent)\ndiv().absolute().top(px(8.)).left(px(8.))\n```\n\n## Stacking Order\n\n```rust\ndiv()\n    .relative()\n    .child(content)\n    .child(\n        div()\n            .absolute()\n            .top_0()\n            .right_0()\n            .child(\"badge\")\n    ) // later children are typically painted above earlier siblings\n```\n\nGPUI's general `Styled` API does **not** provide a `z_index(...)` method.\n\nFor normal elements, stacking is usually controlled by:\n\n- Parent/child composition\n- Absolute positioning\n- Render order of siblings (later siblings paint above earlier ones)\n\nIf you see a `z_index(...)` method in this repository, make sure it belongs to the specific component you are using: a component's own ordering API is not a general GPUI `Div` styling method.\n\n## Theme Integration\n\n```rust\ndiv()\n    .bg(cx.theme().surface)\n    .text_color(cx.theme().foreground)\n    .border_color(cx.theme().border)\n    .when(is_hovered, |el| {\n        el.bg(cx.theme().hover)\n    })\n```\n\n## Conditional Styling\n\n```rust\nuse gpui_kit::prelude::FluentBuilder as _;\n\ndiv()\n    .when(is_active, |el| el.bg(cx.theme().primary))\n    .when(!is_active, |el| el.opacity(0.5))\n    .when_some(optional_color.as_ref(), |el, color| el.bg(*color))\n```\n\n## Text Styling\n\n```rust\ndiv()\n    .text_sm()          // font-size: small\n    .text_base()        // font-size: base\n    .text_lg()          // font-size: large\n    .font_bold()        // font-weight: bold\n    .line_height_snug() // tighter line height\n    .truncate()         // overflow: ellipsis, single line\n    .whitespace_nowrap()\n```\n","isInternal":false,"tokens":1837,"sizeBytes":6360},{"name":"test-examples.md","path":"skills/gpui-kit/references/gpui/test-examples.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/test-examples.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Test Examples\n\n**Contents:** [Testing Best Practices](#testing-best-practices) · [Test Organization](#test-organization) · [Setup and Teardown](#setup-and-teardown) · [Assertions](#assertions) · [Performance Testing](#performance-testing) · [Running Tests](#running-tests) · [Basic Test Execution](#basic-test-execution) · [Test Configuration](#test-configuration) · [Advanced Test Execution](#advanced-test-execution) · [CI/CD Integration](#cicd-integration)\n\n## Testing Best Practices\n\n### Test Organization\n\nGroup related tests in modules:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    mod entity_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        fn test_creation() { /* ... */ }\n\n        #[gpui_kit::test]\n        fn test_updates() { /* ... */ }\n    }\n\n    mod async_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        async fn test_async_ops() { /* ... */ }\n    }\n\n    mod distributed_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        fn test_multi_app() { /* ... */ }\n    }\n}\n```\n\n### Setup and Teardown\n\nUse helper functions for common setup:\n\n```rust\nfn create_test_counter(cx: &mut TestAppContext) -> Entity<Counter> {\n    cx.new(|cx| Counter::new(cx))\n}\n\n#[gpui_kit::test]\nfn test_counter_operations(cx: &mut TestAppContext) {\n    let counter = create_test_counter(cx);\n\n    // Test operations\n}\n```\n\n### Assertions\n\nUse descriptive assertions:\n\n```rust\n#[gpui_kit::test]\nfn test_counter_bounds(cx: &mut TestAppContext) {\n    let counter = create_test_counter(cx);\n\n    // Test upper bound\n    for _ in 0..100 {\n        counter.update(cx, |counter, cx| {\n            counter.increment(cx);\n        });\n    }\n\n    let count = counter.read_with(cx, |counter, _| counter.count);\n    assert!(count <= 100, \"Counter should not exceed maximum\");\n\n    // Test lower bound\n    for _ in 0..200 {\n        counter.update(cx, |counter, cx| {\n            counter.decrement(cx);\n        });\n    }\n\n    let count = counter.read_with(cx, |counter, _| counter.count);\n    assert!(count >= 0, \"Counter should not go below minimum\");\n}\n```\n\n### Performance Testing\n\nTest performance characteristics:\n\n```rust\n#[gpui_kit::test]\nfn test_operation_performance(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    let start = std::time::Instant::now();\n\n    // Perform many operations\n    for i in 0..1000 {\n        component.update(cx, |comp, cx| {\n            comp.perform_operation(i, cx);\n        });\n    }\n\n    let elapsed = start.elapsed();\n    assert!(elapsed < Duration::from_millis(100), \"Operations should complete quickly\");\n}\n```\n\n## Running Tests\n\n### Basic Test Execution\n\n```bash\n# Run all tests\ncargo test\n\n# Run specific test\ncargo test test_counter_operations\n\n# Run tests in a specific module\ncargo test entity_tests::\n\n# Run with output\ncargo test -- --nocapture\n```\n\n### Test Configuration\n\nEnable test-support feature for GPUI tests:\n\n```toml\n[features]\ntest-support = [\"gpui/test-support\"]\n```\n\n```bash\ncargo test --features test-support\n```\n\n### Advanced Test Execution\n\n```bash\n# Run tests with iterations for property testing\ncargo test -- --test-threads=1\n\n# Run tests matching a pattern\ncargo test test_async\n\n# Run tests with backtrace on failure\nRUST_BACKTRACE=1 cargo test\n```\n\n### CI/CD Integration\n\nFor continuous integration:\n\n```yaml\n# .github/workflows/test.yml\nname: Tests\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: dtolnay/rust-toolchain@stable\n      - name: Run tests\n        run: cargo test --features test-support\n```\n\nGPUI's testing framework provides deterministic, fast, and comprehensive testing capabilities that mirror real application behavior while providing the control needed for thorough testing of complex UI and async scenarios.","isInternal":false,"tokens":935,"sizeBytes":3851},{"name":"test-reference.md","path":"skills/gpui-kit/references/gpui/test-reference.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/test-reference.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Test Reference\n\n**Contents:** [Testing Patterns](#testing-patterns) · [Testing Crash-Free State Management (Re-entrancy)](#testing-crash-free-state-management-re-entrancy) · [Property Testing](#property-testing) · [Distributed Systems Testing](#distributed-systems-testing) · [Mocking and Isolation](#mocking-and-isolation)\n\n## Testing Patterns\n\n### Basic Entity Testing\n\nTest entity creation, updates, and reads:\n\n```rust\n#[gpui_kit::test]\nfn test_counter_entity(cx: &mut TestAppContext) {\n    let counter = cx.new(|cx| Counter::new(cx));\n\n    // Test initial state\n    let initial_count = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(initial_count, 0);\n\n    // Test updates\n    counter.update(cx, |counter, cx| {\n        counter.count = 42;\n        cx.notify();\n    });\n\n    let updated_count = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(updated_count, 42);\n}\n```\n\n### Event Testing\n\nTest event emission and handling:\n\n```rust\n#[derive(Clone)]\nstruct ValueChanged {\n    new_value: i32,\n}\n\nimpl EventEmitter<ValueChanged> for MyComponent {}\n\n#[gpui_kit::test]\nfn test_event_emission(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| {\n        let mut comp = MyComponent::default();\n\n        // Subscribe to self\n        cx.subscribe_self(|this, event: &ValueChanged, cx| {\n            this.received_value = event.new_value;\n            cx.notify();\n        });\n\n        comp\n    });\n\n    // Emit event\n    component.update(cx, |_, cx| {\n        cx.emit(ValueChanged { new_value: 123 });\n    });\n\n    // Verify event was handled\n    let received = component.read_with(cx, |comp, _| comp.received_value);\n    assert_eq!(received, 123);\n}\n```\n\n### Action Testing\n\nTest action dispatching and handling:\n\n```rust\nactions!(my_app, [Increment, Decrement]);\n\n#[gpui_kit::test]\nfn test_action_dispatch(cx: &mut TestAppContext) {\n    let window = cx.update(|cx| {\n        cx.open_window(Default::default(), |_, cx| {\n            cx.new(|cx| MyComponent::new(cx))\n        }).unwrap()\n    });\n\n    let mut cx = VisualTestContext::from_window(window.into(), cx);\n    let counter = window.root(&mut cx).unwrap();\n\n    // Dispatch action via focus handle\n    let focus_handle = counter.read_with(&cx, |counter, _| counter.focus_handle.clone());\n    cx.update(|window, cx| {\n        focus_handle.dispatch_action(&Increment, window, cx);\n    });\n\n    let count = counter.read_with(&cx, |counter, _| counter.count);\n    assert_eq!(count, 1);\n}\n```\n\n### Async Testing\n\nTest async operations and background tasks:\n\n```rust\nimpl MyComponent {\n    fn load_data(&self, cx: &mut Context<Self>) -> Task<i32> {\n        cx.spawn(async move |this, cx| {\n            // Simulate async work\n            this.update(cx, |comp, _| comp.loading = true).await;\n            // Return result\n            42\n        })\n    }\n\n    fn background_update(&self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            // Background work\n            this.update(cx, |comp, _| {\n                comp.value += 10;\n            }).await;\n        }).detach();\n    }\n}\n\n#[gpui_kit::test]\nasync fn test_async_operations(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    // Test awaited task\n    let result = component.update(cx, |comp, cx| comp.load_data(cx)).await;\n    assert_eq!(result, 42);\n\n    // Test detached task\n    component.update(cx, |comp, cx| comp.background_update(cx));\n\n    // Detached tasks don't run until you yield\n    let value_before = component.read_with(cx, |comp, _| comp.value);\n    assert_eq!(value_before, 0);\n\n    // Run pending tasks\n    cx.run_until_parked();\n\n    let value_after = component.read_with(cx, |comp, _| comp.value);\n    assert_eq!(value_after, 10);\n}\n```\n\n### Timer Testing\n\nTest timer-based operations:\n\n```rust\nimpl MyComponent {\n    fn delayed_action(&self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            cx.background_executor()\n                .timer(Duration::from_millis(100))\n                .await;\n\n            this.update(cx, |comp, cx| {\n                comp.action_performed = true;\n                cx.notify();\n            }).await;\n        }).detach();\n    }\n}\n\n#[gpui_kit::test]\nasync fn test_timers(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    component.update(cx, |comp, cx| comp.delayed_action(cx));\n\n    // Action shouldn't have completed yet\n    let performed = component.read_with(cx, |comp, _| comp.action_performed);\n    assert!(!performed);\n\n    // Run until parked (timers complete)\n    cx.run_until_parked();\n\n    let performed = component.read_with(cx, |comp, _| comp.action_performed);\n    assert!(performed);\n}\n```\n\n### External I/O Testing\n\nFor tests involving external systems, use `allow_parking()`:\n\n```rust\n#[gpui_kit::test]\nasync fn test_external_io(cx: &mut TestAppContext) {\n    // Allow parking for external I/O\n    cx.executor().allow_parking();\n\n    // Simulate external operation\n    let (tx, rx) = futures::channel::oneshot::channel();\n    std::thread::spawn(move || {\n        std::thread::sleep(Duration::from_millis(10));\n        tx.send(42).ok();\n    });\n\n    let result = rx.await.unwrap();\n    assert_eq!(result, 42);\n}\n```\n\n## Testing Crash-Free State Management (Re-entrancy)\n\nThe most dangerous class of GPUI bugs is **entity re-entrancy**: code that tries to update or read an entity while it is already locked in a render/update pass. These bugs are invisible at compile time — they only panic at runtime, typically when the user clicks something in a list or dropdown.\n\n**Key properties of re-entrancy panics:**\n- Triggered by user interaction (click, key press), not during static rendering.\n- `#[should_panic]` only confirms the bug exists — tests must pass *without* panicking.\n- `Select` commits through `defer_in` after the key or click dispatch returns. Wait for the result with `cx.wait_for` instead of asserting straight after the interaction.\n\nDrive the component the way a user does. `SelectState` keeps its list state `pub(crate)`, so a test outside `gpui-component` opens the menu, presses keys, and observes through `selected_value()`, the element snapshot, and the delegate's own hooks.\n\n### Pattern: Confirm through the real UI\n\n```rust\nuse gpui_kit::test::{TestAppContextExt, TestWindowExt};\nuse gpui_kit::{\n    AnyWindowHandle, AppContext, Bounds, Context, Entity, TestAppContext, Window, WindowBounds,\n    WindowOptions,\n    component::{\n        IndexPath,\n        searchable_list::SearchableListChange,\n        select::{SearchableVec, Select, SelectDelegate, SelectItem, SelectState},\n    },\n    div,\n    prelude::*,\n    px, size,\n};\nuse std::{cell::RefCell, rc::Rc, time::Duration};\n\nstruct Form {\n    language: Entity<SelectState<SearchableVec<&'static str>>>,\n}\n\nimpl Render for Form {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .size_full()\n            .child(Select::new(&self.language).id(\"language\").w(px(240.)))\n    }\n}\n\n#[gpui_kit::test]\nasync fn confirming_from_the_keyboard_commits_the_value(cx: &mut TestAppContext) {\n    cx.update(gpui_kit::init);\n    let mut language = None;\n    let (handle, _view) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let state = cx.new(|cx| {\n                    SelectState::new(\n                        SearchableVec::new(vec![\"Rust\", \"Go\"]),\n                        Some(IndexPath::new(0)),\n                        window,\n                        cx,\n                    )\n                });\n                language = Some(state.clone());\n                let view = cx.new(|_| Form { language: state });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n    let language = language.unwrap();\n\n    // Open the menu, move to \"Go\" and confirm — the same path a user takes.\n    cx.update_window(handle.into(), |_, window, cx| {\n        window.render_frame(cx);\n        window.within(\"language\").click(\"input\", cx);\n        window.press(\"down\", cx);\n        window.press(\"enter\", cx);\n    })\n    .unwrap();\n\n    // Select commits through `defer_in` after the key dispatch returns, so\n    // wait for the closed menu instead of asserting straight away.\n    cx.wait_for(handle.into(), Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n            && window.find(\"language\").value() == Some(\"Go\")\n    })\n    .await;\n\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Go\")));\n}\n```\n\n### Pattern: Record `on_will_change` and `on_confirm`\n\nA recording delegate shows which changes the selection strategy proposed and what was committed. `on_will_change` receives the proposed changes and the selection to edit; the delegate applies them itself (the trait's default applies all of them). It has no `cx`, because it runs while the list entity is borrowed, so put side effects that need `cx` in `on_confirm`.\n\n```rust\ntype Log = Rc<RefCell<Vec<String>>>;\n\n/// Records each hook call; `accept: false` vetoes every change.\nstruct Recording {\n    items: Vec<&'static str>,\n    accept: bool,\n    log: Log,\n}\n\nimpl SelectDelegate for Recording {\n    type Item = &'static str;\n\n    fn items_count(&self, _: usize) -> usize {\n        self.items.len()\n    }\n\n    fn item(&self, ix: IndexPath) -> Option<&Self::Item> {\n        self.items.get(ix.row)\n    }\n\n    fn position<V>(&self, value: &V) -> Option<IndexPath>\n    where\n        Self::Item: SelectItem<Value = V>,\n        V: PartialEq,\n    {\n        self.items\n            .iter()\n            .position(|item| item.value() == value)\n            .map(IndexPath::new)\n    }\n\n    fn on_will_change(\n        &mut self,\n        selection: &mut Vec<(IndexPath, Self::Item)>,\n        changes: &[SearchableListChange],\n    ) {\n        for change in changes {\n            match *change {\n                SearchableListChange::Select { index } => {\n                    self.log.borrow_mut().push(format!(\"select {}\", index.row));\n                    if self.accept\n                        && let Some(item) = self.item(index)\n                    {\n                        selection.push((index, *item));\n                    }\n                }\n                SearchableListChange::Deselect { index } => {\n                    self.log\n                        .borrow_mut()\n                        .push(format!(\"deselect {}\", index.row));\n                    if self.accept {\n                        selection.retain(|(ix, _)| *ix != index);\n                    }\n                }\n            }\n        }\n    }\n\n    fn on_confirm(&mut self, final_selection: &[(IndexPath, Self::Item)]) {\n        let values: Vec<_> = final_selection.iter().map(|(_, item)| *item).collect();\n        self.log.borrow_mut().push(format!(\"confirm {values:?}\"));\n    }\n}\n\nstruct Picker {\n    language: Entity<SelectState<Recording>>,\n}\n\nimpl Render for Picker {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .size_full()\n            .child(Select::new(&self.language).id(\"language\").w(px(240.)))\n    }\n}\n\nfn open_picker(\n    cx: &mut TestAppContext,\n    accept: bool,\n) -> (AnyWindowHandle, Entity<SelectState<Recording>>, Log) {\n    cx.update(gpui_kit::init);\n    let log = Rc::new(RefCell::new(Vec::new()));\n    let mut language = None;\n    let (handle, _view) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let delegate = Recording {\n                    items: vec![\"Rust\", \"Go\"],\n                    accept,\n                    log: log.clone(),\n                };\n                let state =\n                    cx.new(|cx| SelectState::new(delegate, Some(IndexPath::new(0)), window, cx));\n                language = Some(state.clone());\n                let view = cx.new(|_| Picker { language: state });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n    (handle.into(), language.unwrap(), log)\n}\n\nfn confirm_next(cx: &mut TestAppContext, handle: AnyWindowHandle) {\n    cx.update_window(handle, |_, window, cx| {\n        window.render_frame(cx);\n        window.within(\"language\").click(\"input\", cx);\n        window.press(\"down\", cx);\n        window.press(\"enter\", cx);\n    })\n    .unwrap();\n}\n\n#[gpui_kit::test]\nasync fn hooks_fire_in_order_with_the_final_selection(cx: &mut TestAppContext) {\n    let (handle, language, log) = open_picker(cx, true);\n    confirm_next(cx, handle);\n    cx.wait_for(handle, Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n    })\n    .await;\n    // Single selection proposes replacing the old item, then commits once.\n    assert_eq!(\n        *log.borrow(),\n        [\"deselect 0\", \"select 1\", r#\"confirm [\"Go\"]\"#]\n    );\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Go\")));\n}\n```\n\n### Pattern: A vetoing delegate keeps the selection\n\nThe same delegate with `accept: false` applies none of the proposed changes:\n\n```rust\n#[gpui_kit::test]\nasync fn a_vetoing_delegate_keeps_the_selection(cx: &mut TestAppContext) {\n    let (handle, language, log) = open_picker(cx, false);\n    confirm_next(cx, handle);\n    cx.wait_for(handle, Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n    })\n    .await;\n    // The same changes are proposed, but the delegate applied none of them:\n    // `on_confirm` still runs, with the selection the user started from.\n    assert_eq!(*log.borrow(), [\"deselect 0\", \"select 1\", r#\"confirm [\"Rust\"]\"#]);\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Rust\")));\n    cx.update_window(handle, |_, window, _| {\n        assert_eq!(window.find(\"language\").value(), Some(\"Rust\"));\n    })\n    .unwrap();\n}\n```\n\n### Checklist: What to test for each component that uses `defer_in`\n\n- [ ] `confirm` path: no panic, the value is committed, and `selected_value()` agrees with the trigger's `value()`\n- [ ] `cancel` path (Escape, click outside): no panic, selection unchanged, menu closed (`expanded() == Some(false)`)\n- [ ] `on_will_change` veto: selection unchanged; `on_confirm` still runs, with the unchanged selection\n- [ ] `on_will_change` editing the selection: the final selection reflects the delegate's edit\n- [ ] Repeated confirms: each one leaves `selected_value()` matching the displayed value\n- [ ] `render_item` never panics even when called immediately after a mutation\n\n## Property Testing\n\nUse random data to test edge cases:\n\n```rust\n#[gpui_kit::test(iterations = 10)]\nfn test_counter_random_operations(cx: &mut TestAppContext, mut rng: StdRng) {\n    let counter = cx.new(|cx| Counter::new(cx));\n\n    let mut expected = 0i32;\n    for _ in 0..100 {\n        let delta = rng.random_range(-10..=10);\n        expected += delta;\n\n        counter.update(cx, |counter, cx| {\n            counter.count += delta;\n            cx.notify();\n        });\n    }\n\n    let actual = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(actual, expected);\n}\n```\n\n## Distributed Systems Testing\n\nTest multiple app contexts communicating:\n\n```rust\n#[derive(Clone)]\nstruct NetworkMessage {\n    from: String,\n    to: String,\n    data: i32,\n}\n\n#[gpui_kit::test]\nfn test_distributed_apps(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {\n    // Create components in different app contexts\n    let comp_a = cx_a.new(|_| MyComponent::new(\"A\".to_string()));\n    let comp_b = cx_b.new(|_| MyComponent::new(\"B\".to_string()));\n\n    // Simulate message passing\n    comp_a.update(cx_a, |comp, cx| {\n        comp.send_message(\"B\", 42, cx);\n    });\n\n    // Run async operations\n    cx_a.run_until_parked();\n\n    // Verify message received in other context\n    comp_b.update(cx_b, |comp, _| {\n        comp.receive_messages();\n    });\n\n    let messages = comp_b.read_with(cx_b, |comp, _| comp.messages.clone());\n    assert_eq!(messages.len(), 1);\n    assert_eq!(messages[0].data, 42);\n}\n```\n\n### Interleaving Testing\n\nTest concurrent operations with random execution order:\n\n```rust\n#[gpui_kit::test(iterations = 10)]\nfn test_concurrent_operations(\n    cx_a: &mut TestAppContext,\n    cx_b: &mut TestAppContext,\n    mut rng: StdRng,\n) {\n    let comp_a = cx_a.new(|_| MyComponent::new());\n    let comp_b = cx_b.new(|_| MyComponent::new());\n\n    // Perform random operations across contexts\n    for i in 0..20 {\n        if rng.random_bool(0.5) {\n            comp_a.update(cx_a, |comp, cx| {\n                comp.perform_operation(i, cx);\n            });\n        } else {\n            comp_b.update(cx_b, |comp, cx| {\n                comp.perform_operation(i, cx);\n            });\n        }\n    }\n\n    // Run all pending operations\n    cx_a.run_until_parked();\n\n    // Verify final state\n    let state_a = comp_a.read_with(cx_a, |comp, _| comp.state);\n    let state_b = comp_b.read_with(cx_b, |comp, _| comp.state);\n\n    // Assert invariants hold despite execution order\n    assert!(state_a.is_consistent());\n    assert!(state_b.is_consistent());\n}\n```\n\n## Mocking and Isolation\n\n### Network Mocking\n\nCreate mock networks for testing distributed features:\n\n```rust\nstruct MockNetwork {\n    messages: Arc<Mutex<Vec<NetworkMessage>>>,\n}\n\nimpl MockNetwork {\n    fn new() -> Self {\n        Self {\n            messages: Arc::new(Mutex::new(Vec::new())),\n        }\n    }\n\n    fn send(&self, message: NetworkMessage) {\n        self.messages.lock().unwrap().push(message);\n    }\n\n    fn receive_all(&self) -> Vec<NetworkMessage> {\n        self.messages.lock().unwrap().drain(..).collect()\n    }\n}\n\n#[gpui_kit::test]\nfn test_networked_components(cx: &mut TestAppContext) {\n    let network = Arc::new(MockNetwork::new());\n\n    let sender = cx.new(|_| MessageSender::new(network.clone()));\n    let receiver = cx.new(|_| MessageReceiver::new(network));\n\n    // Send message\n    sender.update(cx, |sender, _| {\n        sender.send(\"Hello\");\n    });\n\n    // Receive message\n    receiver.update(cx, |receiver, _| {\n        receiver.receive_all();\n    });\n\n    let received = receiver.read_with(cx, |receiver, _| receiver.messages.clone());\n    assert_eq!(received, vec![\"Hello\"]);\n}\n```","isInternal":false,"tokens":4500,"sizeBytes":18817},{"name":"test.md","path":"skills/gpui-kit/references/gpui/test.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/gpui/test.md","title":"Gpui Skill","category":"anthropic-skill","format":"markdown","content":"# Testing\n\n**Contents:** [Choose the test level](#choose-the-test-level) · [UI integration workflow](#ui-integration-workflow) · [Complete example](#complete-example) · [Queries and interactions](#queries-and-interactions) · [Frames and async work](#frames-and-async-work) · [Assertion boundaries](#assertion-boundaries) · [Additional resources](#additional-resources)\n\n## UI integration testing\n\nA UI integration test renders real components in a headless window, dispatches\nclicks, keyboard input and scrolling, then checks state, focus, layout and owner\ncallbacks. For example: add a Checkbox UI integration test that proves clicking\ntoggles the owner's value and disabled controls reject the interaction.\nUse this term when describing component interaction coverage.\n`#[gpui_kit::test]` runs the test; `gpui_kit::test` operates and inspects its UI.\n\n## Choose the test level\n\nUse ordinary Rust `#[test]` for pure logic. Use `#[gpui_kit::test]` and\n`TestAppContext` for entities, subscriptions, actions and async tasks; it can\ncreate headless windows too. `VisualTestContext` is available for existing GPUI\nwindow helpers. For an application UI flow, use `gpui_kit::test::TestWindowExt`\non the real `Window` and assert the behavior produced by native events.\n\nImport the Kit types you use explicitly and write `#[gpui_kit::test]`. Avoid `use gpui_kit::*;` in test modules: it imports GPUI’s `test` macro and can shadow Rust’s built-in `#[test]`. Add\n`test-support` to the application's `gpui-kit` development dependency, using\nexactly the same source and version as its normal dependency. The helpers\nrequire a Kit revision that includes them; check the installed API before\nassuming an older published release supports them. No extra testing crate or\nGPUI patch is required.\n\nFor a standalone test package beside a Kit checkout:\n\n```toml\n[package]\nname = \"ui-tests\"\nversion = \"0.1.0\"\nedition = \"2024\"\npublish = false\n\n[dev-dependencies]\ngpui-kit = { path = \"../gpui-kit/crates/kit\", features = [\"test-support\"] }\n```\n\nHeadless tests still need the platform's native build dependencies. Run\n`cargo generate-lockfile` once for the new package, then\n`cargo test --test ui --locked`. In the Kit repository the equivalent command\nis `cargo test -p gpui-kit --features test-support --test ui --locked`.\n\n## UI integration workflow\n\n1. Import the production view and constructor from the application library.\n   Keep state entities and subscriptions owned by that view. Define a view\n   inside a test only for a self-contained example or a deliberate fixture.\n2. Initialize with `cx.update(gpui_kit::init)`, open a headless window of an\n   explicit size through `gpui_kit::open_window`. Its Base `Root` renders\n   the dialog, sheet and notification layers above the view automatically.\n   Do not mount overlay layers in the application view.\n3. Render a frame and locate existing control IDs. Custom native elements opt\n   in with `.id(\"status\").test_support()` through `TestSupportExt`. Place it\n   before `.track_focus(&handle)`; custom wrappers must forward that method\n   to their inner element. Registration adds no layout container.\n4. Dispatch clicks, input and named keys through `TestWindowExt`. Exercise the\n   actual handler path; invoking callbacks or directly setting control state\n   would bypass the behavior being tested.\n5. Assert the initial state, the visible outcome after each meaningful action,\n   and the application result. Include a relevant negative case, such as a\n   disabled control rejecting the interaction or invalid input preventing save.\n6. Run the affected test target and report its result. An uncompiled example or\n   a test which never checks the action's outcome is not completion evidence.\n\n## Complete example\n\nCopy this into `tests/ui.rs`. It follows the Kit integration-test example\nfrom `crates/kit/tests/ui.rs`, with window setup inlined so this reference works\nwithout a repository checkout. In an application, replace that view definition\nwith an import of your production view.\n\n```rust\nuse gpui_kit::test::{TestSupportExt, TestWindowExt};\nuse gpui_kit::{\n    AppContext, Bounds, Context, Entity, SharedString, TestAppContext, Window, WindowBounds,\n    WindowOptions,\n    component::{\n        button::Button,\n        input::{Input, InputState},\n    },\n    div,\n    prelude::*,\n    px, size,\n};\n\nstruct Profile {\n    name: Entity<InputState>,\n    submitted: Option<SharedString>,\n}\n\nimpl Render for Profile {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let status = self.submitted.as_ref().map_or_else(\n            || SharedString::from(\"Not saved\"),\n            |name| SharedString::from(format!(\"Saved: {name}\")),\n        );\n        div()\n            .size_full()\n            .flex()\n            .flex_col()\n            .p_4()\n            .gap_4()\n            .child(Input::new(&self.name).id(\"name\").w(px(240.)))\n            .child(\n                Button::new(\"save\")\n                    .label(\"Save\")\n                    .on_click(cx.listener(|this, _, _, cx| {\n                        this.submitted = Some(this.name.read(cx).value());\n                        cx.notify();\n                    })),\n            )\n            .child(\n                div()\n                    .id(\"status\")\n                    .role(gpui_kit::Role::Status)\n                    .test_support()\n                    .aria_label(status.clone())\n                    .child(status),\n            )\n    }\n}\n\n#[gpui_kit::test]\nfn saves_a_profile_through_the_ui(cx: &mut TestAppContext) {\n    cx.update(gpui_kit::init);\n    let (handle, profile) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let view = cx.new(|cx| Profile {\n                    name: cx.new(|cx| InputState::new(window, cx)),\n                    submitted: None,\n                });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n\n    cx.update_window(handle.into(), |_, window, cx| {\n        window.render_frame(cx);\n        assert_eq!(window.find(\"status\").label(), Some(\"Not saved\"));\n\n        window.click(\"name\", cx);\n        window.input(\"Ada 中文\", cx);\n        let name = window.find(\"name\");\n        assert_eq!(name.focused(), Some(true));\n        assert_eq!(name.value(), Some(\"Ada 中文\"));\n        assert!(name.bounds().size.width > px(0.));\n        // Named keys share the same Window API and refresh the resulting frame.\n        window.press(\"backspace\", cx);\n        assert_eq!(window.find(\"name\").value(), Some(\"Ada 中\"));\n\n        window.click(\"save\", cx);\n        let status = window.find(\"status\");\n        assert!(status.visible());\n        assert_eq!(status.label(), Some(\"Saved: Ada 中\"));\n        assert!(status.bounds().top() >= window.find(\"save\").bounds().bottom());\n    })\n    .unwrap();\n\n    // Verify the application result as well as the native properties.\n    cx.update(|cx| {\n        assert_eq!(profile.read(cx).submitted.as_deref(), Some(\"Ada 中\"));\n    });\n}\n```\n\n## Queries and interactions\n\nImport `TestWindowExt` for queries and interactions from `gpui_kit::test`.\nFor custom registration, import `TestSupportExt`. Use normal Rust assertions with snapshots.\n\n| API | Behavior |\n| --- | --- |\n| `window.find(id)` | Requires a unique observed target; errors list registered paths. |\n| `window.try_find(id)` | Returns `None` when absent; ambiguous IDs still panic. |\n| `window.find_all(id)` | Returns all registered matches, including invisible ones, by current-frame bounds origin (y, then x); equal-origin order is unspecified. Empty when absent. |\n| `window.within(id)` | Resolves a native GPUI identity scope, including an unobserved ancestor. |\n| `click`, `right_click`, `double_click`, `hover` | Dispatch real pointer events at the target center. |\n| `click_at(id, offset, cx)` | Uses an offset from the target bounds' top-left corner. |\n| `window.click_with_modifiers(id, modifiers, cx)` | Centered left click with modifiers; sends modifier changes and restores the previous modifier state afterward. |\n| `window.click_with_options(id, options, cx)` | Combines offset, button, count, and modifiers using `ClickOptions`; restores the previous modifier state afterward. |\n| `scroll(id, delta, cx)` | Dispatches a GPUI `ScrollDelta` wheel event. |\n| `drag_to(from_id, to_id, cx)` | Drags between target centers within the current scope. |\n| `window.drag(from, to, cx)` | Drags between window-local points; use `bounds()` for precise or cross-scope geometry. |\n| `press(key, cx)` | Sends named GPUI keys such as `backspace`, `escape` or `secondary-a`. |\n| `input(text, cx)` | Types Unicode characters at current focus; click the input first. |\n\n`ClickOptions::new()` defaults to one left click at the center without modifiers.\nFor example, `ClickOptions::new().with_offset(point(px(8.), px(8.)))\n.with_button(MouseButton::Right).with_count(2).with_modifiers(Modifiers::shift())`\ncombines a local offset, right double-click, and Shift. Counts must be positive.\nConfigurable clicks preserve caps lock. `find_all` ordering is geometry for the\ncurrent frame, not stable identity, paint order, or business order; filter with\n`visible()` when counting visible matches.\n\nGPUI IDs need only be unique within their native scope. Use\n`window.within(\"dialog\").find(\"name\")` for repeated local IDs. Scoped windows\nalso provide pointer operations, `press` and `input`; keyboard helpers require\nobserved focus inside that scope and recheck it between characters. They do\nnot focus the target or replace its value. For a submenu with another\n`\"popup-menu\"` ID, retain the resolved outer scope before opening the submenu,\nthen query its descendants.\n\n## Inspect accessibility targets and individual events\n\nImport `gpui_kit::test::{TestQueryExt, TestEventExt}` for additional observation\nand event control. `elements()` returns observed elements in the current frame;\n`find_by_label(label)`, `try_find_by_label(label)` and `find_all_by_label(label)`\nmatch exact, case-sensitive native accessibility labels. `find_all_by_role(role)` selects an\nAccessKit `Role`. Results include invisible registrations, ordered by y, then x\nand a path tie-breaker. Required queries panic on absence; all unique queries\npanic on ambiguity. Scoped queries include strict descendants, excluding the\nscope node itself. These queries also work inside `within` and do not discover\nunobserved text or offscreen virtual rows. A label is an accessibility name,\nnot rendered text; use stable IDs when localization changes the name.\nThe pinned GPUI version does not expose an enumeration of anonymous rendered\ntext. Kit therefore has no general rendered-text `HasText` assertion; exact\naccessible-label queries cannot establish that text was actually drawn.\n\nFor gestures whose intermediate state matters, dispatch each step explicitly:\n\n```rust\nuse gpui_kit::test::TestEventExt;\n\nlet start = window.find(\"handle\").bounds().center();\nwindow.pointer_down(start, MouseButton::Left, cx);\nwindow.pointer_move(start + point(px(24.), px(0.)), Some(MouseButton::Left), cx);\n// Assert the state while the pointer is still held.\nwindow.pointer_up(start + point(px(24.), px(0.)), MouseButton::Left, cx);\n```\n\nPositions use window-local pixels. `pointer_move(position, pressed_button, cx)`\nreceives the held button explicitly; these helpers do not remember button state.\n`pointer_down` and `pointer_up` dispatch one click event each. Ordinary click, hover, scroll, drag and individual pointer steps use\nthe window's current modifiers. Configurable clicks temporarily use their\nexplicit modifiers and restore the preceding state afterward. `change_modifiers(modifiers, cx)` changes them and\npreserves caps lock; restore the previous modifiers when the gesture ends.\n`key_down(key, is_held, cx)` and `key_up(key, cx)` allow separate key transitions\nand auto-repeat (`is_held = true`). Key events combine modifiers written in the\nkey string with the window's held modifiers, without changing the retained\nmodifier state. Each step refreshes before dispatch and\ncompletes a frame afterward. These key events do not insert text; use `input`\nfor typing. Leave the window update and wait for deferred results when needed.\n\n## Exercise text composition through an input handler\n\n`gpui_kit::test::TestInput` bridges an explicit GPUI `InputHandler` to a window.\nFor an entity implementing `EntityInputHandler`, construct the adapter with\n`gpui_kit::ElementInputHandler::new(bounds, entity.clone())`, then pass it to\n`TestInput::new(handler, window)`. Keep the entity owned by the\nproduction view and use its actual input geometry. This bridge calls that\nhandler directly; it does not select the focused control or run an OS IME.\n\n`commit_text(text, cx)` commits through `replace_text_in_range`.\n`compose_text(replacement, text, selection, cx)` updates marked text through\n`replace_and_mark_text_in_range`. Replacement and selection ranges use UTF-16\ncode units, not UTF-8 byte offsets; selection is relative to the composed text.\nWith no replacement range, the handler replaces its current marked range or\nselection. Empty composition text cancels preedit according to the handler.\n`marked_text_range(cx)` returns a document-relative range;\n`selected_text_range(cx)` returns `Option<UTF16Selection>`, including direction;\n`unmark_text(cx)` ends marking while retaining its text. Mutation helpers complete a frame after the\nhandler call. They can test composition transitions and commit behavior, while\nplatform candidate windows, focus routing and OS IME integration still need\nnative tests. Use `window.input` for ordinary text typed at the current focus.\n\n## Resize, display scale and clipboard\n\nUse GPUI's existing `TestAppContext::simulate_window_resize(handle, size)` and\n`simulate_window_scale_factor_change(handle, scale)` outside a window update,\nthen call `render_frame` before inspecting layout. Pointer positions remain\nwindow-local logical pixels at every display scale. Assert both preserved\nediting state and resized geometry, then activate a control at its new bounds.\n\nExercise clipboard behavior through production shortcuts (`secondary-c`,\n`secondary-x`, `secondary-v`) and inspect `cx.read_from_clipboard()` when needed.\nThe test platform shares its clipboard across windows; editor state should\nremain window-specific. This verifies the test-platform adapter and application\nbindings, not the operating system's clipboard service.\n\nAfter activating an external Link, inspect `cx.opened_url()` to verify the URL\nreceived by the test platform and assert the application's click callback.\nThis does not establish that a browser opened the destination. The test\nplatform exposes no cursor-style reader; URL and callback assertions do not\nverify the pointer cursor.\n\n## Frames and async work\n\nSnapshots are owned facts from the last completed frame, not live elements.\nFetch a new snapshot after an interaction. Interaction helpers refresh frames;\nafter an external entity update, focus change or resize, call\n`window.render_frame(cx)` before querying.\n\nFor deferred actions, subscriptions or popup updates, leave `update_window`\nso GPUI can process its effects. Use `cx.run_until_parked()` for queued work,\nor import `TestAppContextExt` and await a bounded condition:\n\n```rust\ncx.wait_for(handle.into(), std::time::Duration::from_secs(1), |window, _| {\n    window.try_find(\"dialog\").is_none()\n}).await;\n```\n\n`wait_for` runs outside a borrowed window update and uses GPUI test time.\nProcess a queued action before changing any input that the action is meant to\nvalidate. Otherwise it can read the later input instead of the value at the\nintended test step.\n\nFor timers, check the UI before its deadline as well as after expiration.\nGPUI's non-synced `Animation` uses wall-clock time; advancing the test clock\ndoes not complete it. Use reduced motion when supported, or a bounded wait\nappropriate to that production animation before asserting final geometry.\n\n## Assertion boundaries\n\n- `checked()`, `selected()`, `expanded()`, `value()` and `label()` come from\n  native accessibility properties. `None` means unavailable; masked input\n  deliberately omits its value. Do not supply a second set of test-only state.\n- `disabled()` currently reports `Some(true)` or `None`. To prove a control is\n  enabled, perform the interaction and assert the result. Absence of a flag\n  is not proof that the control accepts input.\n- `focused()` measures the observed native focus scope. Missing bindings are\n  diagnosed when the native element advertises `Action::Focus`; controls\n  without that action can still return `None`. Register the real binding.\n- `bounds()` supports containment, relative position, overlap, scrolling and\n  drag assertions. `visible()` checks geometry, clipping and observed style;\n  it does not prove a target is unobstructed. Real hit testing decides whether\n  a click reaches the control.\n- Native properties can be wrong too. Pair them with real interactions,\n  geometry and the application result. A label is not rendered text, and a\n  correct accessibility value does not establish correct pixels.\n- These tests run in-process. Pixel comparisons need GPUI's separate renderer;\n  packaged-app behavior and full OS IME composition need other coverage. Kit's\n  explicit macOS (Metal) and Linux (WGPU) rendering target is\n  `cargo test -p gpui-kit --features test-support --test rendering --locked`.\n  Linux requires a working WGPU adapter and can use Mesa lavapipe. Windows\n  explicitly skips this target because GPUI 0.3.8 has no Windows headless renderer.\n  Missing renderer support on macOS or Linux fails instead of producing fake images.\n\n## Additional resources\n\n- [Website testing guide](https://gpui-kit.com/docs/test) — bilingual setup,\n  component coverage, platform requirements and CI.\n- [GPUI test examples](test-examples.md) — entity and context patterns.\n- [GPUI test reference](test-reference.md) — re-entrancy and property tests.\n","isInternal":false,"tokens":4022,"sizeBytes":18275},{"name":"recipes.md","path":"skills/gpui-kit/references/recipes.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/recipes.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Tested application recipe\n\nThis complete view comes from `examples/ai_recipes/src/settings.rs`. That consumer crate depends only on `gpui-kit`; the same source is compiled and tested by `cargo test -p gpui-kit-recipes`, and `script/check-ai-recipes` keeps this copy identical to it. Pair it with that example's `src/bootstrap.rs`, which installs assets, initializes the library, and wraps the window in `Root`.\n\nThe view owns both input state and subscriptions. Rendering creates only elements. The window's `Root` renders the dialog, sheet and notification layers above the view.\n\n<!-- recipe:settings:start -->\n```rust\nuse gpui_kit::component::{\n    ActiveTheme, IconName, WindowExt,\n    button::Button,\n    checkbox::Checkbox,\n    form::{Field, Form},\n    input::{Input, InputEvent, InputState},\n    radio::RadioGroup,\n    switch::Switch,\n};\nuse gpui_kit::{\n    AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render, SharedString,\n    Styled as _, Subscription, Window, div,\n};\n\npub struct Settings {\n    name: Entity<InputState>,\n    preview: SharedString,\n    changes: usize,\n    enabled: bool,\n    remember: bool,\n    delivery: Option<usize>,\n    _subscriptions: Vec<Subscription>,\n}\n\nimpl Settings {\n    pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let name = cx.new(|cx| InputState::new(window, cx).placeholder(\"Name\"));\n        let subscription = cx.subscribe_in(&name, window, |this, state, event, _, cx| {\n            if matches!(event, InputEvent::Change) {\n                this.preview = state.read(cx).value().to_string().into();\n                this.changes += 1;\n                cx.notify();\n            }\n        });\n        Self {\n            name,\n            preview: \"\".into(),\n            changes: 0,\n            enabled: false,\n            remember: false,\n            delivery: Some(0),\n            _subscriptions: vec![subscription],\n        }\n    }\n\n    pub fn input(&self) -> Entity<InputState> {\n        self.name.clone()\n    }\n\n    pub fn preview(&self) -> &SharedString {\n        &self.preview\n    }\n\n    pub fn changes(&self) -> usize {\n        self.changes\n    }\n}\n\nimpl Render for Settings {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .flex()\n            .flex_col()\n            .size_full()\n            .p_4()\n            .gap_3()\n            .bg(cx.theme().background)\n            .text_color(cx.theme().foreground)\n            .child(\"Profile\")\n            .child(\n                Form::new()\n                    .child(Field::new().label(\"Name\").child(Input::new(&self.name)))\n                    .child(Field::new().label(\"Preview\").child(self.preview.clone()))\n                    .child(\n                        Field::new().label_indent(false).child(\n                            Checkbox::new(\"remember\")\n                                .label(\"Remember name\")\n                                .checked(self.remember)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.remember = *value;\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .child(\n                        Field::new().label_indent(false).child(\n                            Switch::new(\"enabled\")\n                                .label(\"Enable notifications\")\n                                .checked(self.enabled)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.enabled = *value;\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .child(\n                        Field::new().label(\"Delivery\").child(\n                            RadioGroup::new(\"delivery\")\n                                .children([\"Immediately\", \"Daily summary\"])\n                                .selected_index(self.delivery)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.delivery = Some(*value);\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .footer(\n                        Button::new(\"about\")\n                            .label(\"About…\")\n                            .icon(IconName::Info)\n                            .on_click(|_, window, cx| {\n                                window.open_dialog(cx, |dialog, _, _| {\n                                    dialog.title(\"About\").child(\"A complete GPUI Kit window\")\n                                });\n                            }),\n                    ),\n            )\n    }\n}\n```\n<!-- recipe:settings:end -->\n\nFor changes in this repository, run `script/check-ai docs`, `script/check-ai rust`, or `script/check-ai shell` for the relevant verification profile (or `script/check-ai all` for all three), and `cargo test -p gpui-kit-recipes` when a recipe source changes. For a downstream app, compile and test your own consumer, then verify keyboard/focus and visuals in a real window. Automated recipe tests do not establish a model success rate.\n","isInternal":false,"tokens":1009,"sizeBytes":5324},{"name":"usage.md","path":"skills/gpui-kit/references/usage.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/references/usage.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# gpui-kit Usage Guide\n\n**Contents:** [Setup](#setup) · [Component Types](#component-types) · [Common Components](#common-components) (Button, Input, Select, Checkbox, Icon, Dialog, Notification, Tabs, Tooltip, Form, List) · [Theming](#theming) · [Layout Helpers](#layout-helpers) · [Overlay Layers](#overlay-layers-dialogs-sheets-notifications) · [Shared Traits](#shared-traits)\n\n## Setup\n\nUse the [tested application recipe](recipes.md) for complete examples and their verification command. Store subscription handles on the owning view; binding one to a constructor-local variable alone does not keep it alive after construction.\n\n### 1. Cargo.toml\n\n```toml\n[dependencies]\ngpui-kit = \"0.7\" # re-exports GPUI, platform, base, component and the default icons; Shell is a separate host dependency\n```\n\n### 2. Initialization\n\n```rust\nfn main() {\n    gpui_kit::application()\n        .with_assets(gpui_kit::assets::Assets)\n        .run(move |cx| {\n            gpui_kit::init(cx); // MUST be first\n\n            // Wraps the view in a `Root`, which enables dialogs, sheets,\n            // notifications, tooltips and menus in this window.\n            gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| cx.new(|_| MyApp))\n                .expect(\"Failed to open window\");\n        });\n}\n```\n\nUse `gpui_kit::open_window` for application windows; it mounts `Root` as the window's root view.\n\n---\n\n## Component Types\n\n### Stateless (most components)\n\nUsed directly in `render`, no stored state:\n\n```rust\nuse gpui_kit::component::button::Button;\n\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        Button::new(\"btn\").primary().label(\"Submit\")\n            .on_click(|_, _, _| println!(\"clicked\"))\n    }\n}\n```\n\n### Stateful (Input, Select, Combobox, etc.)\n\nRequire an `Entity<State>` stored in your view:\n\n```rust\nuse gpui_kit::component::input::{Input, InputState};\n\nstruct MyView {\n    name: Entity<InputState>,\n}\n\nimpl MyView {\n    fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        Self {\n            name: cx.new(|cx| InputState::new(window, cx).placeholder(\"Your name\")),\n        }\n    }\n}\n\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        Input::new(&self.name)\n    }\n}\n```\n\n---\n\n## Common Components\n\n### Button\n\n```rust\nuse gpui_kit::component::button::{Button, ButtonGroup};\n\n// Variants\nButton::new(\"btn\").label(\"Default\")\nButton::new(\"btn\").primary().label(\"Primary\")\nButton::new(\"btn\").danger().label(\"Delete\")\nButton::new(\"btn\").warning().label(\"Warning\")\nButton::new(\"btn\").success().label(\"Success\")\nButton::new(\"btn\").ghost().label(\"Ghost\")\nButton::new(\"btn\").link().label(\"Link\")\n\n// States\nButton::new(\"btn\").label(\"Text\").disabled(true)\nButton::new(\"btn\").label(\"Text\").loading(true)\nButton::new(\"btn\").label(\"Text\").selected(true)\n\n// With icon\nButton::new(\"btn\").icon(IconName::Plus).label(\"Add\")\n\n// Sizes\nButton::new(\"btn\").xsmall().label(\"XS\")\nButton::new(\"btn\").small().label(\"S\")\nButton::new(\"btn\").large().label(\"L\")\n\n// Group\nButtonGroup::new(\"group\")\n    .child(Button::new(\"a\").label(\"A\"))\n    .child(Button::new(\"b\").label(\"B\"))\n    .on_click(|indices, _, _| { /* selected indices */ })\n```\n\n### Input\n\n```rust\nuse gpui_kit::component::input::{Input, InputState};\n\n// State setup (in new/init)\nlet input = cx.new(|cx| InputState::new(window, cx)\n    .placeholder(\"Enter text...\")\n    .default_value(\"Hello\")\n);\n\n// Render\nInput::new(&input)\nInput::new(&input).cleanable(true)           // clear button\nInput::new(&input).disabled(true)\nInput::new(&input).prefix(Icon::new(IconName::Search).small())\nInput::new(&input).suffix(Button::new(\"b\").ghost().icon(IconName::X).xsmall())\nInput::new(&input).content_type(InputContentType::Password)\nInput::new(&input).mask_toggle()             // password reveal toggle\nInput::new(&input).appearance(false)         // remove default border/bg\n\n// Reading value\nlet value = input.read(cx).value();\n\n// Keep this subscription in the owning view (for example, `_subscriptions`).\nself._subscriptions.push(cx.subscribe_in(&input, window, |view, state, event, window, cx| {\n    match event {\n        InputEvent::Change => { let v = state.read(cx).value(); }\n        InputEvent::PressEnter { .. } => { /* submit */ }\n        InputEvent::Focus | InputEvent::Blur => {}\n    }\n}));\n```\n\n### Select\n\n```rust\nuse gpui_kit::component::select::{Select, SelectState};\n\n// Simple string list\nlet state = cx.new(|cx| {\n    SelectState::new(vec![\"Apple\", \"Orange\", \"Banana\"], Some(IndexPath::default()), window, cx)\n});\n\n// Render\nSelect::new(&state)\nSelect::new(&state).placeholder(\"Pick one\")\n\n// Reading selection\nlet selected = state.read(cx).selected_item();\n```\n\n### Checkbox / Switch / Radio\n\n```rust\nuse gpui_kit::component::{checkbox::Checkbox, switch::Switch};\n\n// Stateless (controlled)\nCheckbox::new(\"cb\").checked(self.checked)\n    .on_change(cx.listener(|this, checked, _, cx| {\n        this.checked = *checked;\n        cx.notify();\n    }))\n\nSwitch::new(\"sw\").checked(self.enabled)\n    .on_change(cx.listener(|this, checked, _, cx| {\n        this.enabled = *checked;\n        cx.notify();\n    }))\n```\n\n### Icon\n\n```rust\nuse gpui_kit::component::{Icon, IconName};\n\nIcon::new(IconName::Check)\nIcon::new(IconName::Search).small()\nIcon::new(IconName::Plus).large().text_color(cx.theme().primary)\n```\n\n### Dialog\n\n```rust\nuse gpui_kit::component::dialog::{Dialog, DialogAction, DialogClose, DialogFooter};\n\n// Open from window context. `footer` takes an element, not a closure.\n// DialogClose dismisses the dialog, so no manual close call is needed.\nwindow.open_dialog(cx, |dialog, _, _| {\n    dialog\n        .title(\"Export Report\")\n        .child(\"Choose a destination for the exported file.\")\n        .footer(\n            DialogFooter::new()\n                .gap_2()\n                .child(DialogClose::new().child(\n                    Button::new(\"cancel\").label(\"Cancel\").outline(),\n                ))\n                .child(DialogAction::new().child(\n                    Button::new(\"export\").label(\"Export\").primary(),\n                )),\n        )\n});\n```\n\n### AlertDialog\n\nUse `AlertDialog` — not `Dialog` — to confirm a consequential action. It is not\noverlay-closable and has no close button, so the choice must be made. Name the\nobject in the title and the result on the confirming button; see the Design\nGuides for the copy rules.\n\n```rust\nuse gpui_kit::component::button::ButtonVariant;\n\nwindow.open_alert_dialog(cx, |alert, _, _| {\n    alert\n        .title(\"Remove “Roadmap”?\")\n        .description(\"Files on disk aren’t deleted.\")\n        .confirm()\n        .ok_text(\"Remove\")\n        .ok_variant(ButtonVariant::Danger)\n        .on_ok(|_, _, _| true)\n});\n```\n\n`button_props(DialogButtonProps)` takes the same properties as one value; it\noverrides only the fields that value sets, so `confirm` and earlier callbacks\nsurvive it.\n\n### Notification\n\n```rust\n// Simple string message\nwindow.push_notification(\"Saved successfully!\", cx);\n\n// With type variant\nwindow.push_notification(\n    Notification::new(\"Upload complete\").info().message(\"File uploaded\"),\n    cx,\n);\n```\n\n### Tabs\n\n```rust\nuse gpui_kit::component::tab::{Tab, TabBar};\n\nTabBar::new(\"tabs\")\n    .child(Tab::new(\"tab1\").child(\"Overview\"))\n    .child(Tab::new(\"tab2\").child(\"Settings\"))\n    .child(Tab::new(\"tab3\").child(\"Logs\"))\n```\n\n### Tooltip\n\n```rust\n// On any element with .id(), add .tooltip():\ndiv()\n    .id(\"my-btn\")\n    .tooltip(|window, cx| Tooltip::new(\"Delete item\").build(window, cx))\n    .child(\"Delete\")\n\n// Or on a Button directly:\nButton::new(\"btn\").icon(IconName::Trash).tooltip(\"Delete\")\n\n// Component tooltips open after 500 ms; override per trigger,\n// or install `tooltip::TooltipDefaults` to change it app-wide:\nButton::new(\"help\").icon(IconName::Info).tooltip(\"Help\")\n    .tooltip_show_delay(Duration::ZERO)\n```\n\n### Form\n\n```rust\nuse gpui_kit::component::form::{v_form, h_form, field};\n\n// Vertical form\nv_form()\n    .child(field().label(\"Name\").child(Input::new(&self.name)))\n    .child(field().label(\"Email\").child(Input::new(&self.email)))\n    .footer(Button::new(\"submit\").primary().label(\"Submit\"))\n\n// Horizontal label alignment\nh_form()\n    .child(field().label(\"Username\").child(Input::new(&self.username)))\n```\n\n### List (searchable, virtualized)\n\n```rust\nuse gpui_kit::component::list::{List, ListState, ListDelegate, ListItem, ListEvent};\n\n// Implement ListDelegate for your data type, then:\nlet list_state = cx.new(|cx| ListState::new(MyDelegate::new(), window, cx));\n\n// Render\nList::new(&list_state)\n// Keep this subscription in the owning view, alongside list_state.\nself._subscriptions.push(cx.subscribe(&list_state, |this, _, event, cx| {\n    if let ListEvent::Select(index_path) = event {\n        // handle selection\n    }\n}));\n```\n\n---\n\n## Theming\n\n```rust\nuse gpui_kit::component::ActiveTheme as _;\n\n// Access colors\ncx.theme().primary\ncx.theme().background\ncx.theme().foreground\ncx.theme().border\ncx.theme().surface\ncx.theme().muted\ncx.theme().destructive\n\n// Use in styles\ndiv()\n    .bg(cx.theme().surface)\n    .text_color(cx.theme().foreground)\n    .border_color(cx.theme().border)\n```\n\n### Switch Theme\n\n```rust\nuse gpui_kit::component::{Theme, ThemeMode};\n\n// Switch light/dark: loads that mode's registered theme\nTheme::change(ThemeMode::Dark, None, cx);\n// or, as one edit among others\nTheme::update(cx, |theme| theme.mode = ThemeMode::Dark);\n\n// Load a named theme\nTheme::update(cx, |theme| theme.apply_config(&theme_config));\n\n// Edit fields; `update` keeps colors, tokens and the Base projection in step\nTheme::update(cx, |theme| theme.radius = px(8.));\n```\n\n---\n\n## Layout Helpers\n\n`gpui_kit::component` extends GPUI with convenient layout methods:\n\n```rust\nh_flex()    // div().flex().flex_row().items_center()\nv_flex()    // div().flex().flex_col()\n\n// Common patterns\nh_flex().gap_2().items_center()\n    .child(Icon::new(IconName::User))\n    .child(label(\"Username\"))\n\nv_flex().gap_4().p_4()\n    .child(Input::new(&self.name))\n    .child(Input::new(&self.email))\n    .child(Button::new(\"submit\").primary().label(\"Submit\"))\n```\n\n---\n\n## Overlay Layers (Dialogs, Sheets, Notifications)\n\nThe window's `Root` renders dialogs, sheets and notifications above the view, so a window opened with `gpui_kit::open_window` needs nothing else — `window.open_dialog(..)` just works. Applications define their own quit and close-window actions, key bindings, and confirmation flows. `open_window` returns `(AnyWindowHandle, Entity<V>)`. The complete tested consumer recipe is [`examples/ai_recipes/src/bootstrap.rs`](../../../examples/ai_recipes/src/bootstrap.rs).\n\nRoot always mounts all three layers. The former `Root::render_*_layer` methods have been removed; delete their calls from application views when migrating to 0.7.0.\n\n---\n\n## Shared Traits\n\nBuilders return the component so methods can be chained. Constructors follow component families: controls take a stable ID, retained controls take state, and compound parts may take no arguments. See [component conventions](conventions.md).\n\n- `Sizable`: `.xsmall()` / `.small()` / `.medium()` (default) / `.large()`\n- `Disableable`: `.disabled(bool)`\n- `Selectable`: `.selected(bool)`\n- `Styled`: any GPUI style methods (`.w()`, `.bg()`, `.p_2()`, etc.)\n\nFor any component not covered here, fetch its doc from:\n`https://gpui-kit.com/component/{name}.md`\n","isInternal":false,"tokens":2917,"sizeBytes":11463},{"name":"SKILL.md","path":"skills/gpui-kit/SKILL.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/skills/gpui-kit/SKILL.md","title":"gpui-kit","category":"anthropic-skill","format":"markdown","content":"---\nname: gpui-kit\ndescription: 'How to build desktop applications with GPUI Kit, the Rust framework published as the gpui-kit crate (GPUI plus gpui_kit::component, gpui_kit::base, gpui_kit::assets). Use when setting up a gpui-kit app, choosing or using a component (Button, Input, Select, Dialog, Sheet, Tabs, Sidebar, List, DataTable, Tree, Chart, etc.), handling component state, theming, or window overlays, and for GPUI mechanics: actions and keybindings, async tasks, contexts, custom elements, entities, events, focus, global state, layout and styling, ElementId, and tests including UI integration testing. Holds the normative Coding Guides: read them before any architecture, state-ownership, public API, naming, or testing decision. Pairs with the gpui-kit-design-guides skill for the Design Guides.'\n---\n\n# GPUI Kit\n\nApplications depend on one crate, `gpui-kit`. GPUI is `use gpui_kit::*;`, and\neach layer is reachable by name: `gpui_kit::component` (styled components),\n`gpui_kit::base` (unstyled behavior), `gpui_kit::assets` (default icons),\n`gpui_kit::platform`.\n\nStart with [component-family conventions](references/conventions.md) to choose the constructor, state owner, event, and layout contract for the task. Learn the family once, then verify the specific component supports the capability.\n\nFor a complete compiled view with retained state, subscriptions, and overlay\nlayers, read [the tested application recipe](references/recipes.md).\n\n## Read the Guides First\n\nTwo guides hold the rules this skill assumes. They are requirements, not\ninspiration. Read the guide file itself; do not answer from this page, from a\nsimilar file in the codebase, or from training data.\n\n| Guide                                                  | Read before                                                                                                                   |\n| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |\n| Design Guides, skill `gpui-kit-design-guides`          | Choosing components, layout, spacing, hierarchy, color, density, interaction states, overlays, motion, interface copy          |\n| [Coding Guides](references/coding-guides.md)           | Crate layering, `RenderOnce` vs `Entity<T>`, state ownership, `ElementId`, events, focus, async, public API, naming, testing |\n\nRead the Design Guides first when the change has a visible surface: code\nstructure preserves product intent, it does not replace it. If the design\nskill is not installed, fetch `https://gpui-kit.com/docs/design-guides.md`.\nThe coding guide is a verbatim copy of `https://gpui-kit.com/docs/coding-guides.md`,\nso its links to `./design-guides.md` and `./getting-started.md` mean the design\nskill and `https://gpui-kit.com/docs/getting-started.md`.\n\n### Coding Guides section map\n\nRead the whole guide for a new crate, module, or feature. For a narrow change,\nread \"Architecture at a glance\" and \"Rules for coding agents\" first, then the\nsection for the change (`grep -n '^## ' references/coding-guides.md`).\n\n| Section                              | Read when                                                              |\n| ------------------------------------ | ---------------------------------------------------------------------- |\n| Architecture at a glance             | Always; crate layering, ownership boundary                             |\n| Bootstrap and root ownership         | `main`, `init`, `Root`, window creation, app-level state               |\n| Understand GPUI's phases and contexts | Anything touching `App`, `Window`, `Context<T>`, render vs update      |\n| Choose the right unit                | Deciding `RenderOnce` vs `Entity<T>` vs custom `Element`               |\n| State ownership                      | Where a piece of state lives, who mutates it, `Entity<State>` handles  |\n| Stable identity                      | `ElementId`, lists, repeated elements, keyed state                     |\n| Rendering and composition            | `render`, builder chains, `when`/`map`, child composition              |\n| Behavior and presentation boundary   | `gpui-base` vs `gpui-component` vs application code                    |\n| Theme and styling                    | `cx.theme()`, tokens, `Styled`, sizes, variants                        |\n| Events, actions, and focus           | `cx.emit`, `subscribe`, `actions!`, keybindings, `FocusHandle`         |\n| Async work and side effects          | `cx.spawn`, `background_spawn`, `Task`, I/O, timers                    |\n| Layout, measurement, and scrolling   | Flex layout, sizing, `overflow`, scroll handles, measuring             |\n| Lists, tables, and large data        | `VirtualList`, `List`, `DataTable`, delegates, large collections       |\n| Public API design                    | Anything `pub`: builders, private fields, setter and reader naming     |\n| Platform and capability boundaries   | macOS/Windows/Linux/wasm differences, feature gates                    |\n| File and naming conventions          | New files, modules, type and method names, `Kind` suffix, `Context`    |\n| Testing strategy                     | What to test, `#[gpui_kit::test]`, `TestAppContext`                    |\n| Performance rules                    | Render cost, allocation, re-render triggers                            |\n| Common failure modes                 | Before finishing; invented APIs, state in render, index ids            |\n| Rules for coding agents              | Always when an agent writes code                                       |\n| Implementation checklist             | Before finishing; run every item against the work                     |\n\n### Non-negotiables\n\nA floor, not a substitute for the guides.\n\n- **Never invent an API.** Search the current source for the real signature.\n  Do not translate a React, CSS, or older-GPUI example by analogy; a\n  plausible-looking method that does not exist is the most common failure.\n- **One dependency.** Applications depend on `gpui-kit` alone. GPUI is\n  `use gpui_kit::*;`; the layers are `gpui_kit::component`, `gpui_kit::base`,\n  `gpui_kit::assets`, `gpui_kit::platform`.\n- **Framework owns behavior, application owns presentation.** Do not put\n  colors, sizing, or layout in `gpui-base`; do not put interaction behavior in\n  application styling code.\n- **Stable identity.** Repeated elements need domain-derived `ElementId`s, not\n  list indexes.\n- **No `pub` fields across the seam.** Public data types use builders and\n  reader methods.\n- **Spell `Context` out.** `cx` is GPUI's; name anything else after what it\n  holds.\n\n## Documentation\n\n- **Find a task/component page**: use `https://gpui-kit.com/llms.txt`, then load its Markdown page.\n- **Full reference**: `https://gpui-kit.com/llms-full.txt` is available when broad reference is actually needed\n- **Per-component API**: fetch `https://gpui-kit.com/component/{name}.md`,\n  e.g. `button.md`, `input.md`, `select.md`, `dialog.md`, `data-table.md`\n- **Any site page** can be fetched as Markdown by appending `.md` to the URL\n\n## Quick Reference\n\nSetup and examples: [references/usage.md](references/usage.md).\n\n```rust\nuse gpui_kit::*;\n\ngpui_kit::application()\n    .with_assets(gpui_kit::assets::Assets)\n    .run(|cx| {\n        gpui_kit::init(cx);                       // first, before anything else\n        gpui_kit::open_window(options, cx, |window, cx| {\n            cx.new(|cx| AppView::new(window, cx))\n        })\n        .expect(\"failed to open window\");\n    });\n```\n\n- **Stateless** (`RenderOnce`): build in `render`:\n  `Button::new(\"save\").primary().label(\"Save\").on_click(|_, _, _| {})`\n- **Stateful**: hold `Entity<State>` in the view, pass a reference in `render`:\n  `let input = cx.new(|cx| InputState::new(window, cx));` then `Input::new(&self.input)`\n- **Sizes**: `.xsmall()` `.small()` `.medium()` (default) `.large()`\n- **Theme**: `cx.theme().primary` · `.background` · `.foreground` · `.border` · `.muted`\n- **Overlays**: `window.open_dialog(...)`, `open_sheet(...)`, `push_notification(...)`\n  via `gpui_kit::component::WindowExt`\n\n## Component Catalog\n\nImport paths are relative to `gpui_kit::component::`, so `input::{Input, InputState}`\nmeans `use gpui_kit::component::input::{Input, InputState};`. For the full API\nfetch the component's `.md` doc.\n\n### Input & Form\n\n| Component     | Import                                          | Notes                                        |\n| ------------- | ----------------------------------------------- | -------------------------------------------- |\n| `Input`       | `input::{Input, InputState}`                    | Stateful. Text, password, mask, validation   |\n| `Textarea`    | `input::{Textarea, TextareaState}`              | Stateful. Multi-line text                    |\n| `Editor`      | `input::{Editor, EditorState}`                  | Stateful. Code editor, `tree-sitter` feature |\n| `NumberInput` | `input::{NumberInput, NumberInputEvent}`        | Stateful. Numeric with step                  |\n| `OtpInput`    | `input::OtpInput`                               | Stateful. One-time password                  |\n| `SpeechButton` | `speech::{SpeechButton, SpeechState}`          | Stateful. Dictation, `speech` feature        |\n| `Select`      | `select::{Select, SelectState}`                 | Stateful. Dropdown picker                    |\n| `Combobox`    | `combobox::{Combobox, ComboboxState}`           | Stateful. Searchable select                  |\n| `Checkbox`    | `checkbox::Checkbox`                            | Stateless. `on_click` receives `&bool`       |\n| `Switch`      | `switch::Switch`                                | Stateless. Toggle                            |\n| `Radio`       | `radio::{Radio, RadioGroup}`                    | Stateless.                                   |\n| `Slider`      | `slider::{Slider, SliderState}`                 | Stateful.                                    |\n| `Toggle`      | `button::Toggle`                                | Stateless.                                   |\n| `Rating`      | `rating::Rating`                                | Stateless.                                   |\n| `Stepper`     | `stepper::Stepper`                              | Stateless. Multi-step progress               |\n| `ColorPicker` | `color_picker::{ColorPicker, ColorPickerState}` | Stateful.                                    |\n| `DatePicker`  | `date_picker::{DatePicker, DatePickerState}`    | Stateful.                                    |\n| `TimeField`   | `time_field::{TimeField, TimeFieldState}`       | Stateful. Time of day, 24/12-hour            |\n| `Calendar`    | `calendar::{Calendar, CalendarState}`           | Stateful. Inline month view                  |\n| `Form`        | `form::{v_form, h_form, field}`                 | Layout container for form fields             |\n\n### Display & Feedback\n\n| Component   | Import                                    | Notes                                 |\n| ----------- | ----------------------------------------- | ------------------------------------- |\n| `Button`    | `button::{Button, ButtonGroup}`           | Stateless. Primary UI action          |\n| `Icon`      | `{Icon, IconName}`                        | Stateless. Lucide icons               |\n| `Badge`     | `badge::Badge`                            | Stateless.                            |\n| `Tag`       | `tag::Tag`                                | Stateless. Closable tags              |\n| `Avatar`    | `avatar::Avatar`                          | Stateless.                            |\n| `Label`     | `label::Label`                            | Stateless. Form label                 |\n| `Kbd`       | `kbd::Kbd`                                | Stateless. Keyboard key display       |\n| `Alert`     | `alert::Alert`                            | Stateless. Info/success/warning/error |\n| `Spinner`   | `spinner::Spinner`                        | Stateless. Loading indicator          |\n| `Skeleton`  | `skeleton::Skeleton`                      | Stateless. Loading placeholder        |\n| `Shimmer`   | `shimmer::{ShimmerText, ShimmerStyle}`    | Stateless. Streaming-text shimmer     |\n| `Marker`    | `marker::{Marker, MarkerVariant}`         | Stateless. Inline status marker       |\n| `Progress`  | `progress::{Progress, ProgressCircle}`    | Stateless.                            |\n| `Tooltip`   | `tooltip::Tooltip`                        | Via `.tooltip()` on elements          |\n| `HoverCard` | `hover_card::{HoverCard, HoverCardState}` | Stateful.                             |\n| `Clipboard` | `clipboard::Clipboard`                    | Stateless. Copy button                |\n| `TextView`  | `text::TextView`                          | `TextView::markdown(id, text)`, HTML too |\n| Image       | `gpui_kit::{img, ImageSource, ObjectFit}` | GPUI's `img()` element                |\n\n### Overlay & Popups\n\n| Component        | Import                                            | Notes                                    |\n| ---------------- | ------------------------------------------------- | ---------------------------------------- |\n| `Dialog`         | `dialog::Dialog` + `WindowExt`                    | Via `window.open_dialog(...)`            |\n| `AlertDialog`    | `WindowExt`                                       | Via `window.open_alert_dialog(...)`      |\n| `Sheet`          | `sheet::Sheet` + `WindowExt`                      | Side panel, via `window.open_sheet(...)` |\n| `Notification`   | `notification::Notification` + `WindowExt`        | Via `window.push_notification(...)`      |\n| `Popover`        | `popover::Popover`                                | Floating overlay                         |\n| `Menu`           | `menu::{PopupMenu, DropdownMenu}`                 | Context menus                            |\n| `DropdownButton` | `button::DropdownButton`                          | Button with dropdown menu                |\n| `Command`        | `command::{Command, CommandState, CommandGroup}`  | Stateful. Command palette                |\n| Focus trap       | `FocusTrapElement`                                | `.focus_trap(id, &handle)` on a container; `Dialog` and `Sheet` have it built in |\n\n### Navigation & Layout\n\n| Component         | Import                                                                   | Notes                     |\n| ----------------- | ------------------------------------------------------------------------ | ------------------------- |\n| `Tabs` / `TabBar` | `tab::{Tab, TabBar}`                                                     | Tabbed interface          |\n| `Sidebar`         | `sidebar::{Sidebar, SidebarMenu, ...}`                                   | App navigation panel      |\n| `TitleBar`        | `TitleBar`                                                               | Window title bar          |\n| `StatusBar`       | `status_bar::StatusBar`                                                  | Window status bar         |\n| `Breadcrumb`      | `breadcrumb::Breadcrumb`                                                 | Navigation breadcrumb     |\n| `Pagination`      | `pagination::Pagination`                                                 | Page navigation           |\n| `Accordion`       | `accordion::Accordion`                                                   | Collapsible sections      |\n| `Collapsible`     | `collapsible::Collapsible`                                               | Single collapsible        |\n| `GroupBox`        | `group_box::GroupBox`                                                    | Labeled container         |\n| `Resizable`       | `resizable::{h_resizable, v_resizable, resizable_panel, ResizableState}` | Draggable split panes     |\n| `ResizeHandle`    | `resizable::{resize_handle, HandleEdge}`                                 | Standalone resize edge    |\n| `Scrollbar`       | `scroll::Scrollbar`                                                      | Custom scrollbar          |\n\n### Data Display\n\n| Component         | Import                                          | Notes                         |\n| ----------------- | ----------------------------------------------- | ----------------------------- |\n| `DataTable`       | `table::{DataTable, TableState, TableDelegate}` | Stateful. Full-featured table |\n| `Diff`            | `diff::{Diff, DiffState, DiffFile}`           | Retained state, `RenderOnce` element. Readonly unified/Git diff display of one or more files, merge conflicts and source files; application supplies the patch |\n| `Table`           | `table::{Table, ...}`                           | Simpler table                 |\n| `VirtualList`     | `{v_virtual_list, h_virtual_list}`              | High-perf large lists         |\n| `List`            | `list::{List, ListState, ListDelegate}`         | Stateful. Searchable list     |\n| `Tree`            | `tree::{Tree, TreeState, TreeItem, TreeEntry}`  | Stateful. Hierarchy           |\n| `DescriptionList` | `description_list::DescriptionList`             | Key-value pairs               |\n| `Settings`        | `setting::Settings`                             | Settings panel                |\n\n### Chat & Messaging\n\n| Component         | Import                                                   | Notes                                 |\n| ----------------- | -------------------------------------------------------- | ------------------------------------- |\n| `Message`         | `message::{Message, MessageContent, MessageAlignment}`   | Stateless. Chat message row           |\n| `Bubble`          | `bubble::{Bubble, BubbleContent, BubbleVariant}`         | Stateless. Message bubble             |\n| `Attachment`      | `attachment::{Attachment, AttachmentContent, ...}`       | Stateless. File/media attachment card |\n| `MessageScroller` | `message_scroller::{MessageScroller, MessageScrollerState}` | Stateful. Auto-scrolling message list |\n\n### Charts\n\n| Component | Import                                                          | Notes                          |\n| --------- | --------------------------------------------------------------- | ------------------------------ |\n| `Chart`   | `chart::{AreaChart, BarChart, LineChart, PieChart, RadarChart}` | Bar, line, area, pie charts    |\n| `Plot`    | `plot::Plot`                                                    | `#[derive(IntoPlot)]` for data |\n\n## Testing\n\n**UI integration testing** means rendering real components in headless windows,\nsimulating input, and checking state, focus, layout and owner callbacks. Use\n`#[gpui_kit::test]` to run tests and `gpui_kit::test` to operate and inspect the UI.\nWhen asked to add component interaction coverage, describe it as UI integration testing.\n\nFor unit tests, GPUI context tests or UI integration tests, read\n[Testing](references/gpui/test.md). It includes dependency setup, a complete\nrunnable UI flow, scoped native interactions, frame/async handling and the\nlimits of accessibility and geometry assertions. Use the production view and\nverify the action's outcome through normal Rust assertions.\n\n## GPUI References\n\nLoad the file for the mechanism the task touches. Each file starts with a\ncontents line.\n\n| Topic                       | File                                                   | Load when                                                       |\n| --------------------------- | ------------------------------------------------------ | --------------------------------------------------------------- |\n| Actions & keybindings       | [action.md](references/gpui/action.md)                 | `actions!`, `bind_keys`, `on_action`, `key_context`             |\n| Async & background tasks    | [async.md](references/gpui/async.md)                   | `cx.spawn`, `background_spawn`, `Task`, async I/O               |\n| Context management          | [context.md](references/gpui/context.md)               | `App`, `Window`, `Context<T>`, `AsyncApp`                       |\n| Custom elements (low-level) | [element.md](references/gpui/element.md)               | `Element` trait, `request_layout`, `prepaint`, `paint`          |\n| Entity state                | [entity.md](references/gpui/entity.md)                 | `Entity<T>`, `WeakEntity`, state management                     |\n| Events & subscriptions      | [event.md](references/gpui/event.md)                   | `cx.emit`, `cx.subscribe`, `cx.observe`                         |\n| Focus & keyboard nav        | [focus-handle.md](references/gpui/focus-handle.md)     | `FocusHandle`, `track_focus`, Tab navigation                    |\n| Global state                | [global.md](references/gpui/global.md)                 | `Global` trait, `cx.set_global`, app-wide config                |\n| Layout & styling            | [layout-style.md](references/gpui/layout-style.md)     | `div()`, `h_flex()`, `v_flex()`, flexbox, overflow, positioning |\n| ElementId                   | [element-id.md](references/gpui/element-id.md)         | `ElementId`, `.id()`, uniqueness rules, stateful elements       |\n| Testing                     | [test.md](references/gpui/test.md)                     | `#[gpui_kit::test]`, `TestAppContext`, `VisualTestContext`      |\n\nDeep dives, for when the topic file is not enough:\n\n- **Element trait**: [element-api.md](references/gpui/element-api.md) (complete API, hitbox, events) ·\n  [element-patterns.md](references/gpui/element-patterns.md) (text, interactive, container, composite) ·\n  [element-examples.md](references/gpui/element-examples.md) (full examples) ·\n  [element-best-practices.md](references/gpui/element-best-practices.md) (performance, state, pitfalls) ·\n  [element-advanced.md](references/gpui/element-advanced.md) (custom layouts, async updates, virtual lists)\n- **Entities**: [entity-api.md](references/gpui/entity-api.md) (complete API, lifecycle) ·\n  [entity-patterns.md](references/gpui/entity-patterns.md) (model-view, cross-entity, observer) ·\n  [entity-best-practices.md](references/gpui/entity-best-practices.md) (memory, performance) ·\n  [entity-advanced.md](references/gpui/entity-advanced.md) (collections, registry, debounce, state machines)\n- **Testing**: [test-examples.md](references/gpui/test-examples.md) (organization, setup, assertions, running tests) ·\n  [test-reference.md](references/gpui/test-reference.md) (re-entrancy, property tests, mocking)\n","frontmatter":{"name":"gpui-kit","description":"How to build desktop applications with GPUI Kit, the Rust framework published as the gpui-kit crate (GPUI plus gpui_kit::component, gpui_kit::base, gpui_kit::assets). Use when setting up a gpui-kit app, choosing or using a component (Button, Input, Select, Dialog, Sheet, Tabs, Sidebar, List, DataTable, Tree, Chart, etc.), handling component state, theming, or window overlays, and for GPUI mechanics: actions and keybindings, async tasks, contexts, custom elements, entities, events, focus, global state, layout and styling, ElementId, and tests including UI integration testing. Holds the normative Coding Guides: read them before any architecture, state-ownership, public API, naming, or testing decision. Pairs with the gpui-kit-design-guides skill for the Design Guides."},"isInternal":false,"tokens":4671,"sizeBytes":22497},{"name":"release-notes.md","path":".agents/commands/release-notes.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/.agents/commands/release-notes.md","title":"Command: /release-notes","category":"command-prompt","format":"markdown","content":"# Release Notes\n\nWrite release notes using the input supplied by the user: either a tag such\nas `v0.6.2`, or the auto-generated \"## What's Changed\" list copied from the\nGitHub release draft. When no input is supplied, use the `version` in the\nworkspace `Cargo.toml` with a `v` prefix.\n\n## Gather\n\n1. Read the previous release with `gh release view <previous-tag> --json body -q .body`\n   to match its structure, tone, and section names. The previous tag is\n   `git describe --tags --abbrev=0 <tag>^` (or the latest published release\n   when `<tag>` does not exist yet).\n2. If no \"What's Changed\" list was pasted, generate it:\n\n   ```bash\n   gh api repos/longbridge/gpui-kit/releases/generate-notes \\\n     -f tag_name=<tag> -f previous_tag_name=<previous-tag> -q .body\n   ```\n\n   Keep this list, its \"New Contributors\" section, and the \"Full Changelog\"\n   line verbatim; they close the notes.\n3. Read the body of every PR that adds a component, a public API, a platform,\n   or a behavior change, with `gh pr view <n> --json title,body`. Take API\n   names, method names, and `## Breaking Changes` diff blocks from the PR\n   text; never invent a name from the title alone. Fix-only PRs can be\n   summarized from their titles.\n\n## Write\n\nProduce one Markdown document in this shape, in English:\n\n```markdown\n# GPUI Kit <tag>\n\n<Two or three sentences: the headline features first, then what else the\nrelease improves.>\n\n## <Theme>\n\n- **<Feature>**: what a consumer can now do, with the API in backticks.\n  ([#123](https://github.com/longbridge/gpui-kit/pull/123))\n- Fixed ... ([#124](...), [#125](...))\n\n...\n\n## Breaking Changes            <!-- only when a PR has one -->\n\n<One sentence per change naming the PR, then its diff block.>\n\nThank you to everyone who contributed code, documentation, testing, and feedback!\n\n## What's Changed\n<verbatim list>\n\n## New Contributors\n<verbatim list>\n\n**Full Changelog**: <verbatim line>\n```\n\nRules:\n\n- Group by product area, ordered by significance: headline features (new\n  platforms, new components), then editor and text input, Markdown and text\n  rendering, motion, dock, other components (one bold component name per\n  bullet), shell, runtime and platform, documentation and website. Drop a\n  section that has nothing to say; merge small ones.\n- Every bullet cites its PR numbers as `[#n](https://github.com/longbridge/gpui-kit/pull/n)`\n  at the end, in parentheses. Combine PRs that land one change into one bullet.\n- Leave out chores, CI, lockfile refreshes, test-only changes, and a PR that\n  reverts another PR in the same release (leave both out).\n- Bold the feature, not the sentence; write what it does for an application,\n  not what the diff touched.\n- Do not create or edit the GitHub release unless asked. Save the document to\n  the scratchpad and show it, so it can be pasted into the release draft.\n","isInternal":false,"tokens":719,"sizeBytes":2851},{"name":"release-notes.md","path":".claude/commands/release-notes.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/.claude/commands/release-notes.md","title":"Command: /release-notes","category":"command-prompt","format":"markdown","content":"---\ndescription: Write the GitHub release notes for a gpui-kit version in the established style\nargument-hint: [tag] or the pasted \"What's Changed\" list\n---\n\nRead and follow the shared release-notes workflow in\n`.agents/commands/release-notes.md` (relative to the repository root).\n\nUse the following as the workflow input; if empty, use the shared workflow's\ndefault version:\n\n$ARGUMENTS\n","isInternal":false,"tokens":88,"sizeBytes":389},{"name":"ARCHITECTURE.md","path":"docs/ARCHITECTURE.md","rawUrl":"https://raw.githubusercontent.com/longbridge/gpui-component/HEAD/docs/ARCHITECTURE.md","title":"docs - System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# gpui-base Architecture\n\n## Status and Scope\n\nThis document describes the architecture implemented by `crates/base`. It is a\nsource-derived reference, not a migration plan. Public exports in\n`crates/base/src/lib.rs` and the Rust API documentation remain authoritative for\nindividual methods.\n\n`gpui-base` is the reusable foundation below the styled `gpui-component` crate.\nIt is designed for both of these callers:\n\n- `crates/component`, which adapts base behavior into GPUI Component's complete visual\n  system;\n- applications that build and own a different visual system directly on top of\n  base behavior.\n\n## Architectural Thesis\n\nThe durable rule is:\n\n> Base owns reusable behavior and the geometry required to implement it. The\n> presentation layer owns the product's visual language.\n\n“Headless” does not mean that every base module is a single empty `Div`.\nKeyboard navigation, text editing, popup collision handling, virtualization,\ncalendar grids, resizable panels, and toast stacking require internal structure,\nmeasurement, and retained state. Base owns that complexity when moving it to\ncallers would duplicate difficult behavior.\n\nBase does not own product-level choices such as brand colors, typography,\ncontrol density, borders, radii, icons, variants, or final composition.\n\n## Dependency Direction\n\n```text\n                       application\n                     /             \\\n                    ▼               ▼\n       application-owned UI     gpui-component\n                    \\               /\n                     └──────┬──────┘\n                            ▼\n                        gpui-base\n                            ▼\n                           GPUI\n```\n\nDependencies point downward. `gpui-base` must not import `gpui-component`\nthemes, assets, or façade types. `gpui-component::init` may initialize and theme\nthe base layer, but the base layer must also work when initialized directly.\n\nThere is no Registry or CLI crate in the current workspace. Source distribution\ncan be added above this seam without changing the ownership model, but it is not\npart of the implemented architecture documented here.\n\n## Module Families\n\nThe public surface contains four distinct module families. Treating all of them\nas identical “primitives” hides important interface differences.\n\n### 1. Semantic elements\n\nExamples include Button, Checkbox, Radio, Switch, Toggle, Link, Tabs, Progress,\nAvatar, and the semantic Table parts.\n\nThese modules typically implement GPUI interfaces directly:\n\n```text\nIntoElement\n+ Styled\n+ ParentElement where composition is meaningful\n+ InteractiveElement for interactive roots\n```\n\nThey provide a stable element identity, event normalization, focus behavior,\nkeyboard activation, accessibility semantics, controlled values, and optional\nsemantic-state styles. The caller supplies visible children and presentation.\n\n`Button::new(\"save\")`, for example, receives an `ElementId`, not a label. It has\nno default height, padding, background, border, or radius.\n\n### 2. Compound behavior roots\n\nExamples include Accordion, Dialog, AlertDialog, Sheet, Popover, HoverCard,\nSelect, Combobox, DatePicker, and Popup.\n\nThese modules coordinate multiple parts or application-owned children. Their\ninterfaces encode behavior that would be fragile if every caller rebuilt it:\n\n- open-state requests and change reasons;\n- trigger and content focus transfer;\n- Escape, Confirm, and directional key actions;\n- dismissal ordering;\n- backdrop hit testing;\n- focus trapping;\n- trigger measurement and popup placement.\n\nParts such as `DialogTitle`, `DialogDescription`, and `DialogClose` are explicit\nsemantic seams. Base does not walk arbitrary descendant trees to discover them.\n\n### 3. Stateful systems\n\nExamples include InputState, TextareaState, EditorState, CalendarState, TreeState, SliderState,\nResizableState, OtpState, ColorPickerState, QuestionnaireState, ToastManager, ToastStackState,\nNavStackState, DockArea, and TabGroup.\n\nThese modules retain data because their behavior spans frames or requires\nmeasurement, subscriptions, history, focus, or incremental updates. State is\nusually stored in a GPUI `Entity`, a keyed element state, or an application-owned\nmodel passed back to the element.\n\nStateful systems expose application rendering seams rather than leaking their\nimplementation. Calendar provides a pre-wired `CalendarItem` and semantic\n`CalendarItemState` to an item renderer. Tree owns flattening, expansion,\nselection, keyboard movement, and virtualization while the caller renders each\nvisible `TreeEntry`.\n\n### 4. Infrastructure and utility modules\n\nExamples include Positioner, Scrollbar, VirtualList, FocusTrapElement,\nAutoScroll, motion, History, geometry helpers, measurement, theme tokens, and\nglobal initialization.\n\nThese are deep modules: a small interface hides layout, lifecycle, or data\nstructure complexity used by many controls. Their interface is also their test\nseam; callers should not need to reproduce the hidden algorithm to verify it.\n\n## State Ownership\n\nState ownership follows behavioral needs rather than one universal pattern.\n\n### Controlled values\n\nCheckbox, Radio, Switch, Toggle, Select, and similar roots accept the current\nvalue and report requested changes. They do not silently mutate application\nstate.\n\n```text\napplication value\n      │\n      ▼\nbase element ── activation ──▶ on_change(next_value)\n      ▲                            │\n      └──── next render ───────────┘\n```\n\nCallbacks describe intent. Pointer-originated value changes include the\n`ClickEvent` when modifier keys are useful. Model-driven changes, such as\npagination requests, do not invent a pointer event.\n\n### Handles and explicitly shared state\n\nDialog supports `DialogHandle` for imperative open and close requests while\nstill reporting `DialogChangeReason`. Scrollbar adapters share an underlying\nscroll handle. Toast stack geometry is shared through `ToastStackState`.\n\nHandles coordinate one logical behavior. They must not be reused across\nunrelated viewports or component instances.\n\n### Entity-backed state\n\nComplex modules use `Entity<State>` when they need GPUI observation,\nsubscriptions, focus handles, or incremental notification. The state entity owns\nbehavioral data; the presentation layer still owns how that data looks.\n\n### Keyed element state\n\nSmall pieces of ephemeral state tied to an element identity use\n`window.use_keyed_state`. Stable `ElementId` values are therefore part of the\ninterface, not an implementation detail. Changing an ID can reset focus,\nmeasurement, animation, or open-state bookkeeping.\n\n## Styling Model\n\nBase separates three styling mechanisms:\n\n1. ordinary GPUI `Styled` calls for instance presentation;\n2. typed semantic-state style builders such as checked, selected, or disabled;\n3. GPUI native runtime modifiers such as hover, active, and focus-visible.\n\nThe shared `state_style::resolve_style` function makes semantic precedence\nconsistent across controls. See [Styling and Motion](STYLING-AND-MOTION.md) for\nthe complete contract.\n\nCompound and stateful modules expose explicit presentation seams:\n\n- GPUI `Styled` on the root or part;\n- application-provided children;\n- typed part elements;\n- item renderer callbacks;\n- style refinements for internal virtualized containers;\n- presentation snapshots such as `InputPresentation`.\n\n## Public Data Types Across the Seam\n\nA public struct that crosses the base/application seam must not expose `pub`\nfields. Every field a caller can name is a field that cannot be added later:\nadding one breaks any struct literal, and removing or renaming one breaks every\nreader. The seam types are the ones that grow the most, because each new\ncapability of a control shows up as another flag in the state it hands out.\n\nThe shape to use instead:\n\n- private fields;\n- a builder for construction — `new()` plus one chained setter per field;\n- a reader per field.\n\nSetters and readers must not collide, which decides the naming:\n\n- a type whose fields are all boolean names its setters after the field and its\n  readers `is_<adjective>`/`has_<noun>`, never `can_`, matching how elements\n  read — `CalendarItemState`, `InputContextMenuCapabilities`;\n- a type carrying non-boolean fields prefixes every setter with `with_`, so the\n  readers keep the plain field name — `RenderOptions::with_item_ix` against\n  `RenderOptions::item_ix`. This follows `Sizable::with_size`.\n\nA `with_`-style setter that takes `self` by value also replaces functional\nupdate syntax, which stops compiling once the fields are private:\n\n```rust\n// was: RenderOptions { item_ix, ..*options }\nitem.render_item(&options.with_item_ix(item_ix), window, cx)\n```\n\nA type that is only ever built inside its own module — `InputPresentation` is\nbuilt by `InputBaseState::presentation` and nowhere else — needs the private\nfields and the readers, but not a public builder. Private fields already close\nthe breaking-change hole, and a public builder there would hand out a\nconstruction path the seam does not want. Such a type reads its non-boolean\nfields under the plain field name, which is why it cannot also carry\nfield-named setters.\n\n```rust\nlet capabilities = InputContextMenuCapabilities::new()\n    .code_editor(true)\n    .selection(true);\n\nif capabilities.is_editable() && capabilities.has_selection() { /* ... */ }\n```\n\nDerived answers belong on the type rather than at each call site. When several\nreaders are always combined the same way — `!disabled && !readonly` — publish\nthat combination as its own reader (`is_editable`) so the rule has one\ndefinition and new inputs to it stay invisible to callers.\n\nName such a type in full: `ComboboxTriggerContext`, never `…Ctx`. In a GPUI\ncodebase `cx` is reserved for `App`, `Context<T>`, and `AsyncApp`, so an\nabbreviated `ctx` for anything else reads as a second, competing context. A\ncallback that receives both takes the GPUI one as `cx` and gives the other a\nname describing what it holds.\n\nThis applies to state snapshots (`InputPresentation`, `CalendarItemState`),\ncapability sets (`InputContextMenuCapabilities`), render contexts\n(`ComboboxTriggerContext`), and option sets (`RenderOptions`). It does not\napply to value types whose fields _are_ the definition and cannot grow, such as\n`Point`, `Selection`, `Edges`, `IndexPath`, or `FoldRange`, nor to types that\nmirror an external schema, such as the LSP `Diagnostic`.\n\nDesign-token records (`ColorTokens`, `RadiusTokens`, and the rest of\n`theme_tokens`) still carry `pub` fields. They have the same growth problem, and\nconverting them is tracked separately because every theme in `gpui-component`\nconstructs them.\n\n## Input, Textarea, and Editor Architecture\n\nText editing is intentionally deeper than the semantic elements, but callers do\nnot need to learn the complete editor interface for every text field.\n\n### Public forms\n\nBoth `gpui-base` and `gpui-component` expose three purpose-specific forms:\n\n| Form       | State           | Intended interface                                                                                        |\n| ---------- | --------------- | --------------------------------------------------------------------------------------------------------- |\n| `Input`    | `InputState`    | Single-line values, placeholders, masks, validation, and submission                                       |\n| `Textarea` | `TextareaState` | Ordinary multi-line text, fixed rows, soft wrapping, and optional auto-grow limits                        |\n| `Editor`   | `EditorState`   | Source text, language-aware highlighting, line numbers, folding, search, diagnostics, and LSP integration |\n\n`gpui-base` provides unstyled forms. `gpui-component` adapts the same behavior\ninto the product theme and sizing system. `InputBase` is the foundational frame\nused for input semantics, state styling, accessibility, and application-owned\ncontent; it is not one of the three editing forms.\n\nExisting `gpui-component::Input::new(&Entity<InputState>)` call sites remain the\nsingle-line compatibility path. `InputState` is a real facade, not a type alias\nfor the editing engine: multiline, auto-grow, gutter, folding, diagnostics, and\nLSP configuration are absent from its API. Multi-line code must construct\n`TextareaState` or `EditorState` instead.\n\n### Shared engine\n\n`InputBaseState` owns mechanics shared by all three states:\n\n- Rope-backed text and edit history;\n- cursor, selection, IME, clipboard, and focus;\n- shaping, layout, hit testing, selection and caret painting;\n- auto-scroll, viewport scrolling, and cursor visibility;\n- native text-content integration where supported.\n\nThe implementation under `crates/base/src/input` is organized by responsibility:\n\n- `base/` contains the shared editing engine and foundational mechanics;\n- `input/` contains the single-line control and state facade;\n- `textarea/` contains the multi-line control and state facade;\n- `editor/` contains the editor control and state facade, plus display mapping,\n  highlighting, search, diagnostics, decorations, indentation, and LSP.\n\nThese are implementation folders rather than public Rust module segments. The\nexternal seam remains `gpui_base::input`, with stable re-exports in `mod.rs`.\n\nPurpose-specific state facades configure the shared engine and forward\n`InputEvent` without duplicating those mechanics. `InputState`, `TextareaState`,\nand `EditorState` are distinct GPUI entity types. Their private bridge to\n`InputBaseState` exists for component composition; it is not the application\nAPI.\n\nEditor-only implementation includes indentation, folding, decorations,\ndiagnostics, search, LSP providers, overlays, line-number/gutter painting, and\nsyntax highlighting. Textarea owns rows, soft wrapping, Enter submission, and\nauto-grow policy. Masking, validation, and number stepping remain input-only\nconcepts.\n\n### Presentation and geometry\n\nPresentation is injected through `InputEditorStyle`, highlighter interfaces,\nfold-icon renderers, context-menu adapters, and the higher-level UI forms.\n`gpui-component` supplies editor insets from its size system. Base consumes\nthose insets only as geometry so text, the fixed gutter, and scrollbars share a\ncoordinate system:\n\n- text remains inset from the frame;\n- vertical and horizontal scrollbars terminate at the frame edge;\n- the gutter background covers the complete fixed column, including top,\n  bottom, and leading insets;\n- editor focus does not add the single-line input focus-border treatment.\n\nThis keeps product values in the presentation layer while keeping coupled text,\ngutter, and scrollbar geometry local to the editing engine.\n\n### Input groups\n\n`gpui-component::input::InputGroup` composes one `Input` or `Textarea` with typed\naddons and buttons in a shared frame. It owns no editing state: the control is\nthe ordinary styled `Input`, rendered without its own border, background and\nfocus ring, so every capability the input gains — paste hooks, touch\nselection, native menus, accessibility — reaches a group without being\nmirrored. `InputGroup` owns the outer border, radius, focus and error\ntreatment, and four logical addon regions; `InputGroupButton` wraps a `Button`\nwith compact presentation and sizes through `Sizable`. Textarea viewport\ngeometry remains with the editing engine. Validation appearance is\ncaller-controlled, separately from edit acceptance.\n\nPlatform-specific behavior is isolated behind adapters. For example, folding is\ndisabled on WebAssembly, time uses `web_time` where needed, and native text\ncontent support is conditionally compiled.\n\n## Text Rendering for External Components\n\n`gpui_base::text::editor_host` adapts the same renderer used by `TextView`.\nIt is a rendering boundary for externally owned rich-text components, not an\nediting engine. The host projects its own document into `BlockNode` values;\nBase owns shaping, wrapping, inline-object layout and geometry. The host owns\ndocument identity and revisions, editing semantics, commands, history, selection,\nfocus, accessibility integration, native input and scrolling policy.\n\n### Identity and lifecycle\n\nThere are two independent identities. A stable GPUI element ID scopes retained\nrender state; `BlockNode::render_with_id` provides that scope for top-level\nblocks. Leaf keys identify geometry and decorations within one collection.\nKeys must be unique in that collection. Cloning the AST shares runtime state;\ncalling `with_leaf_key` detaches the leaf's runtime text/selection state so\nrekeying a clone does not rename the original leaf. Independently rendered\ninstances need distinct keys.\n\nRun `collect_leaf_geometry` around child prepaint, not rendering or painting.\nThe scope is synchronous, nests with isolation and restores its predecessor\nduring unwinding. Only prepainted leaves are reported. A virtualized or cached\nsubtree that does not prepaint is absent; a missing entry does not remove a leaf\nfrom the host document.\n\n`LeafGeometry` copies bounds and retains immutable shaped lines. It does not\nretain mutable `TextLayout` handles. A later frame cannot change an existing\nsnapshot, but that snapshot describes only its original content, typography,\nwidth and scroll offset. Hosts must associate geometry with their own document\nrevision and replace it when those inputs change.\n\n### Coordinates and presentation\n\nLeaf offsets are UTF-8 bytes. Each inline image or custom inline node occupies\none U+FFFC (three bytes), independent of its fallback text. Window coordinates\nare logical pixels, before display scaling. Hard breaks and empty lines retain\ncaret positions, including the final empty line. Native input APIs that use\nUTF-16 require conversion in the host.\n\nDecorations are ordered half-open byte ranges. Text decorations paint behind\nglyphs. Any nonempty overlap with an atom decorates its entire box, over the\ncontent, so an opaque image can show its selected state. The host supplies the\ncolor and should use translucency for an atom overlay. Empty ranges paint\nnothing. Decorations do not change layout.\n\n`RenderContext::new` accepts local presentation without application globals;\n`from_app` uses TextView defaults. A host can override syntax highlighting,\nimage resolution and link activation locally. Reference links need definitions\nfrom the entire document, including blocks outside the viewport. Register them\nthrough `with_link_reference`.\n\n### Evolution boundary\n\nKeep the sink, layout caches, flow fragments and shaping implementations private.\nThe public AST is a projection into the renderer, not a canonical editor model\nor persistence format. Do not add editor-specific document operations, history,\ncollaboration or serializer policy to Base merely to serve one consumer.\n\nThis boundary currently supports horizontal text rendered through TextView's\nblock flow. It is not a complete contract for every future editor. In particular,\na future extension for visual navigation must represent caret affinity at soft\nwraps and bidirectional runs; a byte index alone is insufficient. Per-position\ncaret metrics and range rectangles should be designed together with that\ncontract, not inferred from one leaf-wide line height. Pagination, arbitrary\nblock-level widgets, native accessibility text ranges and vertical writing need\ntheir own demonstrated requirements and contract tests before being promised.\n\nThe newly public `BlockNode` enum is non-exhaustive so variants may be added.\nIts existing named variant fields still constrain changes to those variants;\nnon-exhaustiveness is not permission to rename fields or add required fields.\nPrefer new private-field option types and additive constructors when extending\nthe seam. Preserve existing public types and import paths; a pre-1.0 disclaimer\ndoes not replace this project's compatibility requirement.\n\n## Overlay and Positioning Architecture\n\nOverlay modules separate lifecycle from placement and presentation.\n\n### Positioner\n\n`Positioner` is the shared placement implementation. It supports:\n\n- side placement with preferred-side selection, flipping, alignment, offset,\n  and viewport clamping;\n- corner placement compatible with anchored trigger geometry, with viewport\n  clamping but no side flip.\n\nPopup measures its trigger during prepaint, stores the captured bounds in keyed\nstate, and renders positioned content through a deferred element on the next\nframe. Tooltip reuses Positioner rather than maintaining another collision\nalgorithm.\n\n### Modal hosts\n\nDialog and Sheet create viewport-sized hosts. They own focus trapping, keyboard\nactions, backdrop or overlay dismissal, and callback ordering. They do not own\nthe final popup or panel placement: the application styles the supplied popup or\nsurface as centered, right-aligned, bottom-aligned, or another product-specific\nlayout.\n\nOverlay visuals and overlay hit targets are separate layers. The surface is\npainted above the dismissal target so a click inside content does not dismiss\nthe modal.\n\n## Scrolling and Virtualization\n\n`ScrollbarHandle` is the seam between scrolling implementations and the shared\nScrollbar element. An adapter reports:\n\n- viewport bounds;\n- current offset;\n- content size;\n- offset updates;\n- optional drag lifecycle notifications.\n\nAdapters exist for GPUI `ScrollHandle`, `UniformListScrollHandle`, and\n`ListState`, plus base `VirtualListScrollHandle`.\n\nScrollbar normally overlays the viewport reported by its handle. Two explicit\nalternatives support deeper widgets:\n\n- `viewport_bounds` supplies custom-painted bounds, as the editor does;\n- `viewport_from_layout` uses same-frame layout bounds, as DataTable does when\n  excluding fixed headers and columns.\n\nVirtualList owns variable-size item layout, visible-range calculation, content\nmasking, deferred scroll-to-item requests, and clamped offsets. The caller owns\nitem sizes and renders only the requested range. Tree builds on GPUI's uniform\nlist because its visible entries share a row height.\n\n`ScrollableMask` owns wheel dispatch, not scrolling. GPUI's own overflow\nlistener runs in the bubble phase and never stops propagation, so a scroll area\nnested inside another one cannot win: `gpui::list` registers its listener after\nits items paint, and bubble runs in reverse registration order. The mask is a\nsibling of the scrolled element that consumes axis-dominant wheel events in the\ncapture phase, locks each gesture to the axis it started on, and stays inert\nwhile occluded. Edge semantics differ per axis, matching platform scrollers: a\nvertical mask chains to the ancestor at the edge, a horizontal one keeps\nconsuming. `horizontal_scroll_area` is the paired viewport and mask, used by the\nMarkdown scrolling table. A Markdown code block whose style sets `overflow.y` to\n`Overflow::Scroll` pairs its viewport with a vertical mask and a `Scrollbar`.\n\nA plain mouse wheel has only a vertical axis, which a native horizontal scroller\nwith a locked axis ignores. `ScrollableMask::vertical_wheel` sits over such a\nscroller and handles only that wheel: its lines move the scroller sideways and,\nat the edge, chain to the ancestor; trackpad gestures and horizontal wheels go\non to the scroller with its axis lock and bounce. TabBar, the attachment row,\nthe app menu bar and a horizontal `Scrollable` use it. The mask is pinned to its\nparent's top-left corner, so it covers the parent in a row as in a column.\n\nOne handle represents one logical viewport. Sharing a handle between nested or\nunrelated scroll areas causes offsets, hitboxes, and scrollbar geometry to\ninterfere.\n\n## Dock Layout Architecture\n\n`crates/base/src/dock` owns the layout tree, persistence, drag hit-testing,\nresize arithmetic, the active-panel state machine, zoom, focus, and the panel\nregistry. `crates/component/src/dock` is a skin: `DockSkin` implements the renderer\ntraits below to supply the tab bar, toolbar, drop-indicator, and dock-toggle\nappearance. A `DockArea` built without a renderer still docks, drags, and\npersists — it draws no chrome at all.\n\n### The layout tree\n\n`PaneTree` is the single source of truth for one region — the center, or\none of the left/bottom/right docks. It stores no GPUI entity handles:\ncontainers are addressed by `NodeId`, panels by `PanelId` (the panel entity's\n`EntityId`), and a container's `NodeKind` is one of `Split` or `Tabs`. There\nis no leaf variant, so a panel can only ever live inside a `Tabs` node — the\ninvariant a runtime assertion checked in the old implementation is expressed\nin the type instead.\n\n`NodeKind` stays private. Callers read a node through the borrowed `PaneRef`\nprojection and never construct one directly; every mutation goes through\n`PaneTree`'s edit methods (`insert_panel`, `remove_panel`, `move_panel`,\n`split`, `set_active`, `set_sizes`), each\nof which runs `normalize` before returning. When base needs a fact about a\npanel — its name, its visibility, its dump — it asks a `PanelSource` rather\nthan the entity directly, which is what makes the layout algebra testable as\npure functions with no `TestAppContext`.\n\nBuilding a layout is entity-free too: `DockLayout` (`h_split`, `v_split`,\n`tabs`, chained with `.child(...)`, `.panel_view(...)`, and\n`.active_index(...)`) produces a tree rather than\nconstructing containers. `DockArea::set_center` and `set_dock` reconcile a\n`DockLayout` into live entities when it is installed.\n\nPanels go in wrapped: `gpui_component::dock::panel_handle(panel)` is what\ncarries a panel's presentation across the renderer seam, and every entry point\ntakes one — `DockLayout::panel_view` when describing a layout,\n`DockArea::add_panel_view` when adding to a live one, and\nthe closure a `register_panel` builder returns.\n\n```rust,ignore\nlet center = DockLayout::h_split()\n    .child(DockLayout::tabs().panel_view(panel_handle(files), cx), Some(px(240.)))\n    .child(DockLayout::tabs().panel_view(panel_handle(editor), cx), None);\ndock_area.update(cx, |area, cx| area.set_center(center, window, cx));\n```\n\nBase's own `DockLayout::panel` and `DockArea::add_panel`\ntake a bare `Entity<P>` instead. They are the base-only forms: the panel docks,\ndrags and persists exactly the same, but base stores the bare entity and the\nskin cannot recover presentation from it, so **every tab draws the panel's\n`panel_name` where its title belongs**. The only signal is a one-off\n`tracing::warn!`. Use them only when there is no skin over the dock at all.\n\n### Normalization\n\nOne post-order pass, repeated to a fixpoint, replaces the mutually recursive\nparent-pointer collapse the old `StackPanel`/`TabPanel` pair used:\n\n1. An empty `Tabs` or `Split` is removed from its parent; the root\n   is exempt.\n2. A `Split` with one child is replaced by that child, which keeps its own\n   `NodeId` and inherits the split's slot size.\n3. A `Split` containing a `Split` of the same axis splices the inner\n   children into the outer node.\n4. `active_ix` is clamped to the panel count.\n5. Root shape is enforced per `RootKind` — the center's root is always a\n   `Split`, so an empty center still serializes as a stack; a dock's root is\n   unconstrained.\n\n`normalize` is idempotent and needs no parent pointers or deferred work: the\ntree is self-consistent the instant an edit operation returns.\n\n### Reconciliation\n\n`DockArea` holds the tree plus a cache of container and panel entities keyed\nby `NodeId` and `PanelId`. After any edit that reports a change, it walks the\ntree, creates an entity for each container id the cache does not yet have,\ndrops cache entries for ids no longer present — calling `on_removed` on the\npanels that departed — pushes sizes and `active_ix` into the surviving\nentities, and emits `DockEvent::LayoutChanged`.\n\nBecause `NodeId` survives every edit operation and every `normalize` rule, a\nsteady-state reconciliation pass creates and drops nothing: only genuinely\nnew or dead containers churn. That is what keeps a drag from resetting the\nstate of panels it did not touch.\n\n### Rendering seam\n\n`TabGroup` owns the panel list mirrored from the tree, the active index, the\nfocus handle, drag-and-drop hit state, and the zoom flag; it renders a\nskeleton and delegates all appearance to a `TabGroupRenderer`.\n`DockAreaRenderer` does the same for the area frame and the docks. Base\nattaches the drag source, drop-target hit testing, keyboard actions, and focus\nhandling — a renderer implementation never sees a drag event, only resolved\nstate through `TabGroupContext` and `DockContext`.\n\n`Panel` splits at the seam the same way: `gpui_base::dock::Panel` covers\nbehavior (`panel_name`, `visible`, `closable`, `zoomable`, `set_active`,\n`set_zoomed`, `on_added_to`, `on_removed`, `dump`), and\n`gpui_component::dock::Panel` extends it with presentation (`title`,\n`tab_name`, `toolbar_buttons`, `dropdown_menu`, `zoom_control`). A panel type\nimplements both.\n\n## Theme Projection\n\nThe base `Theme` contains:\n\n- `SemanticThemeTokens` for colors, radius, spacing, typography, and shadows;\n- global Scrollbar defaults;\n- the minimal Resizable handle colors required by its infrastructure.\n\nSemantic tokens describe roles and scales, never component names. They do not\nautomatically style base controls. A presentation layer reads and applies them.\n\n`gpui-component` projects its active theme into the base theme during\ninitialization and theme changes. Direct base users can mutate\n`gpui_base::Theme::global_mut(cx)` themselves.\n\n## Motion and Lifecycle\n\nOrdinary semantic controls do not install product motion. The generic\n`motion::transition` function manages keyed interpolation, timing, reversal,\nanimation frames, and reduced-motion behavior while the caller chooses the\nanimated property.\n\nSome deep behavior modules own configurable motion that is inseparable from\ntheir layout lifecycle. `ToastStack`, for example, owns stack expansion,\ncollapse, measurement, and overlap motion through `ToastMotion`. Its child\n`Toast` remains an unstyled semantic root, and the application owns toast\ncontent and visual styling.\n\nThis distinction is intentional:\n\n- product decoration and choreography belong to presentation;\n- motion required to keep a deep behavioral layout coherent may live in that\n  module and must be configurable.\n\n## Initialization\n\nCall `gpui_base::init(cx)` before constructing base controls. Initialization:\n\n- installs the base global theme if absent;\n- initializes shared global state;\n- reads the operating system's reduced-motion preference into\n  `App::set_reduce_motion` (see `reduce_motion.rs` for the per-platform\n  sources and the rule that an application's own setting wins);\n- registers key bindings and infrastructure for dialog, focus traps, popover,\n  sheet, combobox, color picker, select, number input, input, and tree.\n\nApplications that call `gpui_component::init(cx)` must not initialize base a\nsecond time; the styled crate includes base initialization.\n\n## Relationship to `gpui-component`\n\n`gpui-component` is a presentation adapter and compatibility layer above base.\nIt may:\n\n- map its Theme into base tokens and infrastructure defaults;\n- wrap base elements with labels, icons, sizes, variants, and product layout;\n- provide application-specific popup menus, LSP views, and native integrations;\n- preserve historical public interfaces while delegating behavior to base.\n\nThe migration of a UI control to a base module is complete only when behavior,\nfocus, keyboard interaction, accessibility, overlay geometry, and visual output\nremain correct. Sharing a type name or compiling an adapter is not sufficient.\n\n## Design Invariants\n\nChanges to `gpui-base` should preserve these invariants:\n\n1. Base remains independent of `gpui-component` presentation and assets.\n2. Reusable behavior is implemented once behind the lowest useful interface.\n3. Applications can replace the visual language without reimplementing the\n   behavior module.\n4. Behavioral geometry stays with the module that must keep it correct.\n5. Controlled elements report intent and do not own application values.\n6. Stable element identity is documented wherever keyed state is used.\n7. Pointer and keyboard paths converge on the same semantic action.\n8. Accessibility is behavior, not optional decoration.\n9. Overlay coordinates, paint order, and hitboxes use one viewport model.\n10. One scroll handle represents one logical viewport.\n11. Platform differences are isolated behind explicit adapters or conditional\n    implementations.\n12. Public types that cross the seam keep their fields private, are built with a\n    builder, and are read through methods, so a new field is not a breaking\n    change.\n13. Long-lived architectural facts belong here; progress logs and temporary\n    reviews belong in issues and pull requests.\n","isInternal":false,"tokens":6824,"sizeBytes":32763}],"systemPromptSnippet":"<yakaai_skills repo=\"longbridge/gpui-component\">\n<!-- File: AGENTS.md (Tokens: ~3818 | Category: root-instruction) -->\n# AGENTS.md\n\nThis file provides shared guidance for coding agents working in this repository.\nKeep project rules here; `CLAUDE.md` imports this file for Claude Code.\n\n## Canonical Design and Coding Guides\n\nBefore changing UI, interaction, interface language, layout, styling,\ncomponents, or application architecture, read and follow the repository's\ncanonical guides:\n\n- [Design Guides](website/docs/design-guides.md)\n- [Coding Guides](website/docs/coding-guides.md)\n\nThese guides are requirements, not optional inspiration. Do not copy generic\nweb conventions, infer a design system from one existing screen, or add a\ncontrol merely because the underlying feature exists. Preserve the documented\ntask hierarchy, interaction promise, desktop conventions, spacing, alignment,\ntheme tokens, component boundaries, naming, and crate architecture. Review the\nfinished work against both guides before considering it complete.\n\nFor Chinese documentation and UI, apply the terminology rules in Design Guides.\nKeep established framework, component, and API names in their canonical English\nform when translation would reduce precision; write the surrounding Chinese as\nnatural Chinese rather than word-for-word translation.\n\n## Project Overview\n\nGPUI Kit is a Rust desktop application framework built on GPUI, published at <https://gpui-kit.com>. It ships as three crates: `gpui-base` (unstyled behavior and infrastructure), `gpui-shell` (JavaScript extensions for a Rust host), and `gpui-component` (GPUI Component, the styled component library with 60+ cross-platform desktop UI components, inspired by macOS/Windows controls and combined with shadcn/ui design). Applications depend on the umbrella crate `gpui-kit` (`crates/kit`), which pins the matching `gpui-pre-*` snapshot of GPUI and puts GPUI at its root (`use gpui_kit::*;`) with `gpui_kit::platform`, `gpui_kit::base`, `gpui_kit::component` and `gpui_kit::assets` reachable by name, so they never list GPUI itself. `gpui-shell` is not part of `gpui-kit` and is not published yet (its `llrt_*` dependencies are git-only); use it as a git dependency.\n\nThis is a Rust workspace project with the following main crates:\n\n- `crates/kit` - Umbrella crate applications depend on (published as `gpui-kit`)\n- `crates/component` - Core UI component library (published as `gpui-component`)\n- `crates/story` - Gallery application for showcasing and testing components\n- `crates/story-web` - Web version of the story gallery (using WebAssembly)\n- `crates/component-macros` - Procedural macros (`IntoPlot` derive)\n- `crates/assets` - Static assets\n- `crates/webview` - WebView component support\n- `examples/` - Various example applications\n\n## Common Commands\n\n### Development and Testing\n\n```bash\n# Run Story Gallery (component showcase application)\ncargo run\n\n# Run individual examples\ncargo run --example hello_world\ncargo run --example table\n\n# Build the project\ncargo build\n\n# Lint check\ncargo clippy -- --deny warnings\n\n# Format check\ncargo fmt --check\n\n# Spell check\ntypos\n\n# Check for unused dependencies\ncargo machete\n```\n\n### Testing\n\n**Note**: Per user configuration, tests do not need to be run.\n\nFor pure UI visual or sizing adjustments, do not add automated tests solely to\nassert presentation dimensions. Add tests when the change affects behavior,\ninteraction, data flow, or prevents a meaningful regression.\n\n```bash\n# Run all tests\ncargo test --all\n\n# Run tests for a specific crate\ncargo test -p gpui-component\n\n# Run doc tests\ncargo test -p gpui-component --doc\n```\n\n### Performance Profiling\n\n```bash\n# View FPS on macOS (using Metal HUD)\nMTL_HUD_ENABLED=1 cargo run\n\n# Profile performance using samply\nsamply record cargo run\n```\n\n## Core Architecture\n\n### Architecture Refactoring Constraints\n\nThe implemented foundation architecture is documented in\n`docs/ARCHITECTURE.md`, with styling and motion rules in\n`docs/STYLING-AND-MOTION.md`. Preserve these constraints when designing or\nimplementing this architecture:\n\n- Do not modify `gpui-base` unless the user explicitly requests a Base-layer\n  change. By default, implement component behavior and visual styling in\n  `crates/component` or the application layer.\n\n- Keep GPUI Kit as the ecosystem and product brand; `gpui-component` is its\n  styled component layer, alongside `gpui-base` and `gpui-shell`.\n- Name the foundation crate `gpui-base`.\n- Follow the ownership boundary: the framework owns behavior and infrastructure;\n  the application owns component source and visual style.\n- Keep the base layer visually unopinionated. It may provide interaction behavior,\n  accessibility, focus, overlay and popup infrastructure, positioning, animation,\n  virtual lists, dock infrastructure, and semantic design tokens.\n- Theme APIs must expose semantic tokens (colors, spacing, radius, typography, and\n  shadows), not an ever-growing set of component-specific styling fields.\n- Keep source distribution or registry tooling above the `gpui-base` seam; no\n  registry or CLI crate is currently part of the workspace.\n- Preserve 100% backward compatibility for existing consumers, including current\n  imports such as `use gpui_kit::component::button::Button;`.\n\n### Component Initialization\n\nCall `gpui_kit::init(cx)` before opening windows that use styled components.\nIt includes Base initialization and registers Component's window extension.\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx| {\n        gpui_kit::init(cx);\n        gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| {\n            cx.new(|_| MyView)\n        })\n        .expect(\"Failed to open window\");\n    });\n}\n```\n\nBase-only fixtures use GPUI directly and must not depend on Kit or Component.\nApplications and Kit tests use `gpui_kit::open_window` as their window entry point.\n\n### Root View System\n\n`gpui_base::Root` is the top-level view for every window created by\n`gpui_kit::open_window`. The helper belongs only to Kit; Base supplies the Root\nimplementation. `component::Root` re-exports the Base type. Cargo features do not\nselect a different root type.\n\nBase owns content and overlay hosting, keyboard navigation (Tab/Shift-Tab),\nand selection copying. Explicit Component initialization registers per-window\nstate and presentation for dialogs, sheets, notifications, tooltips, menus,\ntouch selection, themes and window chrome. Initialize before creating windows.\n\nThe helper returns the window handle and application content entity. Its builder\nmust return content, not another Root. Overlay layers mount automatically; do not\ncall the removed `Root::render_*_layer` methods. In async contexts call the helper\ninside `cx.update`. Tests should use the same helper and retain its returned\ncontent entity when they need to inspect or update application state. Avoid\nconstructing `Root` directly in application and test startup code.\n\nQuit/close actions, keyboard shortcuts and confirmation flows belong to the application.\n\n### Theme System\n\n- Uses `Theme` global singleton for theme configuration\n- Supports light/dark mode switching\n- Access theme via `ActiveTheme` trait: `cx.theme()`\n- Theme configuration includes:\n  - Colors (`ThemeColor`)\n  - Syntax highlighting theme (`HighlightTheme`)\n  - Font configuration (system font and monospace font)\n  - UI parameters like border radius, shadows\n  - Scrollbar display mode\n\n### Dock System\n\nLayout behavior lives in `crates/base/src/dock`; `crates/component/src/dock` is a\npresentation skin (`DockSkin`) over it. See `docs/ARCHITECTURE.md`.\n\n- **`LayoutTree`**: Pure-data layout tree, the single source of truth.\n  - `NodeKind::Split` / `Tabs`: containers, addressed by `NodeId`\n  - Panels are addressed by `PanelId`; the tree holds no entity handles\n- **`DockArea`**: Owns the center and dock trees, reconciles them into a\n  cache of container entities keyed by `NodeId`\n- **`TabGroup`**: The `Tabs` container entity\n- **`Panel`**: Split at the seam — `gpui_base::dock::Panel` for behavior,\n  `gpui_component::dock::Panel` for presentation; a panel implements both\n- **`PanelRegistry`**: Resolves a persisted `panel_name` back to a panel type\n\nThe Dock system supports:\n\n- Panel drag-and-drop reordering\n- Panel zoom\n- Layout locking\n- Layout serialization/restoration\n\n### Input System\n\nText input system based on Rope data structure:\n\n- **InputState**: Input state management\n- **Rope**: Efficient text storage (from ropey crate)\n- LSP integration support (diagnostics, completion, hover)\n- Syntax highlighting support (Tree-sitter)\n- Multiple input modes:\n  - Regular input (`Input`)\n  - Number input (`NumberInput`)\n  - OTP input (`OtpInput`)\n\n### Component Design Principles\n\n1. **Stateless design**: Use `RenderOnce` trait, components should be stateless when possible\n2. **Size system**: Supports `xs`, `sm`, `md` (default), `lg` sizes via `Sizable` trait.\n3. **Mouse cursor**: Buttons use `default` cursor not `pointer` (desktop app convention), unless it's a link button\n4. **Style system**: Provides CSS-like styling API via `Styled` trait and `ElementExt` extensions\n5. **Base controls are no-style**: Base controls and parts do not install layout,\n   positioning, colors, sizing, gaps, radius, borders, shadows, variants, or animation.\n   Complete presentation belongs to `crates/component` or the application. The deliberate\n   exception is the foundational Base Input frame, which provides only a semantic\n   one-pixel input border and semantic radius baseline; UI/application layers own\n   its background, sizing, padding, typography, adornments, and richer focus style.\n6. **GPUI builder style**: Keep element construction as one fluent builder chain. Express\n   conditions with `when`, `when_some`, `when_none`, and `map`; do not split a chain into a\n   mutable temporary element followed by imperative reassignment when the builder API can\n   express the same operation.\n7. **No `pub` fields on public data types**: A public struct handed across the\n   `gpui-base`/application seam — a state snapshot, capability set, render context, or\n   option set — keeps its fields private, is constructed with a builder, and is read\n   through methods. Adding a `pub` field is a breaking change; adding one behind a builder\n   is not. Setters and readers must not collide: an all-boolean type names setters after\n   the field and readers `is_<adjective>`/`has_<noun>`, never `can_`; a type with\n   non-boolean fields prefixes every setter with `with_` and keeps the field name for\n   readers. Value types whose fields are the definition and cannot grow (`Point`,\n   `Selection`, `Edges`) are exempt. See the \"Public Data Types Across the Seam\" section\n   of `docs/ARCHITECTURE.md`.\n8. **Spell `Context` out**: Name a context type `ComboboxTriggerContext`, never `…Ctx`.\n   `cx` is reserved for GPUI's `App`, `Context<T>`, and `AsyncApp`, so `ctx` for anything\n   else reads as a competing context. A callback receiving both takes the GPUI one as `cx`\n   and names the other after what it holds (`trigger`, `state`).\n\n## Pull Request Reviews\n\nEvery PR review must present its conclusions in this order:\n\n1. Explain the PR's purpose: the problem it addresses and the scope of its changes.\n2. Assess whether the requirement and proposed approach are reasonable.\n3. Report concrete findings, followed by validation performed and its limitations.\n\nDo not start a review with findings alone; include the purpose and reasonableness\nassessment even when no issues are found.\n\n## Code Style\n\n- Follow naming and organization patterns from existing code\n- Reference macOS/Windows control API design for naming\n- AI-generated code must be refactored to match project style\n- Mark AI-generated portions when submitting PRs\n- When creating a PR, inspect previous PR titles in the repository and match\n  that style. Do not blindly use conventional prefixes like `fix:` or `feat:`\n  unless the existing PR title style uses them.\n- When a PR adds, changes or removes public API in any crate, list every item\n  under a `## Public API` section of the description, grouped by crate, with its\n  signature and one line on its purpose (JavaScript methods and TypeScript\n  declarations included). Changes to existing items also go under\n  `## Breaking Changes` with `diff` blocks showing the old and new usage. See\n  PR #2691 and the \"Describe public API changes\" section of `CONTRIBUTING.md`.\n- Avoid `Kind` as a type-name suffix. It says an enum classifies something\n  without saying what it classifies, and carries no meaning a reader could not\n  already infer from `enum`. Name the type after what its variants _are_\n  instead. Keep `Kind` only when no honest name covers the variant set —\n  `NodeKind`'s variants straddle two levels (`Split` is an interior node,\n  `Tabs` is a leaf), and every domain word for the leaf level\n  (`Pane`, most of all) would misdescribe `Split`; a vaguer name is better\n  than a precise wrong one. Prefer confining such a type to `pub(crate)`.\n  This governs new code; existing `Kind` names are not a rewrite target on\n  their own, and names owned by external crates (`CodeActionKind`,\n  `CompletionItemKind`, `WindowKind`) keep their upstream spelling.\n\n## Icon System\n\nThe `Icon` element does not include SVG files by default. You need to:\n\n- Use [Lucide](https://lucide.dev) or other icon libraries\n- Name SVG files according to the `IconName` enum definition (located in `crates/component/src/icon.rs`)\n\n## Dependencies\n\n- GPUI: Git version from Zed repository\n- Tree-sitter: For syntax highlighting\n- Ropey: Rope data structure for text, and `RopeExt` trait with more features.\n- Markdown rendering: `markdown` crate\n- HTML rendering: `html5ever` (basic support)\n- Charts: Built-in chart components\n- LSP: `lsp-types` crate\n\n## Internationalization\n\nUses `rust-i18n` crate.\n\n- Localization files are located in `crates/component/locales/`.\n- Only add `en`, `zh-CN`, `zh-HK` by default.\n- Accessibility (A11y) names and labels may remain in English; localization is\n  not required for these strings. Keep the item's own label when naming a\n  control that acts on it. This exception does not apply to visible UI copy.\n\n## Documentation\n\n- The documentation site source is in `website/`.\n- Site docs have two locales: English (`website/docs/`) and Chinese (`website/zh-CN/docs/`).\n- When modifying any documentation file, always sync changes to both `en` and `zh-CN` versions.\n- `docs/` holds internal architecture specifications (RFC, migration status, reviews).\n  These are single-language and are not published to the site; see `docs/README.md`.\n- `skills/gpui-kit/references/coding-guides.md` and\n  `skills/gpui-kit-design-guides/references/design-guides.md` are verbatim copies\n  of the English `website/docs/` originals, vendored so the skills work after\n  `npx skills add` in a project that does not have this repo. After editing either\n  guide, copy it across:\n\n  ```bash\n  cp website/docs/design-guides.md skills/gpui-kit-design-guides/references/design-guides.md\n  cp website/docs/coding-guides.md skills/gpui-kit/references/coding-guides.md\n  ```\n\n  Never edit the copy directly — edit `website/docs/`.\n\n## Platform Support\n\n- macOS (aarch64, x86_64)\n- Linux (x86_64)\n- Windows (x86_64)\n\nCI runs full test suite on each platform.\n\n## Skills Reference\n\nThis project provides skills for coding agents to assist with common development tasks:\n\n- **gpui-kit** (`skills/gpui-kit/SKILL.md`) - Building applications on the `gpui-kit` crate: setup, component catalog, stateless/stateful patterns, theming, GPUI mechanics (actions, async, contexts, custom elements, entities, events, focus, global state, layout, `ElementId`, testing), and the normative Coding Guides\n- **gpui-kit-design-guides** (`skills/gpui-kit-design-guides/SKILL.md`) - The normative Design Guides; load before any UI, layout, interaction, or interface-copy work\n\nWhen working on tasks related to these areas, read the appropriate `SKILL.md`\nfor specialized guidance and patterns.\n\n## Shared Workflows\n\n- [Release notes](.agents/commands/release-notes.md) - Write release notes from a\n  version tag or a pasted \"What's Changed\" list. Claude Code exposes this workflow\n  through `/release-notes`; other agents can read and follow the shared file.\n\n## Testing Guidelines\n\nSee `.agents/COMPONENT_TEST_RULES.md` for detailed testing principles:\n\n- **Simplicity First**: Focus on complex logic and core functionality, avoid excessive simple tests\n- **Builder Pattern Testing**: Every component should have a `test_*_builder` test covering the builder pattern\n- **Complex Logic Testing**: Test conditional branching, state transitions, and edge cases\n\n<!-- File: CLAUDE.md (Tokens: ~9 | Category: claude-rule) -->\n# Claude Code\n\n@AGENTS.md\n\n<!-- File: skills/gpui-kit-design-guides/references/design-guides.md (Tokens: ~10244 | Category: anthropic-skill) -->\n---\ntitle: Design Guides\ndescription: Product and interaction design guidance for GPUI Kit applications\norder: -12\n---\n\n# Design Guides\n\nUse this guide before choosing components or writing layout code. It records\nthe product judgment accumulated through years of GPUI Kit desktop work:\nan interface should feel native, restrained, precise, and understandable\nwithout guesswork.\n\nThis is a normative guide. **Must** identifies a correctness or ecosystem\nconstraint, **should** is the default that needs a concrete reason to override,\nand **may** is an optional technique. Component API documentation remains the\nauthority for individual methods.\n\nThe rules build on behavior in `gpui-base`, the GPUI Component theme and\ncomponent system, and familiar desktop interaction. <a href=\"https://ui.shadcn.com/docs\" target=\"_blank\" rel=\"noopener noreferrer\">shadcn/ui</a> contributes useful\nmethods—open code, composition, and dependable defaults—but does not determine\nhow a GPUI application should look. When influences conflict, preserve GPUI's\nlifecycle constraints and the interaction people already understand.\n\n## Design thesis\n\nBuild interfaces that feel native, quiet, and precise. Let content, hierarchy,\nand interaction carry the experience; decoration should support them rather\nthan compete with them.\n\n1. **Clarity before personality.** Make the primary task and next action clear\n   before adding brand expression.\n2. **Composition before invention.** Start with established components and\n   compose them into product-specific workflows. Create a new primitive only\n   when its behavior is genuinely new.\n3. **Tokens before values.** Colors, radii, typography, and spacing should form\n   a system. Avoid isolated literals that cannot respond to themes. See\n   [Style](./style) for GPUI's styling API.\n4. **Desktop before web convention.** Preserve keyboard access, window chrome,\n   menus, dense data views, resizable regions, and persistent navigation where\n   the task benefits from them.\n5. **State must be visible.** Hover, focus, selection, disabled, loading,\n   validation, and destructive states need distinct and consistent treatment.\n6. **Geometry explains containment.** Radii, insets, and boundaries should\n   describe one coherent hierarchy, even where surfaces overlap.\n7. **Feedback reflects reality.** Loading, tooltips, and motion should clarify\n   a real state or transition, not add ceremony to an immediate action.\n\n## Learning from Shadcn\n\nShadcn's most useful contribution is not a particular border color. It is a\nway of building a system:\n\n- own the top layer of the interface instead of fighting a sealed abstraction;\n- compose small, predictable parts into product-specific components;\n- provide defaults that already form one visual language;\n- keep the code and composition legible to both people and AI;\n- separate behavior primitives from the styled layer.\n\nGPUI Kit applies those ideas through a Rust library and the split between\n`gpui-base` and `gpui-component`. Applications normally compose or wrap the\npublished components; contributors move genuinely reusable behavior into Base\nand keep visual policy above it.\n\nDo not copy these web assumptions blindly:\n\n| Web habit | Native GPUI default |\n| --- | --- |\n| Pointing-hand cursor on every button | Default arrow cursor; pointing hand for links |\n| Page navigation as the main structure | Persistent windows, panes, sidebars, tabs, and menus |\n| Browser focus and scrolling as a fallback | Explicit focus ownership and region-owned scrolling |\n| Mobile-first single column | Resizable desktop shell with a defined minimum window size |\n| Hover-revealed critical actions | Keyboard- and pointer-reachable actions that do not depend on hover |\n| A row of hover-only icon buttons | A visible primary action plus `DropdownMenu` or `ContextMenu` for secondary commands |\n| Link-styled text for application commands | `Button`, `outline`, or `ghost`; Link only for URLs, web resources, or email addresses |\n| Large touch density everywhere | Medium density by default; compact only where information work benefits |\n| CSS overrides across descendants | Typed builders, semantic parts, and application composition |\n\n## Start from the task\n\nBefore drawing a screen, write down:\n\n- the user's primary task;\n- the object being viewed or changed;\n- the actions that must remain immediately available;\n- the information required to make a decision;\n- empty, loading, error, offline, read-only, and permission-denied states;\n- the keyboard path through the workflow.\n\nOrganize the window around those answers. Do not begin with a dashboard grid or\na component catalogue. A good desktop interface exposes the user's mental\nmodel: documents, accounts, projects, messages, settings, or another stable\nobject—not the internal service architecture.\n\nDesign the primary task before distributing controls. Its visual weight,\nlocation, and information depth should match its importance to the product. A\ncore result must not be reduced to a small count, an icon in a corner, or a\nweak footer action while secondary content consumes the page. When a result set\nis the product's main value, consider a summary region or card that exposes the\ncount, representative results, meaningful state, and a clear next action.\n\nFor every proposed action, name its visible object, current state, scope, and\nresult. If the interface does not show or clearly imply those things, the\naction is premature. Do not expose a capability merely because the backend has\nit; first design how the object enters the user's mental model.\n\n## Visual language\n\n### Hierarchy\n\nPrefer a small number of clear levels:\n\n- **window or page title** identifies the current object or workspace;\n- **section title** separates meaningful regions;\n- **body text** carries the work;\n- **muted text** provides secondary metadata and help;\n- **labels** identify controls and values.\n\nUse size, weight, spacing, and separators before adding color or containers.\nAvoid nesting cards inside cards: most desktop regions need only a background,\na hairline boundary, and intentional spacing.\n\nEvaluate hierarchy across the whole feature, not component by component. Hide\naccent color and decoration during review: the primary task, current selection,\nresult summary, and next action should still be obvious from structure. A\nscreen that contains individually plausible controls can still fail when they\ndo not form one reading order and one decision path.\n\nTreat emphasis as a limited budget. A local surface needs one clear focal point,\nnot a field of competing highlights. If everything is colored, badged, bold,\nboxed, or promoted to an alert, nothing reads as important. Establish priority\nwith structure and proximity first; spend stronger color and components only\nwhere a distinction changes what the user notices or does.\n\n### Color and themes\n\nRead colors from `cx.theme()` and use them by semantic role:\n\n- `background` and `foreground` for the main surface and text;\n- `group_box`, `popover`, `sidebar`, and their foreground tokens for their\n  named surfaces;\n- `muted` and `muted_foreground` for supporting information;\n- `primary` for the principal action or selection emphasis;\n- `danger`, `warning`, `success`, and `info` only for their meanings;\n- `border`, `input`, and focus-ring tokens for structure and interaction.\n\nDo not use a semantic status color as decoration. Do not encode meaning by\ncolor alone. Verify every custom surface in light and dark themes and with\ncustom theme values; never assume that foreground is black or background is\nwhite.\n\nUse Badge for a short state, count, or classification that benefits from rapid\nscanning—not for every label, metadata value, filter, or section title. Keep\nmost badges neutral; reserve semantic variants for states that truly carry\nsuccess, warning, danger, or informational meaning. A row of multicolored\nbadges is usually a missing hierarchy or grouping decision.\n\nApplication UI should not contain raw hex, `rgb`/`rgba`, or `hsla` colors.\nResolve colors from `cx.theme()` by semantic role. If the required role does\nnot exist, define it in the product's theme/token layer rather than embedding a\npalette value at the call site. Raw colors belong only inside theme definitions\nor in audited data/raster content whose color is itself the data.\n\n### Radius, spacing, and density\n\nUse a finite radius scale, as with type and control sizes. Choose from the\ntheme's named tiers (`sm`, `md`, `lg`, `xl`, and larger surface tiers) instead\nof inventing a radius for each element. Large containers may use a softer tier\nthan the controls they contain; compact controls and overlays use tighter\ntiers. For an ordinary rectangle, the radius should remain visibly smaller\nthan half its shorter side. Use `radius_full()` only for intentional circles\nand pills; a tooltip must not become a capsule by accident.\n\nNested surfaces should read as concentric shapes. Use\n`inner radius ≈ max(0, outer radius − gap)` to choose the closest suitable\ntheme tier; the visible band should remain even through the turn. Add a\nnamed application token if a repeated composition needs an intermediate\nvalue. A segmented control is one silhouette: its end segments follow the container's inner\ncorners, its middle segments remain square, and each boundary has one divider\nof consistent thickness.\n\n<img class=\"alignment-light\" src=\"/radius-hierarchy.svg?v=20260923-easing\" alt=\"Light theme chat composer: the inset surface, both buttons, and placeholder spacing change together; red guide circles show their shared corner center.\">\n<img class=\"alignment-dark\" src=\"/radius-hierarchy-dark.svg?v=20260923-easing\" alt=\"Dark theme chat composer: the inset surface, both buttons, and placeholder spacing change together; red guide circles show their shared corner center.\">\n\nA radius must govern the entire visible surface, not just its border. Exposed\ncorners remain transparent to the surface behind them; child backgrounds,\nselection fills, and scrolling content must also follow the boundary. In GPUI,\ndo not assume a rounded parent clips its descendants. Give inner surfaces their\nown radius or an appropriate clip, then inspect the composition against a\ncontrasting background in both themes. Preserve outward focus rings when\nchoosing a clip.\n\nUse a compact spacing scale and repeat it. Related label/control pairs should\nbe closer than separate groups; separate groups should be closer than separate\nsections. Prefer component sizes (`xsmall`, `small`, default medium, `large`)\nover one-off heights. Use compact variants for toolbars and data-dense screens,\nnot to squeeze an unclear layout into less space.\n\nThe shared semantic scale is intentionally small: spacing progresses through\nroughly 2, 4, 8, 12, 16, 24, and 32 pixels, while typography stays near 12,\n14, 16, 18, and 20 pixels. Treat these as relationships rather than permission\nto scatter their current values through feature code. GPUI Component currently\nprojects a fixed default `SpacingTokens` scale from its global `Theme`; unlike\ncolors and radii, `Theme::apply_semantic_tokens` does not persist a custom\nspacing scale. An application that needs different spacing must own that full\ntoken snapshot and use it consistently in its application components.\n\n### Spatial grammar\n\nSpacing expresses relationship. Choose a gap from the semantic scale by asking\nwhat the two things mean to each other:\n\n| Relationship | Typical token | Current scale | Examples |\n| --- | --- | --- | --- |\n| Optical correction | `xxs` | 2 px | icon baseline, compact separator |\n| Parts of one control | `xs` | 4 px | menu icon/label, title/description |\n| Closely related controls | `sm` | 8 px | button icon/label, dialog actions |\n| One content group | `md` | 12 px | notification columns, compact form rows |\n| Separate groups in one section | `lg` | 16 px | panel padding, form groups |\n| Separate sections | `xl` | 24 px | major blocks in a page or inspector |\n| Major region boundary | `xxl` | 32 px | empty-state breathing room, page bands |\n\nThese values describe the current default scale, not literals to repeat. Use\n`cx.theme().spacing_tokens()` or the corresponding GPUI scale helpers for the\necosystem default. A product-owned scale should preserve the ordering and\nrelationships and must be passed through the application's own design-system\ncontext rather than assumed to persist in the global GPUI Component theme.\n\nUse these rules when resolving horizontal and vertical space:\n\n1. **Inside before outside.** A component's padding belongs to the component;\n   the gap between components belongs to their parent.\n2. **Vertical rhythm shows grouping.** The gap between a title and its\n   description is smaller than the gap from that description to the next\n   section. Equal gaps imply equal relationships.\n3. **Horizontal space supports scanning.** Repeated rows keep icons, labels,\n   values, badges, and trailing actions on stable columns.\n4. **Leading and trailing are semantic.** Think in reading-order edges even\n   when the current API uses left/right; this keeps future RTL adaptation\n   possible.\n5. **Do not double padding.** A card placed in an already padded panel should\n   not automatically add another full panel inset.\n6. **Use optical alignment sparingly.** A one- or two-pixel correction is valid\n   for icon or glyph geometry, but document why it differs from the scale.\n\nCommon compositions in the current system illustrate the relationships:\n\n- button contents use 4 px at small sizes and 8 px at normal sizes;\n- dialog headers and footers use an 8 px internal gap;\n- compact list and menu rows use 4 px vertical and 8–12 px horizontal padding;\n- sheet headers use about 16 px leading and 12 px trailing space, leaving room\n  for a close affordance, while footers use 16 px horizontal and 12 px vertical\n  space;\n- notifications use 16 px horizontal padding and a 12 px column gap because\n  icon, message, and action are distinct groups.\n\nDo not treat these as copy-and-paste recipes for every surface. They reveal the\nsystem: controls are tighter internally, rows optimize scanning, and\ncontainers spend more space at their boundary than between their contents.\n\n### Proportion and layer hierarchy\n\nStart with content requirements, then set proportions. Avoid arbitrary halves\nwhen one pane has a clearly different role.\n\n- A navigation sidebar should be wide enough for stable labels but visibly\n  subordinate to the work area. Give it a minimum, preferred, and maximum\n  width rather than a percentage alone.\n- In master–detail layouts, let the collection remain scannable and give the\n  detail pane the surplus. A roughly one-third/two-thirds starting point is\n  often useful, but content constraints are authoritative.\n- Inspectors and auxiliary sheets should not cover the primary object by\n  default. They should be resizable or dismissible when their content grows.\n- Dialog width comes from the decision: short confirmation, medium form, or a\n  dedicated window/page for complex work. Do not enlarge a dialog simply to\n  create whitespace.\n- Reserve the strongest elevation for the topmost decision layer. Within a\n  layer, use background and hairlines—not successively larger shadows—to show\n  hierarchy.\n\nDefine three size constraints for every major region: the minimum at which its\ntask still works, a comfortable default, and how it consumes surplus. Persist\nuser-controlled splits when they represent workflow preference, and clamp\nrestored values against the current window.\n\n### Alignment details\n\nAlignment is a structural system, not a final polish pass. Establish a small\nset of alignment spines for each surface: shared leading and trailing edges,\ntext baselines, center lines, and fixed functional lanes. Elements at the same\nlevel should attach to the same spine from top to bottom or leading to trailing,\neven when they are different component types.\n\n<img class=\"alignment-light\" src=\"/alignment-spines.svg?v=20260822-4\" alt=\"Alignment spines across a desktop surface\">\n<img class=\"alignment-dark\" src=\"/alignment-spines-dark.svg?v=20260822-4\" alt=\"Alignment spines across a desktop surface\">\n\nVertical red lines sit beside shared edges or control centers for content,\nstatus, time, and trailing actions. Horizontal lines sit beneath text baselines\nor pass through a row center to show bottom and vertical-center alignment. The\ncompact comparison isolates a one-rendered-pixel drift that must be corrected\nat its structural owner.\n\n- Give sibling regions a shared content inset. A heading, toolbar, list row,\n  empty state, and footer that describe the same level should not each invent a\n  slightly different leading edge.\n- Repeat column geometry through the whole region. Headers, rows, summaries,\n  loading states, and inline editors should reserve the same lanes for identity,\n  metadata, status, numbers, and actions.\n- Align related controls across rows and sections. Form labels, fields,\n  descriptions, and validation messages should reveal a stable vertical grid\n  when the page is scanned from top to bottom.\n- Keep horizontal bands coherent. Items sharing a toolbar, title bar, status\n  bar, or row should use one baseline or center line instead of individually\n  tuned offsets.\n- Introduce indentation only for real hierarchy, containment, or disclosure.\n  Decorative indentation makes siblings look subordinate and breaks the\n  surface's reading line.\n- When a nested level ends, return exactly to the parent spine. Do not let\n  accumulated padding drift across nested containers.\n- Preserve the spine through optional content. Missing icons, badges,\n  descriptions, or trailing actions must not move the remaining labels; use\n  intentional slots or lanes when cross-row comparison matters.\n- Align major regions with one another where their hierarchy matches. Sidebar\n  headers, content titles, split panes, toolbars, and bottom bars need not share\n  every coordinate, but coincident levels should form visible continuous lines.\n\nNot every edge should align. A child can indent, a primary value can lead its\nsupporting metadata, and a destructive decision can gain separation. Such\nexceptions must communicate hierarchy or meaning; they must not result from\nuncoordinated component padding. Start with the shared spine, then make the\nexception explicit.\n\nTreat exact alignment and repeated gaps as quality invariants. When two edges\nor spaces are intended to be equal, a one-rendered-pixel difference is a defect,\nnot an acceptable optical approximation. Inspect resolved bounds with a\nmeasurement tool at representative window sizes, zoom levels, and display scale\nfactors. Compare coordinates and distances; do not approve alignment only from\na casual screenshot.\n\nThe rendered-pixel tolerance is a verification rule, not permission to patch\nthe code with raw pixel offsets. Equal relationships should resolve from the\nsame `rem` helper, spacing token, grid definition, or shared component inset.\nFix the common owner when they differ. Account for fractional layout and device\nrounding so intended spines land on the same physical pixel instead of drifting\nat particular zoom levels.\n\n- Align text by baselines, not by bounding-box centers, when mixed sizes share\n  a row.\n- Center icons in a fixed slot so labels do not move when icons differ in\n  intrinsic width.\n- Right-align comparable numbers; left-align prose and identifiers unless the\n  locale requires otherwise.\n- Keep trailing row actions and disclosure indicators in fixed-width lanes.\n- Align form controls by their interactive frame, not by help text below them.\n- Use `justify_between` only when the two sides truly own opposite edges; it\n  should not disguise missing structure in the middle.\n- Hairlines belong on the boundary owner. Two adjacent regions must not each\n  draw the same separator.\n- A scrollbar belongs to the region that scrolls and sits against that panel,\n  editor, or window's trailing edge. Content padding may inset text and rows;\n  it must not pull the scrollbar into the middle of the surface. Reserve a\n  deliberate scrollbar gutter when content needs clearance.\n\n### Density tiers\n\nMedium is the ecosystem default. Change density for the whole local context,\nnot one isolated control:\n\n- **comfortable / large:** onboarding, sparse forms, prominent decisions;\n- **standard / medium:** most application chrome and workflows;\n- **compact / small:** toolbars, menus, tables, and repeated professional data;\n- **extra compact / xsmall:** exceptional high-density utilities, never the\n  automatic choice for an entire application.\n\nThe current controls demonstrate a bounded scale rather than arbitrary sizing:\nbuttons commonly move through approximately 20, 24, and 32 px frames; input\nand data controls may extend to about 44 px at large size; table rows use about\n26, 30, 32, and 40 px. Use the component's `Size` API so typography, icon,\npadding, and hit target change together. A custom height that changes only the\nouter box is usually incomplete.\n\n### Zoom, base font, and `rem`\n\nA well-designed `rem` system preserves hierarchy while the interface zooms.\nZoom is successful when the relationship between title and body, control and\nicon, inner and outer spacing, primary and secondary regions still feels the\nsame at every scale—not merely when every object becomes larger.\n\nGPUI Component adopts the relative-scale idea familiar from <a href=\"https://tailwindcss.com/docs/theme\" target=\"_blank\" rel=\"noopener noreferrer\">Tailwind CSS</a>. The\ntheme's base `font_size` becomes the window's `rem` through `Root`, and GPUI\nscale helpers such as `text_sm()`, `gap_2()`, `p_4()`, `h_8()`, and `size_4()`\nresolve against it. This gives typography, spacing, controls, and icons one\nshared zoom axis.\n\nDesign in ratios:\n\n- type steps keep the same hierarchy around the base body size;\n- spacing steps keep the same grouping relationships around the type;\n- control frames, icons, and hit targets scale with their labels;\n- pane minima and comfortable widths account for the scaled content;\n- corner radii and focus treatment remain optically consistent with the\n  control frame.\n\nDo not implement zoom by changing text size alone. A larger label inside a\nfixed-height button, a larger document inside fixed pane minima, or larger rows\ninside a stale virtual-list measurement destroys the original rhythm and can\nclip content. Conversely, multiplying every physical pixel—including\nhairlines—can make the interface visually heavy.\n\nAs a rule, application layout should not call `px(...)` directly. Use GPUI's\nrem-based scale helpers (`p_2`, `gap_3`, `w_64`, `text_sm`, and related\nbuilders) or semantic component sizes. Use fixed pixels only when the value\nrepresents a physical or raster boundary:\na one-device-pixel hairline, platform window inset, bitmap dimension, minimum\nhit-test tolerance, or geometry that must match an external surface. These are\naudited, documented exceptions. Product spacing, typography, icon size, and\nordinary control geometry stay on the relative scale.\n\nTest interface zoom at several base-font values, not just the default. Verify\nhierarchy, wrapping, truncation, minimum window size, pane resizing, focus-ring\nclearance, popup placement, and virtualized row measurement. Also distinguish\ninterface zoom from Dock's panel zoom: Dock zoom makes one container fill its\narea while retaining its chrome; it does not change `rem` or application scale.\n\n### Surfaces and elevation\n\nUse elevation to explain stacking, not importance. The base window surface is\nflat; separators and background contrast define its regions. Popovers, menus,\ndialogs, and notifications may use progressively stronger shadows because they\nsit above other content. Do not put a shadow on every card.\n\nAll surfaces of the same kind should share one treatment. GPUI Component, for\nexample, deliberately gives popup families one themed popover surface so\nPopover, Select, Combobox, DatePicker, and menus do not drift apart. When an\napplication invents another anchored surface, reuse that semantic treatment\ninstead of approximating it with unrelated border and shadow literals.\n\n### Typography and icons\n\nUse the platform UI font for interface text and monospace only for code,\nidentifiers, shortcuts, and aligned numeric data. Keep body text readable and\navoid excessive uppercase or letter spacing, especially for CJK text.\n\nUse one icon family in a product. Icons supplement labels; they should not\nreplace unfamiliar actions with guesswork. Icon-only buttons always need an\naccessible name. Their visual explanation follows the tooltip policy below.\nUse filled or colored icons to communicate a state, not merely to make a\ntoolbar lively.\n\n## Layout patterns\n\n### Choose a stable shell\n\nMost applications should use one of these shells:\n\n- **single workspace:** toolbar or title bar above one primary view;\n- **sidebar workspace:** persistent navigation beside a changing detail view;\n- **master–detail:** resizable collection and detail panes;\n- **document workspace:** tabs or a dock area for multiple long-lived objects;\n- **utility window:** one focused task with a short, fixed action path.\n\nKeep global navigation stable while content changes. Give the primary work area\nthe remaining space with `flex_1()` and `min_w_0()` / `min_h_0()` where\noverflowing children must shrink. Use `Scrollable`, `VirtualList`, `Table`, or\n`DockArea` for their intended behavior instead of rebuilding scrolling or pane\nmanagement from nested `div`s.\n\nThe title bar is window chrome first. Preserve its drag region and avoid\nbinding ordinary title clicks to infrequent editing commands. Rename belongs\nbehind an explicit object command, with a keyboard path where appropriate.\n\n### Responsive desktop windows\n\nDesktop does not mean fixed-size. Decide what happens as a window narrows:\n\n1. preserve the primary task;\n2. allow resizable regions to reach a documented minimum;\n3. collapse secondary labels or inspectors;\n4. move low-frequency actions into a menu;\n5. scroll only the region whose content actually overflows.\n\nDo not hide an action without providing another path to it. Avoid making the\nentire window scroll when only a list or document body should scroll.\n\nGPUI flex layouts have the same intrinsic-size pressure found in other layout\nsystems: a `flex_1()` child may still refuse to shrink around long content.\nDesign and implementation must agree on which panes may shrink, truncate, wrap,\nor scroll. A clipped region also clips an outward focus ring; never trade away\nkeyboard visibility merely to simplify overflow.\n\n### Forms and settings\n\nUse a visible label for each field and place help or validation next to the\nfield it describes. Align related fields, but do not force long labels into a\nnarrow fixed column. Use the appropriate control: `Checkbox` for independent\nchoices, `RadioGroup` for a small visible set, `Select` for a longer set, and\n`Switch` for a setting that takes effect immediately.\n\nDisable submission while an operation is in flight, keep the user's input, and\nshow the result near the action. Reserve dialogs for short, focused decisions;\nuse a full page or sheet for workflows that need exploration or many fields.\n\nA loading treatment must represent actual waiting. Switching between settings\npanels whose content is already available should be immediate; a skeleton is\nappropriate only while content is genuinely loading and its shape is known.\n\n## Components and composition\n\nFollow the Shadcn principle that components are building material rather than a\nsealed design system. GPUI Component supplies coherent defaults, while the\napplication owns composition and product semantics.\n\n- Use component variants by meaning. Primary is reserved for the explicit\n  default commit in a decision area—normally the action invoked by Enter. A\n  lone, frequent, or desirable action is not automatically primary. An `Add`\n  command in a management toolbar normally uses a default Button; a form's\n  default `Create` commit may use primary. Use `danger` for destructive\n  commitment and `ghost` for quiet toolbar actions.\n- Prefer explicit compound parts and render callbacks over styling arbitrary\n  descendants.\n- Keep a repeated pattern consistent across the product. Wrap it in an\n  application component when it carries domain language or policy.\n- Use the standard component for its semantic role. A menu, dropdown menu,\n  popover, select, and command palette are not interchangeable boxes; each owns\n  different selection, focus, keyboard, dismissal, and layout contracts.\n- Preserve the component family's geometry. Menu rows share vertical and\n  horizontal padding, height, icon and checkmark slots, separators, radius, and\n  state treatment. Do not imitate one menu with a custom popup whose spacing\n  only approximates the system.\n- Do not wrap a library component merely to rename every method or freeze all\n  of its capabilities.\n- Move reusable behavior without product styling to `gpui-base`; keep themed,\n  opinionated presentation in GPUI Component or the application.\n\n## Interaction states\n\n### Make the result understandable before the click\n\nA control should predict its result. Use familiar desktop controls and\nplacement so people can act without learning the interface first. Its label\nnames the action and object, its state shows availability, and its feedback\nconfirms the same outcome.\n\nDo not label a Button `Save` if it opens a configuration flow, or `Delete` if\nit only removes an item from a group. Name the scope when context does not make\nit clear. Respond immediately to activation, prevent duplicate submission\nduring longer work, and show the result near the object that changed. Add a\nsuccess message only when the result itself is not visible.\n\nEvery interactive control should be designed for:\n\n| State | Design requirement |\n| --- | --- |\n| Rest | Clear affordance without visual noise |\n| Hover | Subtle pointer feedback, never the only cue |\n| Pressed | Immediate press feedback |\n| Open / pressed | Persistent feedback while an attached popup is open |\n| Focus visible | High-contrast keyboard focus ring |\n| Selected / checked | Persistent state distinct from hover |\n| Disabled | Lower emphasis and no misleading hover/pressed response |\n| Loading | Preserve context, prevent duplicate action, explain long waits |\n| Error | State what happened and how to recover |\n\nUse GPUI's focus system and Actions for commands that should work from the\nkeyboard. Match familiar desktop shortcuts, expose shortcuts in menus or\ntooltips, and keep focus in a logical place after opening or dismissing an\noverlay.\n\nSelection is part of the information model, not optional polish. Tabs,\nsegmented choices, selectable rows, filters, and navigation destinations must\nshow a persistent selected state. A Button that owns a dropdown must remain\nvisibly pressed or open until the popup closes; hover alone cannot explain the\nrelationship between trigger and surface.\n\nIn a segmented control, the selected fill and unselected surface must share\nthe container's silhouette. Neither may square off an end corner or make a\nboundary appear heavier than its peers.\n\nShow a selected navigation item, list row, or tab through the item's own\nsurface: a selected fill, stronger foreground, or heavier weight. Do not add a\nleading-edge bar or one-sided border as the selection marker. It is a web\ntemplate habit, not a desktop convention; it breaks the item's rounded\nsilhouette and adds a second, competing edge to a column that already aligns\non its text.\n\nFor destructive actions, distinguish between reversible and irreversible work.\nPrefer undo or a temporary notification for reversible changes. Use an\n`AlertDialog` when the consequence is serious and cannot be undone; name the\nspecific object and consequence in the confirmation copy.\n\n### Pointer conventions\n\nUse the default arrow cursor for buttons, checkboxes, menu items, tabs, and\nother native controls. Use a pointing hand for links and content that behaves\nas a link. Use text, resize, grab, and prohibited cursors only when they\ndescribe the active manipulation. A cursor reinforces an affordance; it does\nnot replace the control's visible state or accessible role.\n\nKeep hover effects modest because keyboard and accessibility interaction has no\nhover. Do not reveal the only copy of a destructive or essential action on\nhover. Contextual row actions may become quieter at rest if the same commands\nremain available through selection, keyboard, or a context menu.\n\n### Prefer desktop command surfaces over hover toolbars\n\nUse command frequency and scope to choose where an action lives:\n\n- keep the primary or frequent action visible as a labeled Button or familiar\n  toolbar control;\n- put secondary actions for the current region behind a visible\n  `DropdownMenu` trigger;\n- put commands that act on the object under the pointer in a `ContextMenu`;\n- expose the same important command through an [Action](./action)/[key binding](./keybinding) when it has a\n  natural keyboard form;\n- use a hover-revealed icon only as a shortcut to a command that remains\n  reachable elsewhere.\n\nThis is more than a visual preference. GPUI Component's menu system already\nowns directional keyboard navigation, confirmation and cancellation, disabled\nitems, separators, submenus, shortcut presentation, focus transfer and\nrestoration, and nested-menu dismissal. A custom strip of hover buttons must\nrebuild those behaviors and is invisible to keyboard-only and many assistive\ntechnology workflows.\n\nChoose `DropdownMenu` when users need a visible indication that more commands\nexist—for example a toolbar overflow, document actions, or account menu. Choose\n`ContextMenu` for selection- or object-scoped commands such as rename,\nduplicate, reveal, or remove. The context menu must not be the only way to\nperform an essential command; provide a menu-bar, toolbar, keyboard, or detail\nview path as appropriate.\n\nDo not put every action into a menu to make a screen look minimal. Discovery\nand speed matter: the main action stays visible, dangerous items remain clearly\nlabeled and separated, and a menu item should use the same verb, icon, shortcut,\nenabled state, and result everywhere it appears.\n\n### Button means application action; Link means external resource\n\nUse a Button when activation changes application state, confirms a decision,\nopens a tool, submits data, or runs a command. Choose its treatment by local\nhierarchy:\n\n- primary Button for the one emphasized commitment in a decision area;\n- default Button for ordinary visible actions;\n- outline Button when an action needs a clear boundary with less emphasis;\n- ghost Button for familiar, low-emphasis toolbar and inline actions;\n- icon Button only for a well-known symbol, with an accessible name and a\n  tooltip when meaning or scope is unclear.\n\nDo not assign primary because a Button is the only action on screen, because it\nis placed at the top right, or because the team wants more clicks. Primary\ncommunicates default commitment and keyboard behavior. If activation is merely\nan ordinary command such as adding an item, opening a tool, or refreshing a\nview, use a default, outline, or ghost Button according to its local hierarchy.\n\nUse an underlined Link only for an external resource target: a URL, web page,\nonline documentation, or email address. It uses the pointing-hand cursor\nbecause its contract is leaving the current application context for that\nresource. Do not use Link styling to make a functional command look quiet. A\nlink-shaped Delete, Save, Refresh, Add, Open-menu, or in-app navigation action\nhides the control's affordance and exposes the wrong accessibility role.\n\n“View” does not make an in-app destination a Link. A full report, analysis,\ndetails panel, or local record still opens through a Button, row, card, tab, or\ndisclosure control. Use concise context-aware labels such as `Full analysis`\nwhen the containing card already establishes what opens; reserve underlining\nfor a resource that actually opens in a browser or mail client.\n\nAll internal navigation—sidebar rows, tabs, breadcrumbs, list items, opening a\nlocal view, or switching workspaces—must use the corresponding native component\nor a Button/Action. Visual emphasis is chosen through Button variant or the\nnavigation component's selected state, never by lying about semantics.\n\n## Feedback and overlays\n\nChoose the smallest surface that fits the decision:\n\n- tooltip: a short explanation or shortcut;\n- popover: contextual controls that do not interrupt the task;\n- menu: a compact list of actions;\n- notification: asynchronous status that does not require a decision;\n- dialog: a focused decision or short form;\n- alert dialog: explicit confirmation of a consequential action;\n- sheet: supplementary work that benefits from more persistent space.\n\nA tooltip supplies missing meaning; it does not restate an obvious action.\nReserve it for an unfamiliar symbol, ambiguous scope, or a useful shortcut\nthat is otherwise hidden. Repeated, recognizable commands such as Copy and\nDownload in a message footer need accessible names and keyboard access, but\ntheir hover labels add interruption rather than clarity.\n\nAn Alert interrupts the visual hierarchy even when it does not open a modal.\nUse it for important, exceptional information that needs attention in the\ncurrent task, not as a decorated container for ordinary descriptions, tips, or\nempty space. Prefer inline help, muted text, or a normal section when the\ncontent does not require immediate notice or action.\n\nAvoid stacking overlays. Escape should dismiss the topmost dismissible layer,\nand focus should return to the trigger or the next logical target.\n\nAn overlay action must refer to an object or state the overlay actually shows.\nFor example, expose `Clear history` only when a distinct recent-history section\nis visible and contains entries. Search results, recent items, and favorites\nare different collections; label and separate them instead of merging them\ninto one unexplained list. Hide an inapplicable action or disable it with a\nuseful reason—do not park an ambiguous trash icon in a footer.\n\nFooter space is not a catch-all for capabilities that lacked a place in the\ndesign. A footer may present shortcuts, status, or actions that apply to the\nwhole surface, but each item must answer: what is its object, why is it\navailable now, what scope does it affect, and what visible state changes after\nactivation?\n\n## Motion\n\nMotion explains change; it is not ambient decoration. Use short transitions for\nappearance, dismissal, expansion, and spatial continuity. Avoid animating large\nlayout changes when opacity or transform communicates the same relationship.\nHonor reduced-motion preferences, never require animation to understand state,\nand do not add a default animation to every component.\n\nMotion policy belongs to the styled or application layer. Base may own the\nlifecycle mechanism or geometry needed for a transition, but it should not\ndecide that every product fades or slides. Give independently animated values\nstable identity, and make interruption reverse smoothly from the currently\nsampled value rather than restarting from an old endpoint.\n\nMotion follows the continuity of the interaction. While a pointer or scroll\nposition moves among related targets, keep the preview surface stable and\nupdate its content or position in place. Dismiss it only after the interaction\nends; repeated fade-out and re-entry on each update reads as flicker.\n\n## Designing data-heavy interfaces\n\nDense does not mean cramped. In tables, trees, command palettes, editors, and\ndocks:\n\n- keep headers and primary row identity visually stable;\n- align comparable values and use tabular numerals where appropriate;\n- distinguish focus, hover, active row, and multi-selection;\n- keep sorting and filtering visible and reversible;\n- preserve selection by domain identity across filtering and reordering;\n- virtualize large collections without changing keyboard semantics;\n- use progressive disclosure for secondary columns and inspectors;\n- provide a useful empty state that explains the next action.\n\nChoose a table for comparison across consistent fields, a list for scanning\nheterogeneous items, a tree for real hierarchy, and a dock only when users need\nto arrange long-lived tools or documents. Do not use a complex data component\nas a visual style.\n\n## Interface language\n\nWords are part of the interface architecture. Write the vocabulary for a\nfeature as a system—destinations, objects, commands, states, and outcomes—not as\nisolated translations of implementation features. Prefer the shortest wording\nthat remains accurate in its actual context.\n\n### Let context carry context\n\nDo not repeat information that the surrounding surface already establishes. A\nsidebar destination is usually the object or domain itself: use `Users`, not\n`User Management`; `Shortcuts`, not `Shortcut Configuration Management`. A\ncolumn whose rows already contain actions can omit a generic `Operation`\nheading. A dialog titled `Delete “Roadmap”?` does not need body text that asks\nthe same question again.\n\nThis is context economy, not deletion for its own sake. Add text when it changes\nthe decision: identify the affected scope, an irreversible consequence, an\nunusual prerequisite, or a way to recover. Every extra word should answer a\nquestion the current layout does not already answer.\n\nUse nouns for destinations and objects (`Users`, `Appearance`, `Orders`), verbs\nfor commands (`Save`, `Duplicate`, `Export`), and adjectives or short phrases\nfor states (`Offline`, `Up to date`, `Pending review`). Avoid wrappers such as\n`Management`, `Module`, `Page`, `Function`, `Operation`, and `System` unless the\nword distinguishes a real domain concept.\n\n### Write each language, do not translate its shape\n\nStart from shared intent, hierarchy, and terminology, then compose each locale\nas natural interface language. Do not preserve the source language's word\norder, number of words, politeness filler, or grammatical category. English\n`Users` can express a Chinese feature concept that would literally expand to\n“user management”; fidelity means preserving purpose, not preserving tokens.\n\nRemove words supplied by the enclosing information architecture. Inside a\n`Settings` surface, a destination is often simply `Account`, not `Account\nSettings` and never the unnatural singular `Account Setting`. The correct\nEnglish label is chosen from its role and neighbors, not from the standalone\nsource phrase.\n\nMaintain a small product lexicon for recurring objects, commands, and states.\nUse the same term in the toolbar, menu, context menu, dialog, shortcut search,\nand documentation unless the context genuinely changes its meaning. Review\ncopy in the rendered surface: neighboring labels often reveal repetition or\ninconsistent scope that a locale file cannot.\n\nIn localized technical writing, preserve an established framework term when a\ntranslation would be less precise. Keep API identifiers in their original form\nand format them as code. Do not retain ordinary foreign words merely to sound\ntechnical. Explain a retained term on first use when needed, then use the same\nform throughout the interface, documentation, and API examples.\n\nIn documentation, use the exact English name for a named API, component,\nsource file, or guide in link text, including localized pages. For example,\nwrite `Font`, `Render`, `Input element`, and `Plot label` rather than translating\ntheir names or adding a redundant `GPUI Kit` prefix. Keep surrounding explanations in the\npage's language. Link only the named target; place words such as “source”\noutside the link when they describe why it is cited.\n\nIn a technical comparison table shared across locales, keep capability names,\nframework names, API names, and model names in their established English form.\nTranslate the explanation around the table, not its technical labels. Common\ninterface words with an established local name may still be localized outside\nthat comparison context.\n\n### Buttons and confirmation dialogs\n\nButton labels are short by default—usually one or two words—and describe the\nresult, not the gesture or the component. Prefer `Save`, `Move`, or `Delete` to\n`Click to save`, `Perform move`, or `Confirm deletion`. Use `Cancel` consistently\nfor the action that leaves without committing. Reserve `OK` for acknowledging\npurely informational content.\n\nShort is a default, not a character limit. A deliberately longer label is\nbetter when its words expose a consequence or distinguish choices that users\ncould otherwise confuse, for example `Delete from this group` versus `Delete\neverywhere`, or `Restart without saving`. Length must buy decision-critical\ninformation; it must not restate the dialog title or body.\n\nUse the most specific concise result as the confirmation label when possible:\n\n| Context | Weak | Prefer |\n| --- | --- | --- |\n| Delete dialog | `Yes`, `Sure`, `Confirm deletion` | `Delete` |\n| Unsaved changes | `Confirm`, `Yes` | `Discard changes` |\n| Pure acknowledgement | `Confirm operation` | `OK` or `Done` |\n| Complex consent whose result has no clear verb | `Yes` | `Confirm` |\n\n`Confirm` is a useful fallback when the surrounding dialog fully names a\ncomplex commitment and no shorter result verb is accurate. It should not\nreplace a clear command. `Sure` is conversational rather than a stable English\ncommand and is too ambiguous for the standard vocabulary.\n\nA confirmation dialog should form one compact decision:\n\n- title: the decision or condition, such as `Delete “Roadmap”?`;\n- body: only new scope, consequence, or recovery information;\n- actions: `Cancel` and the result, such as `Delete`;\n- destructive styling: applied to the destructive result, not substituted for\n  precise wording.\n\nAvoid generic titles such as `Notice`, `Warning`, `Error`, and `Confirmation`\nwhen the actual condition can be named. Avoid ritual phrases such as “Are you\nsure you want to…”, “Would you like to…”, “Please note that…”, and “successfully”\nwhen the structure or state already communicates them. Courtesy should come\nfrom a calm, respectful tone, not repeated `please`.\n\n### Capitalization, punctuation, and symbols\n\nUse sentence case for English UI by default: `Reset layout`, not `Reset Layout`\nor `RESET LAYOUT`. Preserve proper nouns and established acronyms. Follow a\nplatform convention such as title case for native menu commands only when the\nplatform integration benefits from it, and apply that convention consistently\nwithin the component class.\n\nALL CAPS can provide restrained typographic emphasis for very short section\nlabels, eyebrows, statuses, established acronyms, and code-like identifiers.\nIts compact shape and measured tracking can form a level similar to bold type,\nbut it does not belong on Buttons, long headings, sentences, or dense lists. Do\nnot combine uppercase, strong color, and bold weight in the same region, and do\nnot transform every string automatically: product names, acronyms, and localized\ncontent must preserve their intended casing.\n\nLabels, buttons, menu items, tabs, headings, placeholders, and short states do\nnot take a final period. Complete explanatory, warning, and error sentences do.\nAvoid exclamation marks in routine success and failure messages. In Chinese,\nuse full-width punctuation in sentences and omit terminal punctuation from\nshort control labels by the same semantic rule.\n\nUse the single ellipsis character (`…`), not three periods. Append it to every\nButton or MenuItem that opens a dialog, sheet, or separate window, and to a\ncommand that requires more input or choices before it can complete, such as\n`Settings…` or `Export…`. An immediately executed command does not take an\nellipsis. Use an indeterminate progress indicator, not decorative dots, to\ncommunicate ongoing work.\n\nErrors should say what happened and, when useful, the next recovery action.\nSuccess feedback should name the resulting state only when that state is not\nalready visible. Prefer `Couldn’t save. Check your connection and try again.`\nto a technical code or a long apology; omit a `Saved successfully` toast when\nthe document visibly becomes saved.\n\n## Internationalization and platform fit\n\nAccessibility (A11y) names and labels may remain in English; localization is\nnot required for these strings. Keep the item's own label when naming a control\nthat acts on it, even when that label is localized. This exception does not\napply to visible UI copy.\n\nCopy must survive expansion, CJK typography, and different shortcut notation.\nDo not size a control from one English label. Keep text out of raster assets,\navoid concatenating translated fragments, and let labels wrap or truncate only\nwhere the product defines a recovery path such as a tooltip.\n\nRespect platform differences that carry meaning: Command versus Control,\nnative window decorations, system appearance, scrollbar behavior, menus, and\nnotification capabilities. Keep the product's information architecture stable\nacross platforms, but do not erase familiar platform behavior for superficial\npixel equality.\n\n## Guidance for AI-generated interfaces\n\nAn AI changing a GPUI interface should first inspect the nearest feature,\ntheme tokens, and component documentation. It should state the primary task,\nstate owner, component composition, and keyboard path before generating code.\nIt must not infer an API from React/Shadcn examples or invent a GPUI method\nbecause the name seems plausible.\n\nAI output is incomplete until a human can explain why the hierarchy, density,\ncomponent choice, and exceptional literal values belong in this product. A\nvisually plausible screenshot is not proof: keyboard behavior, focus, dynamic\ncontent, themes, resizing, and failure states are part of the design.\n\n## Accessibility checklist\n\nBefore considering a screen complete, verify that:\n\n- every action is reachable and operable by keyboard;\n- focus or\n\n<!-- [TRUNCATED AT 50KB] -->\n\n<!-- File: skills/gpui-kit-design-guides/SKILL.md (Tokens: ~835 | Category: anthropic-skill) -->\n---\nname: gpui-kit-design-guides\ndescription: The normative Design Guides for GPUI Kit desktop applications. Read in full before designing or changing any screen, layout, spacing, visual hierarchy, color, density, component choice, interaction state, overlay, motion, data-heavy view, or interface copy in a GPUI Kit (gpui-kit / gpui-component) application, and before reviewing UI work for design quality. Also use when asked what the design rules are, or whether a UI decision follows them.\n---\n\n# GPUI Kit Design Guides\n\nThe guide is [references/design-guides.md](references/design-guides.md). It is\na requirement, not inspiration. Read the guide file itself before doing UI\nwork. Do not answer from this page, from an existing screen in the codebase, or\nfrom training data.\n\nIf the file is missing, fetch `https://gpui-kit.com/docs/design-guides.md`.\nThe guide is a verbatim copy of that page, so its link to `./coding-guides.md`\nmeans the Coding Guides in the `gpui-kit` skill (or `https://gpui-kit.com/docs/coding-guides.md`).\n\n## How to read it\n\nRead the whole guide for a new screen or a redesign. For a narrow change, read\n\"Design thesis\" and \"Start from the task\" first, then the section for the\nchange. Sections, in order (`grep -n '^## ' references/design-guides.md`):\n\n| Section                              | Read when                                                              |\n| ------------------------------------ | ---------------------------------------------------------------------- |\n| Design thesis                        | Always                                                                 |\n| Learning from Shadcn                 | Choosing what to borrow from web component libraries                   |\n| Start from the task                  | Always; task hierarchy, interaction promise, what to leave out         |\n| Visual language                      | Color, typography, spacing, radius, borders, elevation, density, icons |\n| Layout patterns                      | Window structure, sidebars, toolbars, panels, forms, resizable regions |\n| Components and composition           | Picking a component, composing parts, when to build a new one          |\n| Interaction states                   | Hover, focus, pressed, selected, disabled, loading, validation, danger |\n| Feedback and overlays                | Dialog, sheet, popover, menu, notification, tooltip, dismissal, focus  |\n| Motion                               | Any animation or transition                                            |\n| Designing data-heavy interfaces      | Tables, lists, trees, dashboards, dense inspectors                     |\n| Interface language                   | Any user-facing text: labels, buttons, titles, errors, empty states    |\n| Internationalization and platform fit | Multi-locale copy, Chinese terminology, macOS/Windows conventions     |\n| Guidance for AI-generated interfaces | Always when an agent produces UI                                       |\n| Accessibility checklist              | Before finishing                                                       |\n| Design review checklist              | Before finishing; run every item against the work                     |\n\n## Non-negotiables\n\nA floor, not a substitute for the guide.\n\n- **Desktop before web convention.** Keyboard access, window chrome, menus,\n  dense data views, resizable regions, persistent navigation.\n- **`Button` vs `Link`.** `Button` for every in-app command, `ghost` or\n  `outline` when it should read quietly. `Link` only for external URLs and\n  email addresses.\n- **Tokens before values.** No raw hex or `rgb(...)`; use `cx.theme()`\n  semantic tokens and rem-based helpers. Any spacing number quoted in the guide\n  is the current default scale, not a literal to repeat.\n- **State must be visible.** Hover, focus, selection, disabled, loading,\n  validation, and destructive states each need distinct, consistent treatment.\n- **Overlays.** Escape dismisses the topmost surface and returns focus to its\n  trigger.\n- **Copy.** Name the object and the verb: `Delete \"Roadmap\"?` with a `Delete`\n  button, not `Are you sure?` with `OK`.\n\nFinish by running the Design review checklist against the work.\n\n<!-- File: skills/gpui-kit/references/coding-guides.md (Tokens: ~9325 | Category: anthropic-skill) -->\n---\ntitle: Coding Guides\ndescription: Architecture and coding conventions for maintainable GPUI Kit applications\norder: -13\n---\n\n# Coding Guides\n\nThis guide describes the application architecture and code patterns that have\nproved durable in GPUI Kit. It is written for both engineers and coding\nagents. Read [Design Guides](./design-guides.md) first: code structure should\npreserve product intent, not replace it.\n\nThis is a normative guide. **Must** marks lifecycle, correctness, or ecosystem\nconstraints; **should** is the default architecture and requires a concrete\nreason to depart from it. Current source and API docs remain authoritative for\nexact signatures.\n\n## Architecture at a glance\n\n<img class=\"architecture-light\" src=\"/application-layers-light.svg?v=20260822-16\" alt=\"GPUI application architecture layers\">\n<img class=\"architecture-dark\" src=\"/application-layers-dark.svg?v=20260822-16\" alt=\"GPUI application architecture layers\">\n\nDependencies point downward. Higher layers own domain meaning and orchestration;\nlower layers own reusable presentation or behavior. Do not make a reusable\ncomponent depend on an application screen, or make `gpui-base` depend on a\ntheme from GPUI Component.\n\nUse these boundaries:\n\n- **app shell:** compose windows and feature crates while keeping feature logic out;\n- **feature crate:** keep one capability's model, services, views, commands, dialogs,\n  and workflow behind one public boundary;\n- **app component:** a repeated domain-aware pattern;\n- **gpui-component:** themed, general-purpose UI;\n- **gpui-base:** reusable behavior and geometry without product presentation.\n\n### Organize large applications by capability\n\nIn a large Rust application, a feature should usually be a crate, not another\nfile in a global `views`, `models`, or `modals` directory. Keep the model,\nviews, commands, dialogs, and workflow for one capability together. A dialog\nthat edits a workspace belongs to the workspace feature; only the reusable\ndialog primitive belongs to the UI library.\n\n```text\ncrates/\n├── app/\n│   └── src/main.rs             # Compose windows and features\n├── workspace/\n│   └── src/\n│       ├── lib.rs              # The feature's public boundary\n│       ├── model.rs\n│       ├── commands.rs\n│       ├── workspace_view.rs\n│       └── rename_dialog.rs\n├── search/\n│   └── src/\n│       ├── lib.rs\n│       ├── model.rs\n│       ├── commands.rs\n│       ├── search_view.rs\n│       └── filters.rs\n├── settings/\n│   └── src/\n│       ├── lib.rs\n│       ├── model.rs\n│       ├── settings_view.rs\n│       └── account_dialog.rs\n└── shared/\n    └── src/\n        ├── lib.rs\n        └── recent_items.rs     # A stable capability with multiple owners\n```\n\nDo not invert this into global `models/`, `views/`, `modals/`, and `commands/`\ndirectories. Those folders classify files by implementation role while\nscattering every feature across the application.\n\nThe application shell composes feature crates but contains little feature\nlogic. A feature may depend on stable shared capabilities and UI foundations;\nit must not depend on the shell or reach into a sibling feature's internals.\nWhen two features need to communicate, prefer an explicit command, event, data\ntype, or small shared service over a dependency between their views. Extract a\nshared crate only after the capability has a coherent name and more than one\nreal owner.\n\nCrate boundaries are engineering boundaries. They let Cargo rebuild and test a\nsmaller dependency subgraph, make ownership visible in `Cargo.toml`, and limit\nthe review and regression surface of a change. They also make removal honest:\na feature that cannot be detached without searching through global view and\nmodal directories was never isolated.\n\nDo not create a crate for every screen or helper. Split where a capability has\nits own state and lifecycle, a stable public seam, or enough implementation to\nbenefit from independent compilation and tests. Keep dependencies acyclic and\npointing toward smaller, more stable crates.\n\n## Bootstrap and root ownership\n\nInitialize GPUI Component once, before creating component-backed views, and put\n`Root` at the first level of each window:\n\n```rust\napp.run(move |cx| {\n    gpui_kit::init(cx);\n\n    gpui_kit::open_window(WindowOptions::default(), cx, |window, cx| {\n        cx.new(|cx| Workspace::new(window, cx))\n    })\n    .expect(\"failed to open window\");\n});\n```\n\n`Root` coordinates window-level component facilities such as overlays and\nnotifications. Do not create a separate root for each page inside one window.\nIt also coordinates modal focus restoration, focus traps, tooltip/menu layers,\nand window-scoped text selection. Bypassing it can produce behavior that looks\ncorrect at rest but fails when overlays nest or focus changes quickly.\n\n## Understand GPUI's phases and contexts\n\nGPUI is retained state with declarative rendering. An entity survives across\nframes; the element tree returned by `render` is a fresh description of the\ncurrent frame. Keep that distinction explicit.\n\n- `Context<Self>` mutates the current entity, creates listeners tied to it,\n  emits its events, and notifies its observers.\n- `App` gives access to application globals and entity reads/updates without\n  implying ownership by the rendered element.\n- `Window` owns focus, actions, input dispatch, element-keyed state,\n  measurement, and animation-frame requests for that window.\n- layout, prepaint, and paint are later phases; use their hooks only when\n  resolved geometry is genuinely required.\n\nNever retain `&mut Window`, `&mut App`, or `&mut Context<_>` beyond the call in\nwhich it is provided. Retain typed handles—`Entity`, `WeakEntity`,\n`FocusHandle`, scroll handles, or domain IDs—instead.\n\n## Choose the right unit\n\n### Use `RenderOnce` for value-like elements\n\nUse a `RenderOnce`/`IntoElement` component when all inputs can be supplied by\nthe caller and the element does not need to retain application state between\nframes. This is the normal choice for presentational wrappers and small\ncontrols.\n\n```rust\n#[derive(IntoElement)]\nstruct EmptyState {\n    title: SharedString,\n}\n\nimpl RenderOnce for EmptyState {\n    fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {\n        div()\n            .v_flex()\n            .gap_2()\n            .items_center()\n            .text_color(cx.theme().muted_foreground)\n            .child(self.title)\n    }\n}\n```\n\n### Use `Entity<T>` for retained behavior\n\nUse an entity-backed `Render` view when behavior spans frames or needs\nobservation, subscriptions, focus, async work, history, measurement, or\nincremental updates. Store entities in an owning view rather than recreating\nthem in `render`.\n\n```rust\nstruct SearchView {\n    query: Entity<InputState>,\n}\n\nimpl SearchView {\n    fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let query = cx.new(|cx| InputState::new(window, cx).placeholder(\"Search…\"));\n        Self { query }\n    }\n}\n```\n\nDo not turn every visual fragment into an entity. Entity boundaries have\nlifecycle and coordination costs; use them where retained identity matters.\n\n### Elements, views, and behavior systems are different\n\nDo not force every component into one template. The ecosystem contains:\n\n- semantic elements such as Button, Checkbox, Link, and Tabs;\n- compound behavior roots such as Dialog, Popover, Select, and Combobox;\n- entity-backed systems such as Input, Table, Tree, Dock, and notifications;\n- infrastructure such as positioning, virtualization, scrolling, focus traps,\n  motion, history, and measurement.\n\nAn element may be internally complex and still be value-like to its caller. A\nstateful system may expose render callbacks so applications own presentation\nwithout reimplementing behavior. Choose the public seam from the behavior,\nnot from how many `div`s appear in its renderer.\n\n## State ownership\n\nPut each state in the narrowest owner that can keep it correct:\n\n- domain state belongs to a model or feature view;\n- transient view state belongs to the view that renders it;\n- reusable behavioral state belongs to the component state designed for it;\n- tiny element-local state may use GPUI keyed element state;\n- shared application services may be stored as GPUI globals.\n\nPrefer controlled values for ordinary selection and toggles: pass the current\nvalue into the component, receive a requested change, update the owner, and\nrender again. A callback reports intent; it should not create a second hidden\nsource of truth.\n\n```rust\nCheckbox::new(\"show-hidden\")\n    .checked(self.show_hidden)\n    .label(\"Show hidden files\")\n    .on_click(cx.listener(|this, checked, _, cx| {\n        this.show_hidden = *checked;\n        cx.notify();\n    }))\n```\n\nCall `cx.notify()` after a mutation that changes rendering. Use `cx.emit(...)`\nfor a semantic event that an owner should handle, and `cx.subscribe(...)` or\n`cx.observe(...)` when the lifetime should follow an entity. Keep returned\nsubscriptions alive when the API requires it.\n\nDo not notify merely because a value was read or derived. Avoid unconditional\nnotification from `render`; it schedules another render and can create a\npermanent redraw loop. When several fields form one invariant, update them\ntogether and notify once. A reusable state type that cannot receive a context\nshould make that limitation explicit and require its owner to emit/notify.\n\n### Avoid state feedback loops\n\nText input, selection, filters, and controlled popups commonly have two paths:\nan external owner updates the value, and user interaction requests a new value.\nDo not send an owner-supplied value back through the user callback during sync.\nTrack the origin or compare coherent snapshots so each logical change is\nreported once. Make callbacks re-entrancy-safe when a callback can synchronously\nclose, replace, or update the component that invoked it.\n\n## Stable identity\n\nAn `ElementId` is part of behavior. It gives an element stable identity and keys\nelement-local or component state. A component may also use it as one input to\nits own focus, measurement, or animation identity; focus and scrolling are\notherwise owned by their dedicated handles.\n\n- Use stable domain IDs for rows, tabs, tree nodes, and repeated controls.\n- Namespace child IDs with their owning object when the same control repeats.\n- Never derive identity from a translated label or a mutable list index when\n  items can be inserted or reordered.\n- Do not generate a fresh random ID during `render`.\n\n```rust\nButton::new((\"delete-project\", project.id))\n    .danger()\n    .label(\"Delete\")\n```\n\nA changed ID means a changed UI identity. Treat that reset as deliberate.\n\nThe same rule applies to transition channels, overlay tokens, scroll handles,\nand persistence IDs. If two independently retained behaviors share a key, they\ncan overwrite each other's state; if one behavior changes keys every frame, it\nnever accumulates state.\n\n## Rendering and composition\n\nKeep `render` declarative: read current state, derive presentation values, and\ncompose elements. Move domain operations, parsing, and non-trivial mutation to\nnamed methods or services.\n\n```rust\nimpl Render for ProjectView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .v_flex()\n            .size_full()\n            .child(self.render_toolbar(cx))\n            .child(self.render_content(cx))\n    }\n}\n```\n\nExtract a render helper when it names a meaningful region and reduces the\namount of state a reader must hold at once. Extract a new component when the\nregion has its own reusable contract or retained lifecycle—not merely because\na builder chain is long.\n\nUse GPUI Component's fluent traits consistently (`Sizable`, `Disableable`,\n`Selectable`, and component-specific builders). Prefer `.when(...)` and\n`.when_some(...)` for small conditional refinements; use ordinary Rust control\nflow when branches represent substantially different interfaces.\n\nCompose from the standard semantic component before building a custom surface.\nDo not reproduce a menu, select, dropdown, or command palette from generic\n`div`s merely to match one screenshot. Reusing the component preserves its\nitem geometry, focus transfer, keyboard navigation, selection, disabled state,\ndismissal, and accessibility contract. If the standard component cannot\nexpress a recurring valid pattern, improve its explicit API instead of styling\narbitrary descendants at each call site.\n\nRender callbacks supplied by application code should be side-effect-free. A\nlist item renderer, menu builder, or dock panel renderer may run whenever its\nowner needs to measure or redraw. It must not perform a business operation,\nappend data, or register an unbounded subscription.\n\n## Behavior and presentation boundary\n\nThe durable Base rule is:\n\n> Base owns reusable behavior and the geometry required to implement it. The\n> presentation layer owns the product's visual language.\n\n“Headless” does not mean “one empty `div`.” Popup collision, keyboard\nnavigation, editing, virtualization, resize arithmetic, focus trapping, and\ndock reconciliation require internal structure and state. Moving that work to\nevery caller would not create flexibility; it would duplicate fragile\nbehavior.\n\nConversely, Base must not choose brand colors, typography, density, final\nicons, component variants, or application composition. Expose presentation\nthrough `Styled`, typed semantic-state styles, explicit parts, child slots, and\nitem renderers. Do not inspect arbitrary descendants to discover titles,\ndescriptions, or close buttons—make semantic parts explicit.\n\n## Theme and styling\n\nRead semantic values from the active theme and apply layout with GPUI's\n`Styled` methods:\n\n```rust\ndiv()\n    .bg(cx.theme().background)\n    .text_color(cx.theme().foreground)\n    .border_1()\n    .border_color(cx.theme().border)\n    .rounded(cx.theme().radius)\n```\n\nRules:\n\n- do not hard-code product colors, corner radii, spacing, or control geometry;\n- application code must not introduce raw hex, `rgb`/`rgba`, or `hsla`; read a\n  semantic color from `cx.theme()` or add the missing role to the product theme;\n- application layout should use GPUI's rem-based scale helpers (`p_2()`,\n  `gap_3()`, `w_64()`, `text_sm()`) instead of direct `px(...)` values;\n- use semantic tokens for meaning, not palette position;\n- keep state-independent geometry in the ordinary builder chain;\n- use GPUI `hover`, `active`, `focus`, and `focus_visible` modifiers for\n  runtime interaction states;\n- use a component's semantic state styles for checked, selected, pressed, or\n  disabled appearance;\n- keep popup ownership in explicit state so its trigger can render the open or\n  pressed appearance until dismissal;\n- guard hover/active refinements when a disabled control must not react;\n- keep component variants few and meaningful rather than adding a variant for\n  every call site.\n- bind primary styling to the decision area's real default commit and Enter\n  action; do not derive it from action count, frequency, or toolbar position.\n- keep Badge and Alert variants semantic and scarce. Ordinary metadata stays\n  neutral; do not map every enum case or section to a different color merely\n  because a variant exists.\n\nThe effective precedence is instance style, active semantic value states,\ndisabled state, then GPUI runtime interaction refinements. Later layers only\nreplace fields they set.\n\nPrefer `Theme::semantic_tokens()` for new application-owned presentation. The\nsemantic token surface contains generic color roles plus radius, spacing,\ntypography, and shadow scales; it deliberately avoids component names. Legacy\ncomponent-specific theme values still exist for compatibility but should not\nbecome the extension point for every application widget.\n\nThere is one current ownership caveat: `Theme::spacing_tokens()` projects the\ndefault scale, and `Theme::apply_semantic_tokens(...)` does not store custom\nspacing or elevation scales. An application that customizes those scales must\nretain its own `SemanticThemeTokens` (or narrower design-system state) and make\nthat state available to its components. Do not write a custom spacing snapshot\ninto the global theme and expect a later `cx.theme().semantic_tokens()` call to\nreturn it.\n\nEdit the global GPUI Component theme through `Theme::update(cx, |theme| ...)`.\nThe theme keeps the same colors twice (`colors` as solid colors, `tokens` as\nrenderable backgrounds that may carry a gradient) and the Base layer holds a\nprojection for its scrollbars and resize handles; `update` brings all three\nback in step after the closure and refreshes every window. An edit through\n`Theme::global_mut(cx)` updates only the field you touched — a sidebar can then\npaint its text from the new colors and its background from the old tokens —\nso it owns the rest: derive `tokens` from `colors`, call `Theme::sync_base(cx)`,\nrefresh the windows. `Theme::change(...)` performs the projection as part of a\ncomplete theme change.\n\nAn outward focus ring needs physical room. An ancestor with\n`overflow_hidden()` clips it. Prefer layouts that leave room; if a product must\nclip heavily, use the theme's focus-ring policy and retain the focused border\ninstead of silently hiding all keyboard focus.\n\n### Base font is the application zoom control\n\nThe Component Root plugin calls `window.set_rem_size(cx.theme().font_size)` from\nits `prepare` hook before the Root surface is rendered. Therefore the theme's\nbase font is not only body typography; it is the reference length for the\napplication's rem-based design scale. This deliberately follows the useful part\nof Tailwind's model: named type, spacing, and size steps share one relative base\ninstead of becoming unrelated pixel constants.\n\nChange zoom by updating the base font and refreshing the window:\n\n```rust\nTheme::update(cx, |theme| theme.font_size = px(18.));\n```\n\nThe base font itself is a pixel value because it anchors the scale. Descendant\napplication UI should normally use relative helpers—`text_sm()`, `gap_2()`,\n`px_3()`, `h_8()`, `size_4()`—so type, whitespace, controls, and icons respond\ntogether. A custom component that combines rem-based text with fixed-pixel\npadding or icon geometry must document why that part should not zoom.\n\nTreat every direct `px(...)` and raw color constructor in application UI as a\nreview finding. Accept it only for a documented physical/platform boundary,\nmeasured runtime geometry, raster/data color, or the theme/token definition\nitself. Convenience and matching a screenshot are not valid exceptions.\n\nAnything cached from resolved layout must include `window.rem_size()` in its\ninvalidation key, directly or through a revision that changes with it. This\nincludes wrapped row heights, text shaping/layout, virtual-list measurement,\npopup and dialog geometry, icon sizing derived from text, and custom canvas\nmetrics. The Command component's variable-height rows are an ecosystem example:\nthey remeasure when rem changes because the same fixed width wraps differently\nat a larger base font.\n\nDo not confuse this application zoom with Dock panel zoom. Dock zoom is a\nstateful layout operation that makes one tab group fill the DockArea\nwhile keeping the container chrome and the way back out. It must not modify the\nwindow rem size.\n\n## Events, actions, and focus\n\nUse pointer callbacks for pointer-specific behavior. Use GPUI Actions for\ncommands that should support key bindings, menus, or dispatch from multiple\ninputs. Keep action handlers close to the view that owns the command.\n\nModel one logical desktop command once. A toolbar Button, `DropdownMenu` item,\n`ContextMenu` item, menu-bar item, and key binding should dispatch the same\nAction or call the same owner method instead of copying five mutations. Derive\ntheir label, icon, shortcut, and enabled state from one command policy where\npractical, so the entry points cannot disagree. The menu owns navigation and\ndismissal; the feature owner still owns whether the command is allowed and\nwhat it does.\n\nPreserve semantic roles in the element choice. Use `Button` for commands even\nwhen the desired treatment is quiet—select `outline`, `ghost`, or an icon\npresentation instead of replacing it with `Link`. GPUI Kit applications\nreserve `Link` for targets opened by a browser or mail client, such as a URL,\nweb document, or email address. Use the relevant navigation component for an\nin-app destination and `Button`/`Action` for a command. This is a product\nconvention, not a limitation of `gpui_kit::base::Link`, whose `open_with` seam can\nroute a destination elsewhere.\n\nOnly stop propagation when a nested interaction must prevent its parent from\nhandling the same event. Blanket propagation stops break menus, selection,\ndragging, and window-level commands in ways that are difficult to diagnose.\n\nBind keys before building the menu bar. `cx.set_menus` reads the keymap at\nthe moment it is called and bakes each item's shortcut into the native menu,\nso a binding registered afterwards never shows next to its menu item and the\nitem does not react to the key. Call `cx.bind_keys` first, then\n`cx.set_menus`; if the keymap changes later (a user keymap file, a locale\nswitch that rebuilds the menus), call `cx.set_menus` again.\n\nMake focus ownership explicit:\n\n- retain a `FocusHandle` in the entity that owns keyboard interaction;\n- register key contexts and actions on the appropriate focused region;\n- transfer focus when opening an overlay and restore it on dismissal;\n- render a visible `focus_visible` state;\n- do not request focus unconditionally from `render`.\n\nA tracked handle is a Tab stop only when it says so: build it with\n`cx.focus_handle().tab_stop(true)` (or `.tab_index(n)`), because the element's\nown `tab_index`/`tab_stop` settings do not apply to a handle passed to\n`track_focus`. A stateless component may create that handle in `render`\nthrough `window.use_keyed_state(id, cx, |_, cx| cx.focus_handle().tab_stop(true))`;\nthe keyed state survives re-renders, so the Tab order is stable — this is\nwhat `Button` does.\n\nAttach a `key_context` and its `on_action` handlers to the same focused region.\nBindings are contextual: a registered Action without the intended focus path\nis not a working keyboard interaction. Composite widgets should implement the\ncomplete navigation model—arrow movement, Home/End or page movement where\nappropriate, confirmation, cancellation, and Tab behavior—rather than a few\nisolated shortcuts.\n\nModal surfaces must trap focus and restore the previous valid focus target on\ndismissal. Nested overlays dismiss from the top. Handle rapid close/open\nsequences without restoring focus through an intermediate, already-closing\nsurface.\n\n## Async work and side effects\n\nStart async work from an event, lifecycle hook, or named method—not as an\nunconditional side effect of `render`. Capture weak entities when work should\nnot keep a closed view alive. When the task completes, update state through the\nGPUI context, handle the case where the entity or window no longer exists, and\nnotify once after the coherent state change.\n\nRepresent async operations with explicit states such as idle, loading, loaded,\nand failed. Preserve usable previous data during refresh when possible. Prevent\nduplicate destructive submissions and surface recoverable errors in the UI;\ndo not rely on logs as user feedback.\n\nUse background executors for expensive parsing or computation, but keep GPUI\nentity mutation on the appropriate application context. Results can arrive\nafter the request, document, view, or selection has changed; attach a revision\nor identity and reject stale work rather than applying it to new state.\n\n## Layout, measurement, and scrolling\n\n`h_flex` centres its children on the cross axis; `v_flex` leaves flexbox's\ndefault, `stretch`. This matches Zed's `h_flex`, and it is what a row of\ncontrols wants, so a row of icon and label says nothing. It is not what a row\nof full-height columns wants: a column placed in a bare `h_flex` does not fill\nthe row's height, so a column taller than the row is centred and its top —\ncommonly a header — is clipped off the top of the window, with nothing near the\ncolumn to say why. A row whose children are columns says `items_stretch()`:\n\n```rust\nh_flex()\n    .items_stretch()\n    .size_full()\n    .child(sidebar)\n    .child(content)\n```\n\nMost UI should use GPUI layout rather than measuring itself. Measurement is a\ndeep behavior tool for popups, virtualization, editors, resize handles, charts,\nand similar components whose correctness depends on resolved geometry.\n\n- Put measurement and geometry in the layer that owns the behavior.\n- Observe bounds in prepaint only when ordinary layout cannot express the\n  relationship.\n- Never mutate unrelated application state every prepaint.\n- Treat measured data as frame- or revision-scoped; it can become stale after\n  typography, rem size, width, theme, or content changes.\n- Centralize shared geometry such as popup flipping and viewport clamping so\n  every overlay follows the same edge policy.\n\nFor alignment invariants, prefer construction over correction: sibling regions\nshould consume the same spacing token or shared inset instead of repeating\nequivalent literals. Add geometry assertions or visual regression coverage for\ncritical repeated edges, columns, and gaps. Exercise more than the default\nwindow: rem zoom and display scaling can turn fractional coordinates into a\none-physical-pixel drift even when the default screenshot looks aligned.\n\nMeasure the resolved result when reviewing precision, but do not encode a\nmeasured correction as a raw `px(...)` nudge. Trace the mismatch to duplicated\npadding, nested insets, border ownership, font metrics, or rounding, then fix\nthe structural owner.\n\n`h_flex()` and `v_flex()` are not mirror images: `h_flex()` centers its\nchildren on the cross axis, `v_flex()` leaves them stretching. A column placed\nin a row therefore takes its content's height, not the row's, and a column\ntaller than the row is centered — its header is pushed off the top edge and\nclipped. Give a full-height column `h_full()`, or give the row `items_start()`\nor `items_stretch()`, whenever the child owns a header, a footer, or a scroll\nregion that must resolve against the row's height.\n\nEvery scrollable region must have one owner. In flex layouts, apply\n`min_w_0()` or `min_h_0()` to the flexible child that is allowed to shrink.\nA flex item only drops its content-based automatic minimum size when its own\noverflow is not visible, so an ordinary flexible child refuses to shrink around\nlong content until you say so. `Scrollable` handles this for its own wrapper,\nbut a plain `div` between it and the flex container still needs the minimum\nreleased. Avoid accidental nested scrolling; route wheel input to the intended\naxis and preserve platform/wasm differences when an API is not portable.\n\nAttach `Scrollable` to the element that owns the full panel, editor, or window\nviewport so its scrollbar resolves against the region edge. Put content inset\ninside that scroll owner rather than wrapping the scroll owner in a padded\ncontainer. A scrollbar floating between content and the panel boundary usually\nreveals the wrong scroll owner or padding on the wrong layer.\n\n## Lists, tables, and large data\n\nUse virtualization when data can grow beyond a small, bounded collection. Keep\nrow identity separate from visible position and avoid cloning the full data set\non every render. Let a stateful list or table own navigation, selection, scroll\ncoordination, and visible-range calculation while item renderers own row\npresentation.\n\nSeparate:\n\n- source data and domain IDs;\n- filtering/sorting state;\n- selection state;\n- viewport/scroll state;\n- row rendering.\n\nThis keeps updates local and prevents the view tree from becoming the data\nmodel.\n\nVirtualization is a behavioral contract, not just a performance switch. Item\nmeasurement must be invalidated when width, typography, rem size, or row\ncontent changes. Keyboard selection and scroll-to-item must operate in model\ncoordinates even when most elements do not exist in the current frame.\n\n## Public API design\n\nFor reusable components:\n\n- constructors should establish valid defaults;\n- builders take and return `Self` and use domain language;\n- callbacks describe requested changes and include pointer events only when\n  modifiers or pointer details are meaningful;\n- evolvable behavioral seams use private fields, builders for construction,\n  and readers for inspection;\n- boolean readers use `is_` or `has_` where a same-named builder exists;\n- non-boolean setters use `with_` when readers need the plain field name;\n- explicit compound parts are preferable to inspecting arbitrary descendants;\n- adding reusable behavior must not force a product-level visual choice.\n\nPrivate fields are the default for behavioral state that must evolve without\nbreaking callers. Public fields are appropriate for deliberately record-like\nconfiguration, theme tokens, geometry, and serialized schemas. Every public\nstruct with public fields must carry `#[non_exhaustive]`. Provide constructors,\n`Default`, or builders so callers can create values without exhaustive struct\nliterals. This preserves the ability to add fields without breaking callers.\nApply this rule to new types and public API changes; unrelated existing types\ncan be migrated separately.\n\nKeep public module paths stable while reorganizing internals: use a module seam\nwith deliberate re-exports so folders can change without forcing downstream\nimports to change. Prefer platform control terminology and established project\nnaming over web-framework vocabulary.\n\n## Platform and capability boundaries\n\nDo not assume every native or web target supports the same facility. Window\ndecorations, accessibility bridges, system notifications, clipboard behavior,\nscroll gestures, fonts, and timing can differ. Put platform-specific code\nbehind a narrow capability seam and define the fallback behavior.\n\nA platform branch must preserve the semantic contract even if presentation\ndiffers. For example, a system notification may have different retraction\nsupport, but the application still needs a coherent delivery state. Test both\nthe shared state machine and the platform adapter where possible.\n\n## File and naming conventions\n\n- Name views and entities after product concepts: `ProjectList`,\n  `ProjectEditor`, `SettingsState`.\n- Name event handlers after intent: `confirm_delete`, `open_project`,\n  `on_query_changed`.\n- Keep one main responsibility per module; split a file when state ownership or\n  lifecycle can no longer be understood without reading unrelated behavior.\n- Keep component module, state, events, and focused tests together when they\n  change together.\n- Document invariants and surprising lifecycle constraints; do not narrate\n  obvious builder calls.\n- Use `rustfmt` and satisfy the workspace's Clippy rules. Avoid broad `allow`\n  attributes that conceal unrelated warnings.\n\n### Vocabulary is part of the API\n\nUse the same word for the same concept across components. Before naming a new\nmethod, search GPUI, `gpui-base`, and GPUI Component for the established term;\nprefer macOS/Windows control terminology where the ecosystem has no precedent.\nLocalized documentation preserves exact API identifiers and established UI\nframework terms when translation would reduce precision. Format identifiers as\ncode, explain retained terms when needed, and do not mix languages merely to\nmake ordinary prose sound technical.\n\n| Concept | Naming pattern | Example |\n| --- | --- | --- |\n| Value-like rendered control | noun | `Button`, `Checkbox`, `Tab` |\n| Retained behavioral model | `<Control>State` | `InputState`, `TableState` |\n| Imperative shared reference | `<Control>Handle` | `DialogHandle`, scroll handle |\n| Semantic notification | `<Control>Event` | `TableEvent`, `SelectEvent` |\n| Keyboard command | verb or intent noun | `Confirm`, `Cancel`, `SelectNext` |\n| Pluggable data/behavior owner | `<Role>Delegate` / `<Role>Provider` | `TableDelegate`, `CompletionProvider` |\n| Application-supplied presentation | `render_<part>` or `<part>_renderer` | `render_item` |\n| Construction | `new`, or a semantic constructor | `new`, `horizontal`, `vertical` |\n| Fluent property | noun/adjective | `label`, `disabled`, `selected`, `placement` |\n| General non-boolean replacement builder | `with_<field>` | `with_size`, `with_mode` |\n| In-place mutation | `set_<field>` | `set_items`, `set_selected_index` |\n| Boolean reader | `is_<adjective>` / `has_<noun>` | `is_open`, `is_closable`, `has_selection` |\n| Plain value reader | field noun | `placement`, `selected_value` |\n| Callback registration | `on_<event or intent>` | `on_click`, `on_open_change` |\n| Rendering a named region | `render_<region>` | `render_toolbar`, `render_content` |\n\nFor new APIs, fluent builders omit `set_` because they consume and return\n`Self`; mutation through `&mut self` uses `set_`. Preserve established public\nnames when changing them would cause needless churn. Existing builder names\nsuch as `set_position` are compatibility exceptions, not patterns for new APIs.\n\nA boolean reader is either `has_<noun>`, when the value holds something, or\n`is_<adjective>`, when it describes a state or a permission. Reach for the\nadjective whenever the action has one: `is_closable` over `can_close`,\n`is_zoomable` over `can_zoom`, `is_copyable` over `can_copy`. When the action\nis a verb phrase with no adjective form, name the thing it needs instead:\n`has_definition`, not `can_go_to_definition`. Do not add new `can_` readers.\n\nBoolean builders may use the field name (`disabled(bool)`) while their readers\nuse `is_disabled()`. For a public seam struct containing non-boolean fields,\nuse `with_item_ix(...)` for construction and `item_ix()` for reading so setter\nand getter names never collide. Prefer `_ix` for new local or internal\nzero-based indices, preserve established public terms such as `selected_index`,\nand do not introduce `_idx`. If callers never construct the seam value, do not\npublish a builder merely for symmetry.\n\n### Let the enclosing name carry the context\n\nA name is read inside something. A field is read inside its type and a parameter\ninside its method, so neither repeats what encloses it: `with_item_ix(ix)`, not\n`with_item_ix(item_ix)`.\n\nKeep one type's fields at the same level of abbreviation. A single field spelled\nout in full becomes the odd one out, and a reader goes looking for the\ndistinction that made it different. Because a builder is named `with_<field>`,\nshortening a field shortens its builder with it and the pair stays matched.\n\nShorten only where the enclosing name really does disambiguate. When a short\nform is also the established term for a *different* quantity elsewhere in the\necosystem, say which one you mean in the doc comment rather than lengthening the\nidentifier — the doc is read at the call, and it can explain what a longer name\ncould only hint at.\n\n### Use precise domain words\n\n- **selected** is persistent membership or the active item; **focused** is the\n  current keyboard target; **hovered** is pointer presence; **confirmed** is an\n  activation result. Never use them interchangeably.\n- **open/close** describes an overlay or disclosure state; **show/hide** is for\n  transient presentation requests; **expand/collapse** describes structure.\n- **disabled** prevents interaction; **readonly** permits navigation and\n  selection but prevents editing; **loading** prevents duplicate work while an\n  operation is pending. Spell the state `readonly` — one word, as the\n  `readonly(bool)` builder and `is_readonly()` reader do — in identifiers,\n  interface labels, and documentation alike; never `read-only` or `read only`.\n- **index** is a current positional coordinate; **id** is stable identity;\n  `IndexPath` represents hierarchical position. Do not persist or key\n  reorderable data by index.\n- **value** is controlled domain data; **presentation** is a read-only snapshot\n  prepared for rendering; **state** is retained behavior.\n- **placement** is a side or anchor policy; **position** is resolved geometry.\n- **size** is a semantic control tier; **width/height/bounds** are geometry.\n- **child/children** follows GPUI composition; named slots such as `header`,\n  `footer`, `trigger`, and `content` carry additional semantics.\n\nAvoid vague public names such as `data`, `item2`, `handle_action`, `update_ui`,\n`process`, `manager`, or `config` when a narrower domain term exists. `Manager`\nis appropriate only when a type truly coordinates a collection or lifecycle,\nas `ToastManager` does.\n\n### Type and module style\n\n- Rust types and Actions use `UpperCamelCase`; modules, functions, methods,\n  fields, and local variables use `snake_case`; constants use\n  `SCREAMING_SNAKE_CASE`.\n- A module named after a component owns its public seam. Internal folders may\n  split state, element, geometry, platform adapter, and tests without leaking\n  those folder names into imports.\n- Use singular module names for one component concept and established\n  ecosystem names for families (`input`, `table`, `dock`).\n- Suffix type-erased wrappers with `Any` only when they erase a real type\n  boundary, such as `AnyInputState` or `AnyElement`.\n- Suffix identifiers with `Id`, zero-based indices with `ix`, and collections\n  with meaningful plurals. Do not alternate `idx`, `index`, and `ix` in one\n  subsystem.\n- Name predicates positively when possible. A positive `enabled`/`visible`\n  contract is easier to compose than multiple negatives, but preserve\n  established API terms such as `disabled` where they match control semantics.\n\n### Callback and event wording\n\nUse `on_click` only for a genuine click-level contract. A controlled semantic\nprimitive in Base should prefer `on_change(next_value, ...)`; a styled\ncompatibility component may retain `on_click` when pointer details or existing\nAPI expectations matter. Do not invent a `ClickEvent` for a model-driven\nchange.\n\nName before/after lifecycle hooks precisely. `on_will_change` can veto or\nprepare; `on_change` observes a requested/current value contract; `on_confirm`\ncommits a choice; `on_dismiss` closes a transient surface. Document whether a\ncallback runs before internal state changes, after them, or instead of them,\nand whether it may synchronously re-enter the component.\n\n### Documentation and copy style\n\nPublic docs should begin with what a type does and who owns its state. Examples\nmust use current, compilable APIs and show stable IDs. Document defaults,\nplatform limitations, focus behavior, callback ordering, and any requirement\nto call `notify`, `emit`, or a theme synchronization method.\n\nFollow the [interface-language rules](./design-guides.md#interface-language) for\nlabels, commands, confirmation dialogs, capitalization, and ellipses. Keep one\ncanonical term for each domain object, command, and state.\n\nTranslation keys describe stable intent (`dialog.delete_project.title`), not a\nsource-language sentence or a screen coordinate. Never assemble a sentence\nfrom translated fragments or reuse one key for meanings that happen to share\nthe same English text.\n\nLocalize intent, not syntax. Give every locale control over word order,\npluralization, punctuation, and the amount of context it needs. Review strings\ninside the component and with realistic data. Tests or linting should catch\nmissing keys, unintended CJK text in English resources, three-dot ellipses,\nunreviewed ALL CAPS, and inconsistent fixed terms; human review still decides\nwhether repetition is justified by context. Verify every string inside its\ncomponent with realistic content, text expansion, and application zoom.\n\n## Testing strategy\n\nTest at the lowest layer that can prove the behavior:\n\n1. pure tests for state transitions, geometry, parsing, and ordering;\n2. GPUI context tests for entities, events, and subscriptions;\n3. `VisualTestContext` interaction tests for focus, keyboard, pointer, layout,\n   and rendered state;\n4. example or application smoke tests for complete workflows.\n\nFor an interactive component, cover the semantic contract rather than its\nimplementation details: pointer and keyboard activation, controlled value\nchanges, disabled behavior, focus movement, event count/order, stable identity,\nand important empty or failure states. Add a regression test before fixing a\nbug whenever the failure can be reproduced deterministically.\n\nFor UI behavior that depends on the real window system, test through the\naccessibility tree by role, label, value, enabled state, focus, and selection.\nRe-read the tree after every state-changing action because element indexes are\nsnapshots. Use screenshots for visual facts the semantic tree cannot express;\nuse coordinate input only as a fallback. Report automated and manual evidence\nseparately.\n\n## Performance rules\n\n- Do not mutate state or notify unconditionally in `render`.\n- Avoid rebuilding entities, subscriptions, focus handles, and expensive data\n  structures per frame.\n- Notify the narrowest owning entity after a coherent state change.\n- Virtualize long collections and render only the visible range.\n- Avoid cloning large strings or collections solely to satisfy a closure;\n  capture stable handles or shared data.\n- Measure before adding caches. A cache must have a clear invalidation owner.\n- Keep animation work bounded and honor reduced motion.\n\n## Common failure modes\n\nAvoid these patterns:\n\n- one entity containing the entire application's unrelated state;\n- business logic and network requests embedded in a long `render` method;\n- random or index-based `ElementId` values for reorderable content;\n- literal colors and radii that break custom themes;\n- custom clickable `div`s where a semantic component already supplies focus,\n  keyboard, disabled, and accessibility behavior;\n- duplicated local state that drifts from a controlled model value;\n- `cx.notify()` loops caused by mutation during every render;\n- nested scroll containers without explicit ownership;\n- a new component variant for a one-off screen;\n- confirmation dialogs for reversible, low-risk actions;\n- tests that call internal methods but never exercise keyboard or pointer\n  behavior.\n\n## Rules for coding agents\n\nBefore editing, an agent must read the nearest implementation, its tests, the\nre-export seam, and the relevant component documentation. It must search the\ncurrent source for signatures instead of translating a React, CSS, or old GPUI\nexample by analogy.\n\nFor each change, the agent should be able to name:\n\n1. the behavior owner and presentation owner;\n2. the retained identity and state lifecycle;\n3. the pointer, keyboard, focus, and accessibility contract;\n4. the layout and overflow owner;\n5. the theme tokens and intentional exceptions;\n6. the test that would fail if the behavior regressed.\n\nGenerated code must be reviewed and tested by a person. “Compiles” is not a UI\nquality bar, and a broad refactor that merely makes generated code look tidy is\nnot a substitute for matching the repository's architecture.\n\n## Implementation checklist\n\nBefore opening a change for review, confirm that:\n\n- state and side-effect ownership are explicit;\n- `RenderOnce` versus `Entity<T>` is chosen deliberately;\n- repeated elements have stable domain-based IDs;\n- theme tokens and component sizes replace isolated visual literals;\n- keyboard actions, focus, disabled state, and overlays work together;\n- loading, empty, error, and cancellation paths are represented;\n- long data sets use an appropriate virtualized component;\n- public API additions preserve dependency direction and encapsulation;\n- tests prove behavior at the appropriate layer;\n- formatting, Clippy, targeted tests, and relevant examples pass.\n\nSee [Getting Started](./getting-started.md) for application setup and the\ncomponent pages for current API details.\n\n<!-- File: skills/gpui-kit/references/conventions.md (Tokens: ~1146 | Category: anthropic-skill) -->\n# Component-family conventions\n\nUse this page to predict a component's shape before reading its detailed API. These conventions describe Rust GPUI Component. JavaScript uses its host's generated catalog; a Rust method is not automatically a JavaScript method.\n\n## Choose the family\n\n| Task | Family and constructor | State owner | Event or composition |\n| --- | --- | --- | --- |\n| Execute a command | `Button::new(\"save\")` | Application owns the operation | `on_click` receives a click event |\n| Change a boolean | `Checkbox::new(\"remember\")`, `Switch::new(\"enabled\")`, `Radio::new(\"choice\")` | Application supplies `checked(bool)` | `on_change` receives the requested `&bool` |\n| Choose one radio option | `RadioGroup::new(\"delivery\")` | Application supplies `selected_index(Option<usize>)` | `on_change` receives the requested `&usize` |\n| Edit retained text | `Input::new(&self.input)` | View retains `Entity<InputState>` | Retain the subscription; handle `InputEvent` |\n| Display a supplied patch | `Diff::new(&self.diff)` | View retains `Entity<DiffState>`; application parses supplied unified/Git diff with `DiffFile::parse`; one state shows all files | Readonly `RenderOnce` element; retain subscriptions to `DiffEvent` when needed |\n| Lay out fields | `Form::new()` | Children retain their own state | `child(Field)`, `columns`, `label_layout`, `footer` |\n| Supply a compound part | `Field::new()`, `Tab::new()` | Containing component owns placement/selection | Read the parent's accepted child type |\n\nConstructors establish the component family's ownership model. Do not infer that every `new` takes an ID or that every `child` accepts an arbitrary element. Keep domain IDs stable when controls are reordered. Positional selection APIs remain positional; applications map them to domain identity when needed.\n\n## A value request is different from a command\n\nFor Checkbox, Switch, Radio, and RadioGroup, use the same owner-update pattern:\n\n```rust\nSwitch::new(\"enabled\")\n    .checked(self.enabled)\n    .on_change(cx.listener(|this, next, _, cx| {\n        this.enabled = *next;\n        cx.notify();\n    }))\n```\n\nReplace Switch with Checkbox or Radio without changing the boolean callback shape. Radio represents selecting an option; its activation semantics still differ from toggling a Switch. RadioGroup supplies an index, so its owner stores `Some(*next)` instead.\n\n`on_change` requests a value; it does not mutate your application model. Existing `on_click` calls on these four controls remain valid compatibility aliases. Both names set one handler, and the last call wins. Use `Button::on_click` for commands. Retained controls such as Input keep their existing event/subscription API because the state entity, rather than a transient builder, owns their changes.\n\n## Form layout has independent decisions\n\n| Decision | API | Default |\n| --- | --- | --- |\n| Label above or beside its control | `label_layout(Axis::Vertical / Horizontal)` | Above |\n| Number of field columns | `columns(count)` | One |\n| A field spanning several columns | `Field::col_span(count)` | One |\n| Commands after the fields | `footer(element)` | No footer; supplied footer spans all columns and aligns to the trailing edge |\n\n`Form::horizontal()` and `h_form()` mean labels beside controls. They do not put all fields into one horizontal row. `Form::vertical()`, `v_form()`, and `layout(Axis)` remain supported.\n\n```rust\nForm::new()\n    .label_layout(Axis::Horizontal)\n    .columns(2)\n    .child(Field::new().label(\"Name\").child(Input::new(&self.name)))\n    .child(Field::new().label(\"Email\").child(Input::new(&self.email)))\n    .footer(Button::new(\"save\").label(\"Save\"))\n```\n\nThe footer supplies layout only: attach the save action to the Button. Form does not own submission, validation, responsive breakpoints, or data persistence. Choose column count for the available width. Put multiple action buttons in one supplied action row with a shared gap. Keep field descriptions with their Field so they follow its alignment.\n\n## Import capabilities explicitly\n\nComponents live in their component modules. Common capabilities may be extension traits, not inherent methods: import `ButtonVariants` for button variants, `Sizable` for size tiers, `Disableable` for supported disabled builders, `ActiveTheme` for theme access, and `WindowExt` for window overlays. Do not infer that every component supports every trait.\n\nUse the [complete application recipe](recipes.md) for imports, retained ownership, initialization, Root, and overlay layers. For a narrow task, load its component page and the relevant section of the coding/design guides; a component catalog is not a required reading sequence.\n\n## Verify the convention transfer\n\nWhen transferring a pattern to another family member, check that it compiles, receives the expected requested value, preserves controlled state after redraw, and behaves correctly when disabled. For Form, check label orientation independently of column count and keep footer geometry outside the field grid's individual cells.\n\nIn this repository, `cargo test -p gpui-kit-recipes` compiles the external-style consumer and runs its interaction tests, and `script/check-ai rust` runs the control-family event and compatibility tests and Form geometry tests. These are deterministic contract checks, not measured AI first-attempt success rates.\n\n<!-- File: skills/gpui-kit/references/gpui/action.md (Tokens: ~1347 | Category: anthropic-skill) -->\n# Actions & Keybindings\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Key Formats](#key-formats) · [Menu Bar Shortcuts](#menu-bar-shortcuts) · [Action Naming](#action-naming) · [Context-Aware Bindings](#context-aware-bindings) · [Best Practices](#best-practices)\n\n## Overview\n\nActions provide declarative keyboard-driven UI interactions in GPUI.\n\n**Key Concepts:**\n- Define actions with `actions!` macro or `#[derive(Action)]`\n- Bind keys with `cx.bind_keys()`\n- Handle with `.on_action()` on elements\n- Context-aware via `key_context()`\n\n## Quick Start\n\n### Simple Actions\n\n```rust\nuse gpui_kit::actions;\n\nactions!(editor, [MoveUp, MoveDown, Save, Quit]);\n\nconst CONTEXT: &str = \"Editor\";\n\npub fn init(cx: &mut App) {\n    cx.bind_keys([\n        KeyBinding::new(\"up\", MoveUp, Some(CONTEXT)),\n        KeyBinding::new(\"down\", MoveDown, Some(CONTEXT)),\n        KeyBinding::new(\"cmd-s\", Save, Some(CONTEXT)),\n        KeyBinding::new(\"cmd-q\", Quit, Some(CONTEXT)),\n    ]);\n}\n\nimpl Render for Editor {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .key_context(CONTEXT)\n            .on_action(cx.listener(Self::move_up))\n            .on_action(cx.listener(Self::move_down))\n            .on_action(cx.listener(Self::save))\n    }\n}\n\nimpl Editor {\n    fn move_up(&mut self, _: &MoveUp, cx: &mut Context<Self>) {\n        // Handle move up\n        cx.notify();\n    }\n\n    fn move_down(&mut self, _: &MoveDown, cx: &mut Context<Self>) {\n        cx.notify();\n    }\n\n    fn save(&mut self, _: &Save, cx: &mut Context<Self>) {\n        // Save logic\n        cx.notify();\n    }\n}\n```\n\n### Actions with Parameters\n\n```rust\n#[derive(Clone, PartialEq, Action, Deserialize)]\n#[action(namespace = editor)]\npub struct InsertText {\n    pub text: String,\n}\n\n#[derive(Action, Clone, PartialEq, Eq, Deserialize)]\n#[action(namespace = editor, no_json)]\npub struct Digit(pub u8);\n\ncx.bind_keys([\n    KeyBinding::new(\"0\", Digit(0), Some(CONTEXT)),\n    KeyBinding::new(\"1\", Digit(1), Some(CONTEXT)),\n    // ...\n]);\n\nimpl Editor {\n    fn on_digit(&mut self, action: &Digit, cx: &mut Context<Self>) {\n        self.insert_digit(action.0, cx);\n    }\n}\n```\n\n## Key Formats\n\n```rust\n// Modifiers\n\"cmd-s\"         // Command (macOS) / Ctrl (Windows/Linux)\n\"ctrl-c\"        // Control\n\"alt-f\"         // Alt\n\"shift-tab\"     // Shift\n\"cmd-ctrl-f\"    // Multiple modifiers\n\n// Keys\n\"a-z\", \"0-9\"    // Letters and numbers\n\"f1-f12\"        // Function keys\n\"up\", \"down\", \"left\", \"right\"\n\"enter\", \"escape\", \"space\", \"tab\"\n\"backspace\", \"delete\"\n\"-\", \"=\", \"[\", \"]\", etc.  // Special characters\n```\n\n## Menu Bar Shortcuts\n\n`cx.set_menus` reads the keymap **at the moment it is called** and bakes each\nitem's shortcut into the native menu. A key bound afterwards never appears next\nto its menu item, and the item does not react to that key. There is no event to\nhook: bind first, then build the menus, and rebuild them when the keymap\nchanges.\n\n```rust\npub fn init(cx: &mut App) {\n    // 1. Bindings first — the menu items copy their shortcuts from these.\n    cx.bind_keys([\n        KeyBinding::new(\"cmd-n\", NewChat, None),\n        KeyBinding::new(\"cmd-,\", OpenSettings, None),\n        KeyBinding::new(\"cmd-q\", Quit, None),\n    ]);\n\n    // 2. Then the menu bar.\n    cx.set_menus(vec![Menu {\n        name: \"File\".into(),\n        items: vec![\n            MenuItem::action(\"New Chat\", NewChat),\n            MenuItem::action(\"Settings…\", OpenSettings),\n            MenuItem::separator(),\n            MenuItem::action(\"Quit\", Quit),\n        ],\n    }]);\n}\n```\n\nCall `cx.set_menus` again after anything that changes bindings or labels: a\nuser keymap file loaded later, a locale switch that renames the items. `Undo`,\n`Redo`, `Cut`, `Copy`, `Paste` need no `on_action` of your own — give the item\nan `OsAction` and the platform forwards it to the focused text control.\n\n## Action Naming\n\nPrefer verb-noun pattern:\n\n```rust\nactions!([\n    OpenFile,      // ✅ Good\n    CloseWindow,   // ✅ Good\n    ToggleSidebar, // ✅ Good\n    Save,          // ✅ Good (common exception)\n]);\n```\n\n## Context-Aware Bindings\n\n```rust\nconst EDITOR_CONTEXT: &str = \"Editor\";\nconst MODAL_CONTEXT: &str = \"Modal\";\n\n// Same key, different contexts\ncx.bind_keys([\n    KeyBinding::new(\"escape\", CloseModal, Some(MODAL_CONTEXT)),\n    KeyBinding::new(\"escape\", ClearSelection, Some(EDITOR_CONTEXT)),\n]);\n\n// Set context on element\ndiv()\n    .key_context(EDITOR_CONTEXT)\n    .child(editor_content)\n```\n\n## Best Practices\n\n### ✅ Use Contexts\n\n```rust\n// ✅ Good: Context-aware\ndiv()\n    .key_context(\"MyComponent\")\n    .on_action(cx.listener(Self::handle))\n```\n\n### ✅ Name Actions Clearly\n\n```rust\n// ✅ Good: Clear intent\nactions!([\n    SaveDocument,\n    CloseTab,\n    TogglePreview,\n]);\n```\n\n### ✅ Handle with Listeners\n\n```rust\n// ✅ Good: Proper handler naming\nimpl MyComponent {\n    fn on_action_save(&mut self, _: &Save, cx: &mut Context<Self>) {\n        // Handle save\n        cx.notify();\n    }\n}\n\ndiv().on_action(cx.listener(Self::on_action_save))\n```\n\n<!-- File: skills/gpui-kit/references/gpui/async.md (Tokens: ~1507 | Category: anthropic-skill) -->\n# Async & Background Tasks\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Core Patterns](#core-patterns) · [Common Pitfalls](#common-pitfalls)\n\n## Overview\n\nGPUI provides integrated async runtime for foreground UI updates and background computation.\n\n**Key Concepts:**\n\n- **Foreground tasks**: UI thread, can update entities (`cx.spawn`)\n- **Background tasks**: Worker threads, CPU-intensive work (`cx.background_spawn`)\n- All entity updates happen on foreground thread\n\n## Quick Start\n\n### Foreground Tasks (UI Updates)\n\nWhen spawned from `Context<Self>`, the closure receives `(WeakEntity<Self>, &mut AsyncApp)`:\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx: &mut AsyncApp| {\n            // Runs on UI thread, can await and update entities\n            let data = fetch_from_api().await;\n\n            this.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            }).ok();\n        }).detach();\n    }\n}\n```\n\nWhen spawned from `&mut App` (not inside an entity), the closure receives only `(cx: &mut AsyncApp)`:\n\n```rust\ncx.spawn(async move |cx: &mut AsyncApp| {\n    // No entity reference\n}).detach();\n```\n\n### Spawn with Window Context (spawn_in)\n\nUse `spawn_in` when the task also needs window access (`update_in`):\n\n```rust\nimpl MyComponent {\n    fn animate(&mut self, window: &mut Window, cx: &mut Context<Self>) {\n        cx.spawn_in(window, async move |this, cx| {\n            // cx here is AsyncWindowContext\n            this.update_in(cx, |state, window, cx| {\n                // Can access window here\n                state.frame += 1;\n                cx.notify();\n            }).ok();\n        }).detach();\n    }\n}\n```\n\n### Background Tasks (Heavy Work)\n\n```rust\nimpl MyComponent {\n    fn process_file(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            // Runs on background thread, CPU-intensive\n            let result = cx\n                .background_spawn(async move { heavy_computation() })\n                .await;\n\n            // Back on the foreground to update UI\n            this.update(cx, |state, cx| {\n                state.result = result;\n                cx.notify();\n            }).ok();\n        })\n        .detach();\n    }\n}\n```\n\n### Task Management\n\n```rust\nstruct MyView {\n    _task: Task<()>,  // Prefix with _ if stored but not accessed\n}\n\nimpl MyView {\n    fn new(cx: &mut Context<Self>) -> Self {\n        let _task = cx.spawn(async move |this, cx: &mut AsyncApp| {\n            // Task automatically cancelled when dropped\n            loop {\n                cx.background_executor().timer(Duration::from_secs(1)).await;\n\n                this.update(cx, |state, cx| {\n                    state.tick();\n                    cx.notify();\n                }).ok();\n            }\n        });\n\n        Self { _task }\n    }\n}\n```\n\n## Core Patterns\n\n### 1. Async Data Fetching (from Context<Self>)\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    let data = fetch_data().await?;\n    this.update(cx, |state, cx| {\n        state.data = Some(data);\n        cx.notify();\n    })?;\n    Ok::<_, anyhow::Error>(())\n}).detach();\n```\n\n### 2. Background Computation + UI Update\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    let result = cx.background_spawn(async move { heavy_work() }).await;\n    this.update(cx, |state, cx| {\n        state.result = result;\n        cx.notify();\n    }).ok();\n})\n.detach();\n```\n\n### 3. Periodic Tasks\n\n```rust\ncx.spawn(async move |this, cx: &mut AsyncApp| {\n    loop {\n        cx.background_executor().timer(Duration::from_secs(5)).await;\n\n        this.update(cx, |state, cx| {\n            state.tick();\n            cx.notify();\n        }).ok();\n    }\n}).detach();\n```\n\n### 4. Task Cancellation\n\nTasks are automatically cancelled when dropped. Store in struct to keep alive.\n\n## Common Pitfalls\n\n### ❌ Don't: Use `defer_in` and then update the same entity through its handle\n\n`cx.defer_in(window, callback)` schedules `callback` to run **on the current entity** — GPUI re-acquires that entity's lock to execute it. Calling `entity.update(cx, …)` on the *same* entity from within the deferred callback re-enters the lock and panics:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: list entity is locked for the defer_in; calling list.update re-enters\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        parent.update(cx, |this, cx| {\n            this.inner_list.update(cx, |_, _| {}); // PANIC if inner_list == the deferred entity\n        });\n    });\n}\n```\n\n```rust\n// ✅ Correct: use the direct &mut reference — no lock needed\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // Access list data directly through the &mut reference\n        list_state.delegate_mut().some_method();\n\n        // Update a *different* entity — fine, different lock\n        parent.update(cx, |this, cx| { /* … */ });\n\n        // Sync list state directly after parent update — no lock needed\n        list_state.delegate_mut().update_snapshot(new_val);\n    });\n}\n```\n\nThe rule: inside a `defer_in` callback, **never call `entity.update(cx, …)` or `entity.read(cx)` on the entity the `defer_in` was scheduled on**. Use the `&mut Entity` direct reference the callback provides instead.\n\n### ❌ Don't: Update entities from background tasks\n\n```rust\n// ❌ Wrong: Can't update entities from background thread\ncx.background_spawn(async move {\n    entity.update(cx, |state, cx| { // Compile error!\n        state.data = data;\n    });\n});\n```\n\n### ✅ Do: Await the background task inside a foreground task\n\n```rust\n// ✅ Correct: the foreground task awaits the background result\ncx.spawn(async move |this, cx| {\n    let data = cx.background_spawn(async move { load_data() }).await;\n    this.update(cx, |state, cx| {\n        state.data = data;\n        cx.notify();\n    }).ok();\n})\n.detach();\n```\n\nGPUI has no `Task::then`. Await the background task inside `cx.spawn`. The\nclosure receives `(WeakEntity<Self>, &mut AsyncApp)`, not the background result.\n\n<!-- File: skills/gpui-kit/references/gpui/context.md (Tokens: ~1556 | Category: anthropic-skill) -->\n# Context Management\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Operations](#common-operations) · [Context Hierarchy](#context-hierarchy) · [cx.listener](#cxlistener--binding-callbacks-to-self) · [subscribe_in](#subscribe_in--subscribe-with-window-access) · [observe_window_activation](#observe_window_activation) · [observe_global](#observe_global) · [defer / defer_in](#defer-and-defer_in) · [Naming Convention](#context-naming-convention)\n\n## Overview\n\nGPUI uses different context types for different scenarios:\n\n**Context Types:**\n- **`App`**: Global app state, entity creation\n- **`Window`**: Window-specific operations, painting, layout\n- **`Context<T>`**: Entity-specific context for component `T`\n- **`AsyncApp`**: Async context for foreground tasks\n- **`AsyncWindowContext`**: Async context with window access\n\n## Quick Start\n\n### Context<T> - Component Context\n\n```rust\nimpl MyComponent {\n    fn update_state(&mut self, cx: &mut Context<Self>) {\n        self.value = 42;\n        cx.notify(); // Trigger re-render\n\n        // Spawn async task\n        cx.spawn(async move |cx| {\n            // Async work\n        }).detach();\n\n        // Get current entity\n        let entity = cx.entity();\n    }\n}\n```\n\n### App - Global Context\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx: &mut App| {\n        gpui_kit::init(cx);\n\n        // Create entities\n        let entity = cx.new(|cx| MyState::default());\n\n        // Open windows (wraps the view in a `Root`)\n        gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| cx.new(|_| MyView))\n            .expect(\"failed to open window\");\n    });\n}\n```\n\n### Window - Window Context\n\n```rust\nimpl Render for MyView {\n    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        // Window operations\n        let is_focused = window.is_window_focused();\n        let bounds = window.bounds();\n\n        div().child(\"Content\")\n    }\n}\n```\n\n### AsyncApp - Async Context\n\n```rust\ncx.spawn(async move |cx: &mut AsyncApp| {\n    let data = fetch_data().await;\n\n    entity.update(cx, |state, inner_cx| {\n        state.data = data;\n        inner_cx.notify();\n    }).ok();\n}).detach();\n```\n\n## Common Operations\n\n### Entity Operations\n\n```rust\n// Create entity\nlet entity = cx.new(|cx| MyState::default());\n\n// Update entity\nentity.update(cx, |state, cx| {\n    state.value = 42;\n    cx.notify();\n});\n\n// Read entity\nlet value = entity.read(cx).value;\n```\n\n### Notifications and Events\n\n```rust\n// Trigger re-render\ncx.notify();\n\n// Emit event\ncx.emit(MyEvent::Updated);\n\n// Observe entity\ncx.observe(&entity, |this, observed, cx| {\n    // React to changes\n}).detach();\n\n// Subscribe to events\ncx.subscribe(&entity, |this, source, event, cx| {\n    // Handle event\n}).detach();\n```\n\n### Window Operations\n\n```rust\n// Window state\nlet focused = window.is_window_focused();\nlet bounds = window.bounds();\nlet scale = window.scale_factor();\n\n// Close window\nwindow.remove_window();\n```\n\n### Async Operations\n\n```rust\n// Spawn foreground task\ncx.spawn(async move |cx| {\n    // Async work with entity access\n}).detach();\n\n// Spawn background task\ncx.background_spawn(async move {\n    // Heavy computation\n}).detach();\n```\n\n## Context Hierarchy\n\n```\nApp (Global)\n  └─ Window (Per-window)\n       └─ Context<T> (Per-component)\n            └─ AsyncApp (In async tasks)\n                 └─ AsyncWindowContext (Async + Window)\n```\n\n## cx.listener — Binding Callbacks to Self\n\n`cx.listener` creates a callback that borrows `&mut self` (the current entity). Use it for `on_click`, `on_action`, and other element event handlers:\n\n```rust\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .on_action(cx.listener(Self::on_save))\n            .child(\n                Button::new(\"btn\")\n                    .on_click(cx.listener(|this, _event, _window, cx| {\n                        this.count += 1;\n                        cx.notify();\n                    }))\n            )\n    }\n}\n\nimpl MyView {\n    fn on_save(&mut self, _: &Save, _window: &mut Window, cx: &mut Context<Self>) {\n        cx.notify();\n    }\n}\n```\n\n`cx.listener(Self::method)` is equivalent to creating a closure that calls `self.method(...)`.\n\n## subscribe_in — Subscribe with Window Access\n\nUse `subscribe_in` (instead of `subscribe`) when the callback needs `&mut Window`:\n\n```rust\nlet _subscription = cx.subscribe_in(&input, window, |this, state, event, window, cx| {\n    match event {\n        InputEvent::Change => {\n            let val = state.read(cx).value();\n            this.on_input_change(val, window, cx);\n        }\n        _ => {}\n    }\n});\n// Store _subscription in struct to keep it alive\n```\n\n`subscribe` vs `subscribe_in`:\n- `subscribe(&entity, |this, source, event, cx|)` — no window access\n- `subscribe_in(&entity, window, |this, source, event, window, cx|)` — has window access\n\n## observe_window_activation\n\nReact when the window gains or loses focus:\n\n```rust\nlet _sub = cx.observe_window_activation(window, |this, window, cx| {\n    if window.is_window_active() {\n        this.resume(cx);\n    } else {\n        this.pause(cx);\n    }\n});\n```\n\n## observe_global\n\nReact when a global value changes:\n\n```rust\ncx.observe_global::<Theme>(|cx| {\n    // Theme changed — react\n    cx.notify();\n});\n```\n\n## defer and defer_in\n\nSchedule work after the current update completes:\n\n```rust\n// defer: runs after current App update, no window access\ncx.defer(|cx| {\n    // Runs after current entity update is done\n});\n\n// defer_in: runs after update, with window access\ncx.defer_in(window, |this, window, cx| {\n    // Can access window here\n    // CAUTION: never call entity.update(cx) on *this same entity* inside defer_in\n    // — it re-enters the lock and panics. Use the &mut self reference directly.\n    this.some_method(window, cx);\n});\n```\n\n## Context Naming Convention\n\nAlways name contexts `cx` regardless of type:\n\n```rust\nfn new(window: &mut Window, cx: &mut App) {}             // cx = App\nimpl Render for View {\n    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) {}  // cx = Context<Self>\n}\ncx.spawn(async move |this, cx: &mut AsyncApp| {})         // cx = AsyncApp\n```\n\n<!-- File: skills/gpui-kit/references/gpui/element-advanced.md (Tokens: ~4672 | Category: anthropic-skill) -->\n# Advanced Element Patterns\n\n**Contents:** [Custom Layout Algorithms](#custom-layout-algorithms) · [Element Composition with Traits](#element-composition-with-traits) · [Async Element Updates](#async-element-updates) · [Element Memoization](#element-memoization) · [Virtual List Pattern](#virtual-list-pattern)\n\n## Custom Layout Algorithms\n\nImplementing custom layout algorithms not supported by GPUI's built-in layouts.\n\n### Masonry Layout (Pinterest-Style)\n\n```rust\npub struct MasonryLayout {\n    id: ElementId,\n    columns: usize,\n    gap: Pixels,\n    children: Vec<AnyElement>,\n}\n\nstruct MasonryLayoutState {\n    column_layouts: Vec<Vec<LayoutId>>,\n    column_heights: Vec<Pixels>,\n}\n\nstruct MasonryPaintState {\n    child_bounds: Vec<Bounds<Pixels>>,\n}\n\nimpl Element for MasonryLayout {\n    type RequestLayoutState = MasonryLayoutState;\n    type PrepaintState = MasonryPaintState;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, MasonryLayoutState) {\n        // Initialize columns\n        let mut columns: Vec<Vec<LayoutId>> = vec![Vec::new(); self.columns];\n        let mut column_heights = vec![px(0.); self.columns];\n\n        // Distribute children across columns\n        for child in &mut self.children {\n            let (child_layout_id, _) = child.request_layout(\n                global_id,\n                inspector_id,\n                window,\n                cx\n            );\n\n            let child_size = window.layout_bounds(child_layout_id).size;\n\n            // Find shortest column\n            let min_column_idx = column_heights\n                .iter()\n                .enumerate()\n                .min_by(|a, b| a.1.partial_cmp(b.1).unwrap())\n                .unwrap()\n                .0;\n\n            // Add child to shortest column\n            columns[min_column_idx].push(child_layout_id);\n            column_heights[min_column_idx] += child_size.height + self.gap;\n        }\n\n        // Calculate total layout size\n        let column_width = px(200.); // Fixed column width\n        let total_width = column_width * self.columns as f32\n            + self.gap * (self.columns - 1) as f32;\n        let total_height = column_heights.iter()\n            .max_by(|a, b| a.partial_cmp(b).unwrap())\n            .copied()\n            .unwrap_or(px(0.));\n\n        let layout_id = window.request_layout(\n            Style {\n                size: size(total_width, total_height),\n                ..default()\n            },\n            columns.iter().flatten().copied().collect(),\n            cx\n        );\n\n        (layout_id, MasonryLayoutState {\n            column_layouts: columns,\n            column_heights,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut MasonryLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> MasonryPaintState {\n        let column_width = px(200.);\n        let mut child_bounds = Vec::new();\n\n        // Position children in columns\n        for (col_idx, column) in layout_state.column_layouts.iter().enumerate() {\n            let x_offset = bounds.left()\n                + (column_width + self.gap) * col_idx as f32;\n            let mut y_offset = bounds.top();\n\n            for (child_idx, layout_id) in column.iter().enumerate() {\n                let child_size = window.layout_bounds(*layout_id).size;\n                let child_bound = Bounds::new(\n                    point(x_offset, y_offset),\n                    size(column_width, child_size.height)\n                );\n\n                self.children[child_idx].prepaint(\n                    global_id,\n                    inspector_id,\n                    child_bound,\n                    window,\n                    cx\n                );\n\n                child_bounds.push(child_bound);\n                y_offset += child_size.height + self.gap;\n            }\n        }\n\n        MasonryPaintState { child_bounds }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        _bounds: Bounds<Pixels>,\n        _layout_state: &mut MasonryLayoutState,\n        paint_state: &mut MasonryPaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        for (child, bounds) in self.children.iter_mut().zip(&paint_state.child_bounds) {\n            child.paint(global_id, inspector_id, *bounds, window, cx);\n        }\n    }\n}\n```\n\n### Circular Layout\n\n```rust\npub struct CircularLayout {\n    id: ElementId,\n    radius: Pixels,\n    children: Vec<AnyElement>,\n}\n\nimpl Element for CircularLayout {\n    type RequestLayoutState = Vec<LayoutId>;\n    type PrepaintState = Vec<Bounds<Pixels>>;\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Vec<LayoutId>) {\n        let child_layouts: Vec<_> = self.children\n            .iter_mut()\n            .map(|child| child.request_layout(global_id, inspector_id, window, cx).0)\n            .collect();\n\n        let diameter = self.radius * 2.;\n        let layout_id = window.request_layout(\n            Style {\n                size: size(diameter, diameter),\n                ..default()\n            },\n            child_layouts.clone(),\n            cx\n        );\n\n        (layout_id, child_layouts)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_ids: &mut Vec<LayoutId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Vec<Bounds<Pixels>> {\n        let center = bounds.center();\n        let angle_step = 2.0 * std::f32::consts::PI / self.children.len() as f32;\n\n        let mut child_bounds = Vec::new();\n\n        for (i, (child, layout_id)) in self.children.iter_mut()\n            .zip(layout_ids.iter())\n            .enumerate()\n        {\n            let angle = angle_step * i as f32;\n            let child_size = window.layout_bounds(*layout_id).size;\n\n            // Position child on circle\n            let x = center.x + self.radius * angle.cos() - child_size.width / 2.;\n            let y = center.y + self.radius * angle.sin() - child_size.height / 2.;\n\n            let child_bound = Bounds::new(point(x, y), child_size);\n\n            child.prepaint(global_id, inspector_id, child_bound, window, cx);\n            child_bounds.push(child_bound);\n        }\n\n        child_bounds\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        _bounds: Bounds<Pixels>,\n        _layout_ids: &mut Vec<LayoutId>,\n        child_bounds: &mut Vec<Bounds<Pixels>>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        for (child, bounds) in self.children.iter_mut().zip(child_bounds) {\n            child.paint(global_id, inspector_id, *bounds, window, cx);\n        }\n    }\n}\n```\n\n## Element Composition with Traits\n\nCreate reusable behaviors via traits for element composition.\n\n### Hoverable Trait\n\n```rust\npub trait Hoverable: Element {\n    fn on_hover<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static;\n\n    fn on_hover_end<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static;\n}\n\n// Implementation for custom element\npub struct HoverableElement {\n    id: ElementId,\n    content: AnyElement,\n    hover_handlers: Vec<Box<dyn Fn(&mut Window, &mut App)>>,\n    hover_end_handlers: Vec<Box<dyn Fn(&mut Window, &mut App)>>,\n    was_hovered: bool,\n}\n\nimpl Hoverable for HoverableElement {\n    fn on_hover<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static\n    {\n        self.hover_handlers.push(Box::new(f));\n        self\n    }\n\n    fn on_hover_end<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&mut Window, &mut App) + 'static\n    {\n        self.hover_end_handlers.push(Box::new(f));\n        self\n    }\n}\n\nimpl Element for HoverableElement {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = Hitbox;\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout: &mut LayoutId,\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let is_hovered = hitbox.is_hovered(window);\n\n        // Trigger hover events\n        if is_hovered && !self.was_hovered {\n            for handler in &self.hover_handlers {\n                handler(window, cx);\n            }\n        } else if !is_hovered && self.was_hovered {\n            for handler in &self.hover_end_handlers {\n                handler(window, cx);\n            }\n        }\n\n        self.was_hovered = is_hovered;\n\n        // Paint content\n        self.content.paint(bounds, window, cx);\n    }\n\n    // ... other methods\n}\n```\n\n### Clickable Trait\n\n```rust\npub trait Clickable: Element {\n    fn on_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static;\n\n    fn on_double_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static;\n}\n\npub struct ClickableElement {\n    id: ElementId,\n    content: AnyElement,\n    click_handlers: Vec<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    double_click_handlers: Vec<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    last_click_time: Option<Instant>,\n}\n\nimpl Clickable for ClickableElement {\n    fn on_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static\n    {\n        self.click_handlers.push(Box::new(f));\n        self\n    }\n\n    fn on_double_click<F>(&mut self, f: F) -> &mut Self\n    where\n        F: Fn(&MouseUpEvent, &mut Window, &mut App) + 'static\n    {\n        self.double_click_handlers.push(Box::new(f));\n        self\n    }\n}\n```\n\n## Async Element Updates\n\nElements that update based on async operations.\n\n```rust\npub struct AsyncElement {\n    id: ElementId,\n    state: Entity<AsyncState>,\n    loading: bool,\n    data: Option<String>,\n}\n\npub struct AsyncState {\n    loading: bool,\n    data: Option<String>,\n}\n\nimpl Element for AsyncElement {\n    type RequestLayoutState = ();\n    type PrepaintState = Hitbox;\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout: &mut (),\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Display loading or data\n        if self.loading {\n            // Paint loading indicator\n            self.paint_loading(bounds, window, cx);\n        } else if let Some(data) = &self.data {\n            // Paint data\n            self.paint_data(data, bounds, window, cx);\n        }\n\n        // Trigger async update on click\n        window.on_mouse_event({\n            let state = self.state.clone();\n            let hitbox = hitbox.clone();\n\n            move |event: &MouseUpEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Spawn async task\n                    cx.spawn({\n                        let state = state.clone();\n                        async move {\n                            // Perform async operation\n                            let result = fetch_data_async().await;\n\n                            // Update state on completion\n                            state.update(cx, |state, cx| {\n                                state.loading = false;\n                                state.data = Some(result);\n                                cx.notify();\n                            });\n                        }\n                    }).detach();\n\n                    // Set loading state immediately\n                    state.update(cx, |state, cx| {\n                        state.loading = true;\n                        cx.notify();\n                    });\n\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n\n    // ... other methods\n}\n\nasync fn fetch_data_async() -> String {\n    // Simulate async operation\n    tokio::time::sleep(Duration::from_secs(1)).await;\n    \"Data loaded!\".to_string()\n}\n```\n\n## Element Memoization\n\nOptimize performance by memoizing expensive element computations.\n\n```rust\npub struct MemoizedElement<T: PartialEq + Clone + 'static> {\n    id: ElementId,\n    value: T,\n    render_fn: Box<dyn Fn(&T) -> AnyElement>,\n    cached_element: Option<AnyElement>,\n    last_value: Option<T>,\n}\n\nimpl<T: PartialEq + Clone + 'static> MemoizedElement<T> {\n    pub fn new<F>(id: ElementId, value: T, render_fn: F) -> Self\n    where\n        F: Fn(&T) -> AnyElement + 'static,\n    {\n        Self {\n            id,\n            value,\n            render_fn: Box::new(render_fn),\n            cached_element: None,\n            last_value: None,\n        }\n    }\n}\n\nimpl<T: PartialEq + Clone + 'static> Element for MemoizedElement<T> {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = ();\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, LayoutId) {\n        // Check if value changed\n        if self.last_value.as_ref() != Some(&self.value) || self.cached_element.is_none() {\n            // Recompute element\n            self.cached_element = Some((self.render_fn)(&self.value));\n            self.last_value = Some(self.value.clone());\n        }\n\n        // Request layout for cached element\n        let (layout_id, _) = self.cached_element\n            .as_mut()\n            .unwrap()\n            .request_layout(global_id, inspector_id, window, cx);\n\n        (layout_id, layout_id)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout_id: &mut LayoutId,\n        window: &mut Window,\n        cx: &mut App\n    ) -> () {\n        self.cached_element\n            .as_mut()\n            .unwrap()\n            .prepaint(global_id, inspector_id, bounds, window, cx);\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _layout_id: &mut LayoutId,\n        _: &mut (),\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        self.cached_element\n            .as_mut()\n            .unwrap()\n            .paint(global_id, inspector_id, bounds, window, cx);\n    }\n}\n\n// Usage\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    MemoizedElement::new(\n        ElementId::Name(\"memoized\".into()),\n        self.expensive_value.clone(),\n        |value| {\n            // Expensive rendering function only called when value changes\n            div().child(format!(\"Computed: {}\", value))\n        }\n    )\n}\n```\n\n## Virtual List Pattern\n\nEfficiently render large lists by only rendering visible items.\n\n```rust\npub struct VirtualList {\n    id: ElementId,\n    item_count: usize,\n    item_height: Pixels,\n    viewport_height: Pixels,\n    scroll_offset: Pixels,\n    render_item: Box<dyn Fn(usize) -> AnyElement>,\n}\n\nstruct VirtualListState {\n    visible_range: Range<usize>,\n    visible_item_layouts: Vec<LayoutId>,\n}\n\nimpl Element for VirtualList {\n    type RequestLayoutState = VirtualListState;\n    type PrepaintState = Hitbox;\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, VirtualListState) {\n        // Calculate visible range\n        let start_idx = (self.scroll_offset / self.item_height).floor() as usize;\n        let end_idx = ((self.scroll_offset + self.viewport_height) / self.item_height)\n            .ceil() as usize;\n        let visible_range = start_idx..end_idx.min(self.item_count);\n\n        // Request layout only for visible items\n        let visible_item_layouts: Vec<_> = visible_range.clone()\n            .map(|i| {\n                let mut item = (self.render_item)(i);\n                item.request_layout(global_id, inspector_id, window, cx).0\n            })\n            .collect();\n\n        let total_height = self.item_height * self.item_count as f32;\n        let layout_id = window.request_layout(\n            Style {\n                size: size(relative(1.0), self.viewport_height),\n                overflow: Overflow::Hidden,\n                ..default()\n            },\n            visible_item_layouts.clone(),\n            cx\n        );\n\n        (layout_id, VirtualListState {\n            visible_range,\n            visible_item_layouts,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        state: &mut VirtualListState,\n        window: &mut Window,\n        _cx: &mut App\n    ) -> Hitbox {\n        // Prepaint visible items at correct positions\n        for (i, layout_id) in state.visible_item_layouts.iter().enumerate() {\n            let item_idx = state.visible_range.start + i;\n            let y = item_idx as f32 * self.item_height - self.scroll_offset;\n            let item_bounds = Bounds::new(\n                point(bounds.left(), bounds.top() + y),\n                size(bounds.width(), self.item_height)\n            );\n\n            // Prepaint if visible\n            if item_bounds.intersects(&bounds) {\n                // Prepaint item...\n            }\n        }\n\n        window.insert_hitbox(bounds, HitboxBehavior::Normal)\n    }\n\n    fn paint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        state: &mut VirtualListState,\n        hitbox: &mut Hitbox,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint visible items\n        for (i, _layout_id) in state.visible_item_layouts.iter().enumerate() {\n            let item_idx = state.visible_range.start + i;\n            let y = item_idx as f32 * self.item_height - self.scroll_offset;\n            let item_bounds = Bounds::new(\n                point(bounds.left(), bounds.top() + y),\n                size(bounds.width(), self.item_height)\n            );\n\n            if item_bounds.intersects(&bounds) {\n                let mut item = (self.render_item)(item_idx);\n                item.paint(item_bounds, window, cx);\n            }\n        }\n\n        // Handle scroll\n        window.on_mouse_event({\n            let hitbox = hitbox.clone();\n            let total_height = self.item_height * self.item_count as f32;\n\n            move |event: &ScrollWheelEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    self.scroll_offset -= event.delta.y;\n                    self.scroll_offset = self.scroll_offset\n                        .max(px(0.))\n                        .min(total_height - self.viewport_height);\n                    cx.notify();\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\n// Usage: Efficiently render 10,000 items\nlet virtual_list = VirtualList {\n    id: ElementId::Name(\"large-list\".into()),\n    item_count: 10_000,\n    item_height: px(40.),\n    viewport_height: px(400.),\n    scroll_offset: px(0.),\n    render_item: Box::new(|index| {\n        div().child(format!(\"Item {}\", index))\n    }),\n};\n```\n\nThese advanced patterns enable sophisticated element implementations while maintaining performance and code quality.\n\n<!-- File: skills/gpui-kit/references/gpui/element-api.md (Tokens: ~2743 | Category: anthropic-skill) -->\n# Element API Reference\n\n**Contents:** [Element Trait Structure](#element-trait-structure) · [Associated Types](#associated-types) · [Methods](#methods) · [IntoElement Integration](#intoelement-integration) · [Layout System Integration](#layout-system-integration) · [Hitbox System](#hitbox-system) · [Event Handling](#event-handling) · [Cursor Styles](#cursor-styles)\n\n## Element Trait Structure\n\nThe `Element` trait requires implementing three associated types and five methods:\n\n```rust\npub trait Element: 'static + IntoElement {\n    type RequestLayoutState: 'static;\n    type PrepaintState: 'static;\n\n    fn id(&self) -> Option<ElementId>;\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>>;\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App,\n    ) -> (LayoutId, Self::RequestLayoutState);\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        request_layout: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App,\n    ) -> Self::PrepaintState;\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        request_layout: &mut Self::RequestLayoutState,\n        prepaint: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App,\n    );\n}\n```\n\n## Associated Types\n\n### RequestLayoutState\n\nData passed from `request_layout` to `prepaint` and `paint` phases.\n\n**Usage:**\n- Store layout calculations (styled text, child layout IDs)\n- Cache expensive computations\n- Pass child state between phases\n\n**Examples:**\n```rust\n// Simple: no state needed\ntype RequestLayoutState = ();\n\n// Single value\ntype RequestLayoutState = StyledText;\n\n// Multiple values\ntype RequestLayoutState = (StyledText, Vec<ChildLayout>);\n\n// Complex struct\npub struct MyLayoutState {\n    pub styled_text: StyledText,\n    pub child_layouts: Vec<(LayoutId, ChildState)>,\n    pub computed_bounds: Bounds<Pixels>,\n}\ntype RequestLayoutState = MyLayoutState;\n```\n\n### PrepaintState\n\nData passed from `prepaint` to `paint` phase.\n\n**Usage:**\n- Store hitboxes for interaction\n- Cache visual bounds\n- Store prepaint results\n\n**Examples:**\n```rust\n// Simple: just a hitbox\ntype PrepaintState = Hitbox;\n\n// Optional hitbox\ntype PrepaintState = Option<Hitbox>;\n\n// Multiple values\ntype PrepaintState = (Hitbox, Vec<Bounds<Pixels>>);\n\n// Complex struct\npub struct MyPaintState {\n    pub hitbox: Hitbox,\n    pub child_bounds: Vec<Bounds<Pixels>>,\n    pub visible_range: Range<usize>,\n}\ntype PrepaintState = MyPaintState;\n```\n\n## Methods\n\n### id()\n\nReturns optional unique identifier for debugging and inspection.\n\n```rust\nfn id(&self) -> Option<ElementId> {\n    Some(self.id.clone())\n}\n\n// Or if no ID needed\nfn id(&self) -> Option<ElementId> {\n    None\n}\n```\n\n### source_location()\n\nReturns source location for debugging. Usually returns `None` unless debugging is needed.\n\n```rust\nfn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n    None\n}\n```\n\n### request_layout()\n\nCalculates sizes and positions for the element tree.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Returns:**\n- `(LayoutId, Self::RequestLayoutState)`: Layout ID and state for next phases\n\n**Responsibilities:**\n1. Calculate child layouts by calling `child.request_layout()`\n2. Create own layout using `window.request_layout()`\n3. Return layout ID and state to pass to next phases\n\n**Example:**\n```rust\nfn request_layout(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    window: &mut Window,\n    cx: &mut App,\n) -> (LayoutId, Self::RequestLayoutState) {\n    // 1. Calculate child layouts\n    let child_layout_id = self.child.request_layout(\n        global_id,\n        inspector_id,\n        window,\n        cx\n    ).0;\n\n    // 2. Create own layout\n    let layout_id = window.request_layout(\n        Style {\n            size: size(px(200.), px(100.)),\n            ..default()\n        },\n        vec![child_layout_id],\n        cx\n    );\n\n    // 3. Return layout ID and state\n    (layout_id, MyLayoutState { child_layout_id })\n}\n```\n\n### prepaint()\n\nPrepares for painting by creating hitboxes and computing final bounds.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `bounds`: Final bounds calculated by layout engine\n- `request_layout`: Mutable reference to layout state\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Returns:**\n- `Self::PrepaintState`: State for paint phase\n\n**Responsibilities:**\n1. Compute final child bounds based on layout bounds\n2. Call `child.prepaint()` for all children\n3. Create hitboxes using `window.insert_hitbox()`\n4. Return state for paint phase\n\n**Example:**\n```rust\nfn prepaint(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    bounds: Bounds<Pixels>,\n    request_layout: &mut Self::RequestLayoutState,\n    window: &mut Window,\n    cx: &mut App,\n) -> Self::PrepaintState {\n    // 1. Compute child bounds\n    let child_bounds = bounds; // or calculated subset\n\n    // 2. Prepaint children\n    self.child.prepaint(\n        global_id,\n        inspector_id,\n        child_bounds,\n        &mut request_layout.child_state,\n        window,\n        cx\n    );\n\n    // 3. Create hitboxes\n    let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n    // 4. Return paint state\n    MyPaintState { hitbox }\n}\n```\n\n### paint()\n\nRenders the element and handles interactions.\n\n**Parameters:**\n- `global_id`: Global element identifier (optional)\n- `inspector_id`: Inspector element identifier (optional)\n- `bounds`: Final bounds for rendering\n- `request_layout`: Mutable reference to layout state\n- `prepaint`: Mutable reference to prepaint state\n- `window`: Mutable window reference\n- `cx`: Mutable app context\n\n**Responsibilities:**\n1. Paint children first (bottom to top)\n2. Paint own content (backgrounds, borders, etc.)\n3. Set up interactions (mouse events, cursor styles)\n\n**Example:**\n```rust\nfn paint(\n    &mut self,\n    global_id: Option<&GlobalElementId>,\n    inspector_id: Option<&InspectorElementId>,\n    bounds: Bounds<Pixels>,\n    request_layout: &mut Self::RequestLayoutState,\n    prepaint: &mut Self::PrepaintState,\n    window: &mut Window,\n    cx: &mut App,\n) {\n    // 1. Paint children first\n    self.child.paint(\n        global_id,\n        inspector_id,\n        child_bounds,\n        &mut request_layout.child_state,\n        &mut prepaint.child_paint_state,\n        window,\n        cx\n    );\n\n    // 2. Paint own content\n    window.paint_quad(paint_quad(\n        bounds,\n        Anchor::all(px(4.)),\n        cx.theme().background,\n    ));\n\n    // 3. Set up interactions\n    window.on_mouse_event({\n        let hitbox = prepaint.hitbox.clone();\n        move |event: &MouseDownEvent, phase, window, cx| {\n            if hitbox.is_hovered(window) && phase.bubble() {\n                // Handle click\n                cx.stop_propagation();\n            }\n        }\n    });\n\n    window.set_cursor_style(CursorStyle::PointingHand, &prepaint.hitbox);\n}\n```\n\n## IntoElement Integration\n\nElements must also implement `IntoElement` to be used as children:\n\n```rust\nimpl IntoElement for MyElement {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n```\n\nThis allows your custom element to be used directly in the element tree:\n\n```rust\ndiv()\n    .child(MyElement::new()) // Works because of IntoElement\n```\n\n## Common Parameters\n\n### Global and Inspector IDs\n\nBoth are optional identifiers used for debugging and inspection:\n- `global_id`: Unique identifier across entire app\n- `inspector_id`: Identifier for dev tools/inspector\n\nUsually passed through to children without modification.\n\n### Window and Context\n\n- `window: &mut Window`: Window-specific operations (painting, hitboxes, events)\n- `cx: &mut App`: App-wide operations (spawning tasks, accessing globals)\n\n## Layout System Integration\n\n### window.request_layout()\n\nCreates a layout node with specified style and children:\n\n```rust\nlet layout_id = window.request_layout(\n    Style {\n        size: size(px(200.), px(100.)),\n        flex: Flex::Column,\n        gap: px(8.),\n        ..default()\n    },\n    vec![child1_layout_id, child2_layout_id],\n    cx\n);\n```\n\n### Bounds<Pixels>\n\nRepresents rectangular region:\n\n```rust\npub struct Bounds<T> {\n    pub origin: Point<T>,\n    pub size: Size<T>,\n}\n\n// Create bounds\nlet bounds = Bounds::new(\n    point(px(10.), px(20.)),\n    size(px(100.), px(50.))\n);\n\n// Access properties\nbounds.left()    // origin.x\nbounds.top()     // origin.y\nbounds.right()   // origin.x + size.width\nbounds.bottom()  // origin.y + size.height\nbounds.center()  // center point\n```\n\n## Hitbox System\n\n### Creating Hitboxes\n\n```rust\n// Normal hitbox (blocks events)\nlet hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n// Transparent hitbox (passes events through)\nlet hitbox = window.insert_hitbox(bounds, HitboxBehavior::Transparent);\n```\n\n### Using Hitboxes\n\n```rust\n// Check if hovered\nif hitbox.is_hovered(window) {\n    // ...\n}\n\n// Set cursor style\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n\n// Use in event handlers\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    if hitbox.is_hovered(window) && phase.bubble() {\n        // Handle event\n    }\n});\n```\n\n## Event Handling\n\n### Mouse Events\n\n```rust\n// Mouse down\nwindow.on_mouse_event(move |event: &MouseDownEvent, phase, window, cx| {\n    if phase.bubble() && bounds.contains(&event.position) {\n        // Handle mouse down\n        cx.stop_propagation(); // Prevent bubbling\n    }\n});\n\n// Mouse up\nwindow.on_mouse_event(move |event: &MouseUpEvent, phase, window, cx| {\n    // Handle mouse up\n});\n\n// Mouse move\nwindow.on_mouse_event(move |event: &MouseMoveEvent, phase, window, cx| {\n    // Handle mouse move\n});\n\n// Scroll\nwindow.on_mouse_event(move |event: &ScrollWheelEvent, phase, window, cx| {\n    // Handle scroll\n});\n```\n\n### Event Phase\n\nEvents go through two phases:\n- **Capture**: Top-down (parent → child)\n- **Bubble**: Bottom-up (child → parent)\n\n```rust\nmove |event, phase, window, cx| {\n    if phase.capture() {\n        // Handle in capture phase\n    } else if phase.bubble() {\n        // Handle in bubble phase\n    }\n\n    cx.stop_propagation(); // Stop event from continuing\n}\n```\n\n## Cursor Styles\n\nAvailable cursor styles:\n\n```rust\nCursorStyle::Arrow\nCursorStyle::IBeam           // Text selection\nCursorStyle::PointingHand    // Clickable\nCursorStyle::ResizeLeft\nCursorStyle::ResizeRight\nCursorStyle::ResizeUp\nCursorStyle::ResizeDown\nCursorStyle::ResizeLeftRight\nCursorStyle::ResizeUpDown\nCursorStyle::Crosshair\nCursorStyle::OperationNotAllowed\n```\n\nUsage:\n\n```rust\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n```\n\n<!-- File: skills/gpui-kit/references/gpui/element-best-practices.md (Tokens: ~3166 | Category: anthropic-skill) -->\n# Element Best Practices\n\n**Contents:** [State Management](#state-management) · [Performance Considerations](#performance-considerations) · [Interaction Handling](#interaction-handling) · [Layout Strategies](#layout-strategies) · [Error Handling](#error-handling) · [Testing Element Implementations](#testing-element-implementations) · [Common Pitfalls](#common-pitfalls) · [Performance Checklist](#performance-checklist)\n\n## State Management\n\n### Using Associated Types Effectively\n\n**Good:** Use associated types to pass meaningful data between phases\n\n```rust\n// Good: Structured state with type safety\ntype RequestLayoutState = (StyledText, Vec<ChildLayout>);\ntype PrepaintState = (Hitbox, Vec<ChildBounds>);\n```\n\n**Bad:** Using empty state when you need data\n\n```rust\n// Bad: No state when you need to pass data\ntype RequestLayoutState = ();\ntype PrepaintState = ();\n// Now you can't pass layout info to paint phase!\n```\n\n### Managing Complex State\n\nFor elements with complex state, create dedicated structs:\n\n```rust\n// Good: Dedicated struct for complex state\npub struct TextElementState {\n    pub styled_text: StyledText,\n    pub text_layout: TextLayout,\n    pub child_states: Vec<ChildState>,\n}\n\ntype RequestLayoutState = TextElementState;\n```\n\n**Benefits:**\n- Clear documentation of state structure\n- Easy to extend\n- Type-safe access\n\n### State Lifecycle\n\n**Golden Rule:** State flows in one direction through the phases\n\n```\nrequest_layout → RequestLayoutState →\nprepaint → PrepaintState →\npaint\n```\n\n**Don't:**\n- Store state in the element struct that should be in associated types\n- Try to mutate element state in paint phase (use `cx.notify()` to schedule re-render)\n- Pass mutable references across phase boundaries\n\n## Performance Considerations\n\n### Minimize Allocations in Paint Phase\n\n**Critical:** Paint phase is called every frame during animations. Minimize allocations.\n\n**Good:** Pre-allocate in `request_layout` or `prepaint`\n\n```rust\nimpl Element for MyElement {\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Vec<StyledText>)\n    {\n        // Allocate once during layout\n        let styled_texts = self.children\n            .iter()\n            .map(|child| StyledText::new(child.text.clone()))\n            .collect();\n\n        (layout_id, styled_texts)\n    }\n\n    fn paint(&mut self, .., styled_texts: &mut Vec<StyledText>, ..) {\n        // Just use pre-allocated styled_texts\n        for text in styled_texts {\n            text.paint(..);\n        }\n    }\n}\n```\n\n**Bad:** Allocate in `paint` phase\n\n```rust\nfn paint(&mut self, ..) {\n    // Bad: Allocation in paint phase!\n    let styled_texts: Vec<_> = self.children\n        .iter()\n        .map(|child| StyledText::new(child.text.clone()))\n        .collect();\n}\n```\n\n### Cache Expensive Computations\n\nUse memoization for expensive operations:\n\n```rust\npub struct CachedElement {\n    // Cache key\n    last_text: Option<SharedString>,\n    last_width: Option<Pixels>,\n\n    // Cached result\n    cached_layout: Option<TextLayout>,\n}\n\nimpl Element for CachedElement {\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, TextLayout)\n    {\n        let current_width = window.bounds().width();\n\n        // Check if cache is valid\n        if self.last_text.as_ref() != Some(&self.text)\n            || self.last_width != Some(current_width)\n            || self.cached_layout.is_none()\n        {\n            // Recompute expensive layout\n            self.cached_layout = Some(self.compute_text_layout(current_width));\n            self.last_text = Some(self.text.clone());\n            self.last_width = Some(current_width);\n        }\n\n        // Use cached layout\n        let layout = self.cached_layout.as_ref().unwrap();\n        (layout_id, layout.clone())\n    }\n}\n```\n\n### Lazy Child Rendering\n\nOnly render visible children in scrollable containers:\n\n```rust\nfn paint(&mut self, .., bounds: Bounds<Pixels>, paint_state: &mut Self::PrepaintState, ..) {\n    for (i, child) in self.children.iter_mut().enumerate() {\n        let child_bounds = paint_state.child_bounds[i];\n\n        // Only paint visible children\n        if self.is_visible(&child_bounds, &bounds) {\n            child.paint(..);\n        }\n    }\n}\n\nfn is_visible(&self, child_bounds: &Bounds<Pixels>, container_bounds: &Bounds<Pixels>) -> bool {\n    child_bounds.bottom() >= container_bounds.top() &&\n    child_bounds.top() <= container_bounds.bottom()\n}\n```\n\n## Interaction Handling\n\n### Proper Event Bubbling\n\nAlways check phase and bounds before handling events:\n\n```rust\nfn paint(&mut self, .., window: &mut Window, cx: &mut App) {\n    window.on_mouse_event({\n        let hitbox = self.hitbox.clone();\n        move |event: &MouseDownEvent, phase, window, cx| {\n            // Check phase first\n            if !phase.bubble() {\n                return;\n            }\n\n            // Check if event is within bounds\n            if !hitbox.is_hovered(window) {\n                return;\n            }\n\n            // Handle event\n            self.handle_click(event);\n\n            // Stop propagation if handled\n            cx.stop_propagation();\n        }\n    });\n}\n```\n\n**Don't forget:**\n- Check `phase.bubble()` or `phase.capture()` as appropriate\n- Check hitbox hover state or bounds\n- Call `cx.stop_propagation()` if you handle the event\n\n### Hitbox Management\n\nCreate hitboxes in `prepaint` phase, not `paint`:\n\n**Good:**\n\n```rust\nfn prepaint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) -> Hitbox {\n    // Create hitbox in prepaint\n    window.insert_hitbox(bounds, HitboxBehavior::Normal)\n}\n\nfn paint(&mut self, .., hitbox: &mut Hitbox, window: &mut Window, ..) {\n    // Use hitbox in paint\n    window.set_cursor_style(CursorStyle::PointingHand, hitbox);\n}\n```\n\n**Hitbox Behaviors:**\n\n```rust\n// Normal: Blocks events from passing through\nHitboxBehavior::Normal\n\n// Transparent: Allows events to pass through to elements below\nHitboxBehavior::Transparent\n```\n\n### Cursor Style Guidelines\n\nSet appropriate cursor styles for interactivity cues:\n\n```rust\n// Text selection\nwindow.set_cursor_style(CursorStyle::IBeam, &hitbox);\n\n// Clickable elements (desktop convention: use default, not pointing hand)\nwindow.set_cursor_style(CursorStyle::Arrow, &hitbox);\n\n// Links (web convention: use pointing hand)\nwindow.set_cursor_style(CursorStyle::PointingHand, &hitbox);\n\n// Resizable edges\nwindow.set_cursor_style(CursorStyle::ResizeLeftRight, &hitbox);\n```\n\n**Desktop vs Web Convention:**\n- Desktop apps: Use `Arrow` for buttons\n- Web apps: Use `PointingHand` for links only\n\n## Layout Strategies\n\n### Fixed Size Elements\n\nFor elements with known, unchanging size:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App) -> (LayoutId, ()) {\n    let layout_id = window.request_layout(\n        Style {\n            size: size(px(200.), px(100.)),\n            ..default()\n        },\n        vec![], // No children\n        cx\n    );\n    (layout_id, ())\n}\n```\n\n### Content-Based Sizing\n\nFor elements sized by their content:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Size<Pixels>)\n{\n    // Measure content\n    let text_bounds = self.measure_text(window);\n    let padding = px(16.);\n\n    let layout_id = window.request_layout(\n        Style {\n            size: size(\n                text_bounds.width() + padding * 2.,\n                text_bounds.height() + padding * 2.,\n            ),\n            ..default()\n        },\n        vec![],\n        cx\n    );\n\n    (layout_id, text_bounds)\n}\n```\n\n### Flexible Layouts\n\nFor elements that adapt to available space:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Vec<LayoutId>)\n{\n    let mut child_layout_ids = Vec::new();\n\n    for child in &mut self.children {\n        let (layout_id, _) = child.request_layout(window, cx);\n        child_layout_ids.push(layout_id);\n    }\n\n    let layout_id = window.request_layout(\n        Style {\n            flex_direction: FlexDirection::Row,\n            gap: px(8.),\n            size: Size {\n                width: relative(1.0),  // Fill parent width\n                height: auto(),        // Auto height\n            },\n            ..default()\n        },\n        child_layout_ids.clone(),\n        cx\n    );\n\n    (layout_id, child_layout_ids)\n}\n```\n\n## Error Handling\n\n### Graceful Degradation\n\nHandle errors gracefully, don't panic:\n\n```rust\nfn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n    -> (LayoutId, Option<TextLayout>)\n{\n    // Try to create styled text\n    match StyledText::new(self.text.clone()).request_layout(None, None, window, cx) {\n        Ok((layout_id, text_layout)) => {\n            (layout_id, Some(text_layout))\n        }\n        Err(e) => {\n            // Log error\n            eprintln!(\"Failed to layout text: {}\", e);\n\n            // Fallback to simple text\n            let fallback_text = StyledText::new(\"(Error loading text)\".into());\n            let (layout_id, _) = fallback_text.request_layout(None, None, window, cx);\n            (layout_id, None)\n        }\n    }\n}\n```\n\n### Defensive Bounds Checking\n\nAlways validate bounds and indices:\n\n```rust\nfn paint_selection(&self, selection: &Selection, text_layout: &TextLayout, ..) {\n    // Validate selection bounds\n    let start = selection.start.min(self.text.len());\n    let end = selection.end.min(self.text.len());\n\n    if start >= end {\n        return; // Invalid selection\n    }\n\n    let rects = text_layout.rects_for_range(start..end);\n    // Paint selection...\n}\n```\n\n## Testing Element Implementations\n\n### Layout Tests\n\nTest that layout calculations are correct:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use gpui_kit::TestAppContext;\n\n    #[gpui_kit::test]\n    fn test_element_layout(cx: &mut TestAppContext) {\n        cx.update(|cx| {\n            let mut window = cx.open_window(Default::default(), |_, _| ()).unwrap();\n\n            window.update(cx, |window, cx| {\n                let mut element = MyElement::new();\n                let (layout_id, layout_state) = element.request_layout(\n                    None,\n                    None,\n                    window,\n                    cx\n                );\n\n                // Assert layout properties\n                let bounds = window.layout_bounds(layout_id);\n                assert_eq!(bounds.size.width, px(200.));\n                assert_eq!(bounds.size.height, px(100.));\n            });\n        });\n    }\n}\n```\n\n### Interaction Tests\n\nTest that interactions work correctly:\n\n```rust\n#[gpui_kit::test]\nfn test_element_click(cx: &mut TestAppContext) {\n    cx.update(|cx| {\n        let mut window = cx.open_window(Default::default(), |_, cx| {\n            cx.new(|_| MyElement::new())\n        }).unwrap();\n\n        window.update(cx, |window, cx| {\n            let view = window.root_view().unwrap();\n\n            // Simulate click\n            let position = point(px(10.), px(10.));\n            window.dispatch_event(MouseDownEvent {\n                position,\n                button: MouseButton::Left,\n                modifiers: Modifiers::default(),\n            });\n\n            // Assert element responded\n            view.read(cx).assert_clicked();\n        });\n    });\n}\n```\n\n## Common Pitfalls\n\n### ❌ Storing Layout State in Element Struct\n\n**Bad:**\n\n```rust\npub struct MyElement {\n    id: ElementId,\n    // Bad: This should be in RequestLayoutState\n    cached_layout: Option<TextLayout>,\n}\n```\n\n**Good:**\n\n```rust\npub struct MyElement {\n    id: ElementId,\n    text: SharedString,\n}\n\ntype RequestLayoutState = TextLayout; // Good: State in associated type\n```\n\n### ❌ Mutating Element in Paint Phase\n\n**Bad:**\n\n```rust\nfn paint(&mut self, ..) {\n    self.counter += 1; // Bad: Mutating element in paint\n}\n```\n\n**Good:**\n\n```rust\nfn paint(&mut self, .., window: &mut Window, cx: &mut App) {\n    window.on_mouse_event(move |event, phase, window, cx| {\n        if phase.bubble() {\n            self.counter += 1;\n            cx.notify(); // Schedule re-render\n        }\n    });\n}\n```\n\n### ❌ Creating Hitboxes in Paint Phase\n\n**Bad:**\n\n```rust\nfn paint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) {\n    // Bad: Creating hitbox in paint\n    let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n}\n```\n\n**Good:**\n\n```rust\nfn prepaint(&mut self, .., bounds: Bounds<Pixels>, window: &mut Window, ..) -> Hitbox {\n    // Good: Creating hitbox in prepaint\n    window.insert_hitbox(bounds, HitboxBehavior::Normal)\n}\n```\n\n### ❌ Ignoring Event Phase\n\n**Bad:**\n\n```rust\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    // Bad: Not checking phase\n    self.handle_click(event);\n});\n```\n\n**Good:**\n\n```rust\nwindow.on_mouse_event(move |event, phase, window, cx| {\n    // Good: Checking phase\n    if !phase.bubble() {\n        return;\n    }\n    self.handle_click(event);\n});\n```\n\n## Performance Checklist\n\nBefore shipping an element implementation, verify:\n\n- [ ] No allocations in `paint` phase (except event handlers)\n- [ ] Expensive computations are cached/memoized\n- [ ] Only visible children are rendered in scrollable containers\n- [ ] Hitboxes created in `prepaint`, not `paint`\n- [ ] Event handlers check phase and bounds\n- [ ] Layout state is passed through associated types, not stored in element\n- [ ] Element implements proper error handling with fallbacks\n- [ ] Tests cover layout calculations and interactions\n\n<!-- File: skills/gpui-kit/references/gpui/element-examples.md (Tokens: ~3685 | Category: anthropic-skill) -->\n# Element Implementation Examples\n\nComplete examples of implementing custom elements for various scenarios.\n\n## Table of Contents\n\n1. [Simple Text Element](#simple-text-element)\n2. [Interactive Element with Selection](#interactive-element-with-selection)\n3. [Complex Element with Child Management](#complex-element-with-child-management)\n\n## Simple Text Element\n\nA basic text element with syntax highlighting support.\n\n```rust\npub struct SimpleText {\n    id: ElementId,\n    text: SharedString,\n    highlights: Vec<(Range<usize>, HighlightStyle)>,\n}\n\nimpl IntoElement for SimpleText {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for SimpleText {\n    type RequestLayoutState = StyledText;\n    type PrepaintState = Hitbox;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        // Create styled text with highlights\n        let mut runs = Vec::new();\n        let mut ix = 0;\n\n        for (range, highlight) in &self.highlights {\n            // Add unstyled text before highlight\n            if ix < range.start {\n                runs.push(window.text_style().to_run(range.start - ix));\n            }\n\n            // Add highlighted text\n            runs.push(\n                window.text_style()\n                    .highlight(*highlight)\n                    .to_run(range.len())\n            );\n            ix = range.end;\n        }\n\n        // Add remaining unstyled text\n        if ix < self.text.len() {\n            runs.push(window.text_style().to_run(self.text.len() - ix));\n        }\n\n        let styled_text = StyledText::new(self.text.clone()).with_runs(runs);\n        let (layout_id, _) = styled_text.request_layout(\n            global_id,\n            inspector_id,\n            window,\n            cx\n        );\n\n        (layout_id, styled_text)\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        styled_text: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Self::PrepaintState {\n        // Prepaint the styled text\n        styled_text.prepaint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            window,\n            cx\n        );\n\n        // Create hitbox for interaction\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        hitbox\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        styled_text: &mut Self::RequestLayoutState,\n        hitbox: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint the styled text\n        styled_text.paint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            &mut (),\n            window,\n            cx\n        );\n\n        // Set cursor style for text\n        window.set_cursor_style(CursorStyle::IBeam, hitbox);\n    }\n}\n```\n\n## Interactive Element with Selection\n\nA text element that supports text selection via mouse interaction.\n\n```rust\n#[derive(Clone)]\npub struct Selection {\n    pub start: usize,\n    pub end: usize,\n}\n\npub struct SelectableText {\n    id: ElementId,\n    text: SharedString,\n    selectable: bool,\n    selection: Option<Selection>,\n}\n\nimpl IntoElement for SelectableText {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for SelectableText {\n    type RequestLayoutState = TextLayout;\n    type PrepaintState = Option<Hitbox>;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        let styled_text = StyledText::new(self.text.clone());\n        let (layout_id, _) = styled_text.request_layout(\n            global_id,\n            inspector_id,\n            window,\n            cx\n        );\n\n        // Extract text layout for selection painting\n        let text_layout = styled_text.layout().clone();\n\n        (layout_id, text_layout)\n    }\n\n    fn prepaint(\n        &mut self,\n        _global_id: Option<&GlobalElementId>,\n        _inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        _text_layout: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        _cx: &mut App\n    ) -> Self::PrepaintState {\n        // Only create hitbox if selectable\n        if self.selectable {\n            Some(window.insert_hitbox(bounds, HitboxBehavior::Normal))\n        } else {\n            None\n        }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        text_layout: &mut Self::RequestLayoutState,\n        hitbox: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint text\n        let styled_text = StyledText::new(self.text.clone());\n        styled_text.paint(\n            global_id,\n            inspector_id,\n            bounds,\n            &mut (),\n            &mut (),\n            window,\n            cx\n        );\n\n        // Paint selection if any\n        if let Some(selection) = &self.selection {\n            Self::paint_selection(selection, text_layout, &bounds, window, cx);\n        }\n\n        // Handle mouse events for selection\n        if let Some(hitbox) = hitbox {\n            window.set_cursor_style(CursorStyle::IBeam, hitbox);\n\n            // Mouse down to start selection\n            window.on_mouse_event({\n                let bounds = bounds.clone();\n                move |event: &MouseDownEvent, phase, window, cx| {\n                    if bounds.contains(&event.position) && phase.bubble() {\n                        // Start selection at mouse position\n                        let char_index = Self::position_to_index(\n                            event.position,\n                            &bounds,\n                            text_layout\n                        );\n                        self.selection = Some(Selection {\n                            start: char_index,\n                            end: char_index,\n                        });\n                        cx.notify();\n                        cx.stop_propagation();\n                    }\n                }\n            });\n\n            // Mouse drag to extend selection\n            window.on_mouse_event({\n                let bounds = bounds.clone();\n                move |event: &MouseMoveEvent, phase, window, cx| {\n                    if let Some(selection) = &mut self.selection {\n                        if phase.bubble() {\n                            let char_index = Self::position_to_index(\n                                event.position,\n                                &bounds,\n                                text_layout\n                            );\n                            selection.end = char_index;\n                            cx.notify();\n                        }\n                    }\n                }\n            });\n        }\n    }\n}\n\nimpl SelectableText {\n    fn paint_selection(\n        selection: &Selection,\n        text_layout: &TextLayout,\n        bounds: &Bounds<Pixels>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Calculate selection bounds from text layout\n        let selection_rects = text_layout.rects_for_range(\n            selection.start..selection.end\n        );\n\n        // Paint selection background\n        for rect in selection_rects {\n            window.paint_quad(paint_quad(\n                Bounds::new(\n                    point(bounds.left() + rect.origin.x, bounds.top() + rect.origin.y),\n                    rect.size\n                ),\n                Anchor::default(),\n                cx.theme().selection_background,\n            ));\n        }\n    }\n\n    fn position_to_index(\n        position: Point<Pixels>,\n        bounds: &Bounds<Pixels>,\n        text_layout: &TextLayout\n    ) -> usize {\n        // Convert screen position to character index\n        let relative_pos = point(\n            position.x - bounds.left(),\n            position.y - bounds.top()\n        );\n        text_layout.index_for_position(relative_pos)\n    }\n}\n```\n\n## Complex Element with Child Management\n\nA container element that manages multiple children with scrolling support.\n\n```rust\npub struct ComplexElement {\n    id: ElementId,\n    children: Vec<Box<dyn Element<RequestLayoutState = (), PrepaintState = ()>>>,\n    scrollable: bool,\n    scroll_offset: Point<Pixels>,\n}\n\nstruct ComplexLayoutState {\n    child_layouts: Vec<LayoutId>,\n    total_height: Pixels,\n}\n\nstruct ComplexPaintState {\n    child_bounds: Vec<Bounds<Pixels>>,\n    hitbox: Hitbox,\n}\n\nimpl IntoElement for ComplexElement {\n    type Element = Self;\n\n    fn into_element(self) -> Self::Element {\n        self\n    }\n}\n\nimpl Element for ComplexElement {\n    type RequestLayoutState = ComplexLayoutState;\n    type PrepaintState = ComplexPaintState;\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    fn request_layout(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        window: &mut Window,\n        cx: &mut App\n    ) -> (LayoutId, Self::RequestLayoutState) {\n        let mut child_layouts = Vec::new();\n        let mut total_height = px(0.);\n\n        // Request layout for all children\n        for child in &mut self.children {\n            let (child_layout_id, _) = child.request_layout(\n                global_id,\n                inspector_id,\n                window,\n                cx\n            );\n            child_layouts.push(child_layout_id);\n\n            // Get child size from layout\n            let child_size = window.layout_bounds(child_layout_id).size();\n            total_height += child_size.height;\n        }\n\n        // Create container layout\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: FlexDirection::Column,\n                gap: px(8.),\n                size: Size {\n                    width: relative(1.0),\n                    height: if self.scrollable {\n                        // Fixed height for scrollable\n                        px(400.)\n                    } else {\n                        // Auto height for non-scrollable\n                        total_height\n                    },\n                },\n                ..default()\n            },\n            child_layouts.clone(),\n            cx\n        );\n\n        (layout_id, ComplexLayoutState {\n            child_layouts,\n            total_height,\n        })\n    }\n\n    fn prepaint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut Self::RequestLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) -> Self::PrepaintState {\n        let mut child_bounds = Vec::new();\n        let mut y_offset = self.scroll_offset.y;\n\n        // Calculate child bounds and prepaint children\n        for (child, layout_id) in self.children.iter_mut()\n            .zip(&layout_state.child_layouts)\n        {\n            let child_size = window.layout_bounds(*layout_id).size();\n            let child_bound = Bounds::new(\n                point(bounds.left(), bounds.top() + y_offset),\n                child_size\n            );\n\n            // Only prepaint visible children\n            if self.is_visible(&child_bound, &bounds) {\n                child.prepaint(\n                    global_id,\n                    inspector_id,\n                    child_bound,\n                    &mut (),\n                    window,\n                    cx\n                );\n            }\n\n            child_bounds.push(child_bound);\n            y_offset += child_size.height + px(8.); // gap\n        }\n\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n        ComplexPaintState {\n            child_bounds,\n            hitbox,\n        }\n    }\n\n    fn paint(\n        &mut self,\n        global_id: Option<&GlobalElementId>,\n        inspector_id: Option<&InspectorElementId>,\n        bounds: Bounds<Pixels>,\n        layout_state: &mut Self::RequestLayoutState,\n        paint_state: &mut Self::PrepaintState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        // Paint background\n        window.paint_quad(paint_quad(\n            bounds,\n            Anchor::all(px(4.)),\n            cx.theme().background,\n        ));\n\n        // Paint visible children only\n        for (i, child) in self.children.iter_mut().enumerate() {\n            let child_bounds = paint_state.child_bounds[i];\n\n            if self.is_visible(&child_bounds, &bounds) {\n                child.paint(\n                    global_id,\n                    inspector_id,\n                    child_bounds,\n                    &mut (),\n                    &mut (),\n                    window,\n                    cx\n                );\n            }\n        }\n\n        // Paint scrollbar if scrollable\n        if self.scrollable {\n            self.paint_scrollbar(bounds, layout_state, window, cx);\n        }\n\n        // Handle scroll events\n        if self.scrollable {\n            window.on_mouse_event({\n                let hitbox = paint_state.hitbox.clone();\n                let total_height = layout_state.total_height;\n                let visible_height = bounds.size.height;\n\n                move |event: &ScrollWheelEvent, phase, window, cx| {\n                    if hitbox.is_hovered(window) && phase.bubble() {\n                        // Update scroll offset\n                        self.scroll_offset.y -= event.delta.y;\n\n                        // Clamp scroll offset\n                        let max_scroll = (total_height - visible_height).max(px(0.));\n                        self.scroll_offset.y = self.scroll_offset.y\n                            .max(px(0.))\n                            .min(max_scroll);\n\n                        cx.notify();\n                        cx.stop_propagation();\n                    }\n                }\n            });\n        }\n    }\n}\n\nimpl ComplexElement {\n    fn is_visible(&self, child_bounds: &Bounds<Pixels>, container_bounds: &Bounds<Pixels>) -> bool {\n        // Check if child is within visible area\n        child_bounds.bottom() >= container_bounds.top() &&\n        child_bounds.top() <= container_bounds.bottom()\n    }\n\n    fn paint_scrollbar(\n        &self,\n        bounds: Bounds<Pixels>,\n        layout_state: &ComplexLayoutState,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let scrollbar_width = px(8.);\n        let visible_height = bounds.size.height;\n        let total_height = layout_state.total_height;\n\n        if total_height <= visible_height {\n            return; // No need for scrollbar\n        }\n\n        // Calculate scrollbar position and size\n        let scroll_ratio = self.scroll_offset.y / (total_height - visible_height);\n        let thumb_height = (visible_height / total_height) * visible_height;\n        let thumb_y = scroll_ratio * (visible_height - thumb_height);\n\n        // Paint scrollbar track\n        let track_bounds = Bounds::new(\n            point(bounds.right() - scrollbar_width, bounds.top()),\n            size(scrollbar_width, visible_height)\n        );\n        window.paint_quad(paint_quad(\n            track_bounds,\n            Anchor::default(),\n            cx.theme().scrollbar_track,\n        ));\n\n        // Paint scrollbar thumb\n        let thumb_bounds = Bounds::new(\n            point(bounds.right() - scrollbar_width, bounds.top() + thumb_y),\n            size(scrollbar_width, thumb_height)\n        );\n        window.paint_quad(paint_quad(\n            thumb_bounds,\n            Anchor::all(px(4.)),\n            cx.theme().scrollbar_thumb,\n        ));\n    }\n}\n```\n\n## Usage Examples\n\n### Using SimpleText\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    div()\n        .child(SimpleText {\n            id: ElementId::Name(\"code-text\".into()),\n            text: \"fn main() { println!(\\\"Hello\\\"); }\".into(),\n            highlights: vec![\n                (0..2, HighlightStyle::keyword()),\n                (3..7, HighlightStyle::function()),\n            ],\n        })\n}\n```\n\n### Using SelectableText\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    div()\n        .child(SelectableText {\n            id: ElementId::Name(\"selectable-text\".into()),\n            text: \"Select this text with your mouse\".into(),\n            selectable: true,\n            selection: self.current_selection.clone(),\n        })\n}\n```\n\n### Using ComplexElement\n\n```rust\nfn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n    let children: Vec<Box<dyn Element<_, _>>> = self.items\n        .iter()\n        .map(|item| Box::new(div().child(item.name.clone())) as Box<_>)\n        .collect();\n\n    div()\n        .child(ComplexElement {\n            id: ElementId::Name(\"scrollable-list\".into()),\n            children,\n            scrollable: true,\n            scroll_offset: self.scroll_offset,\n        })\n}\n```\n\n<!-- File: skills/gpui-kit/references/gpui/element-id.md (Tokens: ~666 | Category: anthropic-skill) -->\n# ElementId\n\n`ElementId` is a unique identifier for a GPUI element. It is required for elements that need:\n- Mouse event handling (`on_click`, `on_hover`, etc.)\n- State storage via `window.use_keyed_state`\n- Interaction tracking\n\n## Making an Element Stateful\n\nCall `.id()` on a `div()` to create a `Stateful<Div>`:\n\n```rust\ndiv().id(\"my-element\")          // ElementId from &str\ndiv().id(42usize)               // ElementId from usize\ndiv().id(ElementId::from(idx))  // Explicit\n```\n\nWithout `.id()`, a div cannot receive mouse events or store state.\n\n## Accepted Types\n\n```rust\nimpl Into<ElementId> for &str      // \"my-id\"\nimpl Into<ElementId> for String    // String::from(\"my-id\")\nimpl Into<ElementId> for usize     // 0, 1, 2, ...\nimpl Into<ElementId> for u64\nimpl Into<ElementId> for SharedString\n```\n\n## Uniqueness Rules\n\nIDs must be unique within the same **stateful parent's scope** — not globally. GPUI builds a `GlobalElementId` by chaining parent IDs:\n\n```rust\ndiv().id(\"app\").child(\n    div().id(\"list1\").children(vec![\n        div().id(1usize).child(\"Item 1\"),  // GlobalId: [\"app\", \"list1\", 1]\n        div().id(2usize).child(\"Item 2\"),  // GlobalId: [\"app\", \"list1\", 2]\n    ])\n).child(\n    div().id(\"list2\").children(vec![\n        div().id(1usize).child(\"Item 1\"),  // GlobalId: [\"app\", \"list2\", 1] — no conflict\n    ])\n)\n```\n\nItems in different parent scopes can reuse simple IDs (integers, short strings).\n\n## In Component Structs\n\nComponents always store `id: ElementId` and pass it in `new()`:\n\n```rust\n#[derive(IntoElement)]\npub struct Button {\n    id: ElementId,\n    base: Stateful<Div>,\n    // ...\n}\n\nimpl Button {\n    pub fn new(id: impl Into<ElementId>) -> Self {\n        let id = id.into();\n        Self {\n            id: id.clone(),\n            base: div().id(id),  // id applied to base\n            // ...\n        }\n    }\n}\n\nimpl RenderOnce for Button {\n    fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {\n        self.base  // already has .id() applied\n            .on_click(/* ... */)\n    }\n}\n```\n\n## Usage at Call Sites\n\n```rust\n// Use unique string IDs for named components\nButton::new(\"save-btn\").label(\"Save\")\nButton::new(\"cancel-btn\").label(\"Cancel\")\n\n// Use index-based IDs in lists\nfor (i, item) in items.iter().enumerate() {\n    div().id(i)  // unique within this parent\n}\n\n// Use descriptive IDs for debugging\nInput::new(\"search-input\")\nSelect::new(\"country-select\")\n```\n\n<!-- File: skills/gpui-kit/references/gpui/element-patterns.md (Tokens: ~3265 | Category: anthropic-skill) -->\n# Common Element Patterns\n\n**Contents:** [Text Rendering Elements](#text-rendering-elements) · [Container Elements](#container-elements) · [Interactive Elements](#interactive-elements) · [Composite Elements](#composite-elements) · [Scrollable Elements](#scrollable-elements) · [Pattern Selection Guide](#pattern-selection-guide)\n\n## Text Rendering Elements\n\nElements that display and manipulate text content.\n\n### Pattern Characteristics\n\n- Use `StyledText` for text layout and rendering\n- Handle text selection in `paint` phase with hitbox interaction\n- Create hitboxes for text interaction in `prepaint`\n- Support text highlighting and custom styling via runs\n\n### Implementation Template\n\n```rust\npub struct TextElement {\n    id: ElementId,\n    text: SharedString,\n    style: TextStyle,\n}\n\nimpl Element for TextElement {\n    type RequestLayoutState = StyledText;\n    type PrepaintState = Hitbox;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, StyledText)\n    {\n        let styled_text = StyledText::new(self.text.clone())\n            .with_style(self.style);\n        let (layout_id, _) = styled_text.request_layout(None, None, window, cx);\n        (layout_id, styled_text)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, styled_text: &mut StyledText,\n                window: &mut Window, cx: &mut App) -> Hitbox\n    {\n        styled_text.prepaint(None, None, bounds, &mut (), window, cx);\n        window.insert_hitbox(bounds, HitboxBehavior::Normal)\n    }\n\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, styled_text: &mut StyledText,\n             hitbox: &mut Hitbox, window: &mut Window, cx: &mut App)\n    {\n        styled_text.paint(None, None, bounds, &mut (), &mut (), window, cx);\n        window.set_cursor_style(CursorStyle::IBeam, hitbox);\n    }\n}\n```\n\n### Use Cases\n\n- Code editors with syntax highlighting\n- Rich text displays\n- Labels with custom formatting\n- Selectable text areas\n\n## Container Elements\n\nElements that manage and layout child elements.\n\n### Pattern Characteristics\n\n- Manage child element layouts and positions\n- Handle scrolling and clipping when needed\n- Implement flex/grid-like layouts\n- Coordinate child interactions and event delegation\n\n### Implementation Template\n\n```rust\npub struct ContainerElement {\n    id: ElementId,\n    children: Vec<AnyElement>,\n    direction: FlexDirection,\n    gap: Pixels,\n}\n\nimpl Element for ContainerElement {\n    type RequestLayoutState = Vec<LayoutId>;\n    type PrepaintState = Vec<Bounds<Pixels>>;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Vec<LayoutId>)\n    {\n        let child_layout_ids: Vec<_> = self.children\n            .iter_mut()\n            .map(|child| child.request_layout(window, cx).0)\n            .collect();\n\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: self.direction,\n                gap: self.gap,\n                ..default()\n            },\n            child_layout_ids.clone(),\n            cx\n        );\n\n        (layout_id, child_layout_ids)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout_ids: &mut Vec<LayoutId>,\n                window: &mut Window, cx: &mut App) -> Vec<Bounds<Pixels>>\n    {\n        let mut child_bounds = Vec::new();\n\n        for (child, layout_id) in self.children.iter_mut().zip(layout_ids.iter()) {\n            let child_bound = window.layout_bounds(*layout_id);\n            child.prepaint(child_bound, window, cx);\n            child_bounds.push(child_bound);\n        }\n\n        child_bounds\n    }\n\n    fn paint(&mut self, .., child_bounds: &mut Vec<Bounds<Pixels>>,\n             window: &mut Window, cx: &mut App)\n    {\n        for (child, bounds) in self.children.iter_mut().zip(child_bounds.iter()) {\n            child.paint(*bounds, window, cx);\n        }\n    }\n}\n```\n\n### Use Cases\n\n- Panels and split views\n- List containers\n- Grid layouts\n- Tab containers\n\n## Interactive Elements\n\nElements that respond to user input (mouse, keyboard, touch).\n\n### Pattern Characteristics\n\n- Create appropriate hitboxes for interaction areas\n- Handle mouse/keyboard/touch events properly\n- Manage focus and cursor styles\n- Support hover, active, and disabled states\n\n### Implementation Template\n\n```rust\npub struct InteractiveElement {\n    id: ElementId,\n    content: AnyElement,\n    on_click: Option<Box<dyn Fn(&MouseUpEvent, &mut Window, &mut App)>>,\n    hover_style: Option<Style>,\n}\n\nimpl Element for InteractiveElement {\n    type RequestLayoutState = LayoutId;\n    type PrepaintState = (Hitbox, bool); // hitbox and is_hovered\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, LayoutId)\n    {\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        (content_layout, content_layout)\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, content_layout: &mut LayoutId,\n                window: &mut Window, cx: &mut App) -> (Hitbox, bool)\n    {\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        let is_hovered = hitbox.is_hovered(window);\n\n        self.content.prepaint(bounds, window, cx);\n\n        (hitbox, is_hovered)\n    }\n\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, content_layout: &mut LayoutId,\n             prepaint: &mut (Hitbox, bool), window: &mut Window, cx: &mut App)\n    {\n        let (hitbox, is_hovered) = prepaint;\n\n        // Paint hover background if hovered\n        if *is_hovered {\n            if let Some(hover_style) = &self.hover_style {\n                window.paint_quad(paint_quad(\n                    bounds,\n                    Anchor::all(px(4.)),\n                    hover_style.background_color.unwrap_or(cx.theme().hover),\n                ));\n            }\n        }\n\n        // Paint content\n        self.content.paint(bounds, window, cx);\n\n        // Handle click\n        if let Some(on_click) = self.on_click.as_ref() {\n            window.on_mouse_event({\n                let on_click = on_click.clone();\n                let hitbox = hitbox.clone();\n                move |event: &MouseUpEvent, phase, window, cx| {\n                    if hitbox.is_hovered(window) && phase.bubble() {\n                        on_click(event, window, cx);\n                        cx.stop_propagation();\n                    }\n                }\n            });\n        }\n\n        // Set cursor style\n        window.set_cursor_style(CursorStyle::PointingHand, hitbox);\n    }\n}\n```\n\n### Use Cases\n\n- Buttons\n- Links\n- Clickable cards\n- Drag handles\n- Menu items\n\n## Composite Elements\n\nElements that combine multiple child elements with complex coordination.\n\n### Pattern Characteristics\n\n- Combine multiple child elements with different types\n- Manage complex state across children\n- Coordinate animations and transitions\n- Handle focus delegation between children\n\n### Implementation Template\n\n```rust\npub struct CompositeElement {\n    id: ElementId,\n    header: AnyElement,\n    content: AnyElement,\n    footer: Option<AnyElement>,\n}\n\nstruct CompositeLayoutState {\n    header_layout: LayoutId,\n    content_layout: LayoutId,\n    footer_layout: Option<LayoutId>,\n}\n\nstruct CompositePaintState {\n    header_bounds: Bounds<Pixels>,\n    content_bounds: Bounds<Pixels>,\n    footer_bounds: Option<Bounds<Pixels>>,\n}\n\nimpl Element for CompositeElement {\n    type RequestLayoutState = CompositeLayoutState;\n    type PrepaintState = CompositePaintState;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, CompositeLayoutState)\n    {\n        let (header_layout, _) = self.header.request_layout(window, cx);\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        let footer_layout = self.footer.as_mut()\n            .map(|f| f.request_layout(window, cx).0);\n\n        let mut children = vec![header_layout, content_layout];\n        if let Some(footer) = footer_layout {\n            children.push(footer);\n        }\n\n        let layout_id = window.request_layout(\n            Style {\n                flex_direction: FlexDirection::Column,\n                size: Size {\n                    width: relative(1.0),\n                    height: auto(),\n                },\n                ..default()\n            },\n            children,\n            cx\n        );\n\n        (layout_id, CompositeLayoutState {\n            header_layout,\n            content_layout,\n            footer_layout,\n        })\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut CompositeLayoutState,\n                window: &mut Window, cx: &mut App) -> CompositePaintState\n    {\n        let header_bounds = window.layout_bounds(layout.header_layout);\n        let content_bounds = window.layout_bounds(layout.content_layout);\n        let footer_bounds = layout.footer_layout\n            .map(|id| window.layout_bounds(id));\n\n        self.header.prepaint(header_bounds, window, cx);\n        self.content.prepaint(content_bounds, window, cx);\n        if let (Some(footer), Some(bounds)) = (&mut self.footer, footer_bounds) {\n            footer.prepaint(bounds, window, cx);\n        }\n\n        CompositePaintState {\n            header_bounds,\n            content_bounds,\n            footer_bounds,\n        }\n    }\n\n    fn paint(&mut self, .., paint_state: &mut CompositePaintState,\n             window: &mut Window, cx: &mut App)\n    {\n        self.header.paint(paint_state.header_bounds, window, cx);\n        self.content.paint(paint_state.content_bounds, window, cx);\n        if let (Some(footer), Some(bounds)) = (&mut self.footer, paint_state.footer_bounds) {\n            footer.paint(bounds, window, cx);\n        }\n    }\n}\n```\n\n### Use Cases\n\n- Dialog boxes (header + content + footer)\n- Cards with multiple sections\n- Form layouts\n- Panels with toolbars\n\n## Scrollable Elements\n\nElements with scrollable content areas.\n\n### Pattern Characteristics\n\n- Manage scroll state (offset, velocity)\n- Handle scroll events (wheel, drag, touch)\n- Paint scrollbars (track and thumb)\n- Clip content to visible area\n\n### Implementation Template\n\n```rust\npub struct ScrollableElement {\n    id: ElementId,\n    content: AnyElement,\n    scroll_offset: Point<Pixels>,\n    content_size: Size<Pixels>,\n}\n\nstruct ScrollPaintState {\n    hitbox: Hitbox,\n    visible_bounds: Bounds<Pixels>,\n}\n\nimpl Element for ScrollableElement {\n    type RequestLayoutState = (LayoutId, Size<Pixels>);\n    type PrepaintState = ScrollPaintState;\n\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, (LayoutId, Size<Pixels>))\n    {\n        let (content_layout, _) = self.content.request_layout(window, cx);\n        let content_size = window.layout_bounds(content_layout).size;\n\n        let layout_id = window.request_layout(\n            Style {\n                size: Size {\n                    width: relative(1.0),\n                    height: px(400.), // Fixed viewport height\n                },\n                overflow: Overflow::Hidden,\n                ..default()\n            },\n            vec![content_layout],\n            cx\n        );\n\n        (layout_id, (content_layout, content_size))\n    }\n\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut (LayoutId, Size<Pixels>),\n                window: &mut Window, cx: &mut App) -> ScrollPaintState\n    {\n        let (content_layout, content_size) = layout;\n\n        // Calculate content bounds with scroll offset\n        let content_bounds = Bounds::new(\n            point(bounds.left(), bounds.top() - self.scroll_offset.y),\n            *content_size\n        );\n\n        self.content.prepaint(content_bounds, window, cx);\n\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n\n        ScrollPaintState {\n            hitbox,\n            visible_bounds: bounds,\n        }\n    }\n\n    fn paint(&mut self, .., layout: &mut (LayoutId, Size<Pixels>),\n             paint_state: &mut ScrollPaintState, window: &mut Window, cx: &mut App)\n    {\n        let (_, content_size) = layout;\n\n        // Paint content\n        self.content.paint(paint_state.visible_bounds, window, cx);\n\n        // Paint scrollbar\n        self.paint_scrollbar(paint_state.visible_bounds, *content_size, window, cx);\n\n        // Handle scroll events\n        window.on_mouse_event({\n            let hitbox = paint_state.hitbox.clone();\n            let content_height = content_size.height;\n            let visible_height = paint_state.visible_bounds.size.height;\n\n            move |event: &ScrollWheelEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Update scroll offset\n                    self.scroll_offset.y -= event.delta.y;\n\n                    // Clamp to valid range\n                    let max_scroll = (content_height - visible_height).max(px(0.));\n                    self.scroll_offset.y = self.scroll_offset.y\n                        .max(px(0.))\n                        .min(max_scroll);\n\n                    cx.notify();\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\nimpl ScrollableElement {\n    fn paint_scrollbar(\n        &self,\n        bounds: Bounds<Pixels>,\n        content_size: Size<Pixels>,\n        window: &mut Window,\n        cx: &mut App\n    ) {\n        let visible_height = bounds.size.height;\n        let content_height = content_size.height;\n\n        if content_height <= visible_height {\n            return; // No scrollbar needed\n        }\n\n        let scrollbar_width = px(8.);\n\n        // Calculate thumb position and size\n        let scroll_ratio = self.scroll_offset.y / (content_height - visible_height);\n        let thumb_height = (visible_height / content_height) * visible_height;\n        let thumb_y = scroll_ratio * (visible_height - thumb_height);\n\n        // Paint track\n        window.paint_quad(paint_quad(\n            Bounds::new(\n                point(bounds.right() - scrollbar_width, bounds.top()),\n                size(scrollbar_width, visible_height)\n            ),\n            Anchor::default(),\n            cx.theme().scrollbar_track,\n        ));\n\n        // Paint thumb\n        window.paint_quad(paint_quad(\n            Bounds::new(\n                point(bounds.right() - scrollbar_width, bounds.top() + thumb_y),\n                size(scrollbar_width, thumb_height)\n            ),\n            Anchor::all(px(4.)),\n            cx.theme().scrollbar_thumb,\n        ));\n    }\n}\n```\n\n### Use Cases\n\n- Scrollable lists\n- Code editors with large files\n- Long-form text content\n- Image galleries\n\n## Pattern Selection Guide\n\n| Need | Pattern | Complexity |\n|------|---------|------------|\n| Display styled text | Text Rendering | Low |\n| Layout multiple children | Container | Low-Medium |\n| Handle clicks/hovers | Interactive | Medium |\n| Complex multi-part UI | Composite | Medium-High |\n| Large content with scrolling | Scrollable | High |\n\nChoose the simplest pattern that meets your requirements, then extend as needed.\n\n<!-- File: skills/gpui-kit/references/gpui/element.md (Tokens: ~932 | Category: anthropic-skill) -->\n# Custom Elements\n\n**Contents:** [When to Use](#when-to-use) · [Quick Start](#quick-start) · [Core Concepts](#core-concepts) · [Reference Documentation](#reference-documentation)\n\n## When to Use\n\nUse the low-level `Element` trait when:\n- Need fine-grained control over layout calculation\n- Building complex, performance-critical components\n- Implementing custom layout algorithms (masonry, circular, etc.)\n- High-level `Render`/`RenderOnce` APIs are insufficient\n\n**Prefer `Render`/`RenderOnce` for:** Simple components, standard layouts, declarative UI\n\n## Quick Start\n\nThe `Element` trait provides direct control over three rendering phases:\n\n```rust\nimpl Element for MyElement {\n    type RequestLayoutState = MyLayoutState;  // Data passed to later phases\n    type PrepaintState = MyPaintState;        // Data for painting\n\n    fn id(&self) -> Option<ElementId> {\n        Some(self.id.clone())\n    }\n\n    fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {\n        None\n    }\n\n    // Phase 1: Calculate sizes and positions\n    fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)\n        -> (LayoutId, Self::RequestLayoutState)\n    {\n        let layout_id = window.request_layout(\n            Style { size: size(px(200.), px(100.)), ..default() },\n            vec![],\n            cx\n        );\n        (layout_id, MyLayoutState { /* ... */ })\n    }\n\n    // Phase 2: Create hitboxes, prepare for painting\n    fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,\n                window: &mut Window, cx: &mut App) -> Self::PrepaintState\n    {\n        let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);\n        MyPaintState { hitbox }\n    }\n\n    // Phase 3: Render and handle interactions\n    fn paint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,\n             paint_state: &mut Self::PrepaintState, window: &mut Window, cx: &mut App)\n    {\n        window.paint_quad(paint_quad(bounds, Anchor::all(px(4.)), cx.theme().background));\n\n        window.on_mouse_event({\n            let hitbox = paint_state.hitbox.clone();\n            move |event: &MouseDownEvent, phase, window, cx| {\n                if hitbox.is_hovered(window) && phase.bubble() {\n                    // Handle interaction\n                    cx.stop_propagation();\n                }\n            }\n        });\n    }\n}\n\n// Enable element to be used as child\nimpl IntoElement for MyElement {\n    type Element = Self;\n    fn into_element(self) -> Self::Element { self }\n}\n```\n\n## Core Concepts\n\n### Three-Phase Rendering\n\n1. **request_layout**: Calculate sizes and positions, return layout ID and state\n2. **prepaint**: Create hitboxes, compute final bounds, prepare for painting\n3. **paint**: Render element, set up interactions (mouse events, cursor styles)\n\n### State Flow\n\n```\nRequestLayoutState → PrepaintState → paint\n```\n\nState flows in one direction through associated types, passed as mutable references between phases.\n\n### Key Operations\n\n- **Layout**: `window.request_layout(style, children, cx)` - Create layout node\n- **Hitboxes**: `window.insert_hitbox(bounds, behavior)` - Create interaction area\n- **Painting**: `window.paint_quad(...)` - Render visual content\n- **Events**: `window.on_mouse_event(handler)` - Handle user input\n\n## Reference Documentation\n\n### Complete API Documentation\n- **API**: See [element-api.md](element-api.md) — associated types, hitbox system, event handling, cursor styles\n- **Examples**: See [element-examples.md](element-examples.md) — text, interactive, complex elements\n- **Patterns**: See [element-patterns.md](element-patterns.md) — text, container, interactive, composite, scrollable\n- **Best Practices**: See [element-best-practices.md](element-best-practices.md) — performance, state, common pitfalls\n- **Advanced**: See [element-advanced.md](element-advanced.md) — masonry/circular layouts, memoization, virtual lists\n\n<!-- File: skills/gpui-kit/references/gpui/entity-advanced.md (Tokens: ~3054 | Category: anthropic-skill) -->\n# Advanced Entity Patterns\n\n**Contents:** [Entity Collections Management](#entity-collections-management) · [Conditional Update Patterns](#conditional-update-patterns) · [Entity State Machine Pattern](#entity-state-machine-pattern) · [Entity Proxy Pattern](#entity-proxy-pattern) · [Cascading Updates Pattern](#cascading-updates-pattern) · [Entity Snapshot Pattern](#entity-snapshot-pattern) · [Entity Transaction Pattern](#entity-transaction-pattern) · [Entity Pool Pattern](#entity-pool-pattern)\n\n## Entity Collections Management\n\n### Dynamic Collection with Cleanup\n\n```rust\nstruct EntityCollection<T> {\n    strong_refs: Vec<Entity<T>>,\n    weak_refs: Vec<WeakEntity<T>>,\n}\n\nimpl<T> EntityCollection<T> {\n    fn new() -> Self {\n        Self {\n            strong_refs: Vec::new(),\n            weak_refs: Vec::new(),\n        }\n    }\n\n    fn add(&mut self, entity: Entity<T>, cx: &mut App) {\n        self.strong_refs.push(entity.clone());\n        self.weak_refs.push(entity.downgrade());\n    }\n\n    fn remove(&mut self, entity_id: EntityId, cx: &mut App) {\n        self.strong_refs.retain(|e| e.entity_id() != entity_id);\n        self.weak_refs.retain(|w| {\n            w.upgrade()\n                .map(|e| e.entity_id() != entity_id)\n                .unwrap_or(false)\n        });\n    }\n\n    fn cleanup_invalid(&mut self, cx: &mut App) {\n        self.weak_refs.retain(|weak| weak.upgrade().is_some());\n    }\n\n    fn for_each<F>(&self, cx: &mut App, mut f: F)\n    where\n        F: FnMut(&Entity<T>, &mut App),\n    {\n        for entity in &self.strong_refs {\n            f(entity, cx);\n        }\n    }\n\n    fn for_each_weak<F>(&mut self, cx: &mut App, mut f: F)\n    where\n        F: FnMut(Entity<T>, &mut App),\n    {\n        self.weak_refs.retain(|weak| {\n            if let Some(entity) = weak.upgrade() {\n                f(entity, cx);\n                true\n            } else {\n                false // Remove invalid weak references\n            }\n        });\n    }\n}\n```\n\n### Entity Registry Pattern\n\n```rust\nuse std::collections::HashMap;\n\nstruct EntityRegistry<T> {\n    entities: HashMap<EntityId, WeakEntity<T>>,\n}\n\nimpl<T> EntityRegistry<T> {\n    fn new() -> Self {\n        Self {\n            entities: HashMap::new(),\n        }\n    }\n\n    fn register(&mut self, entity: &Entity<T>) {\n        self.entities.insert(entity.entity_id(), entity.downgrade());\n    }\n\n    fn unregister(&mut self, entity_id: EntityId) {\n        self.entities.remove(&entity_id);\n    }\n\n    fn get(&self, entity_id: EntityId) -> Option<Entity<T>> {\n        self.entities.get(&entity_id)?.upgrade()\n    }\n\n    fn cleanup(&mut self) {\n        self.entities.retain(|_, weak| weak.upgrade().is_some());\n    }\n\n    fn count(&self) -> usize {\n        self.entities.len()\n    }\n\n    fn all_entities(&self) -> Vec<Entity<T>> {\n        self.entities\n            .values()\n            .filter_map(|weak| weak.upgrade())\n            .collect()\n    }\n}\n```\n\n## Conditional Update Patterns\n\n### Debounced Updates\n\n```rust\nuse std::time::{Duration, Instant};\n\nstruct DebouncedEntity<T> {\n    entity: Entity<T>,\n    last_update: Instant,\n    debounce_duration: Duration,\n    pending_update: Option<Box<dyn FnOnce(&mut T, &mut Context<T>)>>,\n}\n\nimpl<T: 'static> DebouncedEntity<T> {\n    fn new(entity: Entity<T>, debounce_ms: u64) -> Self {\n        Self {\n            entity,\n            last_update: Instant::now(),\n            debounce_duration: Duration::from_millis(debounce_ms),\n            pending_update: None,\n        }\n    }\n\n    fn update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: FnOnce(&mut T, &mut Context<T>) + 'static,\n    {\n        let now = Instant::now();\n        let elapsed = now.duration_since(self.last_update);\n\n        if elapsed >= self.debounce_duration {\n            // Execute immediately\n            self.entity.update(cx, update_fn);\n            self.last_update = now;\n            self.pending_update = None;\n        } else {\n            // Store for later\n            self.pending_update = Some(Box::new(update_fn));\n\n            // Schedule execution\n            let entity = self.entity.clone();\n            let delay = self.debounce_duration - elapsed;\n\n            cx.spawn(async move |cx| {\n                tokio::time::sleep(delay).await;\n\n                if let Some(update) = self.pending_update.take() {\n                    entity.update(cx, |state, inner_cx| {\n                        update(state, inner_cx);\n                    });\n                }\n            }).detach();\n        }\n    }\n}\n```\n\n### Throttled Updates\n\n```rust\nstruct ThrottledEntity<T> {\n    entity: Entity<T>,\n    last_update: Instant,\n    throttle_duration: Duration,\n}\n\nimpl<T: 'static> ThrottledEntity<T> {\n    fn new(entity: Entity<T>, throttle_ms: u64) -> Self {\n        Self {\n            entity,\n            last_update: Instant::now(),\n            throttle_duration: Duration::from_millis(throttle_ms),\n        }\n    }\n\n    fn try_update<F>(&mut self, cx: &mut App, update_fn: F) -> bool\n    where\n        F: FnOnce(&mut T, &mut Context<T>),\n    {\n        let now = Instant::now();\n        let elapsed = now.duration_since(self.last_update);\n\n        if elapsed >= self.throttle_duration {\n            self.entity.update(cx, update_fn);\n            self.last_update = now;\n            true\n        } else {\n            false // Update throttled\n        }\n    }\n}\n```\n\n## Entity State Machine Pattern\n\n```rust\nenum AppState {\n    Idle,\n    Loading,\n    Loaded(String),\n    Error(String),\n}\n\nstruct StateMachine {\n    state: AppState,\n}\n\nimpl StateMachine {\n    fn new() -> Self {\n        Self {\n            state: AppState::Idle,\n        }\n    }\n\n    fn start_loading(&mut self, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Idle | AppState::Error(_)) {\n            self.state = AppState::Loading;\n            cx.notify();\n\n            let weak_entity = cx.entity().downgrade();\n\n            cx.spawn(async move |cx| {\n                let result = perform_load().await;\n\n                let _ = weak_entity.update(cx, |state, cx| {\n                    match result {\n                        Ok(data) => state.on_load_success(data, cx),\n                        Err(e) => state.on_load_error(e.to_string(), cx),\n                    }\n                });\n            }).detach();\n        }\n    }\n\n    fn on_load_success(&mut self, data: String, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Loading) {\n            self.state = AppState::Loaded(data);\n            cx.notify();\n        }\n    }\n\n    fn on_load_error(&mut self, error: String, cx: &mut Context<Self>) {\n        if matches!(self.state, AppState::Loading) {\n            self.state = AppState::Error(error);\n            cx.notify();\n        }\n    }\n\n    fn reset(&mut self, cx: &mut Context<Self>) {\n        self.state = AppState::Idle;\n        cx.notify();\n    }\n}\n\nasync fn perform_load() -> Result<String, anyhow::Error> {\n    // Actual load implementation\n    Ok(\"Data\".to_string())\n}\n```\n\n## Entity Proxy Pattern\n\n```rust\nstruct EntityProxy<T> {\n    entity: WeakEntity<T>,\n}\n\nimpl<T> EntityProxy<T> {\n    fn new(entity: &Entity<T>) -> Self {\n        Self {\n            entity: entity.downgrade(),\n        }\n    }\n\n    fn with<F, R>(&self, cx: &mut App, f: F) -> Result<R, anyhow::Error>\n    where\n        F: FnOnce(&T, &App) -> R,\n    {\n        self.entity.read_with(cx, f)\n    }\n\n    fn update<F, R>(&self, cx: &mut App, f: F) -> Result<R, anyhow::Error>\n    where\n        F: FnOnce(&mut T, &mut Context<T>) -> R,\n    {\n        self.entity.update(cx, f)\n    }\n\n    fn is_valid(&self, cx: &App) -> bool {\n        self.entity.upgrade().is_some()\n    }\n}\n```\n\n## Cascading Updates Pattern\n\n```rust\nstruct CascadingUpdater {\n    entities: Vec<WeakEntity<UpdateTarget>>,\n}\n\nimpl CascadingUpdater {\n    fn new() -> Self {\n        Self {\n            entities: Vec::new(),\n        }\n    }\n\n    fn add_target(&mut self, entity: &Entity<UpdateTarget>) {\n        self.entities.push(entity.downgrade());\n    }\n\n    fn cascade_update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: Fn(&mut UpdateTarget, &mut Context<UpdateTarget>) + Clone,\n    {\n        // Update all entities in sequence\n        self.entities.retain(|weak| {\n            if let Ok(_) = weak.update(cx, |state, inner_cx| {\n                update_fn.clone()(state, inner_cx);\n            }) {\n                true // Keep valid entity\n            } else {\n                false // Remove invalid entity\n            }\n        });\n    }\n}\n\nstruct UpdateTarget {\n    value: i32,\n}\n```\n\n## Entity Snapshot Pattern\n\n```rust\nuse serde::{Serialize, Deserialize};\n\n#[derive(Clone, Serialize, Deserialize)]\nstruct EntitySnapshot {\n    data: String,\n    timestamp: u64,\n}\n\nstruct SnapshotableEntity {\n    data: String,\n    snapshots: Vec<EntitySnapshot>,\n}\n\nimpl SnapshotableEntity {\n    fn new(data: String) -> Self {\n        Self {\n            data,\n            snapshots: Vec::new(),\n        }\n    }\n\n    fn take_snapshot(&mut self, cx: &mut Context<Self>) {\n        let snapshot = EntitySnapshot {\n            data: self.data.clone(),\n            timestamp: current_timestamp(),\n        };\n        self.snapshots.push(snapshot);\n        cx.notify();\n    }\n\n    fn restore_snapshot(&mut self, index: usize, cx: &mut Context<Self>) -> Result<(), String> {\n        if let Some(snapshot) = self.snapshots.get(index) {\n            self.data = snapshot.data.clone();\n            cx.notify();\n            Ok(())\n        } else {\n            Err(\"Invalid snapshot index\".to_string())\n        }\n    }\n\n    fn clear_old_snapshots(&mut self, keep_last: usize, cx: &mut Context<Self>) {\n        if self.snapshots.len() > keep_last {\n            self.snapshots.drain(0..self.snapshots.len() - keep_last);\n            cx.notify();\n        }\n    }\n}\n\nfn current_timestamp() -> u64 {\n    use std::time::{SystemTime, UNIX_EPOCH};\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .unwrap()\n        .as_secs()\n}\n```\n\n## Entity Transaction Pattern\n\n```rust\nstruct Transaction<T> {\n    entity: Entity<T>,\n    original_state: Option<T>,\n}\n\nimpl<T: Clone> Transaction<T> {\n    fn begin(entity: Entity<T>, cx: &mut App) -> Self {\n        let original_state = entity.read(cx).clone();\n\n        Self {\n            entity,\n            original_state: Some(original_state),\n        }\n    }\n\n    fn update<F>(&mut self, cx: &mut App, update_fn: F)\n    where\n        F: FnOnce(&mut T, &mut Context<T>),\n    {\n        self.entity.update(cx, update_fn);\n    }\n\n    fn commit(mut self, cx: &mut App) {\n        self.original_state = None; // Don't rollback\n        self.entity.update(cx, |_, cx| {\n            cx.notify();\n        });\n    }\n\n    fn rollback(mut self, cx: &mut App) {\n        if let Some(original) = self.original_state.take() {\n            self.entity.update(cx, |state, cx| {\n                *state = original;\n                cx.notify();\n            });\n        }\n    }\n}\n\nimpl<T> Drop for Transaction<T> {\n    fn drop(&mut self) {\n        // Auto-rollback if not committed\n        if self.original_state.is_some() {\n            eprintln!(\"Warning: Transaction dropped without commit\");\n        }\n    }\n}\n\n// Usage\nfn perform_transaction(entity: Entity<MyState>, cx: &mut App) -> Result<(), String> {\n    let mut tx = Transaction::begin(entity, cx);\n\n    tx.update(cx, |state, cx| {\n        state.value = 42;\n    });\n\n    if validate_state(&tx.entity, cx)? {\n        tx.commit(cx);\n        Ok(())\n    } else {\n        tx.rollback(cx);\n        Err(\"Validation failed\".to_string())\n    }\n}\n```\n\n## Entity Pool Pattern\n\n```rust\nstruct EntityPool<T> {\n    available: Vec<Entity<T>>,\n    in_use: Vec<WeakEntity<T>>,\n    factory: Box<dyn Fn(&mut App) -> Entity<T>>,\n}\n\nimpl<T: 'static> EntityPool<T> {\n    fn new<F>(factory: F) -> Self\n    where\n        F: Fn(&mut App) -> Entity<T> + 'static,\n    {\n        Self {\n            available: Vec::new(),\n            in_use: Vec::new(),\n            factory: Box::new(factory),\n        }\n    }\n\n    fn acquire(&mut self, cx: &mut App) -> Entity<T> {\n        let entity = if let Some(entity) = self.available.pop() {\n            entity\n        } else {\n            (self.factory)(cx)\n        };\n\n        self.in_use.push(entity.downgrade());\n        entity\n    }\n\n    fn release(&mut self, entity: Entity<T>, cx: &mut App) {\n        // Reset entity state if needed\n        entity.update(cx, |state, cx| {\n            // Reset logic here\n            cx.notify();\n        });\n\n        self.available.push(entity);\n        self.cleanup_in_use();\n    }\n\n    fn cleanup_in_use(&mut self) {\n        self.in_use.retain(|weak| weak.upgrade().is_some());\n    }\n\n    fn pool_size(&self) -> (usize, usize) {\n        (self.available.len(), self.in_use.len())\n    }\n}\n```\n\nThese advanced patterns provide powerful abstractions for managing complex entity scenarios while maintaining code quality and performance.\n\n<!-- File: skills/gpui-kit/references/gpui/entity-api.md (Tokens: ~2161 | Category: anthropic-skill) -->\n# Entity API Reference\n\n**Contents:** [Entity Types](#entity-types) · [Entity Creation](#entity-creation) · [Entity Operations](#entity-operations) · [Context Methods](#context-methods-for-entities) · [Async Operations](#async-operations) · [Entity Lifecycle](#entity-lifecycle) · [EntityId](#entityid) · [Error Handling](#error-handling) · [Type Conversions](#type-conversions)\n\n## Entity Types\n\n### Entity<T>\n\nA strong reference to state of type `T`.\n\n**Methods:**\n- `entity_id()` → `EntityId` - Returns unique identifier\n- `downgrade()` → `WeakEntity<T>` - Creates weak reference\n- `read(cx)` → `&T` - Immutable access to state\n- `read_with(cx, |state, cx| ...)` → `R` - Read with closure, returns closure result\n- `update(cx, |state, cx| ...)` → `R` - Mutable update with `Context<T>`, returns closure result\n- `update_in(cx, |state, window, cx| ...)` → `R` - Update with `Window` access (requires `AsyncWindowContext` or `VisualTestContext`)\n\n**Important Notes:**\n- Trying to update an entity while it's already being updated will panic\n- Within closures, use the inner `cx` provided to avoid multiple borrow issues\n- With async contexts, return values are wrapped in `anyhow::Result`\n\n### WeakEntity<T>\n\nA weak reference to state of type `T`.\n\n**Methods:**\n- `upgrade()` → `Option<Entity<T>>` - Convert to strong reference if still alive\n- `read_with(cx, |state, cx| ...)` → `Result<R>` - Read if entity exists\n- `update(cx, |state, cx| ...)` → `Result<R>` - Update if entity exists\n- `update_in(cx, |state, window, cx| ...)` → `Result<R>` - Update with window if entity exists\n\n**Use Cases:**\n- Avoid circular dependencies between entities\n- Store references in closures/callbacks without preventing cleanup\n- Optional relationships between components\n\n**Important:** All operations return `Result` since the entity may no longer exist.\n\n### AnyEntity\n\nDynamically-typed entity handle for storing entities of different types.\n\n### AnyWeakEntity\n\nDynamically-typed weak entity handle.\n\n## Entity Creation\n\n### cx.new()\n\nCreate new entity with initial state.\n\n```rust\nlet entity = cx.new(|cx| MyState {\n    count: 0,\n    name: \"Default\".to_string(),\n});\n```\n\n**Parameters:**\n- `cx: &mut App` or other context type\n- Closure receiving `&mut Context<T>` returning initial state `T`\n\n**Returns:** `Entity<T>`\n\n## Entity Operations\n\n### Reading State\n\n#### read()\n\nDirect read-only access to state.\n\n```rust\nlet count = my_entity.read(cx).count;\n```\n\n**Use when:** Simple field access, no context operations needed.\n\n#### read_with()\n\nRead with context access in closure.\n\n```rust\nlet count = my_entity.read_with(cx, |state, cx| {\n    // Can access both state and context\n    state.count\n});\n\n// Return multiple values\nlet (count, theme) = my_entity.read_with(cx, |state, cx| {\n    (state.count, cx.theme().clone())\n});\n```\n\n**Use when:** Need context operations, multiple return values, complex logic.\n\n### Updating State\n\n#### update()\n\nMutable update with `Context<T>`.\n\n```rust\nmy_entity.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify(); // Trigger re-render\n});\n```\n\n**Available Operations:**\n- `cx.notify()` - Trigger re-render\n- `cx.entity()` - Get current entity\n- `cx.emit(event)` - Emit event\n- `cx.spawn(task)` - Spawn async task\n- Other `Context<T>` methods\n\n#### update_in()\n\nUpdate with both `Window` and `Context<T>` access.\n\n```rust\nmy_entity.update_in(cx, |state, window, cx| {\n    state.focused = window.is_window_focused();\n    cx.notify();\n});\n```\n\n**Requires:** `AsyncWindowContext` or `VisualTestContext`\n\n**Use when:** Need window-specific operations like focus state, window bounds, etc.\n\n## Context Methods for Entities\n\n### cx.entity()\n\nGet current entity being updated.\n\n```rust\nimpl MyComponent {\n    fn some_method(&mut self, cx: &mut Context<Self>) {\n        let current_entity = cx.entity();  // Entity<MyComponent>\n        let weak = current_entity.downgrade();\n    }\n}\n```\n\n### cx.observe()\n\nObserve entity for changes.\n\n```rust\ncx.observe(&entity, |this, observed_entity, cx| {\n    // Called when observed_entity.update() calls cx.notify()\n    println!(\"Entity changed\");\n}).detach();\n```\n\n**Returns:** `Subscription` - Call `.detach()` to make permanent\n\n### cx.subscribe()\n\nSubscribe to events from entity.\n\n```rust\ncx.subscribe(&entity, |this, emitter, event: &SomeEvent, cx| {\n    // Called when emitter emits SomeEvent\n    match event {\n        SomeEvent::DataChanged => {\n            cx.notify();\n        }\n    }\n}).detach();\n```\n\n**Returns:** `Subscription` - Call `.detach()` to make permanent\n\n### cx.observe_new_entities()\n\nRegister callback for new entities of a type.\n\n```rust\ncx.observe_new_entities::<MyState>(|entity, cx| {\n    println!(\"New entity created: {:?}\", entity.entity_id());\n}).detach();\n```\n\n## Async Operations\n\n### cx.spawn()\n\nSpawn foreground task (UI thread).\n\n```rust\ncx.spawn(async move |this, cx| {\n    // `this`: WeakEntity<T>\n    // `cx`: &mut AsyncApp\n\n    let result = some_async_work().await;\n\n    // Update entity safely\n    let _ = this.update(cx, |state, cx| {\n        state.data = result;\n        cx.notify();\n    });\n}).detach();\n```\n\n**Note:** Always use weak entity reference in spawned tasks to prevent retain cycles.\n\n### cx.background_spawn()\n\nSpawn background task (background thread).\n\n```rust\ncx.background_spawn(async move {\n    // Long-running computation\n    let result = heavy_computation().await;\n    // Cannot directly update entities here\n    // Use channels or spawn foreground task to update\n}).detach();\n```\n\n## Entity Lifecycle\n\n### Creation\n\nEntities are created via `cx.new()` and immediately registered in the app.\n\n### Reference Counting\n\n- `Entity<T>` is a strong reference (increases reference count)\n- `WeakEntity<T>` is a weak reference (does not increase reference count)\n- Cloning `Entity<T>` increases reference count\n\n### Disposal\n\nEntities are automatically disposed when all strong references are dropped.\n\n```rust\n{\n    let entity = cx.new(|cx| MyState::default());\n    // entity exists\n} // entity dropped here if no other strong references exist\n```\n\n**Memory Leak Prevention:**\n- Use `WeakEntity` in closures/callbacks\n- Use `WeakEntity` for parent-child relationships\n- Avoid circular strong references\n\n## EntityId\n\nEvery entity has a unique identifier.\n\n```rust\nlet id: EntityId = entity.entity_id();\n\n// EntityIds can be compared\nif entity1.entity_id() == entity2.entity_id() {\n    // Same entity\n}\n```\n\n**Use Cases:**\n- Debugging and logging\n- Entity comparison without borrowing\n- Hash maps keyed by entity\n\n## Error Handling\n\n### WeakEntity Operations\n\nAll `WeakEntity` operations return `Result`:\n\n```rust\nlet weak = entity.downgrade();\n\n// Handle potential failure\nmatch weak.read_with(cx, |state, cx| state.count) {\n    Ok(count) => println!(\"Count: {}\", count),\n    Err(e) => eprintln!(\"Entity no longer exists: {}\", e),\n}\n\n// Or use Result combinators\nlet _ = weak.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify();\n}).ok(); // Ignore errors\n```\n\n### Update Panics\n\nNested updates on the same entity will panic:\n\n```rust\n// ❌ Will panic\nentity.update(cx, |state1, cx| {\n    entity.update(cx, |state2, cx| {\n        // Panic: entity already borrowed\n    });\n});\n```\n\n**Solution:** Perform updates sequentially or use different entities.\n\n## Type Conversions\n\n### Entity → WeakEntity\n\n```rust\nlet entity: Entity<T> = cx.new(|cx| T::default());\nlet weak: WeakEntity<T> = entity.downgrade();\n```\n\n### WeakEntity → Entity\n\n```rust\nlet weak: WeakEntity<T> = entity.downgrade();\nlet strong: Option<Entity<T>> = weak.upgrade();\n```\n\n### AnyEntity\n\n```rust\nlet any: AnyEntity = entity.into();\nlet typed: Option<Entity<T>> = any.downcast::<T>();\n```\n\n## Best Practice Guidelines\n\n### Always Use Inner cx\n\n```rust\n// ✅ Good: Use inner cx\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Use inner_cx, not outer cx\n});\n\n// ❌ Bad: Use outer cx\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong! Multiple borrow error\n});\n```\n\n### Weak References in Closures\n\n```rust\n// ✅ Good: Weak reference\nlet weak = cx.entity().downgrade();\ncallback(move || {\n    let _ = weak.update(cx, |state, cx| {\n        cx.notify();\n    });\n});\n\n// ❌ Bad: Strong reference (retain cycle)\nlet strong = cx.entity();\ncallback(move || {\n    strong.update(cx, |state, cx| {\n        // May never be dropped\n        cx.notify();\n    });\n});\n```\n\n### Sequential Updates\n\n```rust\n// ✅ Good: Sequential updates\nentity1.update(cx, |state, cx| { /* ... */ });\nentity2.update(cx, |state, cx| { /* ... */ });\n\n// ❌ Bad: Nested updates\nentity1.update(cx, |_, cx| {\n    entity2.update(cx, |_, cx| {\n        // May panic if entities are related\n    });\n});\n```\n\n<!-- File: skills/gpui-kit/references/gpui/entity-best-practices.md (Tokens: ~3470 | Category: anthropic-skill) -->\n# Entity Best Practices\n\n**Contents:** [Avoiding Common Pitfalls](#avoiding-common-pitfalls) · [Performance Optimization](#performance-optimization) · [Entity Lifecycle Management](#entity-lifecycle-management) · [Entity Observation Best Practices](#entity-observation-best-practices) · [Async Best Practices](#async-best-practices) · [Testing Best Practices](#testing-best-practices) · [Performance Checklist](#performance-checklist)\n\n## Avoiding Common Pitfalls\n\n### Avoid Re-entrant Entity Access (Same Entity)\n\n**Problem:** GPUI locks an entity for the entire duration of its render or update pass. Any attempt to `read` or `update` that *same* entity while the lock is held panics:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: entity_a updated from within entity_a's own update\nentity_a.update(cx, |_, cx| {\n    entity_a.update(cx, |_, _| {}); // PANIC\n});\n\n// ✅ Fine: updating a *different* entity from within an update\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, _| {}); // OK — different lock\n});\n```\n\n**Note:** Updating two *different* entities in a nested fashion is safe. The restriction is strictly about re-entering the *same* entity's lock.\n\n### `defer_in` Re-locks the Entity — Same Rules Apply\n\n`cx.defer_in(window, callback)` schedules `callback` to run *on the entity the context refers to*. GPUI re-acquires that entity's lock to execute the deferred callback, so the re-entrancy rules apply equally inside it:\n\n```rust\n// ❌ Panic: defer_in runs with ListState locked; calling list.update re-enters\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // list_state IS locked for this entire callback!\n        parent.update(cx, |this, cx| {\n            this.list.update(cx, |_, _| {}); // PANIC — re-enters ListState lock\n        });\n    });\n}\n```\n\n**Fix:** Use the direct `&mut` reference the callback provides instead of going through the entity handle:\n\n```rust\n// ✅ Correct: direct mutable access — no lock needed\nfn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n    cx.defer_in(window, |list_state, window, cx| {\n        // Step 1: call hooks directly through list_state (no entity lock)\n        list_state.delegate_mut().on_will_change(&mut op, &snapshot);\n\n        // Step 2: update the parent entity — different lock, safe\n        let new_sel = parent.update(cx, |this, cx| {\n            this.state.apply_change(op);\n            cx.notify();\n            this.state.selection.clone() // return data needed for step 3\n        });\n\n        // Step 3: sync list state directly — no entity lock\n        if let Ok(sel) = new_sel {\n            list_state.delegate_mut().update_snapshot(sel.clone());\n            list_state.delegate_mut().on_confirm(&sel);\n        }\n    });\n}\n```\n\n### Render Callbacks Must Not Access External Entities\n\n`render_item` and any other rendering hook runs inside the entity's render pass. Calling `entity.read(cx)` or `entity.update(cx, …)` on an external entity (which may itself be in a render/update pass) panics with the same re-entrancy error.\n\n**Fix:** Keep a plain `snapshot` field updated eagerly from outside render after every mutation:\n\n```rust\n// ❌ Panic — called during ListState render; external entity access re-enters\nfn render_item(&mut self, ix: IndexPath, …) -> … {\n    let checked = parent.read(cx).selection.contains(&ix); // PANIC\n}\n\n// ✅ Read from snapshot field — no entity access at all\nfn render_item(&mut self, ix: IndexPath, …) -> … {\n    let checked = self.selection_snapshot.iter().any(|(sel_ix, _)| sel_ix == &ix);\n}\n// After every mutation from outside render:\nlist.update(cx, |l, _| l.delegate_mut().update_snapshot(new_snapshot));\n```\n\n### Use Weak References in Closures\n\n**Problem:** Strong references in closures can create retain cycles and memory leaks.\n\n```rust\n// ❌ Bad: Strong reference creates retain cycle\nimpl MyComponent {\n    fn setup_callback(&mut self, cx: &mut Context<Self>) {\n        let entity = cx.entity(); // Strong reference\n\n        some_callback(move || {\n            entity.update(cx, |state, cx| {\n                // This closure holds a strong reference\n                // If the closure itself is retained by the entity, memory leak!\n                cx.notify();\n            });\n        });\n    }\n}\n```\n\n**Solution:** Use weak references in closures.\n\n```rust\n// ✅ Good: Weak reference prevents retain cycle\nimpl MyComponent {\n    fn setup_callback(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade(); // Weak reference\n\n        some_callback(move || {\n            // Safe: weak reference doesn't prevent cleanup\n            let _ = weak_entity.update(cx, |state, cx| {\n                cx.notify();\n            });\n        });\n    }\n}\n```\n\n### Use Inner Context in Closures\n\n**Problem:** Using outer context causes multiple borrow errors.\n\n```rust\n// ❌ Bad: Using outer cx causes borrow issues\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong! Using outer cx\n    cx.spawn(...); // Multiple borrow error\n});\n```\n\n**Solution:** Always use the inner context provided to the closure.\n\n```rust\n// ✅ Good: Use inner cx\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Correct\n    inner_cx.spawn(...); // Works fine\n});\n```\n\n### Entity as Props - Use Weak References\n\n**Problem:** Strong entity references in props can create ownership issues.\n\n```rust\n// ❌ Questionable: Strong reference in child\nstruct ChildComponent {\n    parent: Entity<ParentComponent>, // Strong reference\n}\n```\n\n**Better:** Use weak references for parent relationships.\n\n```rust\n// ✅ Good: Weak reference prevents issues\nstruct ChildComponent {\n    parent: WeakEntity<ParentComponent>, // Weak reference\n}\n\nimpl ChildComponent {\n    fn notify_parent(&mut self, cx: &mut Context<Self>) {\n        // Check if parent still exists\n        if let Ok(_) = self.parent.update(cx, |parent_state, cx| {\n            // Update parent\n            cx.notify();\n        }) {\n            // Parent successfully updated\n        }\n    }\n}\n```\n\n## Performance Optimization\n\n### Minimize cx.notify() Calls\n\nEach `cx.notify()` triggers a re-render. Batch updates when possible.\n\n```rust\n// ❌ Bad: Multiple notifications\nimpl MyComponent {\n    fn update_multiple_fields(&mut self, cx: &mut Context<Self>) {\n        self.field1 = new_value1;\n        cx.notify(); // Unnecessary intermediate notification\n\n        self.field2 = new_value2;\n        cx.notify(); // Unnecessary intermediate notification\n\n        self.field3 = new_value3;\n        cx.notify();\n    }\n}\n```\n\n```rust\n// ✅ Good: Single notification after all updates\nimpl MyComponent {\n    fn update_multiple_fields(&mut self, cx: &mut Context<Self>) {\n        self.field1 = new_value1;\n        self.field2 = new_value2;\n        self.field3 = new_value3;\n        cx.notify(); // Single notification\n    }\n}\n```\n\n### Conditional Updates\n\nOnly notify when state actually changes.\n\n```rust\nimpl MyComponent {\n    fn set_value(&mut self, new_value: i32, cx: &mut Context<Self>) {\n        if self.value != new_value {\n            self.value = new_value;\n            cx.notify(); // Only notify if changed\n        }\n    }\n}\n```\n\n### Use read_with for Complex Operations\n\nPrefer `read_with` over separate `read` calls.\n\n```rust\n// ❌ Less efficient: Multiple borrows\nlet state_ref = entity.read(cx);\nlet value1 = state_ref.field1;\nlet value2 = state_ref.field2;\n// state_ref borrowed for entire scope\n\n// ✅ More efficient: Single borrow with closure\nlet (value1, value2) = entity.read_with(cx, |state, cx| {\n    (state.field1, state.field2)\n});\n```\n\n### Avoid Excessive Entity Creation\n\nCreating entities has overhead. Reuse when appropriate.\n\n```rust\n// ❌ Bad: Creating entity per item in render\nimpl Render for MyList {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div().children(\n            self.items.iter().map(|item| {\n                // Don't create entities in render!\n                let entity = cx.new(|_| item.clone());\n                ItemView { entity }\n            })\n        )\n    }\n}\n```\n\n```rust\n// ✅ Good: Create entities once, reuse\nstruct MyList {\n    item_entities: Vec<Entity<Item>>,\n}\n\nimpl MyList {\n    fn add_item(&mut self, item: Item, cx: &mut Context<Self>) {\n        let entity = cx.new(|_| item);\n        self.item_entities.push(entity);\n        cx.notify();\n    }\n}\n```\n\n## Entity Lifecycle Management\n\n### Clean Up Weak References\n\nPeriodically clean up invalid weak references from collections.\n\n```rust\nstruct Container {\n    weak_children: Vec<WeakEntity<Child>>,\n}\n\nimpl Container {\n    fn cleanup_invalid_children(&mut self, cx: &mut Context<Self>) {\n        // Remove weak references that are no longer valid\n        let before_count = self.weak_children.len();\n        self.weak_children.retain(|weak| weak.upgrade().is_some());\n        let after_count = self.weak_children.len();\n\n        if before_count != after_count {\n            cx.notify(); // Notify if list changed\n        }\n    }\n}\n```\n\n### Entity Cloning and Sharing\n\nUnderstand that cloning `Entity<T>` increases reference count.\n\n```rust\n// Each clone increases the reference count\nlet entity1: Entity<MyState> = cx.new(|_| MyState::default());\nlet entity2 = entity1.clone(); // Reference count: 2\nlet entity3 = entity1.clone(); // Reference count: 3\n\n// Entity is dropped only when all references are dropped\ndrop(entity1); // Reference count: 2\ndrop(entity2); // Reference count: 1\ndrop(entity3); // Reference count: 0, entity is deallocated\n```\n\n### Proper Resource Cleanup\n\nImplement cleanup in `Drop` or explicit cleanup methods.\n\n```rust\nstruct ManagedResource {\n    handle: Option<FileHandle>,\n}\n\nimpl ManagedResource {\n    fn close(&mut self, cx: &mut Context<Self>) {\n        if let Some(handle) = self.handle.take() {\n            // Explicit cleanup\n            handle.close();\n            cx.notify();\n        }\n    }\n}\n\nimpl Drop for ManagedResource {\n    fn drop(&mut self) {\n        // Automatic cleanup when entity is dropped\n        if let Some(handle) = self.handle.take() {\n            handle.close();\n        }\n    }\n}\n```\n\n## Entity Observation Best Practices\n\n### Detach Subscriptions Appropriately\n\nCall `.detach()` on subscriptions you want to keep alive.\n\n```rust\nimpl MyComponent {\n    fn new(other_entity: Entity<OtherComponent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observer will live as long as both entities exist\n            cx.observe(&other_entity, |this, observed, cx| {\n                // Handle changes\n                cx.notify();\n            }).detach(); // Important: detach to make permanent\n\n            Self { /* fields */ }\n        })\n    }\n}\n```\n\n### Avoid Observation Cycles\n\nDon't create mutual observation between entities.\n\n```rust\n// ❌ Bad: Mutual observation can cause infinite loops\nentity1.update(cx, |_, cx| {\n    cx.observe(&entity2, |_, _, cx| {\n        cx.notify(); // May trigger entity2's observer\n    }).detach();\n});\n\nentity2.update(cx, |_, cx| {\n    cx.observe(&entity1, |_, _, cx| {\n        cx.notify(); // May trigger entity1's observer → infinite loop\n    }).detach();\n});\n```\n\n## Async Best Practices\n\n### Always Use Weak References in Async Tasks\n\n```rust\n// ✅ Good: Weak reference in spawned task\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            let data = fetch_from_api().await;\n\n            // Entity may have been dropped during fetch\n            let _ = weak_entity.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n```\n\n### Handle Async Errors Gracefully\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let weak_entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            match fetch_from_api().await {\n                Ok(data) => {\n                    let _ = weak_entity.update(cx, |state, cx| {\n                        state.data = Some(data);\n                        state.error = None;\n                        cx.notify();\n                    });\n                }\n                Err(e) => {\n                    let _ = weak_entity.update(cx, |state, cx| {\n                        state.error = Some(e.to_string());\n                        cx.notify();\n                    });\n                }\n            }\n        }).detach();\n    }\n}\n```\n\n### Cancellation Patterns\n\nImplement cancellation for long-running tasks.\n\n```rust\nstruct DataFetcher {\n    current_task: Option<Task<()>>,\n    data: Option<String>,\n}\n\nimpl DataFetcher {\n    fn fetch_data(&mut self, url: String, cx: &mut Context<Self>) {\n        // Cancel previous task\n        self.current_task = None; // Dropping task cancels it\n\n        let weak_entity = cx.entity().downgrade();\n\n        let task = cx.spawn(async move |cx| {\n            let data = fetch_from_url(&url).await?;\n\n            let _ = weak_entity.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n\n            Ok::<(), anyhow::Error>(())\n        });\n\n        self.current_task = Some(task);\n    }\n}\n```\n\n## Testing Best Practices\n\n### Use TestAppContext for Entity Tests\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use gpui_kit::TestAppContext;\n\n    #[gpui_kit::test]\n    fn test_entity_update(cx: &mut TestAppContext) {\n        let entity = cx.new(|_| MyState { count: 0 });\n\n        entity.update(cx, |state, cx| {\n            state.count += 1;\n            assert_eq!(state.count, 1);\n        });\n\n        let count = entity.read(cx).count;\n        assert_eq!(count, 1);\n    }\n}\n```\n\n### Test Entity Observation\n\n```rust\n#[gpui_kit::test]\nfn test_entity_observation(cx: &mut TestAppContext) {\n    let observed = cx.new(|_| MyState { value: 0 });\n    let observer = cx.new(|cx| Observer::new(observed.clone(), cx));\n\n    // Update observed entity\n    observed.update(cx, |state, cx| {\n        state.value = 42;\n        cx.notify();\n    });\n\n    // Verify observer was notified\n    observer.read(cx).assert_observed();\n}\n```\n\n## Performance Checklist\n\nBefore shipping entity-based code, verify:\n\n- [ ] No strong references in closures/callbacks (use `WeakEntity`)\n- [ ] No nested entity updates (use sequential updates)\n- [ ] Using inner `cx` in update closures\n- [ ] Batching updates before calling `cx.notify()`\n- [ ] Cleaning up invalid weak references periodically\n- [ ] Using `read_with` for complex read operations\n- [ ] Properly detaching subscriptions and observers\n- [ ] Using weak references in async tasks\n- [ ] No observation cycles between entities\n- [ ] Proper error handling in async operations\n- [ ] Resource cleanup in `Drop` or explicit methods\n- [ ] Tests cover entity lifecycle and interactions\n\n<!-- File: skills/gpui-kit/references/gpui/entity-patterns.md (Tokens: ~2881 | Category: anthropic-skill) -->\n# Entity Patterns\n\n**Contents:** [Application Scenarios](#application-scenarios) · [Common Patterns](#common-patterns) · [Pattern Selection Guide](#pattern-selection-guide)\n\n## Application Scenarios\n\n### Model-View Separation\n\nSeparate business logic (model) from UI (view) using entities.\n\n```rust\nstruct CounterModel {\n    count: usize,\n    listeners: Vec<Box<dyn Fn(usize)>>,\n}\n\nstruct CounterView {\n    model: Entity<CounterModel>,\n}\n\nimpl CounterModel {\n    fn increment(&mut self, cx: &mut Context<Self>) {\n        self.count += 1;\n\n        // Notify listeners\n        for listener in &self.listeners {\n            listener(self.count);\n        }\n\n        cx.notify();\n    }\n\n    fn decrement(&mut self, cx: &mut Context<Self>) {\n        if self.count > 0 {\n            self.count -= 1;\n            cx.notify();\n        }\n    }\n}\n\nimpl CounterView {\n    fn new(cx: &mut App) -> Entity<Self> {\n        let model = cx.new(|_cx| CounterModel {\n            count: 0,\n            listeners: Vec::new(),\n        });\n\n        cx.new(|cx| Self { model })\n    }\n\n    fn increment_count(&mut self, cx: &mut Context<Self>) {\n        self.model.update(cx, |model, cx| {\n            model.increment(cx);\n        });\n    }\n}\n\nimpl Render for CounterView {\n    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let count = self.model.read(cx).count;\n\n        div()\n            .child(format!(\"Count: {}\", count))\n            .child(\n                Button::new(\"increment\")\n                    .label(\"Increment\")\n                    .on_click(cx.listener(|this, _, cx| {\n                        this.increment_count(cx);\n                    }))\n            )\n    }\n}\n```\n\n### Component State Management\n\nManaging complex component state with entities.\n\n```rust\nstruct TodoList {\n    todos: Vec<Todo>,\n    filter: TodoFilter,\n    next_id: usize,\n}\n\nstruct Todo {\n    id: usize,\n    text: String,\n    completed: bool,\n}\n\nenum TodoFilter {\n    All,\n    Active,\n    Completed,\n}\n\nimpl TodoList {\n    fn new() -> Self {\n        Self {\n            todos: Vec::new(),\n            filter: TodoFilter::All,\n            next_id: 0,\n        }\n    }\n\n    fn add_todo(&mut self, text: String, cx: &mut Context<Self>) {\n        self.todos.push(Todo {\n            id: self.next_id,\n            text,\n            completed: false,\n        });\n        self.next_id += 1;\n        cx.notify();\n    }\n\n    fn toggle_todo(&mut self, id: usize, cx: &mut Context<Self>) {\n        if let Some(todo) = self.todos.iter_mut().find(|t| t.id == id) {\n            todo.completed = !todo.completed;\n            cx.notify();\n        }\n    }\n\n    fn remove_todo(&mut self, id: usize, cx: &mut Context<Self>) {\n        self.todos.retain(|t| t.id != id);\n        cx.notify();\n    }\n\n    fn set_filter(&mut self, filter: TodoFilter, cx: &mut Context<Self>) {\n        self.filter = filter;\n        cx.notify();\n    }\n\n    fn visible_todos(&self) -> impl Iterator<Item = &Todo> {\n        self.todos.iter().filter(move |todo| match self.filter {\n            TodoFilter::All => true,\n            TodoFilter::Active => !todo.completed,\n            TodoFilter::Completed => todo.completed,\n        })\n    }\n}\n```\n\n### Cross-Entity Communication\n\nCoordinating state between parent and child entities.\n\n```rust\nstruct ParentComponent {\n    child_entities: Vec<Entity<ChildComponent>>,\n    global_message: String,\n}\n\nstruct ChildComponent {\n    id: usize,\n    message: String,\n    parent: WeakEntity<ParentComponent>,\n}\n\nimpl ParentComponent {\n    fn new(cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| Self {\n            child_entities: Vec::new(),\n            global_message: String::new(),\n        })\n    }\n\n    fn add_child(&mut self, cx: &mut Context<Self>) {\n        let parent_weak = cx.entity().downgrade();\n        let child_id = self.child_entities.len();\n\n        let child = cx.new(|cx| ChildComponent {\n            id: child_id,\n            message: String::new(),\n            parent: parent_weak,\n        });\n\n        self.child_entities.push(child);\n        cx.notify();\n    }\n\n    fn broadcast_message(&mut self, message: String, cx: &mut Context<Self>) {\n        self.global_message = message.clone();\n\n        // Update all children\n        for child in &self.child_entities {\n            child.update(cx, |child_state, cx| {\n                child_state.message = message.clone();\n                cx.notify();\n            });\n        }\n\n        cx.notify();\n    }\n}\n\nimpl ChildComponent {\n    fn notify_parent(&mut self, message: String, cx: &mut Context<Self>) {\n        if let Ok(_) = self.parent.update(cx, |parent_state, cx| {\n            parent_state.global_message = format!(\"Child {}: {}\", self.id, message);\n            cx.notify();\n        }) {\n            // Parent successfully notified\n        }\n    }\n}\n```\n\n### Async Operations with Entities\n\nManaging async state updates.\n\n```rust\nstruct DataLoader {\n    loading: bool,\n    data: Option<String>,\n    error: Option<String>,\n}\n\nimpl DataLoader {\n    fn new() -> Self {\n        Self {\n            loading: false,\n            data: None,\n            error: None,\n        }\n    }\n\n    fn load_data(&mut self, cx: &mut Context<Self>) {\n        // Set loading state\n        self.loading = true;\n        self.error = None;\n        cx.notify();\n\n        // Get weak reference for async task\n        let entity = cx.entity().downgrade();\n\n        cx.spawn(async move |cx| {\n            // Simulate async operation\n            tokio::time::sleep(Duration::from_secs(2)).await;\n            let result = fetch_data().await;\n\n            // Update entity with result\n            let _ = entity.update(cx, |state, cx| {\n                state.loading = false;\n                match result {\n                    Ok(data) => state.data = Some(data),\n                    Err(e) => state.error = Some(e.to_string()),\n                }\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n\nasync fn fetch_data() -> Result<String, anyhow::Error> {\n    // Actual fetch implementation\n    Ok(\"Fetched data\".to_string())\n}\n```\n\n### Background Task Coordination\n\nUsing background tasks with entity updates.\n\n```rust\nstruct ImageProcessor {\n    images: Vec<ProcessedImage>,\n    processing: bool,\n}\n\nstruct ProcessedImage {\n    path: PathBuf,\n    thumbnail: Option<Vec<u8>>,\n}\n\nimpl ImageProcessor {\n    fn process_images(&mut self, paths: Vec<PathBuf>, cx: &mut Context<Self>) {\n        self.processing = true;\n        cx.notify();\n\n        cx.spawn(async move |this, cx| {\n            let processed = cx\n                .background_spawn(async move {\n                    let mut processed = Vec::new();\n\n                    for path in paths {\n                        // Process image on background thread\n                        let thumbnail = generate_thumbnail(&path).await;\n                        processed.push((path, thumbnail));\n                    }\n\n                    // Send results back to foreground\n                    processed\n                })\n                .await;\n\n            // Update entity on foreground thread\n            let _ = this.update(cx, |state, cx| {\n                for (path, thumbnail) in processed {\n                    state.images.push(ProcessedImage {\n                        path,\n                        thumbnail: Some(thumbnail),\n                    });\n                }\n                state.processing = false;\n                cx.notify();\n            });\n        })\n        .detach();\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Stateful Components\n\nUse entities for components that maintain internal state.\n\n```rust\nstruct StatefulComponent {\n    value: i32,\n    history: Vec<i32>,\n}\n\nimpl StatefulComponent {\n    fn update_value(&mut self, new_value: i32, cx: &mut Context<Self>) {\n        self.history.push(self.value);\n        self.value = new_value;\n        cx.notify();\n    }\n\n    fn undo(&mut self, cx: &mut Context<Self>) {\n        if let Some(prev_value) = self.history.pop() {\n            self.value = prev_value;\n            cx.notify();\n        }\n    }\n}\n```\n\n### 2. Shared State\n\nShare state between multiple components using entities.\n\n```rust\nstruct SharedState {\n    theme: Theme,\n    user: Option<User>,\n}\n\nstruct ComponentA {\n    shared: Entity<SharedState>,\n}\n\nstruct ComponentB {\n    shared: Entity<SharedState>,\n}\n\n// Both components can read/update the same shared state\nimpl ComponentA {\n    fn update_theme(&mut self, theme: Theme, cx: &mut Context<Self>) {\n        self.shared.update(cx, |state, cx| {\n            state.theme = theme;\n            cx.notify();\n        });\n    }\n}\n```\n\n### 3. Event Coordination\n\nUse entities to coordinate events between components.\n\n```rust\nstruct EventCoordinator {\n    listeners: Vec<WeakEntity<dyn EventListener>>,\n}\n\ntrait EventListener {\n    fn on_event(&mut self, event: &AppEvent, cx: &mut App);\n}\n\nimpl EventCoordinator {\n    fn emit_event(&mut self, event: AppEvent, cx: &mut Context<Self>) {\n        // Notify all listeners\n        self.listeners.retain(|weak_listener| {\n            weak_listener.update(cx, |listener, cx| {\n                listener.on_event(&event, cx);\n            }).is_ok()\n        });\n        cx.notify();\n    }\n}\n```\n\n### 4. Async State Management\n\nManage state that changes based on async operations.\n\n```rust\nstruct AsyncState<T> {\n    state: AsyncValue<T>,\n}\n\nenum AsyncValue<T> {\n    Loading,\n    Loaded(T),\n    Error(String),\n}\n\nimpl<T> AsyncState<T> {\n    fn is_loading(&self) -> bool {\n        matches!(self.state, AsyncValue::Loading)\n    }\n\n    fn value(&self) -> Option<&T> {\n        match &self.state {\n            AsyncValue::Loaded(v) => Some(v),\n            _ => None,\n        }\n    }\n}\n```\n\n### 5. Parent-Child Relationships\n\nManage hierarchical relationships with weak references.\n\n```rust\nstruct Parent {\n    children: Vec<Entity<Child>>,\n}\n\nstruct Child {\n    parent: WeakEntity<Parent>,\n    data: String,\n}\n\nimpl Child {\n    fn notify_parent_of_change(&mut self, cx: &mut Context<Self>) {\n        if let Ok(_) = self.parent.update(cx, |parent, cx| {\n            // Parent can react to child change\n            cx.notify();\n        }) {\n            // Successfully notified\n        }\n    }\n}\n```\n\n### 6. Observer Pattern\n\nReact to entity state changes using observers.\n\n```rust\nstruct Observable {\n    value: i32,\n}\n\nstruct Observer {\n    observed: Entity<Observable>,\n}\n\nimpl Observer {\n    fn new(observed: Entity<Observable>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observe the entity\n            cx.observe(&observed, |this, observed_entity, cx| {\n                // React to changes\n                let value = observed_entity.read(cx).value;\n                println!(\"Value changed to: {}\", value);\n            }).detach();\n\n            Self { observed }\n        })\n    }\n}\n```\n\n### 7. Event Subscription\n\nHandle events emitted by other entities.\n\n```rust\n#[derive(Clone)]\nenum DataEvent {\n    Updated,\n    Deleted,\n}\n\nstruct DataSource {\n    data: Vec<String>,\n}\n\nimpl DataSource {\n    fn update_data(&mut self, cx: &mut Context<Self>) {\n        // Update data\n        cx.emit(DataEvent::Updated);\n        cx.notify();\n    }\n}\n\nstruct DataConsumer {\n    source: Entity<DataSource>,\n}\n\nimpl DataConsumer {\n    fn new(source: Entity<DataSource>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Subscribe to events\n            cx.subscribe(&source, |this, source, event: &DataEvent, cx| {\n                match event {\n                    DataEvent::Updated => {\n                        // Handle update\n                        cx.notify();\n                    }\n                    DataEvent::Deleted => {\n                        // Handle deletion\n                    }\n                }\n            }).detach();\n\n            Self { source }\n        })\n    }\n}\n```\n\n### 8. Resource Management\n\nManage external resources with proper cleanup.\n\n```rust\nstruct FileHandle {\n    path: PathBuf,\n    file: Option<File>,\n}\n\nimpl FileHandle {\n    fn open(&mut self, cx: &mut Context<Self>) -> Result<()> {\n        self.file = Some(File::open(&self.path)?);\n        cx.notify();\n        Ok(())\n    }\n\n    fn close(&mut self, cx: &mut Context<Self>) {\n        self.file = None;\n        cx.notify();\n    }\n}\n\nimpl Drop for FileHandle {\n    fn drop(&mut self) {\n        // Cleanup when entity is dropped\n        if let Some(file) = self.file.take() {\n            drop(file);\n        }\n    }\n}\n```\n\n## Pattern Selection Guide\n\n| Need | Pattern | Complexity |\n|------|---------|------------|\n| Component with internal state | Stateful Components | Low |\n| State shared by multiple components | Shared State | Low |\n| Coordinate events between components | Event Coordination | Medium |\n| Handle async data fetching | Async State Management | Medium |\n| Parent-child component hierarchy | Parent-Child Relationships | Medium |\n| React to state changes | Observer Pattern | Medium |\n| Handle custom events | Event Subscription | Medium-High |\n| Manage external resources | Resource Management | High |\n\nChoose the simplest pattern that meets your requirements. Combine patterns as needed for complex scenarios.\n\n<!-- File: skills/gpui-kit/references/gpui/entity.md (Tokens: ~1816 | Category: anthropic-skill) -->\n# Entity State Management\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Core Principles](#core-principles) · [Common Use Cases](#common-use-cases) · [Extended References](#reference-documentation)\n\n## Overview\n\nAn `Entity<T>` is a handle to state of type `T`, providing safe access and updates.\n\n**Key Methods:**\n- `entity.read(cx)` → `&T` - Read-only access\n- `entity.read_with(cx, |state, cx| ...)` → `R` - Read with closure\n- `entity.update(cx, |state, cx| ...)` → `R` - Mutable update\n- `entity.downgrade()` → `WeakEntity<T>` - Create weak reference\n- `entity.entity_id()` → `EntityId` - Unique identifier\n\n**Entity Types:**\n- **`Entity<T>`**: Strong reference (increases ref count)\n- **`WeakEntity<T>`**: Weak reference (doesn't prevent cleanup, returns `Result`)\n\n## Quick Start\n\n### Creating and Using Entities\n\n```rust\n// Create entity\nlet counter = cx.new(|cx| Counter { count: 0 });\n\n// Read state\nlet count = counter.read(cx).count;\n\n// Update state\ncounter.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify(); // Trigger re-render\n});\n\n// Weak reference (for closures/callbacks)\nlet weak = counter.downgrade();\nlet _ = weak.update(cx, |state, cx| {\n    state.count += 1;\n    cx.notify();\n});\n```\n\n### In Components\n\n```rust\nstruct MyComponent {\n    shared_state: Entity<SharedData>,\n}\n\nimpl MyComponent {\n    fn new(cx: &mut App) -> Entity<Self> {\n        let shared = cx.new(|_| SharedData::default());\n\n        cx.new(|cx| Self {\n            shared_state: shared,\n        })\n    }\n\n    fn update_shared(&mut self, cx: &mut Context<Self>) {\n        self.shared_state.update(cx, |state, cx| {\n            state.value = 42;\n            cx.notify();\n        });\n    }\n}\n```\n\n### Async Operations\n\nWhen calling `cx.spawn` from `Context<Self>`, the closure receives `(WeakEntity<Self>, &mut AsyncApp)`:\n\n```rust\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx: &mut AsyncApp| {\n            let data = fetch_from_api().await;\n\n            // Update entity safely via the weak reference\n            let _ = this.update(cx, |state, cx| {\n                state.data = Some(data);\n                cx.notify();\n            });\n        }).detach();\n    }\n}\n```\n\n## Core Principles\n\n### Always Use Weak References in Closures\n\n```rust\n// ✅ Good: Weak reference prevents retain cycles\nlet weak = cx.entity().downgrade();\ncallback(move || {\n    let _ = weak.update(cx, |state, cx| cx.notify());\n});\n\n// ❌ Bad: Strong reference may cause memory leak\nlet strong = cx.entity();\ncallback(move || {\n    strong.update(cx, |state, cx| cx.notify());\n});\n```\n\n### Use Inner Context\n\n```rust\n// ✅ Good: Use inner cx from closure\nentity.update(cx, |state, inner_cx| {\n    inner_cx.notify(); // Correct\n});\n\n// ❌ Bad: Use outer cx (multiple borrow error)\nentity.update(cx, |state, inner_cx| {\n    cx.notify(); // Wrong!\n});\n```\n\n### Avoid Nested Entity Updates\n\nNested `entity.update(cx, …)` calls are dangerous. The default posture is: **do not nest them**. The sub-cases below clarify when a panic is guaranteed vs. merely possible.\n\n**Same entity → always panics.**  \nGPUI locks an entity for the entire duration of its update or render pass. Re-entering that same lock panics immediately:\n\n```\ncannot update … while it is already being updated\n```\n\n```rust\n// ❌ Panic: updating entity_a from inside entity_a's own update\nentity_a.update(cx, |state, cx| {\n    entity_a.update(cx, |_, _| {}); // PANIC — same lock\n});\n```\n\n**Different entity → generally safe, but indirect cycles still panic.**  \nEach entity has its own lock, so updating `entity_b` from within `entity_a`'s update normally succeeds. However, if `entity_b`'s callback reaches back into `entity_a` — directly or through a chain — GPUI will attempt to re-acquire `entity_a`'s lock and panic.\n\n```rust\n// ✅ Usually fine: different entities, no cycle\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, _| {}); // OK — different lock\n});\n\n// ❌ Panic: indirect cycle back to entity_a\nentity_a.update(cx, |_, cx| {\n    entity_b.update(cx, |_, cx| {\n        entity_a.update(cx, |_, _| {}); // PANIC — entity_a is still locked\n    });\n});\n```\n\nWhen in doubt, flatten the call sequence rather than nesting: finish the outer update, then update the second entity from outside.\n\n**`defer_in` does not bypass the lock.** `cx.defer_in(window, callback)` schedules `callback` to run on the current entity — meaning GPUI re-acquires the entity's lock to execute it. The re-entrancy rules apply equally inside the deferred callback:\n\n```rust\n// ❌ Panic: defer_in re-locks entity_a; calling entity_a.update inside re-enters\nimpl SomeDelegate for MyAdapter {\n    fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n        cx.defer_in(window, |list_state, window, cx| {\n            // list_state is locked for this callback!\n            parent.update(cx, |this, cx| {\n                this.list.update(cx, |_, _| {}); // PANIC — list is already locked above\n            });\n        });\n    }\n}\n\n// ✅ Fix: use the direct &mut reference the callback provides\nimpl SomeDelegate for MyAdapter {\n    fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<ListState<Self>>) {\n        cx.defer_in(window, |list_state, window, cx| {\n            // Access list data directly — no entity lock needed\n            list_state.delegate_mut().some_hook();\n\n            // Update the *parent* entity — different lock, safe\n            parent.update(cx, |this, cx| { /* … */ });\n\n            // Sync list state directly after parent update\n            list_state.delegate_mut().update_snapshot(new_val);\n        });\n    }\n}\n```\n\n**Snapshot pattern for render callbacks.** `render_item` (and any other rendering hook) runs inside the entity's render pass. It must never call `entity.read(cx)` or `entity.update(cx, …)` on any external entity. Instead, keep a plain `snapshot` field updated eagerly from *outside* render after every mutation:\n\n```rust\n// ❌ Panic in render_item — ListState is already locked\nfn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<ListState<Self>>) -> … {\n    let checked = parent_entity.read(cx).selection.contains(&ix); // PANIC\n}\n\n// ✅ Read from a plain snapshot field — no entity access\nfn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<ListState<Self>>) -> … {\n    let checked = self.selection_snapshot.iter().any(|(sel_ix, _)| sel_ix == &ix);\n}\n```\n\n## Common Use Cases\n\n1. **Component State**: Internal state that needs reactivity\n2. **Shared State**: State shared between multiple components\n3. **Parent-Child**: Coordinating between related components (use weak refs)\n4. **Async State**: Managing state that changes from async operations\n5. **Observations**: Reacting to changes in other entities\n\n## Reference Documentation\n\n- **API**: See [entity-api.md](entity-api.md) — entity types, methods, lifecycle, error handling\n- **Patterns**: See [entity-patterns.md](entity-patterns.md) — model-view, cross-entity communication, observer\n- **Best Practices**: See [entity-best-practices.md](entity-best-practices.md) — pitfalls, memory, performance, async\n- **Advanced**: See [entity-advanced.md](entity-advanced.md) — collections, registry, debounce, state machines\n\n<!-- File: skills/gpui-kit/references/gpui/event.md (Tokens: ~1303 | Category: anthropic-skill) -->\n# Events & Subscriptions\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Patterns](#common-patterns) · [subscribe_in](#subscribe_in--subscription-with-window-access) · [observe_window_activation](#observe_window_activation) · [observe_global](#observe_global) · [Subscription Lifetime](#subscription-lifetime) · [Best Practices](#best-practices)\n\n## Overview\n\nGPUI provides event system for component coordination:\n\n**Event Mechanisms:**\n- **Custom Events**: Define and emit type-safe events\n- **Observations**: React to entity state changes\n- **Subscriptions**: Listen to events from other entities\n- **Global Events**: App-wide event handling\n\n## Quick Start\n\n### Define and Emit Events\n\n```rust\n#[derive(Clone)]\nenum MyEvent {\n    DataUpdated(String),\n    ActionTriggered,\n}\n\nimpl MyComponent {\n    fn update_data(&mut self, data: String, cx: &mut Context<Self>) {\n        self.data = data.clone();\n\n        // Emit event\n        cx.emit(MyEvent::DataUpdated(data));\n        cx.notify();\n    }\n}\n```\n\n### Subscribe to Events\n\n```rust\nimpl Listener {\n    fn new(source: Entity<MyComponent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Subscribe to events\n            cx.subscribe(&source, |this, emitter, event: &MyEvent, cx| {\n                match event {\n                    MyEvent::DataUpdated(data) => {\n                        this.handle_update(data.clone(), cx);\n                    }\n                    MyEvent::ActionTriggered => {\n                        this.handle_action(cx);\n                    }\n                }\n            }).detach();\n\n            Self { source }\n        })\n    }\n}\n```\n\n### Observe Entity Changes\n\n```rust\nimpl Observer {\n    fn new(target: Entity<Target>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            // Observe entity for any changes\n            cx.observe(&target, |this, observed, cx| {\n                // Called when observed.update() calls cx.notify()\n                println!(\"Target changed\");\n                cx.notify();\n            }).detach();\n\n            Self { target }\n        })\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Parent-Child Communication\n\n```rust\n// Parent emits events\nimpl Parent {\n    fn notify_children(&mut self, cx: &mut Context<Self>) {\n        cx.emit(ParentEvent::Updated);\n        cx.notify();\n    }\n}\n\n// Children subscribe\nimpl Child {\n    fn new(parent: Entity<Parent>, cx: &mut App) -> Entity<Self> {\n        cx.new(|cx| {\n            cx.subscribe(&parent, |this, parent, event, cx| {\n                this.handle_parent_event(event, cx);\n            }).detach();\n\n            Self { parent }\n        })\n    }\n}\n```\n\n### 2. Global Event Broadcasting\n\n```rust\nstruct EventBus {\n    listeners: Vec<WeakEntity<dyn Listener>>,\n}\n\nimpl EventBus {\n    fn broadcast(&mut self, event: GlobalEvent, cx: &mut Context<Self>) {\n        self.listeners.retain(|weak| {\n            weak.update(cx, |listener, cx| {\n                listener.on_event(&event, cx);\n            }).is_ok()\n        });\n    }\n}\n```\n\n### 3. Observer Pattern\n\n```rust\ncx.observe(&entity, |this, observed, cx| {\n    // React to any state change\n    let state = observed.read(cx);\n    this.sync_with_state(state, cx);\n}).detach();\n```\n\n## subscribe_in — Subscription with Window Access\n\nUse when the subscription callback needs `&mut Window`:\n\n```rust\n// Store subscriptions to keep them alive\nstruct MyComponent {\n    _subscriptions: Vec<Subscription>,\n}\n\nimpl MyComponent {\n    fn new(input: &Entity<InputState>, window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let _subscriptions = vec![\n            cx.subscribe_in(input, window, |this, state, event, window, cx| {\n                match event {\n                    InputEvent::PressEnter { .. } => this.on_submit(window, cx),\n                    InputEvent::Change => {\n                        let val = state.read(cx).value();\n                        this.on_change(val, cx);\n                    }\n                    _ => {}\n                }\n            }),\n        ];\n        Self { _subscriptions }\n    }\n}\n```\n\n`subscribe` vs `subscribe_in`:\n- `cx.subscribe(&entity, |this, source, event, cx|)` — no window\n- `cx.subscribe_in(&entity, window, |this, source, event, window, cx|)` — window access\n\n## observe_window_activation\n\n```rust\nlet _sub = cx.observe_window_activation(window, |this, window, cx| {\n    if window.is_window_active() {\n        this.start_polling(cx);\n    } else {\n        this.stop_polling(cx);\n    }\n});\n```\n\n## observe_global\n\n```rust\ncx.observe_global::<Theme>(|cx| {\n    cx.notify(); // Re-render when theme changes\n});\n```\n\n## Subscription Lifetime\n\nSubscriptions are cancelled when dropped. Two ways to keep alive:\n\n```rust\n// 1. .detach() — lives until entity is dropped\ncx.subscribe(&entity, |this, _, event, cx| {\n    // ...\n}).detach();\n\n// 2. Store in struct — cancelled when struct drops\nstruct MyView {\n    _subscriptions: Vec<Subscription>,\n}\n// _subscriptions.push(cx.subscribe(...));\n```\n\nUse `.detach()` for permanent subscriptions; store in struct for subscriptions that should stop when the component unmounts.\n\n## Best Practices\n\n### ✅ Detach Subscriptions\n\n```rust\n// ✅ Detach to keep alive\ncx.subscribe(&entity, |this, source, event, cx| {\n    // Handle event\n}).detach();\n```\n\n### ✅ Clean Event Types\n\n```rust\n#[derive(Clone)]\nenum AppEvent {\n    DataChanged { id: usize, value: String },\n    ActionPerformed(ActionType),\n    Error(String),\n}\n```\n\n### ❌ Avoid Event Loops\n\n```rust\n// ❌ Don't create mutual subscriptions\nentity1.subscribe(entity2) → emits event\nentity2.subscribe(entity1) → emits event → infinite loop!\n```\n\n## Reference Documentation\n\n<!-- File: skills/gpui-kit/references/gpui/focus-handle.md (Tokens: ~1721 | Category: anthropic-skill) -->\n# Focus & Keyboard Navigation\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Focus Events](#focus-events) · [Keyboard Navigation](#keyboard-navigation) · [Common Patterns](#common-patterns) · [Best Practices](#best-practices)\n\n## Overview\n\nGPUI's focus system enables keyboard navigation and focus management.\n\n**Key Concepts:**\n- **FocusHandle**: Reference to focusable element\n- **Focus tracking**: Current focused element\n- **Keyboard navigation**: Tab/Shift-Tab between elements\n- **Focus events**: on_focus, on_blur\n\n## Quick Start\n\n### Creating Focus Handles\n\n```rust\nstruct FocusableComponent {\n    focus_handle: FocusHandle,\n}\n\nimpl FocusableComponent {\n    fn new(cx: &mut Context<Self>) -> Self {\n        Self {\n            focus_handle: cx.focus_handle(),\n        }\n    }\n}\n```\n\n### Making Elements Focusable\n\n```rust\nimpl Render for FocusableComponent {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .on_action(cx.listener(Self::on_enter))\n            .child(\"Focusable content\")\n    }\n\n    fn on_enter(&mut self, _: &Enter, cx: &mut Context<Self>) {\n        // Handle Enter key when focused\n        cx.notify();\n    }\n}\n```\n\n### Focus Management\n\n```rust\nimpl MyComponent {\n    fn focus(&mut self, cx: &mut Context<Self>) {\n        self.focus_handle.focus(cx);\n    }\n\n    fn is_focused(&self, cx: &App) -> bool {\n        self.focus_handle.is_focused(cx)\n    }\n\n    fn blur(&mut self, cx: &mut Context<Self>) {\n        cx.blur();\n    }\n}\n```\n\n## Focus Events\n\n### Handling Focus Changes\n\n```rust\nimpl Render for MyInput {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let is_focused = self.focus_handle.is_focused(cx);\n\n        div()\n            .track_focus(&self.focus_handle)\n            .on_focus(cx.listener(|this, _event, cx| {\n                this.on_focus(cx);\n            }))\n            .on_blur(cx.listener(|this, _event, cx| {\n                this.on_blur(cx);\n            }))\n            .when(is_focused, |el| {\n                el.bg(cx.theme().focused_background)\n            })\n            .child(self.render_content())\n    }\n}\n\nimpl MyInput {\n    fn on_focus(&mut self, cx: &mut Context<Self>) {\n        // Handle focus gained\n        cx.notify();\n    }\n\n    fn on_blur(&mut self, cx: &mut Context<Self>) {\n        // Handle focus lost\n        cx.notify();\n    }\n}\n```\n\n## Keyboard Navigation\n\n### Tab Order\n\nA tracked handle is a Tab stop only when the handle says so. `cx.focus_handle()`\nstarts with `tab_stop = false`, and an element's own `.tab_index()` /\n`.tab_stop()` do not apply to a handle passed to `track_focus`: build the handle\nwith the flag.\n\n```rust\n// In the owning entity's constructor:\nlet focus1 = cx.focus_handle().tab_stop(true);          // Tab order: 1\nlet focus2 = cx.focus_handle().tab_stop(true);          // Tab order: 2\nlet hidden = cx.focus_handle();                         // focusable, never a Tab stop\n\ndiv()\n    .child(div().track_focus(&focus1).child(\"first\"))\n    .child(div().track_focus(&focus2).child(\"second\"))\n    .child(div().track_focus(&hidden).child(\"container\"))\n```\n\nThe Tab table is rebuilt every frame from the elements that painted with a\ntracked handle, in tree order (`tab_index` reorders within a `tab_group`). A\nstateless component may create its handle in `render` through keyed state —\n`window.use_keyed_state(id, cx, |_, cx| cx.focus_handle().tab_stop(true))` —\nwhich survives re-renders, so the order stays stable; `Button` does exactly\nthis. A focused element receives `ClickEvent::Keyboard` in `on_click` when\nEnter or Space is released, so a `track_focus` + `on_click` row activates from\nthe keyboard without extra bindings.\n\n### Focus Within Containers\n\n```rust\nimpl Container {\n    fn focus_first(&mut self, cx: &mut Context<Self>) {\n        if let Some(first) = self.children.first() {\n            first.update(cx, |child, cx| {\n                child.focus_handle.focus(cx);\n            });\n        }\n    }\n\n    fn focus_next(&mut self, cx: &mut Context<Self>) {\n        // Custom focus navigation logic\n    }\n}\n```\n\n## Common Patterns\n\n### 1. Auto-focus on Mount\n\n```rust\nimpl MyDialog {\n    fn new(cx: &mut Context<Self>) -> Self {\n        let focus_handle = cx.focus_handle();\n\n        // Focus when created\n        focus_handle.focus(cx);\n\n        Self { focus_handle }\n    }\n}\n```\n\n### 2. Focus Trap (Modal)\n\n```rust\nimpl Modal {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .on_key_down(cx.listener(|this, event: &KeyDownEvent, cx| {\n                if event.key == Key::Tab {\n                    // Keep focus within modal\n                    this.focus_next_in_modal(cx);\n                    cx.stop_propagation();\n                }\n            }))\n            .child(self.render_content())\n    }\n}\n```\n\n### 3. Conditional Focus\n\n```rust\nimpl Searchable {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .track_focus(&self.focus_handle)\n            .when(self.search_active, |el| {\n                el.on_mount(cx.listener(|this, _, cx| {\n                    this.focus_handle.focus(cx);\n                }))\n            })\n            .child(self.search_input())\n    }\n}\n```\n\n### 4. Restore Lost Focus\n\nIf the focused element is no longer rendered (a table swapped for an empty\nstate), key dispatch starts at the dispatch tree's root node, so the view's\n`key_context` bindings and `on_action` handlers stop firing. Register one\n`cx.on_focus_lost` listener per window, usually on the root view, and move\nFocus to `window.focus_lost_restore_target(cx)`: the closest focusable\nancestor that is still rendered. Track the view's own handle on the element\nthat carries its `key_context`, so that element is the ancestor Focus returns\nto.\n\n```rust\nlet focus_lost = cx.on_focus_lost(window, |this, window, cx| {\n    let target = window\n        .focus_lost_restore_target(cx)\n        .unwrap_or_else(|| this.focus_handle.clone());\n    target.focus(window, cx);\n});\n// `this.focus_handle` is the view's tracked handle. Keep `focus_lost:\n// Subscription` on the view; dropping it unregisters.\n```\n\n## Best Practices\n\n### ✅ Track Focus on Interactive Elements\n\n```rust\n// ✅ Good: Track focus for keyboard interaction\ninput()\n    .track_focus(&self.focus_handle)\n    .on_action(cx.listener(Self::on_enter))\n```\n\n### ✅ Provide Visual Focus Indicators\n\nDraw the framework's ring so custom controls match `Button` and `Input`:\n\n```rust\nuse gpui_kit::component::ThemeStyled as _;\n\nlet is_focused = self.focus_handle.is_focused(window);\n\ndiv()\n    .track_focus(&self.focus_handle)\n    .when(is_focused, |el| el.focus_ring_style(window, cx))\n```\n\nThe ring is painted 3px outside the element, so an ancestor with\n`overflow_hidden()` clips it; leave it room or draw the ring inside the element.\n\n### ❌ Don't: Forget to Track Focus\n\n```rust\n// ❌ Bad: No track_focus, keyboard navigation won't work\ndiv()\n    .on_action(cx.listener(Self::on_enter))\n```\n\n<!-- File: skills/gpui-kit/references/gpui/global.md (Tokens: ~940 | Category: anthropic-skill) -->\n# Global State\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Use Cases](#common-use-cases) · [Best Practices](#best-practices) · [When to Use](#when-to-use)\n\n## Overview\n\nGlobal state in GPUI provides app-wide shared data accessible from any context.\n\n**Key Trait**: `Global` - Implement on types to make them globally accessible\n\n## Quick Start\n\n### Define Global State\n\n```rust\nuse gpui_kit::Global;\n\n#[derive(Clone)]\nstruct AppSettings {\n    theme: Theme,\n    language: String,\n}\n\nimpl Global for AppSettings {}\n```\n\n### Set and Access Globals\n\n```rust\nfn main() {\n    gpui_kit::application().run(|cx: &mut App| {\n        // Set global\n        cx.set_global(AppSettings {\n            theme: Theme::Dark,\n            language: \"en\".to_string(),\n        });\n\n        // Access global (read-only)\n        let settings = cx.global::<AppSettings>();\n        println!(\"Theme: {:?}\", settings.theme);\n    });\n}\n```\n\n### Update Globals\n\n```rust\nimpl MyComponent {\n    fn change_theme(&mut self, new_theme: Theme, cx: &mut Context<Self>) {\n        cx.update_global::<AppSettings, _>(|settings, cx| {\n            settings.theme = new_theme;\n            // Global updates don't trigger automatic notifications\n            // Manually notify components that care\n        });\n\n        cx.notify(); // Re-render this component\n    }\n}\n```\n\n## Common Use Cases\n\n### 1. App Configuration\n\n```rust\n#[derive(Clone)]\nstruct AppConfig {\n    api_endpoint: String,\n    max_retries: u32,\n    timeout: Duration,\n}\n\nimpl Global for AppConfig {}\n\n// Set once at startup\ncx.set_global(AppConfig {\n    api_endpoint: \"https://api.example.com\".to_string(),\n    max_retries: 3,\n    timeout: Duration::from_secs(30),\n});\n\n// Access anywhere\nlet config = cx.global::<AppConfig>();\n```\n\n### 2. Feature Flags\n\n```rust\n#[derive(Clone)]\nstruct FeatureFlags {\n    enable_beta_features: bool,\n    enable_analytics: bool,\n}\n\nimpl Global for FeatureFlags {}\n\nimpl MyComponent {\n    fn render_beta_feature(&self, cx: &App) -> Option<impl IntoElement> {\n        let flags = cx.global::<FeatureFlags>();\n\n        if flags.enable_beta_features {\n            Some(div().child(\"Beta feature\"))\n        } else {\n            None\n        }\n    }\n}\n```\n\n### 3. Shared Services\n\n```rust\n#[derive(Clone)]\nstruct ServiceRegistry {\n    http_client: Arc<HttpClient>,\n    logger: Arc<Logger>,\n}\n\nimpl Global for ServiceRegistry {}\n\nimpl MyComponent {\n    fn fetch_data(&mut self, cx: &mut Context<Self>) {\n        let registry = cx.global::<ServiceRegistry>();\n        let client = registry.http_client.clone();\n\n        cx.spawn(async move |cx| {\n            let data = client.get(\"api/data\").await?;\n            // Process data...\n            Ok::<_, anyhow::Error>(())\n        }).detach();\n    }\n}\n```\n\n## Best Practices\n\n### ✅ Use Arc for Shared Resources\n\n```rust\n#[derive(Clone)]\nstruct GlobalState {\n    database: Arc<Database>,  // Cheap to clone\n    cache: Arc<RwLock<Cache>>,\n}\n\nimpl Global for GlobalState {}\n```\n\n### ✅ Immutable by Default\n\nGlobals are read-only by default. Use interior mutability when needed:\n\n```rust\n#[derive(Clone)]\nstruct Counter {\n    count: Arc<AtomicUsize>,\n}\n\nimpl Global for Counter {}\n\nimpl Counter {\n    fn increment(&self) {\n        self.count.fetch_add(1, Ordering::SeqCst);\n    }\n\n    fn get(&self) -> usize {\n        self.count.load(Ordering::SeqCst)\n    }\n}\n```\n\n### ❌ Don't: Overuse Globals\n\n```rust\n// ❌ Bad: Too many globals\ncx.set_global(UserState { ... });\ncx.set_global(CartState { ... });\ncx.set_global(CheckoutState { ... });\n\n// ✅ Good: Use entities for component state\nlet user_entity = cx.new(|_| UserState { ... });\n```\n\n## When to Use\n\n**Use Globals for:**\n- App-wide configuration\n- Feature flags\n- Shared services (HTTP client, logger)\n- Read-only reference data\n\n**Use Entities for:**\n- Component-specific state\n- State that changes frequently\n- State that needs notifications\n\n<!-- File: skills/gpui-kit/references/gpui/layout-style.md (Tokens: ~1837 | Category: anthropic-skill) -->\n# Layout & Styling\n\n**Contents:** [Overview](#overview) · [Quick Start](#quick-start) · [Common Patterns](#common-patterns) · [Styling Methods](#styling-methods) · [h_flex / v_flex](#h_flex--v_flex-helpers) · [Tailwind Shorthands](#tailwind-style-shorthand) · [Overflow & Scroll](#overflow-and-scroll) · [Absolute Positioning](#absolute-positioning) · [Stacking Order](#stacking-order) · [Theme Integration](#theme-integration) · [Conditional Styling](#conditional-styling) · [Text Styling](#text-styling)\n\n## Overview\n\nGPUI provides CSS-like styling with Rust type safety.\n\n**Key Concepts:**\n\n- Flexbox layout system\n- Styled trait for chaining styles\n- Size units: `px()`, `rems()`, `relative()`\n- Colors, borders, shadows\n\n## Quick Start\n\n### Basic Styling\n\n```rust\nuse gpui_kit::*;\n\ndiv()\n    .w(px(200.))\n    .h(px(100.))\n    .bg(rgb(0x2196F3))\n    .text_color(rgb(0xFFFFFF))\n    .rounded(px(8.))\n    .p(px(16.))\n    .child(\"Styled content\")\n```\n\n### Flexbox Layout\n\n```rust\ndiv()\n    .flex()\n    .flex_row()  // or flex_col() for column\n    .gap(px(8.))\n    .items_center()\n    .justify_between()\n    .children([\n        div().child(\"Item 1\"),\n        div().child(\"Item 2\"),\n        div().child(\"Item 3\"),\n    ])\n```\n\n### Size Units\n\n```rust\ndiv()\n    .w(px(200.))           // Pixels\n    .h(rems(10.))          // Relative to font size\n    .w(relative(0.5))      // 50% of parent\n    .min_w(px(100.))\n    .max_w(px(400.))\n```\n\n## Common Patterns\n\n### Centered Content\n\n```rust\ndiv()\n    .flex()\n    .items_center()\n    .justify_center()\n    .size_full()\n    .child(\"Centered\")\n```\n\n### Card Layout\n\n```rust\ndiv()\n    .w(px(300.))\n    .bg(cx.theme().surface)\n    .rounded(px(8.))\n    .shadow_md()\n    .p(px(16.))\n    .gap(px(12.))\n    .flex()\n    .flex_col()\n    .child(heading())\n    .child(content())\n```\n\n### Responsive Spacing\n\n```rust\ndiv()\n    .p(px(16.))           // Padding all sides\n    .px(px(20.))          // Padding horizontal\n    .py(px(12.))          // Padding vertical\n    .pt(px(8.))           // Padding top\n    .gap(px(8.))          // Gap between children\n```\n\n## Styling Methods\n\n### Dimensions\n\n```rust\n.w(px(200.))              // Width\n.h(px(100.))              // Height\n.size(px(200.))           // Width and height\n.min_w(px(100.))          // Min width\n.max_w(px(400.))          // Max width\n```\n\n### Colors\n\n```rust\n.bg(rgb(0x2196F3))        // Background\n.text_color(rgb(0xFFFFFF)) // Text color\n.border_color(rgb(0x000000)) // Border color\n```\n\n### Borders\n\n```rust\n.border(px(1.))           // Border width\n.rounded(px(8.))          // Border radius\n.rounded_t(px(8.))        // Top corners\n.border_color(rgb(0x000000))\n```\n\n### Spacing\n\n```rust\n.p(px(16.))               // Padding\n.m(px(8.))                // Margin\n.gap(px(8.))              // Gap between flex children\n```\n\n### Flexbox\n\n```rust\n.flex()                   // Enable flexbox\n.flex_row()               // Row direction\n.flex_col()               // Column direction\n.items_center()           // Align items center\n.justify_between()        // Space between items\n.flex_grow_1()              // Grow to fill space\n```\n\n## h_flex / v_flex Helpers\n\n`gpui_kit::component` provides shorthand helpers (import from `gpui_kit::component`):\n\n```rust\nuse gpui_kit::component::{h_flex, v_flex};\n\n// h_flex() = div().flex().flex_row().items_center()\nh_flex()\n    .gap_2()\n    .child(icon)\n    .child(label)\n\n// v_flex() = div().flex().flex_col()\nv_flex()\n    .gap_4()\n    .p_4()\n    .child(input1)\n    .child(input2)\n    .child(submit_btn)\n```\n\nThese are the standard layout primitives in `gpui_kit::component`. Prefer them over raw `div().flex()`.\n\n## Tailwind-style Shorthand\n\nGPUI provides Tailwind-style spacing/sizing shorthands:\n\n```rust\n// Spacing (0=0, 1=4px, 2=8px, 3=12px, 4=16px, ...)\n.p_2()    // padding: 8px\n.px_4()   // padding x: 16px\n.py_3()   // padding y: 12px\n.m_2()    // margin: 8px\n.gap_3()  // gap: 12px\n\n// Size\n.size_full()   // width: 100%, height: 100%\n.size_4()      // width: 16px, height: 16px\n.w_full()      // width: 100%\n.h_full()      // height: 100%\n.flex_1()      // flex: 1 1 0 (fill remaining space)\n.flex_shrink_0() // prevent shrinking\n```\n\n## Overflow and Scroll\n\n```rust\ndiv()\n    .overflow_hidden()          // clip content\n    .overflow_x_hidden()        // clip horizontal\n    .overflow_y_scrollbar()     // show scrollbar on y axis\n    .overflow_scroll()          // scroll both axes\n```\n\n## Absolute Positioning\n\n```rust\ndiv()\n    .relative()                 // position: relative (container)\n    .child(\n        div()\n            .absolute()         // position: absolute\n            .top_0()\n            .right_0()\n            .child(\"badge\")\n    )\n\n// Inset helpers\ndiv().absolute().inset_0()      // top/right/bottom/left: 0 (fill parent)\ndiv().absolute().top(px(8.)).left(px(8.))\n```\n\n## Stacking Order\n\n```rust\ndiv()\n    .relative()\n    .child(content)\n    .child(\n        div()\n            .absolute()\n            .top_0()\n            .right_0()\n            .child(\"badge\")\n    ) // later children are typically painted above earlier siblings\n```\n\nGPUI's general `Styled` API does **not** provide a `z_index(...)` method.\n\nFor normal elements, stacking is usually controlled by:\n\n- Parent/child composition\n- Absolute positioning\n- Render order of siblings (later siblings paint above earlier ones)\n\nIf you see a `z_index(...)` method in this repository, make sure it belongs to the specific component you are using: a component's own ordering API is not a general GPUI `Div` styling method.\n\n## Theme Integration\n\n```rust\ndiv()\n    .bg(cx.theme().surface)\n    .text_color(cx.theme().foreground)\n    .border_color(cx.theme().border)\n    .when(is_hovered, |el| {\n        el.bg(cx.theme().hover)\n    })\n```\n\n## Conditional Styling\n\n```rust\nuse gpui_kit::prelude::FluentBuilder as _;\n\ndiv()\n    .when(is_active, |el| el.bg(cx.theme().primary))\n    .when(!is_active, |el| el.opacity(0.5))\n    .when_some(optional_color.as_ref(), |el, color| el.bg(*color))\n```\n\n## Text Styling\n\n```rust\ndiv()\n    .text_sm()          // font-size: small\n    .text_base()        // font-size: base\n    .text_lg()          // font-size: large\n    .font_bold()        // font-weight: bold\n    .line_height_snug() // tighter line height\n    .truncate()         // overflow: ellipsis, single line\n    .whitespace_nowrap()\n```\n\n<!-- File: skills/gpui-kit/references/gpui/test-examples.md (Tokens: ~935 | Category: anthropic-skill) -->\n# Test Examples\n\n**Contents:** [Testing Best Practices](#testing-best-practices) · [Test Organization](#test-organization) · [Setup and Teardown](#setup-and-teardown) · [Assertions](#assertions) · [Performance Testing](#performance-testing) · [Running Tests](#running-tests) · [Basic Test Execution](#basic-test-execution) · [Test Configuration](#test-configuration) · [Advanced Test Execution](#advanced-test-execution) · [CI/CD Integration](#cicd-integration)\n\n## Testing Best Practices\n\n### Test Organization\n\nGroup related tests in modules:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    mod entity_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        fn test_creation() { /* ... */ }\n\n        #[gpui_kit::test]\n        fn test_updates() { /* ... */ }\n    }\n\n    mod async_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        async fn test_async_ops() { /* ... */ }\n    }\n\n    mod distributed_tests {\n        use super::*;\n\n        #[gpui_kit::test]\n        fn test_multi_app() { /* ... */ }\n    }\n}\n```\n\n### Setup and Teardown\n\nUse helper functions for common setup:\n\n```rust\nfn create_test_counter(cx: &mut TestAppContext) -> Entity<Counter> {\n    cx.new(|cx| Counter::new(cx))\n}\n\n#[gpui_kit::test]\nfn test_counter_operations(cx: &mut TestAppContext) {\n    let counter = create_test_counter(cx);\n\n    // Test operations\n}\n```\n\n### Assertions\n\nUse descriptive assertions:\n\n```rust\n#[gpui_kit::test]\nfn test_counter_bounds(cx: &mut TestAppContext) {\n    let counter = create_test_counter(cx);\n\n    // Test upper bound\n    for _ in 0..100 {\n        counter.update(cx, |counter, cx| {\n            counter.increment(cx);\n        });\n    }\n\n    let count = counter.read_with(cx, |counter, _| counter.count);\n    assert!(count <= 100, \"Counter should not exceed maximum\");\n\n    // Test lower bound\n    for _ in 0..200 {\n        counter.update(cx, |counter, cx| {\n            counter.decrement(cx);\n        });\n    }\n\n    let count = counter.read_with(cx, |counter, _| counter.count);\n    assert!(count >= 0, \"Counter should not go below minimum\");\n}\n```\n\n### Performance Testing\n\nTest performance characteristics:\n\n```rust\n#[gpui_kit::test]\nfn test_operation_performance(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    let start = std::time::Instant::now();\n\n    // Perform many operations\n    for i in 0..1000 {\n        component.update(cx, |comp, cx| {\n            comp.perform_operation(i, cx);\n        });\n    }\n\n    let elapsed = start.elapsed();\n    assert!(elapsed < Duration::from_millis(100), \"Operations should complete quickly\");\n}\n```\n\n## Running Tests\n\n### Basic Test Execution\n\n```bash\n# Run all tests\ncargo test\n\n# Run specific test\ncargo test test_counter_operations\n\n# Run tests in a specific module\ncargo test entity_tests::\n\n# Run with output\ncargo test -- --nocapture\n```\n\n### Test Configuration\n\nEnable test-support feature for GPUI tests:\n\n```toml\n[features]\ntest-support = [\"gpui/test-support\"]\n```\n\n```bash\ncargo test --features test-support\n```\n\n### Advanced Test Execution\n\n```bash\n# Run tests with iterations for property testing\ncargo test -- --test-threads=1\n\n# Run tests matching a pattern\ncargo test test_async\n\n# Run tests with backtrace on failure\nRUST_BACKTRACE=1 cargo test\n```\n\n### CI/CD Integration\n\nFor continuous integration:\n\n```yaml\n# .github/workflows/test.yml\nname: Tests\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: dtolnay/rust-toolchain@stable\n      - name: Run tests\n        run: cargo test --features test-support\n```\n\nGPUI's testing framework provides deterministic, fast, and comprehensive testing capabilities that mirror real application behavior while providing the control needed for thorough testing of complex UI and async scenarios.\n\n<!-- File: skills/gpui-kit/references/gpui/test-reference.md (Tokens: ~4500 | Category: anthropic-skill) -->\n# Test Reference\n\n**Contents:** [Testing Patterns](#testing-patterns) · [Testing Crash-Free State Management (Re-entrancy)](#testing-crash-free-state-management-re-entrancy) · [Property Testing](#property-testing) · [Distributed Systems Testing](#distributed-systems-testing) · [Mocking and Isolation](#mocking-and-isolation)\n\n## Testing Patterns\n\n### Basic Entity Testing\n\nTest entity creation, updates, and reads:\n\n```rust\n#[gpui_kit::test]\nfn test_counter_entity(cx: &mut TestAppContext) {\n    let counter = cx.new(|cx| Counter::new(cx));\n\n    // Test initial state\n    let initial_count = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(initial_count, 0);\n\n    // Test updates\n    counter.update(cx, |counter, cx| {\n        counter.count = 42;\n        cx.notify();\n    });\n\n    let updated_count = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(updated_count, 42);\n}\n```\n\n### Event Testing\n\nTest event emission and handling:\n\n```rust\n#[derive(Clone)]\nstruct ValueChanged {\n    new_value: i32,\n}\n\nimpl EventEmitter<ValueChanged> for MyComponent {}\n\n#[gpui_kit::test]\nfn test_event_emission(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| {\n        let mut comp = MyComponent::default();\n\n        // Subscribe to self\n        cx.subscribe_self(|this, event: &ValueChanged, cx| {\n            this.received_value = event.new_value;\n            cx.notify();\n        });\n\n        comp\n    });\n\n    // Emit event\n    component.update(cx, |_, cx| {\n        cx.emit(ValueChanged { new_value: 123 });\n    });\n\n    // Verify event was handled\n    let received = component.read_with(cx, |comp, _| comp.received_value);\n    assert_eq!(received, 123);\n}\n```\n\n### Action Testing\n\nTest action dispatching and handling:\n\n```rust\nactions!(my_app, [Increment, Decrement]);\n\n#[gpui_kit::test]\nfn test_action_dispatch(cx: &mut TestAppContext) {\n    let window = cx.update(|cx| {\n        cx.open_window(Default::default(), |_, cx| {\n            cx.new(|cx| MyComponent::new(cx))\n        }).unwrap()\n    });\n\n    let mut cx = VisualTestContext::from_window(window.into(), cx);\n    let counter = window.root(&mut cx).unwrap();\n\n    // Dispatch action via focus handle\n    let focus_handle = counter.read_with(&cx, |counter, _| counter.focus_handle.clone());\n    cx.update(|window, cx| {\n        focus_handle.dispatch_action(&Increment, window, cx);\n    });\n\n    let count = counter.read_with(&cx, |counter, _| counter.count);\n    assert_eq!(count, 1);\n}\n```\n\n### Async Testing\n\nTest async operations and background tasks:\n\n```rust\nimpl MyComponent {\n    fn load_data(&self, cx: &mut Context<Self>) -> Task<i32> {\n        cx.spawn(async move |this, cx| {\n            // Simulate async work\n            this.update(cx, |comp, _| comp.loading = true).await;\n            // Return result\n            42\n        })\n    }\n\n    fn background_update(&self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            // Background work\n            this.update(cx, |comp, _| {\n                comp.value += 10;\n            }).await;\n        }).detach();\n    }\n}\n\n#[gpui_kit::test]\nasync fn test_async_operations(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    // Test awaited task\n    let result = component.update(cx, |comp, cx| comp.load_data(cx)).await;\n    assert_eq!(result, 42);\n\n    // Test detached task\n    component.update(cx, |comp, cx| comp.background_update(cx));\n\n    // Detached tasks don't run until you yield\n    let value_before = component.read_with(cx, |comp, _| comp.value);\n    assert_eq!(value_before, 0);\n\n    // Run pending tasks\n    cx.run_until_parked();\n\n    let value_after = component.read_with(cx, |comp, _| comp.value);\n    assert_eq!(value_after, 10);\n}\n```\n\n### Timer Testing\n\nTest timer-based operations:\n\n```rust\nimpl MyComponent {\n    fn delayed_action(&self, cx: &mut Context<Self>) {\n        cx.spawn(async move |this, cx| {\n            cx.background_executor()\n                .timer(Duration::from_millis(100))\n                .await;\n\n            this.update(cx, |comp, cx| {\n                comp.action_performed = true;\n                cx.notify();\n            }).await;\n        }).detach();\n    }\n}\n\n#[gpui_kit::test]\nasync fn test_timers(cx: &mut TestAppContext) {\n    let component = cx.new(|cx| MyComponent::new(cx));\n\n    component.update(cx, |comp, cx| comp.delayed_action(cx));\n\n    // Action shouldn't have completed yet\n    let performed = component.read_with(cx, |comp, _| comp.action_performed);\n    assert!(!performed);\n\n    // Run until parked (timers complete)\n    cx.run_until_parked();\n\n    let performed = component.read_with(cx, |comp, _| comp.action_performed);\n    assert!(performed);\n}\n```\n\n### External I/O Testing\n\nFor tests involving external systems, use `allow_parking()`:\n\n```rust\n#[gpui_kit::test]\nasync fn test_external_io(cx: &mut TestAppContext) {\n    // Allow parking for external I/O\n    cx.executor().allow_parking();\n\n    // Simulate external operation\n    let (tx, rx) = futures::channel::oneshot::channel();\n    std::thread::spawn(move || {\n        std::thread::sleep(Duration::from_millis(10));\n        tx.send(42).ok();\n    });\n\n    let result = rx.await.unwrap();\n    assert_eq!(result, 42);\n}\n```\n\n## Testing Crash-Free State Management (Re-entrancy)\n\nThe most dangerous class of GPUI bugs is **entity re-entrancy**: code that tries to update or read an entity while it is already locked in a render/update pass. These bugs are invisible at compile time — they only panic at runtime, typically when the user clicks something in a list or dropdown.\n\n**Key properties of re-entrancy panics:**\n- Triggered by user interaction (click, key press), not during static rendering.\n- `#[should_panic]` only confirms the bug exists — tests must pass *without* panicking.\n- `Select` commits through `defer_in` after the key or click dispatch returns. Wait for the result with `cx.wait_for` instead of asserting straight after the interaction.\n\nDrive the component the way a user does. `SelectState` keeps its list state `pub(crate)`, so a test outside `gpui-component` opens the menu, presses keys, and observes through `selected_value()`, the element snapshot, and the delegate's own hooks.\n\n### Pattern: Confirm through the real UI\n\n```rust\nuse gpui_kit::test::{TestAppContextExt, TestWindowExt};\nuse gpui_kit::{\n    AnyWindowHandle, AppContext, Bounds, Context, Entity, TestAppContext, Window, WindowBounds,\n    WindowOptions,\n    component::{\n        IndexPath,\n        searchable_list::SearchableListChange,\n        select::{SearchableVec, Select, SelectDelegate, SelectItem, SelectState},\n    },\n    div,\n    prelude::*,\n    px, size,\n};\nuse std::{cell::RefCell, rc::Rc, time::Duration};\n\nstruct Form {\n    language: Entity<SelectState<SearchableVec<&'static str>>>,\n}\n\nimpl Render for Form {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .size_full()\n            .child(Select::new(&self.language).id(\"language\").w(px(240.)))\n    }\n}\n\n#[gpui_kit::test]\nasync fn confirming_from_the_keyboard_commits_the_value(cx: &mut TestAppContext) {\n    cx.update(gpui_kit::init);\n    let mut language = None;\n    let (handle, _view) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let state = cx.new(|cx| {\n                    SelectState::new(\n                        SearchableVec::new(vec![\"Rust\", \"Go\"]),\n                        Some(IndexPath::new(0)),\n                        window,\n                        cx,\n                    )\n                });\n                language = Some(state.clone());\n                let view = cx.new(|_| Form { language: state });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n    let language = language.unwrap();\n\n    // Open the menu, move to \"Go\" and confirm — the same path a user takes.\n    cx.update_window(handle.into(), |_, window, cx| {\n        window.render_frame(cx);\n        window.within(\"language\").click(\"input\", cx);\n        window.press(\"down\", cx);\n        window.press(\"enter\", cx);\n    })\n    .unwrap();\n\n    // Select commits through `defer_in` after the key dispatch returns, so\n    // wait for the closed menu instead of asserting straight away.\n    cx.wait_for(handle.into(), Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n            && window.find(\"language\").value() == Some(\"Go\")\n    })\n    .await;\n\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Go\")));\n}\n```\n\n### Pattern: Record `on_will_change` and `on_confirm`\n\nA recording delegate shows which changes the selection strategy proposed and what was committed. `on_will_change` receives the proposed changes and the selection to edit; the delegate applies them itself (the trait's default applies all of them). It has no `cx`, because it runs while the list entity is borrowed, so put side effects that need `cx` in `on_confirm`.\n\n```rust\ntype Log = Rc<RefCell<Vec<String>>>;\n\n/// Records each hook call; `accept: false` vetoes every change.\nstruct Recording {\n    items: Vec<&'static str>,\n    accept: bool,\n    log: Log,\n}\n\nimpl SelectDelegate for Recording {\n    type Item = &'static str;\n\n    fn items_count(&self, _: usize) -> usize {\n        self.items.len()\n    }\n\n    fn item(&self, ix: IndexPath) -> Option<&Self::Item> {\n        self.items.get(ix.row)\n    }\n\n    fn position<V>(&self, value: &V) -> Option<IndexPath>\n    where\n        Self::Item: SelectItem<Value = V>,\n        V: PartialEq,\n    {\n        self.items\n            .iter()\n            .position(|item| item.value() == value)\n            .map(IndexPath::new)\n    }\n\n    fn on_will_change(\n        &mut self,\n        selection: &mut Vec<(IndexPath, Self::Item)>,\n        changes: &[SearchableListChange],\n    ) {\n        for change in changes {\n            match *change {\n                SearchableListChange::Select { index } => {\n                    self.log.borrow_mut().push(format!(\"select {}\", index.row));\n                    if self.accept\n                        && let Some(item) = self.item(index)\n                    {\n                        selection.push((index, *item));\n                    }\n                }\n                SearchableListChange::Deselect { index } => {\n                    self.log\n                        .borrow_mut()\n                        .push(format!(\"deselect {}\", index.row));\n                    if self.accept {\n                        selection.retain(|(ix, _)| *ix != index);\n                    }\n                }\n            }\n        }\n    }\n\n    fn on_confirm(&mut self, final_selection: &[(IndexPath, Self::Item)]) {\n        let values: Vec<_> = final_selection.iter().map(|(_, item)| *item).collect();\n        self.log.borrow_mut().push(format!(\"confirm {values:?}\"));\n    }\n}\n\nstruct Picker {\n    language: Entity<SelectState<Recording>>,\n}\n\nimpl Render for Picker {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .size_full()\n            .child(Select::new(&self.language).id(\"language\").w(px(240.)))\n    }\n}\n\nfn open_picker(\n    cx: &mut TestAppContext,\n    accept: bool,\n) -> (AnyWindowHandle, Entity<SelectState<Recording>>, Log) {\n    cx.update(gpui_kit::init);\n    let log = Rc::new(RefCell::new(Vec::new()));\n    let mut language = None;\n    let (handle, _view) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let delegate = Recording {\n                    items: vec![\"Rust\", \"Go\"],\n                    accept,\n                    log: log.clone(),\n                };\n                let state =\n                    cx.new(|cx| SelectState::new(delegate, Some(IndexPath::new(0)), window, cx));\n                language = Some(state.clone());\n                let view = cx.new(|_| Picker { language: state });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n    (handle.into(), language.unwrap(), log)\n}\n\nfn confirm_next(cx: &mut TestAppContext, handle: AnyWindowHandle) {\n    cx.update_window(handle, |_, window, cx| {\n        window.render_frame(cx);\n        window.within(\"language\").click(\"input\", cx);\n        window.press(\"down\", cx);\n        window.press(\"enter\", cx);\n    })\n    .unwrap();\n}\n\n#[gpui_kit::test]\nasync fn hooks_fire_in_order_with_the_final_selection(cx: &mut TestAppContext) {\n    let (handle, language, log) = open_picker(cx, true);\n    confirm_next(cx, handle);\n    cx.wait_for(handle, Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n    })\n    .await;\n    // Single selection proposes replacing the old item, then commits once.\n    assert_eq!(\n        *log.borrow(),\n        [\"deselect 0\", \"select 1\", r#\"confirm [\"Go\"]\"#]\n    );\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Go\")));\n}\n```\n\n### Pattern: A vetoing delegate keeps the selection\n\nThe same delegate with `accept: false` applies none of the proposed changes:\n\n```rust\n#[gpui_kit::test]\nasync fn a_vetoing_delegate_keeps_the_selection(cx: &mut TestAppContext) {\n    let (handle, language, log) = open_picker(cx, false);\n    confirm_next(cx, handle);\n    cx.wait_for(handle, Duration::from_millis(500), |window, _| {\n        window.find(\"language\").expanded() == Some(false)\n    })\n    .await;\n    // The same changes are proposed, but the delegate applied none of them:\n    // `on_confirm` still runs, with the selection the user started from.\n    assert_eq!(*log.borrow(), [\"deselect 0\", \"select 1\", r#\"confirm [\"Rust\"]\"#]);\n    cx.update(|cx| assert_eq!(language.read(cx).selected_value(), Some(&\"Rust\")));\n    cx.update_window(handle, |_, window, _| {\n        assert_eq!(window.find(\"language\").value(), Some(\"Rust\"));\n    })\n    .unwrap();\n}\n```\n\n### Checklist: What to test for each component that uses `defer_in`\n\n- [ ] `confirm` path: no panic, the value is committed, and `selected_value()` agrees with the trigger's `value()`\n- [ ] `cancel` path (Escape, click outside): no panic, selection unchanged, menu closed (`expanded() == Some(false)`)\n- [ ] `on_will_change` veto: selection unchanged; `on_confirm` still runs, with the unchanged selection\n- [ ] `on_will_change` editing the selection: the final selection reflects the delegate's edit\n- [ ] Repeated confirms: each one leaves `selected_value()` matching the displayed value\n- [ ] `render_item` never panics even when called immediately after a mutation\n\n## Property Testing\n\nUse random data to test edge cases:\n\n```rust\n#[gpui_kit::test(iterations = 10)]\nfn test_counter_random_operations(cx: &mut TestAppContext, mut rng: StdRng) {\n    let counter = cx.new(|cx| Counter::new(cx));\n\n    let mut expected = 0i32;\n    for _ in 0..100 {\n        let delta = rng.random_range(-10..=10);\n        expected += delta;\n\n        counter.update(cx, |counter, cx| {\n            counter.count += delta;\n            cx.notify();\n        });\n    }\n\n    let actual = counter.read_with(cx, |counter, _| counter.count);\n    assert_eq!(actual, expected);\n}\n```\n\n## Distributed Systems Testing\n\nTest multiple app contexts communicating:\n\n```rust\n#[derive(Clone)]\nstruct NetworkMessage {\n    from: String,\n    to: String,\n    data: i32,\n}\n\n#[gpui_kit::test]\nfn test_distributed_apps(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {\n    // Create components in different app contexts\n    let comp_a = cx_a.new(|_| MyComponent::new(\"A\".to_string()));\n    let comp_b = cx_b.new(|_| MyComponent::new(\"B\".to_string()));\n\n    // Simulate message passing\n    comp_a.update(cx_a, |comp, cx| {\n        comp.send_message(\"B\", 42, cx);\n    });\n\n    // Run async operations\n    cx_a.run_until_parked();\n\n    // Verify message received in other context\n    comp_b.update(cx_b, |comp, _| {\n        comp.receive_messages();\n    });\n\n    let messages = comp_b.read_with(cx_b, |comp, _| comp.messages.clone());\n    assert_eq!(messages.len(), 1);\n    assert_eq!(messages[0].data, 42);\n}\n```\n\n### Interleaving Testing\n\nTest concurrent operations with random execution order:\n\n```rust\n#[gpui_kit::test(iterations = 10)]\nfn test_concurrent_operations(\n    cx_a: &mut TestAppContext,\n    cx_b: &mut TestAppContext,\n    mut rng: StdRng,\n) {\n    let comp_a = cx_a.new(|_| MyComponent::new());\n    let comp_b = cx_b.new(|_| MyComponent::new());\n\n    // Perform random operations across contexts\n    for i in 0..20 {\n        if rng.random_bool(0.5) {\n            comp_a.update(cx_a, |comp, cx| {\n                comp.perform_operation(i, cx);\n            });\n        } else {\n            comp_b.update(cx_b, |comp, cx| {\n                comp.perform_operation(i, cx);\n            });\n        }\n    }\n\n    // Run all pending operations\n    cx_a.run_until_parked();\n\n    // Verify final state\n    let state_a = comp_a.read_with(cx_a, |comp, _| comp.state);\n    let state_b = comp_b.read_with(cx_b, |comp, _| comp.state);\n\n    // Assert invariants hold despite execution order\n    assert!(state_a.is_consistent());\n    assert!(state_b.is_consistent());\n}\n```\n\n## Mocking and Isolation\n\n### Network Mocking\n\nCreate mock networks for testing distributed features:\n\n```rust\nstruct MockNetwork {\n    messages: Arc<Mutex<Vec<NetworkMessage>>>,\n}\n\nimpl MockNetwork {\n    fn new() -> Self {\n        Self {\n            messages: Arc::new(Mutex::new(Vec::new())),\n        }\n    }\n\n    fn send(&self, message: NetworkMessage) {\n        self.messages.lock().unwrap().push(message);\n    }\n\n    fn receive_all(&self) -> Vec<NetworkMessage> {\n        self.messages.lock().unwrap().drain(..).collect()\n    }\n}\n\n#[gpui_kit::test]\nfn test_networked_components(cx: &mut TestAppContext) {\n    let network = Arc::new(MockNetwork::new());\n\n    let sender = cx.new(|_| MessageSender::new(network.clone()));\n    let receiver = cx.new(|_| MessageReceiver::new(network));\n\n    // Send message\n    sender.update(cx, |sender, _| {\n        sender.send(\"Hello\");\n    });\n\n    // Receive message\n    receiver.update(cx, |receiver, _| {\n        receiver.receive_all();\n    });\n\n    let received = receiver.read_with(cx, |receiver, _| receiver.messages.clone());\n    assert_eq!(received, vec![\"Hello\"]);\n}\n```\n\n<!-- File: skills/gpui-kit/references/gpui/test.md (Tokens: ~4022 | Category: anthropic-skill) -->\n# Testing\n\n**Contents:** [Choose the test level](#choose-the-test-level) · [UI integration workflow](#ui-integration-workflow) · [Complete example](#complete-example) · [Queries and interactions](#queries-and-interactions) · [Frames and async work](#frames-and-async-work) · [Assertion boundaries](#assertion-boundaries) · [Additional resources](#additional-resources)\n\n## UI integration testing\n\nA UI integration test renders real components in a headless window, dispatches\nclicks, keyboard input and scrolling, then checks state, focus, layout and owner\ncallbacks. For example: add a Checkbox UI integration test that proves clicking\ntoggles the owner's value and disabled controls reject the interaction.\nUse this term when describing component interaction coverage.\n`#[gpui_kit::test]` runs the test; `gpui_kit::test` operates and inspects its UI.\n\n## Choose the test level\n\nUse ordinary Rust `#[test]` for pure logic. Use `#[gpui_kit::test]` and\n`TestAppContext` for entities, subscriptions, actions and async tasks; it can\ncreate headless windows too. `VisualTestContext` is available for existing GPUI\nwindow helpers. For an application UI flow, use `gpui_kit::test::TestWindowExt`\non the real `Window` and assert the behavior produced by native events.\n\nImport the Kit types you use explicitly and write `#[gpui_kit::test]`. Avoid `use gpui_kit::*;` in test modules: it imports GPUI’s `test` macro and can shadow Rust’s built-in `#[test]`. Add\n`test-support` to the application's `gpui-kit` development dependency, using\nexactly the same source and version as its normal dependency. The helpers\nrequire a Kit revision that includes them; check the installed API before\nassuming an older published release supports them. No extra testing crate or\nGPUI patch is required.\n\nFor a standalone test package beside a Kit checkout:\n\n```toml\n[package]\nname = \"ui-tests\"\nversion = \"0.1.0\"\nedition = \"2024\"\npublish = false\n\n[dev-dependencies]\ngpui-kit = { path = \"../gpui-kit/crates/kit\", features = [\"test-support\"] }\n```\n\nHeadless tests still need the platform's native build dependencies. Run\n`cargo generate-lockfile` once for the new package, then\n`cargo test --test ui --locked`. In the Kit repository the equivalent command\nis `cargo test -p gpui-kit --features test-support --test ui --locked`.\n\n## UI integration workflow\n\n1. Import the production view and constructor from the application library.\n   Keep state entities and subscriptions owned by that view. Define a view\n   inside a test only for a self-contained example or a deliberate fixture.\n2. Initialize with `cx.update(gpui_kit::init)`, open a headless window of an\n   explicit size through `gpui_kit::open_window`. Its Base `Root` renders\n   the dialog, sheet and notification layers above the view automatically.\n   Do not mount overlay layers in the application view.\n3. Render a frame and locate existing control IDs. Custom native elements opt\n   in with `.id(\"status\").test_support()` through `TestSupportExt`. Place it\n   before `.track_focus(&handle)`; custom wrappers must forward that method\n   to their inner element. Registration adds no layout container.\n4. Dispatch clicks, input and named keys through `TestWindowExt`. Exercise the\n   actual handler path; invoking callbacks or directly setting control state\n   would bypass the behavior being tested.\n5. Assert the initial state, the visible outcome after each meaningful action,\n   and the application result. Include a relevant negative case, such as a\n   disabled control rejecting the interaction or invalid input preventing save.\n6. Run the affected test target and report its result. An uncompiled example or\n   a test which never checks the action's outcome is not completion evidence.\n\n## Complete example\n\nCopy this into `tests/ui.rs`. It follows the Kit integration-test example\nfrom `crates/kit/tests/ui.rs`, with window setup inlined so this reference works\nwithout a repository checkout. In an application, replace that view definition\nwith an import of your production view.\n\n```rust\nuse gpui_kit::test::{TestSupportExt, TestWindowExt};\nuse gpui_kit::{\n    AppContext, Bounds, Context, Entity, SharedString, TestAppContext, Window, WindowBounds,\n    WindowOptions,\n    component::{\n        button::Button,\n        input::{Input, InputState},\n    },\n    div,\n    prelude::*,\n    px, size,\n};\n\nstruct Profile {\n    name: Entity<InputState>,\n    submitted: Option<SharedString>,\n}\n\nimpl Render for Profile {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        let status = self.submitted.as_ref().map_or_else(\n            || SharedString::from(\"Not saved\"),\n            |name| SharedString::from(format!(\"Saved: {name}\")),\n        );\n        div()\n            .size_full()\n            .flex()\n            .flex_col()\n            .p_4()\n            .gap_4()\n            .child(Input::new(&self.name).id(\"name\").w(px(240.)))\n            .child(\n                Button::new(\"save\")\n                    .label(\"Save\")\n                    .on_click(cx.listener(|this, _, _, cx| {\n                        this.submitted = Some(this.name.read(cx).value());\n                        cx.notify();\n                    })),\n            )\n            .child(\n                div()\n                    .id(\"status\")\n                    .role(gpui_kit::Role::Status)\n                    .test_support()\n                    .aria_label(status.clone())\n                    .child(status),\n            )\n    }\n}\n\n#[gpui_kit::test]\nfn saves_a_profile_through_the_ui(cx: &mut TestAppContext) {\n    cx.update(gpui_kit::init);\n    let (handle, profile) = cx.update(|cx| {\n        gpui_kit::open_window(\n            WindowOptions {\n                window_bounds: Some(WindowBounds::Windowed(Bounds::new(\n                    Default::default(),\n                    size(px(640.), px(480.)),\n                ))),\n                ..Default::default()\n            },\n            cx,\n            |window, cx| {\n                let view = cx.new(|cx| Profile {\n                    name: cx.new(|cx| InputState::new(window, cx)),\n                    submitted: None,\n                });\n                view\n            },\n        )\n        .expect(\"open test window\")\n    });\n\n    cx.update_window(handle.into(), |_, window, cx| {\n        window.render_frame(cx);\n        assert_eq!(window.find(\"status\").label(), Some(\"Not saved\"));\n\n        window.click(\"name\", cx);\n        window.input(\"Ada 中文\", cx);\n        let name = window.find(\"name\");\n        assert_eq!(name.focused(), Some(true));\n        assert_eq!(name.value(), Some(\"Ada 中文\"));\n        assert!(name.bounds().size.width > px(0.));\n        // Named keys share the same Window API and refresh the resulting frame.\n        window.press(\"backspace\", cx);\n        assert_eq!(window.find(\"name\").value(), Some(\"Ada 中\"));\n\n        window.click(\"save\", cx);\n        let status = window.find(\"status\");\n        assert!(status.visible());\n        assert_eq!(status.label(), Some(\"Saved: Ada 中\"));\n        assert!(status.bounds().top() >= window.find(\"save\").bounds().bottom());\n    })\n    .unwrap();\n\n    // Verify the application result as well as the native properties.\n    cx.update(|cx| {\n        assert_eq!(profile.read(cx).submitted.as_deref(), Some(\"Ada 中\"));\n    });\n}\n```\n\n## Queries and interactions\n\nImport `TestWindowExt` for queries and interactions from `gpui_kit::test`.\nFor custom registration, import `TestSupportExt`. Use normal Rust assertions with snapshots.\n\n| API | Behavior |\n| --- | --- |\n| `window.find(id)` | Requires a unique observed target; errors list registered paths. |\n| `window.try_find(id)` | Returns `None` when absent; ambiguous IDs still panic. |\n| `window.find_all(id)` | Returns all registered matches, including invisible ones, by current-frame bounds origin (y, then x); equal-origin order is unspecified. Empty when absent. |\n| `window.within(id)` | Resolves a native GPUI identity scope, including an unobserved ancestor. |\n| `click`, `right_click`, `double_click`, `hover` | Dispatch real pointer events at the target center. |\n| `click_at(id, offset, cx)` | Uses an offset from the target bounds' top-left corner. |\n| `window.click_with_modifiers(id, modifiers, cx)` | Centered left click with modifiers; sends modifier changes and restores the previous modifier state afterward. |\n| `window.click_with_options(id, options, cx)` | Combines offset, button, count, and modifiers using `ClickOptions`; restores the previous modifier state afterward. |\n| `scroll(id, delta, cx)` | Dispatches a GPUI `ScrollDelta` wheel event. |\n| `drag_to(from_id, to_id, cx)` | Drags between target centers within the current scope. |\n| `window.drag(from, to, cx)` | Drags between window-local points; use `bounds()` for precise or cross-scope geometry. |\n| `press(key, cx)` | Sends named GPUI keys such as `backspace`, `escape` or `secondary-a`. |\n| `input(text, cx)` | Types Unicode characters at current focus; click the input first. |\n\n`ClickOptions::new()` defaults to one left click at the center without modifiers.\nFor example, `ClickOptions::new().with_offset(point(px(8.), px(8.)))\n.with_button(MouseButton::Right).with_count(2).with_modifiers(Modifiers::shift())`\ncombines a local offset, right double-click, and Shift. Counts must be positive.\nConfigurable clicks preserve caps lock. `find_all` ordering is geometry for the\ncurrent frame, not stable identity, paint order, or business order; filter with\n`visible()` when counting visible matches.\n\nGPUI IDs need only be unique within their native scope. Use\n`window.within(\"dialog\").find(\"name\")` for repeated local IDs. Scoped windows\nalso provide pointer operations, `press` and `input`; keyboard helpers require\nobserved focus inside that scope and recheck it between characters. They do\nnot focus the target or replace its value. For a submenu with another\n`\"popup-menu\"` ID, retain the resolved outer scope before opening the submenu,\nthen query its descendants.\n\n## Inspect accessibility targets and individual events\n\nImport `gpui_kit::test::{TestQueryExt, TestEventExt}` for additional observation\nand event control. `elements()` returns observed elements in the current frame;\n`find_by_label(label)`, `try_find_by_label(label)` and `find_all_by_label(label)`\nmatch exact, case-sensitive native accessibility labels. `find_all_by_role(role)` selects an\nAccessKit `Role`. Results include invisible registrations, ordered by y, then x\nand a path tie-breaker. Required queries panic on absence; all unique queries\npanic on ambiguity. Scoped queries include strict descendants, excluding the\nscope node itself. These queries also work inside `within` and do not discover\nunobserved text or offscreen virtual rows. A label is an accessibility name,\nnot rendered text; use stable IDs when localization changes the name.\nThe pinned GPUI version does not expose an enumeration of anonymous rendered\ntext. Kit therefore has no general rendered-text `HasText` assertion; exact\naccessible-label queries cannot establish that text was actually drawn.\n\nFor gestures whose intermediate state matters, dispatch each step explicitly:\n\n```rust\nuse gpui_kit::test::TestEventExt;\n\nlet start = window.find(\"handle\").bounds().center();\nwindow.pointer_down(start, MouseButton::Left, cx);\nwindow.pointer_move(start + point(px(24.), px(0.)), Some(MouseButton::Left), cx);\n// Assert the state while the pointer is still held.\nwindow.pointer_up(start + point(px(24.), px(0.)), MouseButton::Left, cx);\n```\n\nPositions use window-local pixels. `pointer_move(position, pressed_button, cx)`\nreceives the held button explicitly; these helpers do not remember button state.\n`pointer_down` and `pointer_up` dispatch one click event each. Ordinary click, hover, scroll, drag and individual pointer steps use\nthe window's current modifiers. Configurable clicks temporarily use their\nexplicit modifiers and restore the preceding state afterward. `change_modifiers(modifiers, cx)` changes them and\npreserves caps lock; restore the previous modifiers when the gesture ends.\n`key_down(key, is_held, cx)` and `key_up(key, cx)` allow separate key transitions\nand auto-repeat (`is_held = true`). Key events combine modifiers written in the\nkey string with the window's held modifiers, without changing the retained\nmodifier state. Each step refreshes before dispatch and\ncompletes a frame afterward. These key events do not insert text; use `input`\nfor typing. Leave the window update and wait for deferred results when needed.\n\n## Exercise text composition through an input handler\n\n`gpui_kit::test::TestInput` bridges an explicit GPUI `InputHandler` to a window.\nFor an entity implementing `EntityInputHandler`, construct the adapter with\n`gpui_kit::ElementInputHandler::new(bounds, entity.clone())`, then pass it to\n`TestInput::new(handler, window)`. Keep the entity owned by the\nproduction view and use its actual input geometry. This bridge calls that\nhandler directly; it does not select the focused control or run an OS IME.\n\n`commit_text(text, cx)` commits through `replace_text_in_range`.\n`compose_text(replacement, text, selection, cx)` updates marked text through\n`replace_and_mark_text_in_range`. Replacement and selection ranges use UTF-16\ncode units, not UTF-8 byte offsets; selection is relative to the composed text.\nWith no replacement range, the handler replaces its current marked range or\nselection. Empty composition text cancels preedit according to the handler.\n`marked_text_range(cx)` returns a document-relative range;\n`selected_text_range(cx)` returns `Option<UTF16Selection>`, including direction;\n`unmark_text(cx)` ends marking while retaining its text. Mutation helpers complete a frame after the\nhandler call. They can test composition transitions and commit behavior, while\nplatform candidate windows, focus routing and OS IME integration still need\nnative tests. Use `window.input` for ordinary text typed at the current focus.\n\n## Resize, display scale and clipboard\n\nUse GPUI's existing `TestAppContext::simulate_window_resize(handle, size)` and\n`simulate_window_scale_factor_change(handle, scale)` outside a window update,\nthen call `render_frame` before inspecting layout. Pointer positions remain\nwindow-local logical pixels at every display scale. Assert both preserved\nediting state and resized geometry, then activate a control at its new bounds.\n\nExercise clipboard behavior through production shortcuts (`secondary-c`,\n`secondary-x`, `secondary-v`) and inspect `cx.read_from_clipboard()` when needed.\nThe test platform shares its clipboard across windows; editor state should\nremain window-specific. This verifies the test-platform adapter and application\nbindings, not the operating system's clipboard service.\n\nAfter activating an external Link, inspect `cx.opened_url()` to verify the URL\nreceived by the test platform and assert the application's click callback.\nThis does not establish that a browser opened the destination. The test\nplatform exposes no cursor-style reader; URL and callback assertions do not\nverify the pointer cursor.\n\n## Frames and async work\n\nSnapshots are owned facts from the last completed frame, not live elements.\nFetch a new snapshot after an interaction. Interaction helpers refresh frames;\nafter an external entity update, focus change or resize, call\n`window.render_frame(cx)` before querying.\n\nFor deferred actions, subscriptions or popup updates, leave `update_window`\nso GPUI can process its effects. Use `cx.run_until_parked()` for queued work,\nor import `TestAppContextExt` and await a bounded condition:\n\n```rust\ncx.wait_for(handle.into(), std::time::Duration::from_secs(1), |window, _| {\n    window.try_find(\"dialog\").is_none()\n}).await;\n```\n\n`wait_for` runs outside a borrowed window update and uses GPUI test time.\nProcess a queued action before changing any input that the action is meant to\nvalidate. Otherwise it can read the later input instead of the value at the\nintended test step.\n\nFor timers, check the UI before its deadline as well as after expiration.\nGPUI's non-synced `Animation` uses wall-clock time; advancing the test clock\ndoes not complete it. Use reduced motion when supported, or a bounded wait\nappropriate to that production animation before asserting final geometry.\n\n## Assertion boundaries\n\n- `checked()`, `selected()`, `expanded()`, `value()` and `label()` come from\n  native accessibility properties. `None` means unavailable; masked input\n  deliberately omits its value. Do not supply a second set of test-only state.\n- `disabled()` currently reports `Some(true)` or `None`. To prove a control is\n  enabled, perform the interaction and assert the result. Absence of a flag\n  is not proof that the control accepts input.\n- `focused()` measures the observed native focus scope. Missing bindings are\n  diagnosed when the native element advertises `Action::Focus`; controls\n  without that action can still return `None`. Register the real binding.\n- `bounds()` supports containment, relative position, overlap, scrolling and\n  drag assertions. `visible()` checks geometry, clipping and observed style;\n  it does not prove a target is unobstructed. Real hit testing decides whether\n  a click reaches the control.\n- Native properties can be wrong too. Pair them with real interactions,\n  geometry and the application result. A label is not rendered text, and a\n  correct accessibility value does not establish correct pixels.\n- These tests run in-process. Pixel comparisons need GPUI's separate renderer;\n  packaged-app behavior and full OS IME composition need other coverage. Kit's\n  explicit macOS (Metal) and Linux (WGPU) rendering target is\n  `cargo test -p gpui-kit --features test-support --test rendering --locked`.\n  Linux requires a working WGPU adapter and can use Mesa lavapipe. Windows\n  explicitly skips this target because GPUI 0.3.8 has no Windows headless renderer.\n  Missing renderer support on macOS or Linux fails instead of producing fake images.\n\n## Additional resources\n\n- [Website testing guide](https://gpui-kit.com/docs/test) — bilingual setup,\n  component coverage, platform requirements and CI.\n- [GPUI test examples](test-examples.md) — entity and context patterns.\n- [GPUI test reference](test-reference.md) — re-entrancy and property tests.\n\n<!-- File: skills/gpui-kit/references/recipes.md (Tokens: ~1009 | Category: anthropic-skill) -->\n# Tested application recipe\n\nThis complete view comes from `examples/ai_recipes/src/settings.rs`. That consumer crate depends only on `gpui-kit`; the same source is compiled and tested by `cargo test -p gpui-kit-recipes`, and `script/check-ai-recipes` keeps this copy identical to it. Pair it with that example's `src/bootstrap.rs`, which installs assets, initializes the library, and wraps the window in `Root`.\n\nThe view owns both input state and subscriptions. Rendering creates only elements. The window's `Root` renders the dialog, sheet and notification layers above the view.\n\n<!-- recipe:settings:start -->\n```rust\nuse gpui_kit::component::{\n    ActiveTheme, IconName, WindowExt,\n    button::Button,\n    checkbox::Checkbox,\n    form::{Field, Form},\n    input::{Input, InputEvent, InputState},\n    radio::RadioGroup,\n    switch::Switch,\n};\nuse gpui_kit::{\n    AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render, SharedString,\n    Styled as _, Subscription, Window, div,\n};\n\npub struct Settings {\n    name: Entity<InputState>,\n    preview: SharedString,\n    changes: usize,\n    enabled: bool,\n    remember: bool,\n    delivery: Option<usize>,\n    _subscriptions: Vec<Subscription>,\n}\n\nimpl Settings {\n    pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        let name = cx.new(|cx| InputState::new(window, cx).placeholder(\"Name\"));\n        let subscription = cx.subscribe_in(&name, window, |this, state, event, _, cx| {\n            if matches!(event, InputEvent::Change) {\n                this.preview = state.read(cx).value().to_string().into();\n                this.changes += 1;\n                cx.notify();\n            }\n        });\n        Self {\n            name,\n            preview: \"\".into(),\n            changes: 0,\n            enabled: false,\n            remember: false,\n            delivery: Some(0),\n            _subscriptions: vec![subscription],\n        }\n    }\n\n    pub fn input(&self) -> Entity<InputState> {\n        self.name.clone()\n    }\n\n    pub fn preview(&self) -> &SharedString {\n        &self.preview\n    }\n\n    pub fn changes(&self) -> usize {\n        self.changes\n    }\n}\n\nimpl Render for Settings {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        div()\n            .flex()\n            .flex_col()\n            .size_full()\n            .p_4()\n            .gap_3()\n            .bg(cx.theme().background)\n            .text_color(cx.theme().foreground)\n            .child(\"Profile\")\n            .child(\n                Form::new()\n                    .child(Field::new().label(\"Name\").child(Input::new(&self.name)))\n                    .child(Field::new().label(\"Preview\").child(self.preview.clone()))\n                    .child(\n                        Field::new().label_indent(false).child(\n                            Checkbox::new(\"remember\")\n                                .label(\"Remember name\")\n                                .checked(self.remember)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.remember = *value;\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .child(\n                        Field::new().label_indent(false).child(\n                            Switch::new(\"enabled\")\n                                .label(\"Enable notifications\")\n                                .checked(self.enabled)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.enabled = *value;\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .child(\n                        Field::new().label(\"Delivery\").child(\n                            RadioGroup::new(\"delivery\")\n                                .children([\"Immediately\", \"Daily summary\"])\n                                .selected_index(self.delivery)\n                                .on_change(cx.listener(|this, value, _, cx| {\n                                    this.delivery = Some(*value);\n                                    cx.notify();\n                                })),\n                        ),\n                    )\n                    .footer(\n                        Button::new(\"about\")\n                            .label(\"About…\")\n                            .icon(IconName::Info)\n                            .on_click(|_, window, cx| {\n                                window.open_dialog(cx, |dialog, _, _| {\n                                    dialog.title(\"About\").child(\"A complete GPUI Kit window\")\n                                });\n                            }),\n                    ),\n            )\n    }\n}\n```\n<!-- recipe:settings:end -->\n\nFor changes in this repository, run `script/check-ai docs`, `script/check-ai rust`, or `script/check-ai shell` for the relevant verification profile (or `script/check-ai all` for all three), and `cargo test -p gpui-kit-recipes` when a recipe source changes. For a downstream app, compile and test your own consumer, then verify keyboard/focus and visuals in a real window. Automated recipe tests do not establish a model success rate.\n\n<!-- File: skills/gpui-kit/references/usage.md (Tokens: ~2917 | Category: anthropic-skill) -->\n# gpui-kit Usage Guide\n\n**Contents:** [Setup](#setup) · [Component Types](#component-types) · [Common Components](#common-components) (Button, Input, Select, Checkbox, Icon, Dialog, Notification, Tabs, Tooltip, Form, List) · [Theming](#theming) · [Layout Helpers](#layout-helpers) · [Overlay Layers](#overlay-layers-dialogs-sheets-notifications) · [Shared Traits](#shared-traits)\n\n## Setup\n\nUse the [tested application recipe](recipes.md) for complete examples and their verification command. Store subscription handles on the owning view; binding one to a constructor-local variable alone does not keep it alive after construction.\n\n### 1. Cargo.toml\n\n```toml\n[dependencies]\ngpui-kit = \"0.7\" # re-exports GPUI, platform, base, component and the default icons; Shell is a separate host dependency\n```\n\n### 2. Initialization\n\n```rust\nfn main() {\n    gpui_kit::application()\n        .with_assets(gpui_kit::assets::Assets)\n        .run(move |cx| {\n            gpui_kit::init(cx); // MUST be first\n\n            // Wraps the view in a `Root`, which enables dialogs, sheets,\n            // notifications, tooltips and menus in this window.\n            gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| cx.new(|_| MyApp))\n                .expect(\"Failed to open window\");\n        });\n}\n```\n\nUse `gpui_kit::open_window` for application windows; it mounts `Root` as the window's root view.\n\n---\n\n## Component Types\n\n### Stateless (most components)\n\nUsed directly in `render`, no stored state:\n\n```rust\nuse gpui_kit::component::button::Button;\n\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {\n        Button::new(\"btn\").primary().label(\"Submit\")\n            .on_click(|_, _, _| println!(\"clicked\"))\n    }\n}\n```\n\n### Stateful (Input, Select, Combobox, etc.)\n\nRequire an `Entity<State>` stored in your view:\n\n```rust\nuse gpui_kit::component::input::{Input, InputState};\n\nstruct MyView {\n    name: Entity<InputState>,\n}\n\nimpl MyView {\n    fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {\n        Self {\n            name: cx.new(|cx| InputState::new(window, cx).placeholder(\"Your name\")),\n        }\n    }\n}\n\nimpl Render for MyView {\n    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {\n        Input::new(&self.name)\n    }\n}\n```\n\n---\n\n## Common Components\n\n### Button\n\n```rust\nuse gpui_kit::component::button::{Button, ButtonGroup};\n\n// Variants\nButton::new(\"btn\").label(\"Default\")\nButton::new(\"btn\").primary().label(\"Primary\")\nButton::new(\"btn\").danger().label(\"Delete\")\nButton::new(\"btn\").warning().label(\"Warning\")\nButton::new(\"btn\").success().label(\"Success\")\nButton::new(\"btn\").ghost().label(\"Ghost\")\nButton::new(\"btn\").link().label(\"Link\")\n\n// States\nButton::new(\"btn\").label(\"Text\").disabled(true)\nButton::new(\"btn\").label(\"Text\").loading(true)\nButton::new(\"btn\").label(\"Text\").selected(true)\n\n// With icon\nButton::new(\"btn\").icon(IconName::Plus).label(\"Add\")\n\n// Sizes\nButton::new(\"btn\").xsmall().label(\"XS\")\nButton::new(\"btn\").small().label(\"S\")\nButton::new(\"btn\").large().label(\"L\")\n\n// Group\nButtonGroup::new(\"group\")\n    .child(Button::new(\"a\").label(\"A\"))\n    .child(Button::new(\"b\").label(\"B\"))\n    .on_click(|indices, _, _| { /* selected indices */ })\n```\n\n### Input\n\n```rust\nuse gpui_kit::component::input::{Input, InputState};\n\n// State setup (in new/init)\nlet input = cx.new(|cx| InputState::new(window, cx)\n    .placeholder(\"Enter text...\")\n    .default_value(\"Hello\")\n);\n\n// Render\nInput::new(&input)\nInput::new(&input).cleanable(true)           // clear button\nInput::new(&input).disabled(true)\nInput::new(&input).prefix(Icon::new(IconName::Search).small())\nInput::new(&input).suffix(Button::new(\"b\").ghost().icon(IconName::X).xsmall())\nInput::new(&input).content_type(InputContentType::Password)\nInput::new(&input).mask_toggle()             // password reveal toggle\nInput::new(&input).appearance(false)         // remove default border/bg\n\n// Reading value\nlet value = input.read(cx).value();\n\n// Keep this subscription in the owning view (for example, `_subscriptions`).\nself._subscriptions.push(cx.subscribe_in(&input, window, |view, state, event, window, cx| {\n    match event {\n        InputEvent::Change => { let v = state.read(cx).value(); }\n        InputEvent::PressEnter { .. } => { /* submit */ }\n        InputEvent::Focus | InputEvent::Blur => {}\n    }\n}));\n```\n\n### Select\n\n```rust\nuse gpui_kit::component::select::{Select, SelectState};\n\n// Simple string list\nlet state = cx.new(|cx| {\n    SelectState::new(vec![\"Apple\", \"Orange\", \"Banana\"], Some(IndexPath::default()), window, cx)\n});\n\n// Render\nSelect::new(&state)\nSelect::new(&state).placeholder(\"Pick one\")\n\n// Reading selection\nlet selected = state.read(cx).selected_item();\n```\n\n### Checkbox / Switch / Radio\n\n```rust\nuse gpui_kit::component::{checkbox::Checkbox, switch::Switch};\n\n// Stateless (controlled)\nCheckbox::new(\"cb\").checked(self.checked)\n    .on_change(cx.listener(|this, checked, _, cx| {\n        this.checked = *checked;\n        cx.notify();\n    }))\n\nSwitch::new(\"sw\").checked(self.enabled)\n    .on_change(cx.listener(|this, checked, _, cx| {\n        this.enabled = *checked;\n        cx.notify();\n    }))\n```\n\n### Icon\n\n```rust\nuse gpui_kit::component::{Icon, IconName};\n\nIcon::new(IconName::Check)\nIcon::new(IconName::Search).small()\nIcon::new(IconName::Plus).large().text_color(cx.theme().primary)\n```\n\n### Dialog\n\n```rust\nuse gpui_kit::component::dialog::{Dialog, DialogAction, DialogClose, DialogFooter};\n\n// Open from window context. `footer` takes an element, not a closure.\n// DialogClose dismisses the dialog, so no manual close call is needed.\nwindow.open_dialog(cx, |dialog, _, _| {\n    dialog\n        .title(\"Export Report\")\n        .child(\"Choose a destination for the exported file.\")\n        .footer(\n            DialogFooter::new()\n                .gap_2()\n                .child(DialogClose::new().child(\n                    Button::new(\"cancel\").label(\"Cancel\").outline(),\n                ))\n                .child(DialogAction::new().child(\n                    Button::new(\"export\").label(\"Export\").primary(),\n                )),\n        )\n});\n```\n\n### AlertDialog\n\nUse `AlertDialog` — not `Dialog` — to confirm a consequential action. It is not\noverlay-closable and has no close button, so the choice must be made. Name the\nobject in the title and the result on the confirming button; see the Design\nGuides for the copy rules.\n\n```rust\nuse gpui_kit::component::button::ButtonVariant;\n\nwindow.open_alert_dialog(cx, |alert, _, _| {\n    alert\n        .title(\"Remove “Roadmap”?\")\n        .description(\"Files on disk aren’t deleted.\")\n        .confirm()\n        .ok_text(\"Remove\")\n        .ok_variant(ButtonVariant::Danger)\n        .on_ok(|_, _, _| true)\n});\n```\n\n`button_props(DialogButtonProps)` takes the same properties as one value; it\noverrides only the fields that value sets, so `confirm` and earlier callbacks\nsurvive it.\n\n### Notification\n\n```rust\n// Simple string message\nwindow.push_notification(\"Saved successfully!\", cx);\n\n// With type variant\nwindow.push_notification(\n    Notification::new(\"Upload complete\").info().message(\"File uploaded\"),\n    cx,\n);\n```\n\n### Tabs\n\n```rust\nuse gpui_kit::component::tab::{Tab, TabBar};\n\nTabBar::new(\"tabs\")\n    .child(Tab::new(\"tab1\").child(\"Overview\"))\n    .child(Tab::new(\"tab2\").child(\"Settings\"))\n    .child(Tab::new(\"tab3\").child(\"Logs\"))\n```\n\n### Tooltip\n\n```rust\n// On any element with .id(), add .tooltip():\ndiv()\n    .id(\"my-btn\")\n    .tooltip(|window, cx| Tooltip::new(\"Delete item\").build(window, cx))\n    .child(\"Delete\")\n\n// Or on a Button directly:\nButton::new(\"btn\").icon(IconName::Trash).tooltip(\"Delete\")\n\n// Component tooltips open after 500 ms; override per trigger,\n// or install `tooltip::TooltipDefaults` to change it app-wide:\nButton::new(\"help\").icon(IconName::Info).tooltip(\"Help\")\n    .tooltip_show_delay(Duration::ZERO)\n```\n\n### Form\n\n```rust\nuse gpui_kit::component::form::{v_form, h_form, field};\n\n// Vertical form\nv_form()\n    .child(field().label(\"Name\").child(Input::new(&self.name)))\n    .child(field().label(\"Email\").child(Input::new(&self.email)))\n    .footer(Button::new(\"submit\").primary().label(\"Submit\"))\n\n// Horizontal label alignment\nh_form()\n    .child(field().label(\"Username\").child(Input::new(&self.username)))\n```\n\n### List (searchable, virtualized)\n\n```rust\nuse gpui_kit::component::list::{List, ListState, ListDelegate, ListItem, ListEvent};\n\n// Implement ListDelegate for your data type, then:\nlet list_state = cx.new(|cx| ListState::new(MyDelegate::new(), window, cx));\n\n// Render\nList::new(&list_state)\n// Keep this subscription in the owning view, alongside list_state.\nself._subscriptions.push(cx.subscribe(&list_state, |this, _, event, cx| {\n    if let ListEvent::Select(index_path) = event {\n        // handle selection\n    }\n}));\n```\n\n---\n\n## Theming\n\n```rust\nuse gpui_kit::component::ActiveTheme as _;\n\n// Access colors\ncx.theme().primary\ncx.theme().background\ncx.theme().foreground\ncx.theme().border\ncx.theme().surface\ncx.theme().muted\ncx.theme().destructive\n\n// Use in styles\ndiv()\n    .bg(cx.theme().surface)\n    .text_color(cx.theme().foreground)\n    .border_color(cx.theme().border)\n```\n\n### Switch Theme\n\n```rust\nuse gpui_kit::component::{Theme, ThemeMode};\n\n// Switch light/dark: loads that mode's registered theme\nTheme::change(ThemeMode::Dark, None, cx);\n// or, as one edit among others\nTheme::update(cx, |theme| theme.mode = ThemeMode::Dark);\n\n// Load a named theme\nTheme::update(cx, |theme| theme.apply_config(&theme_config));\n\n// Edit fields; `update` keeps colors, tokens and the Base projection in step\nTheme::update(cx, |theme| theme.radius = px(8.));\n```\n\n---\n\n## Layout Helpers\n\n`gpui_kit::component` extends GPUI with convenient layout methods:\n\n```rust\nh_flex()    // div().flex().flex_row().items_center()\nv_flex()    // div().flex().flex_col()\n\n// Common patterns\nh_flex().gap_2().items_center()\n    .child(Icon::new(IconName::User))\n    .child(label(\"Username\"))\n\nv_flex().gap_4().p_4()\n    .child(Input::new(&self.name))\n    .child(Input::new(&self.email))\n    .child(Button::new(\"submit\").primary().label(\"Submit\"))\n```\n\n---\n\n## Overlay Layers (Dialogs, Sheets, Notifications)\n\nThe window's `Root` renders dialogs, sheets and notifications above the view, so a window opened with `gpui_kit::open_window` needs nothing else — `window.open_dialog(..)` just works. Applications define their own quit and close-window actions, key bindings, and confirmation flows. `open_window` returns `(AnyWindowHandle, Entity<V>)`. The complete tested consumer recipe is [`examples/ai_recipes/src/bootstrap.rs`](../../../examples/ai_recipes/src/bootstrap.rs).\n\nRoot always mounts all three layers. The former `Root::render_*_layer` methods have been removed; delete their calls from application views when migrating to 0.7.0.\n\n---\n\n## Shared Traits\n\nBuilders return the component so methods can be chained. Constructors follow component families: controls take a stable ID, retained controls take state, and compound parts may take no arguments. See [component conventions](conventions.md).\n\n- `Sizable`: `.xsmall()` / `.small()` / `.medium()` (default) / `.large()`\n- `Disableable`: `.disabled(bool)`\n- `Selectable`: `.selected(bool)`\n- `Styled`: any GPUI style methods (`.w()`, `.bg()`, `.p_2()`, etc.)\n\nFor any component not covered here, fetch its doc from:\n`https://gpui-kit.com/component/{name}.md`\n\n<!-- ... +4 more modular skills available via /api/skills/longbridge/gpui-component?path={path} -->\n</yakaai_skills>"}