XiLaiTL/moobile/style does not have a README file

    Align

    pub(all) enum Align {
    FlexStart
    FlexEnd
    Center
    Stretch
    Baseline
    }

    Align::to_string

    fn Align::to_string(self : Align) -> String

    AlignSelf

    pub(all) enum AlignSelf {
    Auto
    FlexStart
    FlexEnd
    Center
    Stretch
    Baseline
    }

    AlignSelf::to_string

    fn AlignSelf::to_string(self : AlignSelf) -> String

    BorderStyle

    pub(all) enum BorderStyle {
    Solid
    Dotted
    Dashed
    }

    BorderStyle::to_string

    fn BorderStyle::to_string(self : BorderStyle) -> String

    Dimension

    pub(all) enum Dimension {
    Auto
    Px(Double)
    Pct(Double)
    }

    尺寸:auto / 绝对长度 / 百分比。用类型把它们分开,就不需要 width / width_pct / width_auto 三个方法。

    Dimension::to_style_value

    fn Dimension::to_style_value(self : Dimension) -> StyleValue

    Display

    pub(all) enum Display {
    Flex
    Hidden
    }

    只留 flex 与 none。刻意不含 grid —— 那正是要避免的东西。

    Display::to_string

    fn Display::to_string(self : Display) -> String

    FlexDirection

    pub(all) enum FlexDirection {
    Row
    Column
    RowReverse
    ColumnReverse
    }

    FlexDirection::to_string

    fn FlexDirection::to_string(self : FlexDirection) -> String

    FlexWrap

    pub(all) enum FlexWrap {
    NoWrap
    Wrap
    WrapReverse
    }

    FlexWrap::to_string

    fn FlexWrap::to_string(self : FlexWrap) -> String

    FontStyle

    pub(all) enum FontStyle {
    Normal
    Italic
    }

    FontStyle::to_string

    fn FontStyle::to_string(self : FontStyle) -> String

    FontWeight

    pub(all) enum FontWeight {
    Normal
    Bold
    W100
    W200
    W300
    W400
    W500
    W600
    W700
    W800
    W900
    }

    ⚠️ 注意:fontWeight 在 RN 里是字符串,不是数字。 把它做成枚举,就杜绝了"被 Number() 吃掉变成 700"这个静默 bug(README 的 F3)。

    FontWeight::to_string

    fn FontWeight::to_string(self : FontWeight) -> String

    Justify

    pub(all) enum Justify {
    FlexStart
    FlexEnd
    Center
    SpaceBetween
    SpaceAround
    SpaceEvenly
    }

    Justify::to_string

    fn Justify::to_string(self : Justify) -> String

    Overflow

    pub(all) enum Overflow {
    Visible
    Hidden
    Scroll
    }

    Overflow::to_string

    fn Overflow::to_string(self : Overflow) -> String

    Position

    pub(all) enum Position {
    Relative
    Absolute
    }

    Position::to_string

    fn Position::to_string(self : Position) -> String

    Style

    pub struct Style {
    entries : Array[(String, StyleValue)]
    }

    moobile 的类型化样式层。

    设计要点(对应 README「架构级改造的空间」):

    1. 属性集是封闭的 —— 只有下面这些方法存在。display:grid、 position:sticky、::before 这些根本没有构造器, 所以"Web 能跑、移动端不能"在编译期就不可能发生。 (DESIGN 原则 3:可移植子集优先于表达力。)

    2. 每个属性的值类型由签名钉死 —— font_weight 只收 FontWeight, 所以不可能出现"把数字塞给 fontWeight"这种静默非法。

    3. 一份数据、两个后端 —— StyleValue 同时携带"是不是长度", 于是 RN 侧产出数字、CSS 侧产出 "16px",不需要两边各存一套。

    词表取自 React Native 的 style props(它本身就已经是一份被策展过的 可移植子集:flexbox + 有限属性集,且刻意排除了 grid / sticky / 伪元素)。

    Style::align_items

    fn Style::align_items(self : Style, v : Align) -> Style

    Style::align_self

    fn Style::align_self(self : Style, v : AlignSelf) -> Style

    Style::aspect_ratio

    fn Style::aspect_ratio(self : Style, v : Double) -> Style

    Style::background_color

    fn Style::background_color(self : Style, v : String) -> Style

    Style::border_bottom_color

    fn Style::border_bottom_color(self : Style, v : String) -> Style

    Style::border_bottom_left_radius

    fn Style::border_bottom_left_radius(self : Style, v : Double) -> Style

    Style::border_bottom_right_radius

    fn Style::border_bottom_right_radius(self : Style, v : Double) -> Style

    Style::border_bottom_style

    fn Style::border_bottom_style(self : Style, v : BorderStyle) -> Style

    ⚠️ 原生 RN 没有分边的 border style(只有四边共用的 borderStyle)⇒ 真机上不生效。对应物(半有)见 Style::border_top_style 的说明。判据:tools/style_platform_check.mjs。

    Style::border_bottom_width

    fn Style::border_bottom_width(self : Style, v : Double) -> Style

    Style::border_color

    fn Style::border_color(self : Style, v : String) -> Style

    Style::border_left_color

    fn Style::border_left_color(self : Style, v : String) -> Style

    Style::border_left_style

    fn Style::border_left_style(self : Style, v : BorderStyle) -> Style

    ⚠️ 原生 RN 没有分边的 border style(只有四边共用的 borderStyle)⇒ 真机上不生效。对应物(半有)见 Style::border_top_style 的说明。判据:tools/style_platform_check.mjs。

    Style::border_left_width

    fn Style::border_left_width(self : Style, v : Double) -> Style

    Style::border_radius

    fn Style::border_radius(self : Style, v : Double) -> Style

    Style::border_right_color

    fn Style::border_right_color(self : Style, v : String) -> Style

    Style::border_right_style

    fn Style::border_right_style(self : Style, v : BorderStyle) -> Style

    ⚠️ 原生 RN 没有分边的 border style(只有四边共用的 borderStyle)⇒ 真机上不生效。对应物(半有)见 Style::border_top_style 的说明。判据:tools/style_platform_check.mjs。

    Style::border_right_width

    fn Style::border_right_width(self : Style, v : Double) -> Style

    Style::border_style

    fn Style::border_style(self : Style, v : BorderStyle) -> Style

    Style::border_top_color

    fn Style::border_top_color(self : Style, v : String) -> Style

    Style::border_top_left_radius

    fn Style::border_top_left_radius(self : Style, v : Double) -> Style

    Style::border_top_right_radius

    fn Style::border_top_right_radius(self : Style, v : Double) -> Style

    Style::border_top_style

    fn Style::border_top_style(self : Style, v : BorderStyle) -> Style

    ⚠️ 原生 RN 没有分边的 border style(只有四边共用的 borderStyle)⇒ 真机上这一条不生效(按默认 solid 画)。对应物(半有):当"有宽度的那些边"共用同一个 style 时,发一次 borderStyle 等价。判据:tools/style_platform_check.mjs。

    Style::border_top_width

    fn Style::border_top_width(self : Style, v : Double) -> Style

    Style::border_width

    fn Style::border_width(self : Style, v : Double) -> Style

    Style::bottom

    fn Style::bottom(self : Style, v : Dimension) -> Style

    Style::color

    fn Style::color(self : Style, v : String) -> Style

    Style::column_gap

    fn Style::column_gap(self : Style, v : Double) -> Style

    Style::display

    fn Style::display(self : Style, v : Display) -> Style

    Style::entries

    fn Style::entries(self : Style) -> Array[(String, StyleValue)]

    取出条目(后端按顺序消费)。

    Style::flex

    fn Style::flex(self : Style, v : Double) -> Style

    Style::flex_basis

    fn Style::flex_basis(self : Style, v : Dimension) -> Style

    Style::flex_direction

    fn Style::flex_direction(self : Style, v : FlexDirection) -> Style

    Style::flex_grow

    fn Style::flex_grow(self : Style, v : Double) -> Style

    Style::flex_shrink

    fn Style::flex_shrink(self : Style, v : Double) -> Style

    Style::flex_wrap

    fn Style::flex_wrap(self : Style, v : FlexWrap) -> Style

    Style::font_family

    fn Style::font_family(self : Style, v : String) -> Style

    Style::font_size

    fn Style::font_size(self : Style, v : Double) -> Style

    Style::font_size_of

    fn Style::font_size_of(self : Style) -> Double?

    从一份样式里找字号,供 Em 换算。找不到时返回 None。

    Style::font_style

    fn Style::font_style(self : Style, v : FontStyle) -> Style

    Style::font_weight

    fn Style::font_weight(self : Style, v : FontWeight) -> Style

    Style::from_entries

    fn Style::from_entries(entries : Array[(String, StyleValue)]) -> Style

    把一份 (键, 值) 列表原样装回 Style —— 不按名字过滤。

    为什么不复用"按名字 match"的写法(那种写法踩过,2026-10-23):那种白名单只适用于 特定用途("哪些键会被文字继承")。一旦拿它去重建常态样式,名单外的键 (minWidth / flexGrow …)就被静默丢掉 —— 症状是"样式看起来没生效", 排查方向会被带偏。这个构造器只做类型还原,不认识名字,所以不会漏键。

    Style::gap

    fn Style::gap(self : Style, v : Double) -> Style

    Style::height

    fn Style::height(self : Style, v : Dimension) -> Style

    Style::is_empty

    fn Style::is_empty(self : Style) -> Bool

    Style::justify_content

    fn Style::justify_content(self : Style, v : Justify) -> Style

    Style::left

    fn Style::left(self : Style, v : Dimension) -> Style

    Style::letter_spacing

    fn Style::letter_spacing(self : Style, v : Double) -> Style

    Style::letter_spacing_em

    fn Style::letter_spacing_em(self : Style, ratio : Double) -> Style

    相对字号的字距:letter-spacing: .1em。 RN 侧会按同一样式里的 fontSize 换算成点数(见 README 的 R1-3)。

    Style::line_height

    fn Style::line_height(self : Style, v : Double) -> Style

    Style::line_height_em

    fn Style::line_height_em(self : Style, ratio : Double) -> Style

    相对字号的行动高。

    Style::margin

    fn Style::margin(self : Style, v : Dimension) -> Style

    Style::margin_bottom

    fn Style::margin_bottom(self : Style, v : Dimension) -> Style

    Style::margin_horizontal

    fn Style::margin_horizontal(self : Style, v : Dimension) -> Style

    Style::margin_left

    fn Style::margin_left(self : Style, v : Dimension) -> Style

    Style::margin_right

    fn Style::margin_right(self : Style, v : Dimension) -> Style

    Style::margin_top

    fn Style::margin_top(self : Style, v : Dimension) -> Style

    Style::margin_vertical

    fn Style::margin_vertical(self : Style, v : Dimension) -> Style

    Style::max_height

    fn Style::max_height(self : Style, v : Dimension) -> Style

    Style::max_width

    fn Style::max_width(self : Style, v : Dimension) -> Style

    Style::min_height

    fn Style::min_height(self : Style, v : Dimension) -> Style

    Style::min_width

    fn Style::min_width(self : Style, v : Dimension) -> Style

    Style::new

    fn Style::new() -> Style

    Style::number_of_lines

    fn Style::number_of_lines(self : Style, v : Double) -> Style

    numberOfLines —— white-space: nowrap 在 RN 上惯用的那条替代路径(显式键,不自动折)。

    ⚠️★ 它不是样式键,是 Text 的组件属性(<Text numberOfLines={1}>)。@style 这一层故意 仍把它写成 Style 的一个键(好用、可组合),由渲染层把它从 style 对象里摘出来挂成 prop (render.mbt 的 prop_keys_of)—— 留在 style 里 RN 会忽略、RNW 会当成非法 CSS。

    ⚠️ 语义与 white-space: nowrap 不同:这是截断(超出部分去掉、通常带省略号), 不是"不折行、把容器撑开"。所以: · 生成器不会自动把 white-space: nowrap 折成它(会悄悄改变外观); · 要哪一处用它,人在应用代码里显式写(@style.Style::number_of_lines(1.0))。

    两端都认这个属性(实测):原生 RN Libraries/Text/Text.js 读 props.numberOfLines; react-native-web 的 Text 也读它(1 → 单行样式,>1 → -webkit-line-clamp)。 判据:tools/style_platform_check.mjs 的 PROP_KEYS(属性那一类,与"样式键"分开登记)。

    Style::opacity

    fn Style::opacity(self : Style, v : Double) -> Style

    Style::order

    fn Style::order(self : Style, v : Double) -> Style

    order —— flex 排序。yi 用它把某块提到前面(order: -1)。 ⚠️ 原生 RN 没有 order(Yoga 不支持)⇒ 真机上不生效。对应物:样式层没有 —— 要在 Model 里把顺序排好(与 @media 同一档)。判据:tools/style_platform_check.mjs。

    Style::overflow

    fn Style::overflow(self : Style, v : Overflow) -> Style

    Style::padding

    fn Style::padding(self : Style, v : Dimension) -> Style

    Style::padding_bottom

    fn Style::padding_bottom(self : Style, v : Dimension) -> Style

    Style::padding_horizontal

    fn Style::padding_horizontal(self : Style, v : Dimension) -> Style

    Style::padding_left

    fn Style::padding_left(self : Style, v : Dimension) -> Style

    Style::padding_right

    fn Style::padding_right(self : Style, v : Dimension) -> Style

    Style::padding_top

    fn Style::padding_top(self : Style, v : Dimension) -> Style

    Style::padding_vertical

    fn Style::padding_vertical(self : Style, v : Dimension) -> Style

    Style::position

    fn Style::position(self : Style, v : Position) -> Style

    Style::press

    fn Style::press(self : Style) -> Style

    按下状态的样式 —— 给触屏与 web 同一套表达(源 CSS 的 :hover 降级到这里)。

    用键前缀(press:)而不是给 StyleValue 加变体:加变体会让每一个构造器都得处理 "带不带状态",污染整个类型化属性集;键前缀只影响一次遍历,形状仍是扁平的 (String, Value)。

    ⚠️ 语义:它把当前已有的键都加上前缀 —— 所以.press() 落在链的哪一格, 就决定它前面那一段是按下态。要让"源 CSS 的 :hover 是按下态、常态仍是常态", 链的形状只能是 hover 的键 → .press() → 常态的键(它夹在中间):

    .border_color("#8a2518") // 源 CSS 的 :hover ⇒ 落在 .press() 之前 ⇒ 按下态 ✅ .press() .background_color("#e6d8bc") // 源 CSS 的常态 ⇒ 落在 .press() 之后 ⇒ 仍是常态 ✅ .min_width(@style.px(116.0)) // grid 列宽也是常态调用,必须在这一侧 ✅

    三种落法只有这一种对,而错的两种都很难看见(产物编得过、判据全绿,只是语义反了): · 写在链尾(把常态整段标成按下态)—— 2026-10-23 第十七轮就这么修的,实测后果: 卦卡的 .min_width(116).flex_grow(1) 变成"只在按住时生效" ⇒ 网格塌成单列 (容器 331px、卡片 54px);第十八轮又量到更重的一层:button.bagua-mode 的常态 只剩 borderColor + color 两条 —— 没内边距、没底色、没边框、没字号, 按住才变成一个按钮。 · 写在链中间但两侧写反(常态在前、hover 在后)—— 同样是整体互换,只是这次 连"hover 那一半"也没落在按下态上。

    生成器侧的组装只有一处(style-emit.js 的 emitModule),判据在 tools/regen_styles_check.mjs 的"按下态组装顺序"那一节。

    ⚠️ 消费侧(库的 Pressable 接线)尚未就绪(2026-10-23):生成器默认不产出它 (DSH_PRESS_FROM_HOVER=1 才开),等接线稳了再默认打开。

    Style::right_

    fn Style::right_(self : Style, v : Dimension) -> Style

    Style::row_gap

    fn Style::row_gap(self : Style, v : Double) -> Style

    Style::text_align

    fn Style::text_align(self : Style, v : TextAlign) -> Style

    Style::text_decoration_color

    fn Style::text_decoration_color(self : Style, v : String) -> Style

    ⚠️ 这个键只有 iOS 实现 —— Android 上静默不生效(安卓的 TextPaint 没有"下划线颜色"这个概念)。判据:tools/style_platform_check.mjs。

    Style::text_decoration_line

    fn Style::text_decoration_line(self : Style, v : TextDecorationLine) -> Style

    Style::text_decoration_style

    fn Style::text_decoration_style(self : Style, v : TextDecorationStyle) -> Style

    ⚠️ 这个键只有 iOS 实现 —— Android 上静默不生效(它在 RN 的登记表里,但安卓侧没有对应物)。判据:tools/style_platform_check.mjs。

    Style::text_transform

    fn Style::text_transform(self : Style, v : TextTransform) -> Style

    Style::top

    fn Style::top(self : Style, v : Dimension) -> Style

    Style::white_space

    fn Style::white_space(self : Style, v : WhiteSpace) -> Style

    ⚠️ 原生 RN 没有 whiteSpace 这个键(react-native-web 有)⇒ 真机上这一条不生效。对应物(部分有):nowrap 的 RN 惯例是 Text 的 numberOfLines(1)(截断,语义不同)。详见文件上方"补齐"那段的说明与 tools/style_platform_check.mjs。

    Style::width

    fn Style::width(self : Style, v : Dimension) -> Style

    Style::z_index

    fn Style::z_index(self : Style, v : Double) -> Style

    StyleValue

    pub(all) enum StyleValue {
    Unitless(Double)
    Px(Double)
    Pct(Double)
    Em(Double)
    Auto
    Str(String)
    } derive(Eq)

    值的形态,已足够覆盖 RN 与 CSS 的 style 取值:

    构造器RN 产出CSS 产出
    Unitless(d)数字"1"
    Px(d)数字"16px"
    Pct(d)"50%""50%"
    Em(d)数字(按同一样式里的 fontSize 换算)"0.1em"
    Auto"auto""auto"
    Str(s)字符串字符串

    ★ Em 是实测补上的:yi 大量使用 letter-spacing: .1em 这类相对单位, 而 RN 的 letterSpacing 只认点数。为它单独设构造器, 就把"每次调用点手工乘一遍"这个易错动作消灭了。

    StyleValue::resolve_em

    fn StyleValue::resolve_em(self : StyleValue, font_size : Double) -> StyleValue

    把 Em 按给定字号换算成点数。RN 没有 em 这个概念,只能换算。

    StyleValue::to_css

    fn StyleValue::to_css(self : StyleValue) -> String

    CSS 侧取值:长度要补 px,无单位量不补,em 原样保留(CSS 认识它)。

    StyleValue::to_rn_number

    fn StyleValue::to_rn_number(self : StyleValue) -> Double?

    RN 侧取值:长度与无单位量都是数字(RN 不接受 "16px")。

    Em 需要上下文里的字号,所以这里返回 None; 由后端在知道同一样式的 fontSize 时另行换算(见 Em::resolve)。

    StyleValue::to_rn_string

    fn StyleValue::to_rn_string(self : StyleValue) -> String?

    RN 侧取值:非数字的一律是字符串。

    TextAlign

    pub(all) enum TextAlign {
    Auto
    Left
    Right
    Center
    Justify
    }

    TextAlign::to_string

    fn TextAlign::to_string(self : TextAlign) -> String

    TextDecorationLine

    pub(all) enum TextDecorationLine {
    None
    Underline
    LineThrough
    UnderlineLineThrough
    }

    TextDecorationLine::to_string

    fn TextDecorationLine::to_string(self : TextDecorationLine) -> String

    TextDecorationStyle

    pub(all) enum TextDecorationStyle {
    Solid
    Double_
    Dotted
    Dashed
    }

    TextDecorationStyle::to_string

    fn TextDecorationStyle::to_string(self : TextDecorationStyle) -> String

    TextTransform

    pub(all) enum TextTransform {
    None
    Uppercase
    Lowercase
    Capitalize
    }

    TextTransform::to_string

    fn TextTransform::to_string(self : TextTransform) -> String

    WhiteSpace

    pub(all) enum WhiteSpace {
    Normal
    NoWrap
    Pre
    PreWrap
    }

    WhiteSpace::to_string

    fn WhiteSpace::to_string(self : WhiteSpace) -> String

    auto

    fn auto() -> Dimension

    css_property_name

    fn css_property_name(key : String) -> String

    RN 的键是 camelCase(backgroundColor),CSSOM 要 kebab-case(background-color)。 命名差异由这一层吸收 —— 上层只需要写一种拼法。

    pct

    fn pct(d : Double) -> Dimension

    press_prefix

    let press_prefix : String

    键前缀(render.mbt 与生成物共用一个常量,别各自写死字符串)。
    fn px(d : Double) -> Dimension

    Source Files