feat(design): M69 令牌补齐 —— 圆角分层 / 组件微度量 / 骨架值与一像素线
G13(D32 分层):新增 shape::ComponentRadius(白名单只有 Micro=2)、 MICRO_CONTROL_MAX_SIZE=24 与纯函数 radius_layer_for();微半径走 radius_px(size) -> Option<f32>,尺寸 >24dp 一律 None,靠签名而不是自觉拦。 ShapeScale 与 rank() 一个字未动,2 不进刻度。 G11:LayoutMetrics 加 search_bar_height=56 / nav_rail_width=88 / nav_drawer_width=240 / divider_thickness=1;删除语义相反的 nav_expanded_width=88 / nav_collapsed_width=48(D33:展开 drawer 240 / 折叠 rail 88;值 88 的后继是新名字 nav_rail_width,48 无后继)。 G10:新增 component_map::ComponentMetrics(12 字段 + 4 个命名常量 + indicator_width),入口 Component::metrics();框内几何与 LayoutMetrics 的 骨架值分工写进模块文档,骨架级尺寸在 CM 里留 0 不许重复。 G9:Component 末尾追加 Checkbox / Radio / Search / NavigationDrawer / Divider(20 -> 25),同步 table.rs 槽位、ALL 与 name();ComponentSpec 新增 micro_radius(Some 时 shape 必须是占位 None,由构造器 + 测试钉死)。 G12:新增 spacing::stroke::HAIRLINE = 1.0(crate 根再导出为 unlucky_design::stroke),divider_thickness 直接引用它。 其余:lib.rs 的「OKLCh 近似」文案改回真实口径(真 HCT / ColorSpec2021); component_map 单测拆到 tests.rs 以免 mod.rs 超 400 行;测试 145 -> 165。
This commit is contained in:
1 parent
b89cc91b78
commit
141e9b12c7
9 files changed
+1066
-145
No files matched your search
@@ -2,6 +2,10 @@
|
||||
//!
|
||||
//! 一行一个组件。改值就是在改全站观感——同步协作文档再改。
|
||||
//!
|
||||
//! **末尾 5 行(M69 G9)** 的来源是 `research/15` §18~§23(同一套 `material3-android:1.4.0` 源码):
|
||||
//! Checkbox / Radio / Search / NavigationDrawer / Divider。其中 Checkbox 的 **2dp** 圆角走
|
||||
//! [`ComponentRadius`](D32 第二层,不塞进 `ShapeScale`),Divider 的厚度是一像素线(G12)而不在这张表里。
|
||||
//!
|
||||
//! **高程/形状取值来源(A 级)**:`androidx.compose.material3.tokens` 的各组件 `<X>Tokens.kt`
|
||||
//! (FilledCard/OutlinedCard/ElevatedCard/Menu/Dialog/Snackbar/AppBar/List)。已登记的两处偏离:
|
||||
//! - `Tooltip`:`PlainTooltipTokens.kt` 只有 Corner 行、**没有 Elevation 行**,Table 的 Level2 是
|
||||
@@ -14,7 +18,7 @@ use crate::elevation::Elevation;
|
||||
use crate::motion::{
|
||||
DurationToken, Easing, SPRING_EXPRESSIVE_SPATIAL_DEFAULT, SPRING_EXPRESSIVE_SPATIAL_FAST,
|
||||
};
|
||||
use crate::shape::{ShapeMorph, ShapeScale};
|
||||
use crate::shape::{ComponentRadius, ShapeMorph, ShapeScale};
|
||||
use crate::typography::TypeRole;
|
||||
|
||||
/// 一个组件的档位行(`const fn` 便捷构造,字段名在 [`ComponentSpec`] 里)。
|
||||
@@ -31,6 +35,7 @@ const fn spec(
|
||||
ComponentSpec {
|
||||
component,
|
||||
shape,
|
||||
micro_radius: None,
|
||||
elevation,
|
||||
text,
|
||||
support,
|
||||
@@ -40,8 +45,35 @@ const fn spec(
|
||||
}
|
||||
}
|
||||
|
||||
/// 20 个组件的档位表。
|
||||
pub(super) const SPECS: [ComponentSpec; 20] = [
|
||||
/// 圆角走「微控件层」(D32)的档位行:`shape` 自动填占位 `None`,半径取白名单值。
|
||||
///
|
||||
/// 为什么单独一个构造器:`micro_radius` 与 `shape = None` 必须成对出现,用构造器保证配对,
|
||||
/// 不让 25 行表里出现「填了微半径忘了把 shape 清掉」。
|
||||
const fn spec_micro(
|
||||
component: Component,
|
||||
micro_radius: ComponentRadius,
|
||||
elevation: Elevation,
|
||||
text: TypeRole,
|
||||
support: Option<TypeRole>,
|
||||
motion: Easing,
|
||||
duration: DurationToken,
|
||||
morph: Option<ShapeMorph>,
|
||||
) -> ComponentSpec {
|
||||
ComponentSpec {
|
||||
component,
|
||||
shape: ShapeScale::None,
|
||||
micro_radius: Some(micro_radius),
|
||||
elevation,
|
||||
text,
|
||||
support,
|
||||
motion,
|
||||
duration,
|
||||
morph,
|
||||
}
|
||||
}
|
||||
|
||||
/// 25 个组件的档位表。
|
||||
pub(super) const SPECS: [ComponentSpec; 25] = [
|
||||
spec(
|
||||
Component::TopAppBar,
|
||||
ShapeScale::None,
|
||||
@@ -265,4 +297,73 @@ pub(super) const SPECS: [ComponentSpec; 20] = [
|
||||
DurationToken::Medium2,
|
||||
None,
|
||||
),
|
||||
// ---- M69 G9:末尾追加的 5 个(`research/15` §18~§23;前 20 行次序不许动)----
|
||||
// Checkbox:圆角 **2dp** 不在 `ShapeScale` 刻度里 → 走 `spec_micro`(D32 第二层)。
|
||||
// 高程 L0:`CheckboxTokens` 没有 Elevation 行,容器是「描边/填充」两态而非浮层。
|
||||
// 字级 `BodyLarge` 是**团队口径**:官方没有「框 + 标签」组合 token(§18.9),取列表行同一档。
|
||||
// 动效取 M3 motion scheme 的 fast-effects(100ms standard)——[推导],非 token 原文。
|
||||
spec_micro(
|
||||
Component::Checkbox,
|
||||
ComponentRadius::Micro,
|
||||
Elevation::Level0,
|
||||
TypeRole::BodyLarge,
|
||||
None,
|
||||
Easing::Standard,
|
||||
DurationToken::Short2,
|
||||
None,
|
||||
),
|
||||
// Radio:真圆(`RadioButtonTokens.IconSize = 20` + `CornerFull`),内点/环线宽见
|
||||
// `ComponentMetrics::RADIO`。字级同 Checkbox(团队口径)。
|
||||
spec(
|
||||
Component::Radio,
|
||||
ShapeScale::Full,
|
||||
Elevation::Level0,
|
||||
TypeRole::BodyLarge,
|
||||
None,
|
||||
Easing::Standard,
|
||||
DurationToken::Short2,
|
||||
None,
|
||||
),
|
||||
// Search bar:圆角 `CornerFull` / `SearchBarCornerRadius = 56/2 = 28`。
|
||||
// **高程取 L0**——`SearchBarTokens.ContainerElevation = Level3` 与
|
||||
// `SearchBarDefaults.TonalElevation/ShadowElevation = Level0` 冲突(§26.2 矛盾 ②),
|
||||
// 判据按观感取「无可见阴影 + tone 分层」,这条已在 `design-令牌约定` 登记。
|
||||
// 无 shape morph:bar ⇄ docked 展开时**半径不变**(28 → 28),只长面积(§20C)。
|
||||
spec(
|
||||
Component::Search,
|
||||
ShapeScale::Full,
|
||||
Elevation::Level0,
|
||||
TypeRole::BodyLarge,
|
||||
Some(TypeRole::BodySmall),
|
||||
Easing::Emphasized,
|
||||
DurationToken::Medium2,
|
||||
None,
|
||||
),
|
||||
// Navigation drawer:官方 `ContainerShape = CornerLargeEnd`(只有靠内容那侧两角 16,
|
||||
// 贴边侧直角)。`ShapeScale` 表达不了「部分角」,这里记内侧角的 `Large(16)`,
|
||||
// 哪两个角由组件按侧位决定;写四角 16 = 变成浮动卡片(§21.2 判据)。
|
||||
// 常驻形态 `Surface` + L0(模态才用 `SurfaceContainerLow` + scrim,本项目只在 <600 窗宽兜底)。
|
||||
spec(
|
||||
Component::NavigationDrawer,
|
||||
ShapeScale::Large,
|
||||
Elevation::Level0,
|
||||
TypeRole::LabelLarge,
|
||||
Some(TypeRole::TitleSmall),
|
||||
Easing::Emphasized,
|
||||
DurationToken::Medium2,
|
||||
None,
|
||||
),
|
||||
// Divider:无高程、无圆角、**无文字**(`text` 是占位值,消费方不得据此排版);
|
||||
// 厚度是一像素线 `LayoutMetrics::divider_thickness`,颜色 `OutlineVariant`
|
||||
// (search view 头部分隔是 `Outline`,两个不同角色,§20.8)。
|
||||
spec(
|
||||
Component::Divider,
|
||||
ShapeScale::None,
|
||||
Elevation::Level0,
|
||||
TypeRole::BodySmall,
|
||||
None,
|
||||
Easing::Standard,
|
||||
DurationToken::Short2,
|
||||
None,
|
||||
),
|
||||
];
|
||||
Reference in new issue
Block a user