flutter_interactive_text 0.2.1
flutter_interactive_text: ^0.2.1 copied to clipboard
A performant Flutter widget for detecting, styling, interacting with, and optionally expanding rich text patterns.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_interactive_text/flutter_interactive_text.dart';
void main() => runApp(const ExampleApp());
const orderType = InteractiveTextType('order');
final exampleParser = InteractiveTextParser(
detectors: [
...InteractiveTextDetectors.defaults(),
RegexInteractiveTextDetector(
type: orderType,
id: 'order',
pattern: RegExp(r'ORDER-\d+'),
priority: 160,
),
],
);
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
),
darkTheme: ThemeData(
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.teal,
brightness: Brightness.dark,
),
),
home: const ExamplePage(),
);
}
}
class ExamplePage extends StatelessWidget {
const ExamplePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Interactive text')),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
Text('Common text', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
InteractiveText(
'Visit flutter.dev, email hello@example.com, call +1 555 123 4567, '
'or write to @maria about #Flutter ππ½.',
onTap: (match) => _showMatch(context, match),
),
const SizedBox(height: 28),
Text('Expandable', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
InteractiveText(
'This longer description contains #Flutter, @mentions, links such '
'as flutter.dev, and complete emoji graphemes π©π½βπ». It uses the '
'same widget and only opts into expansion behavior.',
expansion: const InteractiveTextExpansion(
collapsedLines: 2,
expandText: 'More',
collapseText: 'Less',
),
onTap: (match) => _showMatch(context, match),
),
const SizedBox(height: 28),
Text(
'Custom detector',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
InteractiveText(
'Track ORDER-2048 from the same typed callback.',
parser: exampleParser,
styles: InteractiveTextStyles(
custom: {
orderType: TextStyle(
color: Theme.of(context).colorScheme.tertiary,
fontWeight: FontWeight.w700,
),
},
),
onTap: (match) => _showMatch(context, match),
),
const SizedBox(height: 28),
Text('Selectable', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
const InteractiveText(
'This content can be selected while https://flutter.dev remains '
'interactive.',
selectable: true,
),
const SizedBox(height: 28),
Text('Markdown', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
InteractiveText(
'**Important** _note_ ~~old~~ ||spoiler|| `code` '
'[Flutter](https://flutter.dev) ππ½',
types: InteractiveTextGroups.all,
onTap: (match) => _showMatch(context, match),
),
const SizedBox(height: 12),
const InteractiveText(
'**Source syntax** [Flutter](https://flutter.dev)',
types: InteractiveTextGroups.markdown,
showMarkdownSyntax: true,
),
],
),
);
}
void _showMatch(BuildContext context, InteractiveTextMatch match) {
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(
SnackBar(content: Text('${match.type.id}: ${match.text}')),
);
}
}