diff --git a/src/flowchart-generator.html b/src/flowchart-generator.html index 1d06087..7684cba 100644 --- a/src/flowchart-generator.html +++ b/src/flowchart-generator.html @@ -185,6 +185,77 @@ .flowchart-edge { stroke: #1f2328 !important; } + /* v4.13.0 — visual polish. Adds a visible selection ring (was + previously only the .selected class without a distinct colour), + a hover tint, an enlarged resize-handle hit area, a smoother + modal dialog animation, and a proper opaque background behind + edge labels so they stay readable across curved connectors. */ + .flowchart-node { + cursor: grab; + transition: filter 0.12s ease-out; + } + .flowchart-node:hover .flowchart-node-shape { + filter: drop-shadow(0 0 2px rgba(37, 99, 235, 0.45)); + } + .flowchart-node.selected .flowchart-node-shape { + stroke: #2563eb !important; + stroke-width: 2.25; + } + .flowchart-edge { + cursor: pointer; + } + .flowchart-edge:hover { + stroke: #2563eb !important; + } + .flowchart-edge.selected { + stroke: #2563eb !important; + stroke-width: 2.5; + } + /* Resize handle — larger invisible hit area + visible square. */ + .flowchart-resize-handle { + cursor: nwse-resize; + } + .flowchart-resize-handle-hit { + fill: transparent; + stroke: none; + } + .flowchart-resize-handle-grip { + fill: #2563eb; + stroke: #1e40af; + stroke-width: 1; + } + /* Edge label background — keeps labels legible across curves by + giving them an opaque white pill behind the text. */ + .flowchart-edge-label-bg { + fill: #ffffff; + stroke: #d1d5db; + stroke-width: 0.5; + } + /* Modal dialog — fade + scale-in entrance. */ + .fc-modal { + animation: fc-modal-in 0.15s ease-out; + } + @keyframes fc-modal-in { + from { + opacity: 0; + transform: translate(-50%, -50%) scale(0.96); + } + to { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } + } + .fc-modal-overlay { + animation: fc-overlay-in 0.12s ease-out; + } + @keyframes fc-overlay-in { + from { + opacity: 0; + } + to { + opacity: 1; + } + } /* v4.10.0 — preview-render info card explaining the layout */ .fc-preview-render-note { font-size: 0.75rem; diff --git a/src/flowchart/flowchart-canvas.js b/src/flowchart/flowchart-canvas.js index cfb4441..bfe201b 100644 --- a/src/flowchart/flowchart-canvas.js +++ b/src/flowchart/flowchart-canvas.js @@ -232,21 +232,29 @@ function createCanvas(container, store, opts = {}) { // v4.13.0 — bottom-right resize handle on the selected node. A // single square handle is enough for v1; multi-handle (4 corners // + 4 edges) is a follow-up. Width is the only mutable dimension. + // Two rects: a larger transparent hit area (24px) so the handle is + // easier to grab, plus a smaller visible grip (10px) styled via CSS. if (node.id === selectedNodeId) { - const handleSize = 10; - const handle = svgEl('rect', { - x: w - handleSize / 2, - y: DEFAULT_HEIGHT - handleSize / 2, - width: handleSize, - height: handleSize, - fill: '#e5461f', - stroke: '#ffffff', - 'stroke-width': 1, - class: 'flowchart-resize-handle', + const gripSize = 10; + const hitSize = 24; + const hit = svgEl('rect', { + x: w - hitSize / 2, + y: DEFAULT_HEIGHT - hitSize / 2, + width: hitSize, + height: hitSize, + class: 'flowchart-resize-handle flowchart-resize-handle-hit', 'data-resize-node': node.id, - cursor: 'nwse-resize', }); - g.appendChild(handle); + const grip = svgEl('rect', { + x: w - gripSize / 2, + y: DEFAULT_HEIGHT - gripSize / 2, + width: gripSize, + height: gripSize, + rx: 2, + class: 'flowchart-resize-handle flowchart-resize-handle-grip', + }); + g.appendChild(hit); + g.appendChild(grip); } nodesLayer.appendChild(g); diff --git a/tests/flowchart-align.test.js b/tests/flowchart-align.test.js index fb9fbbf..f51074e 100644 --- a/tests/flowchart-align.test.js +++ b/tests/flowchart-align.test.js @@ -91,11 +91,7 @@ describe('flowchart-align: distributeHorizontally', () => { expect(out.map((node) => node.x)).toEqual([0, 300, 600, 900]); }); test('handles unsorted input by sorting first', () => { - const out = distributeHorizontally([ - n('a', 500, 0), - n('b', 0, 0), - n('c', 900, 0), - ]); + const out = distributeHorizontally([n('a', 500, 0), n('b', 0, 0), n('c', 900, 0)]); // sorted: 0, 500, 900 → gap = 450 → x = [0, 450, 900] expect(out.map((node) => node.x)).toEqual([0, 450, 900]); }); @@ -109,12 +105,7 @@ describe('flowchart-align: distributeHorizontally', () => { describe('flowchart-align: distributeVertically', () => { test('spaces 4 nodes evenly between topmost and bottommost', () => { - const out = distributeVertically([ - n('a', 0, 0), - n('b', 0, 60), - n('c', 0, 300), - n('d', 0, 900), - ]); + const out = distributeVertically([n('a', 0, 0), n('b', 0, 60), n('c', 0, 300), n('d', 0, 900)]); // gap = 900 / 3 = 300 expect(out.map((node) => node.y)).toEqual([0, 300, 600, 900]); });