Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions packages/fleather/lib/src/rendering/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class RenderEditor extends RenderEditableContainerBox
required ParchmentDocument document,
required ViewportOffset offset,
required bool hasFocus,
required TextWidthBasis textWidthBasis,
required TextSelection selection,
required LayerLink startHandleLayerLink,
required LayerLink endHandleLayerLink,
Expand All @@ -159,6 +160,7 @@ class RenderEditor extends RenderEditableContainerBox
_endHandleLayerLink = endHandleLayerLink,
_cursorController = cursorController,
_maxContentWidth = maxContentWidth,
_textWidthBasis = textWidthBasis,
super(
node: document.root,
);
Expand Down Expand Up @@ -262,6 +264,16 @@ class RenderEditor extends RenderEditableContainerBox
markNeedsLayout();
}

TextWidthBasis _textWidthBasis;

TextWidthBasis get textWidthBasis => _textWidthBasis;

set textWidthBasis(TextWidthBasis value) {
if (_textWidthBasis == value) return;
_textWidthBasis = value;
markNeedsLayout();
}

final CursorController _cursorController;

/// Track whether position of the start of the selected text is within the viewport.
Expand Down Expand Up @@ -592,11 +604,14 @@ class RenderEditor extends RenderEditableContainerBox
resolvePadding();
assert(resolvedPadding != null);

var contentSize = resolvedPadding!.top;
var contentHeight = resolvedPadding!.top;
var contentWidth = 0.0;
var child = firstChild;
final innerConstraints = BoxConstraints.tightFor(
width: math.min(
_maxContentWidth ?? double.infinity, constraints.maxWidth))
double width =
math.min(_maxContentWidth ?? double.infinity, constraints.maxWidth);
final innerConstraints = (textWidthBasis == TextWidthBasis.longestLine
? BoxConstraints(maxWidth: width)
: BoxConstraints.tightFor(width: width))
.deflate(resolvedPadding!);
final leftOffset = _maxContentWidth == null
? 0.0
Expand All @@ -605,15 +620,16 @@ class RenderEditor extends RenderEditableContainerBox
child.layout(innerConstraints, parentUsesSize: true);
final childParentData = child.parentData as EditableContainerParentData;
childParentData.offset =
Offset(resolvedPadding!.left + leftOffset, contentSize);
contentSize += child.size.height;
Offset(resolvedPadding!.left + leftOffset, contentHeight);
contentHeight += child.size.height;
contentWidth += math.max(contentWidth, child.size.width);
assert(child.parentData == childParentData);
child = childParentData.nextSibling;
}
contentSize += resolvedPadding!.bottom;
contentHeight += resolvedPadding!.bottom;
size = constraints
.constrain(Size(_maxContentWidth ?? constraints.maxWidth, contentSize));
_maxScrollExtent = math.max(0.0, contentSize - size.height);
.constrain(Size(_maxContentWidth ?? contentWidth, contentHeight));
_maxScrollExtent = math.max(0.0, contentHeight - size.height);
offset.applyViewportDimension(size.height);
offset.applyContentDimensions(0.0, _maxScrollExtent);

