Skip to content

fix(types): align remaining StyleX, shorthand and lint contracts - #763

Open
owjs3901 wants to merge 29 commits into
mainfrom
fix/types-and-lint-rest
Open

owjs3901 wants to merge 29 commits into
mainfrom
fix/types-and-lint-rest

Conversation

@owjs3901

@owjs3901 owjs3901 commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Refs #684 (W24: TOOL-17, JSX-13, TOOL-07, W26/W33 타입 후속)

#738(fix/types-match-build, #730 위의 스택)와 #735(fix/eslint-alias-rules, #733 포함)를 포함합니다. base는 Linux CI 검증을 위해 main이며, 이 선행 스택이 먼저 병합되어야 합니다. 18개 dead CSS 이름의 타입은 #759의 빌드 계약을 반영하므로 #759도 먼저 병합되어야 합니다.

#712는 작업 시작 시 OPEN이어서 지시대로 main을 추가 병합하지 않았고 TOOL-15는 제외했습니다. #758의 createThemeContract 타입 후속은 반영하되 그 컴파일러 변경을 병합하지 않았습니다. #715(#758에 포함)는 attrs의 style 객체를 attribute text로 바꾸므로 이 PR과 #758 중 나중에 병합되는 쪽이 attrs 타입을 조정해야 합니다. #756과 이 PR도 styleOrder 코드가 겹치므로 나중에 병합하는 쪽에서 런타임 오류와 새 정적 값 계약을 함께 보존해야 합니다.

요약

초기 hook 통과 커밋으로 PR을 연 뒤, 아래 항목을 다섯 논리 커밋으로 추가했습니다. 각 커밋의 lint/tarpaulin/Bun 훅을 통과했고, 검사한 디스크 트리와 stage한 전체 파일을 일치시켰습니다.

  • 빌드가 컴파일하는 StyleX API 전체에 opaque 스타일, 동적 함수 인자, 조건 값, 변수 계약, 부분 테마 override와 결과 타입을 제공합니다. when/env처럼 이 base에 없는 API는 추가하지 않습니다.
  • shorthand 대상의 오타를 플러그인 생성 시 공통 경계에서 거부합니다. 전체 설정이 유효한 경우에만 WASM/Rust registry를 교체하고, 대상 타입도 제한합니다.
  • styleOrder는 1~254의 정수 Number 또는 그 정규 십진 문자열입니다. 숫자 변환은 ECMAScript StringToNumber(Boa의 구현)를 사용하며 새 오류와 lint가 같은 공유 fixture를 따릅니다.
  • W26의 18개 unprefixed dead CSS 이름을 컴포넌트와 StyleX prop 타입에서 제거합니다. vendor 호환 이름, stroke-color와 ime-mode는 유지합니다.
  • fix(react): make the public and compat types accept what the build compiles #738/feat(eslint-plugin): follow the import aliases and style positions the build compiles #735 병합 후 드러난 배열 합성 lint 오탐도 수정합니다. 합성 배열은 변경하지 않고, 그 안의 실제 반응형 prop만 검사합니다.
  • 모두 Patch changepack이며 스타일링 런타임이나 의존성을 추가하지 않습니다.

동작

항목별 base 확인

항목 수정 전 확인 변경
TOOL-17 공개 create는 입력 객체를 그대로 반환하는 타입이고 동적 namespace/중첩 조건/부분 테마를 표현하지 못함. 실제 WASM은 이 형태들을 컴파일 결과는 opaque, 함수 tuple은 보존, 조건/변수/테마와 상수 문자열 결과를 타입으로 표현
JSX-13 CustomShorthands는 string[]이며 등록 경계는 정규화만 함 CSS catalog/기존 shorthand/custom property만 허용, 원래 alias/target/index를 갖는 오류, 원자적 등록
TOOL-07 이 base는 이미 100px을 무시함(옛 survey의 order100 출력은 재현 안 됨). 1e2 문자열과 1.5 숫자는 각각100/1로 잘못 적용. lint parseInt는 suffix를 허용 숫자는 실제 정수 값, 문자열은 부호/공백/leading zero 없는 십진 표기. 잘못된 정적 값은 무시하지 않고 오류
W26 새 타입 assertion은 base에서 실패. #759의 정확한18개 목록을 읽음 공통 CSS 타입에서 해당 이름 제외, prefixed/strokeColor/imeMode 회귀 유지
W33 #758 본문이 flat null/string placeholder 불일치를 명시 createThemeContract 입력을 그 flat 계약에 맞춤
TOOL-15 #712 OPEN, 이 base의 outer-theme 함수 지원 없음 변경 없음

