@@ -86,16 +86,38 @@ All `@devup-ui/react` components (`Box`, `Flex`, `Text`, etc.) throw `Error('Can
8686
8787## Styling APIs
8888
89+ ### css() Returns className String (NOT object)
90+
8991``` tsx
9092import { css , styled , globalCss , keyframes } from " @devup-ui/react" ;
93+ import clsx from " clsx" ;
94+
95+ // css() returns a className STRING - use with className prop
96+ const cardStyle = css ({ bg: " white" , p: 4 , borderRadius: " 8px" });
97+ <Box className = { cardStyle } /> // CORRECT
9198
92- // Reusable style object
93- const cardStyles = css ({ bg: " white" , p: 4 , borderRadius: " 8px" });
94- <Box { ... cardStyles } />
99+ // WRONG - css() is NOT an object to spread
100+ // <Box {...cardStyle} /> // ERROR!
95101
102+ // Combine multiple styles with clsx
103+ const baseStyle = css ({ p: 4 , borderRadius: " 8px" });
104+ const activeStyle = css ({ bg: " $primary" , color: " white" });
105+ <Box className = { clsx (baseStyle , isActive && activeStyle )} styleOrder = { 1 } />
106+
107+ // styleOrder={1} REQUIRED when mixing className with direct props
108+ <Box className = { cardStyle } bg = " $background" styleOrder = { 1 } />
109+ ```
110+
111+ ### styled() API
112+
113+ ``` tsx
96114// Styled component (familiar styled-components/Emotion API)
97115const Card = styled (" div" , { bg: " white" , p: 4 , _hover: { shadow: " lg" } });
116+ ```
117+
118+ ### globalCss() and keyframes()
98119
120+ ``` tsx
99121// Global styles
100122globalCss ({ body: { margin: 0 }, " *" : { boxSizing: " border-box" } });
101123
@@ -120,7 +142,8 @@ const spin = keyframes({ from: { transform: "rotate(0)" }, to: { transform: "rot
120142}
121143```
122144
123- Use with ` $ ` prefix: ` <Box color="$primary" typography="$heading" /> `
145+ Use colors with ` $ ` prefix: ` <Box color="$primary" /> `
146+ Use typography without prefix: ` <Box typography="heading" /> `
124147
125148Theme API:
126149``` tsx
@@ -157,11 +180,47 @@ Options:
157180DevupUI ({ include: [" @devup/hello" ] }) // required to extract and merge their styles
158181```
159182
183+ ## $color Token Scope
184+
185+ ` $color ` tokens only work in ** JSX props** . Use ` var(--color) ` in external objects.
186+
187+ ``` tsx
188+ // CORRECT - $color in JSX prop
189+ <Box bg = " $primary" />
190+ <Box bg = { { active: ' $primary' , inactive: ' $gray' }[status ]} /> // inline object OK
191+
192+ // WRONG - $color in external object (won't be transformed)
193+ const colors = { active: ' $primary' } // '$primary' stays as string literal
194+ <Box bg = { colors .active } /> // broken!
195+
196+ // CORRECT - var(--color) in external object
197+ const colors = { active: ' var(--primary)' }
198+ <Box bg = { colors .active } /> // works
199+ ```
200+
201+ ## Inline Variant Pattern (Preferred)
202+
203+ Use inline object indexing instead of external config objects:
204+
205+ ``` tsx
206+ // PREFERRED - inline object indexing
207+ <Box
208+ h = { { lg: ' 48px' , md: ' 40px' , sm: ' 32px' }[size ]}
209+ bg = { { primary: ' $primary' , secondary: ' $gray100' }[variant ]}
210+ />
211+
212+ // AVOID - external config object
213+ const sizeStyles = { lg: { h: ' 48px' }, md: { h: ' 40px' } }
214+ <Box h = { sizeStyles [size ].h } /> // unnecessary indirection
215+ ```
216+
160217## Anti-Patterns (NEVER do)
161218
162219| Wrong | Right | Why |
163220| -------| -------| -----|
164221| ` <Box style={{ color: "red" }}> ` | ` <Box color="red"> ` | style prop bypasses extraction |
222+ | ` <Box {...css({...})} /> ` | ` <Box className={css({...})} /> ` | css() returns string, not object |
165223| ` css({ bg: variable }) ` | ` <Box bg={variable}> ` | css()/globalCss() only accept static values |
224+ | ` $color ` in external object | ` var(--color) ` in external object | $color only transformed in JSX props |
166225| No build plugin configured | Configure plugin first | Components throw at runtime without transformation |
167226| ` as any ` on style props | Fix types properly | Type errors indicate real issues |
0 commit comments