## Break Change
- The `width`, `border_width` method has been removed from Sidebar, use
`Styled` trait to use `w`, `border` method from GPUI instead.
```diff
Sidebar::left()
- .width(relative(1.))
- .border_width(px(0.))
+ .w(relative(1.))
+ .border_0()
.collapsed(false)
```
This makes use of the `IconNamed` trait and a blanked implementation to
convert anything that implements this to an `Icon`.
This allows for easily defined custom versions of `IconName`, while
minimally changing existing code (essentially only if you previously
made use of the `.path()` method on the `IconName` enum; this now
requires an import of the `IconNamed` trait).
# Example
```rust
use gpui_component::IconNamed;
pub enum IconName {
Encounters,
Monsters,
Spells,
}
impl IconNamed for IconName {
fn path(self) -> gpui::SharedString {
match self {
IconName::Encounters => "icons/encounters.svg",
IconName::Monsters => "icons/monsters.svg",
IconName::Spells => "icons/spells.svg",
}
.into()
}
}
// this allows for the following interactions (works with anything that has the `.icon(icon)` method
Button::new("my-button").icon(IconName::Spells);
Icon::new(IconName::Monsters);
```
If you want to directly "render" a custom `IconName` you must implement
the `RenderOnce` trait and derive `IntoElement` on the `IconName`.
```rust
use gpui::{IntoElement, RenderOnce};
use gpui_component::IconNamed;
#[derive(IntoElement)]
pub enum IconName {
// The same as before
}
impl IconNamed for IconName {
// The same as before
}
impl RenderOnce for IconName {
fn render(self, _: &mut gpui::Window, _: &mut gpui::App) -> impl gpui::IntoElement {
gpui_component::Icon::empty().path(self.path())
}
}
// this allows for the following interaction
div()
.child(IconName::Monsters)
```
Overall I think is an improvement to the existing way to do custom
`IconName` implementations.
I am unsure if this change should also be reflected in the documentation
on the section with "Icons & Assets", though I personally think it would
make sense to highlight this way to do custom versions of `IconName` as
it is considerably less involved than the current approach.
Closes#1627.
---------
Co-authored-by: Jason Lee <huacnlee@gmail.com>
Fixes#1410
## Problem
The `display_title` prop was overriding the default way dropdown option
titles are displayed, causing incorrect rendering of option titles.
**Expected behavior:**
<img width="716" height="944" alt="Expected dropdown display"
src="https://github.com/user-attachments/assets/38926731-32dd-4a16-9d08-7f2eed2c99a4"
/>
**Actual behavior:**
<img width="580" height="974" alt="image"
src="https://github.com/user-attachments/assets/d96b935a-ce4d-462c-a9ce-4995f5c8eeb5"
/>
## Solution
- Revert the `display_title` change that was causing the issue
- Add a `render` function to allow custom rendering of option titles
instead
This approach provides more flexibility for customizing option display
while preserving the default behavior.
cc @stippi
Fix the issue where clicking a button inside a table row can't stop the
click event from propagating to the table, causing the `td` element to
be selected unexpectedly.
This is a follow up to #1560 I noticed a couple small issues with
resizable panels and their use in docks after experimenting a lot:
- Sometimes the resizable group would take about ~500ms to update after
a resize. This was caused by the `StackPanel` not getting notified and
therefore not redrawn when the `ResizableState` was notified, as well as
the notify in `adjust_to_container_size` not actually firing properly.
The latter was fixed by defering the notify, though I'm still not quite
sure why that is necessary.
- In a couple of places, the total size all the panel missmatches the
container size, causing small glitches the first time a panel is
resized. Update the code in those places to properly adjust all the
panel sizes so they match the container size.
---------
Co-authored-by: Jason Lee <huacnlee@gmail.com>
## Breaking changes
```diff
- Label::new()
+ PlotLabel::new()
- Axis::new()
+ PlotAxis::new()
```
This is to avoid naming conflicts with `gpui` and `gpui-component`.
Currently, there is no good way for a Panel in a dock to e.g. add a tab
to its own tab bar. This is especially annoying as the state in
DockArea::items isn't synced to the underlying views, meaning the
`DockArea::add_panel` function will do nothing after first splitting the
panel, and then deleting the only element in the first part of the
split.
https://github.com/user-attachments/assets/2c61f2f0-9b1c-4154-8a53-b917335b94f0
This pull request adds a function that is called when a PanelView is
added to a tabbar via `add_panel` or `insert_panel_at` or when it is
removed via `detach_panel`.
This allows for entities that implement Panel to keep track of and
directly access the tab bar they belong to, and for example add new
panels to it through buttons in the dropdown menu or the top right of
the tab bar.
Right now the last tab can be closed via the keyboard action, even
though it's explicitly not allowed to be closed via the context menu.
This can result in an invalid app state. This pull request takes the
same check that's currently done to decide whether the close button
should be drawn in the context menu, and adds it to the close action.
Fixes#1562
## Problem
Single-line input fields were blocking all scroll wheel events,
preventing parent containers from handling vertical page scrolling.
## Solution
- Check if input is in single-line mode and scroll is purely vertical
- Allow vertical scroll events to propagate in single-line mode
- Only stop propagation when scroll offset actually changes
## Behavior
- Single-line inputs: vertical scroll passes through to parent
- Multi-line inputs: all scroll behavior unchanged
- Horizontal scrolling still works in both modes
Currently, if dismiss is called from the content_builder or
action_builder, the closing animation doesn't play.
This is because the callback happens after the `closing` variable is
set, so the animation will only start on the next frame, (and for some
reason notify() doesn't trigger another frame?).
This change makes it so that the content_builder is called first, so the
closing animation starts playing immediately on the same frame.
This also adds a check to dismiss to prevent spawning unnecessary
futures if it is called multiple times
## Break Change
- The `Root::render_notification_layer`, `Root::render_sheet_layer`,
`Root::render_dialog_layer` has been removed, we don't need it now, the
Root element has default rendered them.
- Add `open`, `on_open_change` method to control open state.
- Add `default_open` method.
## Break Change
This PR to rewrite the API of Popover API to make it easy to use.
- The `content` method now can receive an element directly.
```diff
- .content(|window, cx| {
- cx.new(|cx| {
- PopoverContent::new(window, cx, |_, _| {
- div().child("This popover content.")
- })
- })
- })
+ .content(|state, window, cx| {
+ div().child("This popover content.")
+ })
```
- And you can also just use `child` and `children` to add child
elements.
```rs
Popover::new("my-popover")
.trigger(Button::new("trigger").label("Open Popover"))
.child("This popover content.")
```
- Removed `PopoverContent`, and changed `Popover` default paddings to
`p_3`.
## Breaking change
```diff
- Tab::new("Account")
+ Tab::new().label("Account")
```
We can currently create a tab item without a label, such as only an
icon.
Adds the ability to choose between a linear and a logarithmic scale for
the slider. A logarithmic scale is the right and intuitive choice for
many different slider applications. Building this right into the
component has two advantages:
- The user doesn't have to convert at every point where they might use
or update the slider value
- On a logarithmic scale, the distance between steps varies over the
sliders range. This implementation respects that
---------
Co-authored-by: Jason Lee <huacnlee@gmail.com>
When `on_click` is not specified on the button group, this PR allows for
specifying on_click on each individual button.
e.g.
```rs
let buttons = ButtonGroup::new(("buttons", index)).layout(Axis::Vertical)
.child(Button::new(("install", index)).label("Install").icon(download_icon).success().on_click(move |_, _, cx| {
// Install
})
.child(Button::new(("open", index)).label("Open Page").icon(IconName::Globe).info().on_click(move |_, _, cx| {
// Open page
}));
```
This pull request adds a drag event to the slider bar itself, analogous
to the drag handles, in case the slider is not a range slider. This
allows for a more intuitive interaction with the slider, where one can
click and drag on any part of the slider bar container.
https://github.com/user-attachments/assets/4d41ba10-2992-4a42-beb6-0bc376185c5e
This doesn't change the behavior for range sliders, as it's ambiguous
which slider should be dragged in case the event starts between the
sliders. Though if desired, it wouldn't be difficult to implement the
same behavior for clicks below the start or above the end slider.
Adds a vertical option to the button group
Also added an example of the vertical button group to the story
Also fixed button rounding only working when both tl/bl and tr/br are
both set, now they can be set individually
I'm not sure if the justify_center in `.when(self.vertical, |this|
this.flex_col().justify_center())` is needed, but I added it to match
the behaviour of `.items_center()` when the flex direction is row.
Currently, the bounds are zero on the first frame.
Therefore, the extra_rows_count will always be zero on the first frame.
This causes rendering issues for row border & row stripes.
Unfortunately, I don't know how to get the correct height on the first
frame to fix the row stripes.
However, an easy fix for the row border rendering issue is to disable
the table_is_filled check. The check is problematic anyways since the
border affects the height of the element.
I attached a video showing the issue, the border doesn't render on the
first frame and the height of the element also shifts due to the border:
https://github.com/user-attachments/assets/b154c686-cd9c-4b6b-8ba6-c79640297abc
---------
Co-authored-by: Jason Lee <huacnlee@gmail.com>
## Break Change
- Renamed `Drawer` to `Sheet`, also renamed relative method contains
`drawer` to `sheet`.
- Renamed `ContextModal` to `WindowExt`.
```diff
- use gpui_component::drawer::Drawer
+ use gpui_component::sheet::Sheet
- use gpui_component::ContextModal
+ use gpui_component::WindowExt
```
## Break Change
- The original `child` method has been renamed to `item`.
- Now the add new `child` to accept a `DescriptionItem` type like the
`children` method.
## Break Changes
- Refactor `Toggle` new API to require a `id`, and renamed `on_change`
to `on_click.
- Renamed `on_change` method to `on_click` for `ToggleGroup`.
```diff
- Toggle::label("Hello").id("hello").on_change(..)
+ Toggle::new("hello).label("Hello").on_click(..)
- ToggleGroup::new("group1).on_change(..)
+ ToggleGroup::new("group1).on_click(..)
```
https://github.com/longbridge/gpui-component/pull/1502#issuecomment-3485354324
## Break Change
- The `DatePicker` and `Select` has changed `cleanable` default from
`true` to `false`.
- Updated `Input`, `DatePicker` and `Select` the `cleanable` to have a
argument.
```diff
- pub fn cleanable(mut self)
+ pub fn cleanable(mut self, cleanable: bool)
```
---------
Co-authored-by: Jason Lee <huacnlee@gmail.com>
## Break Change
- Removed `set_query_input`, `query_input` and `no_query` method from
List. Now use `List::new(&state).searchable(false)` to intead of
`no_query`.
- Removed `searchable` method from `SelectDelegate`, use
`Select::searchable` instead.