Skip to content

fix(extractor): preserve JavaScript semantics across values and element calls - #756

Open
owjs3901 wants to merge 38 commits into
mainfrom
fix/js-semantics
Open

owjs3901 wants to merge 38 commits into
mainfrom
fix/js-semantics

Conversation

@owjs3901

@owjs3901 owjs3901 commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Refs #695 (F: FN-08, FN-09, JSX-02, JSX-06, JSX-09, JSX-12, FN-04 및 namespace runtime escape)

이 PR은 #750 위에 쌓인 PR이며 GitHub base는 main입니다. #750 및 그 기반인 #742/#737/composition 선행 PR이 먼저 병합되어야 합니다. 이 PR 또는 #741 중 나중에 병합하는 PR에 동일한 UI 키트 props 재배치가 적용되어야 합니다. Radio의 1px sold 오타는 #741 소유 변경이므로 여기에서는 수정하지 않았습니다.

요약

  • 모듈 간 computed enum과 EXACT_MATH 20개 멤버의 결과를 동일하게 처리합니다. primitive operand만 Boa에 전달하며 모듈 코드 실행은 추가하지 않습니다. 음수 0도 JavaScript literal 경계에서 보존합니다.
  • 중첩 scope의 안정적인 primitive const를 SymbolId로 읽고, type-only import를 유지합니다. shadow된 require는 CommonJS loader가 아닌 일반 호출로 취급하여 해당 경로를 resolve하지 않습니다.
  • JSX/React createElement/jsx-runtime lowering에서 원본 props 평가와 스타일 선택을 분리합니다. 덮어쓴 표현식도 실행하고 getter/iterator/coercion을 원래 위치에서 한 번만 평가합니다.
  • unknown spread 뒤에서 덮어쓸 수 있는 명시적 flat style은 CSS 변수와 정적 fallback을 사용합니다. 원본 JavaScript의 native object copy와 computed lookup을 보존하며 CSS 정규화 런타임이나 의존성은 추가하지 않습니다.
  • immediate lexical TDZ 읽기는 원래 읽기 위치의 오류가 됩니다. deferred initialized 읽기는 계속 folding하고, assignment 이전 var 읽기는 dynamic CSS variable을 사용합니다.
  • UI 키트 6종은 pure props reordering만 수행했습니다. 일반 DOM props는 spread 앞에 남겨 사용자 override 순서를 유지하고, 오류가 요구한 selector/compound 기본값만 뒤로 옮겼습니다. reset-css는 compile-only namespace spy 대신 실제 compiled code/CSS를 검증합니다.
  • WASM, components, reset-css changepack은 모두 Patch입니다.

동작

JavaScript 평가와 JSX-02 우선순위

<Box {...rest} color="red"/>의 명시적 값은 항상 이깁니다. <Box color="red" {...rest}/>는 마지막 own enumerable color가 변수에 전달되며, 키가 없으면 red로 fallback합니다. 나중 spread의 own undefined/null은 이전 spread 값을 다시 살리지 않습니다. inherited/non-enumerable key는 복사하지 않고 symbol 및 nullish spread는 native JavaScript 동작을 유지합니다. spread에만 존재하는 key는 DOM/pass-through로 남습니다.

responsive 값은 breakpoint마다 다른 fallback을 유지하면서 하나의 override variable을 공유합니다. 정적 theme fallback은 var(--token)을 유지합니다. Devup 기반 styled instance는 component/ref/theme/attrs를 유지하면서 명시적 style props를 컴파일하고, plain-tag styled의 기존 동작은 바꾸지 않습니다.

native { __proto__: null, ...source }는 getter 값을 DOM/className/style/slot이 함께 사용하는 데이터 스냅샷입니다. React 호출은 가능한 경우 props 인자만 감싸므로 callee/receiver lookup이 props보다 먼저, children/key가 props보다 뒤에서 평가됩니다. dynamic as가 필요한 경우에도 이 순서를 보존합니다. computed table은 native selection을 한 번 실행하고 primitive 분기 tag/이미 평가한 leaf를 공유하므로 static 숫자 scale, token, typography, keyframes 및 Tailwind 정적 규칙을 유지합니다.

실제 ReactDOMServer에서 getter 총 실행 횟수는 1, 덮어쓴 explicit effect와 missing-key effect의 trace는 모두 12로 검증했습니다. whole-emitted-props Boa 회귀는 오류·던지는 getter·분기 laziness·식별자 변이·일반 attrs/className/style/children·factory receiver·hygiene·shadowed globals를 함께 실행합니다.

UI 키트 컴파일 전후

기준 컴파일러 29812f37로 Button/Checkbox/Input/Radio/Select/Textarea를 컴파일하고 selector sentinel을 전달해 SSR했습니다. selector 객체는 DOM 속성으로만 전달되었고 sentinel CSS 규칙은 0개였습니다. 재배치는 작동하던 selector override를 제거하지 않습니다.

debug CSS를 비교하면 재배치 전/후(동일한 기준 컴파일러)는 34,225 bytes, byte-identical입니다. 새 컴파일러 출력은 41,756 bytes이고 JSX-02 scalar fallback 규칙은 89개입니다. 각 fallback을 원래 값으로 정규화하면 추가 규칙 0/삭제 규칙 0입니다. 아래에 실제 compact CSS 전/후와 89개 차이를 모두 기재합니다. compact class/variable 이름은 추출 순서에 따라 바뀔 수 있으며 이름 변경 자체는 CSS 값 변경이 아닙니다.

새로 생기는 오류

모든 오류는 file:line:col: ... cannot use ... at build time: ... 형식입니다.

  • unknown spread 또는 unknown computed key가 이전 selector/typography/css whole object를 덮어쓸 수 있고 stylesheet가 이를 정확히 따라갈 수 없는 경우: spread를 해당 명시적 prop 앞에 쓰도록 안내합니다.
  • computed key/accessor가 포함된 opaque literal snapshot이 명시적 selector 또는 @media/@supports를 숨기는 경우: selector를 spread 뒤의 명시적 prop으로 쓰도록 안내합니다. 조용히 DOM 객체로 보내지 않습니다.
  • stylesheet 순서를 알 수 없는 runtime styleOrder와 unsupported 조건/논리 branch: build-known 숫자 또는 숫자 사이 조건식이 필요합니다. shadow된 undefined 및 effectful void도 버리지 않습니다.
  • compile-only Devup namespace를 통째로 runtime에 전달하는 경우(spyOn(ns, 'css') 등): named member/import 사용을 안내합니다. type query와 shadow된 다른 객체는 유지됩니다.
  • 초기화 전 let/const/class style 읽기: 읽기 위치, binding 이름, 원본 ReferenceError 원인, 선언을 use 위로 이동하는 수정 방법을 포함합니다.
  • 생성된 동기 props wrapper로 옮길 수 없는 lazy logical await/yield: 원래 async/generator scope에서 값을 변수로 평가한 뒤 렌더링하도록 안내합니다. 단순 await/yield 인자 capture는 caller scope에 남겨 지원합니다.

남는 한계

  • unknown spread의 raw token 문자열 또는 responsive array를 runtime에 정규화하지 않습니다. 값은 raw CSS variable 또는 pass-through이며 styling runtime은 없습니다.
  • function-local object의 written-out key spread folding/composition은 이 기준에 W27이 없으므로 W27(fix/composition-rest) 소유 범위로 남겼습니다.
  • runtime className/external class와의 조합은 CSS cascade를 따릅니다. 빌드가 모르는 whole-object 스타일은 위치가 있는 오류로 처리합니다.
  • 자동 merge/approve/close는 수행하지 않습니다.

검증

  • 모든 원래 항목을 29812f37 기준에서 먼저 probe하여 오류/잘못된 결과를 확인했습니다. 아래 전후 요약과 실제 출력이 포함됩니다.
  • cargo fmt, Rust 1.99 workspace/all-target Clippy -D warnings, full workspace tests 및 root lint 통과했습니다. Rust LSP daemon은 반복 timeout, TS LSP는 기존 설치 거절 상태라 compiler/Clippy/build를 실제 대체 증거로 사용했습니다.
  • 최근 full extractor 1,948 tests 통과, CSS 530, WASM 34, sheet 148, 관련 integration/alloc tests도 모두 통과했습니다.
  • WASM rebuild + root package build 통과, 로컬 Bun 5,504 pass / 0 fail, Linux CI Bun 5,512 pass / 0 fail, **functions/lines 모두 100%**입니다.
  • public WASM + ReactDOMServer QA: 21 renders + located-error probe, 실패 0. UI kit SSR 6종, pure-reorder CSS byte equality, 모든 fallback 차이 정규화 검증 통과했습니다.
  • 이전 read-only gate 재검토에서 original 7개 결함 모두 PASS를 받았고 추가 2개 변형도 회귀로 재현·수정했습니다(gate_edges 18 pass). 이번 coverage 구조 변경은 별도의 foreground read-only Oracle에서 PASS를 받았습니다. 원본 negative 입력을 유지했습니다.
  • 초기 5개 및 후속 6개 커밋 모두 bun lint + Rust tarpaulin + bun test 전체 hook을 통과했습니다. Windows default coverage는97.20%이며 이를100%로 주장하지 않습니다. 최종 기준인 **Linux Rust coverage는100.00%(13312/13312)**입니다. 보고된64개 미커버 라인은51개 의미 있는 회귀와 class 초기화/known-spread helper 분리, 이미 처리된 중복 fallback 제거로 해결했습니다. coverage 제외·경고 억제·의존성·styling runtime 추가는 없습니다.
  • 최종 CI 37230449955 SUCCESS, head f0969a040ed4f926965468cd27fc92387bb84fa8: publish, landing-next-e2e, benchmark, vinext-rsc-css-e2e 및 codecov/patch 모두 성공했습니다. publish의 Vite landing E2E도 per-file/singleCss 모두 통과했습니다. 이전 실패99.52% 및 중간99.75%를 거쳐100%를 확인했습니다.

기준 결과 요약

