Repository: flutter
Issue: TextField using custom SpellCheckService messes up its contents
Labels: a: text input,framework,has reproducible steps,P2,found in release: 3.10,team-framework,triaged-framework,found in release: 3.13

### Is there an existing issue for this?

- [X] I have searched the [existing issues](https://github.com/flutter/flutter/issues)
- [X] I have read the [guide to filing a bug](https://flutter.dev/docs/resources/bug-reports)

### Steps to reproduce

1. Run code sample and in each TextField, type anything.


### Expected results

- TextField contents not messed up
- Requirement for `List<SuggestionSpan>` to be sorted and not overlapping should be dropped || documented && asserted

### Actual results

TextField shows non-existing content, which also cannot be edited (cursor cannot be moved to it)


### Code sample

<details><summary>Code sample</summary>

```dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('SpellCheckService Bug')),
      body: Padding(padding: const EdgeInsets.all(16), child: _buildTextFields()),
    );
  }

  Widget _buildTextFields() {
    return Column(
      children: [
        TextField(
          controller: TextEditingController(text: 'Lorem ipsum dolor sit amet.'),
          minLines: 3,
          maxLines: 3,
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
            labelText: 'Unsorted list of SuggestionSpan',
          ),
          spellCheckConfiguration: SpellCheckConfiguration(spellCheckService: ReverseSortedSpellCheckServiceMock()),
        ),
        const SizedBox(height: 32),
        TextField(
          controller: TextEditingController(text: 'Lorem ipsum dolor sit amet.'),
          minLines: 3,
          maxLines: 3,
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
            labelText: 'Overlapping list of SuggestionSpan',
          ),
          spellCheckConfiguration: SpellCheckConfiguration(spellCheckService: OverlappingSpellCheckServiceMock()),
        ),
      ],
    );
  }
}

/// Spell check service that will returns a list of all words in the text in reverse order.
class ReverseSortedSpellCheckServiceMock extends SpellCheckService {
  @override
  Future<List<SuggestionSpan>?> fetchSpellCheckSuggestions(Locale locale, String text) async {
    final matches = RegExp(r'\b\w+').allMatches(text);
    final spans = matches
        .map((match) => SuggestionSpan(
              TextRange(start: match.start, end: match.end),
              const [],
            ))
        .toList();
    spans.sort((a, b) => b.range.start.compareTo(a.range.start));

    debugPrint(spans
        .map((e) => '${e.range.start}-${e.range.end}: ${text.substring(e.range.start, e.range.end)}')
        .toList()
        .join(', '));

    return spans;
  }
}

/// Spell check service that will return all pairs of words in the text (which will overlap).
class OverlappingSpellCheckServiceMock extends SpellCheckService {
  @override
  Future<List<SuggestionSpan>?> fetchSpellCheckSuggestions(Locale locale, String text) async {
    final matches = RegExp(r'\b\w+').allMatches(text);
    final spans = [
      for (int i = 1; i < matches.length; i++)
        SuggestionSpan(
          TextRange(start: matches.elementAt(i - 1).start, end: matches.elementAt(i).end),
          const [],
        ),
    ];

    debugPrint(spans
        .map((e) => '${e.range.start}-${e.range.end}: ${text.substring(e.range.start, e.range.end)}')
        .toList()
        .join(', '));

    return spans;
  }
}
```

</details>


### Screenshots or Video

_No response_

### Logs

_No response_

### Flutter Doctor output

<details><summary>Doctor output</summary>

```console
flutter doctor -v
[✓] Flutter (Channel master, 3.13.0-7.0.pre.62, on macOS 13.3.1 22E772610a darwin-arm64, locale en-CZ)
    • Flutter version 3.13.0-7.0.pre.62 on channel master at /opt/homebrew/Caskroom/flutter/1.22.6/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision aafdbc6d12 (2 hours ago), 2023-07-21 03:38:54 -0700
    • Engine revision f5c1650c7a
    • Dart version 3.1.0 (build 3.1.0-333.0.dev)
    • DevTools version 2.25.0

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/lukasnevosad/Library/Android/sdk
    • Platform android-33, build-tools 31.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14E300c
    • CocoaPods version 1.12.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)

[✓] VS Code (version 1.80.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.68.0

[✓] Connected device (5 available)
    • SM G920F (mobile)       • 1015fad829250302                         • android-arm64  • Android 7.0 (API 24)
    • Lukas’s iPhone (mobile) • 00008120-00060C2911E0C01E                • ios            • iOS 16.5.1 20F75
    • Lukas’s iPad (mobile)   • d4caf5df1725164fd6a5d1b4e6c8ca8ec346de71 • ios            • iOS 16.5.1 20F75
    • macOS (desktop)         • macos                                    • darwin-arm64   • macOS 13.3.1 22E772610a darwin-arm64
    • Chrome (web)            • chrome                                   • web-javascript • Google Chrome 114.0.5735.198
    ! Error: Lukas’s iPhone is busy: Making Lukas’s iPhone ready for development. Xcode will continue when Lukas’s iPhone is finished. (code -10)
    ! Error: Lukas’s Apple Watch needs to connect to determine its availability. Check the connection between the device and its companion iPhone, and the connection between the iPhone and Xcode. Both devices may also need to be restarted and unlocked. (code 1)

[✓] Network resources
    • All expected network resources are available.

• No issues found!
```

</details>