Skip to content

[00117] Give Size and Color a Lossless CSS String Wire Format - #109

Merged
rorychatt merged 2 commits into
mainfrom
tendril/00117-GiveSizeAndColorALosslessCSSStringWireFormat
Aug 2, 2026
Merged

[00117] Give Size and Color a Lossless CSS String Wire Format#109
rorychatt merged 2 commits into
mainfrom
tendril/00117-GiveSizeAndColorALosslessCSSStringWireFormat

Conversation

@rorychatt

Copy link
Copy Markdown
Contributor

Summary

Changes

Replaced lossy untagged serde serialization with custom Serialize/Deserialize implementations for Size and Color types. Both now serialize to CSS strings ("8px", "50%", "auto", "primary", "#ff0000", "rgba(1, 2, 3, 0.5)") and deserialize back correctly, making them round-trippable. This fixes DataTable and DataTableColumn which were sending bare numbers that clients couldn't interpret.

API Changes

New Public Methods

Size

  • pub fn parse_css(value: &str) -> Option<Size> — Parse a CSS length string back into a Size variant

Color

  • pub fn to_css(&self) -> String — Render as a CSS color string (wire format)
  • pub fn parse_css(value: &str) -> Option<Color> — Parse a CSS color string back into a Color variant

NamedColor

  • pub fn as_str(&self) -> &'static str — Get the camelCase wire name
  • pub fn parse(value: &str) -> Option<NamedColor> — Parse a camelCase wire name into a variant

Changed Serialization Behavior

Size and Color enums now implement custom Serialize/Deserialize traits instead of deriving them with #[serde(untagged)]. The wire format changes:

Before:

  • Size::Px(8.0)8.0 (indistinguishable from Percent)
  • Size::Percent(8.0)8.0 (indistinguishable from Px)
  • Size::Autonull (indistinguishable from absent field)
  • Color::Rgba{r:1,g:2,b:3,a:0.5}{"r":1,"g":2,"b":3,"a":0.5} (different JSON type than Named/Hex)

After:

  • Size::Px(8.0)"8px"
  • Size::Percent(8.0)"8%"
  • Size::Auto"auto"
  • Color::Rgba{r:1,g:2,b:3,a:0.5}"rgba(1, 2, 3, 0.5)"

Named colors and hex colors were already strings and remain unchanged.

Removed Internal Implementation Details

  • Removed .map(Size::to_css) workaround calls from Container, Image, Layout, and Skeleton widgets' to_json() methods (now redundant since Size serializes itself correctly)
  • Removed cssColor() helper from e2e/app/index.html (Color now always arrives as a string)

Files Modified

Core Type Changes:

  • rusty/src/shared/types.rs — Size custom serialization, +4 tests, -1 obsolete test
  • rusty/src/shared/color.rs — Color custom serialization, NamedColor helpers, +3 tests

Widget Updates:

  • rusty/src/widgets/container.rs — Removed to_css mapping
  • rusty/src/widgets/image.rs — Removed to_css mapping
  • rusty/src/widgets/layout.rs — Removed to_css mapping
  • rusty/src/widgets/skeleton.rs — Removed to_css mapping

E2E Renderer:

  • e2e/app/index.html — Removed cssColor function and call sites

Manual Testing

Test the new CSS string serialization:

  1. Run the widget_harness with a container using various Size and Color values:

    cargo run --bin widget_harness
  2. Open the E2E test page and observe the WebSocket refresh messages in browser DevTools Network tab

  3. Verify Container serialization includes CSS strings:

    • "width": "200px" (not 200.0)
    • "height": "auto" (not null)
    • "background": "rgba(238, 244, 255, 0.5)" (not an object)
  4. Verify Icon serialization includes color as a string:

    • "color": "primary" or "color": "#ff0000" (always a string)
  5. Run the Playwright E2E suite to verify the renderer correctly handles the new format:

    cd e2e
    npm ci
    npx playwright test --retries=0

    Expected: 139 passed (or current count on main)

Test round-tripping:

Run the new unit tests that verify serialization and deserialization:

cargo test test_size_round_trips
cargo test test_color_round_trips

Both should pass, demonstrating that values survive a to_string/from_str cycle.


Commits


Created using Ivy Tendril.

Replace untagged serde derives with custom Serialize/Deserialize
implementations that use CSS string format. This makes Size and Color
round-trippable and fixes DataTable serialization which was sending
bare numbers instead of CSS strings.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@rorychatt rorychatt self-assigned this Aug 2, 2026
- Accepted Widget macro implementations from plan 00093
- Removed size_css helper function (now obsolete)
- Removed prop(with = size_css) attributes from Layout and Skeleton
- Size now serializes itself correctly via custom Serialize impl
@rorychatt
rorychatt merged commit e6c4398 into main Aug 2, 2026
@rorychatt
rorychatt deleted the tendril/00117-GiveSizeAndColorALosslessCSSStringWireFormat branch August 2, 2026 10:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant