Skip to main content

herogpui_components/
traits.rs

1//! Shared builder traits (HeroGPUI extension, not a HeroUI v3 API).
2//!
3//! HeroUI v3 spells `isDisabled`, `size` and `isSelected` on every component
4//! that has them, and this port keeps those spellings as **inherent** builder
5//! methods — the parity audits read them there. These traits add a common
6//! name on top, so generic code can configure any component that supports the
7//! prop without naming its concrete type:
8//!
9//! ```
10//! use herogpui_components::{Button, Disableable, Sizable, Size, Switch};
11//!
12//! fn compact<T: Disableable + Sizable<Size = Size>>(component: T, busy: bool) -> T {
13//!     component.is_disabled(busy).size(Size::Sm)
14//! }
15//!
16//! let _button = compact(Button::new("save").label("Save"), true);
17//! let _switch = compact(Switch::new("wifi"), false);
18//! ```
19//!
20//! Every implementation delegates to the inherent builder of the same name,
21//! so a call through the trait and a direct call are the same code path.
22//! The pattern follows gpui-kit's `Disableable`/`Sizable`/`Selectable`
23//! (Apache-2.0, Longbridge), rewritten for HeroUI's `is_*` naming.
24
25use crate::*;
26
27/// A component with v3's `isDisabled` prop.
28pub trait Disableable: Sized {
29    /// `isDisabled` — whether the component is disabled.
30    fn is_disabled(self, disabled: bool) -> Self;
31}
32
33/// A component with a `size` prop. [`Sizable::Size`] is the component's own
34/// scale: HeroUI's [`Size`] for most, a component-specific enum where v3
35/// defines one (for example [`ModalSize`]).
36pub trait Sizable: Sized {
37    /// The size scale this component accepts.
38    type Size;
39    /// `size` — the component's size step.
40    fn size(self, size: Self::Size) -> Self;
41}
42
43/// A component with v3's controlled `isSelected` prop.
44pub trait Selectable: Sized {
45    /// `isSelected` — the controlled selection state.
46    fn is_selected(self, selected: bool) -> Self;
47}
48
49macro_rules! disableable {
50    ($($ty:ident),* $(,)?) => {$(
51        impl Disableable for $ty {
52            fn is_disabled(self, disabled: bool) -> Self {
53                $ty::is_disabled(self, disabled)
54            }
55        }
56    )*};
57}
58
59macro_rules! sizable {
60    ($($ty:ident => $size:ty),* $(,)?) => {$(
61        impl Sizable for $ty {
62            type Size = $size;
63            fn size(self, size: $size) -> Self {
64                $ty::size(self, size)
65            }
66        }
67    )*};
68}
69
70macro_rules! selectable {
71    ($($ty:ident),* $(,)?) => {$(
72        impl Selectable for $ty {
73            fn is_selected(self, selected: bool) -> Self {
74                $ty::is_selected(self, selected)
75            }
76        }
77    )*};
78}
79
80disableable!(
81    AccordionItem,
82    Accordion,
83    Autocomplete,
84    Breadcrumbs,
85    Button,
86    ButtonGroup,
87    Calendar,
88    Checkbox,
89    CheckboxOption,
90    CheckboxGroup,
91    CloseButton,
92    ColorArea,
93    ColorField,
94    ColorPicker,
95    ColorSlider,
96    ColorSwatch,
97    ColorSwatchPicker,
98    ComboBox,
99    DateField,
100    DatePicker,
101    DateRangePicker,
102    Disclosure,
103    DisclosureGroup,
104    HoverCard,
105    Label,
106    Input,
107    TextField,
108    SearchField,
109    InputGroup,
110    InputOTP,
111    Link,
112    ListBoxItem,
113    NumberField,
114    Pagination,
115    RadioOption,
116    RadioGroup,
117    RangeCalendar,
118    ResizablePanelGroup,
119    Select,
120    Sidebar,
121    SidebarItem,
122    Slider,
123    Switch,
124    TabItem,
125    Tabs,
126    Tag,
127    TagGroup,
128    TextArea,
129    TimeField,
130    ToggleButton,
131    ToggleButtonGroup,
132    Tooltip,
133    TreeItem,
134    TreeView,
135);
136
137sizable!(
138    AlertDialog => AlertDialogSize,
139    Avatar => Size,
140    AvatarGroupCount => Size,
141    AvatarGroup => Size,
142    Badge => Size,
143    Button => Size,
144    ButtonGroup => Size,
145    Checkbox => CheckboxSize,
146    Chip => Size,
147    Icon => IconSize,
148    ColorSwatch => SizeXl,
149    ColorSwatchPicker => SizeXl,
150    Meter => Size,
151    Modal => ModalSize,
152    Pagination => Size,
153    ProgressBar => Size,
154    ProgressCircle => Size,
155    RadioGroup => RadioSize,
156    Slider => SliderSize,
157    Spinner => SpinnerSize,
158    Switch => Size,
159    Tabs => TabsSize,
160    TagGroup => Size,
161    ToggleButton => Size,
162    ToggleButtonGroup => Size,
163    Toolbar => Size,
164);
165
166selectable!(Checkbox, Switch, ToggleButton);