select: Add render prop to customize item title display. (#1638)

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
This commit is contained in:
obito 2025-11-18 20:30:37 +08:00 committed by GitHub
parent 01082f11d2
commit 9d11418bd1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -41,6 +41,10 @@ pub trait SelectItem: Clone {
fn display_title(&self) -> Option<AnyElement> {
None
}
/// Render the item for the select dropdown menu, default is to render the title.
fn render(&self, _: &mut Window, _: &mut App) -> impl IntoElement {
self.title().into_element()
}
/// Get the value of the item.
fn value(&self) -> &Self::Value;
/// Check if the item matches the query for search, default is to match the title.
@ -184,7 +188,7 @@ where
);
}
fn render_item(&self, ix: IndexPath, _: &mut Window, cx: &mut App) -> Option<Self::Item> {
fn render_item(&self, ix: IndexPath, window: &mut Window, cx: &mut App) -> Option<Self::Item> {
let selected = self
.selected_index
.map_or(false, |selected_index| selected_index == ix);
@ -194,16 +198,10 @@ where
.map_or(Size::Medium, |state| state.read(cx).options.size);
if let Some(item) = self.delegate.item(ix) {
let content = item.display_title().unwrap_or_else(|| {
div()
.whitespace_nowrap()
.child(item.title().to_string())
.into_any_element()
});
let list_item = SelectListItem::new(ix.row)
.selected(selected)
.with_size(size)
.child(content);
.child(div().whitespace_nowrap().child(item.render(window, cx)));
Some(list_item)
} else {
None