input, select, date_picker: Refactor cleanable to have argument and default to false. (#1506)
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>
This commit is contained in:
parent
522f3ced43
commit
a4e93132f1
12 changed files with 36 additions and 175 deletions
|
|
@ -1,12 +1,12 @@
|
|||
use chrono::{Datelike, Days, Duration, Utc};
|
||||
use gpui::{
|
||||
div, px, App, AppContext, Context, Entity, Focusable, IntoElement, ParentElement as _, Render,
|
||||
Styled as _, Subscription, Window,
|
||||
App, AppContext, Context, Entity, Focusable, IntoElement, ParentElement as _, Render,
|
||||
Styled as _, Subscription, Window, div, px,
|
||||
};
|
||||
use gpui_component::{
|
||||
calendar,
|
||||
ActiveTheme as _, Sizable as _, calendar,
|
||||
date_picker::{DatePicker, DatePickerEvent, DatePickerState, DateRangePreset},
|
||||
v_flex, ActiveTheme as _, Sizable as _,
|
||||
v_flex,
|
||||
};
|
||||
|
||||
use crate::section;
|
||||
|
|
@ -172,7 +172,7 @@ impl Render for DatePickerStory {
|
|||
.child(
|
||||
section("Normal").max_w_128().child(
|
||||
DatePicker::new(&self.date_picker)
|
||||
.cleanable()
|
||||
.cleanable(true)
|
||||
.presets(presets),
|
||||
),
|
||||
)
|
||||
|
|
@ -195,7 +195,7 @@ impl Render for DatePickerStory {
|
|||
section("Date Range").max_w_128().child(
|
||||
DatePicker::new(&self.date_range_picker)
|
||||
.number_of_months(2)
|
||||
.cleanable()
|
||||
.cleanable(true)
|
||||
.presets(range_presets.clone()),
|
||||
),
|
||||
)
|
||||
|
|
@ -203,7 +203,7 @@ impl Render for DatePickerStory {
|
|||
section("Default Range Mode").max_w_128().child(
|
||||
DatePicker::new(&self.default_range_mode_picker)
|
||||
.placeholder("Range mode picker")
|
||||
.cleanable()
|
||||
.cleanable(true)
|
||||
.presets(range_presets.clone()),
|
||||
),
|
||||
)
|
||||
|
|
@ -217,8 +217,7 @@ impl Render for DatePickerStory {
|
|||
div().w_full().bg(cx.theme().secondary).child(
|
||||
DatePicker::new(&self.without_appearance_picker)
|
||||
.appearance(false)
|
||||
.placeholder("Without appearance")
|
||||
.cleanable(),
|
||||
.placeholder("Without appearance"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -153,32 +153,32 @@ impl Render for InputStory {
|
|||
.child(
|
||||
section("Normal Input")
|
||||
.max_w_md()
|
||||
.child(Input::new(&self.input1).cleanable())
|
||||
.child(Input::new(&self.input1).cleanable(true))
|
||||
.child(Input::new(&self.input2)),
|
||||
)
|
||||
.child(
|
||||
section("Input State")
|
||||
.max_w_md()
|
||||
.child(Input::new(&self.disabled_input).disabled(true))
|
||||
.child(Input::new(&self.mask_input).mask_toggle().cleanable()),
|
||||
.child(Input::new(&self.mask_input).mask_toggle().cleanable(true)),
|
||||
)
|
||||
.child(
|
||||
section("Prefix and Suffix")
|
||||
.max_w_md()
|
||||
.child(
|
||||
Input::new(&self.prefix_input1)
|
||||
.cleanable()
|
||||
.cleanable(true)
|
||||
.prefix(Icon::new(IconName::Search).small()),
|
||||
)
|
||||
.child(
|
||||
Input::new(&self.both_input1)
|
||||
.cleanable()
|
||||
.cleanable(true)
|
||||
.prefix(div().child(Icon::new(IconName::Search).small()))
|
||||
.suffix(Button::new("info").ghost().icon(IconName::Info).xsmall()),
|
||||
)
|
||||
.child(
|
||||
Input::new(&self.suffix_input1)
|
||||
.cleanable()
|
||||
.cleanable(true)
|
||||
.suffix(Button::new("info").ghost().icon(IconName::Info).xsmall()),
|
||||
),
|
||||
)
|
||||
|
|
@ -219,13 +219,13 @@ impl Render for InputStory {
|
|||
.child(
|
||||
section("Input Size")
|
||||
.max_w_md()
|
||||
.child(Input::new(&self.large_input).large().cleanable())
|
||||
.child(Input::new(&self.small_input).small().cleanable()),
|
||||
.child(Input::new(&self.large_input).large())
|
||||
.child(Input::new(&self.small_input).small()),
|
||||
)
|
||||
.child(
|
||||
section("Cleanable and ESC to clean")
|
||||
.max_w_md()
|
||||
.child(Input::new(&self.input_esc).cleanable()),
|
||||
.child(Input::new(&self.input_esc).cleanable(true)),
|
||||
)
|
||||
.child(
|
||||
section("Focused Input")
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ impl Render for LabelStory {
|
|||
.child(
|
||||
h_flex()
|
||||
.gap_x_3()
|
||||
.child(Input::new(&self.highlights_input).cleanable().w_1_3())
|
||||
.child(Input::new(&self.highlights_input).w_1_3())
|
||||
.child(
|
||||
Checkbox::new("prefix")
|
||||
.label("Prefix")
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ impl Render for Gallery {
|
|||
.child(
|
||||
Input::new(&self.search_input)
|
||||
.appearance(false)
|
||||
.cleanable(),
|
||||
.cleanable(true),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ impl Render for SelectStory {
|
|||
section("Select").max_w_128().child(
|
||||
Select::new(&self.country_select)
|
||||
.search_placeholder("Search country by name or code")
|
||||
.cleanable()
|
||||
.cleanable(true)
|
||||
.disabled(self.disabled),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -115,9 +115,9 @@ impl Input {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set true to show the clear button when the input field is not empty.
|
||||
pub fn cleanable(mut self) -> Self {
|
||||
self.cleanable = true;
|
||||
/// Set whether to show the clear button when the input field is not empty, default is false.
|
||||
pub fn cleanable(mut self, cleanable: bool) -> Self {
|
||||
self.cleanable = cleanable;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -635,7 +635,7 @@ where
|
|||
Icon::new(IconName::Search)
|
||||
.text_color(cx.theme().muted_foreground),
|
||||
)
|
||||
.cleanable()
|
||||
.cleanable(true)
|
||||
.p_0()
|
||||
.appearance(false),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ impl Default for SelectOptions {
|
|||
style: StyleRefinement::default(),
|
||||
size: Size::default(),
|
||||
icon: None,
|
||||
cleanable: true,
|
||||
cleanable: false,
|
||||
placeholder: None,
|
||||
title_prefix: None,
|
||||
empty: None,
|
||||
|
|
@ -962,9 +962,9 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
/// Set true to show the clear button when the input field is not empty.
|
||||
pub fn cleanable(mut self) -> Self {
|
||||
self.options.cleanable = true;
|
||||
/// Set whether to show the clear button when the input field is not empty, default is false.
|
||||
pub fn cleanable(mut self, cleanable: bool) -> Self {
|
||||
self.options.cleanable = cleanable;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ impl DatePicker {
|
|||
Self {
|
||||
id: ("date-picker", state.entity_id()).into(),
|
||||
state: state.clone(),
|
||||
cleanable: true,
|
||||
cleanable: false,
|
||||
placeholder: None,
|
||||
size: Size::default(),
|
||||
style: StyleRefinement::default(),
|
||||
|
|
@ -318,9 +318,9 @@ impl DatePicker {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set true to show the clear button when the input field is not empty.
|
||||
pub fn cleanable(mut self) -> Self {
|
||||
self.cleanable = true;
|
||||
/// Set whether to show the clear button when the input field is not empty, default is false.
|
||||
pub fn cleanable(mut self, cleanable: bool) -> Self {
|
||||
self.cleanable = cleanable;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ DatePicker::new(&date_picker)
|
|||
|
||||
```rust
|
||||
DatePicker::new(&date_picker)
|
||||
.cleanable() // Shows clear button when date is selected
|
||||
.cleanable(true) // Show clear button when date is selected
|
||||
```
|
||||
|
||||
### Different Sizes
|
||||
|
|
@ -360,91 +360,6 @@ DatePicker::new(&date_picker)
|
|||
.presets(quarterly_presets)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### DatePickerState
|
||||
|
||||
| Method | Description |
|
||||
| ---------------------------- | ------------------------------------------- |
|
||||
| `new(window, cx)` | Create a single date picker state |
|
||||
| `range(window, cx)` | Create a date range picker state |
|
||||
| `date_format(format)` | Set display format (default: "%Y/%m/%d") |
|
||||
| `number_of_months(count)` | Set calendar months to display (default: 1) |
|
||||
| `disabled_matcher(matcher)` | Set date disabling rules |
|
||||
| `date()` | Get current selected date |
|
||||
| `set_date(date, window, cx)` | Set selected date programmatically |
|
||||
| `focus_handle(cx)` | Get focus handle |
|
||||
|
||||
### DatePicker
|
||||
|
||||
| Method | Description |
|
||||
| ------------------------- | --------------------------------------- |
|
||||
| `new(state)` | Create date picker with state entity |
|
||||
| `placeholder(text)` | Set placeholder text |
|
||||
| `cleanable()` | Show clear button when date selected |
|
||||
| `presets(presets)` | Set quick selection presets |
|
||||
| `number_of_months(count)` | Set months to display (overrides state) |
|
||||
| `appearance(bool)` | Enable/disable default styling |
|
||||
| `disabled(bool)` | Set disabled state |
|
||||
| `large()` | Large size |
|
||||
| `small()` | Small size |
|
||||
|
||||
### DateRangePreset
|
||||
|
||||
| Method | Description |
|
||||
| -------------------------- | ------------------------- |
|
||||
| `single(label, date)` | Create single date preset |
|
||||
| `range(label, start, end)` | Create date range preset |
|
||||
|
||||
### Date
|
||||
|
||||
| Variant | Description |
|
||||
| --------------------------------------------- | --------------------- |
|
||||
| `Single(Option<NaiveDate>)` | Single date selection |
|
||||
| `Range(Option<NaiveDate>, Option<NaiveDate>)` | Date range selection |
|
||||
|
||||
| Method | Description |
|
||||
| -------------------- | ----------------------------------------- |
|
||||
| `format(format_str)` | Format date(s) using chrono format string |
|
||||
| `is_some()` | Check if date is selected |
|
||||
| `is_complete()` | Check if selection is complete |
|
||||
|
||||
### Matcher
|
||||
|
||||
| Variant | Description |
|
||||
| --------------------------- | ------------------------------------------------ |
|
||||
| `DayOfWeek(Vec<u32>)` | Disable specific weekdays (0=Sunday, 6=Saturday) |
|
||||
| `Interval(IntervalMatcher)` | Disable dates outside interval |
|
||||
| `Range(RangeMatcher)` | Disable dates within range |
|
||||
| `Custom(fn)` | Custom disable function |
|
||||
|
||||
| Method | Description |
|
||||
| ------------------------- | ----------------------- |
|
||||
| `interval(before, after)` | Create interval matcher |
|
||||
| `range(from, to)` | Create range matcher |
|
||||
| `custom(fn)` | Create custom matcher |
|
||||
|
||||
### DatePickerEvent
|
||||
|
||||
| Event | Description |
|
||||
| -------------- | ---------------------- |
|
||||
| `Change(Date)` | Date selection changed |
|
||||
|
||||
## Format Strings
|
||||
|
||||
Common date format patterns using chrono format specifiers:
|
||||
|
||||
| Format | Example Output |
|
||||
| ------------------- | ------------------------- |
|
||||
| `%Y-%m-%d` | 2023-12-25 |
|
||||
| `%m/%d/%Y` | 12/25/2023 |
|
||||
| `%d/%m/%Y` | 25/12/2023 |
|
||||
| `%B %d, %Y` | December 25, 2023 |
|
||||
| `%b %d, %Y` | Dec 25, 2023 |
|
||||
| `%d %b %Y` | 25 Dec 2023 |
|
||||
| `%A, %B %d, %Y` | Monday, December 25, 2023 |
|
||||
| `%Y 年 %m 月 %d 日` | 2023 年 12 月 25 日 |
|
||||
|
||||
## Examples
|
||||
|
||||
### Event Date Picker
|
||||
|
|
@ -462,7 +377,7 @@ let event_date = cx.new(|cx| {
|
|||
|
||||
DatePicker::new(&event_date)
|
||||
.placeholder("Choose event date")
|
||||
.cleanable()
|
||||
.cleanable(true)
|
||||
```
|
||||
|
||||
### Booking System Date Range
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ Input::new(&input)
|
|||
|
||||
```rust
|
||||
Input::new(&input)
|
||||
.cleanable() // Shows clear button when input has value
|
||||
.cleanable(true) // Show clear button when input has value
|
||||
```
|
||||
|
||||
### With Prefix and Suffix
|
||||
|
|
@ -60,7 +60,6 @@ use gpui_component::{Icon, IconName};
|
|||
// With prefix icon
|
||||
Input::new(&input)
|
||||
.prefix(Icon::new(IconName::Search).small())
|
||||
.cleanable()
|
||||
|
||||
// With suffix button
|
||||
Input::new(&input)
|
||||
|
|
@ -75,7 +74,6 @@ Input::new(&input)
|
|||
Input::new(&input)
|
||||
.prefix(Icon::new(IconName::Search).small())
|
||||
.suffix(Button::new("btn").ghost().icon(IconName::Info).xsmall())
|
||||
.cleanable()
|
||||
```
|
||||
|
||||
### Password Input (Masked)
|
||||
|
|
@ -113,7 +111,7 @@ let input = cx.new(|cx|
|
|||
.clean_on_escape() // Clear input when ESC is pressed
|
||||
);
|
||||
|
||||
Input::new(&input).cleanable()
|
||||
Input::new(&input)
|
||||
```
|
||||
|
||||
### Input Validation
|
||||
|
|
@ -195,55 +193,6 @@ div()
|
|||
.child(Input::new(&input).appearance(false))
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### InputState
|
||||
|
||||
| Method | Description |
|
||||
| ---------------------------- | -------------------------------------- |
|
||||
| `new(window, cx)` | Create a new input state |
|
||||
| `placeholder(str)` | Set placeholder text |
|
||||
| `default_value(str)` | Set initial value |
|
||||
| `masked(bool)` | Enable password masking |
|
||||
| `clean_on_escape()` | Clear on ESC key |
|
||||
| `validate(fn)` | Set validation function |
|
||||
| `pattern(regex)` | Set regex pattern for validation |
|
||||
| `mask_pattern(pattern)` | Set input mask pattern |
|
||||
| `value()` | Get current value |
|
||||
| `unmask_value()` | Get unmasked value (for masked inputs) |
|
||||
| `set_value(str, window, cx)` | Set input value programmatically |
|
||||
| `focus_handle(cx)` | Get focus handle |
|
||||
|
||||
### Input
|
||||
|
||||
| Method | Description |
|
||||
| ------------------ | ---------------------------------------- |
|
||||
| `new(state)` | Create input with state entity |
|
||||
| `prefix(el)` | Add prefix element |
|
||||
| `suffix(el)` | Add suffix element |
|
||||
| `cleanable()` | Show clear button |
|
||||
| `mask_toggle()` | Show password toggle (for masked inputs) |
|
||||
| `disabled(bool)` | Set disabled state |
|
||||
| `appearance(bool)` | Enable/disable default styling |
|
||||
| `large()` | Large size |
|
||||
| `small()` | Small size |
|
||||
|
||||
### InputEvent
|
||||
|
||||
| Event | Description |
|
||||
| -------------------------- | ----------------- |
|
||||
| `Change` | Value changed |
|
||||
| `PressEnter { secondary }` | Enter key pressed |
|
||||
| `Focus` | Input focused |
|
||||
| `Blur` | Input lost focus |
|
||||
|
||||
### MaskPattern
|
||||
|
||||
| Pattern | Description |
|
||||
| -------------------------------- | ---------------------------------------------------- |
|
||||
| String | Pattern string (9=digit, A=letter, #=digit required) |
|
||||
| `Number { separator, fraction }` | Number with thousands separator |
|
||||
|
||||
## Examples
|
||||
|
||||
### Search Input
|
||||
|
|
@ -256,7 +205,6 @@ let search = cx.new(|cx|
|
|||
|
||||
Input::new(&search)
|
||||
.prefix(Icon::new(IconName::Search).small())
|
||||
.cleanable()
|
||||
```
|
||||
|
||||
### Currency Input
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ Select::new(&state).disabled(true)
|
|||
|
||||
```rust
|
||||
Select::new(&state)
|
||||
.cleanable() // Shows clear button when item is selected
|
||||
.cleanable(true) // Show clear button when item is selected
|
||||
```
|
||||
|
||||
### Custom Appearance
|
||||
|
|
@ -257,7 +257,6 @@ let state = cx.new(|cx| {
|
|||
Select::new(&state)
|
||||
.placeholder("Select language...")
|
||||
.title_prefix("Language: ")
|
||||
.cleanable()
|
||||
```
|
||||
|
||||
### Country/Region Selector
|
||||
|
|
|
|||
Loading…
Reference in a new issue