Expand Down
22 changes: 22 additions & 0 deletions packages/fleather/lib/src/widgets/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ class FleatherEditor extends StatefulWidget {
/// the text field from the clipboard.
final bool enableInteractiveSelection;

/// Defines how to measure the width of the rendered when [readOnly] is `true`
Comment thread
amantoux marked this conversation as resolved.
Outdated
/// text. Otherwise the value is ignored and forced to [TextWidthBasis.parent]
///
/// Default to [TextWidthBasis.parent].
final TextWidthBasis textWidthBasis;

/// The minimum height to be occupied by this editor.
///
/// This only has effect if [scrollable] is set to `true` and [expands] is
Expand Down Expand Up @@ -309,6 +315,7 @@ class FleatherEditor extends StatefulWidget {
this.autocorrect = true,
this.enableSuggestions = true,
this.enableInteractiveSelection = true,
this.textWidthBasis = TextWidthBasis.parent,
this.minHeight,
this.maxHeight,
this.maxContentWidth,
Expand Down Expand Up @@ -486,6 +493,7 @@ class _FleatherEditorState extends State<FleatherEditor>
readOnly: widget.readOnly,
enableSuggestions: widget.enableSuggestions,
enableInteractiveSelection: widget.enableInteractiveSelection,
textWidthBasis: widget.textWidthBasis,
minHeight: widget.minHeight,
maxHeight: widget.maxHeight,
maxContentWidth: widget.maxContentWidth,
Expand Down Expand Up @@ -589,6 +597,7 @@ class RawEditor extends StatefulWidget {
this.autocorrect = true,
this.enableSuggestions = true,
this.enableInteractiveSelection = true,
this.textWidthBasis = TextWidthBasis.parent,
this.minHeight,
this.maxHeight,
this.maxContentWidth,
Expand Down Expand Up @@ -716,6 +725,9 @@ class RawEditor extends StatefulWidget {
/// * [TextCapitalization], for a description of each capitalization behavior.
final TextCapitalization textCapitalization;

/// Defines how to measure the width of the rendered text.
final TextWidthBasis textWidthBasis;

/// The maximum height this editor can have.
///
/// If this is null then there is no limit to the editor's height and it will
Expand Down Expand Up @@ -1706,6 +1718,10 @@ class RawEditorState extends EditorState

final Widget child;

// In edition mode, force to TextWidthBasis.parent
final textWidthBasis =
widget.readOnly ? widget.textWidthBasis : TextWidthBasis.parent;

if (widget.scrollable) {
child = Scrollable(
key: _scrollableKey,
Expand All @@ -1732,6 +1748,7 @@ class RawEditorState extends EditorState
padding: widget.padding,
maxContentWidth: widget.maxContentWidth,
cursorController: _cursorController,
textWidthBasis: textWidthBasis,
children: _buildChildren(context),
),
),
Expand All @@ -1753,6 +1770,7 @@ class RawEditorState extends EditorState
onSelectionChanged: _handleSelectionChanged,
padding: widget.padding,
maxContentWidth: widget.maxContentWidth,
textWidthBasis: textWidthBasis,
children: _buildChildren(context),
),
),
Expand Down Expand Up @@ -2182,6 +2200,7 @@ class _Editor extends MultiChildRenderObjectWidget {
required this.endHandleLayerLink,
required this.onSelectionChanged,
required this.cursorController,
required this.textWidthBasis,
this.padding = EdgeInsets.zero,
this.maxContentWidth,
});
Expand All @@ -2196,6 +2215,7 @@ class _Editor extends MultiChildRenderObjectWidget {
final TextSelectionChangedHandler onSelectionChanged;
final EdgeInsetsGeometry padding;
final double? maxContentWidth;
final TextWidthBasis textWidthBasis;
final CursorController cursorController;

@override
Expand All @@ -2212,6 +2232,7 @@ class _Editor extends MultiChildRenderObjectWidget {
cursorController: cursorController,
padding: padding,
maxContentWidth: maxContentWidth,
textWidthBasis: textWidthBasis,
);
}

Expand All @@ -2229,6 +2250,7 @@ class _Editor extends MultiChildRenderObjectWidget {
renderObject.onSelectionChanged = onSelectionChanged;
renderObject.padding = padding;
renderObject.maxContentWidth = maxContentWidth;
renderObject.textWidthBasis = textWidthBasis;
}
}

