aurora-ui 0.2.0__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.
- aurora_ui-0.2.0/.editorconfig +15 -0
- aurora_ui-0.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +47 -0
- aurora_ui-0.2.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- aurora_ui-0.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +26 -0
- aurora_ui-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- aurora_ui-0.2.0/.github/workflows/ci.yml +76 -0
- aurora_ui-0.2.0/.github/workflows/release.yml +74 -0
- aurora_ui-0.2.0/.gitignore +6 -0
- aurora_ui-0.2.0/CHANGELOG.md +94 -0
- aurora_ui-0.2.0/CLAUDE.md +96 -0
- aurora_ui-0.2.0/CODE_OF_CONDUCT.md +32 -0
- aurora_ui-0.2.0/CONTRIBUTING.md +85 -0
- aurora_ui-0.2.0/Cargo.lock +2465 -0
- aurora_ui-0.2.0/Cargo.toml +32 -0
- aurora_ui-0.2.0/LICENSE +21 -0
- aurora_ui-0.2.0/PKG-INFO +233 -0
- aurora_ui-0.2.0/README.md +205 -0
- aurora_ui-0.2.0/ROADMAP.md +75 -0
- aurora_ui-0.2.0/SECURITY.md +19 -0
- aurora_ui-0.2.0/VISION.md +99 -0
- aurora_ui-0.2.0/docs/architecture.md +238 -0
- aurora_ui-0.2.0/docs/assets/banner.png +0 -0
- aurora_ui-0.2.0/docs/assets/logo.png +0 -0
- aurora_ui-0.2.0/docs/assets/logo.svg +10 -0
- aurora_ui-0.2.0/docs/guide.md +483 -0
- aurora_ui-0.2.0/docs/reference.md +504 -0
- aurora_ui-0.2.0/docs/studio/1-resumen.png +0 -0
- aurora_ui-0.2.0/docs/studio/2-tablero.png +0 -0
- aurora_ui-0.2.0/docs/studio/3-modal.png +0 -0
- aurora_ui-0.2.0/docs/studio/4-equipo-claro.png +0 -0
- aurora_ui-0.2.0/examples/README.md +19 -0
- aurora_ui-0.2.0/examples/brand.py +125 -0
- aurora_ui-0.2.0/examples/hello.py +61 -0
- aurora_ui-0.2.0/examples/studio.py +912 -0
- aurora_ui-0.2.0/pyproject.toml +70 -0
- aurora_ui-0.2.0/python/aurora/__init__.py +129 -0
- aurora_ui-0.2.0/python/aurora/_core.pyi +95 -0
- aurora_ui-0.2.0/python/aurora/components.py +430 -0
- aurora_ui-0.2.0/python/aurora/elements.py +144 -0
- aurora_ui-0.2.0/python/aurora/py.typed +0 -0
- aurora_ui-0.2.0/python/aurora/signal.py +52 -0
- aurora_ui-0.2.0/python/aurora/theme.py +69 -0
- aurora_ui-0.2.0/src/color.rs +41 -0
- aurora_ui-0.2.0/src/edit.rs +389 -0
- aurora_ui-0.2.0/src/image.rs +263 -0
- aurora_ui-0.2.0/src/input.rs +144 -0
- aurora_ui-0.2.0/src/keys.rs +218 -0
- aurora_ui-0.2.0/src/lib.rs +55 -0
- aurora_ui-0.2.0/src/pilot.rs +266 -0
- aurora_ui-0.2.0/src/render.rs +1263 -0
- aurora_ui-0.2.0/src/runtime.rs +993 -0
- aurora_ui-0.2.0/src/scroll.rs +273 -0
- aurora_ui-0.2.0/src/spec.rs +472 -0
- aurora_ui-0.2.0/src/window.rs +393 -0
- aurora_ui-0.2.0/tests/test_components.py +238 -0
- aurora_ui-0.2.0/tests/test_elements.py +55 -0
- aurora_ui-0.2.0/tests/test_image.py +133 -0
- aurora_ui-0.2.0/tests/test_input.py +277 -0
- aurora_ui-0.2.0/tests/test_keyboard.py +258 -0
- aurora_ui-0.2.0/tests/test_pilot.py +256 -0
- aurora_ui-0.2.0/tests/test_render.py +115 -0
- aurora_ui-0.2.0/tests/test_scroll.py +162 -0
- aurora_ui-0.2.0/tests/test_signal.py +20 -0
- aurora_ui-0.2.0/tests/test_studio.py +62 -0
- aurora_ui-0.2.0/uv.lock +229 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 4
|
|
10
|
+
|
|
11
|
+
[*.{yml,yaml,toml,json,md}]
|
|
12
|
+
indent_size = 2
|
|
13
|
+
|
|
14
|
+
[*.md]
|
|
15
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Reportar un bug
|
|
2
|
+
description: Algo no funciona como esperabas.
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: Gracias por tomarte el tiempo de reportarlo. Cuanto más concreto, antes se arregla.
|
|
8
|
+
- type: textarea
|
|
9
|
+
id: what
|
|
10
|
+
attributes:
|
|
11
|
+
label: Qué pasa
|
|
12
|
+
description: Describe el problema. Si es visual, adjunta una captura (puedes usar `app.render_png()`).
|
|
13
|
+
validations:
|
|
14
|
+
required: true
|
|
15
|
+
- type: textarea
|
|
16
|
+
id: expected
|
|
17
|
+
attributes:
|
|
18
|
+
label: Qué esperabas que pasara
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: repro
|
|
23
|
+
attributes:
|
|
24
|
+
label: Ejemplo mínimo
|
|
25
|
+
description: El programa más corto posible que reproduzca el problema.
|
|
26
|
+
render: python
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
- type: input
|
|
30
|
+
id: version
|
|
31
|
+
attributes:
|
|
32
|
+
label: Versión de Aurora
|
|
33
|
+
placeholder: "0.1.0 (o el commit)"
|
|
34
|
+
validations:
|
|
35
|
+
required: true
|
|
36
|
+
- type: dropdown
|
|
37
|
+
id: os
|
|
38
|
+
attributes:
|
|
39
|
+
label: Sistema operativo
|
|
40
|
+
options: [Windows, macOS, Linux (X11), Linux (Wayland)]
|
|
41
|
+
validations:
|
|
42
|
+
required: true
|
|
43
|
+
- type: input
|
|
44
|
+
id: python
|
|
45
|
+
attributes:
|
|
46
|
+
label: Versión de Python
|
|
47
|
+
placeholder: "3.13"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Proponer una funcionalidad
|
|
2
|
+
description: Una idea para mejorar Aurora.
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Antes de proponer, echa un vistazo a [VISION.md](../blob/main/VISION.md) y al
|
|
9
|
+
[ROADMAP.md](../blob/main/ROADMAP.md): puede que ya esté planificada.
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: problem
|
|
12
|
+
attributes:
|
|
13
|
+
label: Qué problema resuelve
|
|
14
|
+
description: Cuéntanos el caso de uso real. Es lo que más pesa al priorizar.
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: proposal
|
|
19
|
+
attributes:
|
|
20
|
+
label: Cómo te gustaría usarlo
|
|
21
|
+
description: Un ejemplo de cómo se vería la API desde Python.
|
|
22
|
+
render: python
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: alternatives
|
|
25
|
+
attributes:
|
|
26
|
+
label: Alternativas que consideraste
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Qué cambia
|
|
2
|
+
|
|
3
|
+
<!-- Describe el cambio y por qué es necesario. Enlaza el issue si existe: "Cierra #123". -->
|
|
4
|
+
|
|
5
|
+
## Cómo se probó
|
|
6
|
+
|
|
7
|
+
<!-- Tests añadidos, ejemplos ejecutados, capturas antes/después si es visual. -->
|
|
8
|
+
|
|
9
|
+
## Checklist
|
|
10
|
+
|
|
11
|
+
- [ ] `uv run pytest` pasa
|
|
12
|
+
- [ ] `uv run ruff check .` y `cargo clippy --release -- -D warnings` sin avisos
|
|
13
|
+
- [ ] Si es visual: hay un test de render y adjunto capturas
|
|
14
|
+
- [ ] Si cambia la API pública: actualicé `docs/reference.md`, los stubs y el `CHANGELOG.md`
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ci-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
env:
|
|
13
|
+
CARGO_TERM_COLOR: always
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
lint:
|
|
17
|
+
name: Lint (Python + Rust)
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: astral-sh/setup-uv@v6
|
|
22
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
23
|
+
with:
|
|
24
|
+
components: rustfmt, clippy
|
|
25
|
+
- uses: Swatinem/rust-cache@v2
|
|
26
|
+
- name: Dependencias del sistema
|
|
27
|
+
run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev libfreetype-dev
|
|
28
|
+
- name: Ruff
|
|
29
|
+
run: |
|
|
30
|
+
uvx ruff check .
|
|
31
|
+
uvx ruff format --check .
|
|
32
|
+
- name: rustfmt
|
|
33
|
+
run: cargo fmt --check
|
|
34
|
+
- name: Clippy
|
|
35
|
+
run: cargo clippy --release -- -D warnings
|
|
36
|
+
|
|
37
|
+
test:
|
|
38
|
+
name: Tests (${{ matrix.os }}, py${{ matrix.python }})
|
|
39
|
+
runs-on: ${{ matrix.os }}
|
|
40
|
+
strategy:
|
|
41
|
+
fail-fast: false
|
|
42
|
+
matrix:
|
|
43
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
44
|
+
python: ["3.10", "3.13"]
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
- uses: astral-sh/setup-uv@v6
|
|
48
|
+
with:
|
|
49
|
+
python-version: ${{ matrix.python }}
|
|
50
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
51
|
+
- uses: Swatinem/rust-cache@v2
|
|
52
|
+
- name: Dependencias del sistema (Linux)
|
|
53
|
+
if: runner.os == 'Linux'
|
|
54
|
+
run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev libfreetype-dev
|
|
55
|
+
- name: Compilar e instalar
|
|
56
|
+
run: uv sync
|
|
57
|
+
- name: Tests
|
|
58
|
+
run: uv run pytest -v
|
|
59
|
+
# Con `extension-module` el binario de tests de Rust no enlaza contra libpython en
|
|
60
|
+
# Linux/macOS; en Windows sí (python3.lib), así que los tests unitarios corren ahí.
|
|
61
|
+
- name: Tests de Rust (Windows)
|
|
62
|
+
if: runner.os == 'Windows'
|
|
63
|
+
run: uv run cargo test --release
|
|
64
|
+
- name: Renderizar los ejemplos (smoke test visual)
|
|
65
|
+
run: |
|
|
66
|
+
uv run examples/hello.py --png hello.png
|
|
67
|
+
uv run examples/studio.py --png studio-shots
|
|
68
|
+
- name: Subir capturas
|
|
69
|
+
if: always()
|
|
70
|
+
uses: actions/upload-artifact@v4
|
|
71
|
+
with:
|
|
72
|
+
name: capturas-${{ matrix.os }}-py${{ matrix.python }}
|
|
73
|
+
path: |
|
|
74
|
+
hello.png
|
|
75
|
+
studio-shots/
|
|
76
|
+
if-no-files-found: ignore
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Publica wheels en PyPI al crear un tag vX.Y.Z.
|
|
2
|
+
#
|
|
3
|
+
# Requisitos (una sola vez):
|
|
4
|
+
# 1. Crear el proyecto en PyPI y configurar "Trusted Publishing" para este repositorio
|
|
5
|
+
# y el workflow release.yml (sin tokens ni secretos).
|
|
6
|
+
# 2. Crear el environment "pypi" en la configuración del repositorio.
|
|
7
|
+
#
|
|
8
|
+
# Nota: el wheel es abi3, así que basta uno por plataforma y arquitectura para todas
|
|
9
|
+
# las versiones de Python >= 3.10.
|
|
10
|
+
|
|
11
|
+
name: Release
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
push:
|
|
15
|
+
tags: ["v*"]
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
wheels:
|
|
23
|
+
name: Wheel ${{ matrix.platform.name }}
|
|
24
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
25
|
+
strategy:
|
|
26
|
+
fail-fast: false
|
|
27
|
+
matrix:
|
|
28
|
+
platform:
|
|
29
|
+
- { name: linux-x86_64, runner: ubuntu-latest, target: x86_64 }
|
|
30
|
+
- { name: windows-x64, runner: windows-latest, target: x64 }
|
|
31
|
+
- { name: macos-arm64, runner: macos-latest, target: aarch64 }
|
|
32
|
+
# macos-13 ya no existe en GitHub Actions; macos-15-intel es la última imagen Intel.
|
|
33
|
+
- { name: macos-x86_64, runner: macos-15-intel, target: x86_64 }
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- uses: PyO3/maturin-action@v1
|
|
37
|
+
with:
|
|
38
|
+
target: ${{ matrix.platform.target }}
|
|
39
|
+
args: --release --out dist
|
|
40
|
+
manylinux: 2_28
|
|
41
|
+
before-script-linux: dnf install -y fontconfig-devel freetype-devel
|
|
42
|
+
- uses: actions/upload-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: wheel-${{ matrix.platform.name }}
|
|
45
|
+
path: dist
|
|
46
|
+
|
|
47
|
+
sdist:
|
|
48
|
+
name: Source distribution
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
- uses: PyO3/maturin-action@v1
|
|
53
|
+
with:
|
|
54
|
+
command: sdist
|
|
55
|
+
args: --out dist
|
|
56
|
+
- uses: actions/upload-artifact@v4
|
|
57
|
+
with:
|
|
58
|
+
name: sdist
|
|
59
|
+
path: dist
|
|
60
|
+
|
|
61
|
+
publish:
|
|
62
|
+
name: Publicar en PyPI
|
|
63
|
+
needs: [wheels, sdist]
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
66
|
+
environment: pypi
|
|
67
|
+
permissions:
|
|
68
|
+
id-token: write
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/download-artifact@v4
|
|
71
|
+
with:
|
|
72
|
+
path: dist
|
|
73
|
+
merge-multiple: true
|
|
74
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Todos los cambios relevantes de Aurora se documentan aquí.
|
|
4
|
+
|
|
5
|
+
El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/) y el proyecto usa
|
|
6
|
+
[Versionado Semántico](https://semver.org/lang/es/). Mientras la versión sea `0.x`, cualquier
|
|
7
|
+
versión menor puede incluir cambios incompatibles, que siempre se señalarán aquí.
|
|
8
|
+
|
|
9
|
+
## [Sin publicar]
|
|
10
|
+
|
|
11
|
+
## [0.2.0] — 2026-10-15
|
|
12
|
+
|
|
13
|
+
Apps de verdad: scroll, teclado y foco, campos de texto, imágenes y más componentes.
|
|
14
|
+
|
|
15
|
+
### Añadido
|
|
16
|
+
|
|
17
|
+
- Componentes `divider`, `avatar`, `checkbox`, `switch`, `tabs` (con ← →) y `select` (desplegable en
|
|
18
|
+
capa superior, con scroll, Esc y ↑ ↓), enlazados a `Signal` donde aplica.
|
|
19
|
+
- `tooltip(child, tip)` y la propiedad `tooltip`: burbuja tras medio segundo de hover, colocada
|
|
20
|
+
dentro de la ventana, con colores heredables `tooltip_bg` y `tooltip_color`; `Pilot.tooltip`.
|
|
21
|
+
- Primitiva `image(src, fit=...)`: PNG, JPEG, WebP, GIF, BMP, ICO y SVG (vectorial) desde una ruta
|
|
22
|
+
o desde `bytes`, con proporción automática, `fit` (`contain`, `cover`, `fill`, `none`), recorte a
|
|
23
|
+
las esquinas redondeadas, caché de decodificación que detecta cambios en disco y errores claros
|
|
24
|
+
(`FileNotFoundError`, `ValueError`).
|
|
25
|
+
- Campos de texto `text_input` y `textarea`, enlazados en los dos sentidos a un `Signal[str]`:
|
|
26
|
+
cursor que parpadea, selección con teclado y ratón (doble y triple clic), recorrido por grafemas y
|
|
27
|
+
palabras, portapapeles, deshacer/rehacer agrupando lo escrito, composición con IME, placeholder,
|
|
28
|
+
`on_submit`, desplazamiento horizontal en una línea y crecimiento con el contenido en varias.
|
|
29
|
+
- Propiedades `placeholder_color` y `selection_color`; cursor de texto del ratón sobre los campos.
|
|
30
|
+
- `Pilot.type()`, `ime_preedit()`, `ime_commit()`, `selection()` y `clipboard`.
|
|
31
|
+
- Teclado y foco: Tab / Shift+Tab en orden de pintura (atrapado dentro de barreras `capture`),
|
|
32
|
+
activación con Enter y Espacio, anillo de foco animado solo al navegar con teclado
|
|
33
|
+
(`focus_color`, heredable) y desplazamiento automático del `scroll` para mostrar el foco.
|
|
34
|
+
- `on_key` con `KeyEvent` (`key`, `text`, modificadores, `matches("mod+s")`), que burbujea desde el
|
|
35
|
+
foco hasta la raíz; `on_focus`, `on_blur`, `focusable` y `autofocus`.
|
|
36
|
+
- Desplazamiento con flechas, RePág/AvPág, Inicio/Fin y Espacio.
|
|
37
|
+
- `Pilot.press()`, `key_down()`, `key_up()`, `focus()` y `focused`.
|
|
38
|
+
- Contenedor `scroll(axis="y" | "x" | "both")`: recorte, rueda con desplazamiento suave, trackpad,
|
|
39
|
+
encadenado al `scroll` exterior en el límite y barra superpuesta que se oculta sola y se puede
|
|
40
|
+
arrastrar. La posición se conserva entre reconstrucciones.
|
|
41
|
+
- Propiedades `min_height`, `max_height` y `scrollbar_color`.
|
|
42
|
+
- `Pilot.wheel()`, `Pilot.scroll()` y `Pilot.scroll_offset()`.
|
|
43
|
+
- `app.pilot()`: piloto headless para tests de interacción (`click`, `move_to`, `hovered`, `rect`,
|
|
44
|
+
`settle`, `png`…) que usa el mismo runtime que la ventana.
|
|
45
|
+
- `Signal.set` es seguro desde cualquier hilo y despierta el bucle de eventos: la ventana se
|
|
46
|
+
actualiza sin esperar a un evento del usuario.
|
|
47
|
+
- `app.spawn(coro)`: ejecuta corrutinas en un bucle `asyncio` en segundo plano.
|
|
48
|
+
- Propiedad `layer="overlay"`: pinta un elemento y le da los eventos por encima de todo el árbol.
|
|
49
|
+
- Manejadores genéricos: cualquier argumento `on_<evento>` de un elemento es un manejador.
|
|
50
|
+
|
|
51
|
+
### Cambiado
|
|
52
|
+
|
|
53
|
+
- `Element.to_spec()` serializa los manejadores en `"handlers": {"click": fn}` en lugar de
|
|
54
|
+
`"on_click"`. `Element.on_click` sigue disponible como propiedad de solo lectura.
|
|
55
|
+
- El núcleo separa el estado de la app (`Runtime`) del bucle de ventana.
|
|
56
|
+
- El hit-testing respeta el recorte de los contenedores `scroll`.
|
|
57
|
+
- La demo `studio.py` desplaza el contenido de cada página y estrena búsqueda en el tablero, un
|
|
58
|
+
formulario de nueva tarea (Ctrl+N y el botón lo abren en vez de añadir una tarea de ejemplo),
|
|
59
|
+
una página de Ajustes y tooltips.
|
|
60
|
+
- Nuevas dependencias del núcleo: `arboard` (portapapeles) y `unicode-segmentation`. Las features de
|
|
61
|
+
`skia-safe` cambian por sistema (`svg`, `webp` y, fuera de macOS, `ganesh` + `vulkan`) para
|
|
62
|
+
seguir usando binarios precompilados de Skia.
|
|
63
|
+
|
|
64
|
+
### Corregido
|
|
65
|
+
|
|
66
|
+
- `examples/studio.py --png` ya no falla en consolas de Windows sin UTF-8.
|
|
67
|
+
|
|
68
|
+
## [0.1.0] — 2026-10-15
|
|
69
|
+
|
|
70
|
+
Primera versión: la base del framework.
|
|
71
|
+
|
|
72
|
+
### Añadido
|
|
73
|
+
|
|
74
|
+
- Núcleo nativo en Rust expuesto como `aurora._core` (PyO3 + maturin, wheel abi3 para Python ≥ 3.10).
|
|
75
|
+
- Layout flexbox con Taffy: `direction`, `gap`, `padding`, `align`, `justify`, `grow`, `shrink`,
|
|
76
|
+
`wrap`, tamaños en píxeles o porcentaje, `min_width`/`max_width` y `position="absolute"` con
|
|
77
|
+
`top`/`right`/`bottom`/`left`.
|
|
78
|
+
- Render con Skia: esquinas redondeadas, bordes, sombras difuminadas, gradientes lineales y opacidad.
|
|
79
|
+
- Texto con shaping real, fallback de fuentes, herencia de estilos de texto, alineación por baseline,
|
|
80
|
+
`max_lines` con elipsis y `text_align`.
|
|
81
|
+
- Ventana nativa con winit; el bucle de eventos corre sin el GIL.
|
|
82
|
+
- Estados hover y pressed animados en el núcleo (`bg_hover`, `bg_pressed`, `press_scale`).
|
|
83
|
+
- Hit-testing con burbujeo al ancestro interactivo y barreras de eventos (`capture`).
|
|
84
|
+
- API declarativa: `box`, `row`, `column`, `text`, `spacer`, hijos con `[...]`, `key` y `on_click`.
|
|
85
|
+
- `Signal` para el estado reactivo.
|
|
86
|
+
- Temas con tokens (`"$primary"`), temas `MIDNIGHT` y `DAYLIGHT`, y tema reactivo vía `Signal[Theme]`.
|
|
87
|
+
- Componentes: `button` (variantes `primary`, `soft`, `ghost`), `card`, `badge` y `stat`.
|
|
88
|
+
- `App.render_png()` para renderizar sin ventana.
|
|
89
|
+
- Ejemplos: `hello.py`, `studio.py` (demo completa) y `brand.py` (genera las imágenes del README).
|
|
90
|
+
- Documentación: guía, referencia, arquitectura, visión y roadmap.
|
|
91
|
+
|
|
92
|
+
[Sin publicar]: https://github.com/<usuario>/aurora/compare/v0.2.0...HEAD
|
|
93
|
+
[0.2.0]: https://github.com/<usuario>/aurora/compare/v0.1.0...v0.2.0
|
|
94
|
+
[0.1.0]: https://github.com/<usuario>/aurora/releases/tag/v0.1.0
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
Aurora (`aurora-ui`, pre-alpha v0.2) is a declarative, reactive desktop UI library: the public API is
|
|
6
|
+
Python (`python/aurora/`), and layout/render/animation/events run in a native Rust core
|
|
7
|
+
(`src/`, built as the extension module `aurora._core` via PyO3 + maturin). Stack: Skia (`skia-safe`)
|
|
8
|
+
for painting and text, Taffy for flexbox layout, winit + softbuffer for the window (CPU raster).
|
|
9
|
+
|
|
10
|
+
## Commands
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
uv sync # builds the Rust core (release) and installs editable + dev deps
|
|
14
|
+
uv run pytest # all tests
|
|
15
|
+
uv run pytest tests/test_render.py::test_name # single test
|
|
16
|
+
uv run examples/studio.py # full demo app (opens a window)
|
|
17
|
+
uv run examples/studio.py --png studio-shots # headless render of the demo (CI smoke test)
|
|
18
|
+
uv run examples/hello.py --png hello.png
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Full lint, same as CI:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
uv run ruff check . && uv run ruff format --check .
|
|
25
|
+
cargo fmt --check && cargo clippy --release -- -D warnings
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Python edits in `python/aurora/` apply immediately (editable install). Rust edits in `src/**/*.rs`
|
|
29
|
+
trigger an automatic rebuild on the next `uv run` (configured via `tool.uv.cache-keys`).
|
|
30
|
+
- Rust unit tests (`uv run cargo test --release`) only link on Windows: with `extension-module`,
|
|
31
|
+
the test binary doesn't link libpython on Linux/macOS.
|
|
32
|
+
- First build downloads prebuilt Skia binaries and takes minutes. The `skia-safe` features in
|
|
33
|
+
`Cargo.toml` (per OS) must match a combination published in rust-skia/skia-binaries; any other
|
|
34
|
+
combination silently falls back to building Skia from source (needs LLVM, very slow). Check the
|
|
35
|
+
release assets before adding a Skia feature. Linux needs
|
|
36
|
+
`libfontconfig-dev` and `libfreetype-dev`.
|
|
37
|
+
|
|
38
|
+
## Architecture
|
|
39
|
+
|
|
40
|
+
Core principle: **Python describes, Rust executes; the boundary is crossed once per update with a
|
|
41
|
+
complete tree.** Never expose low-level operations (draw rect, measure text) to Python.
|
|
42
|
+
|
|
43
|
+
Frame lifecycle:
|
|
44
|
+
|
|
45
|
+
1. `App._build()` (`python/aurora/__init__.py`) calls the user's `view()`, applies root defaults,
|
|
46
|
+
and serializes the `Element` tree to nested dicts via `Element.to_spec(theme)` — this is where
|
|
47
|
+
`"$token"` theme values and text lambdas are resolved.
|
|
48
|
+
2. `spec::parse` (`src/spec.rs`) is the **only** place in Rust that knows the shape of the Python
|
|
49
|
+
data: dicts → typed `Node`. Text style inheritance (`color`, `font_size`, `font_weight`,
|
|
50
|
+
`font_family`, `line_height`, `letter_spacing`) is resolved here once, CSS-style.
|
|
51
|
+
3. `render.rs` `Engine`: builds a parallel Taffy tree (text nodes carry a shaped Skia `Paragraph`,
|
|
52
|
+
reused for both measuring and painting), ticks hover/pressed transitions (exponential smoothing,
|
|
53
|
+
τ = 70 ms, real `dt`), and `Painter` paints shadow → bg → border → text → children while
|
|
54
|
+
recording `HitRegion`s in paint order.
|
|
55
|
+
4. `runtime.rs` `Runtime`: window-independent app state (tree, hit regions, pointer, event
|
|
56
|
+
dispatch by handler name via `dispatch(key, event, arg)`). Two drivers share it: `window.rs`
|
|
57
|
+
(winit loop, runs with the GIL released via `py.detach`; the GIL is taken only to run a handler or
|
|
58
|
+
rebuild the view; hover never touches Python) and `pilot.rs` (`Pilot`, headless, for interaction
|
|
59
|
+
tests via `app.pilot()`).
|
|
60
|
+
|
|
61
|
+
`Signal.set` calls `_core.wake()` (any thread): an atomic flag that `Runtime::sync` consumes, plus an
|
|
62
|
+
`EventLoopProxy` user event to request a frame. Nodes with `layer="overlay"` are deferred by `Painter`
|
|
63
|
+
and painted (and hit-tested) after the whole tree.
|
|
64
|
+
|
|
65
|
+
Hit-testing: take the last-painted region containing the point, bubble up through parents to the
|
|
66
|
+
first node with a `click` handler; a node with `capture=True` stops the bubbling (e.g. modals).
|
|
67
|
+
|
|
68
|
+
Node identity is stable (explicit `key` or tree path) and is used to keep animation state across
|
|
69
|
+
full rebuilds — every event currently rebuilds the whole view.
|
|
70
|
+
|
|
71
|
+
`App.render_png()` → `_core.render_png` renders without a window; this powers `tests/test_render.py`
|
|
72
|
+
(which decodes PNG pixels without Pillow), CI smoke tests, and the README images (`examples/brand.py`).
|
|
73
|
+
|
|
74
|
+
## Extending
|
|
75
|
+
|
|
76
|
+
- **New component:** compose primitives in `components.py` in pure Python whenever possible. Only
|
|
77
|
+
push to Rust what can't be expressed otherwise (new node kinds, render effects, layout).
|
|
78
|
+
- **New style property:** add the field to `spec::Style` and its parsing, its effect in
|
|
79
|
+
`taffy_style` (layout) or `Painter::paint` (paint), and document it in `docs/reference.md`.
|
|
80
|
+
- **New node type:** new `spec::Kind` variant + its layout measurement + its painting.
|
|
81
|
+
- Visual changes need a render test in `tests/test_render.py`; interaction changes need a `Pilot`
|
|
82
|
+
test in `tests/test_pilot.py`. Public API changes must update
|
|
83
|
+
`docs/reference.md`, `python/aurora/_core.pyi` stubs (if the native API changes), and the
|
|
84
|
+
"Sin publicar" section of `CHANGELOG.md`.
|
|
85
|
+
|
|
86
|
+
## Conventions
|
|
87
|
+
|
|
88
|
+
- Code identifiers in English (`bg`, `radius`, `on_click`, CSS-like); docs, comments and commit
|
|
89
|
+
messages in **Spanish**. Commits in imperative mood (`Añade contenedor scroll con clipping`).
|
|
90
|
+
- Components must look good with default values. Optional parameters are keyword-only; positional
|
|
91
|
+
args only for essentials (`text(content)`, `button(label, on_click)`).
|
|
92
|
+
- Children are attached with `[...]` (`column(gap=8)[a, b]`); theme colors use `"$token"` strings.
|
|
93
|
+
- Rust: no `unwrap()` on paths that depend on user data — input errors must surface in Python as
|
|
94
|
+
clear exceptions.
|
|
95
|
+
- Ruff line length is 110; Spanish typography rules (RUF001–003) and lambda assignment (E731) are
|
|
96
|
+
ignored on purpose.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Código de conducta
|
|
2
|
+
|
|
3
|
+
Aurora quiere ser un proyecto donde cualquier persona pueda participar con comodidad,
|
|
4
|
+
independientemente de su experiencia, origen o identidad.
|
|
5
|
+
|
|
6
|
+
## Lo que esperamos
|
|
7
|
+
|
|
8
|
+
- Trato respetuoso y empático, también cuando no estamos de acuerdo.
|
|
9
|
+
- Críticas dirigidas a las ideas y al código, nunca a las personas.
|
|
10
|
+
- Paciencia con quien está aprendiendo: todos empezamos en algún momento.
|
|
11
|
+
- Asumir buena fe, y pedir aclaraciones antes de sacar conclusiones.
|
|
12
|
+
- Reconocer los errores propios y aprender de ellos.
|
|
13
|
+
|
|
14
|
+
## Lo que no aceptamos
|
|
15
|
+
|
|
16
|
+
- Insultos, burlas, comentarios despectivos o ataques personales.
|
|
17
|
+
- Acoso, público o privado, de cualquier tipo.
|
|
18
|
+
- Lenguaje o imágenes sexualizadas, y atención no deseada.
|
|
19
|
+
- Publicar información privada de otras personas sin su permiso.
|
|
20
|
+
- Cualquier conducta que sería inapropiada en un entorno profesional.
|
|
21
|
+
|
|
22
|
+
## Ámbito y aplicación
|
|
23
|
+
|
|
24
|
+
Este código se aplica en todos los espacios del proyecto (issues, pull requests, discusiones y
|
|
25
|
+
canales de chat) y cuando alguien representa al proyecto en público.
|
|
26
|
+
|
|
27
|
+
Para reportar un problema, escribe a las personas que mantienen el proyecto
|
|
28
|
+
(**TODO: añadir un email de contacto**). Los reportes se tratarán con confidencialidad. Quienes
|
|
29
|
+
mantienen el proyecto pueden editar o eliminar contribuciones que no respeten este código y, en
|
|
30
|
+
casos graves o reiterados, excluir temporal o permanentemente a quien lo incumpla.
|
|
31
|
+
|
|
32
|
+
Este código está inspirado en el [Contributor Covenant](https://www.contributor-covenant.org).
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Contribuir a Aurora
|
|
2
|
+
|
|
3
|
+
¡Gracias por tu interés! Toda contribución suma: reportar un bug, mejorar la documentación,
|
|
4
|
+
proponer una idea o implementar una funcionalidad.
|
|
5
|
+
|
|
6
|
+
## Antes de empezar
|
|
7
|
+
|
|
8
|
+
- **Bugs:** abre un issue con la plantilla de bug. Un ejemplo mínimo reproducible (y una captura
|
|
9
|
+
si es visual) ahorra mucho tiempo.
|
|
10
|
+
- **Funcionalidades:** abre primero un issue para discutirla. Revisa [VISION.md](VISION.md) y el
|
|
11
|
+
[ROADMAP.md](ROADMAP.md): las propuestas alineadas con ellos tienen más recorrido.
|
|
12
|
+
- **Cambios pequeños** (erratas, docs, tests): envía el PR directamente.
|
|
13
|
+
|
|
14
|
+
## Entorno de desarrollo
|
|
15
|
+
|
|
16
|
+
Necesitas Python ≥ 3.10, [uv](https://docs.astral.sh/uv/) y Rust estable
|
|
17
|
+
([rustup](https://rustup.rs)). En Linux, además, `libfontconfig-dev` y `libfreetype-dev`.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git clone https://github.com/<usuario>/aurora.git
|
|
21
|
+
cd aurora
|
|
22
|
+
uv sync # compila el núcleo e instala todo (incluye pytest y ruff)
|
|
23
|
+
uv run pytest # tests
|
|
24
|
+
uv run examples/studio.py # demo completa
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- Los cambios en `python/aurora/` se aplican al instante (instalación editable).
|
|
28
|
+
- Los cambios en `src/*.rs` disparan la recompilación en el siguiente `uv run`.
|
|
29
|
+
|
|
30
|
+
## Antes de enviar un PR
|
|
31
|
+
|
|
32
|
+
Ejecuta lo mismo que la CI:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv run ruff check . && uv run ruff format --check .
|
|
36
|
+
cargo fmt --check && cargo clippy --release -- -D warnings
|
|
37
|
+
uv run pytest
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Y verifica a mano:
|
|
41
|
+
|
|
42
|
+
- [ ] Si el cambio es **visual**, hay un test en `tests/test_render.py` que lo renderiza, y
|
|
43
|
+
`uv run examples/studio.py` sigue viéndose bien.
|
|
44
|
+
- [ ] Si cambia la **API pública**, están actualizados `docs/reference.md`, la guía si aplica,
|
|
45
|
+
los stubs (`_core.pyi`) y el `CHANGELOG.md` (sección *Sin publicar*).
|
|
46
|
+
- [ ] Si añades una **propiedad de estilo**, sigue los pasos de
|
|
47
|
+
[Extender Aurora](docs/architecture.md#extender-aurora).
|
|
48
|
+
|
|
49
|
+
## Convenciones
|
|
50
|
+
|
|
51
|
+
### Diseño de la API
|
|
52
|
+
|
|
53
|
+
- **Bonito por defecto:** los valores por defecto de un componente nuevo deben verse bien sin
|
|
54
|
+
configurar nada.
|
|
55
|
+
- **Componentes en Python** siempre que se puedan componer con primitivas. Al núcleo Rust solo
|
|
56
|
+
bajan capacidades que no se puedan expresar de otra forma (nuevos tipos de nodo, efectos de
|
|
57
|
+
render, layout).
|
|
58
|
+
- **Nombres en inglés en el código** (`bg`, `radius`, `on_click`), siguiendo las convenciones
|
|
59
|
+
habituales de CSS y de otros frameworks de UI. Documentación y comentarios, en español.
|
|
60
|
+
- **Keyword arguments** para todo lo opcional; los posicionales, solo para lo esencial
|
|
61
|
+
(`text(contenido)`, `button(label, on_click)`).
|
|
62
|
+
|
|
63
|
+
### Código
|
|
64
|
+
|
|
65
|
+
- **Python:** formateado con `ruff format` y con type hints en la API pública.
|
|
66
|
+
- **Rust:** `cargo fmt` y `clippy` sin warnings. Nada de `unwrap()` en rutas que dependan de datos
|
|
67
|
+
del usuario: los errores de entrada deben llegar a Python como excepciones claras.
|
|
68
|
+
- **Commits:** mensajes en imperativo y descriptivos (`Añade contenedor scroll con clipping`).
|
|
69
|
+
Un commit por cambio lógico.
|
|
70
|
+
|
|
71
|
+
## Estructura del proyecto
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
python/aurora/ API pública en Python
|
|
75
|
+
src/ Núcleo nativo en Rust (módulo aurora._core)
|
|
76
|
+
tests/ Tests (pytest), incluidos tests de render headless
|
|
77
|
+
examples/ Apps de ejemplo; brand.py genera las imágenes del README
|
|
78
|
+
docs/ Guía, referencia, arquitectura y recursos gráficos
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
El recorrido completo por el núcleo está en [docs/architecture.md](docs/architecture.md).
|
|
82
|
+
|
|
83
|
+
## Licencia
|
|
84
|
+
|
|
85
|
+
Al contribuir aceptas que tu aportación se publique bajo la [licencia MIT](LICENSE) del proyecto.
|