항목 29812f3 변경 후
FN-08 imported E.B located build error height:20px
FN-09 imul/clz32/fround 각 imported 값 build error width:48px / 124px / 6px
signed zero consumer 잘못된 red Object.is(...,-0)에 따른 green
JSX-02 spread-after 스타일 override 손실 native snapshot + CSS variable/fallback
JSX-06 createElement compile-only Box runtime 읽기 오류 div 호출 및 children/key/ref 유지
JSX-09 runtime styleOrder 조용히 제거 original-span 오류
JSX-12 nested const CSS variable green/24px 정적 classes
FN-04 type imports import 제거 type declarations/imports 유지
whole namespace runtime spy/읽기 named member 안내 located 오류
TDZ later initializer가 잘못 folding read-position ReferenceError 진단
shadowed require 외부 모듈로 오인 resolve 해당 specifier resolve 0회, global require control 유지
실제 전후 components CSS 공통 prefix 전체 (8171자; 아래 before/after 각각 앞에 동일하게 붙이면 해당 실제 전체 출력)
/*! devup-ui v1.0.82, | Apache License 2.0 | https://devup-ui.com */@layer b,t,o1,o2;@layer t{:root{color-scheme:light;--background:light-dark(#F5F5F5,#202020);--base:light-dark(#FFF,#000);--base50:light-dark(#FFFFFF80,#00000080);--black:#000;--black5:#0000000D;--black50:#00000080;--border:light-dark(#E4E4E4,#434343);--borderBold:light-dark(#BCBCBC,#535353);--caption:#787878;--codeBackground:light-dark(#F5F5F5,#2E2E2E);--containerBackground:light-dark(#FFF,#1E1E1E);--containerHover:light-dark(#EEE,#3A3A3A);--containerPush:light-dark(#DADAE1,#606066);--error:light-dark(#D52B2E,#FF5B5E);--familyHover:light-dark(#A0A1A5,#94969E);--familysiteBg:light-dark(#828389,#B0B0B0);--familysiteTxt:#272727;--filterBg:light-dark(#EFEEF2,#4B494F);--footerAward:light-dark(#EAEAED,#3D3D3D);--footerBackground:light-dark(#2F313B,#D8D8D8);--footerBody:light-dark(#FFF,#404040);--footerCaption:light-dark(#CACACA,#7D7D7D);--footerLink:light-dark(#B7B5C0,#5E6063);--footerNavTitle:light-dark(#98989D,#747276);--footerTitle:light-dark(#F2F2F2,#1F1F1F);--gnbBg:light-dark(#FFFC,#000C);--iconBold:light-dark(#8D8C9A,#666577);--info:#2196F3;--inputBg:light-dark(#FFF,#2E2E2E);--inputCaption:light-dark(#9B9BA6,#C3C2C8);--inputDisabledBg:light-dark(#F0F0F3,#414244);--inputDisabledText:light-dark(#D6D7DE,#373737);--inputIcon:light-dark(#C3C2C8,#696A6F);--inputPlaceholder:light-dark(#A9A8AB,#CBCBCB);--kakaoHover:light-dark(#F0C81A,#FFE232);--kakoBg:#FFE232;--link:light-dark(#7C8EE1,#006BFF);--negative10:light-dark(#0000001A,#FFFFFF1A);--negative20:light-dark(#0003,#FFF6);--negativeBase:light-dark(#000,#FFF);--placeHolder:#9D9D9D;--primary:light-dark(#674DC7,#8163E1);--primary20:light-dark(#614FC433,#7D6DD833);--primary50:light-dark(#614FC480,#7D6DD880);--primaryActive:light-dark(#312395,#BEB3ED);--primaryBg:light-dark(#F4F3FA,#F4F3FA0D);--primaryFocus:light-dark(#9385D3,#927CE4);--primaryHover:light-dark(#4D38AE,#A290E7);--secondary:light-dark(#E3E0F2,#272331);--selectBoxBg:light-dark(#00000012,#FFFFFF12);--selectDisabled:light-dark(#C4C5D1,#45464D);--snackBg:#29292CCC;--snackLink:light-dark(#B2B0EF,#7C8EE1);--success:light-dark(#2CA353,#4CAF50);--tableSearch:light-dark(#FFED8A,#B55100);--text:light-dark(#272727,#F6F6F6);--textFixed:#272727;--title:light-dark(#1A1A1A,#FAFAFA);--toggleBg:light-dark(#E4E4E4,#383838);--warning:#FF9800;--white:#FFF;--white10:light-dark(#FFFFFF1A,#0000001A)}:root[data-theme=dark]{color-scheme:dark}.typo-body{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:400;line-height:24px;letter-spacing:-.01em}.typo-buttonM{font-family:Pretendard;font-size:16px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:0}.typo-buttonS{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:0}.typo-buttonxs{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:600;line-height:1.2;letter-spacing:-.02em}.typo-footerL{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:500;line-height:1.3;letter-spacing:-.02em}.typo-footerList{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:500;line-height:1.2;letter-spacing:-.02em}.typo-footerM{font-family:Pretendard;font-size:13px;font-style:normal;font-weight:300;line-height:18px;letter-spacing:-.01em}.typo-footerMsemibold{font-family:Pretendard;font-size:13px;font-style:normal;font-weight:600;line-height:18px;letter-spacing:-.01em}.typo-footerNav{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:500;line-height:1.3;letter-spacing:-.02em}.typo-footerS{font-family:Pretendard;font-size:12px;font-style:normal;font-weight:300;line-height:1.2;letter-spacing:-.02em}.typo-footerSsemibold{font-family:Pretendard;font-size:12px;font-style:normal;font-weight:600;line-height:1.2;letter-spacing:-.02em}.typo-footerXSsemibold{font-family:Pretendard;font-size:10px;font-style:normal;font-weight:600;line-height:18px;letter-spacing:-.02em}.typo-footerxl{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:700;line-height:1.3;letter-spacing:-.02em}.typo-footerxs{font-family:Pretendard;font-size:10px;font-style:normal;font-weight:300;line-height:1.2;letter-spacing:-.02em}.typo-inlineLabelL{font-family:Pretendard;font-size:16px;font-style:normal;font-weight:500;line-height:1.3;letter-spacing:-.03em}.typo-inlineLabelS{font-family:Pretendard;font-size:12px;font-style:normal;font-weight:500;line-height:1.3;letter-spacing:-.03em}.typo-inputBold{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:-.02em}.typo-inputPhBold{font-family:Pretendard;font-size:13px;font-style:normal;font-weight:600;line-height:1.2;letter-spacing:-.02em}.typo-inputPlaceholder{font-family:Pretendard;font-size:13px;font-style:normal;font-weight:400;line-height:1.2;letter-spacing:-.02em}.typo-inputText{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:400;line-height:1.2;letter-spacing:-.02em}.typo-langButton{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:-.02em}.typo-langMenu{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:500;line-height:1.2;letter-spacing:-.02em}.typo-pagination{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:600;line-height:1.2;letter-spacing:-.02em}.typo-paginationSelected{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:900;line-height:1.2;letter-spacing:-.02em}.typo-resetButton{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:-.02em}.typo-subMenu{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:600;line-height:24px;letter-spacing:-.01em}.typo-tableText{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:400;line-height:24px;letter-spacing:-.01em}.typo-tableTextBold{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:600;line-height:24px;letter-spacing:-.01em}.typo-tableTitle{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:600;line-height:1.2;letter-spacing:-.01em}.typo-uploadButton{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:600;line-height:24px;letter-spacing:-.01em}@media(min-width:1280px){.typo-body{font-family:Pretendard;font-size:16px;font-style:normal;font-weight:400;line-height:24px;letter-spacing:-.01em}.typo-buttonM{font-family:Pretendard;font-size:18px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:-.01em}.typo-buttonS{font-family:Pretendard;font-size:16px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:-.01em}.typo-buttonxs{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:600;line-height:1.2;letter-spacing:-.03em}.typo-inlineLabelL{font-family:Pretendard;font-size:18px;font-style:normal;font-weight:500;line-height:1.3;letter-spacing:-.03em}.typo-inputBold{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:-.02em}.typo-inputPhBold{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:600;line-height:1.2;letter-spacing:-.02em}.typo-inputPlaceholder{font-family:Pretendard;font-size:14px;font-style:normal;font-weight:400;line-height:1.2;letter-spacing:-.02em}.typo-inputText{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:400;line-height:1.2;letter-spacing:-.03em}.typo-langButton{font-family:Pretendard;font-size:16px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:-.02em}.typo-resetButton{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:700;line-height:1.2;letter-spacing:-.02em}.typo-subMenu{font-family:Pretendard;font-size:16px;font-style:normal;font-weight:600;line-height:24px;letter-spacing:-.01em}.typo-tableText{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:400;line-height:1.4;letter-spacing:-.01em}.typo-tableTextBold{font-family:Pretendard;font-size:15px;font-style:normal;font-weight:600;line-height:1.2;letter-spacing:-.01em}.typo-tableTitle{font-family:Pretendard;font-size:16px;font-style:normal;font-weight:600;line-height:1.2;letter-spacing:-.01em}}}
실제 components before CSS 나머지 전체 (위 공통 prefix 바로 뒤에 이어지는 출력)
@layer b{.an{align-items:center}.al{display:flex}.f4{flex-direction:column}.am{justify-content:center}}@keyframes g3{0%{transform:rotateZ(0)}100%{transform:rotateZ(360deg)}}@layer o1{.dh{accent-color:var(--primary,light-dark(#6159D4,#6670F9))}.ek{align-items:center}.di{appearance:none}.ex{background:light-dark(#FFF,#2E2E2E)}.l{background:var(--background,light-dark(#FFF,#2E2E2E))}.e_{background:var(--bg,light-dark(#FFF,#2E2E2E))}.g1{background:var(--border,light-dark(#E4E4E4,#434343))}.b0{background:var(--inputBackground,#FFF)}.dj{background:var(--inputBg,light-dark(#FFF,#2E2E2E))}.el{background:var(--negative20,light-dark(#0003,#FFF6))}.b1{background:var(--primary,#8163E1)}.ey{border:1px solid}.b2{border:1px solid var(--border,#E4E4E4)}.dk{border:1px solid var(--border,light-dark(#E0E0E0,#333))}.f5{border:1px solid var(--border,light-dark(#E4E4E4,#434343))}.b3{border:none}.ez{border-color:var(--border)}.m{border-color:var(--border,light-dark(#E4E4E4,#434343))}.eg{border-color:var(--error,light-dark(#D52B2E,#FF5B5E))}.fb{border-radius:0 8px 8px 0}.e0{border-radius:100%}.b4{border-radius:10px}.dl{border-radius:2px}.em{border-radius:50%}.gp{border-radius:6px}.n{border-radius:8px}.fa{border-radius:8px 0 0 8px}.o{border-style:solid}.p{border-width:1px}.f6{bottom:-4px}.aa{bottom:-8px}.f7{box-shadow:0 2px 2px 0 var(--base10,light-dark(#0000001A,#FFFFFF1A))}.b5{box-sizing:border-box}.b8{color:#FFF}.ep{color:var(--base,light-dark(#FFF,#000))}.b7{color:var(--error,#D52B2E)}.ab{color:var(--error,light-dark(#D52B2E,#FF5B5E))}.d5{color:var(--iconBold,light-dark(#8D8C9A,#666577))}.d4{color:var(--inputDisabledText,light-dark(#D6D7DE,#373737))}.gr{color:var(--primary,light-dark(#674DC7,#8163E1))}.gq{color:var(--selectDisabled,light-dark(#C4C5D1,#45464D))}.b6{color:var(--text,#272727)}.fc{color:var(--text,light-dark(#000,#FFF))}.q{color:var(--text,light-dark(#272727,#F6F6F6))}.gs{color:var(--title,light-dark(#1A1A1A,#FAFAFA))}.gt{cursor:default}.dm{cursor:not-allowed}.b9{cursor:pointer}.dn{display:block}.eq{display:flex}.fq{display:inline-block}.eu{display:none}.ac{font-size:12px}.b_{font-size:14px}.cb{font-size:15px}.r{font-size:16px}.gu{font-weight:400}.cd{font-weight:700}.gw{gap:0}.gv{gap:10px}.f8{gap:6px}.do{height:100%}.e1{height:18px}.g2{height:1px}.en{height:20px}.d2{height:24px}.gx{height:40px}.fr{height:fit-content}.er{justify-content:center}.a-d{left:0}.d6{left:12px}.ce{letter-spacing:-.02em}.cg{letter-spacing:0}.t{line-height:1.5}.dp{margin:0}.u{min-height:80px}.f9{min-width:232px}.ev{opacity:0}.dq{opacity:1}.ci{outline-offset:2px}.f_{padding:10px}.v{padding:12px}.es{padding:2px}.cx{padding-bottom:10px}.cw{padding-bottom:12px}.cy{padding-bottom:8px}.gz{padding-left:10px}.cs{padding-left:12px}.cr{padding-left:16px}.cq{padding-left:20px}.cv{padding-left:24px}.cu{padding-left:28px}.ct{padding-left:32px}.eh{padding-left:36px}.gy{padding-right:10px}.cm{padding-right:12px}.cl{padding-right:16px}.ck{padding-right:20px}.cp{padding-right:24px}.co{padding-right:28px}.cn{padding-right:32px}.ei{padding-right:36px}.c0{padding-top:10px}.cz{padding-top:12px}.c1{padding-top:8px}.dr{pointer-events:none}.ae{position:absolute}.ga{position:fixed}.cj{position:relative}.et{right:12px}.ds{top:0}.d7{top:50%}.d8{transform:translateY(-50%)}.af{transform:translateY(100%)}.c2{transition:.25s}.ej{transition:all .1s ease-in-out}.g0{transition:background-color .1s ease-in-out}.fl{transition:background-color .25s,border-color .25s}.z{transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.gb{user-select:none}._{width:100%}.e9{width:18px}.eo{width:20px}.d3{width:24px}.fm{width:fit-content}.dt{z-index:0}.gc{z-index:1}@media(min-width:1280px){.s{font-size:14px}.ca{font-size:15px}.cc{font-size:16px}.ch{letter-spacing:-.01em}.cf{letter-spacing:-.03em}}.bj:hover{background:color-mix(in srgb,var(--primary,#674DC7) 100%,#000 15%)}.bi:hover{background:color-mix(in srgb,var(--primary,#8163E1) 10%,#FFF 90%)}.df:hover{background:light-dark(color-mix(in srgb,var(--primary,#6159D4) 10%,#FFF 90%),color-mix(in srgb,var(--primary,#6670F9) 20%,#000 80%))}.go:hover{background:var(--primaryBg,light-dark(#F4F3FA,#F4F3FA0D))}.dg:hover{border:1px solid var(--primary,light-dark(#6159D4,#6670F9))}.ee:hover{border:1px solid var(--primary,light-dark(#674DC7,#8163E1))}.bh:hover{border-color:var(--error,#D52B2E)}.bg:hover{border-color:var(--primary,#8163E1)}.j:hover{border-color:var(--primary,light-dark(#674DC7,#8163E1))}:root[data-theme=dark] .bt:hover{background:color-mix(in srgb,var(--primary,#674DC7) 10%,var(--inputBackground,#2E2E2E) 90%)}:root[data-theme=dark] .bu:hover{background:color-mix(in srgb,var(--primary,#8163E1) 100%,#FFF 15%)}:root[data-theme=dark] .bs:hover{border-color:var(--error,#FF5B5E)}:root[data-theme=dark] .br:hover{border-color:var(--primary,#8163E1)}:root[data-theme=dark] .bv:hover{outline-color:var(--primary,#674DC7)}.bd:focus-visible{outline:2px solid}.bf:focus-visible{outline-color:var(--error,#FF5B5E)}.be:focus-visible{outline-color:var(--primaryFocus,#9385D3)}:root[data-theme=dark] .bx:focus-visible{outline-color:var(--error,#D52B2E)}:root[data-theme=dark] .bw:focus-visible{outline-color:var(--primaryFocus,#927CE4)}.ec:focus{background:var(--primaryBg,light-dark(#F4F3FA,#F4F3FA0D))}.ed:focus{border:1px solid var(--primary,light-dark(#674DC7,#8163E1))}.g:focus{border-color:var(--primary,light-dark(#674DC7,#8163E1))}.h:focus{box-shadow:0 0 0 3px var(--focusRing,light-dark(#674DC726,#8163E140))}.ew:focus{outline:1px sold var(--border,var(--primary))}.i:focus{outline:none}.a_:active{background:color-mix(in srgb,var(--primary,#674DC7) 100%,#000 30%)}.a5:active{background:color-mix(in srgb,var(--primary,#8163E1) 20%,#FFF 80%)}.c_:active{background:light-dark(color-mix(in srgb,var(--primary,#6159D4) 20%,#FFF 80%),color-mix(in srgb,var(--primary,#6670F9) 30%,#000 70%))}.a6:active{background:var(--error,#D52B2E)}.a8:active{border:1px solid var(--error,#D52B2E)}.a7:active{border:1px solid var(--primary,#8163E1)}.a9:active{color:var(--text,#272727)}:root[data-theme=dark] .bn:active{background:color-mix(in srgb,var(--primary,#8163E1) 100%,#FFF 30%)}:root[data-theme=dark] .bl:active{background:var(--error,#FF5B5E)}:root[data-theme=dark] .bk:active{background:var(--primary,#8163E1)}:root[data-theme=dark] .bm:active{color:var(--text,#F6F6F6)}.de:disabled{background:light-dark(#F0F0F3,#47474A)}.b:disabled{background:var(--disabledBg,light-dark(#F0F0F3,#414244))}.d_:disabled{background:var(--inputDisabledBg,light-dark(#F0F0F3,#414244))}.bb:disabled{background-color:#F0F0F3}.ea:disabled{border:1px solid var(--border,light-dark(#E4E4E4,#434343))}.bc:disabled{border-color:var(--border,#E4E4E4)}.c:disabled{border-color:var(--border,light-dark(#E4E4E4,#434343))}.ba:disabled{color:#D6D7DE}.d:disabled{color:var(--disabledText,light-dark(#D6D7DE,#373737))}.eb:disabled{color:var(--inputDisabledText,light-dark(#D6D7DE,#373737))}.e:disabled{cursor:not-allowed}.f:disabled{opacity:.5}:root[data-theme=dark] .bp:disabled{background-color:#47474A}:root[data-theme=dark] .bq:disabled{border-color:transparent}:root[data-theme=dark] .bo:disabled{color:#373737}.fs{box-sizing:border-box}.ft *{box-sizing:border-box}.ef::placeholder{color:var(--inputPlaceholder,light-dark(#A9A8AB,#CBCBCB))}.k::placeholder{color:var(--placeholder,light-dark(#A9A8AB,#CBCBCB))}.da:checked{background:var(--primary,light-dark(#6159D4,#6670F9))}.db:checked{border:none}.dd:checked:disabled{background:light-dark(#F0F0F3,#47474A)}.dc:checked:hover{background:light-dark(color-mix(in srgb,var(--primary,#6159D4) 100%,#000 15%),color-mix(in srgb,var(--primary,#6670F9) 100%,#FFF 15%))}.e2:checked:not(:disabled){background:var(--checkedBg,var(--primary,light-dark(#FFF,#2E2E2E)))}.e3:checked:not(:disabled){border:3px solid}.e4:checked:not(:disabled){border-color:var(--checkedBg,light-dark(#FFF,#2E2E2E))}.e5:checked:not(:disabled){box-shadow:0 0 0 1px var(--checkedBorder,var(--primary))}.a:disabled::placeholder{color:var(--disabledText,light-dark(#D6D7DE,#373737))}.d9:disabled::placeholder{color:var(--inputDisabledText,light-dark(#D6D7DE,#373737))}.e7:hover:not(:disabled,:checked){background:var(--hoverBg,light-dark(color-mix(in srgb,var(--primary) 10%,white 90%),color-mix(in srgb,var(--primary) 10%,black 90%)))}.e6:hover:not(:disabled,:checked){border:1px solid var(--hoverBorder,var(--primary))}.fh:hover:not([aria-disabled=true]){background:var(--hoverBg,light-dark(color-mix(in srgb,var(--primary) 10%,white 90%),color-mix(in srgb,var(--primary) 10%,black 90%)))}.fi:hover:not([aria-disabled=true]){border-color:var(--hoverBorder,var(--primary))}.e8:is(:disabled,[aria-disabled=true]){background-color:var(--disabledBg,light-dark(#F0F0F3,#47474A))}.fn[aria-disabled=true]{color:var(--disabledColor,light-dark(#D6D7DE,#373737))}.w[aria-invalid="true"]{border-color:var(--error,light-dark(#D52B2E,#FF5B5E))}.x[aria-invalid="true"]:focus{border-color:var(--error,light-dark(#D52B2E,#FF5B5E))}.y[aria-invalid="true"]:focus{box-shadow:0 0 0 3px var(--focusRing,light-dark(#D52B2E33,#FF5B5E66))}:root[data-theme=dark] .by{background:var(--inputBackground,#2E2E2E)}:root[data-theme=dark] .bz{background:var(--primary,#8163E1)}[data-radio-input]:checked + .fe:not([aria-disabled=true]){background:var(--checkedBg,light-dark(color-mix(in srgb,var(--primary) 10%,white 80%),color-mix(in srgb,var(--primary) 10%,black 80%)))}[data-radio-input]:checked + .ff:not([aria-disabled=true]){border-color:var(--checkedBorder,var(--primary))}[data-radio-input]:checked + .fg:not([aria-disabled=true]){color:var(--checkedColor,var(--primary))}[data-radio-input]:checked + .fd:not([aria-disabled=true]){font-weight:600}[data-radio-input]:disabled + .fj{background:var(--disabledBg,light-dark(#F0F0F3,#47474A))}[data-radio-input]:disabled + .fk{color:var(--disabledColor,light-dark(#D6D7DE,#373737))}}@layer o2{.fu{border-radius:8px}}.c4{align-items:center}.g4{animation-duration:1s}.g5{animation-iteration-count:infinite}.g6{animation-name:g3}.g7{animation-timing-function:linear}.gi{background:var(--border,light-dark(#E4E4E4,#434343))}.gh{background:var(--inputDisabledBackground,light-dark(#F0F0F3,#414244))}.fw{background:var(--primary,light-dark(#674DC7,#8163E1))}.gj{border-radius:4px}.fx{border-radius:8px}.f2{color:#FFF}.gn{color:inherit}.dx{color:light-dark(#D6D7DE,#6F6E6E)}.gd{color:var(--inputDisabledText,light-dark(#E5E5E5,#373737))}.dy{color:var(--text,light-dark(#2F2F2F,#EDEDED))}.c8{cursor:not-allowed}.c9{cursor:pointer}.c3{display:flex}.ag{display:inline-block}.fo{display:inline-flex}.dz{font-size:14px}.d1{gap:8px}.c7{height:16px}.gk{height:18px}.ao{height:24px}.c5{justify-content:center}.f3{justify-content:end}.aq{left:4px}.gf{left:50%}.ay{line-height:1.2}.a3{margin-left:auto}.a2{margin-right:auto}.a1{max-width:100%}.az{min-height:1.2em}.du{opacity:1}.av{overflow:hidden}.f0{padding-bottom:10px}.fz{padding-left:30px}.fy{padding-right:30px}.f1{padding-top:10px}.dv{pointer-events:none}.ar{position:absolute}.ah{position:relative}.fv{text-align:end}.aw{text-overflow:ellipsis}.at{top:50%}.ge{top:55%}.au{transform:translate(-100%,-50%)}.gg{transform:translate(-50%,-50%)}.a0{transform:translateX(8px)}.gm{transition:background-color .1s ease-in-out}.d0{user-select:none}.ax{white-space:nowrap}.ak{width:100%}.c6{width:16px}.gl{width:18px}.ap{width:24px}.a4{width:fit-content}.dw{z-index:1}.ai{box-sizing:border-box}.aj *{box-sizing:border-box}.as>svg{color:inherit}.fp[aria-disabled=true]{cursor:default}
실제 components after CSS 나머지 전체 (위 공통 prefix 바로 뒤에 이어지는 출력)
@layer b{.az{align-items:center}.ax{display:flex}.h1{flex-direction:column}.ay{justify-content:center}}@keyframes iu{0%{transform:rotateZ(0)}100%{transform:rotateZ(360deg)}}@layer o1{.d3{accent-color:var(--d2,var(--primary,light-dark(#6159D4,#6670F9)))}.fu{align-items:var(--ft,center)}.d4{appearance:var(--d1,none)}.gm{background:var(--bg,light-dark(#FFF,#2E2E2E))}.cm{background:var(--inputBackground,#FFF)}.f9{background:var(--l,light-dark(#FFF,#2E2E2E))}.m{background:var(--l,var(--background,light-dark(#FFF,#2E2E2E)))}.is{background:var(--l,var(--border,light-dark(#E4E4E4,#434343)))}.d5{background:var(--l,var(--inputBg,light-dark(#FFF,#2E2E2E)))}.fv{background:var(--l,var(--negative20,light-dark(#0003,#FFF6)))}.cn{background:var(--primary,#8163E1)}.gn{border:1px solid}.co{border:1px solid var(--border,#E4E4E4)}.cp{border:none}.d6{border:var(--d0,1px solid var(--border,light-dark(#E0E0E0,#333)))}.hq{border:var(--d0,1px solid var(--border,light-dark(#E4E4E4,#434343)))}.f_{border:var(--d0,1px solid)}.fw{border:var(--d0,none)}.go{border-color:var(--border)}.ga{border-color:var(--k,var(--border))}.n{border-color:var(--k,var(--border,light-dark(#E4E4E4,#434343)))}.e9{border-color:var(--k,var(--error,light-dark(#D52B2E,#FF5B5E)))}.gq{border-radius:0 8px 8px 0}.cq{border-radius:10px}.cr{border-radius:8px}.gp{border-radius:8px 0 0 8px}.gb{border-radius:var(--j,100%)}.d7{border-radius:var(--j,2px)}.fx{border-radius:var(--j,50%)}.ie{border-radius:var(--j,6px)}.o{border-radius:var(--j,8px)}.p{border-style:var(--i,solid)}.q{border-width:var(--h,1px)}.am{bottom:-8px}.hr{bottom:var(--hp,-4px)}.hs{box-shadow:var(--ho,0 2px 2px 0 var(--base10,light-dark(#0000001A,#FFFFFF1A)))}.bl{box-sizing:var(--bk,border-box)}.cu{color:#FFF}.ct{color:var(--error,#D52B2E)}.an{color:var(--error,light-dark(#D52B2E,#FF5B5E))}.f0{color:var(--g,var(--base,light-dark(#FFF,#000)))}.ig{color:var(--g,var(--primary,light-dark(#674DC7,#8163E1)))}.if{color:var(--g,var(--selectDisabled,light-dark(#C4C5D1,#45464D)))}.r{color:var(--g,var(--text,light-dark(#272727,#F6F6F6)))}.ih{color:var(--g,var(--title,light-dark(#1A1A1A,#FAFAFA)))}.e1{color:var(--iconBold,light-dark(#8D8C9A,#666577))}.e0{color:var(--inputDisabledText,light-dark(#D6D7DE,#373737))}.cs{color:var(--text,#272727)}.gr{color:var(--text,light-dark(#000,#FFF))}.gs{cursor:pointer}.ii{cursor:var(--bj,default)}.d8{cursor:var(--bj,not-allowed)}.bm{cursor:var(--bj,pointer)}.gt{display:flex}.d9{display:var(--dz,block)}.f1{display:var(--dz,flex)}.g8{display:var(--dz,inline-block)}.f7{display:var(--dz,none)}.ao{font-size:12px}.cv{font-size:14px}.cx{font-size:15px}.s{font-size:var(--f,16px)}.ij{font-weight:var(--bi,400)}.bn{font-weight:var(--bi,700)}.iq{gap:0}.ip{gap:10px}.ir{gap:6px}.hv{gap:var(--hn,6px)}.ey{height:24px}.d_{height:var(--dy,100%)}.gc{height:var(--dy,18px)}.fy{height:var(--fs,20px)}.ht{height:var(--fs,fit-content)}.it{height:var(--g7,1px)}.ik{height:var(--g7,40px)}.g9{height:var(--g7,fit-content)}.f2{justify-content:var(--fq,center)}.ap{left:0}.e2{left:12px}.ea{left:var(--dx,0)}.cz{letter-spacing:-.02em}.c1{letter-spacing:0}.u{line-height:var(--e,1.5)}.eb{margin:var(--dw,0)}.v{min-height:var(--d,80px)}.hw{min-width:var(--hm,232px)}.f8{opacity:var(--dv,0)}.ec{opacity:var(--dv,1)}.bo{outline-offset:var(--bh,2px)}.hx{padding:var(--c,10px)}.w{padding:var(--c,12px)}.f3{padding:var(--c,2px)}.df{padding-bottom:10px}.de{padding-bottom:12px}.dg{padding-bottom:8px}.fd{padding-bottom:var(--e6,12px)}.da{padding-left:12px}.c_{padding-left:16px}.c9{padding-left:20px}.dd{padding-left:24px}.dc{padding-left:28px}.db{padding-left:32px}.fa{padding-left:var(--e8,12px)}.e_{padding-left:var(--e8,36px)}.im{padding-left:var(--ic,10px)}.c5{padding-right:12px}.c4{padding-right:16px}.c3{padding-right:20px}.c8{padding-right:24px}.c7{padding-right:28px}.c6{padding-right:32px}.fc{padding-right:var(--e7,12px)}.fb{padding-right:var(--e7,36px)}.il{padding-right:var(--id,10px)}.di{padding-top:10px}.dh{padding-top:12px}.dj{padding-top:8px}.fe{padding-top:var(--e5,12px)}.ed{pointer-events:var(--du,none)}.aq{position:absolute}.ee{position:var(--bg,absolute)}.hy{position:var(--bg,fixed)}.bp{position:var(--bg,relative)}.f4{right:var(--fp,12px)}.e3{top:50%}.ef{top:var(--dt,0)}.f5{top:var(--dt,50%)}.e4{transform:translateY(-50%)}.ar{transform:translateY(100%)}.f6{transform:var(--fo,translateY(-50%))}.g2{transition:background-color .25s,border-color .25s}.bq{transition:var(--b,.25s)}.ff{transition:var(--b,all .1s ease-in-out)}.in{transition:var(--b,background-color .1s ease-in-out)}.x{transition:var(--b,border-color .15s ease-in-out,box-shadow .15s ease-in-out)}.hz{user-select:var(--hl,none)}.ez{width:24px}.g3{width:fit-content}.y{width:var(--a,100%)}.eg{width:var(--ds,100%)}.gd{width:var(--ds,18px)}.fz{width:var(--fr,20px)}.hu{width:var(--fr,fit-content)}.eh{z-index:var(--dr,0)}.h0{z-index:var(--dr,1)}@media(min-width:1280px){.cw{font-size:15px}.cy{font-size:16px}.t{font-size:var(--f,14px)}.c2{letter-spacing:-.01em}.c0{letter-spacing:-.03em}}.b6:hover{background:color-mix(in srgb,var(--primary,#674DC7) 100%,#000 15%)}.b5:hover{background:color-mix(in srgb,var(--primary,#8163E1) 10%,#FFF 90%)}.eo:hover{background:light-dark(color-mix(in srgb,var(--primary,#6159D4) 10%,#FFF 90%),color-mix(in srgb,var(--primary,#6670F9) 20%,#000 80%))}.io:hover{background:var(--primaryBg,light-dark(#F4F3FA,#F4F3FA0D))}.ep:hover{border:1px solid var(--primary,light-dark(#6159D4,#6670F9))}.fm:hover{border:1px solid var(--primary,light-dark(#674DC7,#8163E1))}.b4:hover{border-color:var(--error,#D52B2E)}.b3:hover{border-color:var(--primary,#8163E1)}.ah:hover{border-color:var(--primary,light-dark(#674DC7,#8163E1))}:root[data-theme=dark] .cf:hover{background:color-mix(in srgb,var(--primary,#674DC7) 10%,var(--inputBackground,#2E2E2E) 90%)}:root[data-theme=dark] .cg:hover{background:color-mix(in srgb,var(--primary,#8163E1) 100%,#FFF 15%)}:root[data-theme=dark] .ce:hover{border-color:var(--error,#FF5B5E)}:root[data-theme=dark] .cd:hover{border-color:var(--primary,#8163E1)}:root[data-theme=dark] .ch:hover{outline-color:var(--primary,#674DC7)}.b0:focus-visible{outline:2px solid}.b2:focus-visible{outline-color:var(--error,#FF5B5E)}.b1:focus-visible{outline-color:var(--primaryFocus,#9385D3)}:root[data-theme=dark] .cj:focus-visible{outline-color:var(--error,#D52B2E)}:root[data-theme=dark] .ci:focus-visible{outline-color:var(--primaryFocus,#927CE4)}.fk:focus{background:var(--primaryBg,light-dark(#F4F3FA,#F4F3FA0D))}.fl:focus{border:1px solid var(--primary,light-dark(#674DC7,#8163E1))}.ae:focus{border-color:var(--primary,light-dark(#674DC7,#8163E1))}.af:focus{box-shadow:0 0 0 3px var(--focusRing,light-dark(#674DC726,#8163E140))}.ge:focus{outline:1px sold var(--border,var(--primary))}.ag:focus{outline:none}.bw:active{background:color-mix(in srgb,var(--primary,#674DC7) 100%,#000 30%)}.br:active{background:color-mix(in srgb,var(--primary,#8163E1) 20%,#FFF 80%)}.ei:active{background:light-dark(color-mix(in srgb,var(--primary,#6159D4) 20%,#FFF 80%),color-mix(in srgb,var(--primary,#6670F9) 30%,#000 70%))}.bs:active{background:var(--error,#D52B2E)}.bu:active{border:1px solid var(--error,#D52B2E)}.bt:active{border:1px solid var(--primary,#8163E1)}.bv:active{color:var(--text,#272727)}:root[data-theme=dark] .b_:active{background:color-mix(in srgb,var(--primary,#8163E1) 100%,#FFF 30%)}:root[data-theme=dark] .b8:active{background:var(--error,#FF5B5E)}:root[data-theme=dark] .b7:active{background:var(--primary,#8163E1)}:root[data-theme=dark] .b9:active{color:var(--text,#F6F6F6)}.en:disabled{background:light-dark(#F0F0F3,#47474A)}._:disabled{background:var(--disabledBg,light-dark(#F0F0F3,#414244))}.fh:disabled{background:var(--inputDisabledBg,light-dark(#F0F0F3,#414244))}.by:disabled{background-color:#F0F0F3}.fi:disabled{border:1px solid var(--border,light-dark(#E4E4E4,#434343))}.bz:disabled{border-color:var(--border,#E4E4E4)}.aa:disabled{border-color:var(--border,light-dark(#E4E4E4,#434343))}.bx:disabled{color:#D6D7DE}.ab:disabled{color:var(--disabledText,light-dark(#D6D7DE,#373737))}.fj:disabled{color:var(--inputDisabledText,light-dark(#D6D7DE,#373737))}.ac:disabled{cursor:not-allowed}.a-d:disabled{opacity:.5}:root[data-theme=dark] .cb:disabled{background-color:#47474A}:root[data-theme=dark] .cc:disabled{border-color:transparent}:root[data-theme=dark] .ca:disabled{color:#373737}.g_{box-sizing:border-box}.ha *{box-sizing:border-box}.fn::placeholder{color:var(--inputPlaceholder,light-dark(#A9A8AB,#CBCBCB))}.ai::placeholder{color:var(--placeholder,light-dark(#A9A8AB,#CBCBCB))}.ej:checked{background:var(--primary,light-dark(#6159D4,#6670F9))}.ek:checked{border:none}.em:checked:disabled{background:light-dark(#F0F0F3,#47474A)}.el:checked:hover{background:light-dark(color-mix(in srgb,var(--primary,#6159D4) 100%,#000 15%),color-mix(in srgb,var(--primary,#6670F9) 100%,#FFF 15%))}.gf:checked:not(:disabled){background:var(--checkedBg,var(--primary,light-dark(#FFF,#2E2E2E)))}.gg:checked:not(:disabled){border:3px solid}.gh:checked:not(:disabled){border-color:var(--checkedBg,light-dark(#FFF,#2E2E2E))}.gi:checked:not(:disabled){box-shadow:0 0 0 1px var(--checkedBorder,var(--primary))}.z:disabled::placeholder{color:var(--disabledText,light-dark(#D6D7DE,#373737))}.fg:disabled::placeholder{color:var(--inputDisabledText,light-dark(#D6D7DE,#373737))}.gk:hover:not(:disabled,:checked){background:var(--hoverBg,light-dark(color-mix(in srgb,var(--primary) 10%,white 90%),color-mix(in srgb,var(--primary) 10%,black 90%)))}.gj:hover:not(:disabled,:checked){border:1px solid var(--hoverBorder,var(--primary))}.gy:hover:not([aria-disabled=true]){background:var(--hoverBg,light-dark(color-mix(in srgb,var(--primary) 10%,white 90%),color-mix(in srgb,var(--primary) 10%,black 90%)))}.gz:hover:not([aria-disabled=true]){border-color:var(--hoverBorder,var(--primary))}.gl:is(:disabled,[aria-disabled=true]){background-color:var(--disabledBg,light-dark(#F0F0F3,#47474A))}.g4[aria-disabled=true]{color:var(--disabledColor,light-dark(#D6D7DE,#373737))}.aj[aria-invalid="true"]{border-color:var(--error,light-dark(#D52B2E,#FF5B5E))}.ak[aria-invalid="true"]:focus{border-color:var(--error,light-dark(#D52B2E,#FF5B5E))}.al[aria-invalid="true"]:focus{box-shadow:0 0 0 3px var(--focusRing,light-dark(#D52B2E33,#FF5B5E66))}:root[data-theme=dark] .ck{background:var(--inputBackground,#2E2E2E)}:root[data-theme=dark] .cl{background:var(--primary,#8163E1)}[data-radio-input]:checked + .gv:not([aria-disabled=true]){background:var(--checkedBg,light-dark(color-mix(in srgb,var(--primary) 10%,white 80%),color-mix(in srgb,var(--primary) 10%,black 80%)))}[data-radio-input]:checked + .gw:not([aria-disabled=true]){border-color:var(--checkedBorder,var(--primary))}[data-radio-input]:checked + .gx:not([aria-disabled=true]){color:var(--checkedColor,var(--primary))}[data-radio-input]:checked + .gu:not([aria-disabled=true]){font-weight:600}[data-radio-input]:disabled + .g0{background:var(--disabledBg,light-dark(#F0F0F3,#47474A))}[data-radio-input]:disabled + .g1{color:var(--disabledColor,light-dark(#D6D7DE,#373737))}}@layer o2{.hb{border-radius:8px}}.dl{align-items:center}.iv{animation-duration:1s}.iw{animation-iteration-count:infinite}.ix{animation-name:iu}.iy{animation-timing-function:linear}.h7{background:var(--border,light-dark(#E4E4E4,#434343))}.h6{background:var(--inputDisabledBackground,light-dark(#F0F0F3,#414244))}.hd{background:var(--primary,light-dark(#674DC7,#8163E1))}.h8{border-radius:4px}.he{border-radius:8px}.hj{color:#FFF}.ib{color:inherit}.et{color:light-dark(#D6D7DE,#6F6E6E)}.h2{color:var(--inputDisabledText,light-dark(#E5E5E5,#373737))}.eu{color:var(--text,light-dark(#2F2F2F,#EDEDED))}.dp{cursor:not-allowed}.dq{cursor:pointer}.dk{display:flex}.as{display:inline-block}.g5{display:inline-flex}.ev{font-size:14px}.ex{gap:8px}.do{height:16px}.h9{height:18px}.a0{height:24px}.dm{justify-content:center}.hk{justify-content:end}.a2{left:4px}.h4{left:50%}.a_{line-height:1.2}.be{margin-left:auto}.bd{margin-right:auto}.bc{max-width:100%}.ba{min-height:1.2em}.eq{opacity:1}.a7{overflow:hidden}.hh{padding-bottom:10px}.hg{padding-left:30px}.hf{padding-right:30px}.hi{padding-top:10px}.er{pointer-events:none}.a3{position:absolute}.at{position:relative}.hc{text-align:end}.a8{text-overflow:ellipsis}.a5{top:50%}.h3{top:55%}.a6{transform:translate(-100%,-50%)}.h5{transform:translate(-50%,-50%)}.bb{transform:translateX(8px)}.ia{transition:background-color .1s ease-in-out}.ew{user-select:none}.a9{white-space:nowrap}.aw{width:100%}.dn{width:16px}.h_{width:18px}.a1{width:24px}.bf{width:fit-content}.es{z-index:1}.au{box-sizing:border-box}.av *{box-sizing:border-box}.a4>svg{color:inherit}.g6[aria-disabled=true]{cursor:default}
JSX-02로 생긴 89개 scalar fallback 차이 전체 (각 항목은 해당 style key/breakpoint fallback이며 원래 값 불변)
accent-color; key=accentColor-0-; bp=0; fallback=var(--primary,light-dark(#6159D4,#6670F9))
align-items; key=alignItems-0-; bp=0; fallback=center
appearance; key=appearance-0-; bp=0; fallback=none
background; key=bg-0-; bp=0; fallback=light-dark(#FFF,#2E2E2E)
background; key=bg-0-; bp=0; fallback=var(--background,light-dark(#FFF,#2E2E2E))
background; key=bg-0-; bp=0; fallback=var(--border,light-dark(#E4E4E4,#434343))
background; key=bg-0-; bp=0; fallback=var(--inputBg,light-dark(#FFF,#2E2E2E))
background; key=bg-0-; bp=0; fallback=var(--negative20,light-dark(#0003,#FFF6))
border; key=border-0-; bp=0; fallback=1px solid var(--border,light-dark(#E0E0E0,#333))
border; key=border-0-; bp=0; fallback=1px solid var(--border,light-dark(#E4E4E4,#434343))
border; key=border-0-; bp=0; fallback=1px solid
border; key=border-0-; bp=0; fallback=none
border-color; key=borderColor-0-; bp=0; fallback=var(--border)
border-color; key=borderColor-0-; bp=0; fallback=var(--border,light-dark(#E4E4E4,#434343))
border-color; key=borderColor-0-; bp=0; fallback=var(--error,light-dark(#D52B2E,#FF5B5E))
border-radius; key=borderRadius-0-; bp=0; fallback=100%
border-radius; key=borderRadius-0-; bp=0; fallback=2px
border-radius; key=borderRadius-0-; bp=0; fallback=50%
border-radius; key=borderRadius-0-; bp=0; fallback=6px
border-radius; key=borderRadius-0-; bp=0; fallback=8px
border-style; key=borderStyle-0-; bp=0; fallback=solid
border-width; key=borderWidth-0-; bp=0; fallback=1px
bottom; key=bottom-0-; bp=0; fallback=-4px
box-shadow; key=boxShadow-0-; bp=0; fallback=0 2px 2px 0 var(--base10,light-dark(#0000001A,#FFFFFF1A))
box-sizing; key=boxSizing-0-; bp=0; fallback=border-box
color; key=color-0-; bp=0; fallback=var(--base,light-dark(#FFF,#000))
color; key=color-0-; bp=0; fallback=var(--primary,light-dark(#674DC7,#8163E1))
color; key=color-0-; bp=0; fallback=var(--selectDisabled,light-dark(#C4C5D1,#45464D))
color; key=color-0-; bp=0; fallback=var(--text,light-dark(#272727,#F6F6F6))
color; key=color-0-; bp=0; fallback=var(--title,light-dark(#1A1A1A,#FAFAFA))
cursor; key=cursor-0-; bp=0; fallback=default
cursor; key=cursor-0-; bp=0; fallback=not-allowed
cursor; key=cursor-0-; bp=0; fallback=pointer
display; key=display-0-; bp=0; fallback=block
display; key=display-0-; bp=0; fallback=flex
display; key=display-0-; bp=0; fallback=inline-block
display; key=display-0-; bp=0; fallback=none
font-size; key=fontSize-0-; bp=0; fallback=16px
font-weight; key=fontWeight-0-; bp=0; fallback=400
font-weight; key=fontWeight-0-; bp=0; fallback=700
gap; key=gap-0-; bp=0; fallback=6px
height; key=boxSize-0-; bp=0; fallback=20px
height; key=boxSize-0-; bp=0; fallback=fit-content
height; key=h-0-; bp=0; fallback=1px
height; key=h-0-; bp=0; fallback=40px
height; key=h-0-; bp=0; fallback=fit-content
height; key=height-0-; bp=0; fallback=100%
height; key=height-0-; bp=0; fallback=18px
justify-content; key=justifyContent-0-; bp=0; fallback=center
left; key=left-0-; bp=0; fallback=0
line-height; key=lineHeight-0-; bp=0; fallback=1.5
margin; key=m-0-; bp=0; fallback=0
min-height; key=minH-0-; bp=0; fallback=80px
min-width; key=minW-0-; bp=0; fallback=232px
opacity; key=opacity-0-; bp=0; fallback=0
opacity; key=opacity-0-; bp=0; fallback=1
outline-offset; key=outlineOffset-0-; bp=0; fallback=2px
padding; key=p-0-; bp=0; fallback=10px
padding; key=p-0-; bp=0; fallback=12px
padding; key=p-0-; bp=0; fallback=2px
padding-bottom; key=py-0-; bp=0; fallback=12px
padding-left; key=pl-0-; bp=0; fallback=12px
padding-left; key=pl-0-; bp=0; fallback=36px
padding-left; key=px-0-; bp=0; fallback=10px
padding-right; key=pr-0-; bp=0; fallback=12px
padding-right; key=pr-0-; bp=0; fallback=36px
padding-right; key=px-0-; bp=0; fallback=10px
padding-top; key=py-0-; bp=0; fallback=12px
pointer-events; key=pointerEvents-0-; bp=0; fallback=none
position; key=pos-0-; bp=0; fallback=absolute
position; key=pos-0-; bp=0; fallback=fixed
position; key=pos-0-; bp=0; fallback=relative
right; key=right-0-; bp=0; fallback=12px
top; key=top-0-; bp=0; fallback=0
top; key=top-0-; bp=0; fallback=50%
transform; key=transform-0-; bp=0; fallback=translateY(-50%)
transition; key=transition-0-; bp=0; fallback=.25s
transition; key=transition-0-; bp=0; fallback=all .1s ease-in-out
transition; key=transition-0-; bp=0; fallback=background-color .1s ease-in-out
transition; key=transition-0-; bp=0; fallback=border-color .15s ease-in-out,box-shadow .15s ease-in-out
user-select; key=userSelect-0-; bp=0; fallback=none
width; key=boxSize-0-; bp=0; fallback=20px
width; key=boxSize-0-; bp=0; fallback=fit-content
width; key=w-0-; bp=0; fallback=100%
width; key=width-0-; bp=0; fallback=100%
width; key=width-0-; bp=0; fallback=18px
z-index; key=zIndex-0-; bp=0; fallback=0
z-index; key=zIndex-0-; bp=0; fallback=1
font-size; key=fontSize-0-; bp=4; fallback=14px
public WASM의 실제 항목별 compiled code/error 출력 (공통 theme CSS는 위 CSS 및 검증 보고서 참조)

fn08.tsx

import "@devup-ui/react/devup-ui.css";
import { E } from "./values";
export const value = "height-0-20px--255";

fn09-imul.tsx

import "@devup-ui/react/devup-ui.css";
import { imul } from "./values";
export const value = "width-0-48px--255";

fn09-clz.tsx

import "@devup-ui/react/devup-ui.css";
import { clz } from "./values";
export const value = "width-0-124px--255";

fn09-fround.tsx

import "@devup-ui/react/devup-ui.css";
import { fround } from "./values";
export const value = "width-0-6px--255";

jsx02.tsx

import "@devup-ui/react/devup-ui.css";
export function before(props: object) {
	return ((__devupSpread0) => <div {...__devupSpread0} className={`${__devupSpread0?.className || ""} color-0-red--255`} style={__devupSpread0?.style} />)({
		__proto__: null,
		...props
	});
}
export function after(props: object) {
	return ((__devupSpread1) => <div {...__devupSpread1} className={`${__devupSpread1?.className || ""} color-0-var_lp_--color-spread-color-0-_cm_red_rp_--255`} style={{
		...{ "--color-spread-color-0-": "color" in __devupSpread1 ? __devupSpread1.color : void 0 },
		...__devupSpread1?.style
	}} />)({
		__proto__: null,
		...props
	});
}
export function call(props: object) {
	return ((__devupSpread2) => <div {...__devupSpread2} className={`${__devupSpread2?.className || ""} background-0-gray--255`} style={__devupSpread2?.style} />)({
		__proto__: null,
		...getProps(props)
	});
}
declare function getProps(props: object): object;

jsx02-responsive.tsx

import "@devup-ui/react/devup-ui.css";
export function responsive(props: object) {
	return ((__devupSpread0) => <div {...__devupSpread0} className={`${__devupSpread0?.className || ""} background-0-var_lp_--background-spread-bg-0-_cm_red_rp_--255 background-1-var_lp_--background-spread-bg-0-_cm_blue_rp_--255`} style={{
		...{ "--background-spread-bg-0-": "bg" in __devupSpread0 ? __devupSpread0.bg : void 0 },
		...__devupSpread0?.style
	}} />)({
		__proto__: null,
		...props
	});
}
export function token(props: object) {
	return ((__devupSpread1) => <div {...__devupSpread1} className={`${__devupSpread1?.className || ""} color-0-var_lp_--color-spread-color-0-_cm__dl_primary_rp_--255`} style={{
		...{ "--color-spread-color-0-": "color" in __devupSpread1 ? __devupSpread1.color : void 0 },
		...__devupSpread1?.style
	}} />)({
		__proto__: null,
		...props
	});
}
export function multiple(first: object, last: object) {
	return ((__devupSpread2, __devupSpread3) => <div {...__devupSpread2} {...__devupSpread3} className={`${("className" in __devupSpread3 ? __devupSpread3.className : __devupSpread2?.className) || ""} color-0-var_lp_--color-spread-color-0-_cm_red_rp_--255`} style={{
		...{ "--color-spread-color-0-": "color" in __devupSpread3 ? __devupSpread3.color : "color" in __devupSpread2 ? __devupSpread2.color : void 0 },
		..."style" in __devupSpread3 ? __devupSpread3.style : __devupSpread2?.style
	}} />)({
		__proto__: null,
		...first
	}, {
		__proto__: null,
		...last
	});
}
export function nestedBefore(props: object) {
	return ((__devupSpread4) => <div {...__devupSpread4} className={`${__devupSpread4?.className || ""} background-0-blue-_a__c_hover-255`} style={__devupSpread4?.style} />)({
		__proto__: null,
		...props
	});
}

jsx02-selectors-error.tsx

C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w22-js-semantics/jsx02-selectors-error.tsx:2:58: `<Box>` cannot use `_hover` at build time: a spread after it can replace the whole `_hover` object, which no stylesheet rule can follow: write the spread before `_hover`, or give the nested object through the spread yourself

jsx02-css-error.tsx

C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w22-js-semantics/jsx02-css-error.tsx:2:78: `css` on `<Box>` cannot use `...props` at build time: a spread after the `css` prop may carry a `css` of its own, which replaces it whole where only the runtime could tell: write the spread before `css`

jsx02-styled.tsx

import "@devup-ui/react/devup-ui.css";
import { forwardRef as __devupForwardRef } from "react";
const Card = __devupForwardRef((__devupRefProps, __devupRef) => (({ style, className, as: DevupAs = "div", forwardedAs, ...rest }) => <DevupAs {...(({ "theme": __devupOmit0, ...__devupDom }) => __devupDom)(rest)} as={forwardedAs} className={["background-0-white--255", className].filter(Boolean).join(" ")} style={style} />)({
	...__devupRefProps,
	ref: __devupRef
}));
export function before(props: object) {
	return ((__devupSpread0) => <Card {...__devupSpread0} className={`${__devupSpread0?.className || ""} color-0-red--255`} style={__devupSpread0?.style} />)({
		__proto__: null,
		...props
	});
}
export function after(props: object) {
	return ((__devupSpread1) => <Card {...__devupSpread1} className={`${__devupSpread1?.className || ""} color-0-var_lp_--color-spread-color-0-_cm_red_rp_--255`} style={{
		...{ "--color-spread-color-0-": "color" in __devupSpread1 ? __devupSpread1.color : void 0 },
		...__devupSpread1?.style
	}} />)({
		__proto__: null,
		...props
	});
}

jsx06.tsx

import "@devup-ui/react/devup-ui.css";
import React, { createElement as make } from "react";
export const named = make("div", { className: "color-0-red--255" }, "child");
export const namespace = React.createElement("div", { className: "background-0-blue--255" }, "child");

jsx09.tsx

C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w22-js-semantics/jsx09.tsx:3:50: `<Box>` cannot use `runtime` at build time: `styleOrder` must be a number, or a condition choosing between numbers, since the stylesheet places rules by it before the code runs

jsx12.tsx

import "@devup-ui/react/devup-ui.css";
export function render() {
	const color = "green";
	const width = Math.imul(2, 3);
	return <div className="color-0-green--255 width-0-24px--255" />;
}

fn04.ts

import type { Box, css } from "@devup-ui/react";
import { type Flex, type keyframes } from "@devup-ui/react";
export type A = typeof Box;
export type B = typeof css;
export type C = typeof Flex;
export type D = typeof keyframes;

namespace.ts

C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w22-js-semantics/namespace.ts:3:26: `ns` cannot use `ns` at build time: read its members by name, as `ns.css`, `ns['css']` or `const { css } = ns`, or import them by name

tdz-error.tsx

C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w22-js-semantics/tdz-error.tsx:2:33: style value cannot use `color` at build time: it is read before its lexical declaration is initialized, so the original JavaScript throws ReferenceError; move the declaration of `color` above this use

tdz-deferred-var.tsx

import "@devup-ui/react/devup-ui.css";
export function Render() {
	return <div className="color-0-red--255" />;
}
const color = "red";
export const beforeVar = <div className="color-0---255" style={{ "--color-0-": later }} />;
var later = "blue";

tdz-block-function.tsx

C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w22-js-semantics/tdz-block-function.tsx:2:28: style value cannot use `color` at build time: it is read before its lexical declaration is initialized, so the original JavaScript throws ReferenceError; move the declaration of `color` above this use
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w22-js-semantics/tdz-block-function.tsx:3:53: style value cannot use `local` at build time: it is read before its lexical declaration is initialized, so the original JavaScript throws ReferenceError; move the declaration of `local` above this use
C:/Users/devfive3901/AppData/Local/Temp/opencode/workers/w22-js-semantics/tdz-block-function.tsx:4:38: style value cannot use `Color` at build time: it is read before its lexical declaration is initialized, so the original JavaScript throws ReferenceError; move the declaration of `Color` above this use
의도한 snapshot 변경 111개 전체 설명
  • apply_var_typography-3.snap: native 선택1회; static token 유지, missing key 빈 class
  • apply_var_typography-5.snap: native 선택1회; static token 유지, missing key 빈 class
  • apply_var_typography-6.snap: native 선택1회; static token 유지, missing key 빈 class
  • backtick_prop-2.snap: source capture; CSS 값 불변
  • changed_constants.snap: TDZ/self dependency는 ReferenceError 원인 오류; mutable 값은 원래 읽기 위치에서 capture
  • compose_rules_the_module_computes.snap: source capture; CSS 값 불변
  • compute_what_elements_and_styled_objects_take.snap: source capture; CSS 값 불변
  • conditional_styles.snap: 중첩 stable primitive const folding으로 실제 선택되지 않는 규칙 제거
  • constant_objects_arrays_and_enums.snap: source capture; CSS 값 불변
  • devup_props_optional_chaining.snap: native 선택1회; static token 유지, missing key 빈 class
  • dynamic_as_elements.snap: source capture; CSS 값 불변
  • dynamic_value_with_important.snap: source capture; CSS 값 불변
  • enum_style_prop.snap: source capture; CSS 값 불변
  • evaluate_build_time_values.snap: source capture; CSS 값 불변
  • every_runtime_value_an_element_holds.snap: source capture; CSS 값 불변
  • extract_conditional_style_props-7.snap: source capture; CSS 값 불변
  • extract_conditional_style_props-8.snap: source capture; CSS 값 불변
  • extract_conditional_style_props-9.snap: source capture; CSS 값 불변
  • extract_conditional_style_props_with_class_name-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • extract_dynamic_logical_case-2.snap: source capture; CSS 값 불변
  • extract_dynamic_logical_case-4.snap: source capture; CSS 값 불변
  • extract_dynamic_logical_case.snap: source capture; CSS 값 불변
  • extract_dynamic_style_props-2.snap: source capture; CSS 값 불변
  • extract_dynamic_style_props-4.snap: source capture; CSS 값 불변
  • extract_dynamic_style_props-5.snap: source capture; CSS 값 불변
  • extract_dynamic_style_props_binary_member_call_arm-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • extract_dynamic_style_props_binary_member_call_arm-3.snap: native 선택1회; static token 유지, missing key 빈 class
  • extract_dynamic_style_props_binary_member_call_arm.snap: native 선택1회; static token 유지, missing key 빈 class
  • extract_dynamic_style_props_with_type-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • extract_responsive_conditional_style_props_with_class_name.snap: native 선택1회; static token 유지, missing key 빈 class
  • extract_same_dynamic_value_conditional_style_props-2.snap: source capture; CSS 값 불변
  • extract_selector-2.snap: source capture; CSS 값 불변
  • extract_style_props_with_class_name-6.snap: native 선택1회; static token 유지, missing key 빈 class
  • extract_style_props_with_class_name-9.snap: native 선택1회; static token 유지, missing key 빈 class
  • inline_imported_constants.snap: 명시적 정적 값이 unknown spread 뒤의 own key에 양보하는 CSS variable + 동일 fallback
  • inline_local_constants.snap: TDZ const self-use는 별도 negative regression으로 유지하고 var self-use dynamic 경로를 fixture에서 검증
  • member_expression_style.snap: source capture; CSS 값 불변
  • member_expression_with_dynamic_values.snap: source capture; CSS 값 불변
  • negative_props-2.snap: source capture; CSS 값 불변
  • negative_props-3.snap: source capture; CSS 값 불변
  • negative_props-4.snap: source capture; CSS 값 불변
  • props_direct_array_responsive_select-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_array_responsive_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_array_select-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_array_select-3.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_array_select-4.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_array_select-5.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_array_select-6.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_array_select-7.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_array_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_hybrid_responsive_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_object_responsive_select-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_object_responsive_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_object_select-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_object_select-3.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_object_select-4.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_object_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_variable_array_responsive_select-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_variable_array_responsive_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_variable_object_responsive_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_variable_object_select-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_variable_object_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_direct_wrong.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_multi_expression.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_array_select-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_array_select-3.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_array_select-4.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_array_select-5.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_array_select-6.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_array_select-7.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_array_select-8.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_array_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_object_select-2.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_object_select-3.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_object_select-4.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_object_select-5.snap: native 선택1회; static token 유지, missing key 빈 class
  • props_wrong_direct_object_select.snap: native 선택1회; static token 유지, missing key 빈 class
  • read_once_in_every_place.snap: source capture; CSS 값 불변
  • remove_semicolon-4.snap: capture 전 기존 CSS suffix 처리 보존; runtime variable에 semicolon을 남기지 않음
  • remove_semicolon-5.snap: capture 전 기존 CSS suffix 처리 보존; runtime variable에 semicolon을 남기지 않음
  • rest_props-2.snap: source capture; CSS 값 불변
  • rest_props.snap: 명시적 정적 값이 unknown spread 뒤의 own key에 양보하는 CSS variable + 동일 fallback
  • spread_props.snap: source capture; CSS 값 불변
  • spreads_are_read_once.snap: source capture; CSS 값 불변
  • style_order_conditional-2.snap: 조용한 오해석 대신 original-span build error로 변경; 원래 입력의 negative regression 유지
  • style_order_conditional-3.snap: 조용한 오해석 대신 original-span build error로 변경; 원래 입력의 negative regression 유지
  • style_order_conditional_coverage-3.snap: source capture; CSS 값 불변
  • style_order_conditional_coverage-6.snap: 조용한 오해석 대신 original-span build error로 변경; 원래 입력의 negative regression 유지
  • style_order_coverage_additional-4.snap: source capture; CSS 값 불변
  • style_results_read_as_values.snap: source capture; CSS 값 불변
  • style_variables-11.snap: source capture; CSS 값 불변
  • style_variables-9.snap: source capture; CSS 값 불변
  • styles_the_build_cannot_read.snap: source capture; CSS 값 불변
  • support_transpile_cjs-7.snap: 조용한 오해석 대신 original-span build error로 변경; 원래 입력의 negative regression 유지
  • support_transpile_mjs-5.snap: source capture; CSS 값 불변
  • tailwind_template_literal_with_function_call_expression.snap: template coercion을 원래 순서에서 capture하되 기존 정적 Tailwind 규칙과 styleOrder 유지
  • tailwind_template_literal_with_logical_expression.snap: template coercion을 원래 순서에서 capture하되 기존 정적 Tailwind 규칙과 styleOrder 유지
  • tailwind_template_literal_with_nested_template_literal.snap: template coercion을 원래 순서에서 capture하되 기존 정적 Tailwind 규칙과 styleOrder 유지
  • tailwind_template_literal_with_parenthesized_expression.snap: template coercion을 원래 순서에서 capture하되 기존 정적 Tailwind 규칙과 styleOrder 유지
  • tailwind_template_literal_with_style_order.snap: template coercion을 원래 순서에서 capture하되 기존 정적 Tailwind 규칙과 styleOrder 유지
  • tailwind_template_literal_with_variable_expression.snap: template coercion을 원래 순서에서 capture하되 기존 정적 Tailwind 규칙과 styleOrder 유지
  • tailwind_with_conditional_template_literal.snap: template coercion을 원래 순서에서 capture하되 기존 정적 Tailwind 규칙과 styleOrder 유지
  • values_known_only_at_runtime.snap: source capture; CSS 값 불변
  • index.browser.test.tsx.snap: reorder + JSX-02 fallback; CSS 값 불변
  • index.browser.test.tsx.snap: reorder + JSX-02 fallback; CSS 값 불변
  • index.browser.test.tsx.snap: reorder + JSX-02 fallback; CSS 값 불변
  • index.browser.test.tsx.snap: reorder + JSX-02 fallback; CSS 값 불변
  • index.browser.test.tsx.snap: reorder + JSX-02 fallback; CSS 값 불변
  • index.browser.test.tsx.snap: reorder + JSX-02 fallback; CSS 값 불변
  • index.browser.test.tsx.snap: reorder + JSX-02 fallback; CSS 값 불변
  • index.browser.test.tsx.snap: reorder + JSX-02 fallback; CSS 값 불변
Linux CI가 요구한 landing caller 재배치 및 실제 CSS 전후

추가 재배치 파일: apps/landing/src/app/(detail)/components/Card.tsx, apps/landing/src/components/Header/HeaderInput.tsx. private landing이므로 changepack 없음.

Card 호출부는 MdxCard:45(className만 전달), overview/page:69/129/189(children만 전달)입니다. HeaderInput은 Header/index:187 및 MobMenu:15의 readOnly 호출뿐입니다. 어떤 호출도 selector를 spread로 전달하지 않습니다. 두 파일 모두 기준 compiler의 pure reorder CSS byte equality를 검증했습니다. 새 compiler에서 Card는 background/border/border-radius/cursor/transition, HeaderInput은 background/border/color/outline/width의 5개 fallback씩만 추가되며 값은 동일합니다. 전체 landing Next build도 통과했습니다. 아래 출력은 공통 license banner만 생략했습니다.

card before

@layer b,o1;@layer b{.a{display:flex}.b{flex-direction:column}}@layer o1{.f{background:var(--containerBackground)}.g{border:1px solid var(--border)}.h{border-radius:10px}.i{cursor:pointer}.j{transition:all .2s ease}.e:hover{box-shadow:0 0 20px 0 #00000026}.c:active{box-shadow:none}.d:active{transform:scale(.95)}}

card after

@layer b,o1;@layer b{.k{display:flex}.l{flex-direction:column}}@layer o1{.f{background:var(--e,var(--containerBackground))}.g{border:var(--d,1px solid var(--border))}.h{border-radius:var(--c,10px)}.i{cursor:var(--b,pointer)}.j{transition:var(--a,all .2s ease)}.o:hover{box-shadow:0 0 20px 0 #00000026}.m:active{box-shadow:none}.n:active{transform:scale(.95)}}

header-input before

@layer b;@layer b{.i{display:flex}}.j{align-items:center}.k{background:var(--menuHover)}.d{background:transparent}.e{border:none}.l{border-radius:8px}.f{color:var(--text)}.m{gap:10px}.a{height:24px}.g{outline:none}.n{padding:8px 8px 6px}.h{width:100%}.b{width:24px}.c::placeholder{color:var(--caption)}

header-input after

@layer b;@layer b{.n{display:flex}}.o{align-items:center}.p{background:var(--menuHover)}.h{background:var(--g,transparent)}.i{border:var(--f,none)}.q{border-radius:8px}.j{color:var(--e,var(--text))}.r{gap:10px}.a{height:24px}.k{outline:var(--d,none)}.s{padding:8px 8px 6px}.t{width:100%}.b{width:24px}.l{width:var(--c,100%)}.m::placeholder{color:var(--caption)}

owjs3901 and others added 30 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>
…ead through namespaces

Refs #695

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…akes from the visitor

Refs #695

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…eclared after their use

Refs #695, #686

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

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

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

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

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

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

Refs #695

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 and others added 8 commits October 5, 2026 00:48
Refs #695

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 4, 2026

Copy link
Copy Markdown
Contributor

Changepacks

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

Patch

  • A project module re-exporting Devup UI (export { Box, css } from '@devup-ui/react', export * from '@devup-ui/react', export { styled as s }, export * as Devup, a default export of an import, chains of barrels and the compat entry) now works: a file importing Box or css from it compiles exactly as if it imported from the package, following the barrel through the resolver (relative paths, tsconfig paths, package exports), and hasDevupUI sees such a file. Members read from a namespace or default import of the package (Devup['css'], const { css } = Devup, Devup.css as a value) compile where the build can follow them, Devup.x for a name the package compiles being read like the named import. New build errors, located at the use: what a barrel re-exports but the build cannot read (an unresolvable export * or module, a namespace of modules re-exporting the package) is an error where its name is used instead of a runtime crash, and a namespace member read by a key the build cannot know (Devup[key]), written, or destructured in a form it cannot follow (a rest, a computed key, a default value, a nested pattern, an exported declaration, or members mixed with ones that stay at runtime) is an error that names the members to read. A namespace passed on whole (Object.keys(Devup), spyOn(Devup, 'css'), export default Devup) is left as it is
  • 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
  • hasDevupUI takes the import aliases and is true for a file extraction changes: one importing a redirected package (@emotion/styled, ...), naming @emotion/react in a @jsxImportSource pragma, or in a project whose tsconfig jsxImportSource is @emotion/react, so the Bun plugin no longer skips files whose only Devup UI is Emotion's css prop or an aliased import. Aliases of Devup UI now compile like the original: export const B = Box, const c = css; export { c as cc }, export const D = Devup and export const C = Devup.css in a barrel (the barrel module exports them as re-exports of the package, and what imports them follows them), export { Box } after an import, export default Box, const D = Devup namespace aliases, and const inner = css declared inside a function. A css() or keyframes() const that a function reads before its declaration compiles. New build error: a css()/keyframes() const read before its declaration runs (outside a function) is located and says to move the declaration above its first read
  • Preserve JavaScript semantics for exact imported enum and Math values including negative zero, lexical constants, binding-aware CommonJS require, React createElement calls, type-only imports, and source-ordered props evaluation with native spread snapshots and CSS-variable fallbacks without a styling runtime. Migrate UI-kit style defaults by pure reordering and test reset CSS through compiled output. Report located build errors for runtime styleOrder values, unknowable whole-object style overrides, opaque selector literals, genuinely unmovable lazy logical suspension, Devup UI namespaces passed whole to runtime code, and immediate style reads in the temporal dead zone of lexical bindings; deferred initialized reads keep folding and pre-assignment var reads remain dynamic.
  • Resolve compiled styling APIs and components by their lexical binding so shadowed local names, including minified library identifiers, remain ordinary JavaScript and JSX. No new build errors; existing diagnostics now apply only to the compiled binding they describe.
  • 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
  • hasDevupUI takes the import aliases and is true for a file extraction changes: one importing a redirected package (@emotion/styled, ...), naming @emotion/react in a @jsxImportSource pragma, or in a project whose tsconfig jsxImportSource is @emotion/react, so the Bun plugin no longer skips files whose only Devup UI is Emotion's css prop or an aliased import. Aliases of Devup UI now compile like the original: export const B = Box, const c = css; export { c as cc }, export const D = Devup and export const C = Devup.css in a barrel (the barrel module exports them as re-exports of the package, and what imports them follows them), export { Box } after an import, export default Box, const D = Devup namespace aliases, and const inner = css declared inside a function. A css() or keyframes() const that a function reads before its declaration compiles. New build error: a css()/keyframes() const read before its declaration runs (outside a function) is located and says to move the declaration above its first read

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

Patch

  • Preserve JavaScript semantics for exact imported enum and Math values including negative zero, lexical constants, binding-aware CommonJS require, React createElement calls, type-only imports, and source-ordered props evaluation with native spread snapshots and CSS-variable fallbacks without a styling runtime. Migrate UI-kit style defaults by pure reordering and test reset CSS through compiled output. Report located build errors for runtime styleOrder values, unknowable whole-object style overrides, opaque selector literals, genuinely unmovable lazy logical suspension, Devup UI namespaces passed whole to runtime code, and immediate style reads in the temporal dead zone of lexical bindings; deferred initialized reads keep folding and pre-assignment var reads remain dynamic.

@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

@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

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

Patch

  • 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

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

Patch

  • Preserve JavaScript semantics for exact imported enum and Math values including negative zero, lexical constants, binding-aware CommonJS require, React createElement calls, type-only imports, and source-ordered props evaluation with native spread snapshots and CSS-variable fallbacks without a styling runtime. Migrate UI-kit style defaults by pure reordering and test reset CSS through compiled output. Report located build errors for runtime styleOrder values, unknowable whole-object style overrides, opaque selector literals, genuinely unmovable lazy logical suspension, Devup UI namespaces passed whole to runtime code, and immediate style reads in the temporal dead zone of lexical bindings; deferred initialized reads keep folding and pre-assignment var reads remain dynamic.

@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

@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

@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

@codecov

codecov Bot commented Oct 4, 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/theme_tokens.rs 100.00% <ø> (ø)
libs/extractor/src/barrel.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/aliases.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/gate.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/namespace_aliases.rs 100.00% <100.00%> (ø)
libs/extractor/src/build_time_values.rs 100.00% <100.00%> (ø)
libs/extractor/src/build_time_values/exact_math.rs 100.00% <100.00%> (ø)
libs/extractor/src/composition.rs 100.00% <100.00%> (ø)
... and 51 more

... and 12 files with indirect coverage changes

🚀 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