reflex-gravityui-graph 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reflex_gravityui_graph/__init__.py +93 -0
- reflex_gravityui_graph/domain.py +210 -0
- reflex_gravityui_graph/graph.py +146 -0
- reflex_gravityui_graph/graph.pyi +123 -0
- reflex_gravityui_graph/graph_canvas.jsx +178 -0
- reflex_gravityui_graph/recipes.py +287 -0
- reflex_gravityui_graph-0.1.0.dist-info/METADATA +166 -0
- reflex_gravityui_graph-0.1.0.dist-info/RECORD +11 -0
- reflex_gravityui_graph-0.1.0.dist-info/WHEEL +5 -0
- reflex_gravityui_graph-0.1.0.dist-info/licenses/LICENSE +179 -0
- reflex_gravityui_graph-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""reflex-gravityui-graph: a Reflex wrapper for @gravity-ui/graph.
|
|
2
|
+
|
|
3
|
+
Public API::
|
|
4
|
+
|
|
5
|
+
from reflex_gravityui_graph import graph_canvas, GravityGraph
|
|
6
|
+
|
|
7
|
+
# DDD value objects for building graph data:
|
|
8
|
+
from reflex_gravityui_graph import Block, Connection, Anchor, EAnchorType, GraphData
|
|
9
|
+
|
|
10
|
+
# Example/recipe helpers (reproduce the upstream Storybook stories):
|
|
11
|
+
from reflex_gravityui_graph import (
|
|
12
|
+
one_block, two_connected_blocks, colored_connections, block_with_anchors,
|
|
13
|
+
generate_layered_blocks, grouped_graph, default_settings, THEMES,
|
|
14
|
+
)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from typing import TYPE_CHECKING, Any
|
|
18
|
+
|
|
19
|
+
from .domain import (
|
|
20
|
+
DEFAULT_BLOCK_HEIGHT,
|
|
21
|
+
DEFAULT_BLOCK_IS,
|
|
22
|
+
DEFAULT_BLOCK_WIDTH,
|
|
23
|
+
Anchor,
|
|
24
|
+
Block,
|
|
25
|
+
Connection,
|
|
26
|
+
EAnchorType,
|
|
27
|
+
GraphData,
|
|
28
|
+
)
|
|
29
|
+
from .recipes import (
|
|
30
|
+
DARK_THEME,
|
|
31
|
+
LIGHT_THEME,
|
|
32
|
+
THEMES,
|
|
33
|
+
block_with_anchors,
|
|
34
|
+
colored_connections,
|
|
35
|
+
default_settings,
|
|
36
|
+
generate_layered_blocks,
|
|
37
|
+
grouped_graph,
|
|
38
|
+
one_block,
|
|
39
|
+
two_connected_blocks,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# The component layer (``graph.py``) imports Reflex. We expose it lazily via
|
|
43
|
+
# PEP 562 ``__getattr__`` so the pure-Python domain/recipe API stays importable
|
|
44
|
+
# and unit-testable without Reflex installed (NFR5). Reflex is only imported
|
|
45
|
+
# when one of these symbols is actually accessed.
|
|
46
|
+
_LAZY_COMPONENT_EXPORTS = {"GravityGraph", "graph_canvas", "GRAVITY_GRAPH_VERSION"}
|
|
47
|
+
|
|
48
|
+
if TYPE_CHECKING: # pragma: no cover - typing/IDE only
|
|
49
|
+
from .graph import ( # noqa: F401
|
|
50
|
+
GRAVITY_GRAPH_VERSION,
|
|
51
|
+
GravityGraph,
|
|
52
|
+
graph_canvas,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def __getattr__(name: str) -> Any:
|
|
57
|
+
"""Lazily resolve the Reflex-dependent component exports (PEP 562)."""
|
|
58
|
+
if name in _LAZY_COMPONENT_EXPORTS:
|
|
59
|
+
from . import graph
|
|
60
|
+
|
|
61
|
+
return getattr(graph, name)
|
|
62
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
__version__ = "0.1.0"
|
|
66
|
+
|
|
67
|
+
__all__ = [
|
|
68
|
+
# Component
|
|
69
|
+
"GravityGraph",
|
|
70
|
+
"graph_canvas",
|
|
71
|
+
"GRAVITY_GRAPH_VERSION",
|
|
72
|
+
# Domain
|
|
73
|
+
"Anchor",
|
|
74
|
+
"Block",
|
|
75
|
+
"Connection",
|
|
76
|
+
"EAnchorType",
|
|
77
|
+
"GraphData",
|
|
78
|
+
"DEFAULT_BLOCK_IS",
|
|
79
|
+
"DEFAULT_BLOCK_WIDTH",
|
|
80
|
+
"DEFAULT_BLOCK_HEIGHT",
|
|
81
|
+
# Recipes
|
|
82
|
+
"default_settings",
|
|
83
|
+
"one_block",
|
|
84
|
+
"two_connected_blocks",
|
|
85
|
+
"colored_connections",
|
|
86
|
+
"block_with_anchors",
|
|
87
|
+
"generate_layered_blocks",
|
|
88
|
+
"grouped_graph",
|
|
89
|
+
"THEMES",
|
|
90
|
+
"LIGHT_THEME",
|
|
91
|
+
"DARK_THEME",
|
|
92
|
+
"__version__",
|
|
93
|
+
]
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""Domain value objects for @gravity-ui/graph entities (DDD).
|
|
2
|
+
|
|
3
|
+
These are framework-agnostic, immutable Python value objects that capture the
|
|
4
|
+
upstream entity shapes (``TBlock``, ``TConnection``, ``TAnchor``) and validate
|
|
5
|
+
their invariants in Python, so a misconfigured graph fails fast with a clear
|
|
6
|
+
message instead of silently rendering broken on Canvas. Each value object knows
|
|
7
|
+
how to serialize itself to the exact camelCase dict the library expects.
|
|
8
|
+
|
|
9
|
+
Typical use::
|
|
10
|
+
|
|
11
|
+
from reflex_gravityui_graph import Block, Connection, Anchor, EAnchorType
|
|
12
|
+
|
|
13
|
+
a = Block(id="a", x=0, y=0, name="A",
|
|
14
|
+
anchors=[Anchor(id="out", block_id="a", type=EAnchorType.OUT)])
|
|
15
|
+
b = Block(id="b", x=300, y=200, name="B",
|
|
16
|
+
anchors=[Anchor(id="in", block_id="b", type=EAnchorType.IN)])
|
|
17
|
+
edge = Connection(source_block_id="a", source_anchor_id="out",
|
|
18
|
+
target_block_id="b", target_anchor_id="in")
|
|
19
|
+
|
|
20
|
+
blocks = [a.to_dict(), b.to_dict()]
|
|
21
|
+
connections = [edge.to_dict()]
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from dataclasses import dataclass, field
|
|
27
|
+
from enum import Enum
|
|
28
|
+
from typing import Any, Union
|
|
29
|
+
|
|
30
|
+
BlockId = Union[str, int]
|
|
31
|
+
|
|
32
|
+
# Default block discriminator. @gravity-ui/graph renders blocks whose ``is`` is
|
|
33
|
+
# not registered in ``settings.blockComponents`` with its built-in canvas block,
|
|
34
|
+
# so this default "just works" without registering a custom component.
|
|
35
|
+
DEFAULT_BLOCK_IS = "block-action"
|
|
36
|
+
|
|
37
|
+
# Library defaults for block geometry (constants.block.WIDTH / HEIGHT).
|
|
38
|
+
DEFAULT_BLOCK_WIDTH = 200
|
|
39
|
+
DEFAULT_BLOCK_HEIGHT = 160
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class EAnchorType(str, Enum):
|
|
43
|
+
"""Anchor direction, mirroring the upstream ``EAnchorType`` enum."""
|
|
44
|
+
|
|
45
|
+
IN = "IN"
|
|
46
|
+
OUT = "OUT"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(frozen=True)
|
|
50
|
+
class Anchor:
|
|
51
|
+
"""A connection point on a block (``TAnchor``).
|
|
52
|
+
|
|
53
|
+
``index`` orders multiple anchors of the same ``type`` on a block (the
|
|
54
|
+
library auto-positions IN anchors on the left, OUT anchors on the right).
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
id: str
|
|
58
|
+
block_id: BlockId
|
|
59
|
+
type: Union[EAnchorType, str] = EAnchorType.OUT
|
|
60
|
+
index: int = 0
|
|
61
|
+
|
|
62
|
+
def __post_init__(self) -> None:
|
|
63
|
+
if not self.id:
|
|
64
|
+
raise ValueError("Anchor.id must be a non-empty string")
|
|
65
|
+
if self.index < 0:
|
|
66
|
+
raise ValueError(f"Anchor.index must be >= 0, got {self.index}")
|
|
67
|
+
|
|
68
|
+
def to_dict(self) -> dict[str, Any]:
|
|
69
|
+
anchor_type = (
|
|
70
|
+
self.type.value if isinstance(self.type, EAnchorType) else self.type
|
|
71
|
+
)
|
|
72
|
+
return {
|
|
73
|
+
"id": self.id,
|
|
74
|
+
"blockId": self.block_id,
|
|
75
|
+
"type": anchor_type,
|
|
76
|
+
"index": self.index,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass(frozen=True)
|
|
81
|
+
class Block:
|
|
82
|
+
"""A graph node (``TBlock``).
|
|
83
|
+
|
|
84
|
+
The library requires ``id``, ``is``, ``x``, ``y``, ``width``, ``height`` and
|
|
85
|
+
``name``; everything else is optional. ``is_`` maps to the upstream ``is``
|
|
86
|
+
discriminator (``is`` is a Python keyword, hence the trailing underscore).
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
id: BlockId
|
|
90
|
+
x: int = 0
|
|
91
|
+
y: int = 0
|
|
92
|
+
name: str = ""
|
|
93
|
+
is_: str = DEFAULT_BLOCK_IS
|
|
94
|
+
width: int = DEFAULT_BLOCK_WIDTH
|
|
95
|
+
height: int = DEFAULT_BLOCK_HEIGHT
|
|
96
|
+
selected: bool = False
|
|
97
|
+
group: str | None = None
|
|
98
|
+
anchors: list[Anchor] = field(default_factory=list)
|
|
99
|
+
meta: dict[str, Any] | None = None
|
|
100
|
+
|
|
101
|
+
def __post_init__(self) -> None:
|
|
102
|
+
if self.id is None or self.id == "":
|
|
103
|
+
raise ValueError("Block.id must be a non-empty id")
|
|
104
|
+
if self.width <= 0 or self.height <= 0:
|
|
105
|
+
raise ValueError(
|
|
106
|
+
f"Block {self.id!r} must have positive width/height, "
|
|
107
|
+
f"got {self.width}x{self.height}"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def to_dict(self) -> dict[str, Any]:
|
|
111
|
+
data: dict[str, Any] = {
|
|
112
|
+
"id": self.id,
|
|
113
|
+
"is": self.is_,
|
|
114
|
+
"x": self.x,
|
|
115
|
+
"y": self.y,
|
|
116
|
+
"width": self.width,
|
|
117
|
+
"height": self.height,
|
|
118
|
+
"name": self.name or str(self.id),
|
|
119
|
+
"selected": self.selected,
|
|
120
|
+
"anchors": [a.to_dict() for a in self.anchors],
|
|
121
|
+
}
|
|
122
|
+
if self.group is not None:
|
|
123
|
+
data["group"] = self.group
|
|
124
|
+
if self.meta is not None:
|
|
125
|
+
data["meta"] = self.meta
|
|
126
|
+
return data
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@dataclass(frozen=True)
|
|
130
|
+
class Connection:
|
|
131
|
+
"""A graph edge (``TConnection``).
|
|
132
|
+
|
|
133
|
+
Connect blocks directly (``source_block_id`` -> ``target_block_id``) or via
|
|
134
|
+
named anchors (``source_anchor_id`` / ``target_anchor_id``). Optional
|
|
135
|
+
``label``, ``dashed`` and ``styles`` (e.g. ``{"selectedBackground": ...,
|
|
136
|
+
"dashes": [6, 4]}``) customize the rendered edge.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
source_block_id: BlockId
|
|
140
|
+
target_block_id: BlockId
|
|
141
|
+
source_anchor_id: str | None = None
|
|
142
|
+
target_anchor_id: str | None = None
|
|
143
|
+
id: Union[str, int, None] = None
|
|
144
|
+
label: str | None = None
|
|
145
|
+
dashed: bool = False
|
|
146
|
+
selected: bool = False
|
|
147
|
+
styles: dict[str, Any] | None = None
|
|
148
|
+
|
|
149
|
+
def __post_init__(self) -> None:
|
|
150
|
+
if self.source_block_id is None or self.target_block_id is None:
|
|
151
|
+
raise ValueError(
|
|
152
|
+
"Connection requires both source_block_id and target_block_id"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def to_dict(self) -> dict[str, Any]:
|
|
156
|
+
data: dict[str, Any] = {
|
|
157
|
+
"sourceBlockId": self.source_block_id,
|
|
158
|
+
"targetBlockId": self.target_block_id,
|
|
159
|
+
}
|
|
160
|
+
if self.source_anchor_id is not None:
|
|
161
|
+
data["sourceAnchorId"] = self.source_anchor_id
|
|
162
|
+
if self.target_anchor_id is not None:
|
|
163
|
+
data["targetAnchorId"] = self.target_anchor_id
|
|
164
|
+
if self.id is not None:
|
|
165
|
+
data["id"] = self.id
|
|
166
|
+
if self.label is not None:
|
|
167
|
+
data["label"] = self.label
|
|
168
|
+
if self.dashed:
|
|
169
|
+
data["dashed"] = True
|
|
170
|
+
if self.selected:
|
|
171
|
+
data["selected"] = True
|
|
172
|
+
if self.styles is not None:
|
|
173
|
+
data["styles"] = self.styles
|
|
174
|
+
return data
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@dataclass(frozen=True)
|
|
178
|
+
class GraphData:
|
|
179
|
+
"""An aggregate of blocks + connections with validated referential integrity.
|
|
180
|
+
|
|
181
|
+
Use it to build a whole graph and emit the two props in one step::
|
|
182
|
+
|
|
183
|
+
data = GraphData(blocks=[...], connections=[...])
|
|
184
|
+
graph_canvas(blocks=data.blocks_payload(), connections=data.connections_payload())
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
blocks: list[Block] = field(default_factory=list)
|
|
188
|
+
connections: list[Connection] = field(default_factory=list)
|
|
189
|
+
|
|
190
|
+
def __post_init__(self) -> None:
|
|
191
|
+
ids = [b.id for b in self.blocks]
|
|
192
|
+
duplicates = {i for i in ids if ids.count(i) > 1}
|
|
193
|
+
if duplicates:
|
|
194
|
+
raise ValueError(f"Duplicate block ids: {sorted(map(str, duplicates))}")
|
|
195
|
+
known = set(ids)
|
|
196
|
+
for c in self.connections:
|
|
197
|
+
if c.source_block_id not in known:
|
|
198
|
+
raise ValueError(
|
|
199
|
+
f"Connection source {c.source_block_id!r} is not a known block"
|
|
200
|
+
)
|
|
201
|
+
if c.target_block_id not in known:
|
|
202
|
+
raise ValueError(
|
|
203
|
+
f"Connection target {c.target_block_id!r} is not a known block"
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
def blocks_payload(self) -> list[dict[str, Any]]:
|
|
207
|
+
return [b.to_dict() for b in self.blocks]
|
|
208
|
+
|
|
209
|
+
def connections_payload(self) -> list[dict[str, Any]]:
|
|
210
|
+
return [c.to_dict() for c in self.connections]
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""A Reflex wrapper around @gravity-ui/graph.
|
|
2
|
+
|
|
3
|
+
`@gravity-ui/graph` (https://github.com/gravity-ui/graph) is a high-performance
|
|
4
|
+
graph / flowchart / node-editor visualization library. It renders the whole
|
|
5
|
+
graph on Canvas when zoomed out (fast for thousands of nodes) and swaps to
|
|
6
|
+
HTML/React for rich interactions when zoomed in.
|
|
7
|
+
|
|
8
|
+
The upstream React API is hook + imperative driven (``useGraph`` creates a
|
|
9
|
+
``Graph`` instance, ``setEntities`` pushes nodes/edges, ``start`` runs the render
|
|
10
|
+
loop once attached). Reflex components cannot call React hooks directly, so this
|
|
11
|
+
package ships a small local JSX bridge (``graph_canvas.jsx``) that encapsulates
|
|
12
|
+
that lifecycle and exposes a flat, declarative prop surface. This module is the
|
|
13
|
+
Python side of that bridge.
|
|
14
|
+
|
|
15
|
+
Public API::
|
|
16
|
+
|
|
17
|
+
from reflex_gravityui_graph import graph_canvas
|
|
18
|
+
|
|
19
|
+
graph_canvas(
|
|
20
|
+
blocks=[{"id": "a", "is": "block-action", "x": 0, "y": 0,
|
|
21
|
+
"width": 120, "height": 120, "name": "A"}],
|
|
22
|
+
connections=[],
|
|
23
|
+
)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from typing import Any
|
|
29
|
+
|
|
30
|
+
import reflex as rx
|
|
31
|
+
from reflex.components.component import NoSSRComponent
|
|
32
|
+
|
|
33
|
+
# Pinned npm version for reproducible builds. Bump deliberately.
|
|
34
|
+
GRAVITY_GRAPH_VERSION = "@gravity-ui/graph@1.11.0"
|
|
35
|
+
|
|
36
|
+
# Copy the local JSX bridge into the compiled frontend's public dir, then import
|
|
37
|
+
# the bridge from there (same mechanism used for other JSX-bridge components).
|
|
38
|
+
_BRIDGE_PATH = rx.asset("./graph_canvas.jsx", shared=True)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _payload_event_spec(payload: rx.Var[dict]) -> tuple[rx.Var[dict]]:
|
|
42
|
+
"""Forward a single serializable payload dict to the event handler."""
|
|
43
|
+
return (payload,)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class GravityGraph(NoSSRComponent):
|
|
47
|
+
"""A @gravity-ui/graph canvas, driven declaratively from Reflex.
|
|
48
|
+
|
|
49
|
+
The component is client-only: the engine touches ``window``/Canvas, so it is
|
|
50
|
+
a ``NoSSRComponent`` (Reflex emits a dynamic, SSR-disabled import). See
|
|
51
|
+
``docs/sdd/02-architecture.md``.
|
|
52
|
+
|
|
53
|
+
Sizing: ``GraphCanvas`` fills its container, so give the component an
|
|
54
|
+
explicit height (e.g. ``height="600px"``) or pass ``style``.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
# Import the local JSX bridge from the frontend public dir.
|
|
58
|
+
library = f"$/public{_BRIDGE_PATH}"
|
|
59
|
+
|
|
60
|
+
# Named export from the bridge.
|
|
61
|
+
tag = "GravityGraph"
|
|
62
|
+
is_default = False
|
|
63
|
+
|
|
64
|
+
# Ensure the real npm package lands in package.json with a pinned version.
|
|
65
|
+
lib_dependencies: list[str] = [GRAVITY_GRAPH_VERSION]
|
|
66
|
+
|
|
67
|
+
# ------------------------------------------------------------------ #
|
|
68
|
+
# Data props (plain, JSON-serializable)
|
|
69
|
+
# ------------------------------------------------------------------ #
|
|
70
|
+
|
|
71
|
+
# Blocks (nodes). Each dict uses upstream camelCase keys:
|
|
72
|
+
# ``id``, ``is``, ``x``, ``y``, ``width``, ``height``, ``name`` and the
|
|
73
|
+
# optional ``anchors``, ``selected``, ``group``, ``meta``.
|
|
74
|
+
blocks: rx.Var[list[dict[str, Any]]]
|
|
75
|
+
|
|
76
|
+
# Connections (edges). Each dict: ``sourceBlockId`` / ``targetBlockId`` and
|
|
77
|
+
# optional ``sourceAnchorId`` / ``targetAnchorId`` / ``id`` / ``label`` /
|
|
78
|
+
# ``styles`` / ``dashed`` / ``selected``.
|
|
79
|
+
connections: rx.Var[list[dict[str, Any]]]
|
|
80
|
+
|
|
81
|
+
# Graph settings (``TGraphSettingsConfig``): ``canDragCamera``,
|
|
82
|
+
# ``canZoomCamera``, ``canCreateNewConnections``, ``useBezierConnections``,
|
|
83
|
+
# ``bezierConnectionDirection``, ``showConnectionArrows``,
|
|
84
|
+
# ``showConnectionLabels``, ``useBlocksAnchors``, ``scaleFontSize``, ...
|
|
85
|
+
settings: rx.Var[dict[str, Any]]
|
|
86
|
+
|
|
87
|
+
# View colors (``RecursivePartial<TGraphColors>``): ``canvas``, ``block``,
|
|
88
|
+
# ``anchor``, ``connection``, ``selection``, ...
|
|
89
|
+
colors: rx.Var[dict[str, Any]]
|
|
90
|
+
|
|
91
|
+
# View constants (``RecursivePartial<TGraphConstants>``): ``system``,
|
|
92
|
+
# ``camera``, ``block``, ``connection``, ``text``.
|
|
93
|
+
constants: rx.Var[dict[str, Any]]
|
|
94
|
+
|
|
95
|
+
# Configuration name passed to the underlying graph instance.
|
|
96
|
+
config_name: rx.Var[str] # -> configName
|
|
97
|
+
|
|
98
|
+
# ------------------------------------------------------------------ #
|
|
99
|
+
# Lifecycle / camera props
|
|
100
|
+
# ------------------------------------------------------------------ #
|
|
101
|
+
|
|
102
|
+
# Start the render loop automatically once the canvas is attached.
|
|
103
|
+
auto_start: rx.Var[bool] # -> autoStart
|
|
104
|
+
|
|
105
|
+
# Fit the camera to the graph once attached.
|
|
106
|
+
zoom_on_start: rx.Var[bool] # -> zoomOnStart
|
|
107
|
+
|
|
108
|
+
# Zoom target: ``"center"``, a rect, or a list of block ids.
|
|
109
|
+
zoom_target: rx.Var[Any] # -> zoomTarget
|
|
110
|
+
|
|
111
|
+
# Padding (px) used when fitting the camera on start.
|
|
112
|
+
zoom_padding: rx.Var[int] # -> zoomPadding
|
|
113
|
+
|
|
114
|
+
# Render rich HTML/React block bodies at detailed zoom (default canvas-only).
|
|
115
|
+
render_html_blocks: rx.Var[bool] # -> renderHtmlBlocks
|
|
116
|
+
|
|
117
|
+
# ------------------------------------------------------------------ #
|
|
118
|
+
# Events (each forwards one serializable payload dict)
|
|
119
|
+
# ------------------------------------------------------------------ #
|
|
120
|
+
|
|
121
|
+
# ``{"added": [ids], "removed": [ids]}`` when the block selection changes.
|
|
122
|
+
on_block_selection_change: rx.EventHandler[_payload_event_spec]
|
|
123
|
+
|
|
124
|
+
# ``{"sourceBlockId", "targetBlockId", "sourceAnchorId", "targetAnchorId"}``
|
|
125
|
+
# when a new connection is drawn (requires ``canCreateNewConnections``).
|
|
126
|
+
on_connection_created: rx.EventHandler[_payload_event_spec]
|
|
127
|
+
|
|
128
|
+
# ``{"added": [ids], "removed": [ids]}`` when the connection selection changes.
|
|
129
|
+
on_connection_selection_change: rx.EventHandler[_payload_event_spec]
|
|
130
|
+
|
|
131
|
+
# ``{"x", "y", "scale"}`` whenever the camera pans/zooms.
|
|
132
|
+
on_camera_change: rx.EventHandler[_payload_event_spec]
|
|
133
|
+
|
|
134
|
+
# ``{"blockId", "x", "y"}`` when a block drag finishes.
|
|
135
|
+
on_block_drag_end: rx.EventHandler[_payload_event_spec]
|
|
136
|
+
|
|
137
|
+
# ``{"state"}`` on graph state transitions (e.g. ``"ATTACHED"``).
|
|
138
|
+
on_state_change: rx.EventHandler[_payload_event_spec]
|
|
139
|
+
|
|
140
|
+
# Reflex auto-converts snake_case prop names to camelCase, covering every
|
|
141
|
+
# prop above. Add entries only for names the heuristic would get wrong.
|
|
142
|
+
_rename_props: dict[str, str] = {}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Convenience factory: ``graph_canvas(blocks=[...], connections=[...])``.
|
|
146
|
+
graph_canvas = GravityGraph.create
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Stub file for custom_components/reflex_gravityui_graph/graph.py"""
|
|
2
|
+
|
|
3
|
+
# ------------------- DO NOT EDIT ----------------------
|
|
4
|
+
# This file was generated by `reflex/utils/pyi_generator.py`!
|
|
5
|
+
# ------------------------------------------------------
|
|
6
|
+
from collections.abc import Mapping, Sequence
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
from reflex_components_core.core.breakpoints import Breakpoints
|
|
9
|
+
from reflex_base.event import (
|
|
10
|
+
EventType,
|
|
11
|
+
PointerEventInfo,
|
|
12
|
+
)
|
|
13
|
+
from reflex_base.vars.base import Var
|
|
14
|
+
import reflex as rx
|
|
15
|
+
from reflex.components.component import NoSSRComponent
|
|
16
|
+
|
|
17
|
+
GRAVITY_GRAPH_VERSION = "@gravity-ui/graph@1.11.0"
|
|
18
|
+
_BRIDGE_PATH = rx.asset("./graph_canvas.jsx", shared=True)
|
|
19
|
+
|
|
20
|
+
class GravityGraph(NoSSRComponent):
|
|
21
|
+
@classmethod
|
|
22
|
+
def create(
|
|
23
|
+
cls,
|
|
24
|
+
*children,
|
|
25
|
+
blocks: Var[list[dict[str, Any]]] | list[dict[str, Any]] | None = None,
|
|
26
|
+
connections: Var[list[dict[str, Any]]] | list[dict[str, Any]] | None = None,
|
|
27
|
+
settings: Var[dict[str, Any]] | dict[str, Any] | None = None,
|
|
28
|
+
colors: Var[dict[str, Any]] | dict[str, Any] | None = None,
|
|
29
|
+
constants: Var[dict[str, Any]] | dict[str, Any] | None = None,
|
|
30
|
+
config_name: Var[str] | str | None = None,
|
|
31
|
+
auto_start: Var[bool] | bool | None = None,
|
|
32
|
+
zoom_on_start: Var[bool] | bool | None = None,
|
|
33
|
+
zoom_target: Any | Var[Any] | None = None,
|
|
34
|
+
zoom_padding: Var[int] | int | None = None,
|
|
35
|
+
render_html_blocks: Var[bool] | bool | None = None,
|
|
36
|
+
style: Sequence[Mapping[str, Any]]
|
|
37
|
+
| Mapping[str, Any]
|
|
38
|
+
| Var[Mapping[str, Any]]
|
|
39
|
+
| Breakpoints
|
|
40
|
+
| None = None,
|
|
41
|
+
key: Any | None = None,
|
|
42
|
+
id: Any | None = None,
|
|
43
|
+
ref: Var | None = None,
|
|
44
|
+
class_name: Any | None = None,
|
|
45
|
+
custom_attrs: dict[str, Any | Var] | None = None,
|
|
46
|
+
on_block_drag_end: Optional[EventType[()] | EventType[rx.Var[dict]]] = None,
|
|
47
|
+
on_block_selection_change: Optional[
|
|
48
|
+
EventType[()] | EventType[rx.Var[dict]]
|
|
49
|
+
] = None,
|
|
50
|
+
on_blur: Optional[EventType[()]] = None,
|
|
51
|
+
on_camera_change: Optional[EventType[()] | EventType[rx.Var[dict]]] = None,
|
|
52
|
+
on_click: Optional[EventType[()] | EventType[PointerEventInfo]] = None,
|
|
53
|
+
on_connection_created: Optional[EventType[()] | EventType[rx.Var[dict]]] = None,
|
|
54
|
+
on_connection_selection_change: Optional[
|
|
55
|
+
EventType[()] | EventType[rx.Var[dict]]
|
|
56
|
+
] = None,
|
|
57
|
+
on_context_menu: Optional[EventType[()] | EventType[PointerEventInfo]] = None,
|
|
58
|
+
on_double_click: Optional[EventType[()] | EventType[PointerEventInfo]] = None,
|
|
59
|
+
on_focus: Optional[EventType[()]] = None,
|
|
60
|
+
on_mount: Optional[EventType[()]] = None,
|
|
61
|
+
on_mouse_down: Optional[EventType[()]] = None,
|
|
62
|
+
on_mouse_enter: Optional[EventType[()]] = None,
|
|
63
|
+
on_mouse_leave: Optional[EventType[()]] = None,
|
|
64
|
+
on_mouse_move: Optional[EventType[()]] = None,
|
|
65
|
+
on_mouse_out: Optional[EventType[()]] = None,
|
|
66
|
+
on_mouse_over: Optional[EventType[()]] = None,
|
|
67
|
+
on_mouse_up: Optional[EventType[()]] = None,
|
|
68
|
+
on_scroll: Optional[EventType[()]] = None,
|
|
69
|
+
on_scroll_end: Optional[EventType[()]] = None,
|
|
70
|
+
on_state_change: Optional[EventType[()] | EventType[rx.Var[dict]]] = None,
|
|
71
|
+
on_unmount: Optional[EventType[()]] = None,
|
|
72
|
+
**props,
|
|
73
|
+
) -> "GravityGraph":
|
|
74
|
+
"""Create the component.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
*children: The children of the component.
|
|
78
|
+
blocks: Blocks (nodes). Each dict uses upstream camelCase keys: ``id``, ``is``, ``x``, ``y``, ``width``, ``height``, ``name`` and the optional ``anchors``, ``selected``, ``group``, ``meta``.
|
|
79
|
+
connections: Connections (edges). Each dict: ``sourceBlockId`` / ``targetBlockId`` and optional ``sourceAnchorId`` / ``targetAnchorId`` / ``id`` / ``label`` / ``styles`` / ``dashed`` / ``selected``.
|
|
80
|
+
settings: Graph settings (``TGraphSettingsConfig``): ``canDragCamera``, ``canZoomCamera``, ``canCreateNewConnections``, ``useBezierConnections``, ``bezierConnectionDirection``, ``showConnectionArrows``, ``showConnectionLabels``, ``useBlocksAnchors``, ``scaleFontSize``, ...
|
|
81
|
+
colors: View colors (``RecursivePartial<TGraphColors>``): ``canvas``, ``block``, ``anchor``, ``connection``, ``selection``, ...
|
|
82
|
+
constants: View constants (``RecursivePartial<TGraphConstants>``): ``system``, ``camera``, ``block``, ``connection``, ``text``.
|
|
83
|
+
config_name: Configuration name passed to the underlying graph instance.
|
|
84
|
+
auto_start: Start the render loop automatically once the canvas is attached.
|
|
85
|
+
zoom_on_start: Fit the camera to the graph once attached.
|
|
86
|
+
zoom_target: Zoom target: ``"center"``, a rect, or a list of block ids.
|
|
87
|
+
zoom_padding: Padding (px) used when fitting the camera on start.
|
|
88
|
+
render_html_blocks: Render rich HTML/React block bodies at detailed zoom (default canvas-only).
|
|
89
|
+
style: The style of the component.
|
|
90
|
+
key: A unique key for the component.
|
|
91
|
+
id: The id for the component.
|
|
92
|
+
ref: The Var to pass as the ref to the component.
|
|
93
|
+
class_name: The class name for the component.
|
|
94
|
+
custom_attrs: Attributes passed directly to the component.
|
|
95
|
+
on_focus: Fired when the element (or some element inside of it) receives focus. For example, it is called when the user clicks on a text input.
|
|
96
|
+
on_blur: Fired when focus has left the element (or left some element inside of it). For example, it is called when the user clicks outside of a focused text input.
|
|
97
|
+
on_click: Fired when the user clicks on an element. For example, it's called when the user clicks on a button.
|
|
98
|
+
on_context_menu: Fired when the user right-clicks on an element.
|
|
99
|
+
on_double_click: Fired when the user double-clicks on an element.
|
|
100
|
+
on_mouse_down: Fired when the user presses a mouse button on an element.
|
|
101
|
+
on_mouse_enter: Fired when the mouse pointer enters the element.
|
|
102
|
+
on_mouse_leave: Fired when the mouse pointer leaves the element.
|
|
103
|
+
on_mouse_move: Fired when the mouse pointer moves over the element.
|
|
104
|
+
on_mouse_out: Fired when the mouse pointer moves out of the element.
|
|
105
|
+
on_mouse_over: Fired when the mouse pointer moves onto the element.
|
|
106
|
+
on_mouse_up: Fired when the user releases a mouse button on an element.
|
|
107
|
+
on_scroll: Fired when the user scrolls the element.
|
|
108
|
+
on_scroll_end: Fired when scrolling ends on the element.
|
|
109
|
+
on_mount: Fired when the component is mounted to the page.
|
|
110
|
+
on_unmount: Fired when the component is removed from the page. Only called during navigation, not on page refresh.
|
|
111
|
+
on_block_selection_change: ``{"added": [ids], "removed": [ids]}`` when the block selection changes.
|
|
112
|
+
on_connection_created: ``{"sourceBlockId", "targetBlockId", "sourceAnchorId", "targetAnchorId"}`` when a new connection is drawn (requires ``canCreateNewConnections``).
|
|
113
|
+
on_connection_selection_change: ``{"added": [ids], "removed": [ids]}`` when the connection selection changes.
|
|
114
|
+
on_camera_change: ``{"x", "y", "scale"}`` whenever the camera pans/zooms.
|
|
115
|
+
on_block_drag_end: ``{"blockId", "x", "y"}`` when a block drag finishes.
|
|
116
|
+
on_state_change: ``{"state"}`` on graph state transitions (e.g. ``"ATTACHED"``).
|
|
117
|
+
**props: The props of the component.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
The component."""
|
|
121
|
+
...
|
|
122
|
+
|
|
123
|
+
graph_canvas = GravityGraph.create
|