Skip to main content

janelkit-router

PyPI Python CI Licencia: MIT

Navegación entre pantallas para aplicaciones JanelKit: pilas de páginas que conservan su estado, secciones paralelas (barra lateral, pestañas), resultados con await, preguntar antes de salir y transiciones.

pip install janelkit-router

En un minuto

from janelkit_router import pages, Pages
from pages.Inicio import Inicio
from pages.Detalle import Detalle

nav = pages(Inicio)

def abrir(item):
    nav.push(Detalle, item=item, on_borrado=borrar)
<row class="barra">
  <button on:click={nav.pop()} enabled={nav.can_go_back}>← Volver</button>
  <text>{nav.current}</text>
</row>
<Pages stack={nav} />

Pages y Sections son elementos de este paquete: se importan en el script, como un componente, y se usan con mayúscula.

Pilas de páginas

  • <Pages stack={nav} /> muestra la página de arriba de la pila y ocupa el espacio libre (flex: 1).

  • push muestra una página nueva encima; la de debajo sigue viva y, al volver con pop(), conserva su estado. Mientras está debajo, lo que muestra espera, como en {#hidden}: se pone al día al volver a verse. replace sustituye la actual; reset vacía la pila y empieza de nuevo. Las páginas descartadas se liberan (sus on_destroy se ejecutan).

  • Cada página ocupa todo su <Pages> (y cada sección, su <Sections>) y se estrecha con la ventana hasta el mínimo de su contenido; lo que deba desplazarse, con overflow: auto. La raíz de la página puede cambiarlo con CSS, como un bloque en una columna:

    .pagina { max-width: 720px; margin: 0 auto; }   /* una columna centrada */
    .pagina { width: 400px; height: 300px; }         /* tamaño fijo, arriba a la izquierda */
    .pagina { align-self: center; }                  /* su ancho natural, centrada */
    .pagina { margin: 24px; }                        /* llena, con margen alrededor */
    
  • Las palabras clave son props y eventos (on_...) de la página, como en open_window. Las páginas heredan el contexto (inject) del componente que declara la pila.

  • nav.current (nombre de la página visible), nav.depth y nav.can_go_back son reactivos; nav.page da la instancia visible.

  • Transiciones: <Pages stack={nav} transition:slide /> anima la página que entra: al avanzar llega desde la derecha y al volver desde la izquierda. También fade y scale, y la duración: transition:fade={150}. En <Sections>, la transición se aplica al cambiar de sección y a las páginas de cada una.

  • Atrás con el teclado y el ratón: Alt+← y el botón «atrás» del ratón vuelven a la página anterior, en la pila visible más interna. Alt+← actúa cuando el foco está dentro de la pila (si está, por ejemplo, en un botón de la barra lateral, no hace nada); el ratón, al pulsar sobre ella. Si un elemento de la página ya usa Alt+← (por ejemplo, para mover una tarjeta), gana el elemento.

Navegar desde una página

Dentro de una página (o de cualquier componente que contenga), navigation() da su pila, sin pasarla como prop:

from janelkit_router import navigation
from pages.Detalle import Detalle

nav = navigation()

def abrir(item):
    nav.push(Detalle, item=item)

Devolver un resultado

push se puede esperar: await devuelve el valor con el que la página vuelve con nav.back(valor) (o None si se descarta de otra forma, con pop, replace o reset).

async def elegir_responsable():                  # en la página que pregunta
    persona = await nav.push(ElegirPersona)
    if persona is not None:
        tarjeta["responsable"] = persona["id"]
<!-- en ElegirPersona.janel -->
<button on:click={nav.back(p)}>{p["nombre"]}</button>

Secciones

Una aplicación con barra lateral o pestañas tiene varias secciones, y cada una necesita su pila. sections() las crea; <Sections of={...} /> muestra la actual:

from janelkit_router import sections, Sections
from pages.Proyectos import Proyectos
from pages.Personas import Personas

secciones = sections(proyectos=Proyectos, personas=Personas)
<flex>
  <flex direction="column" class="barra">
    <button on:click={secciones.show("proyectos")} class:activa={secciones.current == "proyectos"}>Proyectos</button>
    <button on:click={secciones.show("personas")} class:activa={secciones.current == "personas"}>Personas</button>
  </flex>
  <Sections of={secciones} />
</flex>
  • Cada sección es una pila (secciones["personas"], o secciones.stack para la visible) y empieza en el componente indicado. Dentro, navigation() da la pila de su sección.
  • Una sección se crea la primera vez que se muestra. Al cambiar a otra se conserva entera, con todas sus páginas y su estado; volver a ella cuesta lo mismo que mostrarla. Mientras no se ve, lo que muestra espera (como en {#hidden}): un cambio de datos en otra sección no la recalcula.
  • secciones.current (el nombre de la visible) es reactivo; secciones.names lista los nombres.

Preguntar antes de salir

before_leave(fn) (del núcleo) en el script de un componente registra una pregunta: si fn() devuelve False, no se sale. Puede ser async, para preguntar con un diálogo:

from janelkit import before_leave
from janelkit_desktop import dialogs

@before_leave
async def salir():
    return not cambios.value or await dialogs.confirm("Hay cambios sin guardar. ¿Salir igualmente?")
  • Se consulta al descartar la página que contiene el componente (pop, back, replace, reset, Alt+←) y al cerrar con la X la ventana que lo muestra.

  • Cambiar de sección no pregunta: la sección se conserva y no se pierde nada.

  • Para encadenar navegaciones, espera la salida: pop, back, replace y reset devuelven True si se salió y False si un before_leave lo impidió (la respuesta puede llegar después de un diálogo):

    async def ir_a_tarjeta(pid, tid):
        if await nav.reset(Proyectos):      # un detalle con cambios puede pedir quedarse
            nav.push(Proyecto, ident=pid, enfocar=tid)
    

Referencia

Nombre Descripción
pages nav = pages(Inicio, **props) crea una pila de páginas que empieza en Inicio (un componente importado).
PageStack Tipo de pages: .push(C, **props_y_on_eventos) (se puede esperar: await devuelve el valor de .back(valor)), .pop(), .back(valor=None), .replace(...), .reset(...) (los cuatro se pueden esperar: True si se salió, False si un before_leave lo impidió); reactivos .current, .depth, .can_go_back; .page (instancia visible).
navigation nav = navigation() en el script de una página (o de un componente dentro de ella) da su pila.
sections secciones = sections(a=A, b=B) crea secciones paralelas, cada una con su pila.
SectionSet Tipo de sections: .show(nombre), [nombre] (su pila), .stack (la de la visible), .names; reactivo .current.
<Pages stack={nav} /> Muestra la página de arriba. Admite transition: y las propiedades comunes (flex, width, class…).
<Sections of={secciones} /> Muestra la sección visible. Igual que <Pages>.

En pruebas

Con janelkit.inspect, las páginas se buscan por el nombre de su componente (app.find("Detalle")) y la pila se maneja desde el script (app.get("nav").push(...)). La página de debajo y las secciones ocultas no salen en find.

Ejemplo: apps/challenges/gestor (secciones, páginas, resultados con await y preguntas antes de salir).

Cómo está hecho

Solo usa la API pública del núcleo, como cualquier paquete externo: Pages.qml y Sections.qml son elementos cuya raíz es JkDeck y que declaran una propiedad JkHost; PageStack y SectionSet son anfitriones (janelkit.ext.Host) que montan las páginas con Container.mount. Ver arquitectura.md.

Compatibilidad

janelkit-router janelkit Python
0.2.x.x 0.2.x.x ≥ 3.10

Comparte la serie con el núcleo: janelkit-router 0.2.x.x va con janelkit 0.2.x.x. Los dos últimos números son suyos (política de versiones).

Cambios

0.2.0.0 (2026-11-05)

  • Primera versión, en la serie 0.2. Antes era la navegación del núcleo (janelkit.pages): cambia from janelkit import pages, navigation, sections por from janelkit_router import pages, navigation, sections e importa los elementos que uses (from janelkit_router import Pages, Sections). El tipo de sections() pasa a llamarse SectionSet. janel migrate hace el cambio.

Licencia

MIT.

Metadata

Release files for janelkit-router 0.2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for janelkit-router 0.2.0.0
File Size Uploaded Provenance Actions
janelkit_router-0.2.0.0.tar.gz 20.0 kB With provenance Details for janelkit_router-0.2.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for janelkit-router 0.2.0.0
File Interpreter ABI Platform Actions
janelkit_router-0.2.0.0-py3-none-any.whl Python 3 none any Details for janelkit_router-0.2.0.0-py3-none-any.whl

Total release size: 31.5 kB

Release files / janelkit_router-0.2.0.0.tar.gz

Download URL janelkit_router-0.2.0.0.tar.gz
Size 20.0 kB
Tags Source
SHA-256 checksum
How to use checksums
f078d970b7ed82248b61724411cd922713890a1c9479ba0382660483603aa308
BLAKE2b-256 checksum
How to use checksums
befd83fa4b5e878d07a074452ad50a5a534f0d4e94a577c68f471ff344252885
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Release files / janelkit_router-0.2.0.0-py3-none-any.whl

Download URL janelkit_router-0.2.0.0-py3-none-any.whl
Size 11.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d0ee4961245078849e5566672c81b796888ddbd121743a438b366aee7183c935
BLAKE2b-256 checksum
How to use checksums
468cf331fae54e3316cd484bf6bed5e150b35d0527b2025ad53a9ffaed5b1afa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Security for janelkit-router 0.2.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for janelkit_router-0.2.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page