La boucle

Un panneau définit view(state) et, si besoin, initial(), on_open(state) et on_action(action, state). Clink appelle initial() une fois pour l'état de départ, on_open à chaque apparition du panneau, puis view(state) pour construire l'interface. Un contrôle insère du texte là où vous écrivez, fixe un nouvel état, ou nomme une action que on_action traite, et la vue est reconstruite.

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 state
Le panneau de départ, tel que le crée le bouton Nouveau panneau de l'éditeur.

Calculatrices, tableaux de snippets, sélecteurs : tes panneaux apparaissent derrière le bouton de panneau du clavier.

Constructeurs

view(state) renvoie des nœuds créés par ces 19 fonctions. Imbriquez-les librement : les piles et les grilles prennent une liste d'enfants.

ConstructeurCe qu’il dessine
vstack(children, spacing=6, align="leading")Empile ses enfants vers le bas du panneau.
hstack(children, spacing=6, align="center")Empile ses enfants en largeur.
grid(children, columns=4, spacing=6)Répartit ses enfants en colonnes égales.
wrap(children, spacing=6)Répartit ses éléments dans la largeur du panneau et passe à la ligne suivante.
scroll(children, spacing=6)Une zone défilante à part, pour une liste plus longue que le panneau.
card(children, padding=10, color="")Regroupe ses éléments sur une surface, avec une marge autour.
spacer(size=0)Pousse ce qui suit jusqu'au bord.
divider()Un filet entre deux rangées.
text(s, size=17, weight="regular", color="", align="leading", lines=0, mono=False)Une ligne de texte. weight accepte regular, medium, semibold, bold, heavy, light ou thin ; align accepte leading, center ou trailing ; lines limite le nombre de lignes ; color accepte un nom de couleur ou #RRGGBB.
icon(name, size=20, color="")Un SF Symbol, par son nom.
badge(s, color="")Un mot court dans une pastille colorée.
progress(value, total=1, label="")Une barre remplie jusqu'à value sur total.
button(label, action="", value=None, insert="", set=None, style="plain", icon="", enabled=True)Un bouton. insert écrit son texte dans ce que vous êtes en train d'écrire, set fusionne des clés dans l'état, et action nomme un gestionnaire pour on_action. style accepte plain, primary, tinted, quiet ou destructive.
row(title, subtitle="", detail="", icon="", action="", value=None, insert="")Une ligne que l'on touche : un titre, une deuxième ligne, une icône et un détail à droite.
toggle(label, on=False, key="", action="")Un interrupteur. key écrit True ou False dans cette clé d'état.
slider(value, min=0, max=100, step=1, label="", key="", action="")Un curseur entre min et max. key écrit la position dans cette clé d'état.
stepper(value, min=0, max=100, step=1, label="", key="", action="")Une valeur avec − et + à côté, entre min et max.
segmented(options, value=None, key="", action="")Un choix dans une liste. key écrit l'option retenue dans cette clé d'état.
field(key, placeholder="", action="", submit="")Une zone de texte liée à state[key]. En la touchant, les touches écrivent dans cette clé ; submit nomme le gestionnaire que déclenche Entrée.

Une simple chaîne fonctionne partout où un nœud fonctionne : elle s'affiche comme du texte à la taille par défaut.

Réagir à une touche

Un contrôle qui doit calculer quelque chose nomme une action au lieu de porter un set figé. Clink appelle alors on_action(action, state), ou on_action(action, value, state) si la valeur portée par le contrôle vous intéresse. L'état est un dictionnaire ordinaire : modifiez-le sur place sans rien renvoyer, ou renvoyez-en un nouveau.

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 state
Une liste que l'on complète, et dans laquelle on puise d'une touche.

on_open(state) s'exécute à chaque apparition du panneau ; c'est là qu'un panneau part de ce que vous êtes en train d'écrire.

Demander au clavier

Depuis on_action et on_open, un panneau peut demander au clavier ce qu'une valeur de retour ne sait pas exprimer. Chaque appel est noté puis appliqué une fois votre fonction terminée : un panneau ne modifie donc jamais le champ pendant que sa propre vue se construit.

Commandes

  • 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 state
Remplacer le mot au curseur par le même entre guillemets.

context() lit ce qui entoure le curseur : before, selected, after, word, clipboard, locale, language, full_access et time. C’est un instantané pris au début de l’appel, il ne peut donc pas changer sous vos pieds en plein rendu.

L'état

L'état est un dictionnaire ordinaire et contient tout ce qu'un script sait construire : nombres, chaînes, booléens, None, listes et dictionnaires de ceux-ci. Il vous est rendu à chaque appel : une liste complétée lors d'une touche est encore là à la suivante.

def initial():
    return {"name": ""}

def view(state):
    return vstack([
        field("name", placeholder="Who?"),
        button("Greet", insert="Hi " + state["name"] + "!", style="primary"),
    ])
Un champ écrit directement dans la clé d'état que vous nommez.

Mémoriser l'état conserve le contenu du panneau d'une ouverture à l'autre, et d'une session du clavier à l'autre. À laisser désactivé pour une calculatrice, à activer pour une liste.

L'état vit tant que le clavier est à l'écran, et plus longtemps quand le panneau se souvient. Un panneau peut lire le texte autour du curseur avec context() ; rien d'autre à votre sujet.

Limites

Un clavier reçoit une fraction de la mémoire d'une app : les panneaux sont donc bornés plutôt que crus sur parole. Chaque rendu dispose de 2 000 000 pas d'interpréteur, et une boucle emballée se termine par une erreur à l'écran au lieu d'un clavier qui ne répond plus.

Un panneau qui arrive sous forme de fichier ou depuis un dépôt est vérifié avant d'être enregistré. Il doit rester sous 48 000 octets et 1 200 lignes, définir def view(, chaque import doit nommer l'un des espaces de noms isolés, et ces fragments sont refusés d'emblée :

Refusé dans un panneau partagé

  • __
  • exec(
  • eval(
  • open(
  • compile(

Importable dans un panneau partagé

  • json
  • math
  • random
  • re
  • sys
  • time

Les panneaux que vous écrivez dans l'app ne sont pas soumis à cette liste. Seul le budget de pas arrêtera alors une boucle emballée : laissez-lui une sortie.

Emplacement

Donne à chaque panneau son propre bouton dans le sélecteur, plutôt que de les imbriquer derrière un seul bouton Panneaux. Chaque panneau peut modifier ce réglage dans son éditeur.

Par défaut suit ce réglage, Indépendant prend toujours son propre bouton, et Groupé s'imbrique toujours.

En écrire un

  1. Ouvrez Panneaux personnalisés dans Clink et touchez Nouveau panneau.
  2. Écrivez le script. Un aperçu exécute le vrai panneau à côté, et les erreurs s'affichent au fil de la frappe.
  3. Enregistrez, activez le panneau, puis ouvrez le bouton des panneaux sur le clavier.

Panneau de partage écrit un fichier .clinkpanel, qui est du JSON. En l'ouvrant à nouveau dans Clink, il est enregistré avec un nouvel identifiant : importer deux fois le même panneau n'écrase jamais le premier.

Créateur ›
Télécharger dans l’App Store