google / mesop

Rapidly build AI apps in Python
https://google.github.io/mesop/
Apache License 2.0
5.64k stars 271 forks source link

me.slot appending in nested content_components #929

Open ruttenm opened 2 months ago

ruttenm commented 2 months ago

I tried to nest two content_components, where the me.slot() is not at the end of the component. This leads to unexpected behavior in the layout where it seems the content of both me.slots() is combined in the last me.slot().

import mesop as me

@me.page(path="/")
def homepage():
    with layout():
        me.text("hello world")

@me.content_component
def layout():
    with me.box(
        style=me.Style(
            display="flex",
            flex_direction="column",
            height="100vh",
            background="red",
        )
    ):

        with me.box(
            style=me.Style(
                flex="1",
                background="blue",
            )
        ):
            me.slot()

        with nav_bar():
            me.text("navbar")

@me.content_component
def nav_bar():
    me.slot()

To Reproduce

Run mesop test.py

Expected behavior The expected layout is to see "Hello world" in the blue box in the main content, and "navbar" in red at the bottom. However, when using with me.navbar(): the "Hello world" is rendered in the red navbar at the bottom.

Desktop System Info

RodrigoDiasDeOliveira commented 2 months ago

HI whats up?! i hope i can help...

The issue you are facing is likely related to the way the me.slot() function is being handled within nested content components. When me.slot() is used in nested components, especially when the slots are not at the end of the component, it can cause unexpected behavior in rendering. Specifically, the content for the slots might be combined incorrectly due to how the framework interprets and assigns content to the slots.

Here's an analysis of the problem and a potential solution:

I Think: In the layout component, you are using me.slot() within the first me.box, and then you have another content component (nav_bar) that also contains a me.slot(). When the framework processes the slots, it might combine the content meant for the first me.slot() with the content for the second me.slot(), leading to incorrect rendering.

To fix this issue, you can try explicitly specifying different slot names using the name parameter for each me.slot(). This way, you can ensure that the content is correctly assigned to the appropriate slot.

Here is the modified code:

import mesop as me

@me.page(path="/")
def homepage():
    with layout():
        me.text("hello world")

@me.content_component
def layout():
    with me.box(
        style=me.Style(
            display="flex",
            flex_direction="column",
            height="100vh",
            background="red",
        )
    ):
        with me.box(
            style=me.Style(
                flex="1",
                background="blue",
            )
        ):
            me.slot(name="main_content")  # Use a named slot

        with nav_bar():
            me.text("navbar")

@me.content_component
def nav_bar():
    me.slot(name="navbar_content")  # Use a different named slot

Adjusting the homepage Function:

If you need to specify which content goes into which slot, you can do so by passing content directly into named slots:

@me.page(path="/")
def homepage():
    with layout():
        me.slot(name="main_content"):
            me.text("hello world")

This ensures that the content is placed in the correct slot within the layout, and the layout should behave as expected, with "Hello world" displayed in the blue box and "navbar" in the red box at the bottom.

By using named slots, you can avoid the issue where the content from multiple me.slot() instances gets combined incorrectly. This should give you the expected layout where "Hello world" is rendered in the main content area, and the navbar text remains in the navbar area.

I wished i could help!

ruttenm commented 2 months ago

@RodrigoDiasDeOliveira thanks, also what chatGPT suggested, but me.slot() does not take any arguments. The suggestion returns a runtime error: "slot() got an unexpected keyword argument 'name'". Is this maybe supported in a beta version I don't know about? I am using mesop 0.12.3. Would love such functionality though, similar to requested in https://github.com/google/mesop/issues/810

richard-to commented 2 months ago

Thanks for bringing this issue to our attention. This seems like a bug. I don't have a fix off the top of my head, so we'll need to look into it. I also agree support for multiple slots as in #810 would be a nice improvement.