From 7571fe83a2c759e79dea01234d8caddbdefbcd18 Mon Sep 17 00:00:00 2001 From: Christoph Schacht Date: Wed, 25 Jun 2025 14:21:14 +0200 Subject: [PATCH 1/4] added defaultTextStyle to DefaultStyles --- .../editor/raw_editor/raw_editor_state.dart | 22 +- lib/src/editor/widgets/default_styles.dart | 468 ++++++++++-------- 2 files changed, 263 insertions(+), 227 deletions(-) diff --git a/lib/src/editor/raw_editor/raw_editor_state.dart b/lib/src/editor/raw_editor/raw_editor_state.dart index 2c5cdf04d..cdc41c43a 100644 --- a/lib/src/editor/raw_editor/raw_editor_state.dart +++ b/lib/src/editor/raw_editor/raw_editor_state.dart @@ -892,14 +892,14 @@ class QuillRawEditorState extends EditorState void didChangeDependencies() { super.didChangeDependencies(); final parentStyles = QuillStyles.getStyles(context, true); - final defaultStyles = DefaultStyles.getInstance(context); - _styles = (parentStyles != null) - ? defaultStyles.merge(parentStyles) - : defaultStyles; + final customStyles = widget.config.customStyles; + final mergedStyles = parentStyles != null && customStyles != null + ? _styles!.merge(customStyles) + : customStyles ?? parentStyles; - if (widget.config.customStyles != null) { - _styles = _styles!.merge(widget.config.customStyles!); - } + final defaultStyles = + DefaultStyles.getInstance(context, customDefaultStyles: mergedStyles); + _styles = defaultStyles; _requestAutoFocusIfShould(); } @@ -951,9 +951,13 @@ class QuillRawEditorState extends EditorState } } + final customStyles = widget.config.customStyles; // in case customStyles changed in new widget - if (widget.config.customStyles != null) { - _styles = _styles!.merge(widget.config.customStyles!); + if (customStyles != null) { + final mergedStyles = _styles!.merge(customStyles); + final defaultStyles = + DefaultStyles.getInstance(context, customDefaultStyles: mergedStyles); + _styles = defaultStyles; } if (widget.config.actionConfiguration != diff --git a/lib/src/editor/widgets/default_styles.dart b/lib/src/editor/widgets/default_styles.dart index 87636f63c..1bf63a2e2 100644 --- a/lib/src/editor/widgets/default_styles.dart +++ b/lib/src/editor/widgets/default_styles.dart @@ -207,7 +207,7 @@ class DefaultListBlockStyle extends DefaultTextBlockStyle { checkboxUIBuilder ?? this.checkboxUIBuilder, indentWidthBuilder: indentWidthBuilder ?? this.indentWidthBuilder, numberPointWidthBuilder: - numberPointWidthBuilder ?? this.numberPointWidthBuilder, + numberPointWidthBuilder ?? this.numberPointWidthBuilder, ); } } @@ -226,6 +226,7 @@ class DefaultStyles { this.lineHeightTight, this.lineHeightOneAndHalf, this.lineHeightDouble, + this.defaultTextStyle, this.bold, this.subscript, this.superscript, @@ -260,6 +261,7 @@ class DefaultStyles { final DefaultTextBlockStyle? lineHeightTight; final DefaultTextBlockStyle? lineHeightOneAndHalf; final DefaultTextBlockStyle? lineHeightDouble; + final TextStyle? defaultTextStyle; final TextStyle? bold; final TextStyle? subscript; final TextStyle? superscript; @@ -286,14 +288,17 @@ class DefaultStyles { /// Custom palette of colors final Map? palette; - static DefaultStyles getInstance(BuildContext context) { + static DefaultStyles getInstance(BuildContext context, + {DefaultStyles? customDefaultStyles}) { final themeData = Theme.of(context); - final defaultTextStyle = DefaultTextStyle.of(context); - final baseStyle = defaultTextStyle.style.copyWith( - fontSize: 16, - height: 1.15, - decoration: TextDecoration.none, - ); + final defaultTextStyle = DefaultTextStyle.of(context).style; + + final baseStyle = customDefaultStyles?.defaultTextStyle ?? + defaultTextStyle.copyWith( + fontSize: 16, + height: 1.15, + decoration: TextDecoration.none, + ); const baseHorizontalSpacing = HorizontalSpacing(0, 0); const baseVerticalSpacing = VerticalSpacing(6, 0); final fontFamily = themeData.isCupertino ? 'Menlo' : 'Roboto Mono'; @@ -305,228 +310,255 @@ class DefaultStyles { ); return DefaultStyles( - h1: DefaultTextBlockStyle( - defaultTextStyle.style.copyWith( - fontSize: 34, - color: defaultTextStyle.style.color, - letterSpacing: -0.5, - height: 1.083, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, + h1: customDefaultStyles?.h1 ?? + DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 34, + color: baseStyle.color, + letterSpacing: -0.5, + height: 1.083, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(16, 0), + VerticalSpacing.zero, + null), + h2: customDefaultStyles?.h2 ?? + DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 30, + color: baseStyle.color, + letterSpacing: -0.8, + height: 1.067, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(8, 0), + VerticalSpacing.zero, + null), + h3: customDefaultStyles?.h3 ?? + DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 24, + color: baseStyle.color, + letterSpacing: -0.5, + height: 1.083, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(8, 0), + VerticalSpacing.zero, + null, ), - baseHorizontalSpacing, - const VerticalSpacing(16, 0), - VerticalSpacing.zero, - null), - h2: DefaultTextBlockStyle( - defaultTextStyle.style.copyWith( - fontSize: 30, - color: defaultTextStyle.style.color, - letterSpacing: -0.8, - height: 1.067, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, + h4: customDefaultStyles?.h4 ?? + DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 20, + color: baseStyle.color, + letterSpacing: -0.4, + height: 1.1, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(6, 0), + VerticalSpacing.zero, + null, ), - baseHorizontalSpacing, - const VerticalSpacing(8, 0), - VerticalSpacing.zero, - null), - h3: DefaultTextBlockStyle( - defaultTextStyle.style.copyWith( - fontSize: 24, - color: defaultTextStyle.style.color, - letterSpacing: -0.5, - height: 1.083, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(8, 0), - VerticalSpacing.zero, - null, - ), - h4: DefaultTextBlockStyle( - defaultTextStyle.style.copyWith( - fontSize: 20, - color: defaultTextStyle.style.color, - letterSpacing: -0.4, - height: 1.1, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(6, 0), - VerticalSpacing.zero, - null, - ), - h5: DefaultTextBlockStyle( - defaultTextStyle.style.copyWith( - fontSize: 18, - color: defaultTextStyle.style.color, - letterSpacing: -0.2, - height: 1.11, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(6, 0), - VerticalSpacing.zero, - null, - ), - h6: DefaultTextBlockStyle( - defaultTextStyle.style.copyWith( - fontSize: 16, - color: defaultTextStyle.style.color, - letterSpacing: -0.1, - height: 1.125, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(4, 0), - VerticalSpacing.zero, - null, - ), - lineHeightNormal: DefaultTextBlockStyle( - baseStyle.copyWith(height: 1.15), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - lineHeightTight: DefaultTextBlockStyle( - baseStyle.copyWith(height: 1.30), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - lineHeightOneAndHalf: DefaultTextBlockStyle( - baseStyle.copyWith(height: 1.55), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - lineHeightDouble: DefaultTextBlockStyle( - baseStyle.copyWith(height: 2), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - paragraph: DefaultTextBlockStyle( - baseStyle, - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - bold: const TextStyle(fontWeight: FontWeight.bold), + h5: customDefaultStyles?.h5 ?? + DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 18, + color: baseStyle.color, + letterSpacing: -0.2, + height: 1.11, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(6, 0), + VerticalSpacing.zero, + null, + ), + h6: customDefaultStyles?.h6 ?? + DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 16, + color: baseStyle.color, + letterSpacing: -0.1, + height: 1.125, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(4, 0), + VerticalSpacing.zero, + null, + ), + lineHeightNormal: customDefaultStyles?.lineHeightNormal ?? + DefaultTextBlockStyle( + baseStyle.copyWith(height: 1.15), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + lineHeightTight: customDefaultStyles?.lineHeightTight ?? + DefaultTextBlockStyle( + baseStyle.copyWith(height: 1.30), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + lineHeightOneAndHalf: customDefaultStyles?.lineHeightOneAndHalf ?? + DefaultTextBlockStyle( + baseStyle.copyWith(height: 1.55), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + lineHeightDouble: customDefaultStyles?.lineHeightDouble ?? + DefaultTextBlockStyle( + baseStyle.copyWith(height: 2), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + paragraph: customDefaultStyles?.paragraph ?? + DefaultTextBlockStyle( + baseStyle, + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + bold: customDefaultStyles?.bold ?? + const TextStyle(fontWeight: FontWeight.bold), subscript: const TextStyle( fontFeatures: [ FontFeature.liningFigures(), FontFeature.subscripts(), ], ), - superscript: const TextStyle( - fontFeatures: [ - FontFeature.liningFigures(), - FontFeature.superscripts(), - ], - ), - italic: const TextStyle(fontStyle: FontStyle.italic), - small: const TextStyle(fontSize: 12), - underline: const TextStyle(decoration: TextDecoration.underline), - strikeThrough: const TextStyle(decoration: TextDecoration.lineThrough), - inlineCode: InlineCodeStyle( - backgroundColor: Colors.grey.shade100, - radius: const Radius.circular(3), - style: inlineCodeStyle, - header1: inlineCodeStyle.copyWith( - fontSize: 32, - fontWeight: FontWeight.w500, - ), - header2: inlineCodeStyle.copyWith( - fontSize: 22, - fontWeight: FontWeight.w500, - ), - header3: inlineCodeStyle.copyWith( - fontSize: 18, - fontWeight: FontWeight.w500, - ), - ), - link: TextStyle( - color: themeData.colorScheme.secondary, - decoration: TextDecoration.underline, - ), - placeHolder: DefaultTextBlockStyle( - defaultTextStyle.style.copyWith( - fontSize: 20, - height: 1.5, - color: Colors.grey.withValues(alpha: 0.6), + superscript: customDefaultStyles?.superscript ?? + const TextStyle( + fontFeatures: [ + FontFeature.liningFigures(), + FontFeature.superscripts(), + ], ), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null), - lists: DefaultListBlockStyle( - baseStyle, - baseHorizontalSpacing, - baseVerticalSpacing, - const VerticalSpacing(0, 6), - null, - null, - ), - quote: DefaultTextBlockStyle( - TextStyle(color: baseStyle.color!.withValues(alpha: 0.6)), - baseHorizontalSpacing, - baseVerticalSpacing, - const VerticalSpacing(6, 2), - BoxDecoration( - border: Border( - left: BorderSide(width: 4, color: Colors.grey.shade300), + italic: customDefaultStyles?.italic ?? + const TextStyle(fontStyle: FontStyle.italic), + small: customDefaultStyles?.small ?? const TextStyle(fontSize: 12), + underline: customDefaultStyles?.underline ?? + const TextStyle(decoration: TextDecoration.underline), + strikeThrough: customDefaultStyles?.strikeThrough ?? + const TextStyle(decoration: TextDecoration.lineThrough), + inlineCode: customDefaultStyles?.inlineCode ?? + InlineCodeStyle( + backgroundColor: Colors.grey.shade100, + radius: const Radius.circular(3), + style: inlineCodeStyle, + header1: inlineCodeStyle.copyWith( + fontSize: 32, + fontWeight: FontWeight.w500, + ), + header2: inlineCodeStyle.copyWith( + fontSize: 22, + fontWeight: FontWeight.w500, + ), + header3: inlineCodeStyle.copyWith( + fontSize: 18, + fontWeight: FontWeight.w500, + ), ), - ), - ), - code: DefaultTextBlockStyle( + link: customDefaultStyles?.link ?? TextStyle( - color: Colors.blue.shade900.withValues(alpha: 0.9), - fontFamily: fontFamily, - fontSize: 13, - height: 1.15, + color: themeData.colorScheme.secondary, + decoration: TextDecoration.underline, ), - baseHorizontalSpacing, - baseVerticalSpacing, - VerticalSpacing.zero, - BoxDecoration( - color: Colors.grey.shade50, - borderRadius: BorderRadius.circular(2), - )), - indent: DefaultTextBlockStyle( - baseStyle, - baseHorizontalSpacing, - baseVerticalSpacing, - const VerticalSpacing(0, 6), - null, - ), - align: DefaultTextBlockStyle( - baseStyle, - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - leading: DefaultTextBlockStyle( - baseStyle, - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - sizeSmall: const TextStyle(fontSize: 10), - sizeLarge: const TextStyle(fontSize: 18), - sizeHuge: const TextStyle(fontSize: 22), + placeHolder: customDefaultStyles?.placeHolder ?? + DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 20, + height: 1.5, + color: Colors.grey.withValues(alpha: 0.6), + ), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null), + lists: customDefaultStyles?.lists ?? + DefaultListBlockStyle( + baseStyle, + baseHorizontalSpacing, + baseVerticalSpacing, + const VerticalSpacing(0, 6), + null, + null, + ), + quote: customDefaultStyles?.quote ?? + DefaultTextBlockStyle( + TextStyle(color: baseStyle.color!.withValues(alpha: 0.6)), + baseHorizontalSpacing, + baseVerticalSpacing, + const VerticalSpacing(6, 2), + BoxDecoration( + border: Border( + left: BorderSide(width: 4, color: Colors.grey.shade300), + ), + ), + ), + code: customDefaultStyles?.code ?? + DefaultTextBlockStyle( + TextStyle( + color: Colors.blue.shade900.withValues(alpha: 0.9), + fontFamily: fontFamily, + fontSize: 13, + height: 1.15, + ), + baseHorizontalSpacing, + baseVerticalSpacing, + VerticalSpacing.zero, + BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(2), + )), + indent: customDefaultStyles?.indent ?? + DefaultTextBlockStyle( + baseStyle, + baseHorizontalSpacing, + baseVerticalSpacing, + const VerticalSpacing(0, 6), + null, + ), + align: customDefaultStyles?.align ?? + DefaultTextBlockStyle( + baseStyle, + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + leading: customDefaultStyles?.leading ?? + DefaultTextBlockStyle( + baseStyle, + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + sizeSmall: + customDefaultStyles?.sizeSmall ?? const TextStyle(fontSize: 10), + sizeLarge: + customDefaultStyles?.sizeLarge ?? const TextStyle(fontSize: 18), + sizeHuge: customDefaultStyles?.sizeHuge ?? const TextStyle(fontSize: 22), ); } From 182b76eab8b34ab0a35c00a0c2b99f65b9efe9f2 Mon Sep 17 00:00:00 2001 From: Christoph Schacht Date: Wed, 25 Jun 2025 16:58:44 +0200 Subject: [PATCH 2/4] added option to change list point alignment --- .../raw_editor/builders/leading_block_builder.dart | 2 ++ lib/src/editor/style_widgets/bullet_point.dart | 6 ++++-- lib/src/editor/style_widgets/number_point.dart | 10 ++++++---- .../bullet_point_leading.dart | 1 + .../number_point_leading.dart | 1 + lib/src/editor/widgets/default_styles.dart | 4 ++++ lib/src/editor/widgets/text/text_block.dart | 2 ++ 7 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/src/editor/raw_editor/builders/leading_block_builder.dart b/lib/src/editor/raw_editor/builders/leading_block_builder.dart index f93b76f3d..27385cb83 100644 --- a/lib/src/editor/raw_editor/builders/leading_block_builder.dart +++ b/lib/src/editor/raw_editor/builders/leading_block_builder.dart @@ -23,6 +23,7 @@ class LeadingConfig { required this.value, required this.onCheckboxTap, required this.attrs, + this.listPointAlignment, this.withDot = true, this.index, this.lineSize, @@ -40,6 +41,7 @@ class LeadingConfig { final TextStyle? style; final double? width; final double? padding; + final AlignmentDirectional? listPointAlignment; // these values are used if the leading is from a check list final QuillCheckboxBuilder? uiBuilder; diff --git a/lib/src/editor/style_widgets/bullet_point.dart b/lib/src/editor/style_widgets/bullet_point.dart index abba0d9d0..f4d2e0fba 100644 --- a/lib/src/editor/style_widgets/bullet_point.dart +++ b/lib/src/editor/style_widgets/bullet_point.dart @@ -7,19 +7,21 @@ class QuillBulletPoint extends StatelessWidget { this.padding = 0, this.backgroundColor, this.textAlign, + AlignmentDirectional? alignment, super.key, - }); + }) : alignment = alignment ?? AlignmentDirectional.topEnd; final TextStyle style; final double width; final double padding; final Color? backgroundColor; final TextAlign? textAlign; + final AlignmentDirectional alignment; @override Widget build(BuildContext context) { return Container( - alignment: AlignmentDirectional.topEnd, + alignment: alignment, width: width, padding: EdgeInsetsDirectional.only(end: padding), color: backgroundColor, diff --git a/lib/src/editor/style_widgets/number_point.dart b/lib/src/editor/style_widgets/number_point.dart index fadba673e..3d8a24cf9 100644 --- a/lib/src/editor/style_widgets/number_point.dart +++ b/lib/src/editor/style_widgets/number_point.dart @@ -12,9 +12,10 @@ class QuillNumberPoint extends StatelessWidget { this.textAlign, this.withDot = true, this.padding = 0.0, - super.key, this.backgroundColor, - }); + AlignmentDirectional? alignment, + super.key, + }) : alignment = alignment ?? AlignmentDirectional.topEnd; final String index; final Map indentLevelCounts; @@ -26,12 +27,13 @@ class QuillNumberPoint extends StatelessWidget { final double padding; final Color? backgroundColor; final TextAlign? textAlign; + final AlignmentDirectional alignment; @override Widget build(BuildContext context) { if (!attrs.containsKey(Attribute.indent.key) && indentLevelCounts.isEmpty) { return Container( - alignment: AlignmentDirectional.topEnd, + alignment: alignment, width: width, padding: EdgeInsetsDirectional.only(end: padding), color: backgroundColor, @@ -43,7 +45,7 @@ class QuillNumberPoint extends StatelessWidget { ); } return Container( - alignment: AlignmentDirectional.topEnd, + alignment: alignment, width: width, padding: EdgeInsetsDirectional.only(end: padding), color: backgroundColor, diff --git a/lib/src/editor/widgets/default_leading_components/bullet_point_leading.dart b/lib/src/editor/widgets/default_leading_components/bullet_point_leading.dart index 57f823a08..ce418face 100644 --- a/lib/src/editor/widgets/default_leading_components/bullet_point_leading.dart +++ b/lib/src/editor/widgets/default_leading_components/bullet_point_leading.dart @@ -6,4 +6,5 @@ Widget bulletPointLeading(LeadingConfig config) => QuillBulletPoint( style: config.style!, width: config.width!, padding: config.padding!, + alignment: config.listPointAlignment, ); diff --git a/lib/src/editor/widgets/default_leading_components/number_point_leading.dart b/lib/src/editor/widgets/default_leading_components/number_point_leading.dart index 02aba7932..fd2a711f7 100644 --- a/lib/src/editor/widgets/default_leading_components/number_point_leading.dart +++ b/lib/src/editor/widgets/default_leading_components/number_point_leading.dart @@ -10,4 +10,5 @@ Widget numberPointLeading(LeadingConfig config) => QuillNumberPoint( attrs: config.attrs, width: config.width!, padding: config.padding!, + alignment: config.listPointAlignment, ); diff --git a/lib/src/editor/widgets/default_styles.dart b/lib/src/editor/widgets/default_styles.dart index 1bf63a2e2..57d91e30e 100644 --- a/lib/src/editor/widgets/default_styles.dart +++ b/lib/src/editor/widgets/default_styles.dart @@ -181,11 +181,13 @@ class DefaultListBlockStyle extends DefaultTextBlockStyle { this.indentWidthBuilder = TextBlockUtils.defaultIndentWidthBuilder, this.numberPointWidthBuilder = TextBlockUtils.defaultNumberPointWidthBuilder, + this.pointAlignment, }); final QuillCheckboxBuilder? checkboxUIBuilder; final LeadingBlockIndentWidth indentWidthBuilder; final LeadingBlockNumberPointWidth numberPointWidthBuilder; + final AlignmentDirectional? pointAlignment; @override DefaultListBlockStyle copyWith({ @@ -197,6 +199,7 @@ class DefaultListBlockStyle extends DefaultTextBlockStyle { QuillCheckboxBuilder? checkboxUIBuilder, LeadingBlockIndentWidth? indentWidthBuilder, LeadingBlockNumberPointWidth? numberPointWidthBuilder, + AlignmentDirectional? pointAlignment, }) { return DefaultListBlockStyle( style ?? this.style, @@ -208,6 +211,7 @@ class DefaultListBlockStyle extends DefaultTextBlockStyle { indentWidthBuilder: indentWidthBuilder ?? this.indentWidthBuilder, numberPointWidthBuilder: numberPointWidthBuilder ?? this.numberPointWidthBuilder, + pointAlignment: pointAlignment ?? this.pointAlignment, ); } } diff --git a/lib/src/editor/widgets/text/text_block.dart b/lib/src/editor/widgets/text/text_block.dart index 01a4208e4..689b2ce83 100644 --- a/lib/src/editor/widgets/text/text_block.dart +++ b/lib/src/editor/widgets/text/text_block.dart @@ -275,6 +275,8 @@ class EditableTextBlock extends StatelessWidget { index: isOrdered || isCodeBlock ? index : null, count: count, enabled: !isCheck ? null : !(checkBoxReadOnly ?? readOnly), + listPointAlignment: + isOrdered || isCodeBlock ? defaultStyles.lists?.pointAlignment : null, style: () { if (isOrdered) { return defaultStyles.leading!.style.copyWith( From 9f71d101c0dbe1b2c31ea9938cbe8790aa3c68ad Mon Sep 17 00:00:00 2001 From: Christoph Schacht Date: Thu, 26 Jun 2025 10:44:12 +0200 Subject: [PATCH 3/4] added DefaultStylesOverride --- lib/src/editor/config/editor_config.dart | 4 +- .../raw_editor/config/raw_editor_config.dart | 4 +- .../editor/raw_editor/raw_editor_state.dart | 27 +- lib/src/editor/widgets/default_styles.dart | 586 ++++++++++-------- 4 files changed, 360 insertions(+), 261 deletions(-) diff --git a/lib/src/editor/config/editor_config.dart b/lib/src/editor/config/editor_config.dart index 73f2f0654..3774f3aa3 100644 --- a/lib/src/editor/config/editor_config.dart +++ b/lib/src/editor/config/editor_config.dart @@ -293,7 +293,7 @@ class QuillEditorConfig { final double? maxContentWidth; /// Allows to override [DefaultStyles]. - final DefaultStyles? customStyles; + final DefaultStylesOverride? customStyles; /// Whether this editor's height will be sized to fill its parent. /// @@ -502,7 +502,7 @@ class QuillEditorConfig { double? minHeight, double? maxHeight, double? maxContentWidth, - DefaultStyles? customStyles, + DefaultStylesOverride? customStyles, bool? expands, TextCapitalization? textCapitalization, Brightness? keyboardAppearance, diff --git a/lib/src/editor/raw_editor/config/raw_editor_config.dart b/lib/src/editor/raw_editor/config/raw_editor_config.dart index f2eda163c..47bdd497b 100644 --- a/lib/src/editor/raw_editor/config/raw_editor_config.dart +++ b/lib/src/editor/raw_editor/config/raw_editor_config.dart @@ -285,8 +285,8 @@ class QuillRawEditorConfig { /// horizontally centered. This is mostly useful on devices with wide screens. final double? maxContentWidth; - /// Allows to override [DefaultStyles]. - final DefaultStyles? customStyles; + /// Allows to override [DefaultStylesOverride]. + final DefaultStylesOverride? customStyles; /// Whether this widget's height will be sized to fill its parent. /// diff --git a/lib/src/editor/raw_editor/raw_editor_state.dart b/lib/src/editor/raw_editor/raw_editor_state.dart index cdc41c43a..250e2295c 100644 --- a/lib/src/editor/raw_editor/raw_editor_state.dart +++ b/lib/src/editor/raw_editor/raw_editor_state.dart @@ -892,14 +892,16 @@ class QuillRawEditorState extends EditorState void didChangeDependencies() { super.didChangeDependencies(); final parentStyles = QuillStyles.getStyles(context, true); - final customStyles = widget.config.customStyles; - final mergedStyles = parentStyles != null && customStyles != null - ? _styles!.merge(customStyles) - : customStyles ?? parentStyles; - - final defaultStyles = - DefaultStyles.getInstance(context, customDefaultStyles: mergedStyles); - _styles = defaultStyles; + final stylesOverride = widget.config.customStyles; + final defaultStyles = DefaultStyles.getInstance(context, + baseStyleOverride: stylesOverride?.defaultTextStyle); + _styles = (parentStyles != null) + ? defaultStyles.merge(parentStyles) + : defaultStyles; + + if (widget.config.customStyles != null) { + _styles = _styles!.applyOverrides(widget.config.customStyles!); + } _requestAutoFocusIfShould(); } @@ -951,13 +953,10 @@ class QuillRawEditorState extends EditorState } } - final customStyles = widget.config.customStyles; + final stylesOverride = widget.config.customStyles; // in case customStyles changed in new widget - if (customStyles != null) { - final mergedStyles = _styles!.merge(customStyles); - final defaultStyles = - DefaultStyles.getInstance(context, customDefaultStyles: mergedStyles); - _styles = defaultStyles; + if (stylesOverride != null) { + _styles = _styles!.applyOverrides(stylesOverride); } if (widget.config.actionConfiguration != diff --git a/lib/src/editor/widgets/default_styles.dart b/lib/src/editor/widgets/default_styles.dart index 57d91e30e..be60bdb58 100644 --- a/lib/src/editor/widgets/default_styles.dart +++ b/lib/src/editor/widgets/default_styles.dart @@ -293,16 +293,16 @@ class DefaultStyles { final Map? palette; static DefaultStyles getInstance(BuildContext context, - {DefaultStyles? customDefaultStyles}) { + {ValueOverride? baseStyleOverride}) { final themeData = Theme.of(context); - final defaultTextStyle = DefaultTextStyle.of(context).style; - - final baseStyle = customDefaultStyles?.defaultTextStyle ?? - defaultTextStyle.copyWith( + final defaultTextStyle = DefaultTextStyle.of(context); + final baseStyle = defaultTextStyle.style + .copyWith( fontSize: 16, height: 1.15, decoration: TextDecoration.none, - ); + ) + .override(baseStyleOverride); const baseHorizontalSpacing = HorizontalSpacing(0, 0); const baseVerticalSpacing = VerticalSpacing(6, 0); final fontFamily = themeData.isCupertino ? 'Menlo' : 'Roboto Mono'; @@ -314,255 +314,228 @@ class DefaultStyles { ); return DefaultStyles( - h1: customDefaultStyles?.h1 ?? - DefaultTextBlockStyle( - baseStyle.copyWith( - fontSize: 34, - color: baseStyle.color, - letterSpacing: -0.5, - height: 1.083, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(16, 0), - VerticalSpacing.zero, - null), - h2: customDefaultStyles?.h2 ?? - DefaultTextBlockStyle( - baseStyle.copyWith( - fontSize: 30, - color: baseStyle.color, - letterSpacing: -0.8, - height: 1.067, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(8, 0), - VerticalSpacing.zero, - null), - h3: customDefaultStyles?.h3 ?? - DefaultTextBlockStyle( - baseStyle.copyWith( - fontSize: 24, - color: baseStyle.color, - letterSpacing: -0.5, - height: 1.083, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(8, 0), - VerticalSpacing.zero, - null, - ), - h4: customDefaultStyles?.h4 ?? - DefaultTextBlockStyle( - baseStyle.copyWith( - fontSize: 20, - color: baseStyle.color, - letterSpacing: -0.4, - height: 1.1, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(6, 0), - VerticalSpacing.zero, - null, - ), - h5: customDefaultStyles?.h5 ?? - DefaultTextBlockStyle( - baseStyle.copyWith( - fontSize: 18, - color: baseStyle.color, - letterSpacing: -0.2, - height: 1.11, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(6, 0), - VerticalSpacing.zero, - null, - ), - h6: customDefaultStyles?.h6 ?? - DefaultTextBlockStyle( - baseStyle.copyWith( - fontSize: 16, - color: baseStyle.color, - letterSpacing: -0.1, - height: 1.125, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), - baseHorizontalSpacing, - const VerticalSpacing(4, 0), - VerticalSpacing.zero, - null, - ), - lineHeightNormal: customDefaultStyles?.lineHeightNormal ?? - DefaultTextBlockStyle( - baseStyle.copyWith(height: 1.15), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - lineHeightTight: customDefaultStyles?.lineHeightTight ?? - DefaultTextBlockStyle( - baseStyle.copyWith(height: 1.30), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, + h1: DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 34, + color: baseStyle.color, + letterSpacing: -0.5, + height: 1.083, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, ), - lineHeightOneAndHalf: customDefaultStyles?.lineHeightOneAndHalf ?? - DefaultTextBlockStyle( - baseStyle.copyWith(height: 1.55), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, + baseHorizontalSpacing, + const VerticalSpacing(16, 0), + VerticalSpacing.zero, + null), + h2: DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 30, + color: baseStyle.color, + letterSpacing: -0.8, + height: 1.067, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, ), - lineHeightDouble: customDefaultStyles?.lineHeightDouble ?? - DefaultTextBlockStyle( - baseStyle.copyWith(height: 2), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - paragraph: customDefaultStyles?.paragraph ?? - DefaultTextBlockStyle( - baseStyle, - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - bold: customDefaultStyles?.bold ?? - const TextStyle(fontWeight: FontWeight.bold), + baseHorizontalSpacing, + const VerticalSpacing(8, 0), + VerticalSpacing.zero, + null), + h3: DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 24, + color: baseStyle.color, + letterSpacing: -0.5, + height: 1.083, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(8, 0), + VerticalSpacing.zero, + null, + ), + h4: DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 20, + color: baseStyle.color, + letterSpacing: -0.4, + height: 1.1, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(6, 0), + VerticalSpacing.zero, + null, + ), + h5: DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 18, + color: baseStyle.color, + letterSpacing: -0.2, + height: 1.11, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(6, 0), + VerticalSpacing.zero, + null, + ), + h6: DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 16, + color: baseStyle.color, + letterSpacing: -0.1, + height: 1.125, + fontWeight: FontWeight.bold, + decoration: TextDecoration.none, + ), + baseHorizontalSpacing, + const VerticalSpacing(4, 0), + VerticalSpacing.zero, + null, + ), + lineHeightNormal: DefaultTextBlockStyle( + baseStyle.copyWith(height: 1.15), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + lineHeightTight: DefaultTextBlockStyle( + baseStyle.copyWith(height: 1.30), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + lineHeightOneAndHalf: DefaultTextBlockStyle( + baseStyle.copyWith(height: 1.55), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + lineHeightDouble: DefaultTextBlockStyle( + baseStyle.copyWith(height: 2), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + paragraph: DefaultTextBlockStyle( + baseStyle, + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + bold: const TextStyle(fontWeight: FontWeight.bold), subscript: const TextStyle( fontFeatures: [ FontFeature.liningFigures(), FontFeature.subscripts(), ], ), - superscript: customDefaultStyles?.superscript ?? - const TextStyle( - fontFeatures: [ - FontFeature.liningFigures(), - FontFeature.superscripts(), - ], + superscript: const TextStyle( + fontFeatures: [ + FontFeature.liningFigures(), + FontFeature.superscripts(), + ], + ), + italic: const TextStyle(fontStyle: FontStyle.italic), + small: const TextStyle(fontSize: 12), + underline: const TextStyle(decoration: TextDecoration.underline), + strikeThrough: const TextStyle(decoration: TextDecoration.lineThrough), + inlineCode: InlineCodeStyle( + backgroundColor: Colors.grey.shade100, + radius: const Radius.circular(3), + style: inlineCodeStyle, + header1: inlineCodeStyle.copyWith( + fontSize: 32, + fontWeight: FontWeight.w500, + ), + header2: inlineCodeStyle.copyWith( + fontSize: 22, + fontWeight: FontWeight.w500, + ), + header3: inlineCodeStyle.copyWith( + fontSize: 18, + fontWeight: FontWeight.w500, + ), + ), + link: TextStyle( + color: themeData.colorScheme.secondary, + decoration: TextDecoration.underline, + ), + placeHolder: DefaultTextBlockStyle( + baseStyle.copyWith( + fontSize: 20, + height: 1.5, + color: Colors.grey.withValues(alpha: 0.6), ), - italic: customDefaultStyles?.italic ?? - const TextStyle(fontStyle: FontStyle.italic), - small: customDefaultStyles?.small ?? const TextStyle(fontSize: 12), - underline: customDefaultStyles?.underline ?? - const TextStyle(decoration: TextDecoration.underline), - strikeThrough: customDefaultStyles?.strikeThrough ?? - const TextStyle(decoration: TextDecoration.lineThrough), - inlineCode: customDefaultStyles?.inlineCode ?? - InlineCodeStyle( - backgroundColor: Colors.grey.shade100, - radius: const Radius.circular(3), - style: inlineCodeStyle, - header1: inlineCodeStyle.copyWith( - fontSize: 32, - fontWeight: FontWeight.w500, - ), - header2: inlineCodeStyle.copyWith( - fontSize: 22, - fontWeight: FontWeight.w500, - ), - header3: inlineCodeStyle.copyWith( - fontSize: 18, - fontWeight: FontWeight.w500, - ), + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null), + lists: DefaultListBlockStyle( + baseStyle, + baseHorizontalSpacing, + baseVerticalSpacing, + const VerticalSpacing(0, 6), + null, + null, + ), + quote: DefaultTextBlockStyle( + TextStyle(color: baseStyle.color!.withValues(alpha: 0.6)), + baseHorizontalSpacing, + baseVerticalSpacing, + const VerticalSpacing(6, 2), + BoxDecoration( + border: Border( + left: BorderSide(width: 4, color: Colors.grey.shade300), ), - link: customDefaultStyles?.link ?? + ), + ), + code: DefaultTextBlockStyle( TextStyle( - color: themeData.colorScheme.secondary, - decoration: TextDecoration.underline, - ), - placeHolder: customDefaultStyles?.placeHolder ?? - DefaultTextBlockStyle( - baseStyle.copyWith( - fontSize: 20, - height: 1.5, - color: Colors.grey.withValues(alpha: 0.6), - ), - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null), - lists: customDefaultStyles?.lists ?? - DefaultListBlockStyle( - baseStyle, - baseHorizontalSpacing, - baseVerticalSpacing, - const VerticalSpacing(0, 6), - null, - null, - ), - quote: customDefaultStyles?.quote ?? - DefaultTextBlockStyle( - TextStyle(color: baseStyle.color!.withValues(alpha: 0.6)), - baseHorizontalSpacing, - baseVerticalSpacing, - const VerticalSpacing(6, 2), - BoxDecoration( - border: Border( - left: BorderSide(width: 4, color: Colors.grey.shade300), - ), - ), - ), - code: customDefaultStyles?.code ?? - DefaultTextBlockStyle( - TextStyle( - color: Colors.blue.shade900.withValues(alpha: 0.9), - fontFamily: fontFamily, - fontSize: 13, - height: 1.15, - ), - baseHorizontalSpacing, - baseVerticalSpacing, - VerticalSpacing.zero, - BoxDecoration( - color: Colors.grey.shade50, - borderRadius: BorderRadius.circular(2), - )), - indent: customDefaultStyles?.indent ?? - DefaultTextBlockStyle( - baseStyle, - baseHorizontalSpacing, - baseVerticalSpacing, - const VerticalSpacing(0, 6), - null, + color: Colors.blue.shade900.withValues(alpha: 0.9), + fontFamily: fontFamily, + fontSize: 13, + height: 1.15, ), - align: customDefaultStyles?.align ?? - DefaultTextBlockStyle( - baseStyle, - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - leading: customDefaultStyles?.leading ?? - DefaultTextBlockStyle( - baseStyle, - baseHorizontalSpacing, - VerticalSpacing.zero, - VerticalSpacing.zero, - null, - ), - sizeSmall: - customDefaultStyles?.sizeSmall ?? const TextStyle(fontSize: 10), - sizeLarge: - customDefaultStyles?.sizeLarge ?? const TextStyle(fontSize: 18), - sizeHuge: customDefaultStyles?.sizeHuge ?? const TextStyle(fontSize: 22), + baseHorizontalSpacing, + baseVerticalSpacing, + VerticalSpacing.zero, + BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(2), + )), + indent: DefaultTextBlockStyle( + baseStyle, + baseHorizontalSpacing, + baseVerticalSpacing, + const VerticalSpacing(0, 6), + null, + ), + align: DefaultTextBlockStyle( + baseStyle, + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + leading: DefaultTextBlockStyle( + baseStyle, + baseHorizontalSpacing, + VerticalSpacing.zero, + VerticalSpacing.zero, + null, + ), + sizeSmall: const TextStyle(fontSize: 10), + sizeLarge: const TextStyle(fontSize: 18), + sizeHuge: const TextStyle(fontSize: 22), ); } @@ -602,4 +575,131 @@ class DefaultStyles { palette: other.palette ?? palette, ); } + + /// Applies overrides to this DefaultStyles instance and returns a new instance. + DefaultStyles applyOverrides(DefaultStylesOverride overrides) { + return DefaultStyles( + h1: h1?.override(overrides.h1), + h2: h2?.override(overrides.h2), + h3: h3?.override(overrides.h3), + h4: h4?.override(overrides.h4), + h5: h5?.override(overrides.h5), + h6: h6?.override(overrides.h6), + paragraph: paragraph?.override(overrides.paragraph), + lineHeightNormal: lineHeightNormal?.override(overrides.lineHeightNormal), + lineHeightTight: lineHeightTight?.override(overrides.lineHeightTight), + lineHeightOneAndHalf: + lineHeightOneAndHalf?.override(overrides.lineHeightOneAndHalf), + lineHeightDouble: lineHeightDouble?.override(overrides.lineHeightDouble), + defaultTextStyle: defaultTextStyle?.override(overrides.defaultTextStyle), + bold: bold?.override(overrides.bold), + subscript: subscript?.override(overrides.subscript), + superscript: superscript?.override(overrides.superscript), + italic: italic?.override(overrides.italic), + small: small?.override(overrides.small), + underline: underline?.override(overrides.underline), + strikeThrough: strikeThrough?.override(overrides.strikeThrough), + inlineCode: inlineCode?.override(overrides.inlineCode), + link: link?.override(overrides.link), + color: color?.override(overrides.color), + placeHolder: placeHolder?.override(overrides.placeHolder), + lists: lists?.override(overrides.lists), + quote: quote?.override(overrides.quote), + code: code?.override(overrides.code), + indent: indent?.override(overrides.indent), + align: align?.override(overrides.align), + leading: leading?.override(overrides.leading), + sizeSmall: sizeSmall?.override(overrides.sizeSmall), + sizeLarge: sizeLarge?.override(overrides.sizeLarge), + sizeHuge: sizeHuge?.override(overrides.sizeHuge), + palette: palette?.override(overrides.palette), + ); + } +} + +typedef ValueOverride = T Function(T value); + +class DefaultStylesOverride { + const DefaultStylesOverride({ + this.h1, + this.h2, + this.h3, + this.h4, + this.h5, + this.h6, + this.paragraph, + this.lineHeightNormal, + this.lineHeightTight, + this.lineHeightOneAndHalf, + this.lineHeightDouble, + this.defaultTextStyle, + this.bold, + this.subscript, + this.superscript, + this.italic, + this.small, + this.underline, + this.strikeThrough, + this.inlineCode, + this.link, + this.color, + this.placeHolder, + this.lists, + this.quote, + this.code, + this.indent, + this.align, + this.leading, + this.sizeSmall, + this.sizeLarge, + this.sizeHuge, + this.palette, + }); + + final ValueOverride? h1; + final ValueOverride? h2; + final ValueOverride? h3; + final ValueOverride? h4; + final ValueOverride? h5; + final ValueOverride? h6; + final ValueOverride? paragraph; + final ValueOverride? lineHeightNormal; + final ValueOverride? lineHeightTight; + final ValueOverride? lineHeightOneAndHalf; + final ValueOverride? lineHeightDouble; + final ValueOverride? defaultTextStyle; + final ValueOverride? bold; + final ValueOverride? subscript; + final ValueOverride? superscript; + final ValueOverride? italic; + final ValueOverride? small; + final ValueOverride? underline; + final ValueOverride? strikeThrough; + + /// Theme of inline code. + final ValueOverride? inlineCode; + final ValueOverride? sizeSmall; // 'small' + final ValueOverride? sizeLarge; // 'large' + final ValueOverride? sizeHuge; // 'huge' + final ValueOverride? link; + final ValueOverride? color; + final ValueOverride? placeHolder; + final ValueOverride? lists; + final ValueOverride? quote; + final ValueOverride? code; + final ValueOverride? indent; + final ValueOverride? align; + final ValueOverride? leading; + + /// Custom palette of colors + final ValueOverride>? palette; +} + +extension _DefaultStylesOverrideExtension on T { + T override(ValueOverride? override) { + if (override != null) { + return override(this); + } + return this; + } } From d135f9be1464ddc39642224f1388084d54ad6dc0 Mon Sep 17 00:00:00 2001 From: Christoph Schacht Date: Thu, 3 Jul 2025 15:15:23 +0200 Subject: [PATCH 4/4] fix point alignment for unordered lists --- lib/src/editor/widgets/text/text_block.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/editor/widgets/text/text_block.dart b/lib/src/editor/widgets/text/text_block.dart index 689b2ce83..314333fcb 100644 --- a/lib/src/editor/widgets/text/text_block.dart +++ b/lib/src/editor/widgets/text/text_block.dart @@ -275,8 +275,9 @@ class EditableTextBlock extends StatelessWidget { index: isOrdered || isCodeBlock ? index : null, count: count, enabled: !isCheck ? null : !(checkBoxReadOnly ?? readOnly), - listPointAlignment: - isOrdered || isCodeBlock ? defaultStyles.lists?.pointAlignment : null, + listPointAlignment: isOrdered || isUnordered || isCodeBlock + ? defaultStyles.lists?.pointAlignment + : null, style: () { if (isOrdered) { return defaultStyles.leading!.style.copyWith(