!IMPORTANT0.1.0, and early. The viewer is written and tested; the editor is the React package's for now. It is a0.x, which means the API can still change between minor versions — pin the version if that matters to you.
flutter pub add mawy
import 'package:mawy/mawy.dart';
MawyViewer(value: '# Hello\n\nSome **Markdown**.')
Why this package
- The parser is ours, and it is the React package's parser. Not a port in
spirit — the same files, the same functions, the same rules, in Dart.
tool/parity.dartruns both over every Markdown file in the repository and diffs the trees, so a document that means one thing in a browser means the same thing in an app because it is checked rather than hoped for. - The document becomes widgets, not markup. There is no HTML on the path from Markdown to the screen, which is what makes the safe default free: there is nothing to escape and nowhere for an injection to arrive.
- Every URL is checked, in the same allowlist the React package uses. A
[click](javascript:…)is drawn as the words the author wrote rather than as a link that does nothing — and nothing is opened at all until you say what opening means, throughonLinkTap. - No Material, no Cupertino. Every widget is built on
package:flutter/widgets.dart, so a document sits inside a Material app, a Cupertino app or a bareWidgetsAppwithout dragging a second design system in behind it. - The typography is the reader's. The toolbar sets the typeface, the size, the line height, the letter spacing and how wide the column runs, and reports what they chose so an application can remember it.
What it reads
CommonMark, plus GitHub's additions: tables with per-column alignment, task
lists, ~~strikethrough~~, bare URLs, footnotes, and the five alert kinds — and
definition lists, which GitHub does not read. Link reference definitions resolve
wherever in the file they are written.
Raw HTML is shown as the characters it was written with, and there is no option to make it otherwise: Flutter has no HTML to draw it as. That is the one place this package and the React one differ about a document, and it is a difference in what a screen can do rather than in what the document says.
Using it
MawyViewer(
value: document,
colorScheme: MawyColorScheme.system,
onLinkTap: (String url, String? title) => launchUrlString(url),
)
value |
The document, as Markdown |
parse |
MawyParseOptions(gfm:, breaks:, definitionLists:) |
colorScheme |
light, dark, or system — and onColorSchemeChange to let the toolbar change it |
typography / defaultTypography / onTypographyChange |
How the document is set, owned by you or by the viewer |
toolbar |
The controls to draw, in order. const [] for none |
locale |
MawyLocale.en or MawyLocale.ko, for the viewer's own chrome |
onLinkTap |
What a tapped link does. Nothing at all without it |
The gallery
example/ is the viewer running, with a few documents to point it at:
cd packages/flutter/example
flutter run
A note on size
The icon font is the one thing this package adds that is not small:
lucide_icons_flutter ships its variable faces whole, and Flutter's icon
tree-shaking barely dents a variable font — about 3 MB in a build. In an app
bundle that is ordinary and it buys the same icons the React package draws. On
the web it is 3 MB somebody downloads, so a web build that cares should say so
with --no-tree-shake-icons off the list of things to try and a different icon
source on it.
Related
mawy-react— the same library for React, with the editor as well as the viewer.- The documentation — one site, both packages.
Libraries
- mawy
- Mawy — a Markdown viewer that also does the parsing.