# Formulários para modelos Typst

Dê um formulário às suas próprias funções Typst, para que quem preenche um relatório veja campos com rótulo no modo Visual em vez da sintaxe de chamada de função.

Um modelo Typst costuma trazer as próprias funções: uma folha de rosto, uma caixa de informações, um bloco de aprovação. Quem escreve o relatório as chama, como em `#info-box(title: "Supply risk", tone: "risk")[...]`. Se você mantém o modelo, pode descrever os argumentos de cada função uma só vez. O modo Visual passa então a mostrar cada chamada a essa função como um formulário: campos com rótulo, uma lista para opções fixas, um interruptor para sim ou não. Editar um campo reescreve apenas aquele argumento no arquivo `.typ`, então o relatório continua sendo código-fonte Typst comum, que compila do mesmo jeito.

## O que o leitor vê

Uma chamada em linhas próprias vira um **cartão**. O cabeçalho do cartão mostra o nome do formulário e, se você escolher um, um resumo curto, como o título da caixa. Cada argumento ganha uma linha com o rótulo e um controle.

Uma chamada dentro de uma frase, como `#badge("review")`, vira um **chip** na linha de texto. Clicar no chip abre os mesmos campos em um pequeno popover.

Os campos de texto e de marcação são salvos quando você pressiona Enter (⌘ Enter ou Ctrl Enter em um campo de várias linhas) ou sai do campo. Esc devolve o valor antigo. As listas e os interruptores são salvos na hora. Cada alteração é uma etapa de desfazer.

Pôr o cursor dentro de uma chamada mostra o código-fonte dela, como em qualquer outro elemento do modo Visual. **Editar no código**, no cartão, faz o mesmo.

## Onde declarar os formulários

Há dois lugares, com o mesmo formato:

- **Em um pacote.** Acrescente uma seção `[tool.oleafly]` ao `typst.toml` do pacote. O Typst reserva as seções `[tool.*]` para outras ferramentas, então o pacote continua sendo instalado e compilado em qualquer lugar. Isso vale para pacotes `@local` e para pacotes `@preview` do Typst Universe.
- **No projeto.** Para modelos mantidos como arquivos `.typ` simples dentro do projeto, crie `oleafly-forms.toml` na raiz do projeto. Cada formulário também nomeia, com `module`, o arquivo que define a função.

Um formulário de pacote:

```toml
[tool.oleafly]
schema = 1

[[tool.oleafly.forms]]
function = "info-box"
label = "Info box"
summary = "title"

  [[tool.oleafly.forms.fields]]
  arg = "title"
  kind = "text"
  label = "Heading"
  placeholder = "Short heading"
  required = true

  [[tool.oleafly.forms.fields]]
  arg = "tone"
  kind = "choice"
  label = "Tone"
  default = "note"
  options = [{ value = "note", label = "Note" }, { value = "risk", label = "Risk" }, "neutral"]

  [[tool.oleafly.forms.fields]]
  arg = 0
  kind = "content"
  label = "Text"
```

Um formulário de projeto, em `oleafly-forms.toml`:

```toml
[tool.oleafly]
schema = 1

[[tool.oleafly.forms]]
module = "template/memo.typ"
function = "memo-header"
label = "Memo header"
fields = [
  { arg = "to", kind = "text", label = "To" },
  { arg = "subject", kind = "text", label = "Subject" },
]
```

## As chaves

`schema = 1` é obrigatório. Um arquivo sem ele, ou com outro número, é ignorado.

Cada entrada `[[tool.oleafly.forms]]` tem:

| Chave | Obrigatória | Significado |
| --- | --- | --- |
| `function` | Sim | O nome da função, como um único identificador do Typst. Hífens são permitidos. |
| `module` | Só em `oleafly-forms.toml` | O arquivo do projeto que define a função, relativo à raiz do projeto, com `/` entre as pastas. |
| `label` | Não | O nome do formulário em cartões e chips. O padrão é o nome da função. |
| `summary` | Não | O argumento cujo valor aparece ao lado do rótulo, escrito como o `arg` de um campo. |
| `fields` | Sim | Um ou mais campos. |

Cada campo tem:

