Skip to content

Commit

Permalink
[SuperTextField] - Add support for inline widgets (Resolves #2507) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
angelosilvestre authored and matthew-carroll committed Jan 25, 2025
1 parent 8856421 commit ddd06bf
Show file tree
Hide file tree
Showing 20 changed files with 730 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:attributed_text/attributed_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:follow_the_leader/follow_the_leader.dart';
Expand Down Expand Up @@ -35,6 +36,7 @@ class SuperAndroidTextField extends StatefulWidget {
this.textController,
this.textAlign,
this.textStyleBuilder = defaultTextFieldStyleBuilder,
this.inlineWidgetBuilders = const [],
this.hintBehavior = HintBehavior.displayHintUntilFocus,
this.hintBuilder,
this.minLines,
Expand Down Expand Up @@ -73,6 +75,9 @@ class SuperAndroidTextField extends StatefulWidget {
/// [textController] based on the attributions in that content.
final AttributionStyleBuilder textStyleBuilder;

/// {@macro super_text_field_inline_widget_builders}
final InlineWidgetBuilderChain inlineWidgetBuilders;

/// Policy for when the hint should be displayed.
final HintBehavior hintBehavior;

Expand Down Expand Up @@ -631,7 +636,7 @@ class SuperAndroidTextFieldState extends State<SuperAndroidTextField>

Widget _buildSelectableText() {
final textSpan = _textEditingController.text.isNotEmpty
? _textEditingController.text.computeTextSpan(widget.textStyleBuilder)
? _textEditingController.text.computeInlineSpan(context, widget.textStyleBuilder, widget.inlineWidgetBuilders)
: TextSpan(text: "", style: widget.textStyleBuilder({}));

return Directionality(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class SuperDesktopTextField extends StatefulWidget {
this.tapRegionGroupId,
this.textController,
this.textStyleBuilder = defaultTextFieldStyleBuilder,
this.textAlign,
this.inlineWidgetBuilders = const [],
this.textAlign = TextAlign.left,
this.hintBehavior = HintBehavior.displayHintUntilFocus,
this.hintBuilder,
this.selectionHighlightStyle = const SelectionHighlightStyle(
Expand Down Expand Up @@ -92,6 +93,9 @@ class SuperDesktopTextField extends StatefulWidget {
/// [textController] based on the attributions in that content.
final AttributionStyleBuilder textStyleBuilder;

/// {@macro super_text_field_inline_widget_builders}
final InlineWidgetBuilderChain inlineWidgetBuilders;

/// Policy for when the hint should be displayed.
final HintBehavior hintBehavior;

Expand Down Expand Up @@ -525,7 +529,7 @@ class SuperDesktopTextFieldState extends State<SuperDesktopTextField> implements
textDirection: _textDirection,
child: SuperText(
key: _textKey,
richText: _controller.text.computeTextSpan(widget.textStyleBuilder),
richText: _controller.text.computeInlineSpan(context, widget.textStyleBuilder, widget.inlineWidgetBuilders),
textAlign: _textAlign,
textDirection: _textDirection,
textScaler: _textScaler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ class AttributedTextEditingController with ChangeNotifier {
notifyListeners();
}

@Deprecated('Use text.computeInlineSpan() instead, which adds support for inline widgets.')
TextSpan buildTextSpan(AttributionStyleBuilder styleBuilder) {
return text.computeTextSpan(styleBuilder);
}
Expand Down
11 changes: 7 additions & 4 deletions super_editor/lib/src/super_textfield/ios/ios_textfield.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ class SuperIOSTextField extends StatefulWidget {
this.tapHandlers = const [],
this.textController,
this.textStyleBuilder = defaultTextFieldStyleBuilder,
this.textAlign,
this.inlineWidgetBuilders = const [],
this.textAlign = TextAlign.left,
this.padding,
this.hintBehavior = HintBehavior.displayHintUntilFocus,
this.hintBuilder,
Expand Down Expand Up @@ -83,6 +84,9 @@ class SuperIOSTextField extends StatefulWidget {
/// [textController] based on the attributions in that content.
final AttributionStyleBuilder textStyleBuilder;

/// {@macro super_text_field_inline_widget_builders}
final InlineWidgetBuilderChain inlineWidgetBuilders;

/// Padding placed around the text content of this text field, but within the
/// scrollable viewport.
final EdgeInsets? padding;
Expand Down Expand Up @@ -630,9 +634,8 @@ class SuperIOSTextFieldState extends State<SuperIOSTextField>
}

Widget _buildSelectableText() {
final textSpan = _textEditingController.text.isNotEmpty
? _textEditingController.text.computeTextSpan(widget.textStyleBuilder)
: AttributedText().computeTextSpan(widget.textStyleBuilder);
final textSpan = _textEditingController.text //
.computeInlineSpan(context, widget.textStyleBuilder, widget.inlineWidgetBuilders);

CaretStyle caretStyle = widget.caretStyle;

Expand Down
12 changes: 12 additions & 0 deletions super_editor/lib/src/super_textfield/super_textfield.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class SuperTextField extends StatefulWidget {
this.textController,
this.textAlign,
this.textStyleBuilder = defaultTextFieldStyleBuilder,
this.inlineWidgetBuilders = const [],
this.hintBehavior = HintBehavior.displayHintUntilFocus,
this.hintBuilder,
this.controlsColor,
Expand Down Expand Up @@ -107,6 +108,14 @@ class SuperTextField extends StatefulWidget {
/// [textController] based on the attributions in that content.
final AttributionStyleBuilder textStyleBuilder;

/// {@template super_text_field_inline_widget_builders}
/// A Chain of Responsibility that's used to build inline widgets.
///
/// The first builder in the chain to return a non-null `Widget` will be
/// used for a given inline placeholder.
/// {@endtemplate}
final InlineWidgetBuilderChain inlineWidgetBuilders;

/// Policy for when the hint should be displayed.
final HintBehavior hintBehavior;

Expand Down Expand Up @@ -364,6 +373,7 @@ class SuperTextFieldState extends State<SuperTextField> implements ImeInputOwner
textController: _controller,
textAlign: widget.textAlign,
textStyleBuilder: widget.textStyleBuilder,
inlineWidgetBuilders: widget.inlineWidgetBuilders,
hintBehavior: widget.hintBehavior,
hintBuilder: widget.hintBuilder,
selectionHighlightStyle: SelectionHighlightStyle(
Expand Down Expand Up @@ -398,6 +408,7 @@ class SuperTextFieldState extends State<SuperTextField> implements ImeInputOwner
textController: _controller,
textAlign: widget.textAlign,
textStyleBuilder: widget.textStyleBuilder,
inlineWidgetBuilders: widget.inlineWidgetBuilders,
hintBehavior: widget.hintBehavior,
hintBuilder: widget.hintBuilder,
caretStyle: widget.caretStyle ??
Expand Down Expand Up @@ -427,6 +438,7 @@ class SuperTextFieldState extends State<SuperTextField> implements ImeInputOwner
textController: _controller,
textAlign: widget.textAlign,
textStyleBuilder: widget.textStyleBuilder,
inlineWidgetBuilders: widget.inlineWidgetBuilders,
padding: widget.padding,
hintBehavior: widget.hintBehavior,
hintBuilder: widget.hintBuilder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ void main() {
);

// Ensure the text is colored orange.
expect(
SuperTextFieldInspector.findRichText().style!.color,
Colors.orange,
);
for (int i = 0; i <= 9; i++) {
expect(
SuperTextFieldInspector.findRichText().getSpanForPosition(TextPosition(offset: i))!.style!.color,
Colors.orange,
);
}
});

testWidgetsOnAllPlatforms("to partial text", (tester) async {
Expand Down
Loading

0 comments on commit ddd06bf

Please sign in to comment.