Spancraft
A powerful Flutter package for rendering richly formatted text with markdown-like syntax and interactive elements. Spancraft automatically detects and styles bold text, italic text, links, and hashtags with customizable styles and tap callbacks.
Features
- Markdown-like Syntax: Apply bold and italic formatting using customizable delimiters (default:
*for bold,_for italic) - Auto-linked URLs: Automatically detects and highlights HTTP/HTTPS URLs and domain-based links
- Hashtag Detection: Recognizes and styles hashtags (text starting with
#) - Interactive Elements: Tap callbacks for links and hashtags with full URL/hashtag text passed to handlers
- Customizable Styling: Define separate
SmartTextStyleobjects for normal, bold, italic, link, and hashtag text - Text Layout Control: Full support for text alignment, direction (LTR/RTL), overflow handling, and max lines
- Touch Slop Detection: Intelligent tap detection that differentiates between taps and scrolling/panning gestures
Getting started
Prerequisites
- Flutter SDK >= 2.0.0
- Dart >= 2.12.0
Installation
Add this to your pubspec.yaml:
dependencies:
spancraft: ^1.0.0
Then run:
flutter pub get
Usage
Basic Example
import 'package:spancraft/spancraft.dart';
import 'package:flutter/material.dart';
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RichText(
text: TextSpan(
children: [
SmartTextSpan(
text: 'Check out *Google* and visit _github.com_ for #awesome code!',
normalStyle: SmartTextStyle(
style: TextStyle(color: Colors.black),
),
boldStyle: SmartTextStyle(
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
symbol: '*',
),
italicStyle: SmartTextStyle(
style: TextStyle(
color: Colors.black,
fontStyle: FontStyle.italic,
),
symbol: '_',
),
linkStyle: SmartTextStyle(
style: TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
),
),
hashtagsStyle: SmartTextStyle(
style: TextStyle(
color: Colors.purple,
fontWeight: FontWeight.bold,
),
),
onLinkTap: (url) {
print('Link tapped: $url');
// Handle link tap, e.g., launch URL
},
onHashtagTap: (tag) {
print('Hashtag tapped: $tag');
// Handle hashtag tap, e.g., search for hashtag
},
),
],
),
);
}
}
SmartTextStyle
Each text element type can be styled using SmartTextStyle:
SmartTextStyle(
style: TextStyle(
color: Colors.blue,
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
symbol: '*', // Optional: symbol for bold/italic text
)
Customizing Formatting Symbols
By default, bold uses * and italic uses _. You can customize these:
boldStyle: SmartTextStyle(
style: TextStyle(fontWeight: FontWeight.bold),
symbol: '**', // Use ** instead of *
),
italicStyle: SmartTextStyle(
style: TextStyle(fontStyle: FontStyle.italic),
symbol: '__', // Use __ instead of _
),
Text Configuration
SmartTextSpan(
text: 'Your formatted text here',
normalStyle: normalStyle,
boldStyle: boldStyle,
italicStyle: italicStyle,
linkStyle: linkStyle,
hashtagsStyle: hashtagStyle,
textDirection: TextDirection.ltr, // or RTL
textAlign: TextAlign.left, // left, center, right, etc.
overflow: TextOverflow.ellipsis, // How to handle overflow
maxLines: 3, // null for unlimited
)
How It Works
Spancraft uses regular expressions to parse text and identify formatted elements:
- Bold Text: Detected by wrapping with the bold symbol (default:
*bold*) - Italic Text: Detected by wrapping with the italic symbol (default:
_italic_) - Links: Detected by:
- URLs starting with
http://,https://, orwww. - Domain-based links like
example.comorsub.example.com/path
- URLs starting with
- Hashtags: Detected by
#prefix followed by word characters (e.g.,#flutter)
Each detected element is positioned and styled independently, and tap events are accurately mapped to the correct element.
Advanced Features
Handling Link Taps
The onLinkTap callback receives the full URL or domain:
onLinkTap: (url) {
// url contains the detected link (e.g., "https://example.com")
launchUrl(Uri.parse(url));
}
Handling Hashtag Taps
The onHashtagTap callback receives the hashtag including the # symbol:
onHashtagTap: (tag) {
// tag contains the hashtag (e.g., "#flutter")
navigateToHashtagPage(tag);
}
Fine-tuning Touch Detection
The touch slop threshold (18.0 logical pixels by default) determines when a pointer movement cancels a tap. This prevents accidental taps while scrolling.
Example App
See the example/ folder for a complete working example with various use cases.
API Reference
SmartTextStyle
class SmartTextStyle {
final TextStyle style;
final String? symbol; // Optional formatting symbol
}
SmartTextSpan
Create styled text spans with automatic element detection and interactive callbacks.
Limitations
- Formatting symbols must not overlap or nest (e.g.,
*_bold and italic_*may not render as expected) - Regular expression limitations apply to very complex text patterns
- Custom regex patterns are not currently supported (feature for future versions)
Contributing
Contributions are welcome! Please feel free to open issues and submit pull requests on GitHub.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
For questions or issues, please open an issue on the GitHub repository.