From c8bfd4b534fac77f3432d6c30813b832a9e5322f Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 11 Oct 2026 07:11:51 +0300 Subject: [PATCH 1/3] refactor(ui): QueryaIconButton, QueryaSearchField and QueryaTabStrip no longer import shadcn The colour scheme comes from QueryaTheme, gaps are SizedBoxes, the tab label is a plain Text with the same size and weight, and widgets types are taken from material. The three files leave the shadcn allow-list. Part of #1365. --- lib/shared/widgets/querya_icon_button.dart | 7 ++--- lib/shared/widgets/querya_search_field.dart | 11 ++++---- lib/shared/widgets/querya_tab_strip.dart | 28 +++++++++++++------ .../shared_does_not_import_shadcn_test.dart | 3 -- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/lib/shared/widgets/querya_icon_button.dart b/lib/shared/widgets/querya_icon_button.dart index 50f7f5e6..13fd6a32 100644 --- a/lib/shared/widgets/querya_icon_button.dart +++ b/lib/shared/widgets/querya_icon_button.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart' as material; -import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:querya_desktop/core/theme/querya_theme_scope.dart'; import 'package:querya_desktop/core/ui/querya_control_tokens.dart'; import 'package:querya_desktop/core/ui/querya_tooltip.dart'; @@ -90,7 +89,7 @@ class _QueryaIconButtonState extends material.State { final isDestructive = widget.isDestructive; final color = widget.color; final activeColor = widget.activeColor; - final cs = Theme.of(context).colorScheme; + final cs = context.queryaTheme.colorScheme; final workbench = QueryaThemeScope.maybeOf(context)?.workbench; final radius = widget.borderRadius ?? material.BorderRadius.circular(controlSize.scaledRadius(context)); @@ -236,7 +235,7 @@ class _QueryaToolbarButtonState extends material.State { QueryaControlSize.of(context); final isActive = widget.isActive; final isDestructive = widget.isDestructive; - final cs = Theme.of(context).colorScheme; + final cs = context.queryaTheme.colorScheme; final workbench = QueryaThemeScope.maybeOf(context)?.workbench; final isEnabled = onPressed != null; @@ -284,7 +283,7 @@ class _QueryaToolbarButtonState extends material.State { ), ), if (shortcutHint != null) ...[ - const Gap(6), + const material.SizedBox(width: 6), material.Container( padding: const material.EdgeInsets.symmetric(horizontal: 4, vertical: 1), decoration: material.BoxDecoration( diff --git a/lib/shared/widgets/querya_search_field.dart b/lib/shared/widgets/querya_search_field.dart index ad9e354c..ff81257f 100644 --- a/lib/shared/widgets/querya_search_field.dart +++ b/lib/shared/widgets/querya_search_field.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:flutter/material.dart' as material; import 'package:flutter/services.dart'; -import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:querya_desktop/core/theme/querya_theme_scope.dart'; import 'package:querya_desktop/core/ui/querya_control_tokens.dart'; @@ -33,10 +32,10 @@ class QueryaSearchField extends material.StatefulWidget { final String placeholder; /// Callback fired after debounce duration when input text changes. - final ValueChanged? onChanged; + final material.ValueChanged? onChanged; /// Callback fired immediately upon Enter / submit. - final ValueChanged? onSubmitted; + final material.ValueChanged? onSubmitted; /// Debounce delay. Set to [Duration.zero] for immediate invocation. final Duration debounceDuration; @@ -136,7 +135,7 @@ class _QueryaSearchFieldState extends material.State { @override material.Widget build(material.BuildContext context) { - final cs = Theme.of(context).colorScheme; + final cs = context.queryaTheme.colorScheme; final workbench = QueryaThemeScope.maybeOf(context)?.workbench; final controlSize = widget.size ?? QueryaControlSize.of(context); final fieldHeight = widget.height ?? controlSize.scaledHeight(context); @@ -171,9 +170,9 @@ class _QueryaSearchFieldState extends material.State { ), ), material.Expanded( - child: CallbackShortcuts( + child: material.CallbackShortcuts( bindings: { - const SingleActivator(LogicalKeyboardKey.escape): () { + const material.SingleActivator(LogicalKeyboardKey.escape): () { if (_hasText) { _clear(); } else { diff --git a/lib/shared/widgets/querya_tab_strip.dart b/lib/shared/widgets/querya_tab_strip.dart index 483f5eb7..2c4ed8b6 100644 --- a/lib/shared/widgets/querya_tab_strip.dart +++ b/lib/shared/widgets/querya_tab_strip.dart @@ -6,9 +6,9 @@ import 'package:querya_desktop/core/motion/querya_motion.dart'; import 'package:querya_desktop/core/motion/querya_motion_context.dart'; import 'package:querya_desktop/core/motion/querya_spring.dart'; import 'package:querya_desktop/core/motion/querya_spring_controller.dart'; +import 'package:querya_desktop/core/theme/querya_theme_scope.dart'; import 'package:querya_desktop/core/ui/querya_control_tokens.dart'; import 'package:querya_desktop/core/ui/querya_tooltip.dart'; -import 'package:shadcn_flutter/shadcn_flutter.dart'; /// A compact, keyboard-operable tab strip using Querya's motion and theme. /// @@ -254,7 +254,7 @@ class QueryaTabStripState extends material.State @override material.Widget build(material.BuildContext context) { - final colors = Theme.of(context).colorScheme; + final colors = context.queryaTheme.colorScheme; final controlSize = widget.size ?? (widget.dense ? QueryaControlSize.sm @@ -320,12 +320,22 @@ class QueryaTabStripState extends material.State children: [ // The tab's own node carries the label. material.ExcludeSemantics( - child: selected - ? Text(label).small().semiBold() - : Text(label).small().muted(), + child: material.Text( + label, + style: material.TextStyle( + fontSize: 14, + height: 20 / 14, + fontWeight: selected + ? material.FontWeight.w600 + : material.FontWeight.w400, + color: selected + ? colors.foreground + : colors.mutedForeground, + ), + ), ), if (showClose) ...[ - const Gap(2), + const material.SizedBox(width: 2), material.Tooltip( message: 'Close $label tab', waitDuration: kQueryaTooltipWait, @@ -376,7 +386,7 @@ class QueryaTabStripState extends material.State ); }), if (widget.onAdd != null) ...[ - const Gap(4), + const material.SizedBox(width: 4), material.MouseRegion( cursor: material.SystemMouseCursors.click, child: material.GestureDetector( @@ -463,8 +473,8 @@ class _TabStripIndicator extends material.StatelessWidget { @override material.Widget build(material.BuildContext context) { - return ListenableBuilder( - listenable: Listenable.merge([left, width]), + return material.ListenableBuilder( + listenable: material.Listenable.merge([left, width]), builder: (context, __) { final w = width.value; if (w <= 0) return const material.SizedBox.shrink(); diff --git a/test/guards/shared_does_not_import_shadcn_test.dart b/test/guards/shared_does_not_import_shadcn_test.dart index ba5afc60..703f87b3 100644 --- a/test/guards/shared_does_not_import_shadcn_test.dart +++ b/test/guards/shared_does_not_import_shadcn_test.dart @@ -20,11 +20,8 @@ void main() { 'lib/shared/widgets/querya_dialog_card.dart', 'lib/shared/widgets/querya_dropdown.dart', 'lib/shared/widgets/querya_empty_state.dart', - 'lib/shared/widgets/querya_icon_button.dart', 'lib/shared/widgets/querya_modal_dialog.dart', - 'lib/shared/widgets/querya_search_field.dart', 'lib/shared/widgets/querya_spinner.dart', - 'lib/shared/widgets/querya_tab_strip.dart', 'lib/shared/widgets/widgets.dart', }; From 84e49dd970ecf1d2ad230a8a4089d6d18b954d0f Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 11 Oct 2026 07:14:59 +0300 Subject: [PATCH 2/3] fix(ui): icon button gap is a SizedBox, not shadcn's Gap --- lib/shared/widgets/querya_icon_button.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/shared/widgets/querya_icon_button.dart b/lib/shared/widgets/querya_icon_button.dart index 13fd6a32..9ce98dee 100644 --- a/lib/shared/widgets/querya_icon_button.dart +++ b/lib/shared/widgets/querya_icon_button.dart @@ -272,7 +272,7 @@ class _QueryaToolbarButtonState extends material.State { ), child: icon, ), - Gap(controlSize.scaledIconGap(context)), + material.SizedBox(width: controlSize.scaledIconGap(context)), ], material.Text( label, From 2aabdfb75e0debb0282c68352a834d1965a09d19 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sun, 11 Oct 2026 07:28:03 +0300 Subject: [PATCH 3/3] fix(ui): read the colour scheme with context.colors, which needs no QueryaThemeScope Widgets in tests and dialogs can be built under the UI library's theme without a QueryaThemeScope; context.queryaTheme asserts there. context.colors is the same scheme the old code read. --- lib/shared/widgets/querya_icon_button.dart | 4 ++-- lib/shared/widgets/querya_search_field.dart | 2 +- lib/shared/widgets/querya_tab_strip.dart | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/shared/widgets/querya_icon_button.dart b/lib/shared/widgets/querya_icon_button.dart index 9ce98dee..d3dae8f6 100644 --- a/lib/shared/widgets/querya_icon_button.dart +++ b/lib/shared/widgets/querya_icon_button.dart @@ -89,7 +89,7 @@ class _QueryaIconButtonState extends material.State { final isDestructive = widget.isDestructive; final color = widget.color; final activeColor = widget.activeColor; - final cs = context.queryaTheme.colorScheme; + final cs = context.colors; final workbench = QueryaThemeScope.maybeOf(context)?.workbench; final radius = widget.borderRadius ?? material.BorderRadius.circular(controlSize.scaledRadius(context)); @@ -235,7 +235,7 @@ class _QueryaToolbarButtonState extends material.State { QueryaControlSize.of(context); final isActive = widget.isActive; final isDestructive = widget.isDestructive; - final cs = context.queryaTheme.colorScheme; + final cs = context.colors; final workbench = QueryaThemeScope.maybeOf(context)?.workbench; final isEnabled = onPressed != null; diff --git a/lib/shared/widgets/querya_search_field.dart b/lib/shared/widgets/querya_search_field.dart index ff81257f..90ac78ee 100644 --- a/lib/shared/widgets/querya_search_field.dart +++ b/lib/shared/widgets/querya_search_field.dart @@ -135,7 +135,7 @@ class _QueryaSearchFieldState extends material.State { @override material.Widget build(material.BuildContext context) { - final cs = context.queryaTheme.colorScheme; + final cs = context.colors; final workbench = QueryaThemeScope.maybeOf(context)?.workbench; final controlSize = widget.size ?? QueryaControlSize.of(context); final fieldHeight = widget.height ?? controlSize.scaledHeight(context); diff --git a/lib/shared/widgets/querya_tab_strip.dart b/lib/shared/widgets/querya_tab_strip.dart index 2c4ed8b6..71750b75 100644 --- a/lib/shared/widgets/querya_tab_strip.dart +++ b/lib/shared/widgets/querya_tab_strip.dart @@ -254,7 +254,7 @@ class QueryaTabStripState extends material.State @override material.Widget build(material.BuildContext context) { - final colors = context.queryaTheme.colorScheme; + final colors = context.colors; final controlSize = widget.size ?? (widget.dense ? QueryaControlSize.sm