diff --git a/crates/app-iced/src/components/interaction/disabled.rs b/crates/app-iced/src/components/interaction/disabled.rs index 4106c63..3aa52c6 100644 --- a/crates/app-iced/src/components/interaction/disabled.rs +++ b/crates/app-iced/src/components/interaction/disabled.rs @@ -17,6 +17,11 @@ //! ⚠️ TextField 的 **Filled 容器**不在这两族里:官方 //! `FilledTextFieldTokens.FieldDisabledContainerOpacity = 0.04f`,我们仍在用面状族的值 //! (既有 D10 偏离,未在本轮收口)。`inputs::field` 走 [`disabled_colors`] 的口径,行为未变。 +//! +//! ⚠️ **filled-tonal 是另一条已知偏离**:官方 `ButtonDefaults.getDefaultFilledTonalButtonColors` +//! 里硬编码 `ldc_w 0.12f`(`FilledTonalButtonTokens` 没有 `DisabledContainerOpacity` 字段), +//! 而本模块的 `disabled_button_*` **不区分变体**,tonal 与 filled 共用 0.10 ⇒ tonal 实际画 10%。 +//! 这不是对齐、是登记过的偏离;要修得让入口知道变体,本轮(M86)不做。 use iced::Color; @@ -171,30 +176,40 @@ mod tests { /// **面状控件族**的那一对颜色 = 0.12 预混合(chip / switch / slider / TextField 描边)。 /// - /// `disabled_colors` 的名字是历史遗留,语义是这一族。谁把 12% 改成 10%,这条红。 + /// ⚠️ 期望值**写死 0.12 / 0.38**,不从 `DISABLED_SURFACE_ALPHA` 取: + /// 从被测常量求期望是**自指断言**——常量一改,expected 跟着改,永远相等(复审 r1 P2-1 实测: + /// 把 `DISABLED_SURFACE_ALPHA` 改成 0.10,旧版这条照样绿)。现在常量改坏必红。 #[test] fn surface_family_disabled_colors_are_the_12_percent_class() { + const EXPECTED_SURFACE_ALPHA: f32 = 0.12; + const EXPECTED_CONTENT_ALPHA: f32 = 0.38; + let actual_alpha = DISABLED_SURFACE_ALPHA; + assert_eq!( + actual_alpha, EXPECTED_SURFACE_ALPHA, + "面状控件族 α 必须是官方 0.12f;改常量会让下面每一条合成色断言同时红" + ); + for flavor in [SchemeFlavor::Light, SchemeFlavor::Dark] { let ui = ui(flavor); let scheme = Scheme::baseline(flavor); let base = scheme.get(Role::Surface); let expected_container = scheme .get(Role::OnSurface) - .with_alpha(DISABLED_SURFACE_ALPHA) + .with_alpha(EXPECTED_SURFACE_ALPHA) .over(base); let (surface, surface_content) = disabled_colors(&ui, Role::Surface); assert_eq!( surface, to_iced(expected_container), - "{flavor:?}:面状控件容器 = on-surface@12% 叠表面" + "{flavor:?}:面状控件容器 = on-surface@12% 叠表面(期望值硬编码,不取自常量)" ); assert_eq!( surface_content, to_iced( scheme .get(Role::OnSurfaceVariant) - .with_alpha(DISABLED_CONTENT_ALPHA) + .with_alpha(EXPECTED_CONTENT_ALPHA) .over(expected_container) ), "{flavor:?}:面状控件内容仍是 38%,只是叠的底不同" @@ -208,27 +223,40 @@ mod tests { to_iced( scheme .get(Role::OnSurfaceVariant) - .with_alpha(DISABLED_CONTENT_ALPHA) + .with_alpha(EXPECTED_CONTENT_ALPHA) .over(base) ), "{flavor:?}:内容必须叠在容器上" ); + // 跨族对照:面状族的合成色必须与按钮族不同(两族一旦合流,这条红) + let (button, _) = disabled_button_colors(&ui, Role::Surface); + assert_ne!( + surface, button, + "{flavor:?}:面状族 12% 与按钮族 10% 必须落在不同像素值上" + ); } } /// **按钮家族**的那一对颜色 = 0.10 预混合,且与面状控件族**必须落在不同像素值上**。 /// - /// 这条是「拆族真的发生了」的判据:把 `disabled_button_colors` 改回 0.12,它在 - /// `expected` 与 `assert_ne!` 上同时红;两个入口合并回一个常量,也只有它红。 + /// 期望值同样写死(0.10 / 0.38),理由见上一条:自指断言抓不住常量被改坏。 #[test] fn button_family_disabled_colors_are_the_10_percent_class() { + const EXPECTED_BUTTON_ALPHA: f32 = 0.10; + const EXPECTED_CONTENT_ALPHA: f32 = 0.38; + let actual_alpha = DISABLED_CONTAINER_ALPHA; + assert_eq!( + actual_alpha, EXPECTED_BUTTON_ALPHA, + "按钮族 α 必须是官方 0.1f(*ButtonTokens.DisabledContainerOpacity)" + ); + for flavor in [SchemeFlavor::Light, SchemeFlavor::Dark] { let ui = ui(flavor); let scheme = Scheme::baseline(flavor); let base = scheme.get(Role::Surface); let expected_container = scheme .get(Role::OnSurface) - .with_alpha(DISABLED_CONTAINER_ALPHA) + .with_alpha(EXPECTED_BUTTON_ALPHA) .over(base); let (button, button_content) = disabled_button_colors(&ui, Role::Surface); @@ -242,7 +270,7 @@ mod tests { to_iced( scheme .get(Role::OnSurfaceVariant) - .with_alpha(DISABLED_CONTENT_ALPHA) + .with_alpha(EXPECTED_CONTENT_ALPHA) .over(expected_container) ), ); diff --git a/crates/design/src/color/state.rs b/crates/design/src/color/state.rs index 9b99724..8130105 100644 --- a/crates/design/src/color/state.rs +++ b/crates/design/src/color/state.rs @@ -45,12 +45,23 @@ impl StateLayer { /// ⚠️ 官方禁用 α 分**两类**,这个常量只属于第一类: /// - **按钮容器 10%**:`BaselineButtonTokens` / `FilledButtonTokens` / `OutlinedButtonTokens` / /// `TextButtonTokens` / `ElevatedButtonTokens` / `TonalButtonTokens` 的 `DisabledContainerOpacity` -/// = `0.1f`(AAR 字节码); +/// = `0.1f`(AAR 字节码 ``); /// - **面状控件(chip 容器/描边、slider 轨道、switch 轨道)12%**:那是另一类令牌 /// (`AssistChipTokens.FlatDisabledOutlineOpacity` / `SliderTokens.DisabledInactiveTrackOpacity` / /// `SwitchTokens.DisabledTrackOpacity` = `0.12f`),口径在 /// `unlucky_app_iced::components::interaction::disabled_colors`。 /// +/// ## ⚠️ 已知偏离:filled-tonal 的禁用容器**官方是 0.12f,我们走 0.10** +/// +/// 上面那行把 `TonalButtonTokens` 列进 0.1f 家族**只陈述它 `` 里写的 token 值**, +/// 不代表 tonal 的运行时行为是 10%:官方 `ButtonDefaults.getDefaultFilledTonalButtonColors` +/// 里**硬编码** `ldc_w 0.12f`(`FilledTonalButtonTokens` 根本没有 `DisabledContainerOpacity` 字段)。 +/// 我们的实现在 tonal 与 filled 之间**没有区分**,两者共用本常量 ⇒ **tonal 实际画的是 10%**。 +/// +/// 这是**已登记的偏离,不是对齐**:将来若要修,需要按变体分派 α(`disabled_button_colors` 得长出 +/// 一个「哪个变体」的参数),并同步 `gallery/probe` 的逐行断言;本轮(M86)只做令牌一致性收口, +/// 不扩到变体分派。 +/// /// 曾经的缺陷不是「12 是错的」,而是**同一个常量同时服务这两类**:按钮那半边一直错、另半边一直对。 pub const DISABLED_CONTAINER_ALPHA: f32 = 0.10; /// 禁用态内容(文字/图标)透明度。