button: Preserve inner DropdownButton configuration (#2760)
## Summary
`DropdownButton` now preserves the configuration of its inner action
button instead of unconditionally replacing shared values or mirroring
action-specific `Button` options.
### What changed
- An outer variant or size still applies to both halves. When either is
unset, the inner button's value becomes the shared value for the split.
- Action-specific options such as `compact`, `loading`, `rounded`,
`tooltip`, and the click handler remain on the inner `Button`.
- An inner selected or disabled state is no longer cleared by the
`DropdownButton` defaults.
- The menu trigger renders independently of the optional action button
instead of disappearing when `.button(...)` is omitted.
- The existing ghost behavior is explicit: an unselected ghost split
renders as two separate buttons and joins when selected.
- The Story uses focused export, save, and recent-file examples with
visible action feedback.
## Breaking Changes
`compact`, `loading`, `rounded`, and `tooltip` have been removed from
`DropdownButton`. Set them on the inner action `Button`:
```diff
DropdownButton::new("dropdown")
- .button(Button::new("btn").label("Save"))
- .compact()
- .loading(is_saving)
- .rounded(ButtonRounded::Small)
- .tooltip("Save options")
+ .button(
+ Button::new("btn")
+ .label("Save")
+ .compact()
+ .loading(is_saving)
+ .rounded(ButtonRounded::Small)
+ .tooltip("Save options"),
+ )
.dropdown_menu(|menu, _, _| menu)
```
Leaving the outer variant or size unset now uses the inner button's
value for both halves:
```rust
DropdownButton::new("dropdown")
.button(Button::new("btn").label("Delete").danger().small())
.dropdown_menu(|menu, _, _| menu)
```
Loading is now action-specific. A loading inner button is inert while
the menu trigger remains available; use `DropdownButton::disabled(true)`
when both halves must be disabled.
These four removed methods had no users in the downstream application,
so no downstream call site required migration.
## Test plan
- `cargo test -p gpui-component --lib` — 426 passed.
- `cargo test -p gpui-component --test legacy_button_compat` — 5 passed.
- `cargo clippy --workspace --all-targets -- --deny warnings` — passed.
- `cargo fmt --all -- --check` and `git diff --check` — passed.
- `cargo check -p gpui-component-story` — passed.
## AI-generated code
The initial implementation was written with Claude Code. The final
design was reviewed and refined with Codex, then reviewed by hand.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex <codex@openai.com> J
Jason Lee committed
6bd53de4bf4de080b9f23b9c90c0b3effb567927
Parent: 222cf96
Committed by GitHub <noreply@github.com>
on 8/18/2026, 12:27:54 PM