> ## Documentation Index
> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Disegnare nell'interfaccia con un mod

> Disegnare riquadri, una banda sopra il prompt, pulsanti e campi di testo da un mod di Claude Code, gestire pressioni e input, e mantenere lo stato tra i ridisegni e le sessioni.

Un mod può disegnare la propria interfaccia in Claude Code e modificare parti dell'interfaccia che Claude Code disegna già. Ogni luogo in cui un mod può disegnare è chiamato [sito di rendering](/docs/it/plugins/mods/reference#render-sites), come un riquadro, la banda sopra il prompt, o lo spinner. Claude Code genera l'evento [`ui.render`](/docs/it/plugins/mods/reference#interface) ogni volta che sta per disegnare un sito di rendering, e il tuo hook per quell'evento restituisce cosa disegnare lì.

Questa mappa mostra dove un mod può disegnare in una sessione terminale:

<img src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-screen-map.svg?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=5fda26b6609c62b68c6f9e528c1590ea" className="dark:hidden" alt="Mappa di una sessione terminale di Claude Code. Un mod può aggiungere un riquadro come barra laterale sulla destra, un toast in alto a destra della trascrizione, una riga di log nella trascrizione, una banda sopra il prompt, e una riga di stato sotto il prompt. Un mod può ridisegnare messaggi, righe di chiamate di strumenti, e lo spinner. Il prompt è proprio di Claude Code." width="600" height="336" data-path="images/mods-screen-map.svg" />

<img src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-screen-map-dark.svg?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=5b4161581a1bd2c0450b0c8b57bc1225" className="hidden dark:block" alt="Mappa di una sessione terminale di Claude Code. Un mod può aggiungere un riquadro come barra laterale sulla destra, un toast in alto a destra della trascrizione, una riga di log nella trascrizione, una banda sopra il prompt, e una riga di stato sotto il prompt. Un mod può ridisegnare messaggi, righe di chiamate di strumenti, e lo spinner. Il prompt è proprio di Claude Code." width="600" height="336" data-path="images/mods-screen-map-dark.svg" />

In un terminale più stretto, il riquadro si trova sopra il prompt invece che accanto alla trascrizione.

Costruisci il tuo [primo mod](/docs/it/plugins/mods/create) prima di iniziare qui. Inizia con l'esempio pratico, che costruisce un riquadro con due schede e un contatore, quindi leggi la sezione per ogni parte che desideri modificare.

<Note>
  Per cercare una proprietà o un limite, consulta il [riferimento](/docs/it/plugins/mods/reference#render-sites).
</Note>

<h2 id="build-a-pane-with-tabs">
  Costruire un riquadro con schede
</h2>

In questa sezione costruisci un mod che aggiunge un comando `/hello-tabs` e il comando apre un riquadro. Un riquadro è una barra laterale accanto alla trascrizione in un terminale fullscreen ampio, o una regione incorniciata sopra il prompt altrimenti. Questo riquadro mostra due schede, e la seconda scheda ha un pulsante che aggiunge uno a un contatore. Il conteggio è ancora lì dopo aver riavviato Claude Code.

Il mod finito assomiglia a questo. La registrazione apre il riquadro, passa alla seconda scheda, preme il pulsante alcune volte e ritorna alla prima scheda:

<Frame>
  <video autoPlay muted loop playsInline controls className="w-full dark:hidden" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-hello-tabs-light.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=49d520094d87b5b44bfe50fa49677f06" aria-label="Il comando /hello-tabs viene digitato al prompt di Claude Code e un riquadro incorniciato si apre sopra di esso, con '1: One' e '2: Two' nella parte superiore e il testo 'This is the first tab.' La seconda scheda mostra un pulsante 'Add one' accanto a 'Count: 1', e il conteggio sale a 3. Il riquadro ritorna quindi alla prima scheda." data-path="images/mods-hello-tabs-light.mp4" />

  <video autoPlay muted loop playsInline controls className="w-full hidden dark:block" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-hello-tabs-dark.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=ff7a14d713d6e5d3b0000efa8522ea4b" aria-label="Il comando /hello-tabs viene digitato al prompt di Claude Code e un riquadro incorniciato si apre sopra di esso, con '1: One' e '2: Two' nella parte superiore e il testo 'This is the first tab.' La seconda scheda mostra un pulsante 'Add one' accanto a 'Count: 1', e il conteggio sale a 3. Il riquadro ritorna quindi alla prima scheda." data-path="images/mods-hello-tabs-dark.mp4" />
</Frame>

Claude Code non ha un elemento schede integrato, quindi le schede sono due pulsanti in una riga. Il mod tiene traccia di quale è attivo e disegna il contenuto di quella scheda sotto la riga.

<Steps>
  <Step title="Creare il plugin">
    Un mod è un plugin con un manifesto, un `hooks.json` che punta al tuo codice, e il file di codice. [Creare un mod](/docs/it/plugins/mods/create#write-a-mod-yourself) spiega ognuno. Crea una directory denominata `hello-tabs` con directory `.claude-plugin` e `hooks` al suo interno, quindi salva i primi due file.

    Salva il manifesto come `hello-tabs/.claude-plugin/plugin.json`:

    ```json hello-tabs/.claude-plugin/plugin.json theme={null}
    {
      "name": "hello-tabs",
      "version": "0.1.0",
      "description": "Opens a pane with two tabs and a counter",
      "author": { "name": "Your Name" }
    }
    ```

    Nomina il tuo punto di ingresso in `hello-tabs/hooks/hooks.json`:

    ```json hello-tabs/hooks/hooks.json theme={null}
    {
      "modules": ["./register.js"]
    }
    ```
  </Step>

  <Step title="Scrivere il codice">
    Il codice fa tre lavori, uno in ogni hook:

    * Aggiunge il comando `/hello-tabs`
    * Apre il riquadro quando esegui quel comando
    * Disegna il contenuto del riquadro: la riga di schede e il corpo della scheda aperta

    Due variabili a livello di modulo, `tab` e `count`, mantengono lo stato del riquadro.

    Salva questo come `hello-tabs/hooks/register.js`:

    ```javascript hello-tabs/hooks/register.js theme={null}
    // L'id del riquadro, utilizzato per aprire il riquadro e per riconoscerlo durante il disegno
    const PANE = 'hello-tabs'

    // Cosa mostra il riquadro: quale scheda è aperta e il valore del contatore
    let tab = 'one'
    let count = 0

    export function register(on) {
      // Viene eseguito prima del tuo primo prompt, e di nuovo dopo un ricaricamento
      on('session.start', async ($, e, next) => {
        await $.command.register({ name: 'hello-tabs', description: 'Open the hello-tabs pane' })
        // Carica il conteggio che una sessione precedente ha salvato, se ce n'è uno
        const saved = await $.store.get('count')
        if (typeof saved === 'number') count = saved
        return next(e)
      })

      // Viene eseguito quando digiti /hello-tabs
      on('command.run', { command: 'hello-tabs' }, async ($) => {
        // Apri il riquadro, dagli la tastiera, e lascia che Esc lo chiuda
        await $.ui.open({ id: PANE, title: 'Hello tabs', focus: true, closeOnEscape: true })
        // Non stampare nulla nella trascrizione
        return {}
      })

      // Viene eseguito ogni volta che Claude Code disegna un riquadro
      on('ui.render', { component: 'Pane' }, async ($, e, next) => {
        // Lascia in pace i riquadri degli altri mod
        if (e.requestId !== PANE) return next(e)
        // Ottieni gli elementi che questa app può disegnare
        const { Box, Text, Button } = $.ui.resolve(e)
        // Chiedi a Claude Code di eseguire di nuovo questo hook
        const redraw = () => $.ui.invalidate('ui.render')

        // Una scheda: un pulsante che passa a quella scheda quando viene premuto
        const tabButton = (name, label, hotkey) =>
          Button({
            key: 'tab-' + name,
            label,
            hotkey,
            plain: true,
            // Attenua la scheda che non è aperta
            dimColor: tab !== name,
            onPress: () => {
              tab = name
              redraw()
            },
          })

        // Cosa va sotto le schede, a seconda di quale è aperta
        const body =
          tab === 'one'
            ? [Text({ children: ['This is the first tab.'] })]
            : [
                Box({
                  flexDirection: 'row',
                  columnGap: 2,
                  children: [
                    Button({
                      key: 'more',
                      label: 'Add one',
                      hotkey: 'a',
                      onPress: async () => {
                        count += 1
                        redraw()
                        // Salva il conteggio in modo che sia lì dopo un riavvio
                        await $.store.set('count', count)
                      },
                    }),
                    Text({ children: ['Count: ' + count] }),
                  ],
                }),
              ]

        // L'intero riquadro: la riga di schede, una riga vuota, quindi il corpo
        return Box({
          flexDirection: 'column',
          children: [
            Box({
              flexDirection: 'row',
              columnGap: 3,
              children: [tabButton('one', 'One', '1'), tabButton('two', 'Two', '2')],
            }),
            Text({ children: [' '] }),
            ...body,
          ],
        })
      })
    }
    ```

    Ogni hook fa anche qualcosa che il codice non rende evidente:

    * **[`session.start`](/docs/it/plugins/mods/reference#session)** legge anche il conteggio salvato da [`$.store`](#keep-state), un archivio chiave-valore che persiste tra le sessioni.
    * **[`command.run`](/docs/it/plugins/mods/api#add-a-command)** dice solo a Claude Code che il riquadro esiste. Aprire un riquadro non disegna nulla di per sé: Claude Code quindi genera `ui.render` per chiedere cosa metterci.
    * **`ui.render`** restituisce l'albero degli elementi, un `Box` che contiene altri box, testo e pulsanti, e lo costruisce di nuovo da `tab` e `count` ogni volta che viene eseguito.

    Premere un pulsante esegue il suo callback `onPress`, che cambia una variabile e chiama `redraw`. Claude Code quindi esegue di nuovo l'hook `ui.render`, e l'hook costruisce un nuovo albero dai nuovi valori. Ogni disegno interattivo utilizza quel ciclo di rendering: un callback cambia lo stato, e l'hook esegue il rendering di nuovo dal nuovo stato.
  </Step>

  <Step title="Aprire il riquadro">
    Nella tua shell, avvia Claude Code con `claude --plugin-dir ./hello-tabs`. Al prompt di Claude Code, esegui `/hello-tabs`. Un riquadro si apre con `1: One` e `2: Two` nella parte superiore. Premi `2`, quindi premi `a`, la scorciatoia da tastiera per **Add one**, alcune volte. Il conteggio aumenta.
  </Step>

  <Step title="Verificare che il conteggio sia stato salvato">
    Premi Esc per chiudere il riquadro, quindi esci dalla sessione. Nella tua shell, avvia di nuovo Claude Code con lo stesso comando `claude --plugin-dir ./hello-tabs`, e al prompt di Claude Code esegui `/hello-tabs`. Il conteggio è dove l'hai lasciato.

    Per cancellare il conteggio, fai in modo che il mod chiami `$.store.delete('count')`. [Mantenere lo stato](#keep-state) spiega quanto tempo dura ogni tipo di valore.
  </Step>
</Steps>

<h2 id="pick-where-to-draw">
  Scegliere dove disegnare
</h2>

Un hook `ui.render` viene eseguito per ogni sito di rendering a meno che non lo restringi a quello che desideri disegnare. Per scegliere il sito di rendering, passa un filtro, chiamato [matcher](/docs/it/plugins/mods/events#filter-which-events-a-hook-handles), come secondo argomento a `on`. `{ component: 'Pane' }` esegue l'hook solo per i riquadri. Nell'hook, `e.component` nomina il sito, `e.surface` dice quale app sta disegnando, e `e.props` contiene i dati propri del sito. Per un riquadro, `e.requestId` è l'`id` con cui l'hai aperto.

Due siti sono vuoti finché un mod non li riempie, il riquadro e la banda. Seleziona una scheda per vedere cosa è ognuno e come disegnare in esso:

<Tabs>
  <Tab title="Pane">
    Un riquadro è una barra laterale accanto alla trascrizione in un terminale fullscreen ampio, o una regione incorniciata sopra il prompt altrimenti. Con più riquadri aperti, ognuno ottiene una scheda che mostra il suo titolo.

    Un riquadro appare quando il tuo mod chiama `$.ui.open` con un `id` che scegli, come in `$.ui.open({ id: 'hello-tabs' })`. [Aprire un riquadro al momento giusto](#open-a-pane-at-the-right-time) copre gli altri campi e quando un riquadro aspetta un terminale più ampio.

    Per disegnare nel tuo riquadro, filtra su `{ component: 'Pane' }` e verifica che `e.requestId` sia il tuo `id`.
  </Tab>

  <Tab title="Band above the prompt">
    La banda è una striscia direttamente sopra l'input del prompt. È sempre lì, e ogni mod la condivide.

    Il tuo hook restituisce un albero per mostrare qualcosa nella banda, o `next(e)` per non mostrare nulla. Un albero sostituisce quello che i mod [dopo il tuo](/docs/it/plugins/mods/events#the-order-mods-run-in) disegnano lì. Per mantenere il loro, metti il risultato di `await next(e)` tra i figli di un [`Box`](#build-a-tree-from-elements) nel tuo albero.

    Per disegnare nella banda, filtra su `{ component: 'AbovePrompt' }`.
  </Tab>
</Tabs>

<h3 id="change-what-claude-code-already-draws">
  Modificare quello che Claude Code disegna già
</h3>

Claude Code disegna la maggior parte della sua interfaccia da solo: messaggi, righe di chiamate di strumenti, lo spinner, e altro. Ognuna di quelle parti è un sito di rendering anche, quindi un mod può ridisegnarlo o sostituirlo. Per modificarne uno, filtra il tuo hook `ui.render` sul suo nome da questa tabella:

| Sito | Cosa è |
| :- | :- |
| `UserMessage`, `AssistantMessage` | Un messaggio nella trascrizione |
| `ToolUse`, `ToolResult`, `ToolGroup` | La riga di una chiamata di strumento, il suo risultato, e un'esecuzione piegata di chiamate |
| `CommandOutput` | La riga che un comando ha stampato |
| `AskUserQuestion` | La finestra di dialogo che Claude apre per farti una domanda |
| `Spinner`, `ToolProgress`, `TurnDuration` | Righe di stato per un turno: la riga che si anima mentre Claude lavora, la riga di progresso dal vivo di uno strumento in esecuzione, e la riga che chiude un turno |
| `InfoNotice`, `SessionMode`, `PromptHint` | Righe di stato sotto il logo, le etichette della modalità nel piè di pagina, e la riga di suggerimento sotto il prompt |

In un sito che Claude Code disegna già, il tuo hook ha tre scelte: modificare un dettaglio, sostituire il disegno, o lasciarlo in pace. Seleziona una scheda per vedere ognuno applicato allo spinner. Gli esempi leggono una variabile `calls` che un altro hook conta, come nel [mod del tutorial](/docs/it/plugins/mods/create#write-a-mod-yourself).

<Tabs>
  <Tab title="Change a detail">
    Per mantenere il disegno di Claude Code e modificare una parte di esso, passa a `next` una copia dell'evento con `props` modificati. Questo hook cambia il testo dopo la parola dello spinner:

    ```javascript theme={null}
    on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
      // Mantieni lo spinner di Claude Code, e cambia il testo dopo la sua parola
      return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
    })
    ```

    Lo spinner mantiene la sua animazione e la sua parola, e il tuo testo segue la parola:

    ```text theme={null}
    Thinking · tool calls: 2…
    ```
  </Tab>

  <Tab title="Replace the drawing">
    Per disegnare qualcosa di tuo al posto del sito, restituisci un albero e non chiamare `next`. Questo hook disegna una riga di testo dove sarebbe lo spinner:

    ```javascript theme={null}
    on('ui.render', { component: 'Spinner' }, async ($, e) => {
      const { Text } = $.ui.resolve(e)
      // Nessuna chiamata a next, quindi questa riga viene disegnata al posto dello spinner
      return Text({ children: ['Claude has made ' + calls + ' tool calls'] })
    })
    ```

    Mentre Claude lavora, la tua riga si mostra e lo spinner di Claude Code non lo fa:

    ```text theme={null}
    Claude has made 2 tool calls
    ```
  </Tab>

  <Tab title="Leave it alone">
    Per lasciare il sito come Claude Code lo disegna, restituisci `next(e)`. Un hook spesso lo fa per alcuni eventi e non per altri. Questo hook lascia lo spinner in pace finché non c'è una chiamata da contare:

    ```javascript theme={null}
    on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
      // Niente da mostrare ancora, quindi passa l'evento invariato
      if (calls === 0) return next(e)
      return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
    })
    ```

    Prima della prima chiamata di strumento, lo spinner appare come farebbe senza il mod:

    ```text theme={null}
    Thinking…
    ```
  </Tab>
</Tabs>

Il prompt di autorizzazione non è un sito di rendering, quindi un mod non può modificare quello che mostra. La finestra di dialogo della domanda, `AskUserQuestion`, è uno, quindi un mod può modificare quello.

Il terminale e l'app Desktop non generano tutti gli stessi siti. `Pane`, `AbovePrompt`, `Spinner`, e i siti della trascrizione funzionano in entrambi. Poche altre righe di stato vengono generate solo nel terminale. La [tabella dei siti di rendering](/docs/it/plugins/mods/reference#render-sites) elenca dove viene generato ognuno.

<h3 id="open-a-pane-at-the-right-time">
  Aprire un riquadro al momento giusto
</h3>

Un riquadro appare solo quando il tuo mod lo apre. Come e quando lo apri decide se prende il focus della tastiera, quanto spazio chiede, e se appare affatto in un terminale stretto.

Per aprire un riquadro, chiama [`$.ui.open`](/docs/it/plugins/mods/reference#mods-api-methods) con un `id` che scegli. L'`id` è il nome del riquadro: il tuo hook `ui.render` lo controlla, e lo passi di nuovo per chiudere il riquadro.

```javascript theme={null}
await $.ui.open({ id: 'hello-tabs', title: 'Hello tabs', focus: true })
```

Per chiudere il riquadro, chiama `$.ui.close` con l'`id` con cui l'hai aperto:

```javascript theme={null}
await $.ui.close({ id: 'hello-tabs' })
```

Oltre a `id`, `$.ui.open` accetta questi campi opzionali:

| Campo | Cosa fa |
| :- | :- |
| `title` | L'etichetta della scheda del riquadro quando più di un riquadro è aperto |
| `focus` | Richiede il [focus della tastiera](#know-which-keys-your-mod-can-receive) |
| `closeOnEscape` | Fa chiudere il riquadro da Esc. Passa `true` o lascia il campo fuori, perché Claude Code rifiuta `false`. |
| `holdToasts` | Tiene i toast, i piccoli avvisi da [`$.ui.toast`](/docs/it/plugins/mods/api#show-something-without-starting-a-turn), finché il riquadro non si chiude |
| `rows` | L'altezza da chiedere quando il riquadro si trova sopra il prompt. L'impostazione predefinita è un terzo dello spazio. |
| `columns` | La larghezza da chiedere quando il riquadro si trova accanto alla trascrizione |

Per lasciare che un comando apra il riquadro mentre Claude sta lavorando, aggiungi `immediate: true` quando [registri il comando](/docs/it/plugins/mods/api#add-a-command). Senza di esso, un comando digitato durante un turno aspetta che il turno finisca.

<h4 id="when-a-pane-waits-for-a-wider-terminal">
  Quando un riquadro aspetta un terminale più ampio
</h4>

Un riquadro che il tuo mod apre senza essere chiesto non appare in un terminale stretto, quindi non può prendere il controllo di uno schermo piccolo. Se appare dipende da cosa l'ha aperto:

* **Aperto da qualcosa che l'utente ha fatto**, come un comando che ha eseguito o un pulsante che ha premuto, il riquadro appare a qualsiasi larghezza
* **Aperto dal tuo mod che agisce da solo**, come da un timer o un hook [`turn.start`](/docs/it/plugins/mods/events#follow-a-turn), il riquadro appare solo in un terminale di almeno 144 colonne di larghezza. Dopo che l'utente ha aperto quel riquadro una volta da solo, 110 colonne sono sufficienti.

Quando il riquadro appare, `$.ui.open` si risolve in `{ isPlaced: true }`. Quando il riquadro è in attesa, `isPlaced` è `false` e `reason` è una stringa che dice perché. Un riquadro in attesa appare quando l'utente lo apre o allarga il terminale. Per dire che qualcosa è disponibile senza aprire un riquadro, chiama `$.ui.toast('Your message')`, che mostra un piccolo avviso che scompare dopo pochi secondi.

<h2 id="build-a-tree-from-elements">
  Costruire un albero da elementi
</h2>

Quello che un hook `ui.render` restituisce è un albero di elementi: una descrizione di cosa disegnare, fatta di box, testo e controlli annidati l'uno dentro l'altro. Descrivi il disegno, e Claude Code lo renderizza nel terminale o nell'app Desktop.

Per ottenere gli elementi, chiama `$.ui.resolve(e)` nel tuo hook, come in `const { Box, Text, Button } = $.ui.resolve(e)`. Ogni elemento è una funzione. Passi le proprietà, e metti gli elementi e le stringhe che vanno dentro di esso in `children`.

La maggior parte dei disegni usa quattro elementi. Seleziona una scheda per vedere ognuno e come il terminale lo disegna:

<Tabs>
  <Tab title="Text">
    `Text` disegna una stringa, con stile opzionale come `bold` e `color`:

    ```javascript theme={null}
    Text({ children: ['This is the first tab.'] })
    ```

    ```text theme={null}
    This is the first tab.
    ```
  </Tab>

  <Tab title="Box">
    `Box` arrangia quello che è dentro di esso, in una riga o una colonna. Questo mette un pulsante e una riga di testo uno accanto all'altro, due colonne a parte:

    ```javascript theme={null}
    Box({
      flexDirection: 'row',
      columnGap: 2,
      children: [
        Button({ key: 'more', label: 'Add one', onPress: addOne }),
        Text({ children: ['Count: 0'] }),
      ],
    })
    ```

    ```text theme={null}
    [ Add one ]  Count: 0
    ```
  </Tab>

  <Tab title="Button">
    `Button` è un controllo che l'utente può premere. Esegue il tuo callback `onPress`. Con `plain: true` non ha parentesi e mostra la sua scorciatoia da tastiera:

    ```javascript theme={null}
    Button({ key: 'more', label: 'Add one', onPress: addOne })
    Button({ key: 'tab-one', label: 'One', hotkey: '1', plain: true, onPress: showTabOne })
    ```

    ```text theme={null}
    [ Add one ]
    1: One
    ```
  </Tab>

  <Tab title="Input">
    `Input` è un campo di testo. Esegue il tuo callback `onSubmit` con il testo quando l'utente preme Invio:

    ```javascript theme={null}
    Input({
      key: 'new-note',
      label: 'Note',
      placeholder: 'Type a note and press Enter',
      value: '',
      submitLabel: 'add',
      onSubmit: addNote,
    })
    ```

    ```text theme={null}
    Note: Type a note and press Enter ⏎ add
    ```
  </Tab>
</Tabs>

Questa tabella elenca ogni elemento:

| Elemento | Cosa disegna | Dove |
| :- | :- | :- |
| `Box` | Un contenitore flex. Accetta proprietà di layout come `flexDirection`, `columnGap`, `padding`, `borderStyle`, e `width`. | Ovunque |
| `Text` | Testo stilizzato. Accetta `color`, `bold`, `dimColor`, `italic`, e `wrap`. Un `color` è una chiave di tema o un colore come `'red'`. Un `wrap` è `'wrap'`, `'truncate'`, `'truncate-start'`, `'truncate-middle'`, o `'truncate-end'`. | Ovunque |
| `Button` | Un controllo che chiama `onPress` | Ovunque |
| `Link`, `Code`, `Markdown` | Un link con `href` e un `label` opzionale, un blocco di codice, e testo formattato come le risposte di Claude. `Markdown` accetta il suo contenuto in una proprietà `text`, non in `children`, e ha bisogno di una `key` quando passi `onLinkPress`. | Ovunque |
| `Input`, `Select` | Un campo di testo e un selettore | Terminale, Desktop |
| `Svg` | Un documento SVG | Desktop |
| `Client` | Una regione disegnata da un secondo file tuo, per animazione e input del puntatore. Quel file non ottiene l'API dei mod. Raggiunge i tuoi hook solo postando dati, che arrivano come evento `ui.message`. | Terminale, Desktop |
| `Raster`, `Image` | Una [griglia di celle colorate](#draw-a-grid-of-colored-cells), e un'immagine | Terminale |

Se il tuo modulo è un file `.tsx` o `.jsx`, puoi scrivere l'albero come JSX. Destruttura gli elementi da `$.ui.resolve(e)` per primo, perché un modulo di hook non ha globali di elementi.

Se un albero usa un elemento che l'app non ha, una proprietà che un elemento non accetta, o un figlio dove nessuno va, Claude Code disegna la sua versione del sito.

In una sessione avviata con `--plugin-dir`, una riga di trascrizione lo dice, come `ui.render (Pane) refused: Text prop "bogusProp" is not allowed; the engine drew its own`. Il [log di debug](/docs/it/plugins/mods/troubleshoot#read-the-debug-log) lo registra come `ui.render (Pane): a hook returned a tree that does not validate` con la stessa ragione. Nient'altro appare nella sessione, quindi quando un disegno non si mostra, controlla quella riga o il log.

<h3 id="draw-a-grid-of-colored-cells">
  Disegnare una griglia di celle colorate
</h3>

Per una mappa di calore, una sparkline, o una tavola di gioco nel terminale, disegna un `Raster` e non un `Box` per ogni cella. Un `Raster` accetta una `key`, la sua dimensione in `columns` e `rows`, e `cells`, che compatta ogni cella in una stringa. Ogni cella è tre numeri: il punto di codice del carattere, il suo colore, e il colore di sfondo. Un colore è un numero esadecimale con due cifre ciascuno per rosso, verde e blu, come `0xc62828` per un rosso, o `0x01000000` per il default del terminale.

L'app Desktop non ha `Raster`, quindi controlla `e.surface` e disegna testo lì. Questo corpo del riquadro disegna una mappa di calore tre per due:

```javascript theme={null}
// Il valore che significa "usa il colore predefinito del terminale"
const DEFAULT_COLOR = 0x01000000

// Compatta righe di coppie [carattere, colore] nella stringa che un Raster accetta
// Una cella è tre numeri: il punto di codice del carattere, il suo colore, e lo sfondo
function cellsOf(rows) {
  const numbers = rows.flat().flatMap(([char, color]) => [char.codePointAt(0), color, DEFAULT_COLOR])
  return new Uint8Array(Uint32Array.from(numbers).buffer).toBase64()
}

on('ui.render', { component: 'Pane' }, async ($, e, next) => {
  // Disegna solo nel riquadro aperto con l'id 'heat'
  if (e.requestId !== 'heat') return next(e)
  const { Box, Text, Raster } = $.ui.resolve(e)
  // Due righe di tre celle, ognuna un carattere di blocco e il suo colore
  const rows = [
    [['█', 0x2e7d32], ['█', 0xf9a825], ['█', 0xc62828]],
    [['█', 0x2e7d32], ['█', 0x2e7d32], ['█', 0xf9a825]],
  ]
  if (e.surface !== 'terminal') {
    return Text({ children: ['The heat map needs the terminal.'] })
  }
  return Box({
    flexDirection: 'column',
    children: [Raster({ key: 'grid', columns: 3, rows: 2, cells: cellsOf(rows) })],
  })
})
```

Nel terminale, il riquadro mostra la griglia:

<img src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-heat-map.svg?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=b91bcce3bad74bc851149133d4acc5d5" alt="Un riquadro nel terminale che contiene una piccola griglia di blocchi colorati, due righe di tre. La riga superiore è verde, ambra e rossa. La riga inferiore è verde, verde e ambra." width="360" height="132" data-path="images/mods-heat-map.svg" />

L'array `rows` è la parte che cambieresti, e `cellsOf` lo trasforma nella stringa compatta. L'hook disegna solo in un riquadro il cui `id` è `heat`, quindi aprine uno con `$.ui.open({ id: 'heat' })` da un comando, come l'esempio [`hello-tabs`](#build-a-pane-with-tabs) apre il suo riquadro.

Ogni carattere deve essere largo una cella. Per animare un `Raster` che è già sullo schermo, chiama `$.ui.blit` con l'`id` del riquadro come `requestId`, la `key` del `Raster`, la stessa dimensione, e celle nuove. Per questo esempio, è `$.ui.blit({ requestId: 'heat', key: 'grid', columns: 3, rows: 2, cells: cellsOf(newRows) })`. Ridipinge solo quell'elemento senza eseguire di nuovo il tuo hook `ui.render`.

<h2 id="respond-to-presses-and-typing">
  Rispondere a pressioni e digitazione
</h2>

Quando l'utente preme un pulsante, digita in un campo, o sceglie da un elenco che il tuo mod ha disegnato, Claude Code chiama la funzione che hai dato a quel controllo, e viene eseguita nel tuo modulo. Ogni controllo accetta i suoi callback:

* **`Button`**: accetta `onPress(e)`, dove `e.surface` è l'app da cui viene la pressione
* **`Input`**: accetta `onSubmit(value)` e `onInput(value)`
* **`Select`**: accetta `onSelect(value)` con le sue scelte in `options`, un elenco di almeno una scelta con valori unici, come `[{ value: 'sm', label: 'Small' }, { value: 'lg', label: 'Large' }]`

Un test preme o digita in un controllo per la sua `key`, quindi dagli uno. Ogni uso di un controllo genera anche [`ui.press`, `ui.input`, o `ui.select`](/docs/it/plugins/mods/reference#interface) con la `key` in `e.element`, e un altro mod può agganciare quegli eventi. Il suo hook viene eseguito prima del tuo callback, quindi vede quello che l'utente digita nel tuo `Input` e può cambiarlo o rispondere al posto del tuo callback. L'API dei mod non ha un metodo che preme il pulsante di un altro mod.

<h3 id="know-which-keys-your-mod-can-receive">
  Focus della tastiera e scorciatoie da tastiera
</h3>

Il tuo mod non legge mai la tastiera da solo. L'utente preme un tasto, Claude Code decide quale dei tuoi controlli è per esso, e il callback di quel controllo viene eseguito. A parte una [scorciatoia da tastiera con cifra sulla banda](/docs/it/plugins/mods/reference#elements), questo accade solo mentre il tuo riquadro o banda ha il focus della tastiera. Il resto del tempo, i tasti vanno al prompt.

<h4 id="how-a-pane-gets-keyboard-focus">
  Come un riquadro ottiene il focus della tastiera
</h4>

Un riquadro ottiene il focus della tastiera in uno di tre modi:

* Il tuo mod lo apre con `focus: true` da un comando o una pressione
* L'utente preme Ctrl+X poi Tab
* L'utente lo fa clic

Claude Code concede `focus: true` solo mentre il prompt è vuoto e nient'altro ha il focus della tastiera. Un riquadro che si apre mentre l'utente sta digitando non prende i suoi tasti.

<h4 id="what-each-key-does">
  Cosa fa ogni tasto
</h4>

Questa tabella elenca cosa fa un tasto mentre il tuo riquadro o banda ha il focus della tastiera:

| Tasto | Cosa fa |
| :- | :- |
| Tab | Si sposta al controllo successivo |
| Su e Giù | Si spostano tra i controlli mentre il tuo disegno si adatta. Quando il riquadro o la banda ha più righe di quante possa mostrare, lo scorrono. |
| Invio | Preme il `Button` focalizzato, invia il `Input` focalizzato, o sceglie in un `Select` |
| La scorciatoia da tastiera di un pulsante | Preme quel pulsante. Mentre un `Input` ha il focus, ogni tasto stampabile va al campo. |
| Esc | Restituisce il focus della tastiera al prompt. Con `closeOnEscape: true`, chiude anche il riquadro. |

Un mod non può associare Tab o i tasti freccia a nient'altro, quindi un gioco si muove con `w`, `a`, `s`, e `d`.

<h4 id="set-a-hotkey-and-the-first-focus">
  Impostare una scorciatoia da tastiera e il primo focus
</h4>

Due proprietà su un controllo decidono come la tastiera lo raggiunge:

* **`hotkey`**: per lasciare che l'utente preme un `Button` con un tasto, dagli una `hotkey` di una cifra o una lettera minuscola, come in `hotkey: 'a'`
* **`autoFocus`**: per scegliere quale controllo ha il focus quando il riquadro si apre, aggiungi `autoFocus: true` ad esso. Lascia la proprietà fuori dagli altri, perché Claude Code rifiuta `autoFocus: false`.

Come una scorciatoia da tastiera si mostra dipende dal pulsante e dall'app:

| Pulsante | Nel terminale | Nell'app Desktop |
| :- | :- | :- |
| Con parentesi, il default | `[ Add one ]`, senza scorciatoia da tastiera mostrata | L'etichetta con un piccolo tasto accanto |
| Con `plain: true` | `1: One` | L'etichetta con un piccolo tasto accanto |

Nel terminale, nomina il tasto nell'etichetta di un pulsante tra parentesi, o usa `plain: true`, così l'utente può vedere cosa premere. Il [riferimento degli elementi](/docs/it/plugins/mods/reference#elements) ha le altre regole di `Button`: `action`, scorciatoie da tastiera con cifra sulla banda, e due pulsanti su una scorciatoia da tastiera.

<h3 id="take-typed-input-and-draw-a-row-for-each-item">
  Prendere input digitato e disegnare una riga per ogni elemento
</h3>

Molti riquadri sono un campo di testo con un elenco sotto. L'esempio in questa sezione è un riquadro di note: digiti una nota e premi Invio per aggiungerla, e ogni nota ha un pulsante `x` che la elimina. Con due note aggiunte, il terminale disegna il riquadro in questo modo:

```text theme={null}
╭──────────────────────────────────────────────────────────╮
│ Note: Type a note and press Enter ⏎ add                ✕ │
│ x buy milk │
│ x call bob │
╰──────────────────────────────────────────────────────────╯
```

L'esempio usa due tecniche:

* **Prendere input digitato**: un `Input` chiama `onSubmit(value)` con il testo del campo quando l'utente preme Invio, e `onInput(value)` ad ogni cambio
* **Disegnare un elenco**: mappa i tuoi dati a una riga ciascuno, e dai a ogni pulsante della riga la sua `key`

Questo hook disegna il contenuto del riquadro:

```javascript theme={null}
// L'elenco che il riquadro disegna
let notes = []

on('ui.render', { component: 'Pane' }, async ($, e, next) => {
  // Disegna solo nel riquadro aperto con l'id 'notes'
  if (e.requestId !== 'notes') return next(e)
  const { Box, Text, Button, Input } = $.ui.resolve(e)
  const redraw = () => $.ui.invalidate('ui.render')

  return Box({
    flexDirection: 'column',
    children: [
      Input({
        key: 'new-note',
        label: 'Note',
        placeholder: 'Type a note and press Enter',
        // Disegna il campo vuoto ogni volta, che lo cancella dopo un invio
        value: '',
        submitLabel: 'add',
        autoFocus: true,
        // Viene eseguito quando premi Invio nel campo
        onSubmit: async (value) => {
          // Ignora una riga vuota
          if (!value.trim()) return
          notes = [...notes, value.trim()]
          redraw()
          await $.store.set('notes', notes)
        },
      }),
      // Una riga per ogni nota: un pulsante di eliminazione, quindi il testo della nota
      ...notes.map((note, i) =>
        Box({
          flexDirection: 'row',
          columnGap: 1,
          children: [
            Button({
              // Una key propria, così il pulsante di ogni riga può essere distinto
              key: 'delete-' + i,
              label: 'x',
              plain: true,
              onPress: async () => {
                notes = notes.filter((_, j) => j !== i)
                redraw()
                await $.store.set('notes', notes)
              },
            }),
            Text({ children: [note] }),
          ],
        }),
      ),
    ],
  })
})
```

Per provare il riquadro:

* **Aggiungi una nota**: digita una riga e premi Invio. La riga appare come una nuova riga, e il campo si svuota.
* **Elimina una nota**: premi Tab finché il pulsante `x` della nota non ha il focus, quindi premi Invio. La `x` è l'etichetta del pulsante e non una scorciatoia da tastiera, quindi digitare la lettera non lo preme.

Ogni cambio segue lo stesso ciclo di rendering di `hello-tabs`: il callback cambia `notes`, chiama `redraw`, e salva l'elenco in `$.store`.

Il campo si svuota dopo ogni invio a causa della sua proprietà `value`. `value` è il testo che il campo contiene quando viene disegnato, e la digitazione dell'utente lo sostituisce finché il tuo hook non disegna il campo di nuovo. L'esempio disegna sempre il campo con `''`.

L'esempio salva le note e non le carica. Per riportarle nella sessione successiva, leggile in un hook `session.start`, come `hello-tabs` legge `count`.

Tre proprietà compongono la riga del campo, `Note: Type a note and press Enter ⏎ add`:

| Proprietà | Nell'esempio | Cosa è |
| :- | :- | :- |
| `label` | `Note` | Il testo prima del campo. Il terminale disegna `: ` dopo di esso. |
| `placeholder` | `Type a note and press Enter` | Testo attenuato che si mostra mentre il campo è vuoto |
| `submitLabel` | `add` | La parola dopo `⏎` che dice cosa fa Invio |

Inviare un `Input` non avvia un turno a meno che il tuo callback non chiami [`$.prompt.submit`](/docs/it/plugins/mods/api#start-a-turn-from-a-background-job).

<h2 id="redraw-when-something-changes">
  Ridisegnare un sito
</h2>

Un disegno è un'istantanea: mostra quello che il tuo hook `ui.render` ha restituito l'ultima volta che l'hook è stato eseguito. Per mostrare qualcosa di nuovo, l'hook deve essere eseguito di nuovo. Claude Code lo esegue di nuovo per alcuni cambiamenti, e il tuo mod chiede il resto.

<h3 id="when-claude-code-redraws-without-being-asked">
  Quando Claude Code ridisegna senza essere chiesto
</h3>

Claude Code esegue di nuovo il tuo hook `ui.render` quando le proprietà del sito cambiano o la larghezza del terminale cambia. Non esegue l'hook su un timer, e non può dire quando una variabile nel tuo modulo cambia.

<h3 id="redraw-when-your-data-changes">
  Ridisegnare quando i tuoi dati cambiano
</h3>

Per avere i tuoi siti disegnati di nuovo dopo che i tuoi dati cambiano, chiama `$.ui.invalidate('ui.render')`. Questo riquadro conta le pressioni. Il callback del pulsante cambia `count`, quindi chiede un ridisegno:

```javascript theme={null}
let count = 0

on('ui.render', { component: 'Pane' }, async ($, e, next) => {
  if (e.requestId !== 'counter') return next(e)
  const { Box, Text, Button } = $.ui.resolve(e)
  return Box({
    flexDirection: 'row',
    columnGap: 2,
    children: [
      Button({
        key: 'more',
        label: 'Add one',
        onPress: () => {
          count += 1
          // I dati sono cambiati, quindi chiedi a Claude Code di disegnare il riquadro di nuovo
          $.ui.invalidate('ui.render')
        },
      }),
      Text({ children: ['Count: ' + count] }),
    ],
  })
})
```

Ogni pressione alza il numero nel riquadro. L'esempio [`hello-tabs`](#build-a-pane-with-tabs) avvolge la stessa chiamata nella sua funzione `redraw`.

Un valore che mantieni in [`$.state`](#keep-a-value-in-\$-state) non ha bisogno della chiamata, perché scrivere il valore ridisegna i siti che lo leggono.

<h3 id="redraw-on-a-timer">
  Ridisegnare su un timer
</h3>

Per mantenere un orologio, un conto alla rovescia, o un valore da fuori la sessione attuale, ridisegna su un programma. Avvia un timer nell'hook `session.start` del modulo. Se il modulo ne ha già uno, come `hello-tabs`, aggiungi la riga [`$.clock.every`](/docs/it/plugins/mods/api#run-work-in-the-background) ad esso:

```javascript theme={null}
on('session.start', async ($, e, next) => {
  // Ogni 1000 millisecondi, chiedi a Claude Code di disegnare di nuovo i tuoi siti
  $.clock.every(1000, () => $.ui.invalidate('ui.render'))
  return next(e)
})
```

Claude Code ora esegue il tuo hook `ui.render` una volta al secondo. Il timer si ferma quando il modulo si ricarica, e la nuova copia del modulo avvia il suo.

<h3 id="how-often-a-site-can-redraw">
  Quanto spesso un sito può ridisegnare
</h3>

Claude Code limita quanto spesso ridisegna un sito, quindi il tuo mod può chiamare `$.ui.invalidate` quanto spesso i suoi dati cambiano. Il riquadro visibile e la banda hanno un limite più alto rispetto ad altri siti, e la [tabella dei limiti](/docs/it/plugins/mods/reference#limits) contiene i numeri.

Le chiamate che arrivano più velocemente del limite vengono combinate in un ridisegno. Quel ridisegno esegue il tuo hook una volta, e l'hook legge i tuoi dati come sono in quel momento, quindi il valore più recente si mostra e i valori in mezzo no. Un'animazione non può essere eseguita più velocemente del limite.

<h2 id="keep-state">
  Mantenere lo stato
</h2>

Un mod ha tre posti per mantenere un valore, e differiscono in quanto tempo il valore dura: finché il modulo non si ricarica, finché la sessione non finisce, o da una sessione all'altra. Scegli in base a quanto tempo il valore deve durare:

| Mantienilo in | Dura fino a | Usalo per |
| :- | :- | :- |
| Una variabile a livello di modulo | Il modulo si ricarica, che accade ogni volta che salvi un file durante lo sviluppo | Valori che puoi perdere, come `tab` è in `hello-tabs` |
| `$.state` | La sessione finisce, o l'utente esegue `/clear`, `/resume`, o `/branch` | Valori su cui un disegno dipende che dovrebbero sopravvivere a un ricaricamento |
| `$.store` | Il tuo mod lo elimina, o nessuna sessione legge o scrive lo store per [`cleanupPeriodDays`](/docs/it/settings-reference#cleanupperioddays). Lo store è un archivio chiave-valore, salvato come file JSON del tuo plugin sotto `~/.claude/plugins/store/`. | Impostazioni, cronologia, qualsiasi cosa l'utente si aspetta di trovare la prossima volta |

`$.store.get(key)` si risolve nel valore o `undefined`, e `$.store.set(key, value)` accetta qualsiasi valore JSON.

<h3 id="keep-a-value-in-state">
  Mantenere un valore in `$.state`
</h3>

`$.state` contiene valori per la durata di una sessione, e ridisegna per te. È uno stato reattivo: un hook `ui.render` che legge un valore si iscrive ad esso, quindi Claude Code ridisegna quel sito ogni volta che scrivi il valore, e non chiami `$.ui.invalidate`. Un valore in `$.state` sopravvive anche a un ricaricamento del modulo, che una variabile non fa.

Per configurarlo, dichiara i tuoi valori, punta il tuo manifesto alla dichiarazione, quindi definisci e usa ogni valore. Gli esempi spostano il `count` da `hello-tabs` in `$.state`.

<h4 id="declare-the-values">
  Dichiarare i valori
</h4>

Dichiara i valori in un file di tipi. La chiave esterna è il nome del tuo plugin, e ogni voce sotto di esso è un valore e il suo tipo. Salva questo come `hello-tabs/types/index.d.ts`:

```typescript hello-tabs/types/index.d.ts theme={null}
declare module 'claude-code' {
  interface PluginState {
    'hello-tabs': {
      tab: 'one' | 'two'
      count: number
    }
  }
}
```

<h4 id="point-the-manifest-at-the-declaration">
  Puntare il manifesto alla dichiarazione
</h4>

Per lasciare che `claude plugin validate` controlli il tuo codice contro quel file, aggiungi un campo `types` al manifesto con il suo percorso:

```json hello-tabs/.claude-plugin/plugin.json theme={null}
{
  "name": "hello-tabs",
  "version": "0.1.0",
  "description": "Opens a pane with two tabs and a counter",
  "author": { "name": "Your Name" },
  "types": "./types/index.d.ts"
}
```

<h4 id="define-read-and-write-a-value">
  Definire, leggere e scrivere un valore
</h4>

Nel tuo modulo, definisci ogni valore con un default, leggilo mentre disegni, e scrivilo da un callback. `atom` nomina un valore e il suo default, `read` lo restituisce, e `update` lo scrive. I tre helper chiamano `$.state.get` e `$.state.set` per te:

```javascript theme={null}
import { atom, read, update } from 'claude-code'

// In cima al modulo: nomina il valore e dai il suo default
const count = atom({ plugin: 'hello-tabs', key: 'count' }, 0)

// Nell'hook ui.render: leggi il valore per disegnarlo
const n = await read($, count)

// In un Button: scrivi un nuovo valore dal vecchio
onPress: () => update($, count, (value) => value + 1)
```

Perché l'hook `ui.render` ha letto `count`, Claude Code esegue l'hook di nuovo ogni volta che il pulsante lo scrive.

Tre regole si applicano al codice:

* **Scrivi `plugin` e `key` come stringhe letterali**: `claude plugin validate` le legge dal tuo sorgente
* **Dichiara ogni valore nel file di tipi**: altrimenti la validazione fallisce con `hello-tabs.count is not declared`
* **Scrivi da un callback o dall'hook di un altro evento**: un hook `ui.render` può leggere lo stato e non può scriverlo, quindi scrivi da `onPress`, `onSubmit`, o un hook per un altro evento

<h4 id="change-hello-tabs-to-use-state">
  Cambiare `hello-tabs` per usare `$.state`
</h4>

Per spostare `count` in `hello-tabs` in `$.state`, cambia ogni riga che lo usa:

* **In cima al modulo**: aggiungi la riga `import`, e sostituisci `let count = 0` con la riga `atom`
* **Nell'hook `ui.render`**: aggiungi la riga `read` prima di `tabButton`, e disegna `'Count: ' + n` nel `Text`
* **Nel pulsante Add one**: sostituisci `onPress` con quello in [Salvare da più di una sessione](#save-from-more-than-one-session), che salva il conteggio così come lo scrive
* **Nell'hook `session.start`**: sostituisci le due righe che leggono `saved` con la chiamata `loadCount` da [Caricare un valore salvato di nuovo dopo `/clear`](#load-a-saved-value-again-after-clear)

Mantieni `redraw` per i pulsanti delle schede, perché `tab` è ancora una variabile.

<h3 id="load-a-saved-value-again-after-clear">
  Caricare un valore salvato di nuovo dopo `/clear`
</h3>

Se il tuo mod copia un valore salvato da `$.store` in `$.state` a `session.start`, deve copiarlo di nuovo dopo `/clear`, `/resume`, o `/branch`. Questi comandi rimettono ogni valore `$.state` al suo default, e `session.start` non viene generato di nuovo. [`classic.SessionStart`](/docs/it/plugins/mods/events#hook-the-settings-hook-events) viene generato dopo ognuno di essi, con `e.source` impostato a `clear`, `resume`, o `fork`, quindi copia il valore di nuovo in un hook su di esso. Altrimenti il tuo disegno mostra il default, e un callback che salva il valore `$.state` scrive il default su quello che hai archiviato.

Questo codice carica `count` da entrambi gli hook. Si basa sulla versione `$.state` di `hello-tabs`, dove `count` è un atom e `update` è importato. Metti `loadCount` sopra `register`, e aggiungi la chiamata `loadCount` all'hook `session.start` che hai già. `classic.SessionStart` viene generato anche all'avvio e dopo la compattazione, che non ripristina `$.state`, quindi il filtro su `source` mantiene l'hook ai tre ripristini:

```javascript theme={null}
// Copia il conteggio salvato da $.store in $.state, o 0 se nulla è salvato
async function loadCount($) {
  const saved = Number((await $.store.get('count')) ?? 0)
  await update($, count, () => saved)
}

// Viene eseguito prima del tuo primo prompt, e di nuovo dopo un ricaricamento
on('session.start', async ($, e, next) => {
  await loadCount($)
  return next(e)
})

// Viene eseguito di nuovo dopo /clear, /resume, e /branch, che riporta fork
on('classic.SessionStart', { source: ['clear', 'resume', 'fork'] }, async ($, e, next) => {
  await loadCount($)
  return next(e)
})
```

Con entrambi gli hook in posizione, il riquadro mostra il conteggio salvato dopo `/clear` e non `0`, e la prossima pressione di **Add one** aggiunge al conteggio salvato.

`loadCount` scrive il valore archiviato su quello in `$.state`, e `session.start` viene generato di nuovo ogni volta che il modulo si ricarica. Per mantenere lo store dal rimanere indietro, salva ad ogni cambio, come il pulsante **Add one** fa.

Per controllare il ricaricamento senza una sessione, [testa il disegno dopo `/clear`](/docs/it/plugins/mods/test#test-a-drawing-after-clear).

<h3 id="save-from-more-than-one-session">
  Salvare da più di una sessione
</h3>

Ogni sessione sulla tua macchina che esegue il tuo mod condivide uno `$.store`. Un `get` seguito da un `set` non è atomico. Quando due sessioni leggono ciascuna un valore, lo cambiano, e lo scrivono di nuovo, corrono, e la seconda scrittura sostituisce la prima.

Due scelte lo rendono meno probabile:

* **Dai a ogni elemento la sua chiave**: un `set` cambia solo la sua chiave, quindi le sessioni che scrivono chiavi diverse non si sovrascrivono a vicenda
* **Leggi di nuovo subito prima di scrivere**: per un valore che più sessioni cambiano, `get` la chiave nel callback e costruisci il nuovo valore da quello, non da una copia che hai caricato a `session.start`. Un'altra scrittura della sessione è ancora persa se atterra tra il tuo `get` e il tuo `set`.

Questo pulsante aggiunge uno a quello che lo store contiene ora, quindi aggiorna il disegno:

```javascript theme={null}
onPress: async () => {
  // Leggi quello che lo store contiene ora, che un'altra sessione potrebbe aver cambiato
  const saved = Number((await $.store.get('count')) ?? 0)
  // Salva il nuovo conteggio, quindi mostralo
  await $.store.set('count', saved + 1)
  await update($, count, () => saved + 1)
}
```

Se una seconda sessione ha premuto il suo pulsante tre volte da quando questa sessione è iniziata, questa pressione mostra e salva un conteggio che include quei tre.

<h2 id="next-steps">
  Prossimi passi
</h2>

* [Reagire agli eventi](/docs/it/plugins/mods/events): alimenta il tuo disegno da chiamate di strumenti e turni
* [Usare l'API dei mod](/docs/it/plugins/mods/api): alimenta il tuo disegno da timer e chiamate di modello
* [Testare un disegno](/docs/it/plugins/mods/test#test-a-drawing): premi i tuoi pulsanti da un test, su più di una superficie
* [Siti di rendering](/docs/it/plugins/mods/reference#render-sites) e [elementi](/docs/it/plugins/mods/reference#elements): le proprietà di ogni sito e le proprietà di ogni elemento