Vite/Next/Webpack/Rsbuild/Bun은 생성 시 같은 normalizer를 호출합니다. Next의 production cache 재사용보다 먼저 검증합니다. camelCase와 kebab-case, 기존 py 등의 대상은 순서대로 정규화하며 custom property 이름은 대소문자를 보존합니다. Rust/WASM을 직접 사용하는 등록 경계도 잘못된 target을 거부하며 이전 registry를 유지합니다.

정수 Number의 100.0, 1e2, +'1\n', +'0x10'는 각각100/100/1/16으로 허용합니다. plain 문자열 '100.0', '1e2', '1\n'는 거부합니다. 조건부 JSX/jsx-runtime order의 각 정적 branch도 같은 계약을 따릅니다. 내부0과 unlayered255는 명시적인 사용자 order로 허용하지 않습니다.

StyleX의 class-string 합성도 실제 WASM으로 확인하여 props/attrs input에 허용했습니다. raw CSS 객체와 opaque StyleXStyles를 혼동하지 않고 외부 class input을 별도 타입으로 표현합니다. defineConsts의 number/boolean은 문자열 결과이며, flat 변수의 조건 객체와 부분 테마 override를 지원합니다.

새로 생기는 오류

  • styleOrder의 범위 밖 값, 소수, 비정규 문자열, 그 밖의 정적 값/조건 branch: 파일·줄·열, 원래 값, 1~254 정수 계약과 수정 방법을 포함한 빌드 오류입니다. 기존의 조용한 생략/잘림에 의존한 빌드는 실패하는 것이 의도입니다.
  • 잘못된 shorthand target: devup-ui option shorthands["bgx"][0]: shorthand "bgx" cannot use "backgroundColour" at build time: its targets must be supported CSS properties, built-in aliases or custom properties.
  • 옵션 오류 위치는 옵션 경로입니다. 실행된 JS 플러그인 옵션에는 원래 파일 span이 없으므로 가짜 파일·줄·열이나 serialization 문서를 만들지 않습니다. TypeScript 설정에서는 대상 union이 실제 설정 파일의 잘못된 줄을 짚습니다.
  • 18개 dead prop, raw 객체를 compiled StyleX 스타일로 사용하는 경우, 잘못된 함수 인자/변수 조건/테마 키/계약 placeholder는 타입 오류입니다. 새 suppression을 사용하지 않습니다.

남는 한계

검증

최종 head: d69f519392346c5b32fccf7af2fd4911b698d924. Linux CI 37351319043는 success입니다. publish/landing-next-e2e/vinext-rsc-css-e2e/benchmark 모두 성공, Rust 100.00% (11614/11614), Bun 6060 pass / 0 fail / aggregate 함수·라인100%, Codecov 업로드 성공입니다. 기존 Vite 개별 파일99.76% 표시와 LSP 제약은 별도로 남기며 CI gate와 새 줄 검증은 통과했습니다. 수정 후 Oracle delta gate는 APPROVE이며 추가 수정 요청 없음. 여섯 커밋 모두 전체 훅 통과, 작업 트리 깨끗함.

