import 'package:flutter/material.dart'; import 'package:tuple/tuple.dart'; class EditorStyles extends InheritedWidget { const EditorStyles({ required this.data, required Widget child, Key? key, }) : super(key: key, child: child); final DefaultStyles data; @override bool updateShouldNotify(covariant EditorStyles oldWidget) => data != oldWidget.data; static DefaultStyles? getStyles(BuildContext context, bool nullOk) { final widget = context.dependOnInheritedWidgetOfExactType(); if (widget == null && nullOk) { return null; } assert(widget != null); return widget!.data; } } class DefaultTextBlockStyle { DefaultTextBlockStyle( this.style, this.verticalSpacing, this.lineSpacing, this.decoration, ); final TextStyle style; final Tuple2 verticalSpacing; final Tuple2 lineSpacing; final BoxDecoration? decoration; } class DefaultStyles { DefaultStyles({ this.h1, this.h2, this.h3, this.h4, this.h5, this.h6, this.paragraph, this.bold, this.italic, this.underline, this.strikeThrough, this.sizeSmall, this.sizeLarge, this.sizeHuge, this.link, this.color, this.placeHolder, this.lists, this.quote, this.code, this.indent, this.align, this.leading, }); final DefaultTextBlockStyle? h1; final DefaultTextBlockStyle? h2; final DefaultTextBlockStyle? h3; final DefaultTextBlockStyle? h4; final DefaultTextBlockStyle? h5; final DefaultTextBlockStyle? h6; final DefaultTextBlockStyle? paragraph; final TextStyle? bold; final TextStyle? italic; final TextStyle? underline; final TextStyle? strikeThrough; final TextStyle? sizeSmall; final TextStyle? sizeLarge; final TextStyle? sizeHuge; final TextStyle? link; final Color? color; final DefaultTextBlockStyle? placeHolder; final DefaultTextBlockStyle? lists; final DefaultTextBlockStyle? quote; final DefaultTextBlockStyle? code; final DefaultTextBlockStyle? indent; final DefaultTextBlockStyle? align; final DefaultTextBlockStyle? leading; static DefaultStyles getInstance(BuildContext context) { final themeData = Theme.of(context); final defaultTextStyle = DefaultTextStyle.of(context); final baseStyle = defaultTextStyle.style.copyWith( fontSize: 16, height: 1.3, ); const baseSpacing = Tuple2(6, 0); String fontFamily; switch (themeData.platform) { case TargetPlatform.iOS: case TargetPlatform.macOS: fontFamily = 'Menlo'; break; case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.windows: case TargetPlatform.linux: fontFamily = 'Roboto Mono'; break; default: throw UnimplementedError(); } final defaultSmallHeaderTextStyle = DefaultTextBlockStyle( defaultTextStyle.style.copyWith( fontSize: 16, color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.25, fontWeight: FontWeight.w500, ), const Tuple2(8, 0), const Tuple2(0, 0), null, ); return DefaultStyles( h1: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( fontSize: 34, color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.15, fontWeight: FontWeight.w300, ), const Tuple2(16, 0), const Tuple2(0, 0), null, ), h2: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( fontSize: 24, color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.15, fontWeight: FontWeight.normal, ), const Tuple2(8, 0), const Tuple2(0, 0), null, ), h3: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( fontSize: 20, color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.25, fontWeight: FontWeight.w500, ), const Tuple2(8, 0), const Tuple2(0, 0), null, ), h4: defaultSmallHeaderTextStyle, h5: defaultSmallHeaderTextStyle, h6: defaultSmallHeaderTextStyle, paragraph: DefaultTextBlockStyle( baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null, ), bold: const TextStyle( fontWeight: FontWeight.bold, ), italic: const TextStyle( fontStyle: FontStyle.italic, ), underline: const TextStyle( decoration: TextDecoration.underline, ), strikeThrough: const TextStyle( decoration: TextDecoration.lineThrough, ), link: TextStyle( color: themeData.colorScheme.secondary, decoration: TextDecoration.underline, ), placeHolder: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( fontSize: 20, height: 1.5, color: Colors.grey.withOpacity(0.6), ), const Tuple2(0, 0), const Tuple2(0, 0), null, ), lists: DefaultTextBlockStyle( baseStyle, baseSpacing, const Tuple2(0, 6), null, ), quote: DefaultTextBlockStyle( TextStyle(color: baseStyle.color!.withOpacity(0.6)), baseSpacing, const Tuple2(6, 2), BoxDecoration( border: Border( left: BorderSide(width: 4, color: Colors.grey.shade300), ), ), ), code: DefaultTextBlockStyle( TextStyle( color: Colors.blue.shade900.withOpacity(0.9), fontFamily: fontFamily, fontSize: 13, height: 1.15, ), baseSpacing, const Tuple2(0, 0), BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(2), ), ), indent: DefaultTextBlockStyle( baseStyle, baseSpacing, const Tuple2(0, 6), null, ), align: DefaultTextBlockStyle( baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null, ), leading: DefaultTextBlockStyle( baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null, ), sizeSmall: const TextStyle( fontSize: 10, ), sizeLarge: const TextStyle( fontSize: 18, ), sizeHuge: const TextStyle( fontSize: 22, ), ); } DefaultStyles merge(DefaultStyles other) { return DefaultStyles( h1: other.h1 ?? h1, h2: other.h2 ?? h2, h3: other.h3 ?? h3, h4: other.h4 ?? h4, h5: other.h5 ?? h5, h6: other.h6 ?? h6, paragraph: other.paragraph ?? paragraph, bold: other.bold ?? bold, italic: other.italic ?? italic, underline: other.underline ?? underline, strikeThrough: other.strikeThrough ?? strikeThrough, link: other.link ?? link, color: other.color ?? color, placeHolder: other.placeHolder ?? placeHolder, lists: other.lists ?? lists, quote: other.quote ?? quote, code: other.code ?? code, indent: other.indent ?? indent, align: other.align ?? align, leading: other.leading ?? leading, sizeSmall: other.sizeSmall ?? sizeSmall, sizeLarge: other.sizeLarge ?? sizeLarge, sizeHuge: other.sizeHuge ?? sizeHuge, ); } }