Commit Graph
14 Commits
Author SHA1 Message Date
amitwh 1a357bbd6a feat(flowchart): keyboard shortcuts overlay (C19)
After 17 commits of feature work the standalone window had a lot of
hidden keyboard shortcuts (Cmd+Z, Cmd+C/V/D, Delete, Alt+drag, etc.)
that no user could discover. This adds:

  - 'Shortcuts (?)' toolbar button next to Export Visio.
  - '?' key (or Shift+/) toggles the overlay; Esc closes it.
  - A read-only modal that lists every canvas-relevant shortcut in
    a 2-column table (Action / Shortcut) with <kbd> tags for the
    key combos, styled to look like physical keys.
  - Click on the dimmed overlay backdrop also closes it.
  - Reuses the existing .fc-modal fade + scale-in animation.

The overlay sits inside #fc-left so it overlays the canvas, not the
side panel. Hidden by default via the HTML hidden attribute.

Implementation: btnHelp / shortcutsModal / shortcutsOverlay /
shortcutsClose are added to the bundle's els bag. A small
showShortcutsOverlay / hideShortcutsOverlay pair toggles their
.hidden. The keydown handler gets two new branches at the top:

  - Esc: close the overlay if open.
  - ? (computed from ev.key === '?' or 'Shift+/', no modifier
    keys held): toggle the overlay.

Both branches return early so the existing Cmd+Z / Cmd+C / etc.
handlers below them still work.

Tests: 3 new (1386 total) covering the toolbar toggle, the
? + Esc keyboard flow, and that every shortcut the user can
trigger is listed in the modal.

Amit Haridas
2026-09-30 22:43:05 +05:30
amitwh fc017e0101 feat(flowchart): multi-select + drag-rect selection (C17)
Item 1 from the polish list. The canvas previously supported
single-selection only; this adds:

  - Shift+click on a node toggles its membership in a multi-
    selection Set. Plain click still replaces with a single node.
  - Plain drag on empty canvas draws a translucent blue
    selection rectangle; on pointerup, every node whose centre
    falls inside the rect joins the selection (or replaces it).
  - Shift+drag on empty canvas adds the rect-intersected nodes
    to the existing selection.
  - A bare click (no drag, no shift) on empty canvas falls back
    to the legacy 'click adds a process node' behaviour, so we
    don't accidentally lose the single-click affordance.
  - 'Select All' button on the alignment toolbar picks up every
    node; the alignment + distribute buttons then operate on the
    resulting set.
  - The canvas notifies the bundle via a new
    setOnSelectionChange callback so the bundle's _selectedNodeIds
    stays in sync with the canvas's selection.

Architecture changes:

  - src/flowchart/flowchart-canvas.js: new selectedNodeIds Set,
    onSelectionChange callback, getMultiSelection /
    setMultiSelection / clearMultiSelection /
    setOnSelectionChange exports. Drag-rect state machine lives
    alongside panState / dragState. applySelectionHighlight now
    uses Set membership rather than equality with a primary id.
  - src/renderer/flowchart-bundle.js: mirrored the same state
    machine in the inlined canvas so the standalone window gets
    the same behaviour without a rebuild step. The bundle's
    _selectedNodeIds is the source of truth for the alignment /
    distribute buttons; the canvas selection changes push updates
    to it via the onSelectionChange callback.

Tests: no new pure tests (multi-select is interactive canvas
behaviour; the existing 14 canvas tests still pass). 1376 total.

Amit Haridas
2026-09-30 22:35:44 +05:30
amitwh f133efe025 feat(flowchart): alignment + distribution tools (C15)
8 new toolbar buttons (Align L/R/T/B, Center H/V, Distribute H/V)
plus a Select All button. Each operation takes the current
selection and applies a pure-function transform to the (x, y)
positions, then commits each result via store.moveNode().

