-
Notifications
You must be signed in to change notification settings - Fork 271
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add expansion panel component. (#1089)
* Add expansion panel component. Also adds support for the accordion component which uses multiple grouped expansion panels. The accordion behavior needs to be manually implemented through event handlers on the expansion panels. Closes #1081
- Loading branch information
1 parent
69148c9
commit 96a47bb
Showing
31 changed files
with
847 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
from dataclasses import field | ||
|
||
import mesop as me | ||
|
||
|
||
@me.stateclass | ||
class State: | ||
normal_accordion: dict[str, bool] = field( | ||
default_factory=lambda: {"pie": True, "donut": False, "icecream": False} | ||
) | ||
multi_accordion: dict[str, bool] = field( | ||
default_factory=lambda: {"pie": False, "donut": False, "icecream": False} | ||
) | ||
|
||
|
||
def load(e: me.LoadEvent): | ||
me.set_theme_mode("system") | ||
|
||
|
||
@me.page( | ||
on_load=load, | ||
security_policy=me.SecurityPolicy( | ||
allowed_iframe_parents=["https://google.github.io"] | ||
), | ||
path="/expansion_panel", | ||
) | ||
def app(): | ||
state = me.state(State) | ||
with me.box( | ||
style=me.Style( | ||
display="flex", | ||
flex_direction="column", | ||
gap=15, | ||
margin=me.Margin.all(15), | ||
max_width=500, | ||
) | ||
): | ||
me.text("Normal Accordion", type="headline-5") | ||
with me.accordion(): | ||
with me.expansion_panel( | ||
key="pie", | ||
title="Pie", | ||
description="Type of snack", | ||
icon="pie_chart", | ||
disabled=False, | ||
expanded=state.normal_accordion["pie"], | ||
hide_toggle=False, | ||
on_toggle=on_accordion_toggle, | ||
): | ||
me.text( | ||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sed augue ultricies, laoreet nunc eget, ultricies augue. In ornare bibendum mauris vel sodales. Donec ut interdum felis. Nulla facilisi. Morbi a laoreet turpis, sed posuere arcu. Nam nisi neque, molestie vitae euismod eu, sollicitudin eu lectus. Pellentesque orci metus, finibus id faucibus et, ultrices quis dui. Duis in augue ac metus tristique lacinia." | ||
) | ||
|
||
with me.expansion_panel( | ||
key="donut", | ||
title="Donut", | ||
description="Type of breakfast", | ||
icon="donut_large", | ||
disabled=False, | ||
expanded=state.normal_accordion["donut"], | ||
hide_toggle=False, | ||
on_toggle=on_accordion_toggle, | ||
): | ||
me.text( | ||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sed augue ultricies, laoreet nunc eget, ultricies augue. In ornare bibendum mauris vel sodales. Donec ut interdum felis. Nulla facilisi. Morbi a laoreet turpis, sed posuere arcu. Nam nisi neque, molestie vitae euismod eu, sollicitudin eu lectus. Pellentesque orci metus, finibus id faucibus et, ultrices quis dui. Duis in augue ac metus tristique lacinia." | ||
) | ||
|
||
with me.expansion_panel( | ||
key="icecream", | ||
title="Ice cream", | ||
description="Type of dessert", | ||
icon="icecream", | ||
disabled=False, | ||
expanded=state.normal_accordion["icecream"], | ||
hide_toggle=False, | ||
on_toggle=on_accordion_toggle, | ||
): | ||
me.text( | ||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sed augue ultricies, laoreet nunc eget, ultricies augue. In ornare bibendum mauris vel sodales. Donec ut interdum felis. Nulla facilisi. Morbi a laoreet turpis, sed posuere arcu. Nam nisi neque, molestie vitae euismod eu, sollicitudin eu lectus. Pellentesque orci metus, finibus id faucibus et, ultrices quis dui. Duis in augue ac metus tristique lacinia." | ||
) | ||
|
||
me.text("Multi Accordion", type="headline-5") | ||
with me.box( | ||
style=me.Style(display="flex", gap=20, margin=me.Margin(bottom=15)), | ||
): | ||
me.button( | ||
label="Open All", type="flat", on_click=on_multi_accordion_open_all | ||
) | ||
me.button( | ||
label="Close All", type="flat", on_click=on_multi_accordion_close_all | ||
) | ||
|
||
with me.accordion(): | ||
with me.expansion_panel( | ||
key="pie", | ||
title="Pie", | ||
description="Type of snack", | ||
icon="pie_chart", | ||
expanded=state.multi_accordion["pie"], | ||
on_toggle=on_multi_accordion_toggle, | ||
): | ||
me.text( | ||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sed augue ultricies, laoreet nunc eget, ultricies augue. In ornare bibendum mauris vel sodales. Donec ut interdum felis. Nulla facilisi. Morbi a laoreet turpis, sed posuere arcu. Nam nisi neque, molestie vitae euismod eu, sollicitudin eu lectus. Pellentesque orci metus, finibus id faucibus et, ultrices quis dui. Duis in augue ac metus tristique lacinia." | ||
) | ||
|
||
with me.expansion_panel( | ||
key="donut", | ||
title="Donut", | ||
description="Type of breakfast", | ||
icon="donut_large", | ||
expanded=state.multi_accordion["donut"], | ||
on_toggle=on_multi_accordion_toggle, | ||
): | ||
me.text( | ||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sed augue ultricies, laoreet nunc eget, ultricies augue. In ornare bibendum mauris vel sodales. Donec ut interdum felis. Nulla facilisi. Morbi a laoreet turpis, sed posuere arcu. Nam nisi neque, molestie vitae euismod eu, sollicitudin eu lectus. Pellentesque orci metus, finibus id faucibus et, ultrices quis dui. Duis in augue ac metus tristique lacinia." | ||
) | ||
|
||
with me.expansion_panel( | ||
key="icecream", | ||
title="Ice cream", | ||
description="Type of dessert", | ||
icon="icecream", | ||
expanded=state.multi_accordion["icecream"], | ||
on_toggle=on_multi_accordion_toggle, | ||
): | ||
me.text( | ||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sed augue ultricies, laoreet nunc eget, ultricies augue. In ornare bibendum mauris vel sodales. Donec ut interdum felis. Nulla facilisi. Morbi a laoreet turpis, sed posuere arcu. Nam nisi neque, molestie vitae euismod eu, sollicitudin eu lectus. Pellentesque orci metus, finibus id faucibus et, ultrices quis dui. Duis in augue ac metus tristique lacinia." | ||
) | ||
|
||
me.text("Expansion Panel", type="headline-5") | ||
|
||
with me.expansion_panel( | ||
key="pie", | ||
title="Pie", | ||
description="Type of snack", | ||
icon="pie_chart", | ||
): | ||
me.text( | ||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sed augue ultricies, laoreet nunc eget, ultricies augue. In ornare bibendum mauris vel sodales. Donec ut interdum felis. Nulla facilisi. Morbi a laoreet turpis, sed posuere arcu. Nam nisi neque, molestie vitae euismod eu, sollicitudin eu lectus. Pellentesque orci metus, finibus id faucibus et, ultrices quis dui. Duis in augue ac metus tristique lacinia." | ||
) | ||
|
||
|
||
def on_accordion_toggle(e: me.ExpansionPanelToggleEvent): | ||
"""Implements accordion behavior where only one panel can be open at a time""" | ||
state = me.state(State) | ||
state.normal_accordion = {"pie": False, "donut": False, "icecream": False} | ||
state.normal_accordion[e.key] = e.opened | ||
|
||
|
||
def on_multi_accordion_toggle(e: me.ExpansionPanelToggleEvent): | ||
"""Implements accordion behavior where multiple panels can be open at a time""" | ||
state = me.state(State) | ||
state.multi_accordion[e.key] = e.opened | ||
|
||
|
||
def on_multi_accordion_open_all(e: me.ClickEvent): | ||
state = me.state(State) | ||
for key in state.multi_accordion: | ||
state.multi_accordion[key] = True | ||
|
||
|
||
def on_multi_accordion_close_all(e: me.ClickEvent): | ||
state = me.state(State) | ||
for key in state.multi_accordion: | ||
state.multi_accordion[key] = False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
## Overview | ||
|
||
Expansion panel and is based on the [Angular Material expansion panel component](https://material.angular.io/components/expansion/overview). | ||
|
||
This is a useful component for showing a summary header which can be expanded into a more detailed card/panel. | ||
|
||
The expansion panels can also be grouped together to create an accordion. | ||
|
||
## Examples | ||
|
||
<iframe class="component-demo" src="https://google.github.io/mesop/demo/?demo=expansion_panel"></iframe> | ||
|
||
```python | ||
--8<-- "demo/expansion_panel.py" | ||
``` | ||
|
||
## API | ||
|
||
::: mesop.components.accordion.accordion.accordion | ||
::: mesop.components.expansion_panel.expansion_panel.expansion_panel | ||
::: mesop.components.expansion_panel.expansion_panel.ExpansionPanelToggleEvent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
load("//mesop/components:defs.bzl", "mesop_component") | ||
|
||
package( | ||
default_visibility = ["//build_defs:mesop_internal"], | ||
) | ||
|
||
mesop_component( | ||
name = "accordion", | ||
) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<mat-accordion> | ||
<ng-content></ng-content> | ||
</mat-accordion> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
syntax = "proto2"; | ||
|
||
package mesop.components.accordion; | ||
|
||
message AccordionType { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import mesop.components.accordion.accordion_pb2 as accordion_pb | ||
from mesop.component_helpers import ( | ||
insert_composite_component, | ||
register_native_component, | ||
) | ||
|
||
|
||
@register_native_component | ||
def accordion( | ||
*, | ||
key: str | None = None, | ||
): | ||
""" | ||
This function creates an accordion. | ||
This is more of a visual component. It is used to style a group of expansion panel | ||
components in a unified and consistent way (as if they were one component -- i.e. an | ||
accordion). | ||
The mechanics of an accordion that only allows one expansion panel to be open at a | ||
time, must be implemented manually, but is easy to do with Mesop state and event | ||
handlers. | ||
""" | ||
return insert_composite_component( | ||
key=key, | ||
type_name="accordion", | ||
proto=accordion_pb.AccordionType(), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import {MatAccordion} from '@angular/material/expansion'; | ||
import {Component, Input} from '@angular/core'; | ||
import { | ||
Key, | ||
Type, | ||
} from 'mesop/mesop/protos/ui_jspb_proto_pb/mesop/protos/ui_pb'; | ||
import {AccordionType} from 'mesop/mesop/components/accordion/accordion_jspb_proto_pb/mesop/components/accordion/accordion_pb'; | ||
|
||
@Component({ | ||
selector: 'mesop-accordion', | ||
templateUrl: 'accordion.ng.html', | ||
standalone: true, | ||
imports: [MatAccordion], | ||
}) | ||
export class AccordionComponent { | ||
@Input({required: true}) type!: Type; | ||
@Input() key!: Key; | ||
private _config!: AccordionType; | ||
|
||
ngOnChanges() { | ||
this._config = AccordionType.deserializeBinary( | ||
this.type.getValue() as unknown as Uint8Array, | ||
); | ||
} | ||
|
||
config(): AccordionType { | ||
return this._config; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
load("//mesop/components:defs.bzl", "mesop_component") | ||
load("//build_defs:defaults.bzl", "sass_binary") | ||
|
||
package( | ||
default_visibility = ["//build_defs:mesop_internal"], | ||
) | ||
|
||
mesop_component( | ||
name = "expansion_panel", | ||
assets = [":expansion_panel.css"], | ||
) | ||
|
||
sass_binary( | ||
name = "styles", | ||
src = "expansion_panel.scss", | ||
sourcemap = False, | ||
) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
load("//build_defs:defaults.bzl", "py_library") | ||
|
||
package( | ||
default_visibility = ["//build_defs:mesop_examples"], | ||
) | ||
|
||
py_library( | ||
name = "e2e", | ||
srcs = glob(["*.py"]), | ||
deps = [ | ||
"//mesop", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from . import accordion_app as accordion_app | ||
from . import expansion_panel_app as expansion_panel_app | ||
from . import multi_accordion_app as multi_accordion_app |
Oops, something went wrong.