fix: convert foreignObject to native SVG text elements

Added post-processing to convert foreignObject elements containing HTML divs
to native SVG text elements for better browser compatibility. Numbers now
display properly in GitHub's SVG renderer using:

- Native <text> elements instead of <foreignObject><div>
- Proper positioning calculated from original foreignObject dimensions
- Centered text with monospace font styling

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-09-19 15:44:15 -05:00
parent 1364b11ed1
commit 3ccc753a82
6 changed files with 25 additions and 5 deletions

View File

@@ -26,4 +26,4 @@ Or referenced in HTML:
---
_Generated automatically by generate-examples.js using react-dom/server_
_Last updated: 2025-09-19T20:42:42.450Z_
_Last updated: 2025-09-19T20:44:02.744Z_

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -31,4 +31,4 @@
.abacus-svg.hide-inactive-mode:not(.interactive) .abacus-bead.hidden-inactive {
opacity: 0 !important;
}
</style></defs><rect x="11" y="0" width="3" height="160" fill="rgb(0, 0, 0, 0.1)" stroke="none"></rect><rect x="36" y="0" width="3" height="160" fill="rgb(0, 0, 0, 0.1)" stroke="none"></rect><rect x="0" y="30" width="50" height="2" fill="black" stroke="none"></rect><g class="abacus-bead inactive " transform="translate(4.100000000000001, 10)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="rgb(211, 211, 211)" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(4.100000000000001, 33)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#A23B72" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(4.100000000000001, 45.5)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#A23B72" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(4.100000000000001, 58)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#A23B72" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(4.100000000000001, 70.5)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#A23B72" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead inactive " transform="translate(29.1, 10)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="rgb(211, 211, 211)" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(29.1, 33)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#2E86AB" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(29.1, 45.5)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#2E86AB" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead inactive " transform="translate(29.1, 65.5)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="rgb(211, 211, 211)" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead inactive " transform="translate(29.1, 78)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="rgb(211, 211, 211)" stroke="#000" stroke-width="0.5"></polygon></g><rect x="0.5" y="133" width="24" height="24" fill="#f5f5f5" stroke="#ccc" stroke-width="1" rx="3" style="cursor:pointer"></rect><rect x="25.5" y="133" width="24" height="24" fill="#f5f5f5" stroke="#ccc" stroke-width="1" rx="3" style="cursor:pointer"></rect><foreignObject x="0.5" y="137" width="24" height="16" style="pointer-events:none"><div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:14px;font-family:monospace;font-weight:bold;pointer-events:auto;cursor:pointer">4</div></foreignObject><foreignObject x="25.5" y="137" width="24" height="16" style="pointer-events:none"><div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:14px;font-family:monospace;font-weight:bold;pointer-events:auto;cursor:pointer">2</div></foreignObject></svg>
</style></defs><rect x="11" y="0" width="3" height="160" fill="rgb(0, 0, 0, 0.1)" stroke="none"></rect><rect x="36" y="0" width="3" height="160" fill="rgb(0, 0, 0, 0.1)" stroke="none"></rect><rect x="0" y="30" width="50" height="2" fill="black" stroke="none"></rect><g class="abacus-bead inactive " transform="translate(4.100000000000001, 10)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="rgb(211, 211, 211)" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(4.100000000000001, 33)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#A23B72" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(4.100000000000001, 45.5)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#A23B72" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(4.100000000000001, 58)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#A23B72" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(4.100000000000001, 70.5)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#A23B72" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead inactive " transform="translate(29.1, 10)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="rgb(211, 211, 211)" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(29.1, 33)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#2E86AB" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead active " transform="translate(29.1, 45.5)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="#2E86AB" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead inactive " transform="translate(29.1, 65.5)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="rgb(211, 211, 211)" stroke="#000" stroke-width="0.5"></polygon></g><g class="abacus-bead inactive " transform="translate(29.1, 78)" style="cursor:grab;touch-action:none;transition:opacity 0.2s ease-in-out"><polygon points="8.399999999999999,0 16.799999999999997,6 8.399999999999999,12 0,6" fill="rgb(211, 211, 211)" stroke="#000" stroke-width="0.5"></polygon></g><rect x="0.5" y="133" width="24" height="24" fill="#f5f5f5" stroke="#ccc" stroke-width="1" rx="3" style="cursor:pointer"></rect><rect x="25.5" y="133" width="24" height="24" fill="#f5f5f5" stroke="#ccc" stroke-width="1" rx="3" style="cursor:pointer"></rect><text x="12.5" y="149" text-anchor="middle" dominant-baseline="middle" font-family="monospace" font-weight="bold" font-size="12" fill="#333">4</text><text x="37.5" y="149" text-anchor="middle" dominant-baseline="middle" font-family="monospace" font-weight="bold" font-size="12" fill="#333">2</text></svg>

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -262,6 +262,26 @@ async function generateSVGExamples() {
);
}
// Replace foreignObject elements with native SVG text elements for better compatibility
svgMarkup = svgMarkup.replace(
/<foreignObject([^>]*)><div[^>]*>([^<]+)<\/div><\/foreignObject>/g,
(match, attributes, textContent) => {
// Extract x, y, width, height from foreignObject
const xMatch = attributes.match(/x="([^"]+)"/);
const yMatch = attributes.match(/y="([^"]+)"/);
const widthMatch = attributes.match(/width="([^"]+)"/);
const heightMatch = attributes.match(/height="([^"]+)"/);
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
return `<text x="${x}" y="${y}" text-anchor="middle" dominant-baseline="middle" font-family="monospace" font-weight="bold" font-size="12" fill="#333">${textContent.trim()}</text>`;
}
return match; // Return original if we can't parse
}
);
// Add metadata as comments
const svgWithMetadata = `<!-- ${example.description} -->
<!-- Generated from: ${JSON.stringify(example.props, null, 2).replace(/-->/g, '--&gt;')} -->