Migration to 1.2

The 1.2 release line is a drop-in upgrade for 1.1.x: your code should compile. Review these behavior and rendering changes because a clean build does not guarantee the same output. Version 1.2.1 is a patch release within this migration line.

Replace deprecated highlightBuilder

highlightBuilder still works but is scheduled for removal in 2.0. Use InlineCodeStyle for appearance, or inlineCodeBuilder when structure must change.InlineCodeStyle covers fontFamily, fontFamilyPackage,fontFamilyFallback, fontSizeFactor, fontWeight, color,backgroundColor, borderColor, borderWidth, borderRadius,padding, and boxHeightStyle. Every field is optional and an unset field follows the active ColorScheme. ACodeTextSpan preserves the package's wrapping and selection behavior; use baselineWidgetSpan only when a genuine inline widget is worth the usual WidgetSpan trade-offs.

migration.dart
1// Before: highlightBuilder returned a Widget. 2highlightBuilder: (context, text, style) => MyChip(text, style), 3 4// After: use InlineCodeStyle for appearance. Every field is optional; unset 5// values derive from ColorScheme and keep the default text-chip behavior: 6styleSheet: const GptMarkdownStyleSheet( 7 inlineCode: InlineCodeStyle(fontFamily: 'GeistMono'), 8), 9 10// inlineCodeBuilder receives the resolved InlineCodeStyle. Return CodeTextSpan 11// to keep the painted chip; any other TextSpan deliberately drops it: 12inlineCodeBuilder: (context, code, style, codeStyle) => 13 CodeTextSpan(text: code, style: style, codeStyle: codeStyle), 14 15// Use baselineWidgetSpan only for a genuine inline widget. It aligns the widget 16// and handles text scaling, but WidgetSpan content cannot wrap or be selected: 17inlineCodeBuilder: (context, code, style, codeStyle) => 18 baselineWidgetSpan(MyChip(code, style))

Autolinking is now on

Bare URLs, www. hosts, and email addresses use the GFM autolink extension; angle autolinks use CommonMark §6.5. Remove any pre-processor that rewrites URLs into Markdown links—the renderer sees URLs only after surrounding syntax is consumed, so it avoids the raw-Markdown bug where **https://example.com** produces an href ending in **. Keeping both systems can duplicate or corrupt links. Disable autolinking only when legacy plain-text behavior is required.

links.dart
1// Bare URLs are linked by default in 1.2. 2GptMarkdown(text, autolink: false) // Keep legacy plain-text behavior. 3 4// Or allow an app scheme in addition to the standard schemes: 5GptMarkdown(text, autolinkSchemes: {'myapp'})

Components no longer render inside link labels by default

Widget-based inline content nested inside a link label can fail to paint on iOS. The built-in ImageMd, TableMd, and ATagMd components now use MarkdownComponent.allScopesExceptLinkLabel. Custom components still render in link labels unless they declare that same safe scope, so apply it to any custom component returning aWidgetSpan.

scopes.dart
1class MyChipMd extends InlineMd { 2 3 Set<MarkdownScope> get scopes => 4 MarkdownComponent.allScopesExceptLinkLabel; 5 6 // ... 7} 8 9// For an app-specific token, InlinePattern is the simpler safe default: 10InlinePattern.prefixed( 11 prefix: '#', 12 knownNames: channelNames, 13 builder: (context, match, style) => 14 WidgetSpan(child: ChannelChip(match.group(0)!)), 15)

InlinePattern.prefixed is the first-class alternative: it excludes link labels by default and needs no subclass. Leave genericTokenPattern null to match only the supplied knownNames; then #2959 remains an issue number instead of becoming a channel chip.

Update widget tests

Paragraphs that include inline code or need bidirectional placeholder reordering can be rendered with aRichText subclass. Exact type matching skips them, so test with a predicate.

renderer_test.dart
1// Before: exact runtime type misses BidiRichText subclasses. 2find.byType(RichText) 3 4// After: find RichText and its subclasses. 5find.byWidgetPredicate((widget) => widget is RichText)

Other behavior changes to review

Inline code is a real text chip

Inline code now uses bundled JetBrains Mono, a tinted fill, hairline outline, 4px radius, and per-line painting. It wraps across lines and remains selectable. If you need the earlier plain appearance, remove the chip background, border, and padding with InlineCodeStyle.

Text scaling is proportional

Inline widgets no longer reserve inflated space at raised system text scales: the old 2× measurements were 17× for a heading, 10× for a list, and 39× for a checkbox. Layouts tuned around that overflow may look tighter; custom WidgetSpan content should use baselineWidgetSpan or MediaQuery.withNoTextScaling.

Malformed text stays visible

Malformed links such as [[a](http://x) and [label](http://x, plus syntax no component claims, now render as source text instead of silently disappearing. Debug builds print a warning. If an app relied on malformed Markdown vanishing, that behavior has changed.

Alternation patterns are grouped before anchoring

A top-level | is now dispatched as ^(?:pattern)$ rather than ^pattern$. Re-check custom components whose alternatives may previously have claimed text from a later component.

Case-insensitive patterns now receive matches

The combined component regex now honors caseSensitive: false. A component that did not receive case-insensitive matches before may begin matching author text after the upgrade.

What is additive

GptMarkdownStyleSheet and all twelve per-component style classes, existing builders (blockQuoteBuilder, headingBuilder, checkboxBuilder,radioOptionBuilder, hrBuilder), callbacks (onCheckboxChanged,onCodeCopy, onImageTap, onSourceTagTap), MarkdownScope,InlinePattern, autolink, and autolinkSchemes are additive. Existing heading, link-color, and rule-style theme fields keep working; a style-sheet value wins only where you set it.