+57
-31
lib/widgets/faceted_text_field.dart
+57
-31
lib/widgets/faceted_text_field.dart
···
348
348
}
349
349
350
350
class _MentionHighlightTextFieldState extends State<_MentionHighlightTextField> {
351
+
final ScrollController _richTextScrollController = ScrollController();
352
+
final ScrollController _textFieldScrollController = ScrollController();
353
+
351
354
void _onMentionTap(String did) {
352
355
// Show overlay for this mention (simulate as if user is typing @mention)
353
356
final parent = context.findAncestorStateOfType<_FacetedTextFieldState>();
···
364
367
super.initState();
365
368
_parseFacets();
366
369
widget.controller.addListener(_parseFacets);
370
+
371
+
// Sync scroll controllers
372
+
_textFieldScrollController.addListener(() {
373
+
if (_richTextScrollController.hasClients && _textFieldScrollController.hasClients) {
374
+
_richTextScrollController.jumpTo(_textFieldScrollController.offset);
375
+
}
376
+
});
367
377
}
368
378
369
379
@override
370
380
void dispose() {
371
381
widget.controller.removeListener(_parseFacets);
372
382
_facetDebounce?.cancel();
383
+
_richTextScrollController.dispose();
384
+
_textFieldScrollController.dispose();
373
385
super.dispose();
374
386
}
375
387
···
466
478
}
467
479
return LayoutBuilder(
468
480
builder: (context, constraints) {
469
-
return Stack(
470
-
children: [
471
-
// RichText for highlight
472
-
Padding(
473
-
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
474
-
child: RichText(
475
-
text: TextSpan(children: spans),
476
-
maxLines: widget.maxLines,
477
-
overflow: TextOverflow.visible,
481
+
return SizedBox(
482
+
width: double.infinity, // Make it full width
483
+
height: widget.maxLines == 1
484
+
? null
485
+
: (baseStyle?.fontSize ?? 15) * 1.4 * widget.maxLines +
486
+
24, // Line height * maxLines + padding
487
+
child: Stack(
488
+
children: [
489
+
// RichText for highlight wrapped in SingleChildScrollView
490
+
SingleChildScrollView(
491
+
controller: _richTextScrollController,
492
+
physics: const NeverScrollableScrollPhysics(), // Disable direct interaction
493
+
child: Padding(
494
+
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
495
+
child: RichText(
496
+
text: TextSpan(children: spans),
497
+
maxLines: null, // Allow unlimited lines for scrolling
498
+
overflow: TextOverflow.visible,
499
+
),
500
+
),
478
501
),
479
-
),
480
-
// Editable TextField for input, but with transparent text so only RichText is visible
481
-
TextField(
482
-
controller: widget.controller,
483
-
maxLines: widget.maxLines,
484
-
enabled: widget.enabled,
485
-
keyboardType: widget.keyboardType,
486
-
onChanged: widget.onChanged,
487
-
style: baseStyle?.copyWith(color: const Color(0x01000000)),
488
-
cursorColor: theme.colorScheme.primary,
489
-
showCursor: true,
490
-
enableInteractiveSelection: true,
491
-
decoration: InputDecoration(
492
-
hintText: widget.hintText,
493
-
hintStyle: baseStyle?.copyWith(color: theme.hintColor),
494
-
border: InputBorder.none,
495
-
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
496
-
isDense: true,
497
-
prefixIcon: widget.prefixIcon,
498
-
suffixIcon: widget.suffixIcon,
502
+
// Editable TextField for input, but with transparent text so only RichText is visible
503
+
Positioned.fill(
504
+
child: TextField(
505
+
controller: widget.controller,
506
+
scrollController: _textFieldScrollController,
507
+
maxLines: null, // Allow unlimited lines for scrolling
508
+
enabled: widget.enabled,
509
+
keyboardType: widget.keyboardType,
510
+
onChanged: widget.onChanged,
511
+
style: baseStyle?.copyWith(color: const Color(0x01000000)),
512
+
cursorColor: theme.colorScheme.primary,
513
+
showCursor: true,
514
+
enableInteractiveSelection: true,
515
+
decoration: InputDecoration(
516
+
hintText: widget.hintText,
517
+
hintStyle: baseStyle?.copyWith(color: theme.hintColor),
518
+
border: InputBorder.none,
519
+
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
520
+
isDense: true,
521
+
prefixIcon: widget.prefixIcon,
522
+
suffixIcon: widget.suffixIcon,
523
+
),
524
+
),
499
525
),
500
-
),
501
-
],
526
+
],
527
+
),
502
528
);
503
529
},
504
530
);