InlineLinkBuilder typedef
Builds the span for one [label](url) link or autolink.
details carries the URL, the already-parsed label spans, the resolved
TextStyle and LinkStyle, and a tap callback already bound to
GptMarkdown.onLinkTap — see LinkBuildDetails. It is the only parameter
this signature will ever have: new information arrives as a new field on
LinkBuildDetails, never as a new argument here.
Return LinkBuildDetails.defaultSpan to keep the stock link and change only its style, a LinkTextSpan to build it yourself, or LinkBuildDetails.asWidgetSpan when a widget is genuinely required:
inlineLinkBuilder: (link) => LinkTextSpan.wrapping(
children: [
if (link.url.endsWith('.pdf'))
const WidgetSpan(child: Icon(Icons.picture_as_pdf, size: 14)),
...link.labelSpans,
],
url: link.url,
linkStyle: link.linkStyle,
style: link.style,
hoverStyle: link.hoverStyle,
onTap: link.onTap,
),
Do not attach a GestureRecognizer to a span that has children and no text of its own — it can never fire. Use TappableTextSpan: the package resolves those by text range at the paragraph, which works for a whole subtree, covers a WidgetSpan inside the label, and owns the recognizer's lifetime.
Returning an InlineSpan rather than a Widget is what keeps a link on the text baseline, wrapping across lines, selectable, visible to the streaming reveal, and painting on iOS inside another placeholder.
Implementation
typedef InlineLinkBuilder = InlineSpan Function(LinkBuildDetails details);