fix(client): 修聚焦时输入框橙边漏出错位/被裁(登录·注册·搜索·兑换码)
ci-pangolin / Lint — shellcheck (push) Successful in 10s
ci-pangolin / OpenAPI Sync Check (push) Successful in 31s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 5s
ci-pangolin / Flutter — analyze + test (push) Successful in 24s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 6s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 4s
ci-pangolin / Go — build + test (push) Successful in 10s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 18s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Successful in 4m13s
ci-pangolin / Golden — 视觉回归 (components + auth) (push) Successful in 14s

主题 inputDecorationTheme 设了 focusedBorder: OutlineInputBorder(accent),
而登录/注册的邮箱·密码·验证码、节点页搜索框、兑换码框这几处的 TextField
只写 border: InputBorder.none、未覆盖 focusedBorder —— 聚焦瞬间主题的橙色
OutlineInputBorder 漏到内层 TextField 上,与外层自定义容器圆角错位/左右被裁。

统一加共享 kBareInput 装饰(pangolin_theme.dart)关掉所有边框状态泄漏,
四处替换。只压边框、不动 filled/fillColor —— 未聚焦态外观与改前一致,
不动 golden;聚焦指示仍由外层容器自己的 Border.all(accent) 负责。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-28 22:21:50 +08:00
parent 1adf088c68
commit 25e8330e3b
4 changed files with 29 additions and 5 deletions
+21
View File
@@ -24,6 +24,27 @@ import 'package:google_fonts/google_fonts.dart';
import 'pangolin_tokens.gen.dart';
export 'pangolin_tokens.gen.dart';
/// 自定义容器(自带圆角/边框/聚焦态)里嵌 [TextField] 时用此装饰:
/// 彻底关掉主题 [inputDecorationTheme] 的边框/填充泄漏。
///
/// 坑:主题里设了 `focusedBorder: OutlineInputBorder(accent)` + `filled:true`。
/// 字段只写 `border: InputBorder.none` **不覆盖 focusedBorder** 时,聚焦瞬间主题的
/// 橙色 OutlineInputBorder + 填充会画到内层 TextField 上,与外层容器圆角错位/被裁
/// (登录/注册的邮箱·密码·验证码、节点页搜索框聚焦时左右各缺一截即此因)。
/// 聚焦指示交给外层容器自己负责(如 [Border.all(accent)])。
///
/// 注意:只压边框、不动 `filled`/`fillColor`——未聚焦态外观与改前完全一致(不动 golden),
/// 漏出的橙框只来自 `focusedBorder`(未聚焦态早已解析为无边框)。
const InputDecoration kBareInput = InputDecoration(
isCollapsed: true,
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
disabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
focusedErrorBorder: InputBorder.none,
);
/// ── Semantic tokens, resolved per brightness ───────────────────────
@immutable
class PangolinScheme extends ThemeExtension<PangolinScheme> {
+3 -3
View File
@@ -165,10 +165,10 @@ class _SearchBox extends StatelessWidget {
child: TextField(
onChanged: onChanged,
style: PangolinText.sm.copyWith(color: c.fg1, fontSize: 15),
decoration: InputDecoration(
isCollapsed: true,
// kBareInput 关掉主题 inputDecorationTheme 的边框/填充泄漏(否则聚焦时
// 橙色 OutlineInputBorder 会画到内层 TextField 上、与搜索框圆角错位/被裁)。
decoration: kBareInput.copyWith(
contentPadding: const EdgeInsets.symmetric(vertical: 12),
border: InputBorder.none,
hintText: hint,
hintStyle: PangolinText.sm.copyWith(color: c.fg3, fontSize: 15),
),
+2 -1
View File
@@ -260,7 +260,8 @@ class _RedeemScreenState extends ConsumerState<RedeemScreen> {
controller: _code,
textCapitalization: TextCapitalization.characters,
style: PangolinText.mono.copyWith(color: c.fg1, letterSpacing: 1.5),
decoration: InputDecoration(border: InputBorder.none, isCollapsed: true, contentPadding: const EdgeInsets.symmetric(vertical: 13), hintText: t.redeemPh, hintStyle: PangolinText.sm.copyWith(color: c.fg3)),
// kBareInput 关掉主题边框/填充泄漏(聚焦时橙框错位/被裁),聚焦态交给外层 Border。
decoration: kBareInput.copyWith(contentPadding: const EdgeInsets.symmetric(vertical: 13), hintText: t.redeemPh, hintStyle: PangolinText.sm.copyWith(color: c.fg3)),
onChanged: (_) => setState(() {}),
),
)),
+3 -1
View File
@@ -329,8 +329,10 @@ class _AuthScreenState extends ConsumerState<AuthScreen>
]);
}
// kBareInput 关掉主题 inputDecorationTheme 的边框/填充泄漏(否则聚焦时橙色
// OutlineInputBorder 会画到内层 TextField 上、与外层容器错位/被裁)。
InputDecoration get _bare =>
const InputDecoration(border: InputBorder.none, isCollapsed: true, contentPadding: EdgeInsets.symmetric(vertical: 13));
kBareInput.copyWith(contentPadding: const EdgeInsets.symmetric(vertical: 13));
// 密码输入 + 显示/隐藏切换(眼睛按钮)。
Widget _pwInput(PangolinScheme c, String hint) => Row(children: [