El ciclo
Un panel define view(state) y, opcionalmente, initial(), on_open(state) y on_action(action, state). Clink llama a initial() una vez para el estado inicial, a on_open cada vez que aparece el panel, y luego a view(state) para construir la interfaz. Un control inserta texto donde estás escribiendo, fija estado nuevo o nombra una acción que on_action atiende, y la vista se construye otra vez.
def initial():
return {"count": 0, "step": 1}
def view(state):
return vstack([
text(f"{state['count']}", size=34, weight="bold", align="center"),
segmented(["1", "5", "10"], value=str(state["step"]), action="step"),
hstack([
button("−", "bump", value=-1),
button("+", "bump", value=1, style="primary"),
]),
button("Type it", "type", icon="keyboard"),
])
def on_action(action, value, state):
if action == "bump":
state["count"] = state["count"] + value * state["step"]
elif action == "step":
state["step"] = int(value)
elif action == "type":
insert(str(state["count"]))
close()
return stateCalculadoras, tableros de fragmentos, selectores: tus paneles aparecen detrás del botón de panel del teclado.
Constructores
view(state) devuelve nodos creados por estas 19 funciones. Anídalas con libertad: las pilas y las cuadrículas aceptan una lista de hijos.
| Constructor | Qué dibuja |
|---|---|
vstack(children, spacing=6, align="leading") | Apila sus hijos hacia abajo en el panel. |
hstack(children, spacing=6, align="center") | Apila sus hijos a lo ancho del panel. |
grid(children, columns=4, spacing=6) | Distribuye sus hijos en columnas iguales. |
wrap(children, spacing=6) | Distribuye sus elementos a lo ancho del panel y sigue en la línea siguiente. |
scroll(children, spacing=6) | Una zona con desplazamiento propio, para una lista más larga que el panel. |
card(children, padding=10, color="") | Agrupa sus elementos sobre una superficie, con margen alrededor. |
spacer(size=0) | Empuja lo que venga después hasta el extremo. |
divider() | Una línea fina entre filas. |
text(s, size=17, weight="regular", color="", align="leading", lines=0, mono=False) | Una línea de texto. weight admite regular, medium, semibold, bold, heavy, light o thin; align admite leading, center o trailing; lines limita a cuántas líneas se parte; color admite un nombre de color o #RRGGBB. |
icon(name, size=20, color="") | Un SF Symbol, por su nombre. |
badge(s, color="") | Una palabra corta en una cápsula de color. |
progress(value, total=1, label="") | Una barra llena hasta value sobre total. |
button(label, action="", value=None, insert="", set=None, style="plain", icon="", enabled=True) | Un botón. insert escribe su texto en lo que estés redactando, set fusiona claves en el estado y action nombra un manejador para on_action. style admite plain, primary, tinted, quiet o destructive. |
row(title, subtitle="", detail="", icon="", action="", value=None, insert="") | Una fila que se puede tocar: un título, una segunda línea, un icono y un detalle a la derecha. |
toggle(label, on=False, key="", action="") | Un interruptor. key escribe True o False en esa clave del estado. |
slider(value, min=0, max=100, step=1, label="", key="", action="") | Un deslizador entre min y max. key escribe la posición en esa clave del estado. |
stepper(value, min=0, max=100, step=1, label="", key="", action="") | Un valor con − y + al lado, entre min y max. |
segmented(options, value=None, key="", action="") | Una opción de una lista. key escribe la elegida en esa clave del estado. |
field(key, placeholder="", action="", submit="") | Un cuadro de texto ligado a state[key]. Al tocarlo, las teclas escriben en esa clave; submit nombra el manejador que ejecuta Intro. |
Una cadena simple sirve allí donde sirve un nodo: se dibuja como texto en el tamaño por defecto.
Responder a un toque
Un control que tiene que calcular algo nombra una action en lugar de llevar un set literal. Clink llama entonces a on_action(action, state), o a on_action(action, value, state) cuando quieres el valor que lleva el control. El estado es un diccionario normal: puedes cambiarlo en el sitio y no devolver nada, o devolver uno nuevo.
def initial():
return {"items": [], "draft": ""}
def view(state):
return vstack([
field("draft", placeholder="Add one…", submit="add"),
scroll([row(item, action="use", value=item) for item in state["items"]]),
])
def on_action(action, value, state):
if action == "add" and value:
state["items"].append(value)
state["draft"] = ""
elif action == "use":
insert(value)
close()
return stateon_open(state) se ejecuta cada vez que aparece el panel; ahí es donde un panel parte de lo que estás escribiendo.
Pedirle algo al teclado
Desde on_action y on_open un panel puede pedirle al teclado cosas que un valor devuelto no puede expresar. Cada llamada se anota y se aplica cuando tu función termina, así que un panel nunca edita el campo mientras se está construyendo su propia vista.
Comandos
insert()backspace()delete_word()replace()move_cursor()copy()close()haptic()toast()
def on_action(action, state):
if action == "quote":
word = context()["word"]
replace(len(word), "“" + word + "”")
haptic("light")
return statecontext() lee lo que hay alrededor del cursor: before, selected, after, word, clipboard, locale, language, full_access y time. Es una instantánea tomada al empezar la llamada, así que no puede cambiarte por debajo a mitad del render.
Estado
El estado es un diccionario normal y guarda todo lo que un script puede construir: números, cadenas, booleanos, None, y listas y diccionarios de todo eso. Se te devuelve en cada llamada, así que una lista a la que añadiste en un toque sigue ahí en el siguiente.
def initial():
return {"name": ""}
def view(state):
return vstack([
field("name", placeholder="Who?"),
button("Greet", insert="Hi " + state["name"] + "!", style="primary"),
])Recordar el estado conserva lo que el panel contiene entre aperturas y entre sesiones del teclado. Déjalo desactivado para una calculadora; actívalo para una lista.
El estado vive mientras el teclado está en pantalla, y más si el panel recuerda. Un panel puede leer el texto que rodea al cursor con context(); nada más sobre ti.
Límites
Un teclado recibe una fracción de la memoria de una app, así que los paneles están acotados en vez de ser de confianza. Cada renderizado dispone de 2.000.000 pasos de intérprete, y un bucle desbocado termina con un error en pantalla en lugar de dejar el teclado sin responder.
Un panel que llega como archivo o desde un repositorio se comprueba antes de guardarlo. Tiene que ocupar menos de 48.000 bytes y 1200 líneas, tiene que definir def view(, cada import tiene que nombrar uno de los espacios de nombres aislados, y estos fragmentos se rechazan de plano:
Rechazado en un panel compartido
__exec(eval(open(compile(
Importable en un panel compartido
jsonmathrandomresystime
Los paneles que escribes en la app no están sujetos a esa lista. Entonces lo único que detendrá un bucle desbocado es el presupuesto de pasos, así que dale una salida.
Ubicación
Da a cada panel su propio botón en el selector, en lugar de anidarlos todos detrás de un único botón Paneles. Cada panel puede anular esto en su editor.
Predeterminado sigue ese ajuste, Independiente siempre ocupa su propio botón y Agrupado siempre se anida.
Escribir uno
- Abre Paneles personalizados en Clink y toca Nuevo panel.
- Escribe el script. Al lado se ejecuta una vista previa del panel real y los errores aparecen mientras escribes.
- Guarda, activa el panel y abre el botón de paneles del teclado.
Panel de compartir crea un archivo .clinkpanel, que es JSON. Al abrirlo de vuelta en Clink se guarda con un id nuevo, así que importar el mismo panel dos veces nunca sobrescribe el primero.
Creador ›