From d5eb30e7cb06e25d1aee1861c21449f787fa3bf8 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 11 Oct 2026 12:05:03 +0300 Subject: [PATCH] fix(editor): a filling code editor starts its text at the top QueryaCodeEditor did not pass textAlignVertical to the shadcn field, and the field centres the text of one that expands, so the placeholder and the first line of the SQL editor sat in the middle of the pane. A filling editor now aligns to the top unless textAlignVertical says otherwise; tests check the caret position for both variants and an explicit alignment. --- lib/core/editor/querya_code_editor.dart | 10 ++- .../querya_code_editor_alignment_test.dart | 68 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 test/core/editor/querya_code_editor_alignment_test.dart diff --git a/lib/core/editor/querya_code_editor.dart b/lib/core/editor/querya_code_editor.dart index 0d0741e6..0728a6d1 100644 --- a/lib/core/editor/querya_code_editor.dart +++ b/lib/core/editor/querya_code_editor.dart @@ -175,6 +175,13 @@ class _QueryaCodeEditorState extends State { ); } + /// A filling editor starts at the top, like every code editor; an + /// explicit [QueryaCodeEditor.textAlignVertical] still wins. (The field's own + /// default centres the text of a field that expands.) + material.TextAlignVertical? get _verticalAlignment => + widget.textAlignVertical ?? + (widget.expands ? material.TextAlignVertical.top : null); + Widget? _resolvedPlaceholder() { if (widget.placeholder != null) return widget.placeholder; return switch (widget.language) { @@ -202,7 +209,7 @@ class _QueryaCodeEditorState extends State { maxLines: widget.expands ? null : widget.maxLines, expands: widget.expands, style: style, - textAlignVertical: widget.textAlignVertical, + textAlignVertical: _verticalAlignment, decoration: material.InputDecoration( border: material.InputBorder.none, hintText: widget.hintText, @@ -221,6 +228,7 @@ class _QueryaCodeEditorState extends State { maxLines: widget.expands ? null : widget.maxLines, expands: widget.expands, style: style, + textAlignVertical: _verticalAlignment, placeholder: placeholder, onChanged: widget.onChanged, ); diff --git a/test/core/editor/querya_code_editor_alignment_test.dart b/test/core/editor/querya_code_editor_alignment_test.dart new file mode 100644 index 00000000..65cde133 --- /dev/null +++ b/test/core/editor/querya_code_editor_alignment_test.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart' as material; +import 'package:flutter/painting.dart' show TextPosition; +import 'package:flutter_test/flutter_test.dart'; +import 'package:querya_desktop/core/editor/querya_code_editor.dart'; +import 'package:querya_desktop/core/editor/querya_code_language.dart'; + +import '../../support/querya_theme_test_shell.dart'; + +void main() { + Future pump( + WidgetTester tester, { + QueryaCodeEditorVariant variant = QueryaCodeEditorVariant.shadcn, + material.TextAlignVertical? align, + }) async { + await tester.pumpWidget( + queryaThemeTestShell( + child: material.Center( + child: material.SizedBox( + width: 480, + height: 360, + child: QueryaCodeEditor( + language: QueryaCodeLanguage.plain, + variant: variant, + enableHighlighting: false, + textAlignVertical: align, + ), + ), + ), + ), + ); + await tester.pump(); + } + + Future textOffsetFromTop(WidgetTester tester) async { + await tester.enterText(find.byType(material.EditableText), 'select 1'); + await tester.pump(); + final field = tester.getRect(find.byType(QueryaCodeEditor)); + // The widget fills the field either way; the caret shows where the text is. + final render = tester + .state(find.byType(material.EditableText)) + .renderEditable; + final caret = render.getLocalRectForCaret(const TextPosition(offset: 0)); + return render.localToGlobal(caret.topLeft).dy - field.top; + } + + testWidgets('the shadcn editor starts its text at the top', (tester) async { + await pump(tester); + + expect(await textOffsetFromTop(tester), lessThan(60)); + }); + + testWidgets('the material editor starts its text at the top', + (tester) async { + await pump(tester, variant: QueryaCodeEditorVariant.material); + + expect(await textOffsetFromTop(tester), lessThan(60)); + }); + + testWidgets('an explicit alignment still wins', (tester) async { + await pump( + tester, + variant: QueryaCodeEditorVariant.material, + align: material.TextAlignVertical.center, + ); + + expect(await textOffsetFromTop(tester), greaterThan(100)); + }); +}