Metadata-Version: 2.4
Name: janelkit
Version: 0.2.0.0
Summary: Componentes de archivo único (.janel) para aplicaciones de escritorio con Python y Qt Quick
Author-email: d4ndres <d4ndres@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/janelkit/janelkit
Project-URL: Documentation, https://github.com/janelkit/janelkit/tree/main/docs
Project-URL: Repository, https://github.com/janelkit/janelkit
Project-URL: Issues, https://github.com/janelkit/janelkit/issues
Project-URL: Changelog, https://github.com/janelkit/janelkit/blob/main/docs/cambios.md
Keywords: gui,desktop,qt,pyside6,qt-quick,reactive,components,framework
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Environment :: X11 Applications :: Qt
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Natural Language :: Spanish
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PySide6-Essentials!=6.12.0,>=6.8
Requires-Dist: qasync>=0.27
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: build>=1; extra == "dev"
Requires-Dist: pyflakes>=3; extra == "dev"
Dynamic: license-file

# JanelKit

[![PyPI](https://img.shields.io/pypi/v/janelkit)](https://pypi.org/project/janelkit/)
[![Python](https://img.shields.io/pypi/pyversions/janelkit)](https://pypi.org/project/janelkit/)
[![CI](https://github.com/janelkit/janelkit/actions/workflows/ci.yml/badge.svg)](https://github.com/janelkit/janelkit/actions/workflows/ci.yml)
[![Licencia: MIT](https://img.shields.io/badge/licencia-MIT-blue)](https://github.com/janelkit/janelkit/blob/main/LICENSE)

**Aplicaciones de escritorio con componentes de archivo único, escritas en Python.**

Cada componente `.janel` reúne en un archivo la lógica en Python, una plantilla declarativa y reactiva, y sus estilos en CSS. JanelKit lo compila a Qt Quick (PySide6): interfaces nativas y aceleradas por GPU en Windows, macOS y Linux, sin escribir JavaScript ni QML.

```bash
pip install janelkit
janel new mi-app
cd mi-app
python main.py
```

<p align="center">
  <img src="https://raw.githubusercontent.com/janelkit/janelkit/main/docs/img/tutorial.png" alt="La aplicación del tutorial: una lista de la compra con un campo, un botón Añadir y tres productos con casillas" width="360">
</p>

## Un componente

```html
<script lang="python">
from janelkit import state, computed

todos = state([{"id": 1, "title": "Probar JanelKit", "done": False}])
draft = state("")

@computed
def pending():
    return sum(not t["done"] for t in todos.value)

def add():
    todos.value.append({"id": len(todos.value) + 1, "title": draft.value, "done": False})
    draft.value = ""
</script>

<window title="Tareas" width={480} height={400}>
  <column class="page">
    <text class="title">{pending} pendientes</text>
    <row class="new">
      <textfield bind:value={draft} on:submit={add} placeholder="Nueva tarea" flex={1} />
      <button variant="primary" on:click={add}>Añadir</button>
    </row>
    {#each todos as todo (todo["id"])}
      <checkbox checked={todo["done"]} on:change={todo["done"] = event}>{todo["title"]}</checkbox>
    {:else}
      <text>No hay tareas.</text>
    {/each}
  </column>
</window>

<style>
.page { padding: 24px; gap: 12px; }
.title { font-size: var(--font-size-xl); font-weight: 600; }
.new { gap: 8px; }
</style>
```

Cuando cambia un `state`, solo se recalcula lo que lo leyó, y solo se actualiza en pantalla lo afectado. Las listas y diccionarios son reactivos también al modificarlos en el sitio (`append`, `todo["done"] = True`).

## Por qué JanelKit

- **Python de principio a fin.** La lógica, los manejadores y las expresiones de la plantilla son Python: tus módulos, tus bibliotecas y tus pruebas de siempre.
- **Rendimiento nativo.** Qt Quick dibuja; JanelKit solo avisa de lo que cambió. Una aplicación mediana arranca en menos de 300 ms y responde en menos de 70 ms. Una `<list>` virtualizada crea 10 000 filas en unos 40 ms.
- **Errores que ayudan.** Cada error indica archivo, línea y columna, con sugerencias («¿quisiste decir `on:click`?»), también los que vienen de Qt o de la ejecución.
- **Recarga al guardar.** `janel dev` recarga la vista y conserva el estado de los componentes cuyo script no cambió.
- **Probado a fondo.** Una suite extensa de pruebas que la CI ejecuta en Windows, Linux y macOS, y cinco aplicaciones grandes de validación (chat, panel en tiempo real, Kanban, hoja de cálculo y gestor de proyectos) construidas sin tocar el framework.
- **API pública explícita.** Qué es público está documentado y protegido por pruebas, con una [política de versiones](https://github.com/janelkit/janelkit/blob/main/docs/api.md#política-de-versiones) clara.

## Qué incluye

| Área | Contenido |
|---|---|
| **Reactividad** | `state`, `@computed` (también en métodos), `effect`, `batch`, colecciones reactivas. Los stores y `persisted` están en [`janelkit-store`](https://pypi.org/project/janelkit-store/) |
| **Plantilla** | `{expr}` con formato (`{cpu:.1f}`), `on:evento`, `bind:value`, `class:x={cond}`, `{#if}`, `{#each}` con claves, `{#key}`, `{#hidden}`, transiciones |
| **Componentes** | Importados como módulos Python, `prop()` con tipos, `event()`, slots, `on_mount`/`on_destroy`, `ref`, `provide`/`inject` |
| **Asincronía** | Manejadores `async def`, `@task` con estados de carga y error, `background()` para trabajo bloqueante, temporizadores; todo se cancela al desmontar |
| **Disposición y estilos** | Flexbox de CSS (`<flex>`, `column`, `row`), posición, pseudo-clases y selectores, tokens `var(--primary)`, temas claro y oscuro intercambiables en caliente |
| **Controles** | Texto (también Markdown), botones, campos, casillas, `select`, `switch`, `slider`, `radiogroup`, `tabs`, `image`, `progressbar`, `<list>` virtualizada, `<video>`, arrastrar y soltar |
| **Ventanas** | Varias ventanas, en otra pantalla y a pantalla completa, `before_leave` para cambios sin guardar. La navegación entre pantallas está en [`janelkit-router`](https://pypi.org/project/janelkit-router/) |
| **Accesibilidad** | Navegación con teclado, foco visible, nombres accesibles, derecha a izquierda |
| **Interoperabilidad** | Importa un `.qml` propio como si fuera un componente |
| **Pruebas** | `janelkit.inspect`: monta sin ventana, busca elementos, simula clics y teclas, lee el estado |

## Comandos

| Comando | Qué hace |
|---|---|
| `janel new <nombre>` | Crea un proyecto con `main.py` y `src/App.janel`. |
| `janel dev [carpeta]` | Ejecuta la aplicación y la recarga al guardar. |
| `janel build [carpeta]` | Valida todos los componentes y guarda el QML generado. |
| `janel compile <archivo>` | Muestra el QML generado de un componente. |
| `janel parse <archivo>` | Muestra el árbol sintáctico o los errores con línea y columna. |

## Probar una aplicación

```python
from janelkit import inspect

def test_add(tmp_path):
    with inspect.mount("src/App.janel") as app:
        app.find(placeholder="Nueva tarea").type("Pan")
        app.find(text="Añadir").click()
        assert app.find(text="1 pendientes")
```

## Ecosistema

| Paquete | Qué añade |
|---|---|
| [`janelkit-router`](https://pypi.org/project/janelkit-router/) | Navegación entre pantallas: pilas de páginas y secciones. |
| [`janelkit-store`](https://pypi.org/project/janelkit-store/) | Datos compartidos: stores con acciones, escritura controlada y seguimiento de cambios; `persisted`. |
| [`janelkit-i18n`](https://pypi.org/project/janelkit-i18n/) | Traducciones, plurales, formatos según el idioma y cambio de idioma en caliente. |
| [`janelkit-desktop`](https://pypi.org/project/janelkit-desktop/) | Diálogos nativos (archivos, carpeta, mensaje, confirmación) y portapapeles. |
| [Resaltado para VS Code](https://github.com/janelkit/janelkit/tree/main/packages/janelkit-vscode) | Sintaxis de `.janel`: Python, plantilla y CSS. |

## Requisitos

- Python 3.10 o posterior.
- PySide6-Essentials 6.8 o posterior, salvo la 6.12.0: los módulos básicos de Qt, sin los Addons (se instala solo).
- Windows, macOS o Linux.

## Estado

JanelKit está en **alfa** (serie 0.x). Lo público está [documentado](https://github.com/janelkit/janelkit/blob/main/docs/api.md). Cada serie (0.1, 0.2…) es un cambio de paradigma que puede romperlo; dentro de una serie (0.2.0.0, 0.2.1.0…), lo que se rompa o se retire sigue funcionando con un aviso cuando es viable. Todo cambio se anuncia en las [notas de la versión](https://github.com/janelkit/janelkit/blob/main/docs/cambios.md) con cómo migrar.

## Documentación

- [Tutorial](https://github.com/janelkit/janelkit/blob/main/docs/tutorial.md): una aplicación completa paso a paso. **Empieza aquí.**
- [El lenguaje `.janel`](https://github.com/janelkit/janelkit/blob/main/docs/lenguaje.md): expresiones, bloques, componentes y elementos.
- [Estilos y disposición](https://github.com/janelkit/janelkit/blob/main/docs/estilos.md): CSS soportado, flexbox, tokens y temas.
- [Desarrollo](https://github.com/janelkit/janelkit/blob/main/docs/desarrollo.md): `janel dev`, `janel build`, errores y editor.
- [API pública](https://github.com/janelkit/janelkit/blob/main/docs/api.md) y [cambios entre versiones](https://github.com/janelkit/janelkit/blob/main/docs/cambios.md).
- [Crear un ejecutable](https://github.com/janelkit/janelkit/blob/main/docs/desarrollo.md#distribuir-un-ejecutable-con-pyinstaller) con PyInstaller.
- [Ejemplos](https://github.com/janelkit/janelkit/tree/main/apps/examples): contador, tareas, notas, explorador de archivos, cliente de una API, idiomas, vídeo…

## Licencia

[MIT](https://github.com/janelkit/janelkit/blob/main/LICENSE). JanelKit usa [PySide6](https://pypi.org/project/PySide6/) (Qt for Python), que se distribuye bajo LGPL-3.0: si empaquetas tu aplicación con Qt incluido, revisa sus [condiciones](https://doc.qt.io/qtforpython-6/licenses.html).
