diff --git a/CHANGELOG.md b/CHANGELOG.md index 4159aa37c..4d4c095e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,13 +12,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -* Remove unicode from `QuillText` element that causes weird caret behavior on empty lines [#2453](https://github.com/singerdmx/flutter-quill/pull/2453). -* Focus and open context menu on right click if unfocused [#2477](https://github.com/singerdmx/flutter-quill/pull/2477). -* Update QuillController `length` extension method deprecation message [#2483](https://github.com/singerdmx/flutter-quill/pull/2483). +- Remove unicode from `QuillText` element that causes weird caret behavior on empty lines [#2453](https://github.com/singerdmx/flutter-quill/pull/2453). +- Focus and open context menu on right click if unfocused [#2477](https://github.com/singerdmx/flutter-quill/pull/2477). +- Update QuillController `length` extension method deprecation message [#2483](https://github.com/singerdmx/flutter-quill/pull/2483). ### Added -* `Rule` is now part of the public API, so that `Document.setCustomRules` can be used. +- `Rule` is now part of the public API, so that `Document.setCustomRules` can be used. +- `decoration` property in `DefaultTextBlockStyle` for the `header` attribute to customize headers with borders, background colors, and other styles using `BoxDecoration` [#2429](https://github.com/singerdmx/flutter-quill/pull/2429). ## [11.0.0] - 2025-02-16 diff --git a/lib/src/editor/raw_editor/raw_editor_state.dart b/lib/src/editor/raw_editor/raw_editor_state.dart index c6bcfa4a7..eff2d0760 100644 --- a/lib/src/editor/raw_editor/raw_editor_state.dart +++ b/lib/src/editor/raw_editor/raw_editor_state.dart @@ -586,7 +586,8 @@ class QuillRawEditorState extends EditorState prevNodeOl = attrs[Attribute.list.key] == Attribute.ol; final nodeTextDirection = getDirectionOfNode(node, _textDirection); if (node is Line) { - final editableTextLine = _getEditableTextLineFromNode(node, context); + final editableTextLine = + _getEditableTextLineFromNode(node, context, attrs); result.add(Directionality( textDirection: nodeTextDirection, child: editableTextLine)); } else if (node is Block) { @@ -639,7 +640,7 @@ class QuillRawEditorState extends EditorState } EditableTextLine _getEditableTextLineFromNode( - Line node, BuildContext context) { + Line node, BuildContext context, Map> attrs) { final textLine = TextLine( line: node, textDirection: _textDirection, @@ -668,7 +669,8 @@ class QuillRawEditorState extends EditorState _hasFocus, MediaQuery.devicePixelRatioOf(context), _cursorCont, - _styles!.inlineCode!); + _styles!.inlineCode!, + _getDecoration(node, _styles, attrs)); return editableTextLine; } @@ -772,6 +774,30 @@ class QuillRawEditorState extends EditorState return VerticalSpacing.zero; } + BoxDecoration? _getDecoration(Node node, DefaultStyles? defaultStyles, + Map> attrs) { + if (attrs.containsKey(Attribute.header.key)) { + final level = attrs[Attribute.header.key]!.value; + switch (level) { + case 1: + return defaultStyles!.h1!.decoration; + case 2: + return defaultStyles!.h2!.decoration; + case 3: + return defaultStyles!.h3!.decoration; + case 4: + return defaultStyles!.h4!.decoration; + case 5: + return defaultStyles!.h5!.decoration; + case 6: + return defaultStyles!.h6!.decoration; + default: + throw ArgumentError('Invalid level $level'); + } + } + return null; + } + void _didChangeTextEditingValueListener() { _didChangeTextEditingValue(controller.ignoreFocusOnTextChange); } diff --git a/lib/src/editor/widgets/text/text_block.dart b/lib/src/editor/widgets/text/text_block.dart index 36c7f6ca8..01a4208e4 100644 --- a/lib/src/editor/widgets/text/text_block.dart +++ b/lib/src/editor/widgets/text/text_block.dart @@ -209,7 +209,7 @@ class EditableTextBlock extends StatelessWidget { MediaQuery.devicePixelRatioOf(context), cursorCont, styles!.inlineCode!, - ); + null); final nodeTextDirection = getDirectionOfNode(line, textDirection); children.add( Directionality( diff --git a/lib/src/editor/widgets/text/text_line.dart b/lib/src/editor/widgets/text/text_line.dart index 0758f08b5..32e03496b 100644 --- a/lib/src/editor/widgets/text/text_line.dart +++ b/lib/src/editor/widgets/text/text_line.dart @@ -736,6 +736,7 @@ class EditableTextLine extends RenderObjectWidget { this.devicePixelRatio, this.cursorCont, this.inlineCodeStyle, + this.decoration, {super.key}); final Line line; @@ -751,6 +752,7 @@ class EditableTextLine extends RenderObjectWidget { final double devicePixelRatio; final CursorCont cursorCont; final InlineCodeStyle inlineCodeStyle; + final BoxDecoration? decoration; @override RenderObjectElement createElement() { @@ -769,7 +771,8 @@ class EditableTextLine extends RenderObjectWidget { _getPadding(), color, cursorCont, - inlineCodeStyle); + inlineCodeStyle, + decoration); } @override @@ -785,7 +788,8 @@ class EditableTextLine extends RenderObjectWidget { ..hasFocus = hasFocus ..setDevicePixelRatio(devicePixelRatio) ..setCursorCont(cursorCont) - ..setInlineCodeStyle(inlineCodeStyle); + ..setInlineCodeStyle(inlineCodeStyle) + ..setDecoration(decoration); } EdgeInsetsGeometry _getPadding() { @@ -812,6 +816,7 @@ class RenderEditableTextLine extends RenderEditableBox { this.color, this.cursorCont, this.inlineCodeStyle, + this.decoration, ); RenderBox? _leading; @@ -830,6 +835,7 @@ class RenderEditableTextLine extends RenderEditableBox { List? _selectedRects; late Rect _caretPrototype; InlineCodeStyle inlineCodeStyle; + BoxDecoration? decoration; final Map children = {}; Iterable get _children sync* { @@ -945,6 +951,12 @@ class RenderEditableTextLine extends RenderEditableBox { markNeedsLayout(); } + void setDecoration(BoxDecoration? newDecoration) { + if (decoration == newDecoration) return; + decoration = newDecoration; + markNeedsPaint(); + } + // Start selection implementation bool containsTextSelection() { @@ -1334,6 +1346,15 @@ class RenderEditableTextLine extends RenderEditableBox { ); } } + final boxDecoration = decoration; + if (boxDecoration != null) { + final paintRect = offset & size; + boxDecoration.createBoxPainter().paint( + context.canvas, + paintRect.topLeft, + ImageConfiguration(size: paintRect.size), + ); + } if (_body != null) { final parentData = _body!.parentData as BoxParentData;