/// Document model for Mews pages (mews-spec/SPEC.md sections 3 to 6). /// Pure data: no Flutter imports, so it can be built inside an isolate. library; /// The `body` variant class a page carries (spec 5.3), or [plain] when absent. enum MewsVariant { plain, warm, cool, green, mono } /// A parsed page. [specVersion] holds the conformance marker's value and is /// null on a page without the marker, which must be shown plainly (spec 8.1). class MewsPage { const MewsPage({ required this.url, required this.body, required this.lang, required this.direction, required this.variant, required this.entries, this.specVersion, this.title, this.description, this.author, this.atomFeedHref, }); final String url; final List body; final String lang; final TextDirection direction; final MewsVariant variant; final List entries; final String? specVersion; final String? title; final String? description; final String? author; final String? atomFeedHref; bool get isMews => specVersion != null; } /// TextDirection without importing Flutter: pages with dir="rtl" render /// right-to-left (spec 3). enum TextDirection { ltr, rtl } /// A dated link that starts a list item (spec 6.1). class MewsEntry { const MewsEntry({required this.url, required this.date, required this.title}); final String url; final DateTime date; final String title; } sealed class MewsBlock { const MewsBlock(); } class HeadingBlock extends MewsBlock { const HeadingBlock(this.level, this.inline); final int level; // 1 to 6 final List inline; } class ParagraphBlock extends MewsBlock { const ParagraphBlock(this.inline); final List inline; } class QuoteBlock extends MewsBlock { const QuoteBlock(this.children); final List children; } class PreBlock extends MewsBlock { const PreBlock(this.text); final String text; } class AddressBlock extends MewsBlock { const AddressBlock(this.inline); final List inline; } class RuleBlock extends MewsBlock { const RuleBlock(); } class ListBlock extends MewsBlock { const ListBlock({required this.ordered, required this.start, required this.items}); final bool ordered; final int start; final List items; } class MewsListItem { const MewsListItem(this.blocks); final List blocks; } class DefinitionItem { const DefinitionItem(this.term, this.definition); final List term; final List definition; } class DefinitionListBlock extends MewsBlock { const DefinitionListBlock(this.items); final List items; } class TableBlock extends MewsBlock { const TableBlock({required this.rows, this.caption, this.summary}); final List rows; final String? caption; final String? summary; } class MewsTableRow { const MewsTableRow(this.cells); final List cells; } class MewsTableCell { const MewsTableCell({ required this.header, required this.inline, this.colspan = 1, this.rowspan = 1, }); final bool header; final List inline; final int colspan; final int rowspan; } /// Same-site images load normally; off-site or data: sources are refused by /// the client without reader action (specs 4.2 and 8.1), and the alt text is /// shown in their place. class ImageBlock extends MewsBlock { const ImageBlock({required this.src, required this.alt, required this.allowed}); final String src; final String alt; final bool allowed; } class FormBlock extends MewsBlock { const FormBlock({ required this.action, required this.method, required this.fields, required this.submitLabel, }); final String action; final String method; final List fields; final String? submitLabel; } sealed class MewsFormField { const MewsFormField({required this.name, this.label}); final String name; final String? label; } class MewsTextField extends MewsFormField { const MewsTextField({ required super.name, required this.password, this.value = '', this.maxLength, this.inputMode, super.label, }); final bool password; final String value; final int? maxLength; final String? inputMode; } class MewsCheckboxField extends MewsFormField { const MewsCheckboxField({ required super.name, required this.checked, this.value = 'on', super.label, }); final bool checked; final String value; } class MewsRadioField extends MewsFormField { const MewsRadioField({ required super.name, required this.checked, required this.value, super.label, }); final bool checked; final String value; } class MewsSelectField extends MewsFormField { const MewsSelectField({required super.name, required this.options, super.label}); final List options; } class MewsSelectOption { const MewsSelectOption({required this.value, required this.selected}); final String value; final bool selected; } class MewsTextAreaField extends MewsFormField { const MewsTextAreaField({ required super.name, required this.value, this.rows = 3, super.label, }); final String value; final int rows; } /// A hidden input; kept in the model so it round-trips on submit. class MewsHiddenField extends MewsFormField { const MewsHiddenField({required super.name, required this.value}); final String value; } /// One or more inputs of kind submit/reset collapse into this control. class MewsSubmitField extends MewsFormField { const MewsSubmitField({required this.reset, super.label, super.name = ''}); final bool reset; } sealed class MewsInline { const MewsInline(); } class MewsText extends MewsInline { const MewsText(this.text); final String text; } enum EmphasisStyle { emphasis, strong, code, sample, variable, term, quote } /// em, i, cite and abbr map to [EmphasisStyle.emphasis]; strong and b to /// [EmphasisStyle.strong]; kbd and samp to [EmphasisStyle.sample]; var to /// [EmphasisStyle.variable]; dfn to [EmphasisStyle.term]; q to /// [EmphasisStyle.quote]. The distinction keeps the renderer honest about what /// authors meant, per the reader-controls-presentation principle. class MewsEmphasis extends MewsInline { const MewsEmphasis(this.style, this.children); final EmphasisStyle style; final List children; } class MewsLink extends MewsInline { const MewsLink(this.href, this.children); final String href; final List children; } class MewsLineBreak extends MewsInline { const MewsLineBreak(); }