# Note storiche — Handwriting Plugin
Questo file contiene lo storico delle sessioni di sviluppo, bug risolti, tentativi falliti e ricerche effettuate.
Per istruzioni, architettura e task aperti vedi `CLAUDE.md`.
---
## ✅ Task completati (sessione 2026-03-24)
### Fix focus perso dopo `window.confirm()` — RISOLTO ✅
**Sintomo**: dopo aver confermato o annullato la cancellazione di un SVG (sia dal pannello portale inline che dalla `DrawingModal`), il focus veniva perso e non era più possibile scrivere nel documento Obsidian finché non si cambiava finestra.
**Causa**: `window.confirm()` in Electron apre un dialogo nativo che rimuove il focus a livello OS dalla finestra Electron. Alla chiusura il focus non viene ripristinato automaticamente.
**Fix — `DrawingModal`** (`src/editor-view.ts`): aggiunto metodo `showDeleteConfirm()` che crea un overlay `
` dentro `contentEl` con due bottoni ("Elimina" e "Annulla"). Nessun dialogo nativo, nessun problema di focus. La `doDelete()` del modal usa ora `showDeleteConfirm()` + listener `vault.on('modify')` + `setTimeout(300)` per ripristinare il focus dopo la cancellazione del file.
**Fix — pannello portale inline** (`src/embed.ts`): aggiunta funzione helper `showInlineConfirm(anchorEl, msg)` che crea lo stesso overlay `position:absolute` sopra l'elemento passato. Sia il bottone elimina del formato wiki che quello del formato legacy usano ora `showInlineConfirm`.
**File**: `src/editor-view.ts`, `src/embed.ts`, `styles.css`, `src/locales/*.json` (chiavi `confirm_ok`, `confirm_cancel`).
### Fix overlay di conferma non cliccabile nel pannello portale — RISOLTO ✅
**Sintomo**: dopo la conversione all'overlay inline, i bottoni "Elimina" e "Annulla" non erano cliccabili nel pannello portale. Era anche possibile cliccare i bottoni sottostanti attraverso l'overlay.
**Causa**: due problemi CSS simultanei — (1) l'overlay aveva `z-index: 10`, uguale al pannello portale; (2) il container span eredita `pointer-events: none` e l'overlay lo ereditava.
**Fix CSS** (`styles.css`): `z-index: 100` sull'overlay + `pointer-events: auto !important` su `.hwm_confirm-overlay` e sui suoi bottoni.
**File**: `styles.css`.
### Fix letterboxing (bordi neri) su Android al comprimi/espandi — RISOLTO ✅
**Sintomo**: su Android, comprimere o espandere un riquadro SVG creava grossi bordi neri ai lati dell'immagine invece di ridimensionarla correttamente.
**Causa**: Obsidian Mobile ha un `ResizeObserver` interno sul container span. Quando `container.style.height` veniva modificato, il ResizeObserver si attivava e ricalcolava il layout dell'``, forzando proporzioni con letterbox.
**Fix**: tecnica del "wrapper div" — `doCollapse`/`doExpand` in `embed.ts` creano (o riusano) un `
` figlio diretto dell'``. L'animazione viene applicata sull'altezza del wrapper, mai sul container span, quindi il ResizeObserver non si attiva. `img.parentElement.insertBefore(wrapper, img)` per evitare eccezione silenziosa su Android dove `` non è figlio diretto del container.
**CSS aggiunto** (`.hwm_clip-wrapper`): `width: 100%; transition: height 0.3s ease;` e regole sull'img figlio per forzare `width: 100%; height: auto; object-fit: unset`.
**File**: `src/embed.ts`, `styles.css`.
### Animazione comprimi/espandi — AGGIUNTA ✅
**Cosa**: l'altezza del wrapper si anima con `transition: height 0.3s ease`. Al collapse: `scrollHeight` → `collapsedHeight` (px) via `requestAnimationFrame`. All'expand: `collapsedHeight` → `scrollHeight`, poi `height: ''` e `overflow: ''` rimossi su `transitionend` per ripristinare il layout naturale.
**File**: `src/embed.ts`, `styles.css`.
### Rimozione nome branch dalla versione nelle impostazioni — RISOLTO ✅
**Cosa**: il header della pagina impostazioni mostrava `v1.x.x — branch: overlay`. La stringa del branch è stata rimossa; ora mostra solo `v${this.plugin.manifest.version}`.
**File**: `src/settings.ts` (rimossa costante `PLUGIN_BRANCH` dall'UI, variabile mantenuta per uso interno).
### Preview SVG nella ricerca "Insert SVG reference" — AGGIUNTA ✅
**Cosa**: il modal fuzzy-search per inserire un riferimento a un SVG esistente ora mostra una thumbnail dell'SVG a sinistra del nome file, invece del solo testo.
**Implementazione**: override di `renderSuggestion()` in `SvgReferenceSuggest` (`src/main.ts`). Usa `app.vault.getResourcePath(file)` come `src` dell'``. CSS aggiunto: `.hwm_svg-suggest-item` (flex), `.hwm_svg-thumb` (48×48px, border-radius), `.hwm_svg-suggest-name`.
**File**: `src/main.ts`, `styles.css`.
---
## ✅ Task completati (sessione 2026-03-23)
### Tema automatico (bgMode 'auto')
Rinominato 'custom' → 'auto' nel dropdown settings. `MutationObserver` su `document.body` in `main.ts` chiama `notifyBgModeChange()` al cambio di `theme-dark`. Aggiunta `resolveIsDark(bgMode)` in `editor-view.ts` ed `embed.ts` per risolvere 'auto' al tema Obsidian effettivo. Migrazione automatica 'custom'→'auto' in `loadSettings()`. Rimosso `bgCustomColor` e color picker dalle settings.
### Angoli arrotondati
Usato `var(--radius-m)` / `var(--radius-l)` su tutti gli elementi (toolbar, bottoni, pannello portale, modal, container). `border-radius` applicato sull'`` inline invece che sullo span (no `overflow:hidden` sullo span, che clippava l'SVG). Aggiunto `border: 1.5px solid var(--background-modifier-border)` e `box-shadow` al riquadro inline per visibilità contro lo sfondo Obsidian.
### Rimosso switch "Modalità handwriting Android"
Badge mode sempre attiva su `Platform.isMobile`, preview piena sempre su desktop. Rimossi `hwmHandwritingMode` da `HandwritingSettings`, `DEFAULT_SETTINGS`, settings tab, `registerEmbed()` e `tryDecorate()` in `embed.ts`. Le classi CSS `hwm-handwriting-mode` e `hwm-badge-mode` rimangono ma vengono applicate automaticamente.
### Fix toolbar pannello portale al cambio tema
Sostituita classe generica `hwm_toolbar--dark` con `hwm_portal-panel--dark` dedicata. `resolveIsDark` inline in `createPortalPanel` gestisce 'auto', 'light' e 'dark'. `hwm_resize-handle--dark` sostituisce gli inline styles sull'handle del canvas.
---
---
## ✅ TEST EFFETTUATI (sessione 2026-03-22)
### Bug 1 — Pannello portale parzialmente visibile con Modal aperto — RISOLTO ✅
**Sintomo**: su Windows, cliccando il bottone matita, i bottoni "Converti" e "Comprimi" del pannello portale restavano visibili sopra il modal mentre il bottone matita scompariva correttamente.
**Causa**: il RAF loop nascondeva solo il bottone matita (`btn.style.display`) ma non l'intero pannello.
**Fix**: il RAF loop ora setta `panel.style.display = 'none'` quando `modalOpen || tabOpen`, nascondendo l'intero pannello portale (tutti e 4 i bottoni).
**File**: `src/embed.ts` — RAF loop in `decorateSpan()`.
---
### Bug 2 — Canvas modal troppo largo, toolbar non centrata — RISOLTO ✅
**Sintomo**: nel Modal Windows, il canvas occupava tutta la larghezza dell'overlay (troppo largo e non centrato). La toolbar era allineata a sinistra invece che al centro.
**Fix CSS** (`styles.css`):
- `.hwm_canvas-wrap { display: flex; justify-content: center; }` — centra il canvas orizzontalmente
- `.hwm_canvas { max-width: 100%; }` — rimosso `width: 100%` fisso
- `.hwm_editor-topbar--modal { justify-content: center; }` — centra la toolbar nel modal
**Fix TS** (`editor-view.ts`): `DrawingModal.buildEditor()` aggiunge classe `hwm_editor-topbar--modal` alla topbar.
---
### Bug 3 — Auto-scroll sposta i tratti durante il disegno — RISOLTO ✅
**Sintomo**: quando il canvas si espandeva automaticamente (auto-expand) mentre stavo disegnando, lo scroll automatico verso il basso spostava i punti del tratto corrente rispetto alla posizione del pennino.
**Causa**: l'evento `onResize` faceva scroll immediatamente anche con il pointer premuto, spostando il canvas mentre le coordinate del puntatore erano ancora relative alla posizione pre-scroll.
**Fix**: aggiunto metodo pubblico `isPointerDown(): boolean` in `DrawingCanvas` (`drawing-canvas.ts`). Sia `DrawingEditorView` che `DrawingModal` in `editor-view.ts` ora controllano `!canvas.isPointerDown()` prima di eseguire il `scrollTop` automatico.
---
### Bug 4 — Badge mode mostra icona in riquadro piccolissimo — RISOLTO ✅
**Sintomo**: attivando "Modalità handwriting Android" nelle impostazioni, i riquadri SVG si riducevano a un quadratino minuscolo invece di un badge orizzontale a piena larghezza.
**Causa**: lo span `.internal-embed` senza figli visibili collassava alla sua larghezza intrinseca (quasi zero).
**Fix CSS** (`.hwm-handwriting-mode .hwm-badge-mode`):
```css
width: 100% !important; box-sizing: border-box !important;
height: 72px !important; display: flex !important;
align-items: center; justify-content: center;
background: var(--background-secondary); border-radius: 6px;
```
Più: `img { display: none !important }` per nascondere l'SVG e `::after { content: "✏️"; font-size: 28px; opacity: 0.5; }` per l'icona.
**File**: `styles.css`.
---
## ✅ TEST EFFETTUATI (sessione 2026-03-23)
### Bug 5 — Pannello portale visibile nelle impostazioni e ovunque — RISOLTO ✅
**Sintomo**: il pannello portale (`position: fixed` in `document.body`) rimaneva visibile in alto a destra anche navigando nelle impostazioni, in altre schede, ecc.
**Causa**: il pannello era appeso a `document.body` e il RAF loop di posizionamento lo seguiva solo quando lo span era nel viewport.
**Fix**: pannello spostato come figlio diretto dello span contenitore con `position: absolute; top: 6px; right: 6px`. Lo span ha `position: relative`. Il pannello è ora parte del DOM del documento e scompare naturalmente quando si naviga altrove.
**File**: `src/embed.ts` — `createPortalPanel()` + `styles.css`.
---
### Bug 6 — Comprimi/Espandi modificava anche la larghezza — RISOLTO ✅
**Sintomo**: cliccando il bottone freccia per comprimere/espandere il riquadro, anche la larghezza cambiava (l'immagine si restringeva).
**Causa**: il codice precedente usava `max-height` sull'elemento ``, che lo scalava proporzionalmente.
**Fix**: la compressione ora modifica `container.style.height` + `overflow: hidden` sullo span contenitore. L'immagine viene clippata verticalmente senza alterarne la larghezza.
**File**: `src/embed.ts` — handler del bottone collapse in `createPortalPanel()`.
---
### Bug 7 — Pannello portale rimane nel DOM dopo disabilitazione plugin — RISOLTO ✅
**Sintomo**: disabilitando il plugin, i pannelli portale (bottoni) rimanevano visibili nel documento.
**Fix**: `plugin.register(() => panel.remove())` — Obsidian chiama tutti i callback registrati con `plugin.register()` quando il plugin viene disabilitato.
**File**: `src/embed.ts` — `createPortalPanel()`.
---
### Bug 8 — Bottoni pannello portale non cliccabili — RISOLTO ✅
**Sintomo**: dopo lo spostamento del pannello dentro lo span, i bottoni non rispondevano al click.
**Causa**: lo span aveva `pointer-events: none` (impostato in `tryDecorate()` per handwriting Android). Il pannello figlio ereditava la proprietà.
**Fix**: `pointer-events: auto` in CSS su `.hwm_portal-panel` — ripristina i click solo sul pannello, lasciando il resto dello span non interattivo.
**File**: `styles.css`.
---
### Bug 9 — Palette colori SVG non aggiornata al cambio bgMode — RISOLTO ✅
**Sintomo**: cambiando bgMode nelle impostazioni, gli SVG nei documenti aperti mantenevano i vecchi colori dei tratti finché non si ricaricava il plugin.
**Fix**: aggiunto listener `onBgModeRemap` in `registerEmbed()` registrato in `plugin.bgModeListeners`. Quando il bgMode cambia:
1. Itera `plugin.embedPaths` (mappa `embedId → svgPath`)
2. Legge il file SVG dal vault e verifica il marker `hwm-strokes` (ignora SVG non del plugin)
3. Parsa `viewBox="0 0 W H"` per ottenere le dimensioni reali (non quelle di default, che perderebbero l'auto-expand)
4. Rimappa i colori dei tratti con `remapStrokeColor()`, rigenera l'SVG con `strokesToSvg()`, salva
5. Chiama `plugin.refreshPreview(embedId, newContent)` → aggiorna `img.src` con cache-bust
**File**: `src/embed.ts` — `onBgModeRemap` in `registerEmbed()`.
---
### Bug 10 — Toolbar editor non aggiornata al cambio bgMode — RISOLTO ✅
**Sintomo**: i bottoni della toolbar nel `DrawingModal` (Windows) e nel `DrawingEditorView` (Android) non cambiavano colore al cambio bgMode.
**Causa 1 (live update)**: mancava un listener. Aggiunto `bgModeListener` in entrambe le classi, registrato in `bgModeListeners` dopo la costruzione di `colorBtns` (per poterli aggiornare nel closure). Rimosso in `onClose()`.
**Causa 2 (riapertura)**: il cambio bgMode avviene sempre con editor chiuso. `buildEditor()` viene chiamato di nuovo alla riapertura e legge `plugin.settings.bgMode` → corretto per costruzione. Il problema visivo era CSS.
**Causa 3 (CSS)**: Obsidian dark theme ha regole tipo `.modal-content button { background: var(...) }` con specificità `0,1,1` > `0,1,0` di `.hwm_btn`, sovrascrivendo il nostro sfondo trasparente. Il colore del topbar senza `!important` veniva sovrascritto analogamente.
**Fix CSS** (`styles.css`):
- `.hwm_editor-topbar { background: rgba(240,240,240,0.95) !important }` e `.hwm_editor-topbar--dark { background: rgba(40,40,40,0.97) !important }` — entrambe con `!important` (la `--dark` appare dopo → vince in dark mode per cascade order)
- `.hwm_editor-topbar .hwm_btn { background: transparent !important; color: #333 !important }` — batte la specificità di Obsidian
- `.hwm_editor-topbar--dark .hwm_btn { color: #bbb !important }` — appare dopo → vince in dark mode
- Hover e active espliciti con `!important` per entrambe le modalità
**Nota importante**: il cambio bgMode viene SEMPRE effettuato con editor chiuso (il modal copre l'intera finestra). Il listener live è presente ma non è il percorso principale.
**File**: `src/editor-view.ts` + `styles.css`.
---
## Problemi risolti (storico completo)
- **Handwriting Android (disegno)** ✅ — risolto con editor in tab separata (`ItemView`), canvas fuori da `cm-content`
- **Pen scroll** ✅ — penna non scrolla più, solo dito (JS manuale via `setPointerCapture`)
- **Toolbar — tema scuro** ✅
- **Spazio vuoto sezione colori in toolbar compatta** ✅
- **Trashcan non cancella visualmente** ✅
- **Bottoni inline coprivano `>` di Obsidian** ✅ — spostati a `left: 6px`
- **Ordine bottoni inline** ✅ — invertito: X, Converti, Freccia (da sinistra)
- **Placeholder text** ✅ — aggiornato a "Usa il bottone matita in alto a destra per disegnare"
- **Bottone portale non cerchio perfetto** ✅ — risolto con `width/height/min-width/min-height: 36px !important`, `padding: 0 !important`, `overflow: hidden`
- **Icona bottone portale non visibile** ✅ — SVG con `stroke="currentColor"` non diventava bianco; risolto con `.hwm_portal-btn svg { stroke: #ffffff !important }`
- **Bottone portale non si nasconde con editor aperto** ✅ — check `workspace.getLeavesOfType(VIEW_TYPE_HANDWRITING).some(...)` nel RAF loop (Android) + flag `modalOpen` (Windows)
- **Bottone portale `position: absolute` invece di `fixed`** ✅ — `getBoundingClientRect()` restituisce coordinate viewport, non serviva aggiungere `scrollY/scrollX`
- **Bottoni pannello portale rimangono visibili durante lo scroll** ✅ — listener `scroll` su `.cm-scroller`/`.markdown-reading-view` che setta `visibility: hidden` durante lo scroll
- **Modal Windows** ✅ — implementato `DrawingModal extends Modal`; click matita su Desktop apre modal invece di nuova tab
- **Switch handwriting** ✅ — `hwmHandwritingMode` in settings; badge mode via classe CSS su `document.body` e sullo span
- **DrawingModal non gestiva formato wiki** ✅ — aggiunto `wikiEmbedRegex()` e logica try-wiki-then-legacy in `replaceInMd()`
- **Pannello portale visibile con Modal aperto (Bug 1)** ✅ — RAF loop ora nasconde l'intero panel (`display: none`) quando `modalOpen || tabOpen`, non solo il bottone matita
- **Canvas modal non centrato, toolbar a sinistra (Bug 2)** ✅ — `display: flex; justify-content: center` su `.hwm_canvas-wrap`; `max-width: 100%` su `.hwm_canvas`; classe `hwm_editor-topbar--modal` aggiunta al topbar del modal per centrare la toolbar
- **Auto-scroll sposta tratti durante disegno (Bug 3)** ✅ — aggiunto `isPointerDown()` in `DrawingCanvas`; scroll automatico bloccato se il pointer è premuto, sia in `DrawingEditorView` che in `DrawingModal`
- **Badge mode mostra riquadro minuscolo (Bug 4)** ✅ — CSS `.hwm-handwriting-mode .hwm-badge-mode` con `width: 100% !important`, `height: 72px`, flex centrato, `img { display: none }` + `::after` con emoji matita
- **Pannello portale visibile nelle impostazioni (Bug 5)** ✅ — pannello spostato da `document.body` (position:fixed) a figlio diretto dello span (position:absolute); eliminati RAF loop e scroll listener
- **Comprimi/Espandi modificava larghezza (Bug 6)** ✅ — usa `container.style.height + overflow:hidden` invece di `max-height` sull'img
- **Pannello resta dopo disabilitazione plugin (Bug 7)** ✅ — `plugin.register(() => panel.remove())`
- **Bottoni pannello non cliccabili (Bug 8)** ✅ — `pointer-events: auto` su `.hwm_portal-panel` in CSS
- **SVG non aggiornati al cambio bgMode (Bug 9)** ✅ — listener `onBgModeRemap` in `bgModeListeners`; legge viewBox per dimensioni reali, rimappa colori, salva SVG, refresh preview
- **Toolbar editor non aggiornata al cambio bgMode (Bug 10)** ✅ — `bgModeListener` in `DrawingEditorView` e `DrawingModal`; CSS `!important` su topbar e bottoni per battere specificità Obsidian dark theme
---
## BUG APERTO — Handwriting disabilitato nel documento quando il riquadro è presente
**Sintomo**: quando nel documento è presente un riquadro handwriting con un disegno (SVG non vuoto), la stylus handwriting-to-text di Android smette di funzionare nell'intero editor. Cancellare il riquadro ripristina l'handwriting. Il problema persiste tra riavvii di Obsidian.
**Progressione delle scoperte**:
**Fase 1 — Formato code block** (tentativi 16-26):
- `contenteditable="false"` su wrapper CM6 → rimosso → non risolve
- `touch-action: none` → rimosso → non risolve
- `background-image` SVG → rimossa → non risolve
- `