| Chave | Obrigatória | Significado |
| --- | --- | --- |
| `arg` | Sim | Um nome para um argumento nomeado (`"title"`), ou um número para um posicional (`0` é o primeiro). Um bloco `[...]` no final conta como um argumento posicional depois dos que estão entre parênteses. |
| `kind` | Sim | `text`, `content`, `choice`, `number` ou `toggle`. |
| `label` | Sim | O rótulo do campo. |
| `help` | Não | Uma nota curta sob o campo. |
| `placeholder` | Não | Texto cinza em um campo vazio. |
| `required` | Não | `true` marca um campo vazio como ausente e esconde o botão **Limpar** dele. O Oleafly nunca adiciona o argumento sozinho. |
| `default` | Não | O valor que a sua função usa quando o argumento é omitido. Ele é mostrado, nunca escrito. |

Os tipos e as chaves extras deles:

- `text` escreve uma string do Typst. Acrescente `multiline = true` para uma caixa maior.
- `content` edita a marcação do Typst e a escreve como um bloco `[...]`. Um argumento de string continua sendo uma string.
- `choice` precisa de `options`: uma lista de strings, ou tabelas `{ value, label }` quando o rótulo difere do valor. Os valores são escritos como strings.
- `number` aceita `integer`, `min`, `max` e `step`. Os números não têm unidades.
- `toggle` escreve `true` ou `false`.

## Quais chamadas ganham um formulário

O Oleafly segue as linhas `#import` e `#let` do próprio relatório, no nível superior do arquivo:

- `#import "@local/acme-report:0.1.0" as acme` faz de `#acme.info-box(...)` um formulário.
- `#import "@local/acme-report:0.1.0": info-box, status-badge as badge` faz de `#info-box(...)` e `#badge(...)` formulários.
- `#import "@local/acme-report:0.1.0": *` dá um formulário a cada função para a qual o pacote declara um.
- `#import "template/memo.typ": memo-header` corresponde a um formulário de projeto cujo `module` é `template/memo.typ`. Os caminhos são lidos a partir da pasta do próprio relatório, ou da raiz do projeto quando começam com `/`.

A versão do pacote precisa ser exatamente a mesma. Um `#let` com o mesmo nome, mais adiante no arquivo, substitui o formulário a partir desse ponto. As chamadas alcançadas por outro arquivo que reimporta o pacote mantêm o texto do código-fonte.

Uma função com o nome de um elemento do Typst que o modo Visual já desenha, como `table` ou `figure`, mantém a aparência embutida quando chamada só pelo nome. `#acme.table(...)` ou uma importação renomeada ainda recebe o formulário.

## Campos mostrados como somente leitura

Alguns argumentos não podem ser editados com segurança por um formulário. A linha deles mostra o código-fonte com o motivo, e **Editar no código** salta para ele:

- **Calculado no código:** o valor é uma expressão, como `title: data.title`.
- **Escrito como outro tipo de valor:** por exemplo, um número onde o formulário espera texto.
- **Não é uma das opções:** um valor que as suas `options` não listam.
- **Definido por um argumento spread:** uma chamada com `..args` passa valores que o formulário não vê, então todos os campos ficam somente leitura.

Quando um campo não pode ser adicionado onde iria, por exemplo um argumento posicional depois de um ausente, o formulário avisa e oferece **Adicionar no código**.

## Erros em uma definição

Abra `oleafly-forms.toml`, ou o `typst.toml` de um pacote incorporado, no Oleafly e cada problema aparece como um marcador na linha dele: um tipo desconhecido, um rótulo ausente, um formulário duplicado, um `module` fora do projeto. Um formulário com defeito é deixado de fora e os outros continuam funcionando. Um arquivo maior que 256 KB não é lido.

## Compartilhe os modelos

O Oleafly lê os formulários dos pacotes nas mesmas pastas que o compilador usa. Um colaborador que não tem o pacote `@local` vê o código-fonte simples e nenhum erro. Para compartilhar os formulários com todos em um projeto, abra o diálogo **Pacotes Typst**, ligue **Usar pacotes da pasta do projeto** e escolha **Incorporar os pacotes ao projeto**. O pacote, e os formulários dele, passam então a viajar na pasta `typst-packages` do projeto (veja [Projetos Typst](/docs/typst/)).
