diff --git a/src/flowchart/flowchart-canvas.js b/src/flowchart/flowchart-canvas.js index cd9bc83..632d2d1 100644 --- a/src/flowchart/flowchart-canvas.js +++ b/src/flowchart/flowchart-canvas.js @@ -223,12 +223,16 @@ function createCanvas(container, store, opts = {}) { ev.preventDefault(); return; } - // Click on empty canvas: add a process node at the click point. + // Click on empty canvas: hand off to the controller via onEmptyClick so it + // can prompt the user for the shape kind + label. v4.13.0 — the canvas + // no longer auto-creates a process node with placeholder label "Node". if (ev.target === svg || ev.target === nodesLayer || ev.target === edgesLayer) { const p = getSvgPoint(ev.clientX, ev.clientY); const x = Math.max(0, p.x - DEFAULT_WIDTH / 2); const y = Math.max(0, p.y - DEFAULT_HEIGHT / 2); - store.addNode({ kind: 'process', x, y, label: 'Node' }); + if (typeof opts.onEmptyClick === 'function') { + opts.onEmptyClick(x, y, ev); + } ev.preventDefault(); } } diff --git a/src/renderer/flowchart-controller.js b/src/renderer/flowchart-controller.js index 187c7f1..26c8fbe 100644 --- a/src/renderer/flowchart-controller.js +++ b/src/renderer/flowchart-controller.js @@ -59,6 +59,8 @@ const { create: createStore } = window.FlowchartStore; const { createCanvas } = window.FlowchartCanvas; const { toMermaid } = window.FlowchartMermaid; + const { promptInline, confirmInline: _confirmInline } = window.FlowchartModals || {}; + void _confirmInline; // exposed by the bundle for future use (e.g. reset confirmation) // FlowchartShapes is intentionally unused here but its presence is // required for createCanvas() to function; the guard above guarantees it. @@ -66,6 +68,9 @@ const PERSIST_DEBOUNCE_MS = 500; const PERSISTENCE_FILENAME = 'flowchart-session.json'; + const NODE_KIND_OPTIONS_TEXT = 'process, decision, terminator, subroutine, document'; + const EDGE_KIND_OPTIONS_TEXT = 'solid, dotted, thick'; + let _userDataPath = null; let _persistenceFile = null; let _previewTimer = null; @@ -132,14 +137,25 @@ }); _canvas = createCanvas(els.canvasHost, _store, { - onEdgeClick: (edgeId) => { + onEdgeClick: async (edgeId) => { const edge = _store.getGraph().edges.find((e) => e.id === edgeId); if (!edge) return; - const nextKind = window.prompt('Edge kind (solid, dotted, thick):', edge.kind); + // v4.13.0 — replace window.prompt() with the inline modal helper. + // Two sequential prompts: kind first (with the current value as + // default), then label. + const nextKind = await promptInline({ + title: 'Edge Style', + message: `Style (${EDGE_KIND_OPTIONS_TEXT}):`, + defaultValue: edge.kind, + }); if (nextKind && ['solid', 'dotted', 'thick'].includes(nextKind)) { _store.setEdgeKind(edgeId, nextKind); } - const nextLabel = window.prompt('Edge label (empty to clear):', edge.label || ''); + const nextLabel = await promptInline({ + title: 'Edge Label', + message: 'Empty to clear:', + defaultValue: edge.label || '', + }); if (nextLabel !== null) { _store.setEdgeLabel(edgeId, nextLabel); } @@ -148,12 +164,33 @@ // Canvas already paints the .selected highlight; nothing else // needed here for selection state. }, - onShapeMenu: (nodeId) => { - const next = window.prompt( - 'New shape (process, decision, terminator, subroutine, document):' - ); + onShapeMenu: async (nodeId) => { + const node = _store.getGraph().nodes.find((n) => n.id === nodeId); + if (!node) return; + const next = await promptInline({ + title: 'Change Shape', + message: `New shape (${NODE_KIND_OPTIONS_TEXT}):`, + defaultValue: node.kind, + }); if (next) _store.setNodeKind(nodeId, next); }, + onEmptyClick: async (x, y) => { + // v4.13.0 — canvas click no longer auto-creates a process node + // with literal label "Node". User picks the shape kind first. + const kind = await promptInline({ + title: 'Add Node', + message: `Shape (${NODE_KIND_OPTIONS_TEXT}):`, + defaultValue: 'process', + }); + if (!kind) return; + const label = await promptInline({ + title: 'Node Label', + message: 'Label (empty for "Node"):', + defaultValue: '', + }); + const finalLabel = label && label.length > 0 ? label : 'Node'; + _store.addNode({ kind, x, y, label: finalLabel }); + }, }); _store.subscribe(() => {