Py.Cafe

maartenbreddels/

dash-context-menu-interaction

Dash Context Menu Interaction

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import uuid

import dash_mantine_components as dmc
from dash import (
    ALL,
    MATCH,
    ClientsideFunction,
    Dash,
    Input,
    Output,
    State,
    _dash_renderer,
    callback,
    clientside_callback,
    ctx,
    html,
)
from dash_iconify import DashIconify

_dash_renderer._set_react_version("18.2.0")


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

class ids:
    contextmenu_div = lambda idx: {"type": "contextmenu-div", "idx": idx}
    menu = "context-menu"
    menu_button = "context-menu-trigger"
    menu_label = "context-menu-label"
    menu_action = lambda action: {"type": "context-menu-action", "action": action}
    output = "output"

ACTION_ICONS = {
    "open": "carbon:arrow-up-right",
    "copy": "carbon:copy",
    "share": "carbon:share",
    "delete": "carbon:trash-can",
}

app.layout = dmc.MantineProvider(
    [
        dmc.NotificationProvider(containerWidth=200, position="top-right"),
        html.Div(id=ids.output),
        dmc.Menu(
            [
                dmc.MenuTarget(
                    html.Div(id=ids.menu_button),
                    boxWrapperProps={
                        "style": {
                            "position": "fixed",
                            "zIndex": -1,
                            "inset": 0,
                        },
                    }
                ),
                dmc.MenuDropdown(
                    [
                        dmc.MenuLabel("", id=ids.menu_label),
                        dmc.MenuItem(
                            "Open",
                            leftSection=DashIconify(icon=ACTION_ICONS["open"], height=16),
                            id=ids.menu_action("open"),
                        ),
                        dmc.MenuItem(
                            "Copy",
                            leftSection=DashIconify(icon=ACTION_ICONS["copy"], height=16),
                            id=ids.menu_action("copy"),
                        ),
                        dmc.MenuItem(
                            "Share",
                            leftSection=DashIconify(icon=ACTION_ICONS["share"], height=16),
                            id=ids.menu_action("share"),
                        ),
                        dmc.MenuDivider(),
                        dmc.MenuItem(
                            "Delete",
                            leftSection=DashIconify(icon=ACTION_ICONS["delete"], height=16),
                            id=ids.menu_action("delete"),
                        ),
                    ],
                ),
            ],
            id=ids.menu,
            position="left-start",
            shadow="sm",
            trapFocus=False,
            transitionProps={"transition": "pop-top-left"},
            width=150,
        ),
        dmc.SimpleGrid(
            [
                dmc.Paper(
                    children=dmc.Text(i + 1, fw=600, size="3rem", c="dimmed", opacity=0.5),
                    id=ids.contextmenu_div(i + 1),
                    h=250,
                    withBorder=True,
                    bg="var(--mantine-color-default-hover)",
                    style={"display": "grid", "placeItems": "center"},
                )
                for i in range(6)
            ],
            cols=3,
            spacing="1.5rem",
            p="1.5rem",
        ),
    ],
)

clientside_callback(
    ClientsideFunction(namespace="contextmenu", function_name="cardContextMenu"),
    Output(ids.contextmenu_div(MATCH), "id"),
    Input(ids.contextmenu_div(MATCH), "id"),
    State(ids.menu_button, "id"),
    State(ids.menu, "id"),
    State(ids.menu, "width"),
    State(ids.menu_label, "id"),
)

@callback(
    Output(ids.output, "children"),
    Input(ids.menu_action(ALL), "n_clicks"),
    State(ids.menu, "data-item"),
)
def update_output(_trigger, item_id):
    if not any(_trigger):
        return None

    return dmc.Notification(
        message=f"{ctx.triggered_id['action'].title()} item {item_id['idx']}",
        action="show",
        id=uuid.uuid4().hex,
        withBorder=True,
        icon=DashIconify(icon=ACTION_ICONS[ctx.triggered_id["action"]], height=16),
    )


if __name__ == "__main__":
    app.run_server(debug=True, host="localhost")