You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(html): add comprehensive React-style object-as-styles support (#1923)
* feat(html): add comprehensive React-style object-as-styles support
Add full support for passing style objects in JSX, matching React's
style prop behavior. This enables more ergonomic styling in patterns
and recipes.
## Key Features
- **CamelCase to kebab-case conversion**: Automatically converts React-style
property names (e.g., `backgroundColor`) to CSS property names
(e.g., `background-color`)
- **Smart unit handling**: Automatically appends 'px' to numeric values for
properties that require units, while respecting unitless properties like
`opacity`, `zIndex`, `flexGrow`, `lineHeight`, etc.
- **Vendor prefix support**: Handles browser vendor prefixes correctly
(e.g., `WebkitTransform` → `-webkit-transform`, `MozAppearance` →
`-moz-appearance`)
- **Null/undefined value handling**: Gracefully skips null and undefined
values, allowing conditional styling
- **Complex value support**: Handles complex CSS values like gradients,
shadows, and transforms without modification
## Implementation
- Added `styleObjectToCssString()` helper function in both render.ts and
utils.ts for consistent conversion logic
- Updated `setProp()` in render.ts to detect style objects and convert them
to CSS strings before setting the attribute
- Updated mock document's `setProp()` in utils.ts to ensure tests work
correctly with style objects
## Test Coverage
Added 8 comprehensive test cases covering:
- Basic React-style object to CSS string conversion
- Unitless numeric properties
- Vendor prefixes (webkit, moz, ms, o)
- Zero value handling
- Null and undefined value handling
- Complex CSS values (box-shadow, gradients, transforms)
- Style objects alongside other props
- Empty style objects
All tests pass with full type safety.
## Usage Example
```tsx
<div style={{
backgroundColor: "red",
fontSize: 16, // → "16px"
opacity: 0.5, // → "0.5" (unitless)
WebkitTransform: "rotate(45deg)", // → "-webkit-transform"
margin: 0, // → "0"
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
}} />
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(html): add flex to unitless CSS properties
Add the `flex` property to the unitless properties set to prevent
invalid CSS generation. Without this fix, numeric flex values like
`flex: 1` were incorrectly converted to `flex: 1px`, which breaks
flexbox layouts.
## Changes
- Added "flex" to unitlessProperties Set in both render.ts and utils.ts
- Updated test to verify flex property remains unitless
## Test Coverage
Updated "handles unitless numeric properties" test to include:
- `flex: 1` → "flex: 1" (not "flex: 1px")
Fixes issue where flexbox layouts using numeric flex values would
render invalid CSS.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(html): preserve CSS custom properties without px suffix
Prevent automatic 'px' suffix addition for CSS custom properties
(CSS variables). Custom properties can represent any type of value
and should never be modified by auto-unit logic.
## The Problem
CSS custom properties starting with '--' were incorrectly receiving
'px' suffixes when given numeric values, causing:
- `{ "--scale": 2 }` → `--scale: 2px` (invalid, should be `--scale: 2`)
- `{ "--opacity": 0.5 }` → `--opacity: 0.5px` (invalid, should be `--opacity: 0.5`)
This diverges from React's behavior and breaks CSS variable usage.
## The Solution
Added check for `cssKey.startsWith("--")` before applying 'px' suffix
in both render.ts and utils.ts. CSS custom properties now preserve
their values exactly as provided.
## Test Coverage
Added comprehensive test "handles CSS custom properties (variables)
without adding px" covering:
- Numeric variables: `--scale: 2` (not `2px`)
- Decimal variables: `--opacity: 0.5` (not `0.5px`)
- Integer variables: `--columns: 3` (not `3px`)
- String variables: `--primary-color: #ff0000` (unchanged)
All tests pass (3 passed, 39 steps).
## Usage Example
```tsx
<div style={{
"--scale": 2, // → "--scale: 2"
"--opacity": 0.5, // → "--opacity: 0.5"
"--primary-color": "red" // → "--primary-color: red"
}} />
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(html): preserve case sensitivity for CSS custom properties
CSS custom properties (CSS variables) are case-sensitive and must
retain their original casing. Previously, all CSS property names were
lowercased, breaking case-sensitive custom properties.
## The Problem
CSS custom properties were being lowercased during conversion:
- `{ "--MyAccent": "blue" }` → `--myaccent: blue` (incorrect)
- `{ "--THEME-Color": "red" }` → `--theme-color: red` (incorrect)
This breaks CSS variable usage since `--MyAccent` and `--myaccent` are
distinct variables in CSS.
## The Solution
Skip camelCase-to-kebab-case conversion and lowercasing for properties
starting with `--`. CSS custom properties now preserve their exact
casing as provided.
Updated logic in both render.ts and utils.ts:
- Check `!key.startsWith("--")` before applying transformations
- Only convert standard CSS properties to kebab-case and lowercase
- Preserve custom properties exactly as written
## Test Coverage
Updated "handles CSS custom properties (variables) without adding px"
test to verify case preservation:
- `--MyAccent: blue` (preserves mixed case)
- `--THEME-Color: green` (preserves uppercase and mixed case)
- `--scale: 2` (preserves lowercase)
All tests pass (3 passed, 39 steps).
## Usage Example
```tsx
<div style={{
"--MyAccent": "blue", // → "--MyAccent: blue" (case preserved)
"--THEME-Color": "red", // → "--THEME-Color: red" (case preserved)
backgroundColor: "white" // → "background-color: white" (converted)
}} />
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* dedupe styleObjectToCssString function
* move utils.ts to test/ since it's only a test helper
* Revert "move utils.ts to test/ since it's only a test helper"
This reverts commit 5714458.
* test/utils.ts was used elsewhere for non-tests, so renaming to mock-doc instead
---------
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments