Skip to content

Commit 959702f

Browse files
committed
Make button a simpler, high-level API which uses a lower-level API content_button
1 parent a6c0a37 commit 959702f

File tree

22 files changed

+130
-57
lines changed

22 files changed

+130
-57
lines changed

docs/components/button.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Overview
22

3-
Button is based on the [Angular Material button component](https://material.angular.io/components/button/overview). Button is a [composite component](../guides/components.md#composite-components) and frequently used as a parent of the [Text](./text.md) component.
3+
Button is based on the [Angular Material button component](https://material.angular.io/components/button/overview).
44

55
## Examples
66

@@ -11,4 +11,5 @@ Button is based on the [Angular Material button component](https://material.angu
1111
## API
1212

1313
::: mesop.components.button.button.button
14+
::: mesop.components.button.button.content_button
1415
::: mesop.events.ClickEvent

mesop/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@
3131

3232
# REF(//scripts/scaffold_component.py):insert_component_import_export
3333
from mesop.components.box.box import box as box
34-
from mesop.components.button.button import button as button
34+
from mesop.components.button.button import (
35+
button as button,
36+
)
37+
from mesop.components.button.button import (
38+
content_button as content_button,
39+
)
3540
from mesop.components.checkbox.checkbox import (
3641
CheckboxChangeEvent as CheckboxChangeEvent,
3742
)

mesop/component_helpers/helper.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,14 @@ def wrapper(*args: Any, **kw_args: Any):
100100
source_code_location = get_caller_source_code_location(levels=2)
101101
component.MergeFrom(
102102
create_component(
103-
component_name=pb.ComponentName(
104-
fn_name=fn.__name__, module_path=fn.__module__
105-
),
103+
component_name=get_component_name(fn),
106104
proto=pb.UserDefinedType(
107105
args=[
108106
pb.UserDefinedType.Arg(
109107
arg_name=kw_arg, code_value=map_code_value(value)
110108
)
111109
for kw_arg, value in kw_args.items()
110+
if map_code_value(value) is not None
112111
]
113112
),
114113
source_code_location=source_code_location,
@@ -123,7 +122,13 @@ def wrapper(*args: Any, **kw_args: Any):
123122
return cast(C, wrapper)
124123

125124

126-
def map_code_value(value: Any) -> pb.CodeValue:
125+
def get_component_name(fn: Callable[..., Any]) -> pb.ComponentName:
126+
if "mesop.components" in fn.__module__:
127+
return pb.ComponentName(core_module=True, fn_name=fn.__name__)
128+
return pb.ComponentName(fn_name=fn.__name__, module_path=fn.__module__)
129+
130+
131+
def map_code_value(value: Any) -> pb.CodeValue | None:
127132
if isinstance(value, str):
128133
return pb.CodeValue(string_value=value)
129134
if isinstance(value, int):
@@ -132,7 +137,7 @@ def map_code_value(value: Any) -> pb.CodeValue:
132137
return pb.CodeValue(double_value=value)
133138
if isinstance(value, bool):
134139
return pb.CodeValue(bool_value=value)
135-
raise Exception("Unhandled value", value)
140+
return None
136141

137142

138143
def create_component(

mesop/components/button/button.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,50 @@
22

33
import mesop.components.button.button_pb2 as button_pb
44
from mesop.component_helpers import (
5+
component,
56
insert_composite_component,
67
register_event_handler,
78
register_native_component,
89
)
10+
from mesop.components.text.text import text
911
from mesop.events import ClickEvent
1012

1113

12-
@register_native_component
14+
@component
1315
def button(
16+
label: str | None = None,
17+
*,
18+
on_click: Callable[[ClickEvent], Any] | None = None,
19+
type: Literal["raised", "flat", "stroked"] | None = None,
20+
color: Literal["primary", "accent", "warn"] | None = None,
21+
disable_ripple: bool = False,
22+
disabled: bool = False,
23+
key: str | None = None,
24+
):
25+
"""Creates a simple text Button component.
26+
27+
Args:
28+
label: Text label for button
29+
on_click: [click](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click_event) is a native browser event.
30+
type: Type of button style to use
31+
color: Theme color palette of the button
32+
disable_ripple: Whether the ripple effect is disabled or not.
33+
disabled: Whether the button is disabled.
34+
key: Unique identifier for this component instance.
35+
"""
36+
with content_button(
37+
on_click=on_click,
38+
type=type,
39+
color=color,
40+
disable_ripple=disable_ripple,
41+
disabled=disabled,
42+
key=key,
43+
):
44+
text(label)
45+
46+
47+
@register_native_component
48+
def content_button(
1449
*,
1550
on_click: Callable[[ClickEvent], Any] | None = None,
1651
type: Literal["raised", "flat", "stroked", "icon"] | None = None,
@@ -19,8 +54,9 @@ def button(
1954
disabled: bool = False,
2055
key: str | None = None,
2156
):
22-
"""Creates a Button component.
23-
Button is a composite component.
57+
"""Creates a button component, which is a composite component. Typically, you would use a text or icon component as a child.
58+
59+
Intended for advanced use cases.
2460
2561
Args:
2662
on_click: [click](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click_event) is a native browser event.
@@ -32,7 +68,7 @@ def button(
3268
"""
3369
return insert_composite_component(
3470
key=key,
35-
type_name="button",
71+
type_name="content_button",
3672
proto=button_pb.ButtonType(
3773
color=color,
3874
disable_ripple=disable_ripple,

mesop/editor/editor_codemod.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ def leave_Call( # type: ignore (erroneously forbids return type with `None`)
146146
"icon"
147147
]:
148148
first_positional_arg = "icon"
149+
if component_name.fn_name in ["button"]:
150+
first_positional_arg = "label"
149151
return self._update_call(
150152
updated_node,
151153
self.input.arg_path.segments,

mesop/editor/editor_codemod_test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,21 @@ def test_simple_callsite(self) -> None:
160160
),
161161
)
162162

163+
def test_button_callsite(self) -> None:
164+
self.assertEditorUpdate(
165+
"button_callsite",
166+
pb.EditorUpdateCallsite(
167+
component_name=me_name("button"),
168+
arg_path=pb.ArgPath(
169+
segments=[pb.ArgPathSegment(keyword_argument="type")]
170+
),
171+
replacement=pb.CodeReplacement(
172+
new_code=pb.CodeValue(string_value="flat"),
173+
),
174+
source_code_location=pb.SourceCodeLocation(line=5),
175+
),
176+
)
177+
163178
def test_multi_callsite(self) -> None:
164179
self.assertEditorUpdate(
165180
"multi_callsite",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import mesop as me
2+
3+
4+
def app():
5+
me.button(type="flat")
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import mesop as me
2+
3+
4+
def app():
5+
me.button(type="stroked")

mesop/examples/buttons.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,19 @@ def button_click(event: me.ClickEvent):
1414
@me.page(path="/buttons")
1515
def main():
1616
state = me.state(State)
17-
with me.button(
18-
on_click=button_click, type="flat", color="primary", disabled=False
19-
):
20-
me.text(text="primary color button")
2117

22-
with me.button(on_click=button_click, type="flat"):
23-
me.text(text="flat button")
18+
me.button(
19+
"primary color button",
20+
on_click=button_click,
21+
type="flat",
22+
color="primary",
23+
disabled=False,
24+
)
2425

25-
with me.button(on_click=button_click, type="raised"):
26-
me.text(text="raised button")
26+
me.button("flat button", on_click=button_click, type="flat")
2727

28-
with me.button(on_click=button_click, type="stroked"):
29-
me.text(text="stroked button")
28+
me.button("raised button", on_click=button_click, type="raised")
29+
30+
me.button("stroked button", on_click=button_click, type="stroked")
3031

3132
me.text(text=f"{state.count_clicks} clicks")

mesop/examples/docs/counter.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,4 @@ def button_click(event: me.ClickEvent):
1515
def main():
1616
state = me.state(State)
1717
me.text(f"Clicks: {state.clicks}")
18-
with me.button(on_click=button_click):
19-
me.text("Increment")
18+
me.button("Increment", on_click=button_click)

0 commit comments

Comments
 (0)