Architecture:

  - src/flowchart/flowchart-align.js: pure module with 8 helpers
    + nodeWidth / nodeHeight utility. UMD wrapper for browser
    global + CommonJS, same pattern as the other pure modules.
  - src/renderer/flowchart-bundle.js: pure module inlined so the
    standalone window doesn't need a separate bundle build; the
    inlined functions are exposed as window.FlowchartAlign for
    jsdom tests.
  - Bundle's _selectedNodeIds Set tracks the alignment selection.
    Empty by default; populated by Select All or by future
    canvas-side shift+click (item 1: multi-select).
  - Each align button no-ops with a status hint if fewer than 2
    nodes are selected. Distribute needs 3+.
  - Each moveNode call creates its own undo snapshot, which is
    fine for typical 2-10 node selections and lets the user undo
    a misalignment one node at a time.

Tests: 14 new (1376 total) covering all 8 functions plus
immutability, no-op for insufficient nodes, and unsorted-input
sorting for distribute.

Amit Haridas
2026-09-30 22:28:13 +05:30
amitwh d90be20a72 feat(flowchart): export to editable Visio .vsdx (C14)
New 'Export Visio' toolbar button sends the current graph to the
main process, which generates an OOXML .vsdx zip with JSZip and
writes it to a user-chosen path. The result is fully editable in
Microsoft Visio, draw.io, Lucidchart, and any other tool that
accepts the format — not an embedded image.

