refactor: introduce the internal gpui-base architecture (#2677)
## Summary
This PR introduces the internal `gpui-base` foundation crate and
migrates reusable GPUI behavior out of `gpui-component` while keeping
the styled UI facade as the canonical full-component layer.
## Before / After
| Area | Before | After |
| --- | --- | --- |
| Crate boundary | Reusable behavior and styled components lived
together in `gpui-component` | `gpui-component -> gpui-base -> gpui` is
a one-way dependency; `gpui-base` is workspace-internal and is not a
publishing milestone |
| Shared infrastructure | Geometry, events, focus trap, styled helpers,
history, index paths, auto-scroll, virtual lists, and scrollbar behavior
were owned by UI | Generic implementations live in `gpui-base`; existing
`gpui_component` paths re-export the same type identity where applicable
|
| Scrollbar | State, painting, dragging, handles, visibility, and theme
styling were coupled in `crates/ui/src/scroll/scrollbar.rs` | The
complete primitive lives in `gpui_base::Scrollbar`; UI re-exports it
directly from `scroll/mod.rs`; project-specific `Scrollable` and
`ScrollableMask` remain in UI |
| Scrollbar API | `ScrollbarShow` and `.scrollbar_show(...)` |
`ScrollbarMode` and `.mode(...)`; no compatibility alias is retained |
| Scrollbar styling | Appearance was fixed by the legacy UI theme |
Fluent `ScrollbarStyles` covers track/thumb normal, hover, and active
appearance and geometry; Base has a minimal fallback and UI Theme
overrides it |
| Base globals | Styled helpers depended on an ad-hoc `StyledTheme`
projection | One `gpui_base::Theme` global owns semantic tokens and
module defaults such as `ScrollbarTheme { mode, styles }` |
| Theme updates | Direct Story mutation could leave Base scrollbar state
stale | `Theme::set_scrollbar_mode` synchronizes UI Theme and Base
Theme; old serialized `scrollbar_show` state is accepted through a serde
migration alias |
| Controls | Behavior, presentation, content, and state styling were
interleaved | Base primitives own reusable interaction/state contracts;
UI keeps variants, sizing, labels/icons, layout, theme values, tooltips,
and presentation |
| Style boundary | `ui/styled.rs` mixed generic and UI-specific helpers
| Generic GPUI styled/focus helpers moved to Base; UI keeps sizing and
component traits; `ui/styled.rs` is re-export-only |
| Specifications | Decisions were spread across working notes | RFC,
style/motion design, milestones, validation state, and per-control
review criteria live under `specs/` |
## Compatibility and deliberate changes
- Existing styled component module paths remain available through
`gpui_component`.
- Button, Checkbox, Switch, and Slider were manually checked in Story
during migration.
- `ScrollbarShow` is intentionally removed in favor of `ScrollbarMode`.
- Canonical Toggle and Switch keyboard/focus behavior was adopted after
explicit review; these exceptions are documented in the checklist.
- Base controls remain presentation-free. Scrollbar is the intentional
exception because GPUI does not provide one; it has only a minimal
default paint that application/UI styles can override.
- Radio vertical integration, overlay/popup extraction, Dock extraction,
and Registry rollout remain deferred.
- `Scrollable` and `ScrollableMask` intentionally remain in `crates/ui`.
- The intentionally updated Apache license files are preserved.
## Test Plan
- `cargo fmt --all --check`
- `cargo check -p gpui-base -p gpui-component -p gpui-component-story`
- `cargo check -p gpui-component --no-default-features`
- `cargo clippy -p gpui-base -p gpui-component --all-targets -- --deny
warnings`
- `cargo test -p gpui-base --lib` — 71 passed
- `cargo test -p gpui-component --lib` — 441 passed
- `cargo test -p gpui-component --test base_compat --test
legacy_button_compat --test legacy_controls_compat` — 18 passed
- `cargo test -p gpui-component-cli --test cli` — 9 passed
- `git diff --check`
- Manual Story verification: Button, Switch, Checkbox, and Slider
Publishing/package verification for `gpui-base` is intentionally outside
this phase.
---------
Co-authored-by: Codex <codex@openai.com> J
Jason Lee committed
1bb129b56297b8a3f5b40f2f52d37838555a2cf9
Parent: 46576ae
Committed by GitHub <noreply@github.com>
on 8/13/2026, 3:37:40 AM