Expand Down
8 changes: 8 additions & 0 deletions packages/fleather/lib/src/widgets/field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ class FleatherField extends StatefulWidget {
/// the text field from the clipboard.
final bool enableInteractiveSelection;

/// Defines how to measure the width of the rendered when [readOnly] is `true`
Comment thread
amantoux marked this conversation as resolved.
Outdated
/// text. Otherwise the value is ignored and forced to [TextWidthBasis.parent]
///
/// Default to [TextWidthBasis.parent].
final TextWidthBasis textWidthBasis;

/// The minimum height to be occupied by this editor.
///
/// This only has effect if [scrollable] is set to `true` and [expands] is
Expand Down Expand Up @@ -192,6 +198,7 @@ class FleatherField extends StatefulWidget {
this.autocorrect = true,
this.enableSuggestions = true,
this.enableInteractiveSelection = true,
this.textWidthBasis = TextWidthBasis.parent,
this.minHeight,
this.maxHeight,
this.expands = false,
Expand Down Expand Up @@ -264,6 +271,7 @@ class _FleatherFieldState extends State<FleatherField> {
autocorrect: widget.autocorrect,
enableSuggestions: widget.enableSuggestions,
enableInteractiveSelection: widget.enableInteractiveSelection,
textWidthBasis: widget.textWidthBasis,
minHeight: widget.minHeight,
maxHeight: widget.maxHeight,
expands: widget.expands,
Expand Down
2 changes: 2 additions & 0 deletions packages/fleather/lib/src/widgets/text_line.dart
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ class _TextLineState extends State<TextLine> {
final embed = widget.node.children.single as EmbedNode;
return EmbedProxy(child: widget.embedBuilder(context, embed));
}
final editorState = context.findAncestorStateOfType<RawEditorState>()!;
final text = buildText(context, widget.node);
final textAlign = getTextAlign(widget.node);
final strutStyle = StrutStyle.fromTextStyle(text.style!);
Expand All @@ -136,6 +137,7 @@ class _TextLineState extends State<TextLine> {
text: text,
textAlign: textAlign,
strutStyle: strutStyle,
textWidthBasis: editorState.widget.textWidthBasis,
Comment thread
amantoux marked this conversation as resolved.
Outdated
textScaler: MediaQuery.textScalerOf(context),
),
);
Expand Down
71 changes: 58 additions & 13 deletions packages/fleather/test/testing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ class EditorSandBox {
ParchmentDocument? document,
FleatherThemeData? fleatherTheme,
bool autofocus = false,
bool readOnly = false,
bool showCursor = true,
bool scrollable = true,
bool useField = true,
bool enableSelectionInteraction = true,
FakeSpellCheckService? spellCheckService,
TextWidthBasis textWidthBasis = TextWidthBasis.parent,
ClipboardManager clipboardManager = const PlainTextClipboardManager(),
FleatherEmbedBuilder embedBuilder = defaultFleatherEmbedBuilder,
TransitionBuilder? appBuilder,
Expand All @@ -25,10 +30,15 @@ class EditorSandBox {
var controller = FleatherController(document: document);

Widget widget = _FleatherSandbox(
useField: useField,
controller: controller,
focusNode: focusNode,
autofocus: autofocus,
scrollable: scrollable,
readOnly: readOnly,
showCursor: showCursor,
enableSelectionInteraction: enableSelectionInteraction,
textWidthBasis: textWidthBasis,
spellCheckService: spellCheckService,
embedBuilder: embedBuilder,
clipboardManager: clipboardManager,
Expand Down Expand Up @@ -140,44 +150,79 @@ class _FleatherSandbox extends StatefulWidget {
const _FleatherSandbox({
required this.controller,
required this.focusNode,
this.useField = true,
this.autofocus = false,
this.readOnly = false,
this.scrollable = true,
this.showCursor = true,
this.enableSelectionInteraction = true,
this.spellCheckService,
required this.textWidthBasis,
this.embedBuilder = defaultFleatherEmbedBuilder,
this.clipboardManager = const PlainTextClipboardManager(),
});

final bool useField;
final FleatherController controller;
final FocusNode focusNode;
final bool autofocus;
final bool readOnly;
final bool showCursor;
final bool scrollable;
final bool enableSelectionInteraction;
final FakeSpellCheckService? spellCheckService;
final FleatherEmbedBuilder embedBuilder;
final ClipboardManager clipboardManager;
final TextWidthBasis textWidthBasis;

@override
_FleatherSandboxState createState() => _FleatherSandboxState();
}

class _FleatherSandboxState extends State<_FleatherSandbox> {
bool _enabled = true;
late bool _enabled = !widget.readOnly;

@override
Widget build(BuildContext context) {
return Material(
child: FleatherField(
clipboardManager: widget.clipboardManager,
embedBuilder: widget.embedBuilder,
controller: widget.controller,
focusNode: widget.focusNode,
readOnly: !_enabled,
enableInteractiveSelection: widget.enableSelectionInteraction,
autofocus: widget.autofocus,
spellCheckConfiguration: widget.spellCheckService != null
? SpellCheckConfiguration(
spellCheckService: widget.spellCheckService,
// Add alignment to loosen the constraints set by tester
child: Align(
alignment: Alignment.topLeft,
child: widget.useField
? FleatherField(
clipboardManager: widget.clipboardManager,
embedBuilder: widget.embedBuilder,
controller: widget.controller,
focusNode: widget.focusNode,
readOnly: !_enabled,
showCursor: widget.showCursor,
scrollable: widget.scrollable,
textWidthBasis: widget.textWidthBasis,
enableInteractiveSelection: widget.enableSelectionInteraction,
autofocus: widget.autofocus,
spellCheckConfiguration: widget.spellCheckService != null
? SpellCheckConfiguration(
spellCheckService: widget.spellCheckService,
)
: null,
)
: null,
: FleatherEditor(
clipboardManager: widget.clipboardManager,
embedBuilder: widget.embedBuilder,
controller: widget.controller,
focusNode: widget.focusNode,
readOnly: !_enabled,
showCursor: widget.showCursor,
scrollable: widget.scrollable,
textWidthBasis: widget.textWidthBasis,
enableInteractiveSelection: widget.enableSelectionInteraction,
autofocus: widget.autofocus,
spellCheckConfiguration: widget.spellCheckService != null
? SpellCheckConfiguration(
spellCheckService: widget.spellCheckService,
)
: null,
),
),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class MockEditorState extends Mock implements EditorState {
startHandleLayerLink: LayerLink(),
endHandleLayerLink: LayerLink(),
padding: EdgeInsets.zero,
textWidthBasis: TextWidthBasis.parent,
cursorController: CursorController(
showCursor: ValueNotifier(true),
style: const CursorStyle(
Expand Down
Loading