From 8024d0a25cba3b9e06df3a346d4e11545874698e Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Fri, 19 Sep 2025 15:49:53 -0500 Subject: [PATCH] fix: correct SVG text positioning to match React component alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjusted SVG text element positioning to precisely match React component foreignObject calculations, eliminating the "down" positioning offset that made server-rendered SVGs appear misaligned compared to client-rendered versions. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- packages/abacus-react/examples/README.md | 2 +- packages/abacus-react/examples/basic-usage.svg | 2 +- packages/abacus-react/examples/custom-styling.svg | 2 +- packages/abacus-react/examples/interactive.svg | 2 +- packages/abacus-react/examples/tutorial-mode.svg | 2 +- packages/abacus-react/generate-examples.js | 11 +++++++++-- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/abacus-react/examples/README.md b/packages/abacus-react/examples/README.md index d0615e4a..b171f002 100644 --- a/packages/abacus-react/examples/README.md +++ b/packages/abacus-react/examples/README.md @@ -26,4 +26,4 @@ Or referenced in HTML: --- _Generated automatically by generate-examples.js using react-dom/server_ -_Last updated: 2025-09-19T20:45:33.669Z_ +_Last updated: 2025-09-19T20:47:46.001Z_ diff --git a/packages/abacus-react/examples/basic-usage.svg b/packages/abacus-react/examples/basic-usage.svg index 29b4221c..509f34d1 100644 --- a/packages/abacus-react/examples/basic-usage.svg +++ b/packages/abacus-react/examples/basic-usage.svg @@ -31,4 +31,4 @@ .abacus-svg.hide-inactive-mode:not(.interactive) .abacus-bead.hidden-inactive { opacity: 0 !important; } - 123 \ No newline at end of file + 123 \ No newline at end of file diff --git a/packages/abacus-react/examples/custom-styling.svg b/packages/abacus-react/examples/custom-styling.svg index 33888e6f..f01a0159 100644 --- a/packages/abacus-react/examples/custom-styling.svg +++ b/packages/abacus-react/examples/custom-styling.svg @@ -49,4 +49,4 @@ .abacus-svg.hide-inactive-mode:not(.interactive) .abacus-bead.hidden-inactive { opacity: 0 !important; } - 789 \ No newline at end of file + 789 \ No newline at end of file diff --git a/packages/abacus-react/examples/interactive.svg b/packages/abacus-react/examples/interactive.svg index 4f7184a2..b292fec2 100644 --- a/packages/abacus-react/examples/interactive.svg +++ b/packages/abacus-react/examples/interactive.svg @@ -31,4 +31,4 @@ .abacus-svg.hide-inactive-mode:not(.interactive) .abacus-bead.hidden-inactive { opacity: 0 !important; } - 456 \ No newline at end of file + 456 \ No newline at end of file diff --git a/packages/abacus-react/examples/tutorial-mode.svg b/packages/abacus-react/examples/tutorial-mode.svg index 8de8757d..5406a81b 100644 --- a/packages/abacus-react/examples/tutorial-mode.svg +++ b/packages/abacus-react/examples/tutorial-mode.svg @@ -31,4 +31,4 @@ .abacus-svg.hide-inactive-mode:not(.interactive) .abacus-bead.hidden-inactive { opacity: 0 !important; } - 42 \ No newline at end of file + 42 \ No newline at end of file diff --git a/packages/abacus-react/generate-examples.js b/packages/abacus-react/generate-examples.js index a045729e..bd814a21 100644 --- a/packages/abacus-react/generate-examples.js +++ b/packages/abacus-react/generate-examples.js @@ -274,10 +274,17 @@ async function generateSVGExamples() { if (xMatch && yMatch && widthMatch && heightMatch) { const x = parseFloat(xMatch[1]) + parseFloat(widthMatch[1]) / 2; // Center horizontally - const y = parseFloat(yMatch[1]) + parseFloat(heightMatch[1]) / 2 + 4; // Center vertically with slight offset + + // Match React component positioning exactly: + // foreignObject y = (baseHeight + 25) - (8 * scaleFactor) + // foreignObject height = 16 * scaleFactor + // Text should be centered within foreignObject + const scaleFactor = example.props.scaleFactor || 1.0; + const foreignObjectY = parseFloat(yMatch[1]); + const foreignObjectHeight = parseFloat(heightMatch[1]); + const y = foreignObjectY + foreignObjectHeight / 2; // Center within foreignObject // Calculate font size to match React component: Math.max(8, 14 * scaleFactor) - const scaleFactor = example.props.scaleFactor || 1.0; const fontSize = Math.max(8, 14 * scaleFactor); return `${textContent.trim()}`;