blob: 5a6e539a7a384967e861c635eb8c5efefb333501 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(goderbauer): Restructure the examples to avoid this ignore, https://github.com/flutter/flutter/issues/110208.
// ignore_for_file: avoid_implementing_value_types
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:markdown/markdown.dart' as md;
import '../shared/markdown_demo_widget.dart';
// ignore_for_file: public_member_api_docs
// Markdown source data showing the use of subscript tags.
const String _data = '''
## Subscript Syntax
NaOH + Al_2O_3 = NaAlO_2 + H_2O
C_4H_10 = C_2H_6 + C_2H_4
''';
const String _notes = """
# Subscript Syntax Demo
---
## Overview
This is an example of how to create an inline syntax parser with an
associated element builder. This example defines an inline syntax parser that
matches instances of an underscore character "**_**" followed by a integer
numerical value. When the parser finds a match for this syntax sequence,
a '**sub**' element is inserted into the abstract syntac tree. The supplied
builder for the '**sub**' element, SubscriptBuilder, is then called to create
an appropriate RichText widget for the formatted output.
## Usage
To support a new custom inline Markdown tag, an inline syntax object needs to be
defined for the Markdown parser and an element builder which is deligated the
task of building the appropriate Flutter widgets for the resulting Markdown
output. Instances of these objects need to be provided to the Markdown widget.
```
Markdown(
data: _data,
builders: {
'sub': SubscriptBuilder(),
},
extensionSet: md.ExtensionSet([], [SubscriptSyntax()]),
);
```
### Inline Syntax Class
```
class SubscriptSyntax extends md.InlineSyntax {
static final _pattern = r'_([0-9]+)';
SubscriptSyntax() : super(_pattern);
@override
bool onMatch(md.InlineParser parser, Match match) {
parser.addNode(md.Element.text('sub', match[1]));
return true;
}
```
### Markdown Element Builder
```
class SubscriptBuilder extends MarkdownElementBuilder {
static const List<String> _subscripts = [
'₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉'
];
@override
Widget visitElementAfter(md.Element element, TextStyle preferredStyle) {
String textContent = element.textContent;
String text = '';
for (int i = 0; i < textContent.length; i++) {
text += _subscripts[int.parse(textContent[i])];
}
return SelectableText.rich(TextSpan(text: text));
}
}
```
""";
/// The subscript syntax demo provides an example of creating an inline syntax
/// object which defines the syntax for the Markdown inline parser and an
/// accompanying Markdown element builder object to handle subscript tags.
class SubscriptSyntaxDemo extends StatelessWidget
implements MarkdownDemoWidget {
const SubscriptSyntaxDemo({Key? key}) : super(key: key);
static const String _title = 'Subscript Syntax Demo';
@override
String get title => SubscriptSyntaxDemo._title;
@override
String get description => 'An example of how to create a custom inline '
'syntax parser and element builder for numerical subscripts.';
@override
Future<String> get data => Future<String>.value(_data);
@override
Future<String> get notes => Future<String>.value(_notes);
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: data,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Markdown(
data: snapshot.data!,
builders: <String, MarkdownElementBuilder>{
'sub': SubscriptBuilder(),
},
extensionSet: md.ExtensionSet(
<md.BlockSyntax>[], <md.InlineSyntax>[SubscriptSyntax()]),
);
} else {
return const CircularProgressIndicator();
}
},
);
}
}
class SubscriptBuilder extends MarkdownElementBuilder {
static const List<String> _subscripts = <String>[
'₀',
'₁',
'₂',
'₃',
'₄',
'₅',
'₆',
'₇',
'₈',
'₉'
];
@override
Widget visitElementAfter(md.Element element, TextStyle? preferredStyle) {
// We don't currently have a way to control the vertical alignment of text spans.
// See https://github.com/flutter/flutter/issues/10906#issuecomment-385723664
final String textContent = element.textContent;
String text = '';
for (int i = 0; i < textContent.length; i++) {
text += _subscripts[int.parse(textContent[i])];
}
return SelectableText.rich(TextSpan(text: text));
}
}
class SubscriptSyntax extends md.InlineSyntax {
SubscriptSyntax() : super(_pattern);
static const String _pattern = r'_([0-9]+)';
@override
bool onMatch(md.InlineParser parser, Match match) {
parser.addNode(md.Element.text('sub', match[1]!));
return true;
}
}