Skip to content

Commit

Permalink
Feature/dropdown (#210)
Browse files Browse the repository at this point in the history
* dropdown with icon

* dropdown demo page

* on_select instaed of on_click

* code review fixes
  • Loading branch information
kandrelczyk committed Jun 26, 2024
1 parent 2f96fec commit 7685e99
Show file tree
Hide file tree
Showing 15 changed files with 628 additions and 37 deletions.
1 change: 1 addition & 0 deletions demo/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ fn TheRouter(is_routing: RwSignal<bool>) -> impl IntoView {
<Route path="/date-picker" view=DatePickerMdPage/>
<Route path="/divider" view=DividerMdPage/>
<Route path="/drawer" view=DrawerMdPage/>
<Route path="/dropdown" view=DropdownMdPage/>
<Route path="/grid" view=GridMdPage/>
<Route path="/icon" view=IconMdPage/>
<Route path="/image" view=ImageMdPage/>
Expand Down
4 changes: 4 additions & 0 deletions demo/src/pages/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ pub(crate) fn gen_menu_data() -> Vec<MenuGroupOption> {
value: "divider".into(),
label: "Divider".into(),
},
MenuItemOption {
value: "dropdown".into(),
label: "Dropdown".into(),
},
MenuItemOption {
value: "icon".into(),
label: "Icon".into(),
Expand Down
182 changes: 182 additions & 0 deletions demo_markdown/docs/dropdown/mod.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Dropdown

```rust demo
let message = use_message();

let on_select = move |key: String| {
match key.as_str() {
"facebook" => message.create( "Facebook".into(), MessageVariant::Success, Default::default(),),
"twitter" => message.create( "Twitter".into(), MessageVariant::Warning, Default::default(),),
_ => ()
}
};


view! {
<Space>
<Dropdown on_select trigger_type=DropdownTriggerType::Hover>
<DropdownTrigger slot>
<Button>"Hover"</Button>
</DropdownTrigger>
<DropdownItem key="facebook" icon=icondata::AiFacebookOutlined label="Facebook"></DropdownItem>
<DropdownItem key="twitter" disabled=true icon=icondata::AiTwitterOutlined label="Twitter"></DropdownItem>
</Dropdown>

<Dropdown on_select>
<DropdownTrigger slot>
<Button>"Click"</Button>
</DropdownTrigger>
<DropdownItem key="facebook" icon=icondata::AiFacebookOutlined label="Facebook"></DropdownItem>
<DropdownItem key="twitter" icon=icondata::AiTwitterOutlined label="Twitter"></DropdownItem>
<DropdownItem key="no_icon" disabled=true label="Mastodon"></DropdownItem>
</Dropdown>
</Space>
}
```

### Placement

```rust demo
use leptos_meta::Style;

let on_select = move |key| println!("{}", key);

view! {
<Style>
".demo-dropdown .thaw-button { width: 100% } .demo-dropdown .thaw-dropdown-trigger { display: block }"
</Style>
<Grid x_gap=8 y_gap=8 cols=3 class="demo-dropdown">
<GridItem>
<Dropdown on_select placement=DropdownPlacement::TopStart>
<DropdownTrigger slot>
<Button>"Top Start"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem>
<Dropdown on_select placement=DropdownPlacement::Top>
<DropdownTrigger slot>
<Button>"Top"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem>
<Dropdown on_select placement=DropdownPlacement::TopEnd>
<DropdownTrigger slot>
<Button>"Top End"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem>
<Dropdown on_select placement=DropdownPlacement::LeftStart>
<DropdownTrigger slot>
<Button>"Left Start"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem offset=1>
<Dropdown on_select placement=DropdownPlacement::RightStart>
<DropdownTrigger slot>
<Button>"Right Start"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem>
<Dropdown on_select placement=DropdownPlacement::Left>
<DropdownTrigger slot>
<Button>"Left"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem offset=1>
<Dropdown on_select placement=DropdownPlacement::Right>
<DropdownTrigger slot>
<Button>"Right"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem>
<Dropdown on_select placement=DropdownPlacement::LeftEnd>
<DropdownTrigger slot>
<Button>"Left End"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem offset=1>
<Dropdown on_select placement=DropdownPlacement::RightEnd>
<DropdownTrigger slot>
<Button>"Right End"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem>
<Dropdown on_select placement=DropdownPlacement::BottomStart>
<DropdownTrigger slot>
<Button>"Bottom Start"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem>
<Dropdown on_select placement=DropdownPlacement::Bottom>
<DropdownTrigger slot>
<Button>"Bottom"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
<GridItem>
<Dropdown on_select placement=DropdownPlacement::BottomEnd>
<DropdownTrigger slot>
<Button>"Bottom End"</Button>
</DropdownTrigger>
"Content"
</Dropdown>
</GridItem>
</Grid>
}
```

### Dropdown Props

| Name | Type | Default | Description |
| ------------ | ----------------------------------- | ---------------------------- | ------------------------------------------- |
| class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Addtional classes for the dropdown element. |
| on_select | `Callback<String>` | | Called when item is selected. |
| trigger_type | `DropdownTriggerType` | `DropdownTriggerType::Click` | Action that displays the dropdown. |
| placement | `DropdownPlacement` | `DropdownPlacement::Bottom` | Dropdown placement. |
| children | `Children` | | The content inside dropdown. |

### DropdownItem Props

| Name | Type | Default | Description |
| -------- | -------------------------------------------- | -------------------- | ------------------------------------------------ |
| class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Addtional classes for the dropdown item element. |
| key | `MaybeSignal<String>` | `Default::default()` | The key of the dropdown item. |
| label | `MaybeSignal<String>` | `Default::default()` | The label of the dropdown item. |
| icon | `OptionalMaybeSignal<icondata_core::Icon>` | `None` | The icon of the dropdown item. |
| disabled | `MaybeSignal<bool>` | `false` | Whether the dropdown item is disabled. |


### Dropdown Slots

| Name | Default | Description |
| --------------- | ------- | ------------------------------------------------ |
| DropdownTrigger | `None` | The element or component that triggers dropdown. |

### DropdownTriger Props

| Name | Type | Default | Description |
| ------------ | ----------------------------------- | ---------------------------- | -------------------------------------------------- |
| class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Addtional classes for the dropdown trigger element. |
| children | `Children` | | The content inside dropdown trigger. |

21 changes: 15 additions & 6 deletions demo_markdown/docs/popover/mod.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,24 @@ view! {

### Popover Props

| Name | Type | Default | Description |
| --------- | ----------------------------------- | ----------------------- | ----------------------------- |
| class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Content class of the popover. |
| placement | `PopoverPlacement` | `PopoverPlacement::Top` | Popover placement. |
| tooltip | `bool` | `false` | Tooltip. |
| children | `Children` | | The content inside popover. |
| Name | Type | Default | Description |
| -------------| ----------------------------------- | -------------------------- | --------------------------------- |
| class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Content class of the popover. |
| placement | `PopoverPlacement` | `PopoverPlacement::Top` | Popover placement. |
| trigger_type | `PopoverTriggerType` | `PopoverTriggerType::Hover`| Action that displays the dropdown |
| tooltip | `bool` | `false` | Tooltip. |
| children | `Children` | | The content inside popover. |

### Popover Slots

| Name | Default | Description |
| -------------- | ------- | ----------------------------------------------- |
| PopoverTrigger | | The element or component that triggers popover. |

### PopoverTriger Props

| Name | Type | Default | Description |
| ------------ | ----------------------------------- | ---------------------------- | -------------------------------------------------- |
| class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Addtional classes for the popover trigger element. |
| children | `Children` | | The content inside popover trigger. |

3 changes: 2 additions & 1 deletion demo_markdown/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt
"ThemeMdPage" => "../docs/theme/mod.md",
"TimePickerMdPage" => "../docs/time_picker/mod.md",
"TypographyMdPage" => "../docs/typography/mod.md",
"UploadMdPage" => "../docs/upload/mod.md"
"UploadMdPage" => "../docs/upload/mod.md",
"DropdownMdPage" => "../docs/dropdown/mod.md"
};

let mut fn_list = vec![];
Expand Down
16 changes: 16 additions & 0 deletions thaw/src/dropdown/dropdown-item.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.thaw-dropdown-item{
padding: 6px 5px;
border-radius: 2px;
cursor: pointer;
display: flex;
align-items: center;
}

.thaw-dropdown-item:hover:not(.thaw-dropdown-item--disabled) {
background-color: var(--thaw-background-color-hover);
}

.thaw-dropdown-item.thaw-dropdown-item--disabled {
color: var(--thaw-font-color-disabled);
cursor: not-allowed;
}
68 changes: 68 additions & 0 deletions thaw/src/dropdown/dropdown.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.thaw-dropdown {
position: relative;
padding: 5px;
background-color: var(--thaw-background-color);
color: var(--thaw-font-color);
border-radius: 3px;
transform-origin: inherit;
}

[data-thaw-placement="top-start"] > .thaw-dropdown,
[data-thaw-placement="top-end"] > .thaw-dropdown,
[data-thaw-placement="top"] > .thaw-dropdown {
margin-bottom: 4px;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
}

[data-thaw-placement="bottom-start"] > .thaw-dropdown,
[data-thaw-placement="bottom-end"] > .thaw-dropdown,
[data-thaw-placement="bottom"] > .thaw-dropdown {
margin-top: 4px;
box-shadow: 0 -3px 6px -4px rgba(0, 0, 0, 0.12),
0 -6px 16px 0 rgba(0, 0, 0, 0.08), 0 -9px 28px 8px rgba(0, 0, 0, 0.05);
}

[data-thaw-placement="left-start"] > .thaw-dropdown,
[data-thaw-placement="left-end"] > .thaw-dropdown,
[data-thaw-placement="left"] > .thaw-dropdown {
margin-right: 4px;
box-shadow: 3px 0 6px -4px rgba(0, 0, 0, 0.12),
6px 0 16px 0 rgba(0, 0, 0, 0.08), 9px 0 28px 8px rgba(0, 0, 0, 0.05);
}

[data-thaw-placement="right-start"] > .thaw-dropdown,
[data-thaw-placement="right-end"] > .thaw-dropdown,
[data-thaw-placement="right"] > .thaw-dropdown {
margin-left: 4px;
box-shadow: -3px 0 6px -4px rgba(0, 0, 0, 0.12),
-6px 0 16px 0 rgba(0, 0, 0, 0.08), -9px 0 28px 8px rgba(0, 0, 0, 0.05);
}

.thaw-dropdown.dropdown-transition-enter-from,
.thaw-dropdown.dropdown-transition-leave-to {
opacity: 0;
transform: scale(0.85);
}

.thaw-dropdown.dropdown-transition-enter-to,
.thaw-dropdown.dropdown-transition-leave-from {
transform: scale(1);
opacity: 1;
}

.thaw-dropdown.dropdown-transition-enter-active {
transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1),
background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.15s cubic-bezier(0, 0, 0.2, 1),
transform 0.15s cubic-bezier(0, 0, 0.2, 1);
}

.thaw-dropdown.dropdown-transition-leave-active {
transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1),
background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.15s cubic-bezier(0.4, 0, 1, 1),
transform 0.15s cubic-bezier(0.4, 0, 1, 1);
}
Loading

0 comments on commit 7685e99

Please sign in to comment.