Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.0] - 2025-12-15

### Removed

- Removed SVG `<foreignObject>` rendering for code blocks to improve portability across SVG renderers.
- Removed `foreignObject` from the `code_block_overflow` options (use `wrap`, `show`, `hide`, or `ellipsis`).

## [0.6.3] - 2025-12-10

### Added
Expand Down
Binary file added core
Binary file not shown.
1 change: 0 additions & 1 deletion examples/code.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ Long lines demonstrate overflow handling. The `code_block_overflow` style contro
| `show` | Let content overflow visible |
| `hide` | Clip hidden content |
| `ellipsis` | Truncate with `...` |
| `foreignObject` | Scrollable HTML embed |

Here's a long line:

Expand Down
2 changes: 1 addition & 1 deletion notes/INITIAL_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ highlight = ["pygments"] # For syntax highlighting
- **Font metrics mode**: Use actual font files for precise measurement
- **Syntax highlighting**: Pygments integration for code blocks
- **Themes**: Built-in dark/light themes
- **HTML fallback**: Option to embed `<foreignObject>` for complex content
- **HTML fallback**: Avoid `<foreignObject>`; prefer pure SVG primitives for portability

## Timeline

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "markdown-svg"
version = "0.6.3"
version = "0.7.0"
description = "Convert Markdown to SVG with automatic text wrapping"
readme = "README.md"
license = { text = "MIT" }
Expand Down
6 changes: 3 additions & 3 deletions src/mdsvg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

Basic usage:
>>> from mdsvg import render
>>> svg = render("# Hello World\\n\\nThis is **bold** text.")
>>> svg = render("# Hello World\n\nThis is **bold** text.")

With custom styling:
>>> from mdsvg import render, Style
>>> svg = render("# Hello", width=400, style=Style(text_color="#333"))

Measure dimensions without rendering:
>>> from mdsvg import measure
>>> size = measure("# Hello\\n\\nLong paragraph...")
>>> size = measure("# Hello\n\nLong paragraph...")
>>> print(f"Height: {size.height}px")
"""

Expand Down Expand Up @@ -70,7 +70,7 @@
UnorderedList,
)

__version__ = "0.6.3"
__version__ = "0.7.0"

__all__ = [
# Main API
Expand Down
47 changes: 5 additions & 42 deletions src/mdsvg/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,12 +370,13 @@ def _render_code_block(
"""Render a code block with background."""
overflow = self.style.code_block_overflow

if overflow == "foreignObject":
return self._render_code_block_foreign_object(code, ctx)
elif overflow == "wrap":
if overflow == "wrap":
return self._render_code_block_wrapped(code, ctx)
else:
elif overflow in {"show", "hide", "ellipsis"}:
return self._render_code_block_simple(code, ctx, overflow)
else:
# Defensive fallback (should be unreachable due to typing)
return self._render_code_block_wrapped(code, ctx)

def _render_code_block_simple(
self,
Expand Down Expand Up @@ -495,44 +496,6 @@ def _render_code_block_wrapped(

return elements, total_height

def _render_code_block_foreign_object(
self,
code: CodeBlock,
ctx: RenderContext,
) -> Tuple[List[str], float]:
"""Render code block using foreignObject for scrollable HTML."""
elements: List[str] = []

padding = self.style.code_block_padding
font_size = self.style.base_font_size * 0.9
line_height = font_size * 1.4

lines = code.code.split("\n")
# Cap height for scrollable content
max_visible_lines = 20
visible_lines = min(len(lines), max_visible_lines)
text_height = visible_lines * line_height
total_height = text_height + (padding * 2)

escaped_code = escape_svg_text(code.code)

elements.append(
f' <foreignObject x="{format_number(ctx.x)}" y="{format_number(ctx.y)}" '
f'width="{format_number(ctx.width)}" height="{format_number(total_height)}">'
f'<div xmlns="http://www.w3.org/1999/xhtml" style="'
f"width: 100%; height: 100%; overflow: auto; "
f"background: {self.style.code_background}; "
f"border-radius: {self.style.code_block_border_radius}px; "
f'box-sizing: border-box; padding: {padding}px;">'
f'<pre style="margin: 0; font-family: {self.style.mono_font_family}; '
f"font-size: {font_size}px; line-height: {line_height}px; "
f"color: {self.style.text_color}; white-space: pre; "
f'overflow-x: auto;">{escaped_code}</pre>'
f"</div></foreignObject>"
)

return elements, total_height

def _render_blockquote(
self,
bq: Blockquote,
Expand Down
4 changes: 2 additions & 2 deletions src/mdsvg/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Any, Literal, Optional

# Code block overflow options
CodeBlockOverflow = Literal["wrap", "show", "hide", "ellipsis", "foreignObject"]
CodeBlockOverflow = Literal["wrap", "show", "hide", "ellipsis"]


@dataclass(frozen=True)
Expand Down Expand Up @@ -93,7 +93,7 @@ class Style:
list_item_spacing: float = 4.0
code_block_padding: float = 12.0
code_block_border_radius: float = 4.0
code_block_overflow: CodeBlockOverflow = "wrap" # wrap, show, hide, ellipsis, foreignObject
code_block_overflow: CodeBlockOverflow = "wrap" # wrap, show, hide, ellipsis
blockquote_padding: float = 16.0
blockquote_border_width: float = 3.0

Expand Down
2 changes: 1 addition & 1 deletion tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def test_version(self) -> None:
"""Test version is available."""
from mdsvg import __version__

assert __version__ == "0.5.0"
assert __version__ == "0.7.0"


class TestRealWorldExamples:
Expand Down