fix(design): M69 r1 —— SEARCH_BAR 内边距语义收口 + ComponentRadius 取值口上闸
P2-1(语义缝隙):`SEARCH_BAR` 的 pad_start / pad_end 原为 16,与 icon_offset = 4 按字面相加得 20,比官方图标可视边 16 多 4px(越过 rubric ±2px 容差);而被加数的 12 不在 CM 里,消费方只能自己写 12.0 —— 正是 G10 要消灭的字面量。改为 12(文本框内容内边距,Space::X3)+ 4,两侧同式: 图标可视边 = pad + icon_offset = 16。字段文档写明求和公式;测试钉死 pad + offset == 16 且 pad != 16(防有人把 16 写回 pad 再叠加)。 顺带给 SEARCH_BAR.gap 补 [估] 出处(官方无图标↔文字 token)。 P2-2(绕过路径):ComponentRadius::dp() 收成 pub(crate)。它不看尺寸、 无条件返回 2.0,公开等于把 D32 的尺寸闸交给自觉。对外唯一取值口是 radius_px(size) -> Option<f32>;ALL 只暴露变体名、不暴露数值。 tokext_pins 原用 dp(),改为紧邻的 radius_px(20.0) == Some(2.0),覆盖不丢。 顺手:修掉本轮新引入的 rustdoc warning(component_map 文档链到私有模块 metrics,改指 ComponentMetrics);Divider 行标注 motion/duration 为占位, 并在 ComponentSpec 的 text / motion 字段文档写明「无文字 / 无动效的组件 这里是占位值,消费方不得据此排版 / 排动效」。 门禁:test 165 全绿、fmt --check、clippy -D warnings、check --workspace --all-targets、doc(warning 2 → 1,只剩既有的 typography→emphasized 一条)。
This commit is contained in:
1 parent
141e9b12c7
commit
16bdad1b98
5 files changed
+50
-17
No files matched your search
@@ -46,13 +46,14 @@ pub struct ComponentMetrics {
|
||||
pub inner_dot: f32,
|
||||
/// 控件相对容器的外距(dp):drawer 项 = 12,决定选中指示器左右各内缩 12。
|
||||
pub inset: f32,
|
||||
/// 内容起始侧内边距(dp)。
|
||||
/// 内容起始侧内边距(dp)。**图标不算在内**:图标可视边 = `pad_start + icon_offset`。
|
||||
pub pad_start: f32,
|
||||
/// 内容结束侧内边距(dp)。
|
||||
/// 内容结束侧内边距(dp)。同起始侧,图标可视边 = `pad_end + icon_offset`。
|
||||
pub pad_end: f32,
|
||||
/// 图标边长(dp;`0.0` = 无图标)。
|
||||
pub icon: f32,
|
||||
/// 图标相对内边距的**额外**偏移(dp)。
|
||||
/// 图标相对内边距的**额外**偏移(dp)。图标可视边 = 内边距 + 本值(search bar:12 + 4 = 16),
|
||||
/// **不要**把内边距本身当图标边用,也不要再手抄那个 12 / 16。
|
||||
pub icon_offset: f32,
|
||||
/// 图标与文字(或相邻元素)的间距(dp)。
|
||||
pub gap: f32,
|
||||
@@ -107,9 +108,14 @@ impl ComponentMetrics {
|
||||
///
|
||||
/// 高度与宽度**不在这里**:条高 56 是骨架级(`LayoutMetrics::search_bar_height`),
|
||||
/// 最小宽 360 同样属骨架级(尚未进 LM,M69 报告里登记为待办)。这里只装画进 bar 里的几何:
|
||||
/// 图标 24(`IconSize::Toolbar`)、可视左缘 16 = 文本框默认 12 + `SearchBarIconOffsetX = 4`、
|
||||
/// 右端同样 16(§20.4)。圆角走 `ShapeScale::Full`(56 → 28 = 官方 `SearchBarCornerRadius`),
|
||||
/// 图标 24(`IconSize::Toolbar`)、**图标可视边 = `pad_start + icon_offset`** = 12 + 4 = **16**
|
||||
/// (右侧同式为 16,§20.4)、圆角走 `ShapeScale::Full`(56 → 28 = 官方 `SearchBarCornerRadius`),
|
||||
/// 所以 `radius` 是 `None`。
|
||||
///
|
||||
/// 为什么要拆成 12 + 4 而不是直接写 16:官方 = 文本框内容内边距 **12**(`TextFieldImpl` 默认)
|
||||
/// 加上 `SearchBarIconOffsetX = 4`。拆开才能让「文本从 12 起、图标从 16 起」都被消费方拿到;
|
||||
/// 只写 16 的话文本内边距没有落点,消费方只能自己写 `12.0`——正是 G10 要消灭的字面量。
|
||||
/// 图标位置一律按 `pad + icon_offset` 求和,不要单独把 `pad` 当图标边用。
|
||||
pub const SEARCH_BAR: Self = Self {
|
||||
width: 0.0,
|
||||
height: 0.0,
|
||||
@@ -118,10 +124,12 @@ impl ComponentMetrics {
|
||||
state_layer: 0.0,
|
||||
inner_dot: 0.0,
|
||||
inset: 0.0,
|
||||
pad_start: Space::X4.dp(),
|
||||
pad_end: Space::X4.dp(),
|
||||
pad_start: Space::X3.dp(),
|
||||
pad_end: Space::X3.dp(),
|
||||
icon: IconSize::Toolbar.px(),
|
||||
icon_offset: 4.0,
|
||||
// 图标 ↔ 文本 8 是**团队口径 [估]**:`research/15` §20.4 只给了图标尺寸/位置与 48 命中框,
|
||||
// 没有「图标 ↔ 文字」的 token(Compose 由 `TextFieldImpl` 内部排版决定)。
|
||||
gap: Space::X2.dp(),
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
//! [`crate::shape::ComponentRadius`](落在 [`ComponentSpec::micro_radius`])。
|
||||
//!
|
||||
//! 档位(形状/高程/字级/动效)之外,**控件内部的微几何**(20×20、描边 2、状态层 Ø40 …)在
|
||||
//! [`ComponentMetrics`] 里,入口是 [`Component::metrics`]——两者分工见 [`metrics`] 模块文档。
|
||||
//! [`ComponentMetrics`] 里,入口是 [`Component::metrics`]——两者分工见该项的文档
|
||||
//! (`component_map::metrics` 模块)。
|
||||
//!
|
||||
//! **改这里的值 = 改全站观感**,必须同步 `DevDocs/SubAgentsTalk/design-令牌约定.md`;
|
||||
//! 页面线不许在页面里覆盖这些档位。
|
||||
@@ -43,11 +44,14 @@ pub struct ComponentSpec {
|
||||
pub micro_radius: Option<ComponentRadius>,
|
||||
/// 高程级别(决定 surface container 角色与是否画阴影)。
|
||||
pub elevation: Elevation,
|
||||
/// 主要文字角色。
|
||||
/// 主要文字角色。**无文字的组件(如 `Divider`)这里是占位值**,消费方不得据此排版。
|
||||
pub text: TypeRole,
|
||||
/// 辅助文字角色。
|
||||
pub support: Option<TypeRole>,
|
||||
/// 状态过渡缓动。
|
||||
///
|
||||
/// 该字段不是 `Option`,所以**没有动效语义的组件(如 `Divider`)这里是占位值**——
|
||||
/// 读之前先确认组件本身有状态过渡,无过渡的组件不得据此排动效。
|
||||
pub motion: Easing,
|
||||
/// 状态过渡时长。
|
||||
pub duration: DurationToken,
|
||||
|
||||
@@ -356,6 +356,8 @@ pub(super) const SPECS: [ComponentSpec; 25] = [
|
||||
// Divider:无高程、无圆角、**无文字**(`text` 是占位值,消费方不得据此排版);
|
||||
// 厚度是一像素线 `LayoutMetrics::divider_thickness`,颜色 `OutlineVariant`
|
||||
// (search view 头部分隔是 `Outline`,两个不同角色,§20.8)。
|
||||
// **`motion` / `duration` 也是占位值**(`ComponentSpec.motion` 不是 `Option`):Divider 没有
|
||||
// 官方状态过渡令牌,消费方**不得据此排动效**;下轮把该字段改成 `Option` 更彻底。
|
||||
spec(
|
||||
Component::Divider,
|
||||
ShapeScale::None,
|
||||
|
||||
@@ -119,6 +119,10 @@ pub const MICRO_CONTROL_MAX_SIZE: f32 = 24.0;
|
||||
///
|
||||
/// 用法:先 [`radius_layer_for`] 判层,微控件再 `radius_px(size)`。**返回 `None` 说明尺寸超界,
|
||||
/// 必须改查 [`ShapeScale`]**,不许把微半径硬套到容器上。
|
||||
///
|
||||
/// 公开的**唯一取值口是 [`ComponentRadius::radius_px`]**(带尺寸闸):本类型的 `dp()` 是
|
||||
/// `pub(crate)`,故意不对外开放——否则任何调用方都能无条件拿到 `2.0`,「只许 ≤24dp」就成了
|
||||
/// 自觉而不是约束(D32 的原意是拦住,不是提醒)。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ComponentRadius {
|
||||
/// 2dp:官方 Checkbox 容器圆角。
|
||||
@@ -127,10 +131,15 @@ pub enum ComponentRadius {
|
||||
|
||||
impl ComponentRadius {
|
||||
/// 白名单里的全部微半径(D32 当前只有一项;加值必须先在 `design-令牌约定` 登记)。
|
||||
///
|
||||
/// 枚举得出的只是**变体**(`Micro` 这个名字),拿不到数值——取值必须走 [`Self::radius_px`]。
|
||||
pub const ALL: [ComponentRadius; 1] = [ComponentRadius::Micro];
|
||||
|
||||
/// 半径(dp)。
|
||||
pub const fn dp(self) -> f32 {
|
||||
/// 半径(dp)。**`pub(crate)`:crate 内推导与自己用,不对外开放。**
|
||||
///
|
||||
/// 对任何尺寸都返回同一个数,所以它天然绕开 D32 的尺寸闸;对外只留
|
||||
/// [`Self::radius_px`](`Option<f32>`,>24dp 返回 `None`)。
|
||||
pub(crate) const fn dp(self) -> f32 {
|
||||
match self {
|
||||
ComponentRadius::Micro => 2.0,
|
||||
}
|
||||
|
||||
@@ -42,17 +42,19 @@ fn shape_scale_is_unchanged_and_never_contains_two() {
|
||||
#[test]
|
||||
fn component_radius_is_a_one_item_whitelist() {
|
||||
assert_eq!(ComponentRadius::ALL, [ComponentRadius::Micro]);
|
||||
// 2dp 只能通过带尺寸闸的 `radius_px` 拿到(`dp()` 是 crate 内部口,外部看不见)。
|
||||
assert_eq!(
|
||||
ComponentRadius::Micro.dp(),
|
||||
2.0,
|
||||
ComponentRadius::Micro.radius_px(20.0),
|
||||
Some(2.0),
|
||||
"官方 Checkbox RadiusSize = 2.dp"
|
||||
);
|
||||
// 尺寸闸:>24dp 一律拿不到微半径(D32 的「只允许 ≤24dp 微控件」)。
|
||||
assert_eq!(ComponentRadius::Micro.radius_px(20.0), Some(2.0));
|
||||
assert_eq!(ComponentRadius::Micro.radius_px(24.0), Some(2.0));
|
||||
assert_eq!(ComponentRadius::Micro.radius_px(25.0), None);
|
||||
assert_eq!(ComponentRadius::Micro.radius_px(240.0), None);
|
||||
assert_eq!(ComponentRadius::Micro.radius_px(0.0), None);
|
||||
// 边长小于两倍半径时按边长一半折算(2dp 元素不能有 2dp 圆角)。
|
||||
assert_eq!(ComponentRadius::Micro.radius_px(2.0), Some(1.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -149,10 +151,16 @@ fn search_bar_metrics_are_pinned() {
|
||||
// 高 56 属骨架级:CM 里必须留 0,不许重复一份。
|
||||
assert_eq!((cm.width, cm.height), (0.0, 0.0));
|
||||
assert_eq!(cm.icon, IconSize::Toolbar.px(), "leading/trailing 图标 24");
|
||||
// A 级(§20.4):图标可视左缘 16 = 文本框内容内边距 12 + `SearchBarIconOffsetX = 4`。
|
||||
assert_eq!(cm.pad_start, Space::X3.dp(), "内容内边距 12");
|
||||
assert_eq!(cm.icon_offset, 4.0, "SearchBarIconOffsetX = 4");
|
||||
// 可视左缘 16 = 文本框默认 12 + 偏移 4。
|
||||
assert_eq!(cm.pad_start, Space::X4.dp());
|
||||
assert_eq!(cm.pad_end, Space::X4.dp());
|
||||
assert_eq!(cm.pad_start + cm.icon_offset, 16.0, "图标可视左缘必须是 16");
|
||||
// 右侧同式:图标右缘也是 16。
|
||||
assert_eq!(cm.pad_end, Space::X3.dp());
|
||||
assert_eq!(cm.pad_end + cm.icon_offset, 16.0, "图标可视右缘必须是 16");
|
||||
// 守门:不许把 pad 本身写成 16(否则 pad + offset = 20,越过 rubric 的 ±2px)。
|
||||
assert_ne!(cm.pad_start, 16.0);
|
||||
assert_ne!(cm.pad_end, 16.0);
|
||||
// 搜索条圆角 = 高/2 = 28,等于官方 SearchBarCornerRadius。
|
||||
assert_eq!(
|
||||
ShapeScale::Full.radius_px(LayoutMetrics::DESKTOP.search_bar_height),
|
||||
@@ -171,6 +179,8 @@ fn navigation_drawer_metrics_are_pinned() {
|
||||
assert_eq!(cm.pad_start, Space::X4.dp(), "项内 start 16");
|
||||
assert_eq!(cm.pad_end, Space::X6.dp(), "项内 end 24");
|
||||
assert_eq!(cm.icon, IconSize::Toolbar.px());
|
||||
// 与 search bar 同一条公式:图标边 = pad + icon_offset(抽屉的 offset 是 0)。
|
||||
assert_eq!(cm.pad_start + cm.icon_offset, 16.0, "图标起点 = 项内 start");
|
||||
assert_eq!(cm.gap, Space::X3.dp(), "图标 ↔ label 12");
|
||||
// 指示器宽 = 容器宽 − 24;官方 360 − 24 = 336,本项目 240 − 24 = 216。
|
||||
assert_eq!(cm.indicator_width(360.0), 336.0);
|
||||
|
||||
Reference in new issue
Block a user