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")