Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions nicegui/elements/mermaid.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ export default {
console.error(error);
this.$emit("error", error);
}
if (this.function_name) {
window[this.function_name] = (node, param) => {
this.$emit("nodeClicked", {node: node, param: param});
}
}
},
async update(content) {
if (this.last_content === content) return;
Expand Down Expand Up @@ -48,5 +53,6 @@ export default {
props: {
config: Object,
content: String,
function_name: String,
},
};
34 changes: 28 additions & 6 deletions nicegui/elements/mermaid.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import uuid
from typing import Dict, Optional

from ..events import GenericEventArguments, Handler
from ..logging import log
from .mixins.content_element import ContentElement


Expand All @@ -11,7 +14,7 @@ class Mermaid(ContentElement,
]):
CONTENT_PROP = 'content'

def __init__(self, content: str, config: Optional[Dict] = None) -> None:
def __init__(self, content: str, config: Optional[Dict] = None, *, on_node_click: Optional[Handler[GenericEventArguments]] = None) -> None:
"""Mermaid Diagrams

Renders diagrams and charts written in the Markdown-inspired `Mermaid <https://mermaid.js.org/>`_ language.
Expand All @@ -25,12 +28,31 @@ def __init__(self, content: str, config: Optional[Dict] = None) -> None:

Refer to the Mermaid documentation for the ``mermaid.initialize()`` method for a full list of options.

:param content: the Mermaid content to be displayed
:param content: the Mermaid content to be displayed. If ``on_node_click`` is passed, expect lines such as ``click A {handler}()``, where ``{handler}`` is a placeholder for the JavaScript function defined by NiceGUI to handle node clicks.
:param config: configuration dictionary to be passed to ``mermaid.initialize()``
:param on_node_click: a callback function that will be called when a node is clicked. The function should accept an event argument
"""
super().__init__(content=content)
self._props['config'] = config
function_name = f'mermaid_click_handler_{uuid.uuid4().hex}' if on_node_click else None
super().__init__(content=self._format_content(content, function_name))
self._props['config'] = config if config is not None else {}

if on_node_click is not None:
self.on('nodeClicked', on_node_click)
self._props['config']['securityLevel'] = 'loose'
self._props['function_name'] = function_name

def _handle_content_change(self, content: str) -> None:
self._props[self.CONTENT_PROP] = content.strip()
self.run_method('update', content.strip())
content_final = self._format_content(content, self._props.get('function_name'))
self._props[self.CONTENT_PROP] = content_final
self.run_method('update', content_final)

@staticmethod
def _format_content(content: str, function_name: Optional[str]) -> str:
content_final = content.strip()
if function_name is not None:
try:
content_final = content_final.format(handler=function_name)
except KeyError:
log.warning(
'Mermaid content does not contain {handler} placeholder, but node click functionality is enabled. Please add {handler} to the content string.')
return content_final