From 59dad86ac9b18f690557aaf60bed62bdaaf4c8fb Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 18 Oct 2026 21:57:25 +0300 Subject: [PATCH] ui: the hand-built Material text fields move to QueryaTextField; a guard keeps material.TextField inside the kit (#1733) --- lib/core/editor/querya_code_editor.dart | 27 ++++++----- .../connections/connections_panel.dart | 32 +++---------- .../extensions/extension_table_view.dart | 8 +--- .../widgets/extension_sideload_dialog.dart | 9 ++-- .../mongodb/mongo_aggregation_workspace.dart | 29 ++++++------ .../mongodb/mongo_create_index_dialog.dart | 45 +++++-------------- .../redis/editors/redis_string_editor.dart | 23 +++++----- lib/features/redis/redis_keys_view.dart | 19 ++------ lib/features/settings/preferences_dialog.dart | 15 ++----- .../settings/theme_picker_button.dart | 42 ++--------------- .../settings/theme_remote_install_dialog.dart | 18 ++++---- .../workspace/data_grid_filter_bar.dart | 21 +++------ lib/features/workspace/grid_cell_editor.dart | 9 ++-- lib/shared/widgets/querya_text_field.dart | 26 ++++++++--- .../features/redis/redis_key_editor_test.dart | 6 +-- test/guards/shadcn_imports_ratchet_test.dart | 14 ++++++ 16 files changed, 123 insertions(+), 220 deletions(-) diff --git a/lib/core/editor/querya_code_editor.dart b/lib/core/editor/querya_code_editor.dart index ec6632ca..fe71993e 100644 --- a/lib/core/editor/querya_code_editor.dart +++ b/lib/core/editor/querya_code_editor.dart @@ -252,20 +252,19 @@ class _QueryaCodeEditorState extends State { final controller = _effectiveController; if (widget.variant == QueryaCodeEditorVariant.material) { - return material.TextField( - controller: controller, - focusNode: widget.focusNode, - autofocus: widget.autofocus, - readOnly: widget.readOnly, - maxLines: widget.expands ? null : widget.maxLines, - expands: widget.expands, - style: style, - textAlignVertical: _verticalAlignment, - decoration: material.InputDecoration( - border: material.InputBorder.none, - hintText: widget.hintText, - contentPadding: - widget.contentPadding ?? const material.EdgeInsets.all(12), + return material.Padding( + padding: widget.contentPadding ?? const material.EdgeInsets.all(12), + child: QueryaTextField( + framed: false, + controller: controller, + focusNode: widget.focusNode, + autofocus: widget.autofocus, + readOnly: widget.readOnly, + maxLines: widget.expands ? null : widget.maxLines, + expands: widget.expands, + style: style, + textAlignVertical: _verticalAlignment, + placeholder: widget.hintText, ), ); } diff --git a/lib/features/connections/connections_panel.dart b/lib/features/connections/connections_panel.dart index 29a8298b..376f9ee9 100644 --- a/lib/features/connections/connections_panel.dart +++ b/lib/features/connections/connections_panel.dart @@ -58,9 +58,6 @@ import 'package:flutter/material.dart' as material ClampingScrollPhysics, CallbackShortcuts, SingleActivator, - TextField, - InputDecoration, - InputBorder, TextEditingController, FocusNode; import 'package:flutter/services.dart' @@ -255,23 +252,15 @@ class TreeObjectFilterBar extends material.StatelessWidget { ), const Gap(5), material.Expanded( - child: material.TextField( + child: QueryaTextField( + framed: false, controller: controller, onChanged: onChanged, style: material.TextStyle( fontSize: 11, color: colors.foreground, ), - decoration: material.InputDecoration( - hintText: hintText, - hintStyle: material.TextStyle( - fontSize: 11, - color: colors.mutedForeground.withValues(alpha: 0.6), - ), - border: material.InputBorder.none, - isDense: true, - contentPadding: material.EdgeInsets.zero, - ), + placeholder: hintText, ), ), if (isFiltered) ...[ @@ -1228,7 +1217,8 @@ class ConnectionsPanelState extends State { ), const Gap(6), material.Expanded( - child: material.TextField( + child: QueryaTextField( + framed: false, controller: _searchController, focusNode: _searchFocusNode, onChanged: (val) => _searchDebouncer.run(() { @@ -1238,17 +1228,7 @@ class ConnectionsPanelState extends State { fontSize: 12, color: colors.foreground, ), - decoration: material.InputDecoration( - hintText: 'Filter connections... (Ctrl+F)', - hintStyle: material.TextStyle( - fontSize: 12, - color: colors.mutedForeground - .withValues(alpha: 0.6), - ), - border: material.InputBorder.none, - isDense: true, - contentPadding: material.EdgeInsets.zero, - ), + placeholder: 'Filter connections… (Ctrl+F)', ), ), material.ValueListenableBuilder( diff --git a/lib/features/extensions/extension_table_view.dart b/lib/features/extensions/extension_table_view.dart index c9ee04d4..cc6f1ee7 100644 --- a/lib/features/extensions/extension_table_view.dart +++ b/lib/features/extensions/extension_table_view.dart @@ -496,13 +496,9 @@ class _ExtensionTableViewState extends material.State { const material.Text('WHERE ').semiBold().small(), const Gap(8), material.Expanded( - child: material.TextField( + child: QueryaTextField( controller: _filterController, - decoration: const material.InputDecoration( - hintText: "e.g. id > 100 AND status = 'active'", - isDense: true, - border: material.OutlineInputBorder(), - ), + placeholder: "e.g. id > 100 AND status = 'active'", onSubmitted: (_) { final st = _genericKey.currentState; if (st != null) _applyFilter(st); diff --git a/lib/features/extensions/presentation/widgets/extension_sideload_dialog.dart b/lib/features/extensions/presentation/widgets/extension_sideload_dialog.dart index e2b30b7d..b2112cb3 100644 --- a/lib/features/extensions/presentation/widgets/extension_sideload_dialog.dart +++ b/lib/features/extensions/presentation/widgets/extension_sideload_dialog.dart @@ -103,12 +103,11 @@ class _ExtensionSideloadDialogState ), ), const material.SizedBox(height: 12), - material.TextField( + const Text('SHA-256 checksum (optional)').small().semiBold(), + const Gap(6), + QueryaTextField( controller: _checksumController, - decoration: const material.InputDecoration( - labelText: 'SHA-256 checksum (optional)', - hintText: '64-character hex digest from publisher', - ), + placeholder: '64-character hex digest from publisher', autocorrect: false, ), ], diff --git a/lib/features/mongodb/mongo_aggregation_workspace.dart b/lib/features/mongodb/mongo_aggregation_workspace.dart index ae9f5ed9..ffbdbd4f 100644 --- a/lib/features/mongodb/mongo_aggregation_workspace.dart +++ b/lib/features/mongodb/mongo_aggregation_workspace.dart @@ -649,22 +649,21 @@ class _StageCardState extends material.State<_StageCard> { borderRadius: material.BorderRadius.circular(6), color: cs.background, ), - child: material.TextField( - controller: _textController, - maxLines: null, - minLines: 3, - style: const material.TextStyle( - fontFamily: QueryaTypography.mono, - fontFamilyFallback: QueryaTypography.monoFontFamilyFallback, - fontSize: 12.5, - height: 1.4, - ), - decoration: const material.InputDecoration( - isDense: true, - border: material.InputBorder.none, - contentPadding: material.EdgeInsets.all(10), + child: material.Padding( + padding: const material.EdgeInsets.all(10), + child: QueryaTextField( + framed: false, + controller: _textController, + maxLines: null, + minLines: 3, + style: const material.TextStyle( + fontFamily: QueryaTypography.mono, + fontFamilyFallback: QueryaTypography.monoFontFamilyFallback, + fontSize: 12.5, + height: 1.4, + ), + onChanged: widget.onQueryChanged, ), - onChanged: widget.onQueryChanged, ), ), if (syntaxError != null) ...[ diff --git a/lib/features/mongodb/mongo_create_index_dialog.dart b/lib/features/mongodb/mongo_create_index_dialog.dart index 582f22a7..41f95419 100644 --- a/lib/features/mongodb/mongo_create_index_dialog.dart +++ b/lib/features/mongodb/mongo_create_index_dialog.dart @@ -226,18 +226,9 @@ class _MongoCreateIndexDialogState children: [ material.Expanded( flex: 3, - child: material.TextField( + child: QueryaTextField( controller: _fields[i].controller, - decoration: const material.InputDecoration( - hintText: 'Field name (e.g. email)', - isDense: true, - border: material.OutlineInputBorder(), - contentPadding: material.EdgeInsets.symmetric( - horizontal: 10, - vertical: 8, - ), - ), - style: const material.TextStyle(fontSize: 13), + placeholder: 'Field name (e.g. email)', onChanged: (_) => setState(() {}), ), ), @@ -337,36 +328,20 @@ class _MongoCreateIndexDialogState ), const Gap(8), // TTL - material.TextField( + const Text('TTL: expire after seconds (optional)').small().semiBold(), + const Gap(6), + QueryaTextField( controller: _ttlController, keyboardType: material.TextInputType.number, - decoration: const material.InputDecoration( - labelText: 'TTL: Expire After Seconds (optional)', - hintText: 'e.g. 86400 (24 hours)', - isDense: true, - border: material.OutlineInputBorder(), - contentPadding: material.EdgeInsets.symmetric( - horizontal: 10, - vertical: 8, - ), - ), - style: const material.TextStyle(fontSize: 13), + placeholder: 'e.g. 86400 (24 hours)', ), const Gap(12), // Index Name - material.TextField( + const Text('Index name (optional)').small().semiBold(), + const Gap(6), + QueryaTextField( controller: _nameController, - decoration: material.InputDecoration( - labelText: 'Index Name (optional)', - hintText: _computedIndexName(), - isDense: true, - border: const material.OutlineInputBorder(), - contentPadding: const material.EdgeInsets.symmetric( - horizontal: 10, - vertical: 8, - ), - ), - style: const material.TextStyle(fontSize: 13), + placeholder: _computedIndexName(), ), ], ), diff --git a/lib/features/redis/editors/redis_string_editor.dart b/lib/features/redis/editors/redis_string_editor.dart index dcd5058b..71454529 100644 --- a/lib/features/redis/editors/redis_string_editor.dart +++ b/lib/features/redis/editors/redis_string_editor.dart @@ -86,18 +86,17 @@ class RedisStringEditor extends material.StatelessWidget { color: colors.border.withValues(alpha: 0.3)), borderRadius: material.BorderRadius.circular(8), ), - child: material.TextField( - controller: controller, - readOnly: isReadOnly, - maxLines: null, - style: const material.TextStyle( - fontSize: 13, - fontFamily: QueryaTypography.mono, - fontFamilyFallback: QueryaTypography.monoFontFamilyFallback, - ), - decoration: const material.InputDecoration( - border: material.InputBorder.none, - contentPadding: material.EdgeInsets.all(12), + child: material.Padding( + padding: const material.EdgeInsets.all(12), + child: QueryaTextField( + framed: false, + controller: controller, + readOnly: isReadOnly, + maxLines: null, + style: const material.TextStyle( + fontFamily: QueryaTypography.mono, + fontFamilyFallback: QueryaTypography.monoFontFamilyFallback, + ), ), ), ), diff --git a/lib/features/redis/redis_keys_view.dart b/lib/features/redis/redis_keys_view.dart index 043ed6c8..9d528ad9 100644 --- a/lib/features/redis/redis_keys_view.dart +++ b/lib/features/redis/redis_keys_view.dart @@ -537,29 +537,16 @@ class _RedisKeysViewState extends material.State { material.SizedBox( width: 36, height: 28, - child: material.TextField( + child: QueryaTextField( controller: _delimiterController, + size: QueryaControlSize.sm, textAlign: material.TextAlign.center, + contentPadding: material.EdgeInsets.zero, style: const material.TextStyle( - fontSize: 13, fontFamily: QueryaTypography.mono, fontFamilyFallback: QueryaTypography.monoFontFamilyFallback, ), - decoration: material.InputDecoration( - contentPadding: material.EdgeInsets.zero, - isDense: true, - border: material.OutlineInputBorder( - borderRadius: material.BorderRadius.circular(6), - borderSide: material.BorderSide( - color: cs.border.withValues(alpha: 0.4), - ), - ), - focusedBorder: material.OutlineInputBorder( - borderRadius: material.BorderRadius.circular(6), - borderSide: material.BorderSide(color: cs.primary), - ), - ), onChanged: (_) => setState(() {}), ), ), diff --git a/lib/features/settings/preferences_dialog.dart b/lib/features/settings/preferences_dialog.dart index 25622a80..2e742183 100644 --- a/lib/features/settings/preferences_dialog.dart +++ b/lib/features/settings/preferences_dialog.dart @@ -308,7 +308,8 @@ class PreferencesDialogContentState ), const Gap(8), material.Expanded( - child: material.TextField( + child: QueryaTextField( + framed: false, controller: _searchController, focusNode: _searchFocusNode, onChanged: (val) { @@ -333,17 +334,7 @@ class PreferencesDialogContentState fontSize: 12, color: theme.foreground, ), - decoration: material.InputDecoration( - hintText: 'Filter preferences... (Ctrl+F)', - hintStyle: material.TextStyle( - fontSize: 12, - color: theme.mutedForeground - .withValues(alpha: 0.6), - ), - border: material.InputBorder.none, - isDense: true, - contentPadding: material.EdgeInsets.zero, - ), + placeholder: 'Filter preferences… (Ctrl+F)', ), ), if (_searchQuery.isNotEmpty) diff --git a/lib/features/settings/theme_picker_button.dart b/lib/features/settings/theme_picker_button.dart index 15e0d0ec..1d63fe9f 100644 --- a/lib/features/settings/theme_picker_button.dart +++ b/lib/features/settings/theme_picker_button.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/material.dart' as material; +import 'package:querya_desktop/shared/widgets/querya_text_field.dart'; import 'package:querya_desktop/core/theme/querya_theme_scope.dart'; import 'package:querya_desktop/core/theme/querya_ui_colors.dart'; import 'package:querya_desktop/core/layout/ui_scale.dart'; @@ -300,7 +301,6 @@ class _ThemePickerButtonState extends material.State { material.Widget _buildMenuPanel( material.BuildContext context, QueryaUiColors cs) { final filteredThemes = _filteredThemes; - final radius = context.scaled(QueryaDropdownTokens.menuBorderRadius); return material.Column( children: [ @@ -311,44 +311,10 @@ class _ThemePickerButtonState extends material.State { context.scaled(8), context.scaled(4), ), - child: material.TextField( + child: QueryaTextField( controller: _searchController, - style: material.TextStyle( - fontSize: context.scaled(QueryaDropdownTokens.fontSize), - color: cs.popoverForeground, - ), - decoration: material.InputDecoration( - isDense: true, - hintText: 'Search themes…', - hintStyle: material.TextStyle(color: cs.mutedForeground), - prefixIcon: material.Icon( - material.Icons.search, - size: context.scaled(18), - color: cs.mutedForeground, - ), - prefixIconConstraints: material.BoxConstraints( - minWidth: context.scaled(36), - minHeight: context.scaled(32), - ), - contentPadding: material.EdgeInsets.symmetric( - horizontal: context.scaled(8), - vertical: context.scaled(8), - ), - filled: true, - fillColor: cs.muted.withValues(alpha: 0.18), - border: material.OutlineInputBorder( - borderRadius: material.BorderRadius.circular(radius), - borderSide: material.BorderSide(color: cs.border), - ), - enabledBorder: material.OutlineInputBorder( - borderRadius: material.BorderRadius.circular(radius), - borderSide: material.BorderSide(color: cs.border), - ), - focusedBorder: material.OutlineInputBorder( - borderRadius: material.BorderRadius.circular(radius), - borderSide: material.BorderSide(color: cs.ring), - ), - ), + placeholder: 'Search themes…', + leading: const material.Icon(material.Icons.search), ), ), if (widget.onPreviewTheme != null) diff --git a/lib/features/settings/theme_remote_install_dialog.dart b/lib/features/settings/theme_remote_install_dialog.dart index b513b551..3cf927d8 100644 --- a/lib/features/settings/theme_remote_install_dialog.dart +++ b/lib/features/settings/theme_remote_install_dialog.dart @@ -97,23 +97,21 @@ class _ThemeRemoteInstallDialogState ), ], const material.SizedBox(height: 12), - material.TextField( + const Text('Theme URL').small().semiBold(), + const Gap(6), + QueryaTextField( controller: _urlController, - decoration: const material.InputDecoration( - labelText: 'Theme URL', - hintText: 'https://example.com/themes/my-theme.json', - ), + placeholder: 'https://example.com/themes/my-theme.json', keyboardType: material.TextInputType.url, autocorrect: false, onChanged: (_) => setState(() => _validationError = null), ), const material.SizedBox(height: 12), - material.TextField( + const Text('SHA-256 checksum (optional)').small().semiBold(), + const Gap(6), + QueryaTextField( controller: _checksumController, - decoration: const material.InputDecoration( - labelText: 'SHA-256 checksum (optional)', - hintText: 'hex digest or ?sha256= on URL', - ), + placeholder: 'hex digest or ?sha256= on URL', autocorrect: false, ), if (_validationError != null) ...[ diff --git a/lib/features/workspace/data_grid_filter_bar.dart b/lib/features/workspace/data_grid_filter_bar.dart index fe299020..efbf135a 100644 --- a/lib/features/workspace/data_grid_filter_bar.dart +++ b/lib/features/workspace/data_grid_filter_bar.dart @@ -1,6 +1,7 @@ import 'dart:async' show Timer; import 'package:flutter/material.dart' as material; import 'package:flutter/services.dart' show KeyDownEvent, LogicalKeyboardKey; +import 'package:querya_desktop/shared/widgets/querya_text_field.dart'; import 'package:querya_desktop/core/theme/querya_theme_scope.dart'; import 'package:querya_desktop/core/theme/querya_ui_colors.dart'; import 'package:querya_desktop/core/ui/querya_control_tokens.dart'; @@ -385,26 +386,16 @@ class _DataGridFilterBarState extends material.State { } return material.KeyEventResult.ignored; }, - child: material.TextField( + child: QueryaTextField( + framed: false, controller: _controller, focusNode: _focusNode, autofocus: true, onChanged: _onChanged, onSubmitted: _onSubmitted, - style: TextStyle( - fontSize: 12, - color: cs.foreground, - ), - decoration: material.InputDecoration( - hintText: 'Filter results... (e.g. "active", "status = ACTIVE", "amount > 100")', - hintStyle: TextStyle( - fontSize: 12, - color: cs.mutedForeground.withValues(alpha: 0.7), - ), - border: material.InputBorder.none, - isDense: true, - contentPadding: material.EdgeInsets.zero, - ), + style: const TextStyle(fontSize: 12), + placeholder: + 'Filter results… (e.g. "active", "status = ACTIVE", "amount > 100")', ), ), ), diff --git a/lib/features/workspace/grid_cell_editor.dart b/lib/features/workspace/grid_cell_editor.dart index 7b55a26f..70f5163f 100644 --- a/lib/features/workspace/grid_cell_editor.dart +++ b/lib/features/workspace/grid_cell_editor.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart' as material; import 'package:flutter/services.dart'; +import 'package:querya_desktop/shared/widgets/querya_text_field.dart'; import 'package:querya_desktop/core/theme/querya_theme_scope.dart'; import 'package:querya_desktop/core/motion/querya_motion.dart'; import 'package:querya_desktop/core/motion/querya_motion_context.dart'; @@ -183,7 +184,8 @@ class _GridCellEditorState extends material.State { focusNode: _focusNode, onKeyEvent: _handleKeyEvent, autofocus: true, - child: material.TextField( + child: QueryaTextField( + framed: false, controller: _controller, autofocus: true, maxLines: 1, @@ -192,11 +194,6 @@ class _GridCellEditorState extends material.State { fontFamily: 'monospace', fontFamilyFallback: QueryaTypography.cjkFontFamilyFallback, ), - decoration: const material.InputDecoration( - border: material.InputBorder.none, - isDense: true, - contentPadding: material.EdgeInsets.zero, - ), onSubmitted: (value) { _commit(value, moveNextRow: true); }, diff --git a/lib/shared/widgets/querya_text_field.dart b/lib/shared/widgets/querya_text_field.dart index 43a6d50a..bf0a3515 100644 --- a/lib/shared/widgets/querya_text_field.dart +++ b/lib/shared/widgets/querya_text_field.dart @@ -40,6 +40,9 @@ class QueryaTextField extends material.StatefulWidget { this.style, this.textAlignVertical, this.framed = true, + this.textAlign = material.TextAlign.start, + this.autocorrect = true, + this.contentPadding, }); final material.TextEditingController? controller; @@ -79,6 +82,11 @@ class QueryaTextField extends material.StatefulWidget { /// False for a field inside a frame of its own (an editor card): no fill, /// border or padding. final bool framed; + final material.TextAlign textAlign; + final bool autocorrect; + + /// Replaces the padding between the border and the text. + final material.EdgeInsetsGeometry? contentPadding; @override material.State createState() => _QueryaTextFieldState(); @@ -161,6 +169,8 @@ class _QueryaTextFieldState extends material.State { enabled: widget.enabled, readOnly: widget.readOnly, obscureText: widget.obscureText && !_revealed, + autocorrect: widget.autocorrect, + textAlign: widget.textAlign, maxLines: widget.expands ? null : (widget.obscureText ? 1 : widget.maxLines), minLines: widget.expands ? null : widget.minLines, expands: widget.expands, @@ -178,19 +188,21 @@ class _QueryaTextFieldState extends material.State { cursorColor: cs.primary, decoration: material.InputDecoration( hintText: widget.placeholder, - hintStyle: material.TextStyle(fontSize: fontSize, color: muted), + hintStyle: material.TextStyle( + fontSize: widget.style?.fontSize ?? fontSize, color: muted), isDense: true, border: material.InputBorder.none, enabledBorder: material.InputBorder.none, focusedBorder: material.InputBorder.none, disabledBorder: material.InputBorder.none, errorBorder: material.InputBorder.none, - contentPadding: widget.framed - ? material.EdgeInsets.symmetric( - vertical: _multiline ? 8 : 0, - horizontal: widget.leading == null ? 10 : 0, - ) - : material.EdgeInsets.zero, + contentPadding: widget.contentPadding ?? + (widget.framed + ? material.EdgeInsets.symmetric( + vertical: _multiline ? 8 : 0, + horizontal: widget.leading == null ? 10 : 0, + ) + : material.EdgeInsets.zero), ), ); diff --git a/test/features/redis/redis_key_editor_test.dart b/test/features/redis/redis_key_editor_test.dart index 137e6440..dbad505c 100644 --- a/test/features/redis/redis_key_editor_test.dart +++ b/test/features/redis/redis_key_editor_test.dart @@ -297,7 +297,7 @@ void main() { expect(find.text('Rename Key'), findsOneWidget); // Enter new key name - final textField = find.byType(QueryaTextField); + final textField = find.byType(QueryaTextField).last; // the dialog, over the editor await tester.enterText(textField, 'session:renamed'); await tester.pumpAndSettle(); @@ -332,7 +332,7 @@ void main() { await tester.tap(find.byTooltip('Rename key')); await tester.pumpAndSettle(); - final textField = find.byType(QueryaTextField); + final textField = find.byType(QueryaTextField).last; // the dialog, over the editor await tester.enterText(textField, 'session:exists'); await tester.pumpAndSettle(); @@ -353,7 +353,7 @@ void main() { await tester.tap(find.byTooltip('Rename key')); await tester.pumpAndSettle(); - await tester.enterText(find.byType(QueryaTextField), 'session:exists'); + await tester.enterText(find.byType(QueryaTextField).last, 'session:exists'); await tester.pumpAndSettle(); await tester.tap(find.text('Rename')); diff --git a/test/guards/shadcn_imports_ratchet_test.dart b/test/guards/shadcn_imports_ratchet_test.dart index f9b3fdc0..2c5700d5 100644 --- a/test/guards/shadcn_imports_ratchet_test.dart +++ b/test/guards/shadcn_imports_ratchet_test.dart @@ -84,4 +84,18 @@ void main() { expect(offenders, isEmpty, reason: 'Use QueryaTextField (the barrel hides shadcn TextField).'); }); + + test('no hand-built material TextField outside the kit (#1733)', () { + const kit = { + 'lib/shared/widgets/querya_text_field.dart', + 'lib/shared/widgets/querya_search_field.dart', + }; + final offenders = [ + for (final MapEntry(:key, :value) in sources().entries) + if (!kit.contains(key) && value.contains('material.TextField(')) + key, + ]; + expect(offenders, isEmpty, + reason: 'Use QueryaTextField (framed: false inside a frame of your own).'); + }); }