saminsohag

bug fixed

{
"cSpell.words": [
"cellspacing",
"Sohag",
"stylesheet"
]
}
\ No newline at end of file
... ...
## 0.0.9
* To html added.
## 0.0.8
* Bug fixes.
## 0.0.7
* Bug fixes.
## 0.0.6
* Bug fixes.
... ...
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tex_markdown/tex_markdown.dart';
void main() {
... ... @@ -105,8 +106,8 @@ class _MyHomePageState extends State<MyHomePage> {
log(url, name: "url");
},
style: const TextStyle(
// color: Colors.red,
),
color: Colors.green,
),
);
}),
],
... ... @@ -114,14 +115,37 @@ class _MyHomePageState extends State<MyHomePage> {
),
ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: const InputDecoration(
border: OutlineInputBorder(), label: Text("Type here:")),
maxLines: null,
controller: _controller,
),
child: Stack(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text("Type here:")),
maxLines: null,
controller: _controller,
),
),
IconButton(
onPressed: () {
String html = '''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><title>markdown</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" integrity="sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" integrity="sha384-y23I5Q6l+B6vatafAwxRu/0oK/79VlbSz7Q9aiSZUvyWYIYsd+qj+o24G5ZU2zJz" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/contrib/auto-render.min.js" integrity="sha384-kWPLUVMOks5AQFrykwIup5lo0m3iMkkHrD0uJ4H5cjeGihAutqP0yW0J6dpFiVkI" crossorigin="anonymous" onload="renderMathInElement(document.body);"></script>
</head>
<body>
${TexMarkdown.toHtml(_controller.text)}
</body>
</html>
''';
Clipboard.setData(ClipboardData(text: html));
},
icon: const Icon(Icons.html),
),
],
),
),
],
... ...
... ... @@ -238,15 +238,15 @@ packages:
path: ".."
relative: true
source: path
version: "0.0.6"
version: "0.0.9"
tex_text:
dependency: transitive
description:
name: tex_text
sha256: "562415e16b9c46816d8c2ed128fc46b299bb27bca9fac65db0c07535be0d0c60"
sha256: "58c556fb09dff7034d6f29b77b3be6b90e7f1257817daa0000c6f1609094490a"
url: "https://pub.dev"
source: hosted
version: "0.0.8"
version: "0.1.2"
tuple:
dependency: transitive
description:
... ...
import 'package:flutter/material.dart';
import 'package:tex_text/tex_text.dart';
import 'md_widget.dart';
/// Markdown components
abstract class MarkdownComponent {
static final List<MarkdownComponent> components = [
HTag(),
BoldMd(),
ItalicMd(),
ATagMd(),
ImageMd(),
UnOrderedList(),
OrderedList(),
RadioButtonMd(),
CheckBoxMd(),
HrLine(),
TextMd(),
];
static String toHtml(String text) {
String html = "";
text.split(RegExp(r"\n+")).forEach((element) {
for (var each in components) {
if (each.exp.hasMatch(element.trim())) {
if (each is InlineMd) {
html += "${each.toHtml(element)}\n";
break;
} else if (each is BlockMd) {
html += "${each.toHtml(element)}\n";
break;
}
}
}
});
return html;
}
static Widget generate(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
List<Widget> children = [];
List<InlineSpan> spans = [];
text.split(RegExp(r"\n+")).forEach(
(element) {
for (var each in components) {
if (each.exp.hasMatch(element.trim())) {
if (each is InlineMd) {
if (spans.isNotEmpty) {
spans.add(
TextSpan(text: " ", style: style),
);
}
spans.add(each.inlineSpan(
context,
element,
style,
onLinkTab,
));
} else {
if (spans.isNotEmpty) {
children.add(
Text.rich(
TextSpan(children: List.from(spans)),
textAlign: TextAlign.left,
),
);
spans.clear();
}
if (each is BlockMd) {
children.add(
each.build(context, element, style, onLinkTab),
);
}
}
return;
}
}
},
);
if (spans.isNotEmpty) {
children.add(
Text.rich(
TextSpan(children: List.from(spans)),
textAlign: TextAlign.left,
),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: children,
);
}
RegExp get exp;
bool get inline;
}
abstract class InlineMd extends MarkdownComponent {
@override
bool get inline => true;
InlineSpan inlineSpan(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
);
String toHtml(String text);
}
abstract class BlockMd extends MarkdownComponent {
@override
bool get inline => false;
Widget build(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
);
String toHtml(String text);
}
class HTag extends BlockMd {
@override
final RegExp exp = RegExp(r"^(#{1,6})\s([^\n]+)$");
@override
Widget build(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
var match = exp.firstMatch(text.trim());
return Column(
children: [
Row(
children: [
Expanded(
child: TexText(
"${match?[2]}",
style: [
Theme.of(context)
.textTheme
.headlineLarge
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.headlineMedium
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.headlineSmall
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.titleLarge
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.titleMedium
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.titleSmall
?.copyWith(color: style?.color),
][match![1]!.length - 1],
),
),
],
),
if (match[1]!.length == 1) const Divider(height: 6),
],
);
}
@override
String toHtml(String text) {
var match = exp.firstMatch(text.trim());
return "<h${match![1]!.length}>${TexText.toHtmlData(match[2].toString().trim())}<h${match[1]!.length}>";
}
}
class HrLine extends BlockMd {
@override
final RegExp exp = RegExp(r"^(--)[-]+$");
@override
Widget build(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
return const Divider(
height: 5,
);
}
@override
String toHtml(String text) {
return "<hr/>";
}
}
class CheckBoxMd extends BlockMd {
get onLinkTab => null;
@override
Widget build(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
var match = exp.firstMatch(text.trim());
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Checkbox(
// value: true,
value: ("${match?[1]}" == "x"),
onChanged: (value) {},
fillColor: ButtonStyleButton.allOrNull(style?.color),
),
),
Expanded(
child: MdWidget(
"${match?[2]}",
onLinkTab: onLinkTab,
style: style,
),
),
],
);
}
@override
final RegExp exp = RegExp(r"^\[(\x?)\]\s(\S.*)$");
@override
String toHtml(String text) {
var match = exp.firstMatch(text.trim());
return '<p><input type="checkbox"${("${match?[1]}" == "x") ? "checked" : ""}>${MdWidget.toHtml((match?[2]).toString()).trim()}</p>';
}
}
class RadioButtonMd extends BlockMd {
get onLinkTab => null;
@override
Widget build(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
var match = exp.firstMatch(text.trim());
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Radio(
value: true,
groupValue: ("${match?[1]}" == "x"),
onChanged: (value) {},
fillColor: ButtonStyleButton.allOrNull(style?.color),
),
),
Expanded(
child: MdWidget(
"${match?[2]}",
onLinkTab: onLinkTab,
style: style,
),
),
],
);
}
@override
final RegExp exp = RegExp(r"^\((\x?)\)\s(\S.*)$");
@override
String toHtml(String text) {
var match = exp.firstMatch(text.trim());
return '<p><input type="radio"${("${match?[1]}" == "x") ? "checked" : ""}>${MdWidget.toHtml((match?[2]).toString().trim())}</p>';
}
}
class UnOrderedList extends BlockMd {
get onLinkTab => null;
@override
Widget build(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
var match = exp.firstMatch(text.trim());
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.circle,
color: style?.color,
size: 8,
),
),
Expanded(
child: MdWidget(
"${match?[2]}",
onLinkTab: onLinkTab,
style: style,
),
),
],
);
}
@override
final RegExp exp = RegExp(r"^(\-|\*)\s([^\n]+)$");
@override
String toHtml(String text) {
var match = exp.firstMatch(text.trim());
return "<ul><li>${MdWidget.toHtml((match?[2]).toString())}</li></ul>";
}
}
class OrderedList extends BlockMd {
@override
final RegExp exp = RegExp(r"^([0-9]+\.)\s([^\n]+)$");
get onLinkTab => null;
@override
Widget build(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
var match = exp.firstMatch(text.trim());
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 11),
child: Text(
"${match?[1]}",
style: (style ?? const TextStyle())
.copyWith(fontWeight: FontWeight.bold),
),
),
Expanded(
child: MdWidget(
"${match?[2]}",
onLinkTab: onLinkTab,
style: style,
),
),
],
);
}
@override
String toHtml(String text) {
var match = exp.firstMatch(text.trim());
return '<ol start="${match?[1]}"><li>${MdWidget.toHtml((match?[2]).toString())}</li></ol>';
}
}
class BoldMd extends InlineMd {
@override
final RegExp exp = RegExp(r"^\*{2}(([\S^\*].*)?[\S^\*])\*{2}$");
@override
InlineSpan inlineSpan(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
var match = exp.firstMatch(text.trim());
return WidgetSpan(
// text: "${match?[1]}",
child: TexText(
"${match?[1]}",
style: style?.copyWith(fontWeight: FontWeight.bold) ??
const TextStyle(fontWeight: FontWeight.bold),
),
style: style?.copyWith(fontWeight: FontWeight.bold) ??
const TextStyle(fontWeight: FontWeight.bold),
);
}
@override
String toHtml(String text) {
var match = exp.firstMatch(text.trim());
return '<b>${TexText.toHtmlData((match?[1]).toString())}</b>';
}
}
class ItalicMd extends InlineMd {
@override
final RegExp exp = RegExp(r"^\*{1}(([\S^\*].*)?[\S^\*])\*{1}$");
@override
InlineSpan inlineSpan(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
var match = exp.firstMatch(text.trim());
return WidgetSpan(
child: TexText(
"${match?[1]}",
style:
(style ?? const TextStyle()).copyWith(fontStyle: FontStyle.italic),
),
style: (style ?? const TextStyle()).copyWith(fontStyle: FontStyle.italic),
);
}
@override
String toHtml(String text) {
var match = exp.firstMatch(text.trim());
return '<i>${TexText.toHtmlData((match?[1]).toString())}</i>';
}
}
class ATagMd extends InlineMd {
@override
final RegExp exp = RegExp(r"^\[([^\s\*].*[^\s]?)?\]\(([^\s\*]+)?\)$");
@override
InlineSpan inlineSpan(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
var match = exp.firstMatch(text.trim());
if (match?[1] == null && match?[2] == null) {
return const TextSpan();
}
return WidgetSpan(
child: GestureDetector(
onTap: () {
if (onLinkTab == null) {
return;
}
onLinkTab("${match?[2]}", "${match?[1]}");
},
child: TexText(
"${match?[1]}",
style: (style ?? const TextStyle()).copyWith(
color: Colors.blueAccent,
decorationColor: Colors.blue,
decoration: TextDecoration.underline,
),
),
),
);
}
@override
String toHtml(String text) {
var match = exp.firstMatch(text.trim());
return '<a href="${match?[2]}">${TexText.toHtmlData((match?[1]).toString())}</a>';
}
}
class ImageMd extends InlineMd {
@override
final RegExp exp = RegExp(r"^\!\[([^\s].*[^\s]?)?\]\(([^\s]+)\)$");
@override
InlineSpan inlineSpan(
BuildContext context,
String text,
TextStyle? style,
final void Function(String url, String title)? onLinkTab,
) {
var match = exp.firstMatch(text.trim());
double? height;
double? width;
if (match?[1] != null) {
var size = RegExp(r"^([0-9]+)?x?([0-9]+)?")
.firstMatch(match![1].toString().trim());
width = double.tryParse(size?[1]?.toString() ?? 'a');
height = double.tryParse(size?[2]?.toString() ?? 'a');
}
return WidgetSpan(
// alignment: PlaceholderAlignment.middle,
child: SizedBox(
width: width,
height: height,
child: Image.network(
"${match?[2]}",
fit: BoxFit.fill,
errorBuilder: (context, error, stackTrace) {
return Placeholder(
color: Theme.of(context).colorScheme.error,
child: Text(
"${match?[2]}\n$error",
style: style,
),
);
},
),
),
);
}
@override
String toHtml(String text) {
var match = exp.firstMatch(text.trim());
return '<img src="${match?[2]}">';
}
}
class TextMd extends InlineMd {
@override
final RegExp exp = RegExp(".*");
@override
InlineSpan inlineSpan(BuildContext context, String text, TextStyle? style,
void Function(String url, String title)? onLinkTab) {
return WidgetSpan(
child: TexText(
text,
style: style,
));
}
@override
String toHtml(String text) {
return TexText.toHtmlData(text);
}
}
... ...
import 'package:flutter/material.dart';
import 'package:tex_text/tex_text.dart';
import 'package:tex_markdown/markdown_component.dart';
/// It creates a markdown widget closed to each other.
class MdWidget extends StatelessWidget {
... ... @@ -9,18 +9,43 @@ class MdWidget extends StatelessWidget {
final TextStyle? style;
final void Function(String url, String title)? onLinkTab;
final bool followLinkColor;
/// To convert markdown text to html text.
static String toHtml(String text) {
final RegExp table = RegExp(
r"^(((\|[^\n\|]+\|)((([^\n\|]+\|)+)?))(\n(((\|[^\n\|]+\|)(([^\n\|]+\|)+)?)))+)?$",
);
if (table.hasMatch(text)) {
final String value = text.trim().splitMapJoin(
RegExp(r'^\||\|\n\||\|$'),
onMatch: (p0) => "\n",
onNonMatch: (p0) {
if (p0.trim().isEmpty) {
return "";
}
// return p0;
return '<tr>${p0.trim().splitMapJoin(
'|',
onMatch: (p0) {
return "";
},
onNonMatch: (p0) {
return '<td>$p0</td>';
},
)}</tr>';
},
);
return '''
<table border="1" cellspacing="0">
$value
</table>
''';
}
return MarkdownComponent.toHtml(text);
}
@override
Widget build(BuildContext context) {
final RegExp h = RegExp(r"^(#{1,6})\s([^\n]+)$");
final RegExp b = RegExp(r"^\*{2}(([\S^\*].*)?[\S^\*])\*{2}$");
final RegExp i = RegExp(r"^\*{1}(([\S^\*].*)?[\S^\*])\*{1}$");
final RegExp a = RegExp(r"^\[([^\s\*].*[^\s]?)?\]\(([^\s\*]+)?\)$");
final RegExp img = RegExp(r"^\!\[([^\s].*[^\s]?)?\]\(([^\s]+)\)$");
final RegExp ul = RegExp(r"^(\-|\*)\s([^\n]+)$");
final RegExp ol = RegExp(r"^([0-9]+\.)\s([^\n]+)$");
final RegExp rb = RegExp(r"^\((\x?)\)\s(\S.*)$");
final RegExp cb = RegExp(r"^\[(\x?)\]\s(\S.*)$");
final RegExp hr = RegExp(r"^(--)[-]+$");
final RegExp table = RegExp(
r"^(((\|[^\n\|]+\|)((([^\n\|]+\|)+)?))(\n(((\|[^\n\|]+\|)(([^\n\|]+\|)+)?)))+)?$",
);
... ... @@ -42,7 +67,6 @@ class MdWidget extends StatelessWidget {
}
}
if (maxCol == 0) {
// return const SizedBox();
return Text("", style: style);
}
return Table(
... ... @@ -69,256 +93,6 @@ class MdWidget extends StatelessWidget {
.toList(),
);
}
if (h.hasMatch(exp)) {
var match = h.firstMatch(exp.trim());
return Column(
children: [
Row(
children: [
Expanded(
child: TexText(
"${match?[2]}",
style: [
Theme.of(context)
.textTheme
.headlineLarge
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.headlineMedium
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.headlineSmall
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.titleLarge
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.titleMedium
?.copyWith(color: style?.color),
Theme.of(context)
.textTheme
.titleSmall
?.copyWith(color: style?.color),
][match![1]!.length - 1],
),
),
],
),
if (match[1]!.length == 1) const Divider(height: 6),
],
);
}
if (hr.hasMatch(exp)) {
return const Divider(
height: 5,
);
}
if (cb.hasMatch(exp)) {
var match = cb.firstMatch(exp.trim());
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Checkbox(
// value: true,
value: ("${match?[1]}" == "x"),
onChanged: (value) {},
fillColor: ButtonStyleButton.allOrNull(style?.color),
),
),
Expanded(
child: MdWidget(
"${match?[2]}",
onLinkTab: onLinkTab,
style: style,
),
),
],
);
}
if (rb.hasMatch(exp)) {
var match = rb.firstMatch(exp.trim());
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Radio(
value: true,
groupValue: ("${match?[1]}" == "x"),
onChanged: (value) {},
fillColor: ButtonStyleButton.allOrNull(style?.color),
),
),
Expanded(
child: MdWidget(
"${match?[2]}",
onLinkTab: onLinkTab,
style: style,
),
),
],
);
}
if (ul.hasMatch(exp)) {
var match = ul.firstMatch(exp.trim());
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.circle,
color: style?.color,
size: 8,
),
),
Expanded(
child: MdWidget(
"${match?[2]}",
onLinkTab: onLinkTab,
style: style,
),
),
],
);
}
if (ol.hasMatch(exp)) {
var match = ol.firstMatch(exp.trim());
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 11),
child: Text(
"${match?[1]}",
style: (style ?? const TextStyle())
.copyWith(fontWeight: FontWeight.bold),
),
),
Expanded(
child: MdWidget(
"${match?[2]}",
onLinkTab: onLinkTab,
style: style,
),
),
],
);
}
if (b.hasMatch(exp)) {
var match = b.firstMatch(exp.trim());
return TexText(
"${match?[1]}",
style: style?.copyWith(fontWeight: FontWeight.bold) ??
const TextStyle(fontWeight: FontWeight.bold),
);
}
if (i.hasMatch(exp)) {
var match = i.firstMatch(exp.trim());
return TexText(
"${match?[1]}",
style:
(style ?? const TextStyle()).copyWith(fontStyle: FontStyle.italic),
);
}
if (a.hasMatch(exp)) {
var match = a.firstMatch(exp.trim());
if (match?[1] == null && match?[2] == null) {
return const SizedBox();
}
return GestureDetector(
onTap: () {
if (onLinkTab == null) {
return;
}
onLinkTab!("${match?[2]}", "${match?[1]}");
},
child: MdWidget(
"${match?[1]}",
onLinkTab: onLinkTab,
style: ((followLinkColor && style != null)
? style
: const TextStyle(color: Colors.blueAccent))
?.copyWith(decoration: TextDecoration.underline),
),
);
}
if (img.hasMatch(exp)) {
var match = img.firstMatch(exp.trim());
double? height;
double? width;
if (match?[1] != null) {
var size = RegExp(r"^([0-9]+)?x?([0-9]+)?")
.firstMatch(match![1].toString().trim());
width = double.tryParse(size?[1]?.toString() ?? 'a');
height = double.tryParse(size?[2]?.toString() ?? 'a');
}
return SizedBox(
width: width,
height: height,
child: Image.network(
"${match?[2]}",
fit: BoxFit.fill,
errorBuilder: (context, error, stackTrace) {
return Placeholder(
color: Theme.of(context).colorScheme.error,
child: Text(
"${match?[2]}\n$error",
style: style,
),
);
},
),
);
}
List<String> expL = exp.split('\n');
// .map(
// (e) => e.trim(),
// )
// .toList();
bool hasMatch = false;
for (final each in expL) {
if (a.hasMatch(each) ||
b.hasMatch(each) ||
i.hasMatch(each) ||
h.hasMatch(each) ||
hr.hasMatch(each) ||
ol.hasMatch(each) ||
rb.hasMatch(each) ||
cb.hasMatch(each) ||
img.hasMatch(each) ||
ul.hasMatch(each)) {
hasMatch = true;
}
}
if (hasMatch) {
return Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 10,
children: exp
.split("\n")
.map<Widget>((e) => MdWidget(
e,
onLinkTab: onLinkTab,
style: style,
))
.toList(),
);
}
return TexText(
exp,
style: style,
);
return MarkdownComponent.generate(context, exp, style, onLinkTab);
}
}
... ...
... ... @@ -17,6 +17,13 @@ class TexMarkdown extends StatelessWidget {
final TextStyle? style;
final void Function(String url, String title)? onLinkTab;
final bool followLinkColor;
static String toHtml(String text) {
String html = "";
text.trim().split(RegExp(r"\n\n+")).forEach((element) {
html += MdWidget.toHtml(element);
});
return html;
}
@override
Widget build(BuildContext context) {
... ...
name: tex_markdown
description: This package is used to create flutter widget that can render markdown and latex formulas. It is very simple to use and uses native flutter components.
version: 0.0.6
version: 0.0.9
homepage: https://github.com/saminsohag/flutter_packages/tree/main/tex_markdown
environment:
... ... @@ -10,7 +10,7 @@ environment:
dependencies:
flutter:
sdk: flutter
tex_text: ^0.0.8
tex_text: ^0.1.2
dev_dependencies:
flutter_test:
... ...