이전 37343113128은 Rust coverage99.99% (11610/11611)에서 유일한 fallback 한 줄 때문에 실패했습니다. runtime member/call이 정적 값으로 오인되지 않는 실제 회귀로 해당 경로를 검증하며 제외 설정은 추가하지 않습니다. 최종 gate 검토에서 Emotion css prop의 중첩 css() 검증 우회와 metadata 숫자의 px 변환도 발견해 d69f5193에서 수정했습니다. 새 JSX/Emotion jsx-runtime·배열 합성·위치·유효 layer 집중 회귀20개, 재빌드 WASM QA, Rust1.99 clippy와 전체 훅을 통과했습니다.

  • cargo fmt --all, Rust 1.99 strict clippy 통과.

  • cargo test --workspace: 2,229개 통과 / 0 실패 (CSS558, allocation1, WASM36, extractor1483, integration3, sheet147, doctest1). 새 snapshot 변경 없음.

  • WASM 재빌드와 루트 패키지 빌드 통과. bun test: 6,052개 통과 / 0 실패 / 함수·라인 coverage100%.

  • bun lint: 오류0, 기반의 forwardRef/use-prefix 경고2개만 유지.

  • 빌드한 dist를 별도 소비자 node_modules에 복사하여 React19 strict 검사를 통과했습니다. suppression 없는 부정 fixture의 실제 diagnostic은 target typo TS2820, 잘못된 order/dead prop TS2769, raw StyleX 객체 TS2353, numeric contract placeholder TS2322이며 의도한 줄만 실패했습니다.

  • 다섯 커밋 모두 훅 통과: 11e3f1cc, 72781be4, d7e7c631, 809f8e52, 89317347. 각 commit 당시 다른 변경은 고유 label/hash stash로 보관한 뒤 그 해시만 복원했습니다. 다른 worker의 stash를 적용·삭제하지 않았습니다. 최종 작업 트리는 깨끗합니다.

  • source 타입 테스트: React의 전체 test:types, plugin-utils shorthand test:types 통과. 새 부정 타입 검사는 suppression 없는 assignability proof입니다.

  • 모든 adapter 생성 경계의 집중 테스트4684개 통과; 최종 root suite와 재빌드된 WASM 확인은 아래 최종 결과로 대체합니다.

  • 공유 style-order fixture를 lint와 extractor가 함께 읽고, 위치/원래 코드/원인/수정 방법을 검사합니다. JSX/jsx-runtime/css/styled/keyframes 경로를 비교합니다.

  • base WASM의 실제 비교: css/styled 조건부 order는 .a{color:blue}.b{color:green}, JSX/jsx-runtime은 @layer o1과 @layer o2를 생성. StyleX 두 호출은 --a/--a, b/b를 반환하고 .b{animation-duration:1s}.b{animation-duration:2s}를 출력합니다. root/subpath import는 create/props 호출을 그대로 남깁니다.

수정 후 실제 public WASM 출력

@layer o1,o16;
@layer o1{.c{background:blue}.b{color:green}}
@layer o16{.a{color:red}}
/* +'1\\n', +'1.0'은 order1, +'0x10'은 order16 */
.g{-webkit-mask-image:url(test.png)}.c{left:1px}.a{right:1px}
@media(min-width:768px){.d{left:3px}.b{right:3px}}
.e:hover{left:5px}.f:hover{right:5px}
order-bad-jsx.tsx:2:37: `styleOrder()` cannot use `'100px'` at build time: an explicit styleOrder must be an integer from 1 to 254; a string must be canonical decimal digits without a sign, spaces or leading zeros: use a numeric literal such as 1 or a canonical decimal string such as "1"
order-bad-coercion.tsx:2:37: `styleOrder()` cannot use `+"1.5"` at build time: an explicit styleOrder must be an integer from 1 to 254; a string must be canonical decimal digits without a sign, spaces or leading zeros: use a numeric literal such as 1 or a canonical decimal string such as "1"

같은 오류를 jsx-runtime/css/styled/keyframes 경로에서도 실제로 확인했습니다. Emotion css prop의 중첩 css()도 emotion-order-jsx.tsx:2:67 및 emotion-order-runtime.tsx:2:73에서 원래 '100px' 오류를 보고하고, 유효한 +'0x10'은 @layer o16{.b{color:red}}를 생성합니다. exported registerShorthands의 typo·형식 오류 이후에도 기존 insetX registry가 유지되어 위 responsive/hover CSS가 정상 생성됩니다. browser/server 프로세스는 시작하지 않았습니다.

owjs3901 and others added 25 commits October 1, 2026 21:16
…rations

css(a, b) composing classes whose styles the build knows, bound to css() in the file or exported by another module, merges their atoms per property, selector, breakpoint and layer, conditions included, instead of joining classes whose winner the stylesheet order picked. vanilla-extract style([...]) passes each composed style as its own argument, keeping a style composed again later.

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…asurable

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…JSX spreads win

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…led order and JSX element className

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #689

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…uate shouldForwardProp at build time

Refs #689

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ring

Refs #689

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #691

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
… and conditional styles

Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…h Emotion

Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ed parameters

Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…e build compiles

Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…mpiles

Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Changepacks

@devup-ui/wasm@1.0.83 → 1.0.84 - bindings/devup-ui-wasm/package.json

