Skip to content

Commit d207921

Browse files
committed
Simplify checkbox API which uses lower-level content_checkbox component
1 parent e0d7d36 commit d207921

File tree

9 files changed

+74
-16
lines changed

9 files changed

+74
-16
lines changed

docs/components/checkbox.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ Checkbox is a multi-selection form control and is based on the [Angular Material
1111
## API
1212

1313
::: mesop.components.checkbox.checkbox.checkbox
14+
::: mesop.components.checkbox.checkbox.content_checkbox
1415
::: mesop.components.checkbox.checkbox.CheckboxChangeEvent
1516
::: mesop.components.checkbox.checkbox.CheckboxIndeterminateChangeEvent

mesop/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
from mesop.components.checkbox.checkbox import (
4747
checkbox as checkbox,
4848
)
49+
from mesop.components.checkbox.checkbox import (
50+
content_checkbox as content_checkbox,
51+
)
4952
from mesop.components.divider.divider import divider as divider
5053
from mesop.components.icon.icon import icon as icon
5154
from mesop.components.image.image import image as image

mesop/components/checkbox/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ package(
66

77
mesop_component(
88
name = "checkbox",
9+
py_deps = ["//mesop/components/text:py"],
910
)

mesop/components/checkbox/checkbox.py

+53-4
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33

44
import mesop.components.checkbox.checkbox_pb2 as checkbox_pb
55
from mesop.component_helpers import (
6+
component,
67
insert_composite_component,
78
register_event_handler,
89
register_event_mapper,
910
register_native_component,
1011
)
12+
from mesop.components.text.text import text
1113
from mesop.events import MesopEvent
1214

1315

@@ -53,8 +55,54 @@ class CheckboxIndeterminateChangeEvent(MesopEvent):
5355
)
5456

5557

56-
@register_native_component
58+
@component
5759
def checkbox(
60+
label: str | None = None,
61+
*,
62+
on_change: Callable[[CheckboxChangeEvent], Any] | None = None,
63+
on_indeterminate_change: Callable[[CheckboxIndeterminateChangeEvent], Any]
64+
| None = None,
65+
label_position: Literal["before", "after"] = "after",
66+
disable_ripple: bool = False,
67+
tab_index: int = 0,
68+
color: Literal["primary", "accent", "warn"] | None = None,
69+
checked: bool = False,
70+
disabled: bool = False,
71+
indeterminate: bool = False,
72+
key: str | None = None,
73+
):
74+
"""Creates a simple Checkbox component with a text label.
75+
76+
Args:
77+
label: Text label for checkbox
78+
on_change: Event emitted when the checkbox's `checked` value changes.
79+
on_indeterminate_change: Event emitted when the checkbox's `indeterminate` value changes.
80+
label_position: Whether the label should appear after or before the checkbox. Defaults to 'after'
81+
disable_ripple: Whether the checkbox has a ripple.
82+
tab_index: Tabindex for the checkbox.
83+
color: Palette color of the checkbox.
84+
checked: Whether the checkbox is checked.
85+
disabled: Whether the checkbox is disabled.
86+
indeterminate: Whether the checkbox is indeterminate. This is also known as "mixed" mode and can be used to represent a checkbox with three states, e.g. a checkbox that represents a nested list of checkable items. Note that whenever checkbox is manually clicked, indeterminate is immediately set to false.
87+
key: Unique identifier for this component instance.
88+
"""
89+
with content_checkbox(
90+
on_change=on_change,
91+
on_indeterminate_change=on_indeterminate_change,
92+
label_position=label_position,
93+
disable_ripple=disable_ripple,
94+
tab_index=tab_index,
95+
color=color,
96+
checked=checked,
97+
disabled=disabled,
98+
indeterminate=indeterminate,
99+
key=key,
100+
):
101+
text(label)
102+
103+
104+
@register_native_component
105+
def content_checkbox(
58106
*,
59107
on_change: Callable[[CheckboxChangeEvent], Any] | None = None,
60108
on_indeterminate_change: Callable[[CheckboxIndeterminateChangeEvent], Any]
@@ -68,8 +116,9 @@ def checkbox(
68116
indeterminate: bool = False,
69117
key: str | None = None,
70118
):
71-
"""Creates a Checkbox component.
72-
Checkbox is a composite component.
119+
"""Creates a Checkbox component which is a composite component. Typically, you would use a text or icon component as a child.
120+
121+
Intended for advanced use cases.
73122
74123
Args:
75124
on_change: Event emitted when the checkbox's `checked` value changes.
@@ -85,7 +134,7 @@ def checkbox(
85134
"""
86135
return insert_composite_component(
87136
key=key,
88-
type_name="checkbox",
137+
type_name="content_checkbox",
89138
proto=checkbox_pb.CheckboxType(
90139
label_position=label_position,
91140
disable_ripple=disable_ripple,

mesop/components/checkbox/e2e/checkbox_app.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ def on_update(event: me.CheckboxChangeEvent):
1515
@me.page(path="/components/checkbox/e2e/checkbox_app")
1616
def app():
1717
state = me.state(State)
18-
with me.checkbox(
18+
me.checkbox(
19+
"label",
1920
on_change=on_update,
2021
checked=state.checked,
21-
):
22-
me.text(text="label")
22+
disable_ripple=False,
23+
indeterminate=False,
24+
)
2325

2426
if state.checked:
2527
me.text(text="is checked")

mesop/examples/simple.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ def main():
3636
me.text(text=f"{state.count} clicks")
3737
me.text(text=f"Selected keys: {state.keys}")
3838
for i in range(1000):
39-
with me.checkbox(
39+
me.checkbox(
40+
"check",
4041
on_change=checkbox_update,
4142
key=f"check={i}",
42-
):
43-
me.text(text="check")
43+
)
4444
me.text(text=state.string)
4545

4646

mesop/examples/testing/conditional_event_handler.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ def inner_on_change(event: me.CheckboxChangeEvent):
1919
state.second = event.checked
2020

2121
me.text("Make sure tracing discovers event handlers that are conditional")
22-
with me.checkbox(on_change=outer_on_change):
23-
me.text("first checkbox")
22+
me.checkbox("first checkbox", on_change=outer_on_change)
2423
state = me.state(State)
2524
if state.first:
26-
with me.checkbox(on_change=inner_on_change):
27-
me.text("second checkbox")
25+
me.checkbox("second checkbox", on_change=inner_on_change)
2826
if state.second:
2927
me.text("second checkbox has been checked")

mesop/web/src/component_renderer/type_to_component.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ export const typeToComponent = {
6868
'textarea': InputComponent,
6969
'button': UserDefinedComponent,
7070
'content_button': ButtonComponent,
71-
'checkbox': CheckboxComponent,
71+
'checkbox': UserDefinedComponent,
72+
'content_checkbox': CheckboxComponent,
7273
'text': TextComponent,
7374
'markdown': MarkdownComponent,
7475
} as TypeToComponent;

mesop/web/src/dev_tools/services/logger.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ export function mapComponentToObject(
9090

9191
if (
9292
component.getType()?.getName()?.getCoreModule() === false ||
93-
component.getType()?.getName()?.getFnName() === 'button'
93+
// These are core module components which are implemented as user defined components.
94+
['button', 'checkbox'].includes(
95+
component.getType()?.getName()?.getFnName()!,
96+
)
9497
) {
9598
const value: Record<string, any> = {};
9699
// Deserialize type

0 commit comments

Comments
 (0)