refast-echarts 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.
@@ -0,0 +1,64 @@
1
+ """Refast extension for ECharts
2
+
3
+ Provides the ECharts component for Refast applications.
4
+ """
5
+
6
+ from pathlib import Path
7
+
8
+ from refast.extensions import Extension
9
+
10
+ from .components import ECharts, Echarts
11
+
12
+
13
+ class EchartsExtension(Extension):
14
+ """
15
+ ECharts extension for Refast.
16
+
17
+ Provides Apache ECharts integration with support for all chart types,
18
+ mouse events, theming, and dynamic updates via setOption.
19
+
20
+ Example:
21
+ ```python
22
+ from refast import RefastApp, Context
23
+ from refast_echarts import ECharts, EchartsExtension
24
+
25
+ ui = RefastApp(extensions=[EchartsExtension()])
26
+
27
+ @ui.page("/")
28
+ def home(ctx: Context):
29
+ return ECharts(
30
+ id="my-chart",
31
+ option={
32
+ "xAxis": {"data": ["A", "B", "C"]},
33
+ "yAxis": {},
34
+ "series": [{"type": "bar", "data": [10, 20, 30]}]
35
+ },
36
+ on_click=ctx.callback(handle_click),
37
+ theme="light",
38
+ height="400px",
39
+ )
40
+ ```
41
+
42
+ For auto-discovery, install the package and it will be automatically loaded.
43
+ """
44
+
45
+ name = "refast-echarts"
46
+ version = "0.1.0"
47
+ description = "Refast extension for Apache ECharts"
48
+
49
+ # Static assets to load (relative to static_path)
50
+ scripts = ["refast-echarts.js"]
51
+ styles = [] # ECharts doesn't require external CSS
52
+
53
+ @property
54
+ def static_path(self) -> Path:
55
+ """Path to the static assets directory."""
56
+ return Path(__file__).parent / "static"
57
+
58
+ @property
59
+ def components(self) -> list:
60
+ """List of Python component classes provided by this extension."""
61
+ return [ECharts]
62
+
63
+
64
+ __all__ = ["ECharts", "Echarts", "EchartsExtension"]
@@ -0,0 +1,185 @@
1
+ """Component definitions for Refast extension for ECharts."""
2
+
3
+ from typing import Any
4
+
5
+ from refast.components.base import Component
6
+ from refast.components.registry import register_component
7
+
8
+
9
+ @register_component(
10
+ name="ECharts",
11
+ package="refast-echarts",
12
+ module="components",
13
+ )
14
+ class ECharts(Component):
15
+ """
16
+ Apache ECharts component for Refast.
17
+
18
+ A powerful charting library that supports many chart types including
19
+ line, bar, pie, scatter, candlestick, map, and more.
20
+
21
+ Args:
22
+ option: ECharts option configuration object.
23
+ theme: Theme name ('light', 'dark') or custom theme object.
24
+ init_opts: Initialization options for ECharts instance.
25
+ auto_resize: Whether to auto-resize chart when container size changes (default True).
26
+ width: Chart width (e.g., "100%", "600px"). If None, uses container width.
27
+ height: Chart height (e.g., "400px"). If None, uses container height.
28
+ loading: Whether to show loading animation.
29
+ loading_opts: Loading animation options.
30
+
31
+ Event callbacks (all receive event data with chart interaction details):
32
+ on_click: Fired when clicking on a chart element.
33
+ on_dblclick: Fired when double-clicking on a chart element.
34
+ on_mousedown: Fired on mouse down.
35
+ on_mousemove: Fired on mouse move.
36
+ on_mouseup: Fired on mouse up.
37
+ on_mouseover: Fired when hovering over a chart element.
38
+ on_mouseout: Fired when mouse leaves a chart element.
39
+ on_globalout: Fired when mouse leaves the chart area entirely.
40
+ on_contextmenu: Fired on right-click context menu.
41
+
42
+ id: Component ID (required for bound_js calls like setOption).
43
+ class_name: CSS classes to apply to the container.
44
+ style: Inline styles for the container.
45
+
46
+ Bound Methods (callable via ctx.bound_js() or ctx.call_bound_js()):
47
+ setOption(option, notMerge=False, lazyUpdate=False): Update chart options.
48
+ resize(opts=None): Resize the chart.
49
+ clear(): Clear the chart.
50
+ showLoading(type='default', opts=None): Show loading animation.
51
+ hideLoading(): Hide loading animation.
52
+ getDataURL(opts=None): Get chart image as data URL.
53
+ dispose(): Dispose the chart instance.
54
+
55
+ Example:
56
+ ```python
57
+ from refast import RefastApp, Context
58
+ from refast_echarts import ECharts
59
+
60
+ ui = RefastApp()
61
+
62
+ async def handle_click(ctx: Context):
63
+ data = ctx.event.data
64
+ print(f"Clicked: {data.get('name')}: {data.get('value')}")
65
+
66
+ async def update_chart(ctx: Context):
67
+ new_option = {
68
+ "series": [{"data": [100, 200, 150, 80, 70]}]
69
+ }
70
+ await ctx.call_bound_js("my-chart", "setOption", new_option)
71
+
72
+ @ui.page("/")
73
+ def home(ctx: Context):
74
+ return ECharts(
75
+ id="my-chart",
76
+ option={
77
+ "title": {"text": "Sales Chart"},
78
+ "xAxis": {"data": ["Mon", "Tue", "Wed", "Thu", "Fri"]},
79
+ "yAxis": {},
80
+ "series": [{"type": "bar", "data": [120, 200, 150, 80, 70]}]
81
+ },
82
+ on_click=ctx.callback(handle_click),
83
+ theme="light",
84
+ height="400px",
85
+ )
86
+ ```
87
+ """
88
+
89
+ component_type = "ECharts"
90
+
91
+ def __init__(
92
+ self,
93
+ option: dict[str, Any] | None = None,
94
+ theme: str | dict[str, Any] | None = None,
95
+ init_opts: dict[str, Any] | None = None,
96
+ auto_resize: bool = True,
97
+ width: str | None = None,
98
+ height: str | None = None,
99
+ loading: bool = False,
100
+ loading_opts: dict[str, Any] | None = None,
101
+ # Mouse event callbacks
102
+ on_click: Any = None,
103
+ on_dblclick: Any = None,
104
+ on_mousedown: Any = None,
105
+ on_mousemove: Any = None,
106
+ on_mouseup: Any = None,
107
+ on_mouseover: Any = None,
108
+ on_mouseout: Any = None,
109
+ on_globalout: Any = None,
110
+ on_contextmenu: Any = None,
111
+ # Base props
112
+ id: str | None = None,
113
+ class_name: str = "",
114
+ style: dict[str, Any] | None = None,
115
+ **props: Any,
116
+ ):
117
+ super().__init__(id=id, class_name=class_name, **props)
118
+ self.option = option or {}
119
+ self.theme = theme
120
+ self.init_opts = init_opts
121
+ self.auto_resize = auto_resize
122
+ self.width = width
123
+ self.height = height
124
+ self.loading = loading
125
+ self.loading_opts = loading_opts
126
+ self.style = style or {}
127
+
128
+ # Event callbacks
129
+ self.on_click = on_click
130
+ self.on_dblclick = on_dblclick
131
+ self.on_mousedown = on_mousedown
132
+ self.on_mousemove = on_mousemove
133
+ self.on_mouseup = on_mouseup
134
+ self.on_mouseover = on_mouseover
135
+ self.on_mouseout = on_mouseout
136
+ self.on_globalout = on_globalout
137
+ self.on_contextmenu = on_contextmenu
138
+
139
+ def _serialize_callback(self, callback: Any) -> dict | None:
140
+ """Serialize a callback if present."""
141
+ if callback is None:
142
+ return None
143
+ if hasattr(callback, 'serialize'):
144
+ return callback.serialize()
145
+ return callback
146
+
147
+ def render(self) -> dict[str, Any]:
148
+ style = {
149
+ **self.style,
150
+ **({"width": self.width} if self.width else {}),
151
+ **({"height": self.height} if self.height else {}),
152
+ }
153
+ # Exclude "style" from extra_props serialization since we build it above
154
+ extra = {k: v for k, v in self._serialize_extra_props().items() if k != "style"}
155
+
156
+ return {
157
+ "type": self.component_type,
158
+ "id": self.id,
159
+ "props": {
160
+ "option": self.option,
161
+ "theme": self.theme,
162
+ "init_opts": self.init_opts,
163
+ "auto_resize": self.auto_resize,
164
+ "loading": self.loading,
165
+ "loading_opts": self.loading_opts,
166
+ "style": style or None,
167
+ "class_name": self.class_name,
168
+ # Event callbacks
169
+ "on_click": self._serialize_callback(self.on_click),
170
+ "on_dblclick": self._serialize_callback(self.on_dblclick),
171
+ "on_mousedown": self._serialize_callback(self.on_mousedown),
172
+ "on_mousemove": self._serialize_callback(self.on_mousemove),
173
+ "on_mouseup": self._serialize_callback(self.on_mouseup),
174
+ "on_mouseover": self._serialize_callback(self.on_mouseover),
175
+ "on_mouseout": self._serialize_callback(self.on_mouseout),
176
+ "on_globalout": self._serialize_callback(self.on_globalout),
177
+ "on_contextmenu": self._serialize_callback(self.on_contextmenu),
178
+ **extra,
179
+ },
180
+ "children": self._render_children(),
181
+ }
182
+
183
+
184
+ # Alias for backward compatibility
185
+ Echarts = ECharts
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.4
2
+ Name: refast-echarts
3
+ Version: 0.1.0
4
+ Summary: Refast extension for ECharts
5
+ Project-URL: Homepage, https://github.com/idling-mind/refast-echarts
6
+ Project-URL: Bug Tracker, https://github.com/idling-mind/refast-echarts/issues
7
+ Project-URL: Documentation, https://github.com/idling-mind/refast-echarts#readme
8
+ Author-email: Najeem Muhammed <najeem@gmail.com>
9
+ License-File: LICENSE
10
+ Classifier: Framework :: FastAPI
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: refast>=0.0.8
21
+ Description-Content-Type: text/markdown
22
+
23
+ # refast-echarts
24
+
25
+ Refast extension for ECharts
26
+
27
+ A [Refast](https://github.com/idling-mind/refast) extension that provides the `Echarts` component.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install refast-echarts
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ### Option 1: Auto-Discovery (Recommended)
38
+
39
+ When you install the package, Refast will automatically discover and load the extension:
40
+
41
+ ```python
42
+ from fastapi import FastAPI
43
+ from refast import RefastApp, Context
44
+ from refast.components import Container
45
+ from refast_echarts import ECharts
46
+
47
+ ui = RefastApp(title="ECharts Demo")
48
+
49
+
50
+ @ui.page("/")
51
+ def home(ctx: Context):
52
+ option = {
53
+ "title": {"text": "Monthly Sales"},
54
+ "tooltip": {},
55
+ "xAxis": {
56
+ "data": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
57
+ },
58
+ "yAxis": {},
59
+ "series": [
60
+ {
61
+ "name": "Sales",
62
+ "type": "bar",
63
+ "data": [120, 200, 150, 80, 70, 110],
64
+ }
65
+ ],
66
+ }
67
+ return Container(
68
+ children=[
69
+ ECharts(option=option, height="400px"),
70
+ ]
71
+ )
72
+
73
+
74
+ app = FastAPI()
75
+ app.include_router(ui.router)
76
+
77
+ if __name__ == "__main__":
78
+ import uvicorn
79
+ uvicorn.run(app, host="0.0.0.0", port=8000)
80
+ ```
81
+
82
+ ### Option 2: Manual Registration
83
+
84
+ If you want to disable auto-discovery and register extensions manually:
85
+
86
+ ```python
87
+ from refast import RefastApp
88
+ from refast_echarts import Echarts, EchartsExtension
89
+
90
+ ui = RefastApp(
91
+ title="Echarts Demo",
92
+ auto_discover_extensions=False,
93
+ extensions=[EchartsExtension()],
94
+ )
95
+ ```
96
+
97
+ ## Component Props
98
+
99
+ | Prop | Type | Default | Description |
100
+ |------|------|---------|-------------|
101
+ | `option` | dict | `{}` | ECharts option configuration object |
102
+ | `theme` | str \| dict | `None` | Theme name (`"light"`, `"dark"`) or custom theme object |
103
+ | `height` | str | `None` | Chart height (e.g. `"400px"`) |
104
+ | `width` | str | `None` | Chart width (e.g. `"100%"`) |
105
+ | `auto_resize` | bool | `True` | Auto-resize chart when container size changes |
106
+ | `loading` | bool | `False` | Show loading animation |
107
+ | `on_click` | Callback | `None` | Fired when clicking on a chart element |
108
+ | `on_mouseover` | Callback | `None` | Fired when hovering over a chart element |
109
+ | `id` | str | `None` | Component ID (required for `setOption` calls) |
110
+ | `class_name` | str | `""` | CSS classes to apply to the container |
111
+
112
+ ## Development
113
+
114
+ ### Prerequisites
115
+
116
+ - Python 3.10+
117
+ - Node.js 18+
118
+ - npm
119
+
120
+ ### Building the Frontend
121
+
122
+ ```bash
123
+ cd frontend
124
+ npm install
125
+ npm run build
126
+ ```
127
+
128
+ This builds the UMD bundle to `src/refast_echarts/static/`.
129
+
130
+ ### Installing Locally
131
+
132
+ ```bash
133
+ # Install with automatic frontend build (via hatch hook)
134
+ pip install -e .
135
+
136
+ # Or build frontend first, then install
137
+ cd frontend && npm install && npm run build && cd ..
138
+ pip install -e .
139
+ ```
140
+
141
+ ### Running the Example
142
+
143
+ ```bash
144
+ python usage.py
145
+ ```
146
+
147
+ Then open http://localhost:8000 in your browser.
148
+
149
+
150
+ ## License
151
+
152
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,7 @@
1
+ refast_echarts/__init__.py,sha256=CzstttVzp7cg9Y2J39AnH6-FEPrSjL4Dt7P43egXp0k,1770
2
+ refast_echarts/components.py,sha256=d2tIc264ywRThMGjTEuEtFGBshF05PgaEb2tpD0VkZo,7046
3
+ refast_echarts-0.1.0.dist-info/METADATA,sha256=7Qmagyfm6DpGg53NIm78NhPflwnNT0SVQHnpyRI5wDU,3922
4
+ refast_echarts-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
5
+ refast_echarts-0.1.0.dist-info/entry_points.txt,sha256=kXhYVVapeEYp73-0A3YXsqfum9FdAtWoUxD6Xh9vdVM,62
6
+ refast_echarts-0.1.0.dist-info/licenses/LICENSE,sha256=OY3qQlPXNv7ddTdyi2Qd_8rtMniF9sAMRjiaPtnbVJ8,1073
7
+ refast_echarts-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [refast.extensions]
2
+ echarts = refast_echarts:EchartsExtension
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Najeem Muhammed
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+