Patch

  • css(a, b) composing classes whose styles the build knows (a const bound to css() in the file, or a css() result another module exports with a rule object every value of which is known) merges their styles: a later part's declaration replaces an earlier one's for the same property, selector, breakpoint and layer, also under conditions (css(base, cond && danger)) and for ||/?? parts, where the classes used to be joined and the stylesheet order picked the winner. vanilla-extract style([a, b]) passes each composed style as its own argument, so the later one wins, and a style composed again later (style([a, b, a])) is kept. Classes the build does not know (strings, props, CSS Modules) are kept as they are
  • styled(Base) extending a styled component the file binds to a const renders Base's tag directly with Base's styles composed under its own, so the extension's declarations replace Base's for the same property, selector, breakpoint and layer instead of losing to them by stylesheet order; Base's attrs apply before the extension's. attrs merge as styled-components merges them: className is joined with the caller's, style is merged and other props replace earlier ones. On an element, a className or style spread after the explicit prop now wins, as React merges props in the order they are written
  • Emotion's now compiles at build time with no runtime: the element becomes what its child function ({ css, cx, theme }) => ... renders, each css and cx call becomes the classes it composes (later styles replace earlier ones; css reads strings as CSS text and its tagged templates split around mixins; cx keeps unknown classes, reads { name: condition } objects as conditional classes and composes nested css and cx calls), and theme.a.b in their values becomes var(--a-b). Numbers in css rules are px lengths, as Emotion reads them, and top-level constants are inlined. New build errors, each at file:line:col: a without exactly one child function taking { css, cx, theme } that gives what it renders at once (attributes, other children, rest or default parameters, async or generator functions, several statements); reading the theme other than as theme.a.b in a css value; using css or cx other than by calling them; a cx object with a spread, getter or method; parts css and cx cannot compose (runtime calls, spreads, a condition choosing between styles and classes). @devup-ui/react/compat exports ClassNames with the ClassNamesContent and ClassNamesArg types, and the @emotion/react declarations include them
  • Emotion and styled-components component selectors now compile at build time: a styled component the file defines that another style selects (${Child} { ... } in CSS text, [Child] or [&:hover ${Child}] as a rule key) gets a short marker class, which only such components get, and the selector reads it as .marker; a component extending it, or an element inlining it for its css prop, keeps the marker. Selectors written without & now nest under the component as stylis nests them (ul { ... } is & ul, a selector list nests each selector, :hover applies to the component itself) instead of becoming global rules, and rule-object keys starting with ., #, [, *, >, + or ~ are read as nested selectors instead of properties
  • Emotion's css prop compiles at build time while @emotion/react is aliased: on tags and Devup UI components always, and on every element once the file imports @emotion/react or @emotion/styled or names @emotion/react in a @jsxImportSource pragma; jsx, jsxs and jsxDEV from @emotion/react/jsx-runtime (or jsx-dev-runtime) and jsx from @emotion/react compile it too, so libraries built with Emotion's JSX runtime do as well. The prop becomes the element's className, with CSS variables in its style for values only the runtime gives: arrays and conditions compose with a later part replacing what an earlier one sets, css() classes the file knows compose by their styles, strings and templates are CSS text, css`` mixins split the text around them, a function of the theme reads theme.a.b as var(--a-b), unitless numbers are px as in Emotion (constants included), and a className holding known css() classes overrides the prop as Emotion's registered classes do. A styled component the file defines renders its tag in the element's place when the prop overrides its styles and it renders a tag with no attrs or props read and the element has no spread, as or forwardedAs. Emotion's JSX runtime imports become react/jsx-runtime, the pragma names react, and jsx comes from @devup-ui/react/compat (React's createElement); @devup-ui/react/compat/css-prop types the prop on React.Attributes. New build errors, each with file:line:column and the code: a css prop part the build cannot read (a call, an element), a style object declared inside a function or with let, a binding only running the module gives or code changes, a theme function that does more than return rules or reads the theme other than as theme.a.b in a value, an interpolation CSS text cannot place or a mixin inside a nested rule, and a css prop overriding a styled component's styles where its tag cannot be rendered in place. Composing css() with a part that reads a known binding (such as a keyframes name) now reads its value
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • style-order-range only checks styleOrder where the build reads it: a prop of a Devup UI component and a top-level key of a style object passed to css/globalCss/keyframes. A styleOrder key in nested data, in a prop value such as an element passed as a prop, or in a call of a function sharing a name with an Object.prototype member is no longer reported. The array, typography and media rules already skip non-style data, and css-utils-literal-only accepts a css()/keyframes() result held in a const inside a function. No new build errors.
  • Custom shorthand targets are constrained to supported camelCase/kebab-case CSS properties, built-in aliases and valid custom properties. All five build adapters normalize options at creation before registration or extraction, including Next.js production cache reuse. Unsupported targets fail registration atomically with the original shorthand name, target and zero-based index; previously registered shorthands remain unchanged. New devup-ui option errors expose structured logical shorthands paths without inventing source coordinates. Eighteen dead unprefixed property names are rejected.
  • Validate explicit static styleOrder as an integer from 1 to 254 or its canonical decimal digit string, consistently in extraction and lint, including composed Emotion css props. Keep order metadata out of library px conversion. Invalid static values and conditional branches now produce located build errors instead of silently changing cascade order.
  • Styled components the build generates are wrapped in React's forwardRef, so a ref passed to them reaches the element they render on React 18 as well as React 19; the file imports forwardRef from react when it defines one
  • Styled components no longer pass every prop to the tag they render: $ props, theme and the props their style functions or attrs read are kept away from a tag unless it takes them as attributes, and shouldForwardProp (Emotion options or styled-components withConfig) is evaluated at build time. A shouldForwardProp the build cannot evaluate is a build error naming the file, line and code, with the forms it accepts. An element using a styled component the file defines drops props the component neither reads nor passes on; spread props are passed as written
  • Styled components render what their as prop names, defaulting to the tag or component they were defined with, and pass forwardedAs on as as, as styled-components and Emotion do; as used to reach the rendered tag as an attribute. Component.withComponent(target) on a styled component the file binds to a const builds a component rendering the same styles and attrs as target (a tag name or a component JSX can name), where it used to call a method the generated function does not have and throw

@devup-ui/bun-plugin@1.0.22 → 1.0.23 - packages/bun-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • Custom shorthand targets are constrained to supported camelCase/kebab-case CSS properties, built-in aliases and valid custom properties. All five build adapters normalize options at creation before registration or extraction, including Next.js production cache reuse. Unsupported targets fail registration atomically with the original shorthand name, target and zero-based index; previously registered shorthands remain unchanged. New devup-ui option errors expose structured logical shorthands paths without inventing source coordinates. Eighteen dead unprefixed property names are rejected.

@devup-ui/components@0.1.60 → 0.1.61 - packages/components/package.json

Patch

  • Auto-update: depends on '@devup-ui/react' via a local workspace dependency

@devup-ui/eslint-plugin@1.0.22 → 1.0.23 - packages/eslint-plugin/package.json

Patch

  • ESLint rules now check exactly what the build reads. The array, typography, media and styleOrder rules and css-utils-literal-only follow the import aliases the build compiles by default (@emotion/react, @emotion/styled, styled-components, @vanilla-extract/css) and the rules of styled (styled.div({...}), styled("div", {...}), styled(Base)({...}, {...}); not .attrs()), createGlobalStyle({...}) and the styles of Emotion Global, and check and fix a module-level const object that only styles read. Vanilla-extract stylesheets (.css.ts/.css.js) are no longer read as Devup UI. New rule no-runtime-read reports css/keyframes/styled/Box read as a value ("X is read at runtime, where it does not exist"), and css-utils-literal-only reports globals that do not exist where a .css.ts is evaluated (window, document, process, ...). No new build errors.
  • style-order-range only checks styleOrder where the build reads it: a prop of a Devup UI component and a top-level key of a style object passed to css/globalCss/keyframes. A styleOrder key in nested data, in a prop value such as an element passed as a prop, or in a call of a function sharing a name with an Object.prototype member is no longer reported. The array, typography and media rules already skip non-style data, and css-utils-literal-only accepts a css()/keyframes() result held in a const inside a function. No new build errors.
  • Do not treat composition arrays as responsive property values in the duplicate, trailing-null or single-value array rules. Preserve composition arrays and their nested responsive property diagnostics.
  • Validate explicit static styleOrder as an integer from 1 to 254 or its canonical decimal digit string, consistently in extraction and lint, including composed Emotion css props. Keep order metadata out of library px conversion. Invalid static values and conditional branches now produce located build errors instead of silently changing cascade order.

@devup-ui/next-plugin@1.0.90 → 1.0.91 - packages/next-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • Custom shorthand targets are constrained to supported camelCase/kebab-case CSS properties, built-in aliases and valid custom properties. All five build adapters normalize options at creation before registration or extraction, including Next.js production cache reuse. Unsupported targets fail registration atomically with the original shorthand name, target and zero-based index; previously registered shorthands remain unchanged. New devup-ui option errors expose structured logical shorthands paths without inventing source coordinates. Eighteen dead unprefixed property names are rejected.

@devup-ui/plugin-utils@1.0.17 → 1.0.18 - packages/plugin-utils/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • Custom shorthand targets are constrained to supported camelCase/kebab-case CSS properties, built-in aliases and valid custom properties. All five build adapters normalize options at creation before registration or extraction, including Next.js production cache reuse. Unsupported targets fail registration atomically with the original shorthand name, target and zero-based index; previously registered shorthands remain unchanged. New devup-ui option errors expose structured logical shorthands paths without inventing source coordinates. Eighteen dead unprefixed property names are rejected.
  • Types now accept what the build compiles and nothing it rejects. css() takes classes, style objects, arrays and falsy parts, and the css/keyframes/globalCss tags take the static interpolations the build evaluates. styled gets .attrs(), .withConfig() and .withComponent(), and its result renders another tag. styleVars takes numbers; styleOrder is 1 to 254; ResponsiveValue is exported for hand-written custom shorthands. The compat declarations name what Emotion, styled-components and vanilla-extract give (SerializedStyles, Keyframes, RuleSet, an augmentable Theme and DefaultTheme, CSSObject and the other styled-components types) and follow the vanilla-extract APIs the evaluator registers (style arrays, the styleVariants mapper, createGlobalTheme, createGlobalThemeContract; globalKeyframes, composeStyles and generateIdentifier are gone). DevupTheme takes shadow as devup.json documents it. No new build errors.

@devup-ui/react@1.0.44 → 1.0.45 - packages/react/package.json

Patch

  • Reject the 18 unprefixed legacy flexbox and scroll-snap properties rejected by the compiler in component and StyleX property types. Keep vendor-prefixed compatibility properties, stroke-color and ime-mode.
  • Emotion's now compiles at build time with no runtime: the element becomes what its child function ({ css, cx, theme }) => ... renders, each css and cx call becomes the classes it composes (later styles replace earlier ones; css reads strings as CSS text and its tagged templates split around mixins; cx keeps unknown classes, reads { name: condition } objects as conditional classes and composes nested css and cx calls), and theme.a.b in their values becomes var(--a-b). Numbers in css rules are px lengths, as Emotion reads them, and top-level constants are inlined. New build errors, each at file:line:col: a without exactly one child function taking { css, cx, theme } that gives what it renders at once (attributes, other children, rest or default parameters, async or generator functions, several statements); reading the theme other than as theme.a.b in a css value; using css or cx other than by calling them; a cx object with a spread, getter or method; parts css and cx cannot compose (runtime calls, spreads, a condition choosing between styles and classes). @devup-ui/react/compat exports ClassNames with the ClassNamesContent and ClassNamesArg types, and the @emotion/react declarations include them
  • Emotion's css prop compiles at build time while @emotion/react is aliased: on tags and Devup UI components always, and on every element once the file imports @emotion/react or @emotion/styled or names @emotion/react in a @jsxImportSource pragma; jsx, jsxs and jsxDEV from @emotion/react/jsx-runtime (or jsx-dev-runtime) and jsx from @emotion/react compile it too, so libraries built with Emotion's JSX runtime do as well. The prop becomes the element's className, with CSS variables in its style for values only the runtime gives: arrays and conditions compose with a later part replacing what an earlier one sets, css() classes the file knows compose by their styles, strings and templates are CSS text, css`` mixins split the text around them, a function of the theme reads theme.a.b as var(--a-b), unitless numbers are px as in Emotion (constants included), and a className holding known css() classes overrides the prop as Emotion's registered classes do. A styled component the file defines renders its tag in the element's place when the prop overrides its styles and it renders a tag with no attrs or props read and the element has no spread, as or forwardedAs. Emotion's JSX runtime imports become react/jsx-runtime, the pragma names react, and jsx comes from @devup-ui/react/compat (React's createElement); @devup-ui/react/compat/css-prop types the prop on React.Attributes. New build errors, each with file:line:column and the code: a css prop part the build cannot read (a call, an element), a style object declared inside a function or with let, a binding only running the module gives or code changes, a theme function that does more than return rules or reads the theme other than as theme.a.b in a value, an interpolation CSS text cannot place or a mixin inside a nested rule, and a css prop overriding a styled component's styles where its tag cannot be rendered in place. Composing css() with a part that reads a known binding (such as a keyframes name) now reads its value
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • Type every compiled StyleX API with opaque styles, dynamic function arguments, conditional variables, partial themes and static null/string theme contract placeholders. Unsupported runtime shapes are rejected by TypeScript; no new build errors in this change.
  • Types now accept what the build compiles and nothing it rejects. css() takes classes, style objects, arrays and falsy parts, and the css/keyframes/globalCss tags take the static interpolations the build evaluates. styled gets .attrs(), .withConfig() and .withComponent(), and its result renders another tag. styleVars takes numbers; styleOrder is 1 to 254; ResponsiveValue is exported for hand-written custom shorthands. The compat declarations name what Emotion, styled-components and vanilla-extract give (SerializedStyles, Keyframes, RuleSet, an augmentable Theme and DefaultTheme, CSSObject and the other styled-components types) and follow the vanilla-extract APIs the evaluator registers (style arrays, the styleVariants mapper, createGlobalTheme, createGlobalThemeContract; globalKeyframes, composeStyles and generateIdentifier are gone). DevupTheme takes shadow as devup.json documents it. No new build errors.

@devup-ui/reset-css@1.0.31 → 1.0.32 - packages/reset-css/package.json

Patch

  • Auto-update: depends on '@devup-ui/react' via a local workspace dependency

@devup-ui/rsbuild-plugin@1.0.67 → 1.0.68 - packages/rsbuild-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • Custom shorthand targets are constrained to supported camelCase/kebab-case CSS properties, built-in aliases and valid custom properties. All five build adapters normalize options at creation before registration or extraction, including Next.js production cache reuse. Unsupported targets fail registration atomically with the original shorthand name, target and zero-based index; previously registered shorthands remain unchanged. New devup-ui option errors expose structured logical shorthands paths without inventing source coordinates. Eighteen dead unprefixed property names are rejected.

@devup-ui/vite-plugin@1.0.73 → 1.0.74 - packages/vite-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • Custom shorthand targets are constrained to supported camelCase/kebab-case CSS properties, built-in aliases and valid custom properties. All five build adapters normalize options at creation before registration or extraction, including Next.js production cache reuse. Unsupported targets fail registration atomically with the original shorthand name, target and zero-based index; previously registered shorthands remain unchanged. New devup-ui option errors expose structured logical shorthands paths without inventing source coordinates. Eighteen dead unprefixed property names are rejected.

@devup-ui/webpack-plugin@1.0.71 → 1.0.72 - packages/webpack-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • Custom shorthand targets are constrained to supported camelCase/kebab-case CSS properties, built-in aliases and valid custom properties. All five build adapters normalize options at creation before registration or extraction, including Next.js production cache reuse. Unsupported targets fail registration atomically with the original shorthand name, target and zero-based index; previously registered shorthands remain unchanged. New devup-ui option errors expose structured logical shorthands paths without inventing source coordinates. Eighteen dead unprefixed property names are rejected.

owjs3901 and others added 4 commits October 6, 2026 01:14
Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #684

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@codecov

codecov Bot commented Oct 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
bindings/devup-ui-wasm/src/lib.rs 100.00% <ø> (ø)
libs/css/src/lib.rs 100.00% <100.00%> (ø)
libs/css/src/shorthand.rs 100.00% <100.00%> (ø)
libs/css/src/theme_tokens.rs 100.00% <ø> (ø)
libs/extractor/src/build_time_values.rs 100.00% <100.00%> (ø)
libs/extractor/src/composition.rs 100.00% <100.00%> (ø)
libs/extractor/src/css_prop.rs 100.00% <100.00%> (ø)
libs/extractor/src/css_utils.rs 100.00% <100.00%> (ø)
...tor/src/extractor/extract_style_from_expression.rs 100.00% <100.00%> (ø)
...tractor/src/extractor/extract_style_from_styled.rs 100.00% <100.00%> (ø)
... and 43 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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