dars-framework 1.0.1__tar.gz → 1.0.4__tar.gz
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.
- {dars_framework-1.0.1/dars_framework.egg-info → dars_framework-1.0.4}/PKG-INFO +7 -3
- {dars_framework-1.0.1 → dars_framework-1.0.4}/README.md +117 -113
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/all.py +1 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/cli/main.py +5 -5
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/container.py +10 -5
- dars_framework-1.0.4/dars/core/component.py +140 -0
- dars_framework-1.0.4/dars/exporters/web/html_css_js.py +1405 -0
- dars_framework-1.0.1/dars/exporters/web/html_css_js.py → dars_framework-1.0.4/dars/exporters/web/html_css_js_old2.py +1 -1
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/basic/pwa_custom_icons.py +2 -4
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/basic/simple_form.py +2 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4/dars_framework.egg-info}/PKG-INFO +7 -3
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars_framework.egg-info/SOURCES.txt +1 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/pyproject.toml +1 -1
- dars_framework-1.0.1/dars/core/component.py +0 -25
- {dars_framework-1.0.1 → dars_framework-1.0.4}/LICENSE +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/cli/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/cli/hot_reload.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/cli/preview.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/cli/translations.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/advanced/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/advanced/accordion.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/advanced/card.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/advanced/modal.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/advanced/navbar.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/advanced/table.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/advanced/tabs.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/button.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/checkbox.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/datepicker.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/image.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/input.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/link.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/page.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/progressbar.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/radiobutton.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/select.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/slider.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/spinner.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/text.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/textarea.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/basic/tooltip.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/layout/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/layout/anchor.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/layout/flex.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/components/layout/grid.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/core/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/core/app.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/core/events.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/core/properties.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/docs/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/exporters/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/exporters/base.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/exporters/web/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/exporters/web/html_css_js_old.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/scripts/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/scripts/script.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/advanced/all_components_demo.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/advanced/dashboard.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/advanced/modern_web_app.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/basic/flex_layout_responsive.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/basic/form_components.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/basic/grid_layout_responsive.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/basic/hello_world.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/basic/layout_multipage_demo.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/basic/multipage_example.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/examples/demo/complete_app.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars/templates/html/__init__.py +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars_framework.egg-info/dependency_links.txt +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars_framework.egg-info/entry_points.txt +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars_framework.egg-info/requires.txt +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/dars_framework.egg-info/top_level.txt +0 -0
- {dars_framework-1.0.1 → dars_framework-1.0.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dars-framework
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Dars Framework build applications with Python and export to web
|
|
5
5
|
Author-email: ztamdev <zondax2009@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -33,7 +33,11 @@ Dynamic: license-file
|
|
|
33
33
|
|
|
34
34
|
# Dars Framework
|
|
35
35
|
|
|
36
|
-
Dars is a Python UI framework for building modern, interactive web apps with only Python code. Write your interface in Python, export it to static HTML/CSS/JS, and deploy anywhere
|
|
36
|
+
Dars is a Python UI framework for building modern, interactive web apps with only Python code. Write your interface in Python, export it to static HTML/CSS/JS, and deploy anywhere some Javascript or frontend stack required.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install dars-framework
|
|
40
|
+
```
|
|
37
41
|
|
|
38
42
|
## How It Works
|
|
39
43
|
- Build your UI using Python classes and components (like Text, Button, Container, Page, etc).
|
|
@@ -105,7 +109,7 @@ if __name__ == "__main__":
|
|
|
105
109
|
## More
|
|
106
110
|
- [Project Roadmap](ROADMAP.md)
|
|
107
111
|
- [Getting Started](dars/docs/getting_started.md)
|
|
108
|
-
- [Components
|
|
112
|
+
- [Components Documentation](dars/docs/components.md)
|
|
109
113
|
- [Exporters](dars/docs/exporters.md)
|
|
110
114
|
- [Scripts System](dars/docs/scripts.md)
|
|
111
115
|
- [CLI usage and commands](dars/docs/cli.md)
|
|
@@ -1,113 +1,117 @@
|
|
|
1
|
-
# Dars Framework
|
|
2
|
-
|
|
3
|
-
Dars is a Python UI framework for building modern, interactive web apps with only Python code. Write your interface in Python, export it to static HTML/CSS/JS, and deploy anywhere
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
from dars.
|
|
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
|
-
| `dars
|
|
70
|
-
| `dars
|
|
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
|
-
|
|
1
|
+
# Dars Framework
|
|
2
|
+
|
|
3
|
+
Dars is a Python UI framework for building modern, interactive web apps with only Python code. Write your interface in Python, export it to static HTML/CSS/JS, and deploy anywhere some Javascript or frontend stack required.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install dars-framework
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## How It Works
|
|
10
|
+
- Build your UI using Python classes and components (like Text, Button, Container, Page, etc).
|
|
11
|
+
- Preview instantly with hot-reload using `app.rTimeCompile()`.
|
|
12
|
+
- Export your app to static web files with a single CLI command.
|
|
13
|
+
- Use multipage, layouts, scripts, and more—see docs for advanced features.
|
|
14
|
+
|
|
15
|
+
## Quick Example: Your First App
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
#!/usr/bin/env python3
|
|
19
|
+
from dars.core.app import App
|
|
20
|
+
from dars.components.basic.text import Text
|
|
21
|
+
from dars.components.basic.button import Button
|
|
22
|
+
from dars.components.basic.container import Container
|
|
23
|
+
from dars.scripts.script import InlineScript
|
|
24
|
+
|
|
25
|
+
# Crear aplicación
|
|
26
|
+
app = App(title="Mi Primera App")
|
|
27
|
+
|
|
28
|
+
# Crear componentes
|
|
29
|
+
container = Container(style={
|
|
30
|
+
'display': 'flex',
|
|
31
|
+
'flex-direction': 'column',
|
|
32
|
+
'align-items': 'center',
|
|
33
|
+
'padding': '40px'
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
titulo = Text(
|
|
37
|
+
text="Hola Dars",
|
|
38
|
+
style={'font-size': '32px', 'color': '#333'}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
boton = Button(
|
|
42
|
+
text="Hacer clic",
|
|
43
|
+
style={'background-color': '#007bff', 'color': 'white'}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Script para interactividad
|
|
47
|
+
script = InlineScript("""
|
|
48
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
49
|
+
const boton = document.querySelector('button');
|
|
50
|
+
boton.addEventListener('click', function() {
|
|
51
|
+
alert('Hola desde Dars.');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
""")
|
|
55
|
+
|
|
56
|
+
# Ensamblar aplicación
|
|
57
|
+
container.add_child(titulo)
|
|
58
|
+
container.add_child(boton)
|
|
59
|
+
app.set_root(container)
|
|
60
|
+
app.add_script(script)
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
app.rTimeCompile() # Live preview at http://localhost:8000
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## CLI Usage
|
|
67
|
+
| Command | What it does |
|
|
68
|
+
|-----------------------------------------|--------------------------------------------|
|
|
69
|
+
| `dars export my_app.py --format html` | Export app to HTML/CSS/JS in `./my_app_web` |
|
|
70
|
+
| `dars preview ./my_app_web` | Preview exported app locally |
|
|
71
|
+
| `dars init my_project` | Create a new Dars project |
|
|
72
|
+
| `dars info my_app.py` | Show info about your app |
|
|
73
|
+
| `dars formats` | List supported export formats |
|
|
74
|
+
| `dars --help` | Show help and all CLI options |
|
|
75
|
+
|
|
76
|
+
## More
|
|
77
|
+
- [Project Roadmap](ROADMAP.md)
|
|
78
|
+
- [Getting Started](dars/docs/getting_started.md)
|
|
79
|
+
- [Components Documentation](dars/docs/components.md)
|
|
80
|
+
- [Exporters](dars/docs/exporters.md)
|
|
81
|
+
- [Scripts System](dars/docs/scripts.md)
|
|
82
|
+
- [CLI usage and commands](dars/docs/cli.md)
|
|
83
|
+
- [Project Structure](STRUCTURE.md)
|
|
84
|
+
- [Architecture](DARS_ARCHITECTURE.md)
|
|
85
|
+
- [Installation Guide](INSTALL.md)
|
|
86
|
+
|
|
87
|
+
## Local Execution and Live Preview
|
|
88
|
+
|
|
89
|
+
To test your app locally before exporting, use the hot-reload preview from any Python file that defines your app:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
app.rTimeCompile()
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Then run your file directly:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
python my_app.py
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
This will start a local server at http://localhost:8000 so you can view your app in the browser—no manual export needed. You can change the port with:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
python my_app.py --port 8088
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
You can also use the CLI preview command on an exported app:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
dars preview ./my_exported_app
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
This will start a local server at http://localhost:8000 to view your exported app in the browser.
|
|
117
|
+
|
|
@@ -215,6 +215,11 @@ class DarsExporter:
|
|
|
215
215
|
console.print(f"[red]{translator.get('error_file_not_exists')} {file_path}[/red]")
|
|
216
216
|
return None
|
|
217
217
|
|
|
218
|
+
# Add the application's root directory to sys.path
|
|
219
|
+
file_dir = os.path.dirname(os.path.abspath(file_path))
|
|
220
|
+
if file_dir not in sys.path:
|
|
221
|
+
sys.path.insert(0, file_dir)
|
|
222
|
+
|
|
218
223
|
# Load the module dynamically
|
|
219
224
|
spec = importlib.util.spec_from_file_location("user_app", file_path)
|
|
220
225
|
if spec is None or spec.loader is None:
|
|
@@ -222,11 +227,6 @@ class DarsExporter:
|
|
|
222
227
|
return None
|
|
223
228
|
|
|
224
229
|
module = importlib.util.module_from_spec(spec)
|
|
225
|
-
|
|
226
|
-
# Add the file directory to the path for relative imports
|
|
227
|
-
file_dir = os.path.dirname(os.path.abspath(file_path))
|
|
228
|
-
|
|
229
|
-
|
|
230
230
|
spec.loader.exec_module(module)
|
|
231
231
|
|
|
232
232
|
# Look for the 'app' variable in the module
|
|
@@ -4,17 +4,22 @@ from typing import Optional, Union, Dict, Any, List
|
|
|
4
4
|
|
|
5
5
|
class Container(Component):
|
|
6
6
|
def __init__(
|
|
7
|
-
self,
|
|
7
|
+
self,
|
|
8
|
+
*children: Component,
|
|
8
9
|
id: Optional[str] = None,
|
|
9
10
|
class_name: Optional[str] = None,
|
|
10
11
|
style: Optional[Dict[str, Any]] = None,
|
|
11
|
-
|
|
12
|
+
additional_children: Optional[List[Component]] = None
|
|
12
13
|
):
|
|
13
14
|
super().__init__(id=id, class_name=class_name, style=style)
|
|
14
15
|
|
|
15
|
-
# Agregar hijos
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
# Agregar hijos pasados como argumentos posicionales
|
|
17
|
+
for child in children:
|
|
18
|
+
self.add_child(child)
|
|
19
|
+
|
|
20
|
+
# Agregar hijos adicionales si se proporcionan
|
|
21
|
+
if additional_children:
|
|
22
|
+
for child in additional_children:
|
|
18
23
|
self.add_child(child)
|
|
19
24
|
|
|
20
25
|
def render(self, exporter: Any) -> str:
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from typing import Dict, Any, List, Optional, Callable, Union, Type
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
|
|
4
|
+
class ComponentQuery:
|
|
5
|
+
def __init__(self, components: List['Component']):
|
|
6
|
+
self.components = components
|
|
7
|
+
|
|
8
|
+
def find(self,
|
|
9
|
+
id: Optional[str] = None,
|
|
10
|
+
class_name: Optional[str] = None,
|
|
11
|
+
type: Optional[Union[Type['Component'], str]] = None,
|
|
12
|
+
predicate: Optional[Callable[['Component'], bool]] = None) -> 'ComponentQuery':
|
|
13
|
+
"""
|
|
14
|
+
Busca componentes dentro de los componentes actualmente seleccionados
|
|
15
|
+
"""
|
|
16
|
+
results: List['Component'] = []
|
|
17
|
+
|
|
18
|
+
def match_component(comp: Component) -> bool:
|
|
19
|
+
if id is not None and comp.id != id:
|
|
20
|
+
return False
|
|
21
|
+
if class_name is not None and comp.class_name != class_name:
|
|
22
|
+
return False
|
|
23
|
+
if type is not None:
|
|
24
|
+
if isinstance(type, str):
|
|
25
|
+
if comp.__class__.__name__ != type:
|
|
26
|
+
return False
|
|
27
|
+
elif not isinstance(comp, type):
|
|
28
|
+
return False
|
|
29
|
+
if predicate is not None and not predicate(comp):
|
|
30
|
+
return False
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
# Buscar en los hijos de todos los componentes actuales
|
|
34
|
+
for component in self.components:
|
|
35
|
+
for child in component.children:
|
|
36
|
+
if match_component(child):
|
|
37
|
+
results.append(child)
|
|
38
|
+
# Buscar recursivamente en los hijos del hijo
|
|
39
|
+
for descendant in ComponentQuery([child]).find().get():
|
|
40
|
+
if match_component(descendant):
|
|
41
|
+
results.append(descendant)
|
|
42
|
+
|
|
43
|
+
return ComponentQuery(results)
|
|
44
|
+
|
|
45
|
+
def attr(self, **attrs) -> 'ComponentQuery':
|
|
46
|
+
"""Modifica los atributos de todos los componentes encontrados"""
|
|
47
|
+
for component in self.components:
|
|
48
|
+
for key, value in attrs.items():
|
|
49
|
+
# Manejo especial para atributos comunes
|
|
50
|
+
if key == 'style':
|
|
51
|
+
component.style.update(value)
|
|
52
|
+
continue
|
|
53
|
+
elif key == 'class_name':
|
|
54
|
+
component.class_name = value
|
|
55
|
+
continue
|
|
56
|
+
elif key == 'events':
|
|
57
|
+
component.events.update(value)
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
# Intenta establecer el atributo directamente si existe
|
|
61
|
+
if hasattr(component, key):
|
|
62
|
+
setattr(component, key, value)
|
|
63
|
+
# Si no existe como atributo directo, guárdalo en props
|
|
64
|
+
else:
|
|
65
|
+
component.props[key] = value
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
def get(self) -> List['Component']:
|
|
69
|
+
"""Devuelve la lista de componentes encontrados"""
|
|
70
|
+
return self.components
|
|
71
|
+
|
|
72
|
+
def first(self) -> Optional['Component']:
|
|
73
|
+
"""Devuelve el primer componente encontrado o None si no hay ninguno"""
|
|
74
|
+
return self.components[0] if self.components else None
|
|
75
|
+
|
|
76
|
+
class Component(ABC):
|
|
77
|
+
def __init__(self, **props):
|
|
78
|
+
self.props = props
|
|
79
|
+
self.children: List[Component] = []
|
|
80
|
+
self.parent: Optional[Component] = None
|
|
81
|
+
self.id: Optional[str] = props.get('id')
|
|
82
|
+
self.class_name: Optional[str] = props.get('class_name')
|
|
83
|
+
self.style: Dict[str, Any] = props.get('style', {})
|
|
84
|
+
self.events: Dict[str, Callable] = {}
|
|
85
|
+
|
|
86
|
+
def add_child(self, child: 'Component'):
|
|
87
|
+
child.parent = self
|
|
88
|
+
self.children.append(child)
|
|
89
|
+
|
|
90
|
+
def set_event(self, event_name: str, handler: Callable):
|
|
91
|
+
self.events[event_name] = handler
|
|
92
|
+
|
|
93
|
+
def find(self,
|
|
94
|
+
id: Optional[str] = None,
|
|
95
|
+
class_name: Optional[str] = None,
|
|
96
|
+
type: Optional[Union[Type['Component'], str]] = None,
|
|
97
|
+
predicate: Optional[Callable[['Component'], bool]] = None) -> ComponentQuery:
|
|
98
|
+
"""
|
|
99
|
+
Busca componentes que coincidan con los criterios especificados.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
id: Buscar por ID del componente
|
|
103
|
+
class_name: Buscar por nombre de clase CSS
|
|
104
|
+
type: Buscar por tipo de componente (clase o nombre de clase)
|
|
105
|
+
predicate: Función personalizada de filtrado que toma un componente y devuelve bool
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
ComponentQuery que permite encadenar operaciones y modificar atributos
|
|
109
|
+
"""
|
|
110
|
+
results: List[Component] = []
|
|
111
|
+
|
|
112
|
+
def match_component(comp: Component) -> bool:
|
|
113
|
+
if id is not None and comp.id != id:
|
|
114
|
+
return False
|
|
115
|
+
if class_name is not None and comp.class_name != class_name:
|
|
116
|
+
return False
|
|
117
|
+
if type is not None:
|
|
118
|
+
if isinstance(type, str):
|
|
119
|
+
if comp.__class__.__name__ != type:
|
|
120
|
+
return False
|
|
121
|
+
elif not isinstance(comp, type):
|
|
122
|
+
return False
|
|
123
|
+
if predicate is not None and not predicate(comp):
|
|
124
|
+
return False
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
def search_recursive(component: Component):
|
|
128
|
+
if match_component(component):
|
|
129
|
+
results.append(component)
|
|
130
|
+
for child in component.children:
|
|
131
|
+
search_recursive(child)
|
|
132
|
+
|
|
133
|
+
search_recursive(self)
|
|
134
|
+
return ComponentQuery(results)
|
|
135
|
+
|
|
136
|
+
@abstractmethod
|
|
137
|
+
def render(self, exporter: 'Exporter') -> str:
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
|