snehilvj / dash-mantine-components

Plotly Dash components based on Mantine React Components
https://www.dash-mantine-components.com
MIT License
570 stars 56 forks source link

[bug] The Progress with Tooltips - includes workaround #319

Closed AnnMarieW closed 1 month ago

AnnMarieW commented 1 month ago

The example Progress with Tooltips from the upstream Mantine docs is not working.

It should look like this: image



But instead it looks like:

image


from dash import Dash, _dash_renderer
import dash_mantine_components as dmc

_dash_renderer._set_react_version("18.2.0")

app = Dash(external_stylesheets=dmc.styles.ALL)

component = dmc.ProgressRoot(
    [
        dmc.Tooltip(
            dmc.ProgressSection(
                dmc.ProgressLabel("Documents"),
                value=33,
                color="cyan",
            ),
            label="Documents – 33Gb",
        ),
        dmc.Tooltip(
            dmc.ProgressSection(
                dmc.ProgressLabel("Photos"),
                value=28,
                color="pink",
            ),
            label="Photos – 28Gb",
        ),
        dmc.Tooltip(
            dmc.ProgressSection(
                dmc.ProgressLabel("Orhwe"),
                value=25,
                color="orange",
            ),
            label="Other – 15Gb",
        ),
    ],
    size=40,
)

app.layout = dmc.MantineProvider(component)

if __name__ == "__main__":
    app.run(debug=True)
AnnMarieW commented 1 month ago

@datenzauberai do you have any ideas about this one? I tried a few different boxWapperProps but nothing worked so far.

datenzauberai commented 1 month ago

Oh no, once again the wrapping box 😂 You can force the wrapping box to be ignored for layout and sizing by setting display: contents.

        dmc.Tooltip(
            dmc.ProgressSection(
                dmc.ProgressLabel("Documents"),
                value=33,
                color="cyan",
            ),
            label="Documents – 33Gb", boxWrapperProps={"display": "contents"},
        ),

However, this has the bad side-effect that the tooltip is no longer displayed correctly. I'm not sure if both issues can be solved.

datenzauberai commented 1 month ago

I tried a little bit more and I think getting rid of the wrapping boxes is the most promising way. If I understand everything correctly the wrapping box is there, because every custom dash components is a function component at the end (no matter how you define them) and won't accept a ref. See also https://github.com/plotly/dash/issues/2571 The box accepts a ref and keeps a lot of things working.

@AnnMarieW @snehilvj Have you ever tried wrapping the children in a less intrusive way than using a box which gets rendered as a div at the end and causes the problems?

AnnMarieW commented 1 month ago

@datenzauberai Thanks for digging in here - do you have any suggestions?

BSd3v commented 1 month ago

Here is a better workaround, you can overwrite the default boxWrapperProps of w:


from dash import Dash, _dash_renderer
import dash_mantine_components as dmc

_dash_renderer._set_react_version("18.2.0")

app = Dash(external_stylesheets=dmc.styles.ALL)

component = dmc.ProgressRoot(
    [
        dmc.Tooltip(
            dmc.ProgressSection(
                dmc.ProgressLabel("Documents"),
                value=33,
                color="cyan",
                style={'width': '100%'}
            ),
            label="Documents – 33Gb",
            boxWrapperProps={"w": "33%"}
        ),
        dmc.Tooltip(
            dmc.ProgressSection(
                dmc.ProgressLabel("Photos"),
                value=28,
                color="pink",
                style={'width': '100%'}
            ),
            label="Photos – 28Gb",
            boxWrapperProps={"w": "28%"}
        ),
        dmc.Tooltip(
            dmc.ProgressSection(
                dmc.ProgressLabel("Orhwe"),
                value=25,
                color="orange",
                style={'width': '100%'}
            ),
            label="Other – 15Gb",
            boxWrapperProps={"w": "25%"}
        ),
    ],
    size=40,
)

app.layout = dmc.MantineProvider(component)

if __name__ == "__main__":
    app.run(debug=True)

The issue is as you pointed out, @datenzauberai. However, due to how Dash renders, I'm not sure there is much else that can be done about it. Removing the Box as you suggested may work, just not sure if there would be anything that would break.

As there arent really tests, we'd have to manually check.

AnnMarieW commented 1 month ago

@BSd3v - thanks for the workaround! That's super helpful for now, but still searching for a better way :-) I tried just removing the box component, but then the Tootlip did not render at all.

datenzauberai commented 1 month ago

Sorry, no new insights here. I have a gut feeling that solving this in dmc might be possible but won’t be easy at all when the children are dash components. I think it’s not possible to forward the ref through dash's very own wrapping layer. Now, especially this case where the children’s layout depends on the parent and vice versa is hardly solvable with a custom wrapper. If the wrapper is considered for the layout the children can’t be sized to x% of the parent (@BSd3v works around by basically reimplementing the sizing logic for the children). If the wrapper is not part of the layout the children will be sized correctly, but the tooltip can’t be positioned correctly. Simply removing the current wrapping box breaks, because then the tooltip is directly exposed to the dash wrapped children that won’t accept the needed ref. Guess we need to make a PR for dash to get the ref forwarding working…

AnnMarieW commented 1 month ago

@alexcjohnson - I would love to hear your thoughts on this one.

Do you think it's necessary to do a PR in dash as described above because the Mantine Tooltip children are required to support a ref prop? If so, do you have any guidance on getting started?

Here is the dmc.Tooltip Do you know of any other workarounds?

alexcjohnson commented 1 month ago

Oh that’s interesting. I don’t see a clean alternative to adding ref forwarding into dash renderer, and I can imagine this being useful for other coupled components in the future. @t4rk1n any other thoughts?

datenzauberai commented 1 month ago

Inspired by the doc page that @AnnMarieW updated: another good workaround would be to use a FloatingTooltip combined with "display": "contents" or wrapping only the ProgressLabel with the standard Tooltip: https://gist.github.com/datenzauberai/9a16329ef52f8a8117cf67ff8b80d9a1

BSd3v commented 1 month ago

The prgogresslabel only does the wording, so not as good as the floating. The floating is probably the easiest to do.

AnnMarieW commented 1 month ago

Great example @datenzauberai The FloatingTooltip looks fantastic. I added it to the docs :pray:

AnnMarieW commented 1 month ago

The best solution requires a change to Dash. The workaround will be the recommended solution for now.