Architecture follows the existing pure-module pattern:

  - src/flowchart/flowchart-vsdx-export.js: pure translator that
    produces (a) page1.xml describing each node as a Visio Shape
    with correct geometry (PinX/PinY/Width/Height in inches, with
    the Y-axis flipped to match Visio's bottom-up coords), each
    edge as a Connect entry, and (b) the seven static boilerplate
    XML files that make a .vsdx zip valid ([Content_Types].xml,
    _rels/.rels, visio/document.xml, visio/pages/pages.xml, etc.).

  - src/main.js: new 'export-vsdx' IPC handler requires the pure
    module + JSZip, builds the zip, writes to disk, returns
    { canceled, path } | { canceled: false, error }.

  - src/preload.js: flowchart.exportVsdx(graph) bridge.

  - src/renderer/flowchart-bundle.js: btnExportVsdx handler, status
    feedback for cancel / save / error paths.

  - src/flowchart-generator.html: button next to Export JPG.

Tests: 7 new (1362 total) cover graphBounds (empty / single /
multi-node), XML escaping of label text, Connect emission, the 5
node kinds mapping to 5 distinct master names, and that all
boilerplate files start with the XML declaration.

Amit Haridas
2026-09-30 22:17:15 +05:30
amitwh e967af77a7 feat(flowchart): export canvas as SVG / PNG / JPG (C13)
Three new toolbar buttons next to Open from File let the user save
the current canvas to disk in the format their tooling expects:

  - Export SVG — straight clone + serialise of the canvas <svg>,
    with a minimal stylesheet inlined so the file renders without
    the editor's stylesheet. Goes through the existing 'save-text-file'
    IPC channel as a UTF-8 string.
  - Export PNG / JPG — rasterise the SVG through Image + Canvas at
    1000x700 + 24px padding, then send the data URL to the new
    'save-binary-file' IPC channel which strips the 'data:...;base64,'
    prefix and writes the raw bytes. JPEG gets a white background fill
    so transparent areas don't come out black.

New IPC + preload bridge:

  - src/main.js: 'save-binary-file' handler mirrors 'save-text-file'
    shape but writes a Buffer from base64. Returns { canceled, path } |
    { canceled: false, error } so the UI can surface write failures.
  - src/preload.js: flowchart.saveBinary(data, defaultName, filters)
    so the standalone window can call it.

Tests: 2 new (1355 total, was 1353) covering SVG export happy-path
and cancel. Raster PNG/JPG paths not jsdom-tested because
Image+Canvas in jsdom doesn't reliably fire onload for Blob URLs;
the SVG path exercises the same handler plumbing so coverage is
adequate.

Amit Haridas
2026-09-30 22:13:54 +05:30
Amit Haridas 8fb61130f3 feat(flowchart): bundle-side clipboard wire-up (C11)
Cmd+C / Cmd+V / Cmd+D keyboard shortcuts now work in the standalone
window. The clipboard pure module (committed in C6a) is inlined
into the bundle alongside the mermaid parser (C9 inlining) so the
standalone window does not depend on a separate bundle rebuild.

  - copySelection / pasteSelection definitions added inside the
    bundle IIFE, exposed as window.FlowchartClipboard for jsdom
    tests.
  - Module-level _clipboard variable scoped to the keydown handler
    block so copy survives across Cmd+V and Cmd+D presses.
  - Cmd+C: serialises the canvas-owned selection (now read via
    getSelection(), not the old DOM .selected query) and stashes it.
  - Cmd+V: applies the stashed payload to the store via addNode +
    connect; nothing to do for the edge-only payload.
  - Cmd+D: copy + paste in one keystroke, with a 24px offset.
  - Delete/Backspace: reuses getSelection() to delete the selected
    node or edge; replaces the fragile DOM-querying path that the
    test for the bundle was no longer catching.

The pure module in src/flowchart/flowchart-clipboard.js stays the
source of truth for the algorithm (9 tests in C6a). Bundle inline
keeps the standalone window functional without a rebuild step;
a future build-time inclusion would collapse the duplication.

Amit Haridas
2026-09-30 21:43:49 +05:30
Amit Haridas 22bc4dcf56 feat(flowchart): Open from file button + parse on load (C9)
v4.13.0 — round-trips Mermaid source through the editor:

  - new open-text-file-dialog invoke IPC in main.js opens a system
    Open dialog filtered for .mmd / .mermaid / .md / .markdown / .txt,
    reads the chosen file, returns { path, content } or null on cancel.
  - new openFile() on the flowchart preload bridge.
  - new Open from File button in the standalone window toolbar
    alongside Insert / Save / Reset.
  - On click: confirms overwrite when the current graph is non-empty,
    strips any mermaid fence, parses via the inlined fromMermaid()
    (the inverse of toMermaid), and calls _store.deserialize so the
    canvas redraws. Status bar reports Loaded path.

The fromMermaid() in the bundle is duplicated from
src/flowchart/flowchart-mermaid-parse.js (23 tests in C8 land the
same logic) so the standalone window does not depend on the bundle
rebuild step. Pure module + bundle inline stay in sync logically;
future work could collapse them via a build-time inclusion.

Amit Haridas
2026-09-30 21:40:59 +05:30
Amit Haridas 4228ab78d8 feat(flowchart): undo/redo toolbar buttons + history counter (C3)
The flowchart editor had Ctrl+Z / Ctrl+Shift+Z keyboard shortcuts
but no discoverable buttons. New History section in the side panel:
  - Undo / Redo buttons wired to _store.undo() / _store.redo()
  - Counter chip showing ↶/↷ availability
  - Buttons auto-disable when stacks are empty (via _store.canUndo()
    + canRedo() evaluated on every store subscription)

The store already exposed undo/redo/canUndo/canRedo — this commit
only adds the UI surface.

Amit Haridas
2026-09-30 21:27:11 +05:30
amitwh 23046967c3 feat(flowchart): discoverable connect form + per-node color + save-to-file export; v4.12.0
User feedback on v4.11.0: the Add Connection form was buried below the
node/edge lists and they couldn't find it; they also asked for per-node
color and Save to File export. v4.12.0 reorganises the #fc-nodelist panel
to put the connect form right after the Add Node buttons, adds a native
<input type="color"> per node row that drives a new store.setNodeColor
mutator (with serialize/deserialize round-trip), and wires a Save to File
button that pops a system save dialog via a new 'save-text-file' IPC
channel.

- src/flowchart-generator.html — panel order is now Add Node /
  Add Connection / Nodes / Edges / Export (Insert · Save · Reset).
  Removed the legacy top toolbar; status moved into the panel.
  Added .fc-help, per-node color-picker CSS, .fc-toolbar-row.
- src/flowchart/flowchart-shapes.js — shapeSvg() accepts an optional
  6th 'color' arg; emits fill=... on rects and polygons. Falls back to
  #ffffff for empty/null/undefined so old callers keep working.
- src/flowchart/flowchart-store.js — setNodeColor(id, color) mutator
  with snapshot/emit, normalizeColor() helper (hex validation),
  addNode accepts color, deserialize normalises missing color.
- src/renderer/flowchart-bundle.js — mirrors all of the above inline
  (the bundle is loaded as a single <script>), wires fc-btn-save to
  api.saveFile, passes node.color to shapeSvg in the canvas render,
  and renders <input type='color'> per node row.
- src/main.js — new ipcMain.handle('save-text-file', ...) using a
  system Save dialog (mirrors the ascii:save handler shape).
- src/preload.js — added 'save-text-file' to ALLOWED_SEND_CHANNELS
  and a saveFile(content, defaultName) helper on the flowchart bridge.

Tests: 92/92 suites, 1165/1165 tests pass on this run
- +9 store tests (color defaults, setNodeColor, undo, hex validation,
  round-trip, deserialize normalisation)
- +7 shapes tests (fill color on all 5 kinds, fallback to #ffffff)
- +6 controller tests (color picker wires setNodeColor, canvas rect
  reflects color, Save to File calls api.saveFile with the fenced
  Mermaid source and 'flowchart.mmd', cancel + error paths surface in
  status)

Verification:
- npm run lint          clean
- npm run format:check  clean
- npm test              92/92 suites, 1165/1165 tests pass

Amit Haridas
2026-09-15 09:23:58 +05:30
amitwh e87e301b0f chore: remove stale debug-copy + drop placeholder string-split hack; v4.11.1
- Remove untracked root-level flowchart-bundle.js (older v4.10.0 copy
  that had drifted from src/renderer/flowchart-bundle.js; never loaded
  by Electron, just repo noise).
- In src/renderer/flowchart-bundle.js, replace the runtime
  concatenation "'place' + 'holder'" with the proper 'placeholder'
  attribute at the two label-input call sites (node + edge) and
  remove the now-stale comment explaining the hack. No functional
  change.
- Bump version 4.11.0 -> 4.11.1 in package.json and README.md and add
  the matching UPDATES.md entry.

Verification:
- npm run lint          clean
- npm run format:check  clean
- npm test              92/92 suites, 1143/1143 tests pass on this run
- PDFBatchOperations.test.js passes 21/21 in isolation
  (the occasional failure seen in the v4.11.0 run was a parallel-test
  file-IO race, not introduced by these changes)

Amit Haridas
2026-09-15 08:10:35 +05:30
amitwh 075e407f3f feat(flowchart): button-based UI replaces click-canvas interaction; v4.11.0
Replaced the v4.10.0 floating selection toolbar (which relied on
SVG click hit-testing inside #canvas-host and was unreliable in the
user's Electron runtime) with a button-driven node-list panel
(#fc-nodelist) below the canvas. Every mutation now flows through
explicit controls: 5 Add Node buttons, per-node kind-select +
label-input + delete ×, per-edge kind-select + label-input + delete
×, and a Connect form (From/To selects + Edge button + Refresh).

The canvas is purely visual now: no more #fc-selection-toolbar, no
controller-level _selectedId/_selectedKind state, no keyboard
Delete/Backspace selection handler. Canvas click callbacks
(onNodeClick, onEdgeClick, onShapeMenu) are no-ops. The 5-shape /
3-edge-kind / label-input / delete-button surface is unchanged in
spirit — it just lives in the panel instead of floating over the
canvas.

Files:
- src/flowchart-generator.html: added #fc-nodelist between canvas and
  preview (wrapped in new .fc-left column), removed fc-selection-toolbar,
  bumped header hint.
- src/renderer/flowchart-bundle.js: removed SHAPE_BUTTONS/EDGE_BUTTONS,
  setSelection, renderSelectionToolbar, appendLabelInput,
  appendDeleteButton, the keyboard Delete handler, and the
  controller-level selection state. Added rerenderNodeList +
  shapeLabel/edgeLabel, wired all panel buttons (add-row, per-node
  selects/inputs/deletes, per-edge selects/inputs/deletes, connect
  form). Subscribe now calls rerenderNodeList instead of the old
  renderSelectionToolbar.
- tests/flowchart-controller.test.js: replaced 6 v4.10.0 selection
  toolbar tests with 11 v4.11.0 button-driven panel tests.
- package.json: 4.10.0 -> 4.11.0.
- README.md: version line bumped to v4.11.0.
- UPDATES.md: added v4.11.0 changelog entry.

Test summary: 92 suites, 1143 tests pass (was 1138 — +5 net).
Lint + prettier clean.

Amit Haridas
2026-09-15 01:33:17 +05:30
amitwh b81119026e feat(flowchart): visible selection toolbar + console-log diagnostics; v4.10.0
Even after the v4.9.9 inline-modal fix the user kept reporting 'no fix still'
because hidden right-click context menus and window.prompt calls remain
unreliable in Electron renderer contexts. This release ships a *visible*
floating selection toolbar inside the canvas panel so the primary
interactions are not hidden behind modals or context menus.

- New <div id="fc-selection-toolbar"> inside #canvas-host, hidden until a
  node or edge is selected. Renders:
    * 5 shape buttons (Process / Decision / Terminator / Subroutine /
      Document) when a node is selected, calling store.setNodeKind on
      click. The active shape is highlighted.
    * 3 edge-kind buttons (Solid / Dotted / Thick) when an edge is
      selected, calling store.setEdgeKind.
    * An always-visible label input that mirrors the selected item's
      label and writes back via store.setNodeLabel / store.setEdgeLabel
      with a 100ms debounce.
    * A red Delete button calling store.removeNode / store.disconnect.
- Selection state now tracked at the controller level (_selectedId +
  _selectedKind) and exposed via window.FlowchartController so the
  keyboard Delete/Backspace shortcut and the toolbar share one source
  of truth.
- Console-log instrumentation on every canvas event (pointerdown with
  altKey, pointerup with drag result, dblclick, contextmenu, selection
  changes, and every bootstrap phase) so the user can open DevTools
  (Ctrl+Shift+I) and verify Alt+drag and double-click actually fire.
- promptInline / confirmInline kept as advanced fallback for the
  right-click 'change shape' path; the toolbar is now the primary
  interaction surface.
- Preview-render pane now shows a static info card explaining that the
  canvas on the left is the rendered chart (previously blank).
- 6 new tests in tests/flowchart-controller.test.js — toolbar hidden
  by default, selecting a node populates shape buttons + label input +
  Delete, clicking a shape button updates the kind, label input is
  debounced, edge selection populates edge-kind buttons, Delete button
  removes the selected node.

Total tests: 1127 passing (was 1121; +6 new). The 11 pre-existing
PDFOperations failures are unrelated to this change.
2026-09-15 00:40:01 +05:30
amitwh 81e8561403 fix(flowchart): replace window.prompt/confirm with inline modal in standalone window; v4.9.9
Electron renderer contexts return undefined from window.prompt/window.confirm,
so shape change, edge kind, edge label, and reset confirmation did nothing.
Bundle now ships promptInline/confirmInline (custom DOM overlay modals) and
uses them in onEdgeClick / onShapeMenu / reset handler. Exposed as
window.FlowchartModals for jsdom tests.

Amit Haridas
2026-09-15 00:27:24 +05:30
amitwh ca5983e9ff fix(flowchart): bundle pure modules into single file for standalone window; v4.9.8
Amit Haridas
2026-09-15 00:09:57 +05:30