Skip to content

Commit cd205cf

Browse files
authored
feat: Unify CSS-to-RN compiler and runtime pipeline (#5)
## Summary This PR unifies the CSS-to-React-Native style pipeline into a new `@cssxjs/css-to-rn` workspace package and wires CSSX, loaders, Babel output, and runtime entrypoints through it. The goal is to replace the separate forked CSS-to-RN transform libraries and the old CSSX runtime with one maintainable compiler/runtime package. Key changes: - Adds `packages/css-to-rn`, a TypeScript ESM package owning CSS parsing, selector IR, value resolution, property transforms, style resolution, caching, and React runtime tracking. - Keeps Stylus-to-CSS compilation separate, while moving pure CSS-to-RN style compilation and runtime resolution into the unified package. - Supports local JS template interpolation in function-scoped `css`/`styl` templates, with interpolation values reusing one cache slot per compiled call shape. - Adds runtime CSS string compilation for generated CSS via `useRuntimeCss()`, `useCssxLayer()`, and `cssx()`. - Implements nested `var()` resolution, partial shorthand substitution, dynamic dependency tracking, bounded cache behavior, deep inline-style hashing, media/dimension tracking, web `matchMedia` invalidation, and React Native `Dimensions` integration. - Adds React 19 tracking without Teamplay or `@nx-js/observer-util`, including Suspense/aborted-render cleanup tests. - Adds `CssxProvider style` and `theme` for subtree-scoped provider CSS, global utility classes, scoped `:root` / `:root.<theme>` variables, OS dark-mode auto selection, and component tag overrides. - Adds CSSX theme assets and exports: `cssxjs/themes/tailwind` and `cssxjs/themes/shadcn`. - Adds `@custom-media`, CSS media range evaluation for width/height comparisons, built-in `@media (--theme-*)` aliases, and provider-aware `useMedia()`. - Adds component tag selectors through `themed(tagName, Component)`, including `Tag`, `Tag.class`, `Tag:part(name)`, `Tag::part(name)`, `Tag:hover`, and `Tag:active` matching. - Adds `useCssVariable()`, `useCssVariableRaw()`, `getCssVariable()`, and `getCssVariableRaw()` for subscribed and global JS access to resolved CSS variables. - Adds `useCssColor()` and `getCssColor()` for provider-aware JS color bridges, including token lookup and `color-mix()` style mixing. - Adds a deprecated JS `u()` helper and build diagnostics for deprecated CSS `u` units. - Adds validating `variables` and `defaultVariables` proxy methods: `.assign()`, `.set()`, and `.clear()`. - Resolves `var()` inside inline style props and tracks the variables used by those inline props. - Normalizes `oklch()`, `oklab()`, and `color-mix()` through pinned `@colordx/core@5.4.3` so modern color CSS works on RN. - Supports percentage/unitless `calc()` in CSS value resolution for color-channel math while still rejecting mixed layout calc such as `calc(100% - 16px)`. - Mixes `color-mix(in srgb, color, transparent)` with premultiplied alpha so transparent theme colors preserve the source RGB. - Preserves source-condition TypeScript consumers without committing build output: source entrypoints carry vendor shims, `themed()` preserves wrapped component props, and `cssx()` accepts loader-produced opaque sheet records at the type boundary. - Implements `:hover`/`:active` aliases, `filter`, `background-image`/gradient support, limited `background` shorthand, animations/transitions/keyframes, and Reanimated v4-compatible animation style output. - Adds build-strict diagnostics for unsupported static declarations while keeping runtime compilation graceful for generated CSS. - Migrates loaders and Babel runtime paths to the unified package, with source-condition test/dev imports and facade smoke coverage. - Stops tracking generated `dist` output; package builds still emit `dist` for published/default exports. - Keeps legacy `runtime/*-teamplay` import paths as compatibility wrappers only. - Removes the old `packages/runtime` package from the active graph. - Updates `architecture.md`, `AGENTS.md`, `plan.md`, public docs, README credits, and CI smoke checks for the new architecture. ## Architect Review Follow-up After a multi-agent architecture/performance/test-coverage review, this PR now also: - avoids promoting changed tracked sheets, interpolation values, or hook dependencies from Suspense-aborted renders - keeps `useCssxLayer(false)` hook order stable when toggled to a real sheet - allows and resolves template interpolation inside provider `:root` custom property values - resolves provider root variables from compiled sheets and `{ sheet, values }` layers - adds regression coverage for complex partial `var()` values in box-shadow/filter/text-shadow/transform/background - updates runtime docs for precompiled provider `:root` interpolation - maps `:part(root)` to the root `style` prop consistently in the unified resolver - expands `@custom-media` subscriptions to concrete media dependencies and marks width/height range queries as dimension-dependent - surfaces runtime sheet compile diagnostics through `resolveCssx()` for generated CSS callers - keeps `cssxjs/runtime/web` and `cssxjs/runtime/react-native` exporting the public CSSX/color helpers with smoke coverage ## Related PRs - startupjs/startupjs#1327 wires `StartupjsProvider style` and `theme` into CSSX so framework users can pass provider CSS and theme selection through the StartupJS root provider. - startupjs/startupjs-ui#41 moves StartupJS UI theming onto CSSX theme assets, `startupjsUiTheme.cssx.css`, CSS variable primitives, and direct component tag/part overrides. ## Validation - `cd packages/css-to-rn && npm test` - `cd packages/babel-plugin-rn-stylename-inline && yarn test` - `cd packages/babel-plugin-rn-stylename-to-style && yarn test` - `git diff --check` - `cd packages/cssxjs && yarn test` - CSSX theme entrypoints compile through JS import/default-export wrappers instead of leaking `.cssx.css` assets into consuming web builds. - Cross-repo StartupJS UI validation with local source links: - `node scripts/update-style-reference-docs.mjs` idempotency check - `yarn generate-package-dts` - `node scripts/check-startupjs-ui-exports.mjs` - `yarn build` for startupjs-ui docs - Playwright smoke for the generic Styling guide plus Button, Item, Div, and DateTimePicker docs pages - Playwright smoke for Storybook iframe stories: Overview, Button, Item, Badge, Modal, Popover, System/StartupJS UI, and DateTimePicker - visual screenshots checked for Styling, Button, Item, DateTimePicker, provider, and popover stories - Known during DateTimePicker smoke: Moment Timezone logs its existing missing timezone-data warning; no CSS token, page, or provider errors were observed. - startupjs PR validation: `NODE_OPTIONS="-C cssx-ts" npm test` in `core/startupjs`, plus the normal pre-commit hook with eslint and `npx startupjs check`. ## Review Focus This is a large architectural PR. Please scrutinize: - Runtime cache invalidation, interpolation cache behavior, and reference stability. - Provider `:root` / `:root.<theme>` variable scoping and precedence relative to runtime/default variables. - Theme selection, OS color-scheme subscriptions, and `@media (--theme-*)` behavior. - `@custom-media`, range media evaluation, and `useMedia()` subscriptions. - Component tag selector matching and the `themed()` render-local tracking model. - `useCssVariable()` / `useCssColor()` exact subscriptions and Suspense/aborted-render safety. - Media/dimension invalidation, web `matchMedia` subscriptions, React Native dimensions, and listener cleanup. - Complex value parsing: nested `var()`, shorthand fragments, modern colors, gradients/backgrounds, transforms, animations, transitions, and invalid generated CSS. - Babel output compatibility with existing CSSX `styleName`, `css`, `styl`, and part workflows. - Package exports/source-condition behavior and whether the new package boundary is maintainable long term.
1 parent 5d8d1b7 commit cd205cf

109 files changed

Lines changed: 18734 additions & 4226 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,12 @@ jobs:
2424

2525
- name: Run tests
2626
run: yarn test
27+
28+
- name: Smoke source-condition package imports
29+
run: |
30+
node -C cssx-ts --input-type=module -e "import { cssx, useCssxLayer } from 'cssxjs'; if (typeof cssx !== 'function' || typeof useCssxLayer !== 'function') throw new Error('cssxjs source-condition import failed')"
31+
32+
- name: Smoke built package imports
33+
run: |
34+
yarn workspace @cssxjs/css-to-rn build
35+
node --input-type=module -e "import { compileCss, resolveCssx } from '@cssxjs/css-to-rn'; const sheet = compileCss('.root { color: red; }'); const result = resolveCssx({ styleName: 'root', layers: sheet }); if (result.props.style.color !== 'red') throw new Error('built css-to-rn import failed')"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
# Node dependencies
1313
node_modules
14+
packages/*/dist
1415

1516
# npm-debug log
1617
npm-debug.*

AGENTS.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Read this first, then use `architecture.md` for the detailed system map.
44

5-
CSSX is a monorepo for a CSS-in-JS toolchain. Users write `styl`, `css`, or optional `pug` templates plus `styleName` and `part` props. Babel compiles that authoring syntax into style objects and runtime calls. The runtime matches class selectors, applies CSS variables/media queries, supports component parts, and can memoize with teamplay.
5+
CSSX is a monorepo for a CSS-in-JS toolchain. Users write `css`, `styl`, or optional `pug` templates plus `styleName` and `part` props. Babel compiles that authoring syntax into compiled CSS sheet IR and runtime calls. The unified `@cssxjs/css-to-rn` package owns CSS parsing, CSS value resolution, React Native/web style transformation, runtime caching, variables, media/dimension tracking, and React subscriptions.
66

77
## Start Here
88

@@ -12,11 +12,11 @@ CSSX is a monorepo for a CSS-in-JS toolchain. Users write `styl`, `css`, or opti
1212

1313
## Package Map
1414

15-
- `packages/cssxjs/`: public `cssxjs` facade, CLI, wrappers, package exports.
16-
- `packages/runtime/`: `process()`, `matcher()`, variables, dimensions, platform helpers, teamplay caching.
17-
- `packages/loaders/`: Stylus/CSS loaders and direct compiler wrappers.
18-
- `packages/babel-plugin-rn-stylename-inline/`: compiles inline `css` and `styl` templates.
19-
- `packages/babel-plugin-rn-stylename-to-style/`: rewrites JSX `styleName`, `part`, old `*StyleName`, and helper calls.
15+
- `packages/css-to-rn/`: unified compiler/runtime engine. Start here for CSS parsing, selector IR, value resolution, property transforms, caching, `cssx()`, `useRuntimeCss()`, variables, and dimensions.
16+
- `packages/cssxjs/`: public `cssxjs` facade, CLI, package exports, runtime compatibility wrappers, Babel preset wrapper, loader wrappers, and Metro wrappers.
17+
- `packages/loaders/`: Stylus/CSS loaders and direct compiler wrappers. CSS compilation delegates to `@cssxjs/css-to-rn`.
18+
- `packages/babel-plugin-rn-stylename-inline/`: compiles inline `css` and `styl` templates, including local template interpolation lowering.
19+
- `packages/babel-plugin-rn-stylename-to-style/`: rewrites JSX `styleName`, `part`, old `*StyleName`, and helper calls into runtime calls.
2020
- `packages/babel-preset-cssxjs/`: transform ordering and public Babel options.
2121
- `packages/bundler/`: Metro hot-reload path for separate style files.
2222
- `packages/eslint-plugin-cssxjs/`: wrapper around React Pug ESLint processor.
@@ -26,13 +26,17 @@ CSSX is a monorepo for a CSS-in-JS toolchain. Users write `styl`, `css`, or opti
2626
## Core Contracts
2727

2828
- `__CSS_GLOBAL__` and `__CSS_LOCAL__` connect the inline Babel plugin to the JSX/runtime plugin.
29-
- Compiled style metadata `__hash__`, `__vars`, and `__hasMedia` connects loaders to cached and uncached runtime processing.
30-
- Runtime calls have this shape: `runtime(styleName, fileStyles, globalStyles, localStyles, inlineStyleProps)`.
31-
- Style priority is file styles, then global templates, then local templates, then inline props.
32-
- Selector specificity is approximated by class count only.
29+
- Runtime calls generated by Babel keep the compatibility shape `runtime(styleName, fileStyles, globalStyles, localStyles, inlineStyleProps)`.
30+
- `cssxjs/runtime/*` wrappers adapt that call shape to `@cssxjs/css-to-rn` platform entrypoints.
31+
- Style priority is file/imported sheets, then global templates, then local templates, then inline props.
32+
- Compiled sheets are JSON-serializable IR. Runtime cache/tracking state must stay outside the sheet.
3333
- `part='root'` maps to `style`; other parts map to `{partName}Style`.
34-
- `css`/`styl` template interpolation is intentionally unsupported.
35-
- Cached runtime is selected by `cache: 'teamplay'` or by importing `observer` from `teamplay` or `startupjs`.
34+
- `:hover` and `:active` compile to `hoverStyle` and `activeStyle`.
35+
- Provider/global `:root` custom properties compile to `sheet.rootVariables` and resolve as scoped defaults below runtime `variables` and above `defaultVariables`.
36+
- Component tag selectors such as `Button` and `Button:part(text)` apply only inside components wrapped with `themed('Button', Component)` or explicit resolver tag options.
37+
- `variables` and `defaultVariables` are validating proxies. Direct assignment/deletion works for valid `--name` keys; bulk updates use `.assign()`, `.set()`, and `.clear()`.
38+
- Local JS template interpolation is lowered to synthetic `var(--__cssx_dynamic_N)` slots and passed as `values`.
39+
- `cache: 'teamplay'` remains accepted as a Babel option for compatibility, but runtime caching is owned by `@cssxjs/css-to-rn`, not Teamplay.
3640

3741
## Commands
3842

@@ -51,7 +55,7 @@ yarn test
5155
Run targeted tests:
5256

5357
```sh
54-
cd packages/runtime && yarn test
58+
cd packages/css-to-rn && npm test
5559
cd packages/babel-plugin-rn-stylename-inline && yarn test
5660
cd packages/babel-plugin-rn-stylename-to-style && yarn test
5761
```
@@ -70,9 +74,10 @@ yarn start
7074

7175
## Change Guidance
7276

73-
- For runtime matching changes, update `packages/runtime/test/matcher.mjs` and `packages/runtime/test/process.mjs`.
74-
- For Babel changes, update the relevant Jest snapshots.
75-
- For public API or behavior changes, update `docs/` and `architecture.md`.
77+
- For CSS parsing, selector, value, transform, cache, variable, media, or React tracking behavior, update `packages/css-to-rn/test/engine/**` or `packages/css-to-rn/test/react/**`.
78+
- For inline template or interpolation compilation, update `packages/babel-plugin-rn-stylename-inline` snapshots.
79+
- For JSX `styleName`/`part` behavior, update `packages/babel-plugin-rn-stylename-to-style` snapshots.
80+
- For public API or behavior changes, update `docs/`, `architecture.md`, and this guide.
7681
- For Pug, type checking, or ESLint behavior, check whether the implementation lives in `@react-pug/*`; this repo often only wraps it.
7782
- For separate style files, check both Babel `compileCssImports` behavior and Metro transformer behavior.
7883
- Prefer current source code and `docs/` over older package READMEs when they conflict.

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ Install the following extension for full CSSX support with Pug and CSS/Stylus in
2323

2424
[`vscode-react-pug-tsx`](https://marketplace.visualstudio.com/items?itemName=startupjs.vscode-react-pug-tsx)
2525

26+
## Credits
27+
28+
CSSX's unified CSS-to-React-Native compiler/runtime was inspired by and replaces
29+
the separate roles previously handled by:
30+
31+
- [`css-to-react-native`](https://github.com/styled-components/css-to-react-native)
32+
- [`css-to-react-native-transform`](https://github.com/kristerkari/css-to-react-native-transform)
33+
34+
The runtime and API design also benefited from studying:
35+
36+
- [`cssta`](https://github.com/jacobp100/cssta)
37+
2638
## License
2739

2840
MIT

0 commit comments

Comments
 (0)