dars-framework 1.0.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.
- dars/__init__.py +0 -0
- dars/all.py +52 -0
- dars/cli/__init__.py +0 -0
- dars/cli/hot_reload.py +33 -0
- dars/cli/main.py +637 -0
- dars/cli/preview.py +419 -0
- dars/cli/translations.py +389 -0
- dars/components/__init__.py +0 -0
- dars/components/advanced/__init__.py +8 -0
- dars/components/advanced/accordion.py +21 -0
- dars/components/advanced/card.py +28 -0
- dars/components/advanced/modal.py +40 -0
- dars/components/advanced/navbar.py +31 -0
- dars/components/advanced/table.py +24 -0
- dars/components/advanced/tabs.py +26 -0
- dars/components/basic/__init__.py +34 -0
- dars/components/basic/button.py +29 -0
- dars/components/basic/checkbox.py +34 -0
- dars/components/basic/container.py +23 -0
- dars/components/basic/datepicker.py +139 -0
- dars/components/basic/image.py +36 -0
- dars/components/basic/input.py +50 -0
- dars/components/basic/link.py +31 -0
- dars/components/basic/page.py +20 -0
- dars/components/basic/progressbar.py +17 -0
- dars/components/basic/radiobutton.py +34 -0
- dars/components/basic/select.py +81 -0
- dars/components/basic/slider.py +63 -0
- dars/components/basic/spinner.py +11 -0
- dars/components/basic/text.py +22 -0
- dars/components/basic/textarea.py +46 -0
- dars/components/basic/tooltip.py +18 -0
- dars/components/layout/__init__.py +0 -0
- dars/components/layout/anchor.py +13 -0
- dars/components/layout/flex.py +26 -0
- dars/components/layout/grid.py +45 -0
- dars/core/__init__.py +0 -0
- dars/core/app.py +630 -0
- dars/core/component.py +25 -0
- dars/core/events.py +101 -0
- dars/core/properties.py +127 -0
- dars/docs/__init__.py +0 -0
- dars/exporters/__init__.py +0 -0
- dars/exporters/base.py +69 -0
- dars/exporters/web/__init__.py +0 -0
- dars/exporters/web/html_css_js.py +1406 -0
- dars/scripts/__init__.py +0 -0
- dars/scripts/script.py +38 -0
- dars/templates/__init__.py +0 -0
- dars/templates/examples/advanced/all_components_demo.py +87 -0
- dars/templates/examples/advanced/dashboard.py +440 -0
- dars/templates/examples/advanced/modern_web_app.py +452 -0
- dars/templates/examples/basic/flex_layout_responsive.py +13 -0
- dars/templates/examples/basic/form_components.py +516 -0
- dars/templates/examples/basic/grid_layout_responsive.py +13 -0
- dars/templates/examples/basic/hello_world.py +104 -0
- dars/templates/examples/basic/layout_multipage_demo.py +23 -0
- dars/templates/examples/basic/multipage_example.py +70 -0
- dars/templates/examples/basic/pwa_custom_icons.py +31 -0
- dars/templates/examples/basic/simple_form.py +377 -0
- dars/templates/examples/demo/complete_app.py +720 -0
- dars/templates/html/__init__.py +0 -0
- dars_framework-1.0.0.dist-info/METADATA +146 -0
- dars_framework-1.0.0.dist-info/RECORD +68 -0
- dars_framework-1.0.0.dist-info/WHEEL +5 -0
- dars_framework-1.0.0.dist-info/entry_points.txt +2 -0
- dars_framework-1.0.0.dist-info/licenses/LICENSE +21 -0
- dars_framework-1.0.0.dist-info/top_level.txt +1 -0
dars/core/events.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from typing import Callable, Dict, Any, Optional
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
|
|
4
|
+
class EventHandler:
|
|
5
|
+
"""Manejador de eventos para componentes"""
|
|
6
|
+
|
|
7
|
+
def __init__(self, handler: Callable, event_type: str):
|
|
8
|
+
self.handler = handler
|
|
9
|
+
self.event_type = event_type
|
|
10
|
+
self.id = f"event_{id(self)}"
|
|
11
|
+
|
|
12
|
+
def __call__(self, *args, **kwargs):
|
|
13
|
+
return self.handler(*args, **kwargs)
|
|
14
|
+
|
|
15
|
+
class EventManager:
|
|
16
|
+
"""Gestor de eventos para la aplicación"""
|
|
17
|
+
|
|
18
|
+
def __init__(self):
|
|
19
|
+
self.handlers: Dict[str, EventHandler] = {}
|
|
20
|
+
self.component_events: Dict[str, Dict[str, EventHandler]] = {}
|
|
21
|
+
|
|
22
|
+
def register_event(self, component_id: str, event_type: str, handler: Callable) -> str:
|
|
23
|
+
"""Registra un evento para un componente"""
|
|
24
|
+
event_handler = EventHandler(handler, event_type)
|
|
25
|
+
|
|
26
|
+
if component_id not in self.component_events:
|
|
27
|
+
self.component_events[component_id] = {}
|
|
28
|
+
|
|
29
|
+
self.component_events[component_id][event_type] = event_handler
|
|
30
|
+
self.handlers[event_handler.id] = event_handler
|
|
31
|
+
|
|
32
|
+
return event_handler.id
|
|
33
|
+
|
|
34
|
+
def get_event_handler(self, handler_id: str) -> Optional[EventHandler]:
|
|
35
|
+
"""Obtiene un manejador de eventos por su ID"""
|
|
36
|
+
return self.handlers.get(handler_id)
|
|
37
|
+
|
|
38
|
+
def get_component_events(self, component_id: str) -> Dict[str, EventHandler]:
|
|
39
|
+
"""Obtiene todos los eventos de un componente"""
|
|
40
|
+
return self.component_events.get(component_id, {})
|
|
41
|
+
|
|
42
|
+
def remove_event(self, component_id: str, event_type: str):
|
|
43
|
+
"""Elimina un evento de un componente"""
|
|
44
|
+
if component_id in self.component_events:
|
|
45
|
+
if event_type in self.component_events[component_id]:
|
|
46
|
+
handler = self.component_events[component_id][event_type]
|
|
47
|
+
del self.handlers[handler.id]
|
|
48
|
+
del self.component_events[component_id][event_type]
|
|
49
|
+
|
|
50
|
+
class EventEmitter(ABC):
|
|
51
|
+
"""Clase base para componentes que pueden emitir eventos"""
|
|
52
|
+
|
|
53
|
+
def __init__(self):
|
|
54
|
+
self.event_manager = EventManager()
|
|
55
|
+
|
|
56
|
+
def on(self, event_type: str, handler: Callable) -> str:
|
|
57
|
+
"""Registra un manejador de eventos"""
|
|
58
|
+
component_id = getattr(self, 'id', str(id(self)))
|
|
59
|
+
return self.event_manager.register_event(component_id, event_type, handler)
|
|
60
|
+
|
|
61
|
+
def off(self, event_type: str):
|
|
62
|
+
"""Elimina un manejador de eventos"""
|
|
63
|
+
component_id = getattr(self, 'id', str(id(self)))
|
|
64
|
+
self.event_manager.remove_event(component_id, event_type)
|
|
65
|
+
|
|
66
|
+
@abstractmethod
|
|
67
|
+
def emit(self, event_type: str, *args, **kwargs):
|
|
68
|
+
"""Emite un evento"""
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
# Tipos de eventos estándar
|
|
72
|
+
class EventTypes:
|
|
73
|
+
# Eventos de mouse
|
|
74
|
+
CLICK = "click"
|
|
75
|
+
DOUBLE_CLICK = "dblclick"
|
|
76
|
+
MOUSE_DOWN = "mousedown"
|
|
77
|
+
MOUSE_UP = "mouseup"
|
|
78
|
+
MOUSE_ENTER = "mouseenter"
|
|
79
|
+
MOUSE_LEAVE = "mouseleave"
|
|
80
|
+
MOUSE_MOVE = "mousemove"
|
|
81
|
+
|
|
82
|
+
# Eventos de teclado
|
|
83
|
+
KEY_DOWN = "keydown"
|
|
84
|
+
KEY_UP = "keyup"
|
|
85
|
+
KEY_PRESS = "keypress"
|
|
86
|
+
|
|
87
|
+
# Eventos de formulario
|
|
88
|
+
CHANGE = "change"
|
|
89
|
+
INPUT = "input"
|
|
90
|
+
SUBMIT = "submit"
|
|
91
|
+
FOCUS = "focus"
|
|
92
|
+
BLUR = "blur"
|
|
93
|
+
|
|
94
|
+
# Eventos de carga
|
|
95
|
+
LOAD = "load"
|
|
96
|
+
ERROR = "error"
|
|
97
|
+
RESIZE = "resize"
|
|
98
|
+
|
|
99
|
+
# Eventos personalizados
|
|
100
|
+
CUSTOM = "custom"
|
|
101
|
+
|
dars/core/properties.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from typing import Union, Optional, Dict, Any, Callable
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
@dataclass
|
|
5
|
+
class StyleProps:
|
|
6
|
+
"""Propiedades de estilo para componentes UI"""
|
|
7
|
+
# Dimensiones
|
|
8
|
+
width: Optional[Union[str, int]] = None
|
|
9
|
+
height: Optional[Union[str, int]] = None
|
|
10
|
+
min_width: Optional[Union[str, int]] = None
|
|
11
|
+
min_height: Optional[Union[str, int]] = None
|
|
12
|
+
max_width: Optional[Union[str, int]] = None
|
|
13
|
+
max_height: Optional[Union[str, int]] = None
|
|
14
|
+
|
|
15
|
+
# Espaciado
|
|
16
|
+
margin: Optional[Union[str, int]] = None
|
|
17
|
+
margin_top: Optional[Union[str, int]] = None
|
|
18
|
+
margin_right: Optional[Union[str, int]] = None
|
|
19
|
+
margin_bottom: Optional[Union[str, int]] = None
|
|
20
|
+
margin_left: Optional[Union[str, int]] = None
|
|
21
|
+
padding: Optional[Union[str, int]] = None
|
|
22
|
+
padding_top: Optional[Union[str, int]] = None
|
|
23
|
+
padding_right: Optional[Union[str, int]] = None
|
|
24
|
+
padding_bottom: Optional[Union[str, int]] = None
|
|
25
|
+
padding_left: Optional[Union[str, int]] = None
|
|
26
|
+
|
|
27
|
+
# Colores
|
|
28
|
+
background_color: Optional[str] = None
|
|
29
|
+
color: Optional[str] = None
|
|
30
|
+
border_color: Optional[str] = None
|
|
31
|
+
|
|
32
|
+
# Tipografía
|
|
33
|
+
font_size: Optional[Union[str, int]] = None
|
|
34
|
+
font_family: Optional[str] = None
|
|
35
|
+
font_weight: Optional[Union[str, int]] = None
|
|
36
|
+
font_style: Optional[str] = None
|
|
37
|
+
text_align: Optional[str] = None
|
|
38
|
+
text_decoration: Optional[str] = None
|
|
39
|
+
line_height: Optional[Union[str, int]] = None
|
|
40
|
+
|
|
41
|
+
# Bordes
|
|
42
|
+
border: Optional[str] = None
|
|
43
|
+
border_width: Optional[Union[str, int]] = None
|
|
44
|
+
border_style: Optional[str] = None
|
|
45
|
+
border_radius: Optional[Union[str, int]] = None
|
|
46
|
+
|
|
47
|
+
# Layout
|
|
48
|
+
display: Optional[str] = None
|
|
49
|
+
position: Optional[str] = None
|
|
50
|
+
top: Optional[Union[str, int]] = None
|
|
51
|
+
right: Optional[Union[str, int]] = None
|
|
52
|
+
bottom: Optional[Union[str, int]] = None
|
|
53
|
+
left: Optional[Union[str, int]] = None
|
|
54
|
+
z_index: Optional[int] = None
|
|
55
|
+
|
|
56
|
+
# Flexbox
|
|
57
|
+
flex_direction: Optional[str] = None
|
|
58
|
+
flex_wrap: Optional[str] = None
|
|
59
|
+
justify_content: Optional[str] = None
|
|
60
|
+
align_items: Optional[str] = None
|
|
61
|
+
align_content: Optional[str] = None
|
|
62
|
+
flex: Optional[Union[str, int]] = None
|
|
63
|
+
flex_grow: Optional[int] = None
|
|
64
|
+
flex_shrink: Optional[int] = None
|
|
65
|
+
flex_basis: Optional[Union[str, int]] = None
|
|
66
|
+
|
|
67
|
+
# Grid
|
|
68
|
+
grid_template_columns: Optional[str] = None
|
|
69
|
+
grid_template_rows: Optional[str] = None
|
|
70
|
+
grid_gap: Optional[Union[str, int]] = None
|
|
71
|
+
grid_column: Optional[str] = None
|
|
72
|
+
grid_row: Optional[str] = None
|
|
73
|
+
|
|
74
|
+
# Efectos
|
|
75
|
+
opacity: Optional[float] = None
|
|
76
|
+
box_shadow: Optional[str] = None
|
|
77
|
+
transform: Optional[str] = None
|
|
78
|
+
transition: Optional[str] = None
|
|
79
|
+
|
|
80
|
+
# Overflow
|
|
81
|
+
overflow: Optional[str] = None
|
|
82
|
+
overflow_x: Optional[str] = None
|
|
83
|
+
overflow_y: Optional[str] = None
|
|
84
|
+
|
|
85
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
86
|
+
"""Convierte las propiedades a un diccionario, excluyendo valores None"""
|
|
87
|
+
result = {}
|
|
88
|
+
for key, value in self.__dict__.items():
|
|
89
|
+
if value is not None:
|
|
90
|
+
# Convertir snake_case a kebab-case para CSS
|
|
91
|
+
css_key = key.replace('_', '-')
|
|
92
|
+
result[css_key] = value
|
|
93
|
+
return result
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class EventProps:
|
|
97
|
+
"""Propiedades de eventos para componentes UI"""
|
|
98
|
+
on_click: Optional[Callable] = None
|
|
99
|
+
on_double_click: Optional[Callable] = None
|
|
100
|
+
on_mouse_enter: Optional[Callable] = None
|
|
101
|
+
on_mouse_leave: Optional[Callable] = None
|
|
102
|
+
on_mouse_down: Optional[Callable] = None
|
|
103
|
+
on_mouse_up: Optional[Callable] = None
|
|
104
|
+
on_key_down: Optional[Callable] = None
|
|
105
|
+
on_key_up: Optional[Callable] = None
|
|
106
|
+
on_focus: Optional[Callable] = None
|
|
107
|
+
on_blur: Optional[Callable] = None
|
|
108
|
+
on_change: Optional[Callable] = None
|
|
109
|
+
on_input: Optional[Callable] = None
|
|
110
|
+
on_submit: Optional[Callable] = None
|
|
111
|
+
on_load: Optional[Callable] = None
|
|
112
|
+
on_error: Optional[Callable] = None
|
|
113
|
+
|
|
114
|
+
def normalize_style_value(value: Union[str, int]) -> str:
|
|
115
|
+
"""Normaliza un valor de estilo a string CSS"""
|
|
116
|
+
if isinstance(value, int):
|
|
117
|
+
return f"{value}px"
|
|
118
|
+
return str(value)
|
|
119
|
+
|
|
120
|
+
def merge_styles(*styles: Dict[str, Any]) -> Dict[str, Any]:
|
|
121
|
+
"""Combina múltiples diccionarios de estilos"""
|
|
122
|
+
result = {}
|
|
123
|
+
for style in styles:
|
|
124
|
+
if style:
|
|
125
|
+
result.update(style)
|
|
126
|
+
return result
|
|
127
|
+
|
dars/docs/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
dars/exporters/base.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Dict, Any
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
class Exporter(ABC):
|
|
6
|
+
"""Clase base para todos los exportadores"""
|
|
7
|
+
|
|
8
|
+
def __init__(self):
|
|
9
|
+
self.templates_path = os.path.join(os.path.dirname(__file__), "..", "templates")
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def export(self, app: 'App', output_path: str) -> bool:
|
|
13
|
+
"""Exporta la aplicación al formato específico"""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def render_component(self, component: 'Component') -> str:
|
|
18
|
+
"""Renderiza un componente individual"""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
def load_template(self, template_name: str) -> str:
|
|
22
|
+
"""Carga una plantilla desde el directorio de templates"""
|
|
23
|
+
template_path = os.path.join(self.templates_path, self.get_platform(), template_name)
|
|
24
|
+
try:
|
|
25
|
+
with open(template_path, 'r', encoding='utf-8') as f:
|
|
26
|
+
return f.read()
|
|
27
|
+
except FileNotFoundError:
|
|
28
|
+
raise FileNotFoundError(f"Plantilla no encontrada: {template_path}")
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def get_platform(self) -> str:
|
|
32
|
+
"""Retorna el nombre de la plataforma (html, react, etc.)"""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
def create_output_directory(self, output_path: str):
|
|
36
|
+
"""Crea el directorio de salida si no existe"""
|
|
37
|
+
os.makedirs(output_path, exist_ok=True)
|
|
38
|
+
|
|
39
|
+
def write_file(self, file_path: str, content: str):
|
|
40
|
+
"""Escribe contenido a un archivo"""
|
|
41
|
+
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
|
42
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
43
|
+
f.write(content)
|
|
44
|
+
|
|
45
|
+
def copy_file(self, source_path: str, dest_path: str):
|
|
46
|
+
"""Copia un archivo de origen a destino"""
|
|
47
|
+
import shutil
|
|
48
|
+
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
|
|
49
|
+
shutil.copy2(source_path, dest_path)
|
|
50
|
+
|
|
51
|
+
def render_styles(self, styles: Dict[str, Any]) -> str:
|
|
52
|
+
"""Convierte un diccionario de estilos a CSS"""
|
|
53
|
+
if not styles:
|
|
54
|
+
return ""
|
|
55
|
+
|
|
56
|
+
css_rules = []
|
|
57
|
+
for property_name, value in styles.items():
|
|
58
|
+
# Convertir snake_case a kebab-case
|
|
59
|
+
css_property = property_name.replace('_', '-')
|
|
60
|
+
css_rules.append(f"{css_property}: {value}")
|
|
61
|
+
|
|
62
|
+
return "; ".join(css_rules)
|
|
63
|
+
|
|
64
|
+
def generate_unique_id(self, component: 'Component') -> str:
|
|
65
|
+
"""Genera un ID único para un componente si no tiene uno"""
|
|
66
|
+
if component.id:
|
|
67
|
+
return component.id
|
|
68
|
+
return f"component_{id(component)}"
|
|
69
|
+
|
|
File without changes
|