O ciclo
Um painel define view(state) e, se quiser, initial(), on_open(state) e on_action(action, state). O Clink chama initial() uma vez para o estado inicial, on_open sempre que o painel aparece, e depois view(state) para construir a interface. Um controlo insere texto onde está a escrever, define estado novo, ou indica uma ação que on_action trata, e a vista é construída de novo.
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, quadros de snippets, seletores: os teus painéis aparecem atrás do botão de painel do teclado.
Construtores
view(state) devolve nós criados por estas 19 funções. Aninhe-as à vontade: pilhas e grelhas aceitam uma lista de filhos.
| Construtor | O que desenha |
|---|---|
vstack(children, spacing=6, align="leading") | Empilha os filhos para baixo no painel. |
hstack(children, spacing=6, align="center") | Empilha os filhos ao longo do painel. |
grid(children, columns=4, spacing=6) | Distribui os filhos por colunas iguais. |
wrap(children, spacing=6) | Distribui os elementos pela largura do painel e continua na linha seguinte. |
scroll(children, spacing=6) | Uma área de rolagem própria, para uma lista maior que o painel. |
card(children, padding=10, color="") | Agrupa os elementos numa superfície, com espaço à volta. |
spacer(size=0) | Empurra o que vier a seguir até ao extremo. |
divider() | Um traço fino entre linhas. |
text(s, size=17, weight="regular", color="", align="leading", lines=0, mono=False) | Uma linha de texto. weight aceita regular, medium, semibold, bold, heavy, light ou thin; align aceita leading, center ou trailing; lines limita quantas linhas ocupa; color aceita um nome de cor ou #RRGGBB. |
icon(name, size=20, color="") | Um SF Symbol, pelo nome. |
badge(s, color="") | Uma palavra curta numa cápsula colorida. |
progress(value, total=1, label="") | Uma barra preenchida até value sobre total. |
button(label, action="", value=None, insert="", set=None, style="plain", icon="", enabled=True) | Um botão. insert escreve o seu texto naquilo que está a escrever, set funde chaves no estado e action indica um tratador para on_action. style aceita plain, primary, tinted, quiet ou destructive. |
row(title, subtitle="", detail="", icon="", action="", value=None, insert="") | Uma linha tocável: um título, uma segunda linha, um ícone e um detalhe à direita. |
toggle(label, on=False, key="", action="") | Um interruptor. key escreve True ou False nessa chave do estado. |
slider(value, min=0, max=100, step=1, label="", key="", action="") | Um cursor entre min e max. key escreve a posição nessa chave do estado. |
stepper(value, min=0, max=100, step=1, label="", key="", action="") | Um valor com − e + ao lado, entre min e max. |
segmented(options, value=None, key="", action="") | Uma escolha de uma lista. key escreve a opção escolhida nessa chave do estado. |
field(key, placeholder="", action="", submit="") | Uma caixa de texto ligada a state[key]. Ao tocá-la, as teclas escrevem nessa chave; submit indica o tratador que o Return executa. |
Uma string simples serve onde um nó serve: aparece como texto no tamanho predefinido.
Responder a um toque
Um controlo que precisa de calcular alguma coisa indica uma action em vez de levar um set fixo. O Clink chama então on_action(action, state), ou on_action(action, value, state) quando quer o valor que o controlo traz. O estado é um dicionário normal: pode alterá-lo no lugar e não devolver nada, ou devolver um novo.
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) corre sempre que o painel aparece; é aí que um painel parte do que está a escrever.
Pedir ao teclado
A partir de on_action e on_open, um painel pode pedir ao teclado coisas que um valor devolvido não consegue exprimir. Cada chamada é registada e aplicada depois de a sua função terminar, por isso um painel nunca edita o campo enquanto a sua própria vista está a ser construída.
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() lê o que está à volta do cursor: before, selected, after, word, clipboard, locale, language, full_access e time. É um instantâneo tirado quando a chamada começou, por isso não pode mudar por baixo a meio da renderização.
Estado
O estado é um dicionário normal e guarda tudo o que um script consegue construir: números, cadeias, booleanos, None, e listas e dicionários disso. É-lhe devolvido em cada chamada, por isso uma lista à qual acrescentou num toque continua lá no toque seguinte.
def initial():
return {"name": ""}
def view(state):
return vstack([
field("name", placeholder="Who?"),
button("Greet", insert="Hi " + state["name"] + "!", style="primary"),
])Lembrar o estado mantém o que o painel contém entre aberturas e entre sessões do teclado. Deixe desligado para uma calculadora; ligue para uma lista.
O estado vive enquanto o teclado está no ecrã, e mais tempo quando o painel se lembra. Um painel pode ler o texto à volta do cursor com context(); mais nada sobre si.
Limites
Um teclado recebe uma fração da memória de uma app, por isso os painéis são limitados em vez de confiáveis à partida. Cada desenho tem 2.000.000 passos de interpretador, e um ciclo descontrolado acaba com um erro no ecrã em vez de um teclado que deixa de responder.
Um painel que chega como ficheiro ou de um repositório é verificado antes de ser guardado. Tem de ficar abaixo de 48.000 bytes e 1.200 linhas, tem de definir def view(, cada import tem de nomear um dos espaços de nomes isolados, e estes fragmentos são recusados sem mais:
Recusado num painel partilhado
__exec(eval(open(compile(
Importável num painel partilhado
jsonmathrandomresystime
Os painéis que escreve na app não estão sujeitos a essa lista. Aí só o orçamento de passos travará um ciclo desgovernado, por isso dê-lhe uma saída.
Posicionamento
Dá a cada painel o seu próprio botão no seletor, em vez de os aninhar todos atrás de um único botão Painéis. Cada painel pode substituir isto no seu editor.
Predefinição segue esse interruptor, Independente fica sempre com um botão próprio e Agrupado aninha sempre.
Escrever um
- Abra Painéis personalizados no Clink e toque em Novo painel.
- Escreva o script. Ao lado corre uma pré-visualização do painel real e os erros aparecem enquanto escreve.
- Guarde, ligue o painel e abra o botão de painéis no teclado.
Painel de partilha cria um ficheiro .clinkpanel, que é JSON. Ao abri-lo de novo no Clink fica guardado com um id novo, por isso importar o mesmo painel duas vezes nunca substitui o primeiro.
Criador ›