diff --git a/src/views/dropdown.rs b/src/views/dropdown.rs index f8da6852..9f10471f 100644 --- a/src/views/dropdown.rs +++ b/src/views/dropdown.rs @@ -1,3 +1,9 @@ +#![deny(missing_docs)] +//! A view that allows the user to select an item from a list of items. +//! +//! The [Dropdown] struct provides several constructors, each offering different levels of customization and ease of use +//! +//! The [DropdownCustomStyle] struct allows for easy and advanced customization of the dropdown's appearance use std::{any::Any, rc::Rc}; use floem_reactive::{ @@ -16,7 +22,7 @@ use crate::{ prop, prop_extractor, style::{CustomStylable, Style, StyleClass, Width}, style_class, - unit::{PxPctAuto, UnitExt}, + unit::PxPctAuto, view::{default_compute_layout, IntoView, View}, views::{container, scroll, stack, svg, text, Decorators}, AnyView, @@ -24,32 +30,39 @@ use crate::{ use super::list; -type ChildFn = dyn Fn(T) -> (Box, Scope); +type ChildFn = dyn Fn(T) -> (AnyView, Scope); -style_class!(pub DropdownClass); +style_class!( + /// A Style class that is applied to all dropdowns. + pub DropdownClass +); -prop!(pub CloseOnAccept: bool {} = true); +prop!( + /// A property that determines whether the dropdown should close automatically when an item is selected. + pub CloseOnAccept: bool {} = true +); prop_extractor!(DropdownStyle { close_on_accept: CloseOnAccept, }); -pub fn dropdown( - active_item: AIF, - main_view: MF, - iterator: I, - list_item_fn: LF, -) -> Dropdown -where - MF: Fn(T) -> Box + 'static, - I: IntoIterator + Clone + 'static, - LF: Fn(T) -> Box + Clone + 'static, - T: Clone + 'static, - AIF: Fn() -> T + 'static, -{ - Dropdown::new(active_item, main_view, iterator, list_item_fn) -} - -/// A dropdown widget +/// # A customizable dropdown view for selecting an item from a list. +/// +/// The `Dropdown` struct provides several constructors, each offering different levels of +/// customization and ease of use: +/// +/// - [`Dropdown::basic_rw`]: The simplest constructor, ideal for quick setup with minimal customization. +/// It uses default views and assumes direct access to a signal that can be both read from and written to for driving the selection of an item. +/// +/// - [`Dropdown::basic`]: Similar to `basic_rw`, but uses a read-only function for the active item, and requires that you manually provide an `on_accept` callback. +/// +/// - [`Dropdown::new`]: Offers full customization, letting you define custom view functions for +/// both the main display and list items. Uses a read-only function for the active item and requires that you manually provide an `on_accept` callback. +/// +/// - [`Dropdown::new_rw`]: Combines the full customization of `new` with the read-write signal +/// capability of `basic_rw`. +/// +/// +/// Choose the constructor that best fits your needs based on the level of customization required. /// /// **Styling**: /// You can modify the behavior of the dropdown through the `CloseOnAccept` property. @@ -179,6 +192,10 @@ impl View for Dropdown { } impl Dropdown { + /// Creates a default main view for the dropdown. + /// + /// This function generates a view that displays the given item as text, + /// along with a chevron-down icon to indicate that it's a dropdown. pub fn default_main_view(item: T) -> AnyView where T: std::fmt::Display, @@ -191,12 +208,13 @@ impl Dropdown { "##; + // TODO: this should be more customizable stack(( text(item), container(svg(CHEVRON_DOWN).style(|s| s.size(12, 12).color(Color::BLACK))).style(|s| { s.items_center() .padding(3.) - .border_radius(7.pct()) + .border_radius(5) .hover(move |s| s.background(Color::LIGHT_GRAY)) }), )) @@ -204,7 +222,39 @@ impl Dropdown { .into_any() } - /// Creates a new dropdown + /// Creates a new customizable dropdown. + /// + /// You might want to use some of the simpler constructors like [Dropdown::basic] or [Dropdown::basic_rw]. + /// + /// # Example + /// ```rust + /// # use floem::{*, views::*, reactive::*}; + /// # use floem::views::dropdown::*; + /// let active_item = RwSignal::new(3); + /// + /// Dropdown::new( + /// move || active_item.get(), + /// |main_item| text(main_item).into_any(), + /// 1..=5, + /// |list_item| text(list_item).into_any(), + /// ) + /// .on_accept(move |item| active_item.set(item)); + /// ``` + /// + /// This function provides full control over the dropdown's appearance and behavior + /// by allowing custom view functions for both the main display and list items. + /// + /// # Arguments + /// + /// * `active_item` - A function that returns the currently selected item. + /// + /// * `main_view` - A function that takes a value of type `T` and returns an `AnyView` + /// to be used as the main dropdown display. + /// + /// * `iterator` - An iterator that provides the items to be displayed in the dropdown list. + /// + /// * `list_item_fn` - A function that takes a value of type `T` and returns an `AnyView` + /// to be used for each item in the dropdown list. pub fn new( active_item: AIF, main_view: MF, @@ -212,9 +262,9 @@ impl Dropdown { list_item_fn: LF, ) -> Dropdown where - MF: Fn(T) -> Box + 'static, + MF: Fn(T) -> AnyView + 'static, I: IntoIterator + Clone + 'static, - LF: Fn(T) -> Box + Clone + 'static, + LF: Fn(T) -> AnyView + Clone + 'static, T: Clone + 'static, AIF: Fn() -> T + 'static, { @@ -281,7 +331,7 @@ impl Dropdown { /// # use floem::views::dropdown::*; /// let active_item = RwSignal::new(3); /// - /// Dropdown::basic(move || active_item.get(), 1..=5).on_accept(move |val| active_item.set(val))); + /// Dropdown::basic(move || active_item.get(), 1..=5).on_accept(move |val| active_item.set(val)); /// ``` /// /// This function is a convenience wrapper around `Dropdown::new` that uses default views @@ -292,12 +342,8 @@ impl Dropdown { /// # Arguments /// /// * `active_item` - A function that returns the currently selected item. - /// * `AIF` - The type of the active item function of type `T`. - /// * `T` - The type of items in the dropdown. Must implement `Clone` and `std::fmt::Display`. /// /// * `iterator` - An iterator that provides the items to be displayed in the dropdown list. - /// It must be `Clone` and iterate over items of type `T`. - /// * `I` - The type of the iterator. pub fn basic(active_item: AIF, iterator: I) -> Dropdown where AIF: Fn() -> T + 'static, @@ -331,22 +377,14 @@ impl Dropdown { /// # Arguments /// /// * `active_item` - A read-write signal representing the currently selected item. - /// It must implement both `SignalGet` and `SignalUpdate`. - /// * `T` - The type of items in the dropdown. Must implement `Clone`. - /// * `AI` - The type of the active item signal. /// /// * `main_view` - A function that takes a value of type `T` and returns an `AnyView` /// to be used as the main dropdown display. + /// /// * `iterator` - An iterator that provides the items to be displayed in the dropdown list. - /// It must be `Clone` and iterate over items of type `T`. + /// /// * `list_item_fn` - A function that takes a value of type `T` and returns an `AnyView` /// to be used for each item in the dropdown list. - /// - /// # Type Parameters - /// - /// * `MF` - The type of the main view function. - /// * `I` - The type of the iterator. - /// * `LF` - The type of the list item function. pub fn new_rw( active_item: AI, main_view: MF, @@ -382,11 +420,8 @@ impl Dropdown { /// /// * `active_item` - A read-write signal representing the currently selected item. /// It must implement `SignalGet` and `SignalUpdate`. - /// * `T` - The type of items in the dropdown. Must implement `Clone` and `std::fmt::Display`. - /// * `AI` - The type of the active item signal. + /// /// * `iterator` - An iterator that provides the items to be displayed in the dropdown list. - /// It must be `Clone` and iterate over items of type `T`. - /// * `I` - The type of the iterator. pub fn basic_rw(active_item: AI, iterator: I) -> Dropdown where AI: SignalGet + SignalUpdate + Copy + 'static, @@ -398,6 +433,10 @@ impl Dropdown { }) } + /// Sets a reactive condition for showing or hiding the dropdown list. + /// + /// # Reactivity + /// The `show` function will be re-run whenever any signal it depends on changes. pub fn show_list(self, show: impl Fn() -> bool + 'static) -> Self { let id = self.id(); create_effect(move |_| { @@ -407,11 +446,17 @@ impl Dropdown { self } + /// Sets a callback function to be called when an item is selected from the dropdown. + /// + /// Only one `on_accept` callback can be set at a time. pub fn on_accept(mut self, on_accept: impl Fn(T) + 'static) -> Self { self.on_accept = Some(Box::new(on_accept)); self } + /// Sets a callback function to be called when the dropdown is opened. + /// + /// Only one `on_open` callback can be set at a time. pub fn on_open(mut self, on_open: impl Fn(bool) + 'static) -> Self { self.on_open = Some(Box::new(on_open)); self @@ -472,27 +517,29 @@ impl Dropdown { })); } - /// Sets the custom style properties of the `DropDown`. + /// Sets the custom style properties of the `Dropdown`. pub fn dropdown_style( self, - style: impl Fn(DropDownCustomStyle) -> DropDownCustomStyle + 'static, + style: impl Fn(DropdownCustomStyle) -> DropdownCustomStyle + 'static, ) -> Self { self.custom_style(style) } } #[derive(Debug, Clone, Default)] -pub struct DropDownCustomStyle(Style); -impl From for Style { - fn from(val: DropDownCustomStyle) -> Self { +/// A struct that allows for easy custom styling of the `Dropdown` using the [Dropdown::dropdown_style] method or the [Style::custom_style](crate::style::CustomStyle::custom_style) method. +pub struct DropdownCustomStyle(Style); +impl From for Style { + fn from(val: DropdownCustomStyle) -> Self { val.0 } } -impl CustomStylable for Dropdown { +impl CustomStylable for Dropdown { type DV = Self; } -impl DropDownCustomStyle { +impl DropdownCustomStyle { + /// Creates a new `DropDownCustomStyle` with default values. pub fn new() -> Self { Self::default() }