Skip to main content

basecoat_core/props/
select.rs

1use crate::{AttrMap, BasecoatProps, Children};
2use std::borrow::Cow;
3
4/// A single option in a [`SelectProps::options`] list.
5///
6/// Mirrors a native `<option>` element: `value` is the form-submitted value,
7/// `label` is the user-visible text, and `disabled` blocks selection.
8#[derive(Clone, Debug, Default)]
9pub struct SelectOption {
10    /// The form-submitted value for the `<option>`.
11    pub value: Cow<'static, str>,
12    /// The user-visible label shown in the trigger and listbox.
13    pub label: Cow<'static, str>,
14    /// Whether this option is disabled.
15    pub disabled: bool,
16}
17
18impl SelectOption {
19    /// Construct a new enabled option.
20    pub fn new(
21        value: impl Into<Cow<'static, str>>,
22        label: impl Into<Cow<'static, str>>,
23    ) -> Self {
24        Self {
25            value: value.into(),
26            label: label.into(),
27            disabled: false,
28        }
29    }
30
31    /// Mark this option as disabled.
32    pub fn disabled(mut self) -> Self {
33        self.disabled = true;
34        self
35    }
36}
37
38/// Select — maps to CSS class `.select` (custom-styled native form select).
39///
40/// Renders a hidden native `<select>` (the source of truth for form
41/// submission) alongside a visible trigger button and a floating listbox.
42/// The controller wires the listbox open/close behaviour, keyboard
43/// navigation, dismiss handling, and synchronizes the hidden element on
44/// option click.
45#[derive(BasecoatProps, Default, Clone, Debug)]
46pub struct SelectProps {
47    /// Unique DOM id for the trigger button — required for the controller
48    /// to find the element. The hidden `<select>` and listbox derive their
49    /// ids from this value.
50    #[prop(optional, into)]
51    pub id: Option<Cow<'static, str>>,
52    /// Form name for the hidden native `<select>` element.
53    #[prop(optional, into)]
54    pub name: Option<Cow<'static, str>>,
55    /// Accessible label associated via `aria-label` on the trigger.
56    #[prop(optional, into)]
57    pub label: Option<Cow<'static, str>>,
58    /// Initial selected value. Must match one of the option values.
59    #[prop(optional, into)]
60    pub value: Option<Cow<'static, str>>,
61    /// Placeholder text shown when no option is selected.
62    #[prop(optional, into)]
63    pub placeholder: Option<Cow<'static, str>>,
64    /// Whether the entire select is disabled.
65    #[prop(default = false)]
66    pub disabled: bool,
67    /// The list of selectable options.
68    #[prop(default)]
69    pub options: Vec<SelectOption>,
70    /// Extra CSS classes appended to the `.select` wrapper.
71    #[prop(optional, into)]
72    pub class: Option<Cow<'static, str>>,
73    /// Extra HTML attributes for the outer wrapper.
74    #[prop(extend)]
75    pub attrs: AttrMap,
76    /// Optional inline children (rendered inside the listbox before the
77    /// option buttons). Most callers should leave this empty and use
78    /// `options` instead.
79    pub children: Children,
80}