From 0e0981ece69298ff6ff44bbfa06f332e16bc81d1 Mon Sep 17 00:00:00 2001 From: GenericJam Date: Sat, 4 Jul 2026 21:44:32 -0600 Subject: [PATCH] docs: make the 0xAARRGGBB color format explicit (vs CSS hex) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Color props accept raw colors as 0xAARRGGBB integer literals (alpha first), which is easy to get wrong coming from web/CSS habits — coding assistants especially default to "#RRGGBB" strings and alpha-last. The theming guide only showed one opaque example without spelling out the format. Add an explicit "Raw colors are 0xAARRGGBB integers, not CSS hex strings" section: it's an integer literal not a string, alpha is the FIRST byte (not last like CSS #RRGGBBAA), always include the alpha byte (a 6-digit value reads as alpha 00 = transparent), and show that the alpha byte is what makes a translucent/frosted panel composable from primitives. Cross-link it from the components prop-value reference. Docs-only. Co-Authored-By: Claude Opus 4.8 (1M context) --- guides/components.md | 1 + guides/theming.md | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/guides/components.md b/guides/components.md index d13de0ff..46afd4c4 100644 --- a/guides/components.md +++ b/guides/components.md @@ -141,6 +141,7 @@ Props accept: - **Strings** — used as-is - **Booleans** — used as-is - **Color atoms** (`:primary`, `:blue_500`, etc.) — resolved via the active theme and the base palette to ARGB integers. See [Theming](theming.md). +- **Raw colors** — a 32-bit **`0xAARRGGBB` integer** (alpha first, e.g. `0xFF2196F3`), **not** a CSS `"#RRGGBB"` string and **not** alpha-last. Include the `0xFF` alpha byte or the color renders transparent. See [Theming → Raw colors](theming.md#raw-colors-are-0xaarrggbb-integers-not-css-hex-strings). - **Spacing tokens** (`:space_xs`, `:space_sm`, `:space_md`, `:space_lg`, `:space_xl`) — scaled by `theme.space_scale` and resolved to integers. - **Radius tokens** (`:radius_sm`, `:radius_md`, `:radius_lg`, `:radius_pill`) — resolved to integers from the active theme. - **Text size tokens** (`:xs`, `:sm`, `:base`, `:lg`, `:xl`, `:2xl`, `:3xl`, `:4xl`, `:5xl`, `:6xl`) — scaled by `theme.type_scale` and resolved to floats. diff --git a/guides/theming.md b/guides/theming.md index 6a66358f..7d48c9b6 100644 --- a/guides/theming.md +++ b/guides/theming.md @@ -214,10 +214,41 @@ use Mob.App, theme: AcmeCorp.BrandTheme Token atoms that are not semantic theme tokens resolve through the built-in palette. The palette covers grays, blues, greens, reds, oranges, purples, teals, pinks, and more — all as `name_weight` atoms (e.g. `:blue_500`, `:gray_200`, `:emerald_400`). -You can also pass raw ARGB hex integers directly as prop values: +### Raw colors are `0xAARRGGBB` integers, not CSS hex strings + +Any color prop also accepts a raw color **as a 32-bit integer literal** in +`0xAARRGGBB` order — **alpha first**, then red, green, blue: ```elixir %{type: :text, props: %{text: "Hi", text_color: 0xFFFF5733}, children: []} +# ^^ alpha = FF (fully opaque) +# FF5733 red/green/blue +``` + +This is **not** web/CSS color syntax. Two differences trip people (and coding +assistants) up: + +- **It's an integer literal (`0xFFFF5733`), not a string.** A CSS-style + `"#FF5733"` string is **not** a valid color prop — pass the `0x…` integer. +- **Alpha comes first (`0xAARRGGBB`), not last.** CSS's 8-digit form is + `#RRGGBBAA` (alpha last); Mob is `0xAARRGGBB` (alpha first), matching the + Android/`Color`-int and iOS ARGB convention the native layer uses. Putting the + opacity byte in the wrong place gives a wrong color, not just wrong + transparency. + +**Always include the alpha byte.** `0xFF2196F3` is opaque blue; `0x002196F3` +is fully transparent (alpha `00`). A 6-digit `0x2196F3` is read as +`0x002196F3` — invisible — because the missing top byte defaults to `00`. +The built-in palette entries are all `0xFF…` for this reason, and +`:transparent` is `0x00000000`. + +The alpha byte is what makes translucency composable. For example, a frosted +overlay panel is just a box with a semi-transparent background stacked over +content — no special "glass" primitive required: + +```elixir +# ~40% black scrim / frosted panel over whatever is behind it +%{type: :box, props: %{background: 0x66000000}, children: [...]} ``` Use raw integers sparingly. Semantic tokens give you free dark-mode and theme switching.