Skip to content

Commit

Permalink
Add support for named slots (#1145)
Browse files Browse the repository at this point in the history
  • Loading branch information
richard-to authored Dec 29, 2024
1 parent a51cc45 commit 2425b3b
Show file tree
Hide file tree
Showing 13 changed files with 1,111 additions and 51 deletions.
91 changes: 90 additions & 1 deletion docs/components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def scaffold(url: str):
me.slot()
```

Now other components can re-use this scaffold component:
Now other components can re-use this `scaffold` component:

```python
def page1():
Expand All @@ -58,6 +58,95 @@ def page1():

This is similar to Angular's [Content Projection](https://angular.io/guide/content-projection).

### Advanced content component usage

#### Multi-slot projection

Mesop supports multi-slot projection using named slots.

Here is an example:

```python
@me.slotclass
class LayoutSlots:
header: me.NamedSlot
content: me.NamedSlot
footer: me.NamedSlot

@me.content_component(named_slots=LayoutSlots)
def layout():
with me.box(style=me.Style(background="black")):
me.slot("header")
with me.box(style=me.Style(background="white")):
me.slot("content")
with me.box(style=me.Style(background="black")):
me.slot("footer")
```

Now other components can re-use this `layout` component:

```python
def page1():
with layout() as c:
with c.header():
me.text("Header")
with c.content():
me.text("Content")
with c.footer():
me.text("Footer")
```

#### Composed content components

Content components can also use other content components, but you need to be careful since
slot rendering cannot be deferred to the parent component.

???+ failure "Slot rendering cannot be deferred by setting another slot."

```python
@me.content_component
def inner():
me.slot()

@me.content_component
def outer():
with inner():
me.slot()
```

???+ success "Content components can use content components so long as the slots get rendered by the parent content component."

```python
@me.content_component
def header(background_color: str):
with me.box(style=me.Style(background=background_color)):
me.slot()


@me.content_component
def footer(background_color: str):
with me.box(style=me.Style(background=background_color)):
me.slot()


@me.content_component()
def content_layout():
with header(background_color="black"):
me.text("Header")
with me.box(style=me.Style(background="white")):
me.slot()
with footer(background_color="red")
me.text("Footer")
```

Now other components can re-use this `content_layout` component:

```python
def page1():
with content_layout():
me.text("Content")
```

## Component Key

Every native component in Mesop accepts a `key` argument which is a component identifier. This is used by Mesop to tell [Angular whether to reuse the DOM element](https://angular.io/api/core/TrackByFunction#description).
Expand Down
6 changes: 6 additions & 0 deletions mesop/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
from mesop.component_helpers import (
Style as Style,
)
from mesop.component_helpers.helper import (
NamedSlot as NamedSlot,
)
from mesop.component_helpers.helper import (
component as component,
)
Expand All @@ -34,6 +37,9 @@
from mesop.component_helpers.helper import (
slot as slot,
)
from mesop.component_helpers.helper import (
slotclass as slotclass,
)
from mesop.components.accordion.accordion import accordion as accordion
from mesop.components.audio.audio import audio as audio
from mesop.components.autocomplete.autocomplete import (
Expand Down
1 change: 1 addition & 0 deletions mesop/component_helpers/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ py_test(
srcs = ["helper_test.py"],
deps = [
":component_helpers",
"//mesop/runtime",
"//mesop/server",
] + THIRD_PARTY_PY_PYTEST,
)
Loading

0 comments on commit 2425b3b

Please sign in to comment.