# PanConverter - Updates & Changelog ## Version 4.9.4 (2026-09-14) ### Fixes - **Flowchart Panel — selection was invisible**: clicking a node or edge updated the canvas's internal `selectedNodeId` / `selectedEdgeId` but never repainted, so the `.flowchart-node.selected` / `.flowchart-edge.selected` CSS highlight only appeared when the user actually dragged (which triggers `store.subscribe` → `render()`). A bare click left the canvas looking unchanged, and the panel's own `selectedNodeId` (used by the panel-scoped Delete/Backspace shortcut) stayed `null`, so Delete on a freshly-clicked node silently no-op'd. Wired `opts.onNodeClick(id)` end-to-end: - `src/flowchart/flowchart-canvas.js` — added an `opts.onNodeClick` callback parallel to the existing `opts.onEdgeClick`; on click, both branches now call a new surgical `applySelectionHighlight()` that toggles the `.selected` class on the existing `` / `` elements without going through `render()` (which would detach the very element the user's pointer is still on, breaking `pointermove`/`pointerup` bubbling during a drag). - `src/sidebar/flowchart-panel.js` — the panel's `onNodeClick` handler mirrors the id into the panel's `selectedNodeId` (clearing `selectedEdgeId`) so Delete/Backspace routes correctly. Same symmetry was already in place for `onEdgeClick`. - **Flowchart Panel — narrow sidebar cramped the canvas + preview**: the panel lives in the 280 px sidebar, which split the canvas vs. preview to ~175 px each — too tight to edit a flowchart. Added a "Maximize / Restore" button to the panel toolbar (between the status text and the right edge). Clicking it toggles a `flowchart-takeover` class on `.main-content`: - `src/styles-sidebar.css` — new `.main-content.flowchart-takeover` rules hide `.editor-container` (`display: none`) and let `.sidebar` / `.sidebar-panel` grow with `flex: 1` so the canvas + preview split the full window width instead of the 280 px sidebar. - The button label flips between "Maximize" and "Restore", `aria-label` and `title` update, and the button gets an `.active` highlight while takeover is on. `destroy()` clears the class so leaving the panel doesn't leave the editor hidden for the rest of the session. - The class lookup walks up from the panel container to the nearest `.main-content` ancestor (with a `document.querySelector('.main-content')` fallback) so the panel doesn't need to know whether the sidebar lives inside `#sidebar` or any future container. ### Tests - `tests/flowchart-panel.test.js` — added two new `describe` blocks (8 tests total): - "selection wiring (canvas click → panel state + SVG class)": clicking a node applies `.selected` to the matching ``, clicking a second node moves `.selected` from the first to the second, clicking an edge applies `.selected` to the matching ``, and a regression test verifying Delete removes a freshly-clicked node (was broken in v4.9.3 because the panel's `selectedNodeId` was never updated by canvas clicks). - "maximize / takeover": the maximize button is exposed in the toolbar, clicking it toggles `.flowchart-takeover` on `.main-content` and flips the button label/active class, and `destroy()` clears the class so the editor stays usable. - New `mountWithMainContent()` helper wraps the panel container in a fake `.main-content` (mirroring the real DOM layout in `src/index.html:2341`) so the takeover's class-toggling is observable from the test. ## Version 4.9.3 (2026-09-14) ### Fixes - **Flowchart Panel — preview pane accumulated raw Mermaid source**: when the user fired several `addNode` mutations within the 250 ms preview debounce, `mermaid.run({ nodes: [div] })` is async, so the previous render's `
` (still carrying the source text) was sitting in `.flowchart-preview-render` when the next render cleared the target. The first render's eventual `element.innerHTML = svg` landed on a detached node, but the visible preview pane had a stack of stale `
` elements. Fixed in `src/renderer.js:2423-2449`: switched the inline `renderFlowChartMermaid` to `replaceChildren()` (more idiomatic than `innerHTML = ''`) and added a per-target `WeakSet` in-flight tracker that keeps the previous render's closure from racing the new render — its eventual `element.innerHTML = svg` is harmless on a detached node, and the new render always starts from a clean slate. ### Tests - `tests/flowchart-panel.test.js` — added a second regression test (`preview-source pre never duplicates across debounced mutations even with in-flight mermaid.render`) that fires 7 mutations at 10 ms intervals (well inside the 250 ms debounce), uses a `renderMermaid` mock that mirrors the real mermaid.run closure (captures the input div, asynchronously sets `innerHTML = svg` on it regardless of DOM connection), and asserts the `
` contains exactly one copy of the latest source and the render target holds exactly one `
` child whose first element child is the latest ``. ## Version 4.9.2 (2026-09-14) ### Fixes - **Standalone ASCII Art Generator — broken stylesheet path**: `src/ascii-generator.html:7` linked ``. The HTML loads via `BrowserWindow.loadFile(path.join(__dirname, 'ascii-generator.html'))` where `__dirname` is `src/`, so `../fonts.css` escaped the `src/` directory and resolved to a non-existent `/fonts.css`. Changed to `fonts.css` (same file, src/-relative — mirrors `src/index.html:29`). The window rendered without its font rules, leaving the header in the fallback system stack. - **Standalone ASCII Art Generator — dead Box/Templates UI**: the controller (`src/renderer/ascii-controller.js`) shipped three mode tabs (`Text Banner` / `Box-Frame` / `Templates`), 18 `.template-btn[data-template]` buttons, and a Box form (`#box-text` / `#box-style` / `#box-padding`) but wired none of them. Clicking any tab or button was a no-op. Wired all of them: - `setMode(mode)` toggles `.active` on the right `.mode-tab` and the matching `.mode-section` (`text-mode` / `box-mode` / `templates-mode`). - Template buttons call `api.generate({ text: '', font: 'template:' })` so the orchestrator owns template content; preview updates and the button gets `.active`. - Box mode renders the user text with a border using the chosen style (`single` / `double` / `rounded` / `bold` / `ascii`) and padding, exposed as a pure `window.ASCIIBoxRenderer.renderBox(text, style, padding)` helper. - All 11 brief-required behaviours (text-input / font-picker / font-search / insert / copy / save / generate, last-font persistence, debounced preview) remain intact. ### Tests - New `tests/ascii-controller.test.js` — 6 tests covering the stylesheet path (no `..` escape), pure box renderer (single + ascii styles), mode-tab switching (Box and Templates), and template button → preview wiring. ## Version 4.9.1 (2026-09-14) ### Fixes - **Flowchart Panel save failed**: `getUserDataPath()` IPC was not awaited in `src/renderer.js:2439-2449`, so the persistence path was computed as `"[object Promise]/flowchart-session.json"` and rejected by the `write-text-file` userData sandbox. Pre-resolved the path on panel register and cached it; persistence (read and write) now works correctly. ## Version 4.9.0 (2026-09-14) ### New: Visual Flow Chart Editor (Sidebar panel → "Flow Chart") - Pure `flowchart-store.js` — graph data store with bounded undo/redo (depth 50) and injectable persistence IO (testable without touching the filesystem) - 5 node shapes (process, decision, terminator, subroutine, document) × 3 edge kinds (solid, dotted, thick) with full keyboard accessibility - Hand-rolled SVG canvas: drag nodes, double-click to edit labels, Alt+drag from a node edge to wire connections, in-place label editing, delete + backspace to remove the selection - `flowchart-shapes.js` — pure SVG path templates (no DOM, fully unit-tested) - `flowchart-mermaid.js` — translates the graph to Mermaid `flowchart TD` source that renders identically in the preview pane - Sidebar panel `src/sidebar/flowchart-panel.js` with debounced preview (250 ms), debounced persistence (500 ms), and Ctrl+Z / Ctrl+Shift+Z / Delete / Backspace shortcuts - 3 thin IPC channels (`get-user-data-path`, `read-text-file`, `write-text-file`) sandboxed to `app.getPath('userData')` via path validation - Auto-save to `/flowchart-session.json`; restores on reopen - Rail button in the sidebar; toggle the panel with `Ctrl+Alt+F` - Insert-at-Cursor wraps the generated Mermaid in a fenced ` ```mermaid ` block at the current cursor position in the active editor tab - 73 new tests ### New: ASCII Art Generator upgrade - Pure `AsciiArt` orchestrator (`generate / listFonts / getFontMeta`) unifying hand-coded fonts + figlet + 19 named templates behind one API - 17 hand-coded font tables extracted from inline renderer code (5 existing + 12 new: Big, Small, Lean, Slant, Isometric1-4, 3-D, 3x5, ANSI Shadow, Calvin S) - 19 named ASCII templates (arrows, flowcharts, banners, frames) - `figlet@^1.8.0` dep with lazy-load + cache adapter (≥328 bundled fonts; pure JS, no native bindings) - 6 IPC handlers: `ascii:generate / list-fonts / get-font-meta / save / copy / last-font` - Standalone window rewrite: removed the ~385-line inline script; added a searchable font picker, Copy to Clipboard, and Save to File - Major cleanup: -1029 net lines of dead code (the in-app modal `#ascii-art-dialog`, the 800-line renderer controller, the `show-ascii-generator*` preload channels, and the obsolete `textToASCII`/`createASCIIBox`/etc. helpers) - 97 new tests ### New: Editor Theme Registry (extension) - 12 new themes added: Catppuccin Latte / Frappé / Macchiato / Mocha, One Light, Tokyo Night Storm, Synthwave '84, Outrun, Winter is Coming (Light + Dark), Solarized Dark High Contrast, Spring Light - Total: 37 themes (15 light + 22 dark incl. 1 high-contrast), sorted into Light / Dark / High-Contrast tables in the README - Pure `ThemeRegistry` module; the View menu generator now reads `list() + categories()`; new per-theme CSS files live at `src/styles/themes/.css` - `` preload + `` toggle pattern (sub-millisecond theme switch — no flash, no re-fetch) - Aria-friendly: the high-contrast option is announced to assistive tech ### Bug fixes - Plan 3: rail button tooltip `Ctrl+Alt+F` now actually wired (the shortcut existed but the panel toggle was missing) - Plan 3: `destroy()` cleanup on panel unmount — timers, listeners, and the store subscription are all released (no leaks when toggling repeatedly) - Plan 2: standalone window `