@cronocode/react-box 3.1.7 → 3.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BOX_AI_CONTEXT.md +368 -119
- package/core/boxStyles.d.ts +134 -22
- package/core/theme/theme.d.ts +1 -1
- package/core/variables.d.ts +2 -0
- package/core.cjs +3 -3
- package/core.mjs +456 -320
- package/package.json +1 -1
package/BOX_AI_CONTEXT.md
CHANGED
|
@@ -4,6 +4,155 @@ Reference document for AI assistants helping developers use this runtime CSS-in-
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## CRITICAL RULES (Read First!)
|
|
8
|
+
|
|
9
|
+
### Rule #1: NEVER Use Inline Styles
|
|
10
|
+
|
|
11
|
+
**WRONG** - Using `style` attribute:
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
// DO NOT DO THIS
|
|
15
|
+
<Box style={{ minHeight: "100vh", width: "100%" }} />
|
|
16
|
+
<Box style={{ pointerEvents: "none" }} />
|
|
17
|
+
<Box style={{ alignItems: "center" }} />
|
|
18
|
+
<Box style={{ maxWidth: "1200px" }} />
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**CORRECT** - Using Box props:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
// DO THIS INSTEAD
|
|
25
|
+
<Box minHeight="fit-screen" width="fit" />
|
|
26
|
+
<Box pointerEvents="none" />
|
|
27
|
+
<Box ai="center" />
|
|
28
|
+
<Box maxWidth={300} />
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**If a prop doesn't exist for a CSS property**, create it using `Box.extend()` in your boxExtends.ts file. Never fall back to inline styles.
|
|
32
|
+
|
|
33
|
+
### Common Style-to-Prop Conversions
|
|
34
|
+
|
|
35
|
+
| Inline Style (WRONG) | Box Prop (CORRECT) |
|
|
36
|
+
| --------------------------------------------- | ------------------------------------- |
|
|
37
|
+
| `style={{ width: "100%" }}` | `width="fit"` |
|
|
38
|
+
| `style={{ width: "100vw" }}` | `width="fit-screen"` |
|
|
39
|
+
| `style={{ height: "100%" }}` | `height="fit"` |
|
|
40
|
+
| `style={{ height: "100vh" }}` | `height="fit-screen"` |
|
|
41
|
+
| `style={{ minHeight: "100vh" }}` | `minHeight="fit-screen"` |
|
|
42
|
+
| `style={{ maxWidth: "1200px" }}` | `maxWidth={300}` (300/4=75rem=1200px) |
|
|
43
|
+
| `style={{ alignItems: "center" }}` | `ai="center"` |
|
|
44
|
+
| `style={{ justifyContent: "space-between" }}` | `jc="between"` |
|
|
45
|
+
| `style={{ flexDirection: "column" }}` | `d="column"` |
|
|
46
|
+
| `style={{ pointerEvents: "none" }}` | `pointerEvents="none"` |
|
|
47
|
+
| `style={{ cursor: "pointer" }}` | `cursor="pointer"` |
|
|
48
|
+
| `style={{ overflow: "hidden" }}` | `overflow="hidden"` |
|
|
49
|
+
| `style={{ position: "relative" }}` | `position="relative"` |
|
|
50
|
+
| `style={{ zIndex: 10 }}` | `zIndex={10}` |
|
|
51
|
+
| `style={{ opacity: 0.5 }}` | `opacity={0.5}` |
|
|
52
|
+
|
|
53
|
+
### When a Prop Doesn't Exist
|
|
54
|
+
|
|
55
|
+
If you need a CSS property that doesn't have a Box prop, extend Box instead of using inline styles:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
// boxExtends.ts - Create new props for missing CSS properties
|
|
59
|
+
import Box from '@cronocode/react-box';
|
|
60
|
+
|
|
61
|
+
export const { extendedProps, extendedPropTypes } = Box.extend(
|
|
62
|
+
{}, // CSS variables (if needed)
|
|
63
|
+
{
|
|
64
|
+
// Add new props
|
|
65
|
+
aspectRatio: [
|
|
66
|
+
{
|
|
67
|
+
values: ['auto', '1/1', '16/9', '4/3', '3/2'] as const,
|
|
68
|
+
styleName: 'aspect-ratio',
|
|
69
|
+
valueFormat: (value) => value,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
backdropBlur: [
|
|
73
|
+
{
|
|
74
|
+
values: ['none', 'sm', 'md', 'lg'] as const,
|
|
75
|
+
styleName: 'backdrop-filter',
|
|
76
|
+
valueFormat: (value) => {
|
|
77
|
+
const map = { none: 'none', sm: 'blur(4px)', md: 'blur(8px)', lg: 'blur(16px)' };
|
|
78
|
+
return map[value];
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
{}, // Extended existing props (if needed)
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// Now use the new props
|
|
87
|
+
<Box aspectRatio="16/9" backdropBlur="md" />;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Rule #2: ALWAYS Use Component Shortcuts
|
|
91
|
+
|
|
92
|
+
**⚠️ NEVER use `<Box tag="...">` when a semantic component exists!**
|
|
93
|
+
|
|
94
|
+
The `tag` prop should ONLY be used for rare HTML elements that don't have a component shortcut (e.g., `<Box tag="datalist">`). For all common elements, use the corresponding component.
|
|
95
|
+
|
|
96
|
+
**WRONG** - Using `tag` prop for common elements:
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
// ❌ DO NOT DO THIS - These are WRONG even though they work
|
|
100
|
+
<Box tag="img" props={{ src: logo, alt: "Logo" }} /> // WRONG!
|
|
101
|
+
<Box tag="a" props={{ href: "#" }}>Link</Box> // WRONG!
|
|
102
|
+
<Box tag="button" onClick={...}>Click</Box> // WRONG!
|
|
103
|
+
<Box tag="nav">...</Box> // WRONG!
|
|
104
|
+
<Box tag="h1" fontSize={32}>Title</Box> // WRONG!
|
|
105
|
+
<Box tag="p">Text</Box> // WRONG!
|
|
106
|
+
<Box tag="span">Inline</Box> // WRONG!
|
|
107
|
+
<Box display="flex" gap={4}>...</Box> // WRONG!
|
|
108
|
+
<Box display="grid" gridCols={3}>...</Box> // WRONG!
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**CORRECT** - Using semantic components:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
// DO THIS INSTEAD
|
|
115
|
+
import { Img, Link, H1, Nav } from '@cronocode/react-box/components/semantics';
|
|
116
|
+
import Button from '@cronocode/react-box/components/button';
|
|
117
|
+
import Flex from '@cronocode/react-box/components/flex';
|
|
118
|
+
import Grid from '@cronocode/react-box/components/grid';
|
|
119
|
+
|
|
120
|
+
<Img props={{ src: logo, alt: "Logo" }} />
|
|
121
|
+
<Link props={{ href: "#" }}>Link</Link>
|
|
122
|
+
<Button onClick={...}>Click</Button>
|
|
123
|
+
<Flex gap={4}>...</Flex>
|
|
124
|
+
<Grid gridCols={3}>...</Grid>
|
|
125
|
+
<Nav>...</Nav>
|
|
126
|
+
<H1 fontSize={32}>Title</H1>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Component Shortcuts Reference
|
|
130
|
+
|
|
131
|
+
| Instead of... | Use... | Import from |
|
|
132
|
+
| ---------------------- | ------------ | ------------------------------------------- |
|
|
133
|
+
| `<Box display="flex">` | `<Flex>` | `@cronocode/react-box/components/flex` |
|
|
134
|
+
| `<Box display="grid">` | `<Grid>` | `@cronocode/react-box/components/grid` |
|
|
135
|
+
| `<Box tag="button">` | `<Button>` | `@cronocode/react-box/components/button` |
|
|
136
|
+
| `<Box tag="input">` | `<Textbox>` | `@cronocode/react-box/components/textbox` |
|
|
137
|
+
| `<Box tag="textarea">` | `<Textarea>` | `@cronocode/react-box/components/textarea` |
|
|
138
|
+
| `<Box tag="a">` | `<Link>` | `@cronocode/react-box/components/semantics` |
|
|
139
|
+
| `<Box tag="img">` | `<Img>` | `@cronocode/react-box/components/semantics` |
|
|
140
|
+
| `<Box tag="h1">` | `<H1>` | `@cronocode/react-box/components/semantics` |
|
|
141
|
+
| `<Box tag="h2">` | `<H2>` | `@cronocode/react-box/components/semantics` |
|
|
142
|
+
| `<Box tag="h3">` | `<H3>` | `@cronocode/react-box/components/semantics` |
|
|
143
|
+
| `<Box tag="p">` | `<P>` | `@cronocode/react-box/components/semantics` |
|
|
144
|
+
| `<Box tag="span">` | `<Span>` | `@cronocode/react-box/components/semantics` |
|
|
145
|
+
| `<Box tag="nav">` | `<Nav>` | `@cronocode/react-box/components/semantics` |
|
|
146
|
+
| `<Box tag="header">` | `<Header>` | `@cronocode/react-box/components/semantics` |
|
|
147
|
+
| `<Box tag="footer">` | `<Footer>` | `@cronocode/react-box/components/semantics` |
|
|
148
|
+
| `<Box tag="main">` | `<Main>` | `@cronocode/react-box/components/semantics` |
|
|
149
|
+
| `<Box tag="section">` | `<Section>` | `@cronocode/react-box/components/semantics` |
|
|
150
|
+
| `<Box tag="article">` | `<Article>` | `@cronocode/react-box/components/semantics` |
|
|
151
|
+
| `<Box tag="aside">` | `<Aside>` | `@cronocode/react-box/components/semantics` |
|
|
152
|
+
| `<Box tag="label">` | `<Label>` | `@cronocode/react-box/components/semantics` |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
7
156
|
## Quick Overview
|
|
8
157
|
|
|
9
158
|
**What it is**: A React library that converts component props directly into CSS classes at runtime. No CSS files needed.
|
|
@@ -31,15 +180,16 @@ import Button from '@cronocode/react-box/components/button';
|
|
|
31
180
|
|
|
32
181
|
**This is the #1 source of confusion.** Different props have different dividers:
|
|
33
182
|
|
|
34
|
-
| Prop Category
|
|
35
|
-
|
|
36
|
-
| Spacing (`p`, `m`, `gap`, `px`, `py`, `mx`, `my`, etc.) | 4
|
|
37
|
-
| Font size (`fontSize`)
|
|
38
|
-
| Width/Height (numeric)
|
|
39
|
-
| Border width (`b`, `bx`, `by`, `bt`, `br`, `bb`, `bl`)
|
|
40
|
-
| Border radius (`borderRadius`)
|
|
183
|
+
| Prop Category | Divider | Formula | Example | CSS Output |
|
|
184
|
+
| ------------------------------------------------------- | ------- | ------------ | ------------------ | ------------------------ |
|
|
185
|
+
| Spacing (`p`, `m`, `gap`, `px`, `py`, `mx`, `my`, etc.) | 4 | value/4 rem | `p={4}` | `padding: 1rem` (16px) |
|
|
186
|
+
| Font size (`fontSize`) | **16** | value/16 rem | `fontSize={16}` | `font-size: 1rem` (16px) |
|
|
187
|
+
| Width/Height (numeric) | 4 | value/4 rem | `width={20}` | `width: 5rem` (80px) |
|
|
188
|
+
| Border width (`b`, `bx`, `by`, `bt`, `br`, `bb`, `bl`) | none | direct px | `b={1}` | `border-width: 1px` |
|
|
189
|
+
| Border radius (`borderRadius`) | none | direct px | `borderRadius={8}` | `border-radius: 8px` |
|
|
41
190
|
|
|
42
191
|
### Common fontSize Values
|
|
192
|
+
|
|
43
193
|
```tsx
|
|
44
194
|
fontSize={12} // → 0.75rem ≈ 12px (small)
|
|
45
195
|
fontSize={14} // → 0.875rem ≈ 14px (body)
|
|
@@ -50,6 +200,7 @@ fontSize={32} // → 2rem = 32px (h1)
|
|
|
50
200
|
```
|
|
51
201
|
|
|
52
202
|
### Common Spacing Values (divider = 4)
|
|
203
|
+
|
|
53
204
|
```tsx
|
|
54
205
|
p={1} // → 0.25rem = 4px
|
|
55
206
|
p={2} // → 0.5rem = 8px
|
|
@@ -64,87 +215,95 @@ p={8} // → 2rem = 32px
|
|
|
64
215
|
## Prop Reference
|
|
65
216
|
|
|
66
217
|
### Spacing
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
218
|
+
|
|
219
|
+
| Prop | CSS Property |
|
|
220
|
+
| ---------------------- | ----------------------------- |
|
|
221
|
+
| `p` | padding |
|
|
222
|
+
| `px` | padding-left + padding-right |
|
|
223
|
+
| `py` | padding-top + padding-bottom |
|
|
72
224
|
| `pt`, `pr`, `pb`, `pl` | padding-top/right/bottom/left |
|
|
73
|
-
| `m`
|
|
74
|
-
| `mx`, `my`
|
|
75
|
-
| `mt`, `mr`, `mb`, `ml` | margin-top/right/bottom/left
|
|
76
|
-
| `gap`
|
|
225
|
+
| `m` | margin |
|
|
226
|
+
| `mx`, `my` | margin horizontal/vertical |
|
|
227
|
+
| `mt`, `mr`, `mb`, `ml` | margin-top/right/bottom/left |
|
|
228
|
+
| `gap` | gap (flexbox/grid) |
|
|
77
229
|
|
|
78
230
|
### Layout
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
231
|
+
|
|
232
|
+
| Prop | CSS Property | Values |
|
|
233
|
+
| --------- | --------------- | -------------------------------------------------------------------------- |
|
|
234
|
+
| `display` | display | `'flex'`, `'block'`, `'inline'`, `'grid'`, `'none'`, `'inline-flex'`, etc. |
|
|
235
|
+
| `d` | flex-direction | `'row'`, `'column'`, `'row-reverse'`, `'column-reverse'` |
|
|
236
|
+
| `wrap` | flex-wrap | `'wrap'`, `'nowrap'`, `'wrap-reverse'` |
|
|
237
|
+
| `ai` | align-items | `'center'`, `'start'`, `'end'`, `'stretch'`, `'baseline'` |
|
|
238
|
+
| `jc` | justify-content | `'center'`, `'start'`, `'end'`, `'between'`, `'around'`, `'evenly'` |
|
|
239
|
+
| `flex` | flex | number or string |
|
|
240
|
+
| `grow` | flex-grow | number |
|
|
241
|
+
| `shrink` | flex-shrink | number |
|
|
89
242
|
|
|
90
243
|
### Sizing
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
244
|
+
|
|
245
|
+
| Prop | CSS Property | Accepts |
|
|
246
|
+
| ------------------------ | -------------- | ------------------------------------------------------------------- |
|
|
247
|
+
| `width` | width | number (rem/4), string (`'auto'`, `'1/2'`, `'fit'`, `'fit-screen'`) |
|
|
248
|
+
| `height` | height | number (rem/4), string (`'auto'`, `'fit'`, `'fit-screen'`) |
|
|
249
|
+
| `minWidth`, `maxWidth` | min/max-width | number or string |
|
|
250
|
+
| `minHeight`, `maxHeight` | min/max-height | number or string |
|
|
97
251
|
|
|
98
252
|
### Colors (Tailwind-like palette)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
253
|
+
|
|
254
|
+
| Prop | CSS Property |
|
|
255
|
+
| ------------- | ---------------- |
|
|
256
|
+
| `bgColor` | background-color |
|
|
257
|
+
| `color` | color |
|
|
258
|
+
| `borderColor` | border-color |
|
|
104
259
|
|
|
105
260
|
**Color values**: `'gray-50'` through `'gray-900'`, same for `red`, `orange`, `yellow`, `green`, `teal`, `blue`, `indigo`, `purple`, `pink`, `violet`.
|
|
106
261
|
|
|
107
262
|
Also: `'white'`, `'black'`, `'transparent'`, `'inherit'`, `'currentColor'`
|
|
108
263
|
|
|
109
264
|
### Borders
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
265
|
+
|
|
266
|
+
| Prop | CSS Property |
|
|
267
|
+
| ---------------------- | ---------------------------------------------------------- |
|
|
268
|
+
| `b` | border-width (all sides) |
|
|
269
|
+
| `bx` | border-left-width + border-right-width |
|
|
270
|
+
| `by` | border-top-width + border-bottom-width |
|
|
271
|
+
| `bt`, `br`, `bb`, `bl` | individual sides |
|
|
272
|
+
| `borderRadius` | border-radius |
|
|
273
|
+
| `borderStyle` | border-style (`'solid'`, `'dashed'`, `'dotted'`, `'none'`) |
|
|
118
274
|
|
|
119
275
|
### Typography
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
276
|
+
|
|
277
|
+
| Prop | CSS Property |
|
|
278
|
+
| ---------------- | ------------------------------------------------------------ |
|
|
279
|
+
| `fontSize` | font-size (divider: 16) |
|
|
280
|
+
| `fontWeight` | font-weight (`400`, `500`, `600`, `700`, etc.) |
|
|
281
|
+
| `lineHeight` | line-height (number = pixels, e.g. `lineHeight={24}` → 24px) |
|
|
282
|
+
| `textAlign` | text-align |
|
|
283
|
+
| `textDecoration` | text-decoration |
|
|
284
|
+
| `textTransform` | text-transform |
|
|
285
|
+
| `whiteSpace` | white-space |
|
|
286
|
+
| `overflow` | overflow |
|
|
287
|
+
| `textOverflow` | text-overflow |
|
|
131
288
|
|
|
132
289
|
### Positioning
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
290
|
+
|
|
291
|
+
| Prop | CSS Property |
|
|
292
|
+
| -------------------------------- | ------------------------------------------------------------ |
|
|
293
|
+
| `position` | position (`'relative'`, `'absolute'`, `'fixed'`, `'sticky'`) |
|
|
294
|
+
| `top`, `right`, `bottom`, `left` | positioning offsets |
|
|
295
|
+
| `zIndex` | z-index |
|
|
138
296
|
|
|
139
297
|
### Effects
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
298
|
+
|
|
299
|
+
| Prop | CSS Property |
|
|
300
|
+
| --------------- | --------------------------------------------------------------- |
|
|
301
|
+
| `shadow` | box-shadow (`'small'`, `'medium'`, `'large'`, `'xl'`, `'none'`) |
|
|
302
|
+
| `opacity` | opacity |
|
|
303
|
+
| `cursor` | cursor |
|
|
304
|
+
| `pointerEvents` | pointer-events |
|
|
305
|
+
| `transition` | transition |
|
|
306
|
+
| `transform` | transform |
|
|
148
307
|
|
|
149
308
|
---
|
|
150
309
|
|
|
@@ -172,23 +331,24 @@ Mobile-first breakpoints using min-width media queries:
|
|
|
172
331
|
|
|
173
332
|
```tsx
|
|
174
333
|
<Box
|
|
175
|
-
p={2}
|
|
176
|
-
sm={{ p: 3 }}
|
|
177
|
-
md={{ p: 4 }}
|
|
178
|
-
lg={{ p: 6 }}
|
|
179
|
-
xl={{ p: 8 }}
|
|
334
|
+
p={2} // Base (mobile)
|
|
335
|
+
sm={{ p: 3 }} // ≥640px
|
|
336
|
+
md={{ p: 4 }} // ≥768px
|
|
337
|
+
lg={{ p: 6 }} // ≥1024px
|
|
338
|
+
xl={{ p: 8 }} // ≥1280px
|
|
180
339
|
xxl={{ p: 10 }} // ≥1536px
|
|
181
340
|
/>
|
|
182
341
|
```
|
|
183
342
|
|
|
184
343
|
**Combine with pseudo-classes**:
|
|
344
|
+
|
|
185
345
|
```tsx
|
|
186
346
|
<Box
|
|
187
347
|
bgColor="white"
|
|
188
348
|
hover={{ bgColor: 'gray-100' }}
|
|
189
349
|
md={{
|
|
190
350
|
bgColor: 'gray-50',
|
|
191
|
-
hover: { bgColor: 'gray-200' }
|
|
351
|
+
hover: { bgColor: 'gray-200' },
|
|
192
352
|
}}
|
|
193
353
|
/>
|
|
194
354
|
```
|
|
@@ -199,20 +359,70 @@ Mobile-first breakpoints using min-width media queries:
|
|
|
199
359
|
|
|
200
360
|
### Setting Up Themes
|
|
201
361
|
|
|
362
|
+
The `Box.Theme` component provides theme management with automatic detection based on system preferences.
|
|
363
|
+
|
|
364
|
+
**Auto-detect theme** (recommended):
|
|
365
|
+
|
|
202
366
|
```tsx
|
|
203
367
|
import Box from '@cronocode/react-box';
|
|
204
368
|
|
|
205
369
|
function App() {
|
|
206
370
|
return (
|
|
207
|
-
<Box.Theme
|
|
371
|
+
<Box.Theme>
|
|
372
|
+
{/* Theme auto-detects from prefers-color-scheme: 'light' or 'dark' */}
|
|
208
373
|
<YourApp />
|
|
209
374
|
</Box.Theme>
|
|
210
375
|
);
|
|
211
376
|
}
|
|
212
377
|
```
|
|
213
378
|
|
|
379
|
+
**Explicit theme**:
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
<Box.Theme theme="dark">
|
|
383
|
+
<YourApp />
|
|
384
|
+
</Box.Theme>
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Global vs Local theme**:
|
|
388
|
+
|
|
389
|
+
```tsx
|
|
390
|
+
// Global: Adds theme class to document.documentElement (affects entire page)
|
|
391
|
+
<Box.Theme theme="dark" use="global">
|
|
392
|
+
<YourApp />
|
|
393
|
+
</Box.Theme>
|
|
394
|
+
|
|
395
|
+
// Local (default): Wraps children in a Box with theme class (scoped)
|
|
396
|
+
<Box.Theme theme="dark" use="local">
|
|
397
|
+
<Section>Content</Section>
|
|
398
|
+
</Box.Theme>
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Using the Theme Hook
|
|
402
|
+
|
|
403
|
+
```tsx
|
|
404
|
+
import Box from '@cronocode/react-box';
|
|
405
|
+
|
|
406
|
+
function ThemeSwitcher() {
|
|
407
|
+
const [theme, setTheme] = Box.useTheme();
|
|
408
|
+
|
|
409
|
+
return <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Current: {theme}</button>;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Must be used within Box.Theme provider
|
|
413
|
+
function App() {
|
|
414
|
+
return (
|
|
415
|
+
<Box.Theme>
|
|
416
|
+
<ThemeSwitcher />
|
|
417
|
+
</Box.Theme>
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
214
422
|
### Theme-Aware Styles
|
|
215
423
|
|
|
424
|
+
Apply styles based on the active theme:
|
|
425
|
+
|
|
216
426
|
```tsx
|
|
217
427
|
<Box
|
|
218
428
|
bgColor="white"
|
|
@@ -228,6 +438,8 @@ function App() {
|
|
|
228
438
|
|
|
229
439
|
### Theme + Pseudo-Classes
|
|
230
440
|
|
|
441
|
+
Combine theme styles with pseudo-classes:
|
|
442
|
+
|
|
231
443
|
```tsx
|
|
232
444
|
<Box
|
|
233
445
|
bgColor="white"
|
|
@@ -241,6 +453,29 @@ function App() {
|
|
|
241
453
|
/>
|
|
242
454
|
```
|
|
243
455
|
|
|
456
|
+
### Theme + Responsive Breakpoints
|
|
457
|
+
|
|
458
|
+
Combine all three systems:
|
|
459
|
+
|
|
460
|
+
```tsx
|
|
461
|
+
<Box
|
|
462
|
+
p={4}
|
|
463
|
+
bgColor="white"
|
|
464
|
+
md={{
|
|
465
|
+
p: 6,
|
|
466
|
+
bgColor: 'gray-50',
|
|
467
|
+
}}
|
|
468
|
+
theme={{
|
|
469
|
+
dark: {
|
|
470
|
+
bgColor: 'gray-900',
|
|
471
|
+
md: {
|
|
472
|
+
bgColor: 'gray-800',
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
}}
|
|
476
|
+
/>
|
|
477
|
+
```
|
|
478
|
+
|
|
244
479
|
---
|
|
245
480
|
|
|
246
481
|
## Component System
|
|
@@ -261,6 +496,7 @@ Import ready-to-use components:
|
|
|
261
496
|
import Button from '@cronocode/react-box/components/button';
|
|
262
497
|
import Textbox from '@cronocode/react-box/components/textbox';
|
|
263
498
|
import Checkbox from '@cronocode/react-box/components/checkbox';
|
|
499
|
+
import RadioButton from '@cronocode/react-box/components/radioButton';
|
|
264
500
|
import Dropdown from '@cronocode/react-box/components/dropdown';
|
|
265
501
|
import Tooltip from '@cronocode/react-box/components/tooltip';
|
|
266
502
|
|
|
@@ -270,7 +506,7 @@ import Grid from '@cronocode/react-box/components/grid'; // Box with display="g
|
|
|
270
506
|
|
|
271
507
|
<Button variant="primary">Submit</Button>
|
|
272
508
|
<Textbox placeholder="Enter text..." />
|
|
273
|
-
<Flex gap={4}
|
|
509
|
+
<Flex gap={4} ai="center">...</Flex>
|
|
274
510
|
<Flex inline gap={2}>Inline flex</Flex>
|
|
275
511
|
```
|
|
276
512
|
|
|
@@ -324,7 +560,7 @@ Box.components({
|
|
|
324
560
|
<Box component="card" variant="bordered">
|
|
325
561
|
<Box component="card.header">Title</Box>
|
|
326
562
|
<Box component="card.body">Content</Box>
|
|
327
|
-
</Box
|
|
563
|
+
</Box>;
|
|
328
564
|
```
|
|
329
565
|
|
|
330
566
|
---
|
|
@@ -362,11 +598,13 @@ export const { extendedProps, extendedPropTypes } = Box.extend(
|
|
|
362
598
|
valueFormat: (value, getVariable) => getVariable(value),
|
|
363
599
|
},
|
|
364
600
|
],
|
|
365
|
-
}
|
|
601
|
+
},
|
|
366
602
|
);
|
|
367
603
|
|
|
368
604
|
// Now use your custom colors
|
|
369
|
-
<Box bgColor="brand-primary" color="white">
|
|
605
|
+
<Box bgColor="brand-primary" color="white">
|
|
606
|
+
Branded
|
|
607
|
+
</Box>;
|
|
370
608
|
```
|
|
371
609
|
|
|
372
610
|
### TypeScript Type Augmentation
|
|
@@ -411,15 +649,17 @@ declare module '@cronocode/react-box/types' {
|
|
|
411
649
|
## Common Patterns
|
|
412
650
|
|
|
413
651
|
### Flex Container
|
|
652
|
+
|
|
414
653
|
```tsx
|
|
415
654
|
import Flex from '@cronocode/react-box/components/flex';
|
|
416
655
|
|
|
417
|
-
<Flex d="column" gap={4}
|
|
656
|
+
<Flex d="column" gap={4} ai="center" jc="between">
|
|
418
657
|
{children}
|
|
419
|
-
</Flex
|
|
658
|
+
</Flex>;
|
|
420
659
|
```
|
|
421
660
|
|
|
422
661
|
### Card
|
|
662
|
+
|
|
423
663
|
```tsx
|
|
424
664
|
<Box p={4} bgColor="white" borderRadius={8} shadow="medium">
|
|
425
665
|
{content}
|
|
@@ -427,6 +667,7 @@ import Flex from '@cronocode/react-box/components/flex';
|
|
|
427
667
|
```
|
|
428
668
|
|
|
429
669
|
### Button
|
|
670
|
+
|
|
430
671
|
```tsx
|
|
431
672
|
import Button from '@cronocode/react-box/components/button';
|
|
432
673
|
|
|
@@ -441,10 +682,11 @@ import Button from '@cronocode/react-box/components/button';
|
|
|
441
682
|
disabled={{ opacity: 0.5, cursor: 'not-allowed' }}
|
|
442
683
|
>
|
|
443
684
|
Click me
|
|
444
|
-
</Button
|
|
685
|
+
</Button>;
|
|
445
686
|
```
|
|
446
687
|
|
|
447
688
|
### Input Field
|
|
689
|
+
|
|
448
690
|
```tsx
|
|
449
691
|
import Textbox from '@cronocode/react-box/components/textbox';
|
|
450
692
|
|
|
@@ -457,50 +699,43 @@ import Textbox from '@cronocode/react-box/components/textbox';
|
|
|
457
699
|
borderColor="gray-300"
|
|
458
700
|
borderRadius={6}
|
|
459
701
|
focus={{ borderColor: 'blue-500', outline: 'none' }}
|
|
460
|
-
|
|
702
|
+
/>;
|
|
461
703
|
```
|
|
462
704
|
|
|
463
705
|
### Grid Layout
|
|
706
|
+
|
|
464
707
|
```tsx
|
|
465
708
|
import Grid from '@cronocode/react-box/components/grid';
|
|
466
709
|
|
|
467
710
|
<Grid gridCols={3} gap={4}>
|
|
468
|
-
{items.map(item =>
|
|
469
|
-
</
|
|
711
|
+
{items.map((item) => (
|
|
712
|
+
<Box key={item.id}>{item.content}</Box>
|
|
713
|
+
))}
|
|
714
|
+
</Grid>;
|
|
470
715
|
```
|
|
471
716
|
|
|
472
717
|
### Responsive Stack
|
|
718
|
+
|
|
473
719
|
```tsx
|
|
474
720
|
import Flex from '@cronocode/react-box/components/flex';
|
|
475
721
|
|
|
476
722
|
<Flex d="column" gap={2} md={{ d: 'row', gap: 4 }}>
|
|
477
723
|
{children}
|
|
478
|
-
</Flex
|
|
724
|
+
</Flex>;
|
|
479
725
|
```
|
|
480
726
|
|
|
481
727
|
### Truncated Text
|
|
728
|
+
|
|
482
729
|
```tsx
|
|
483
|
-
<Box
|
|
484
|
-
overflow="hidden"
|
|
485
|
-
textOverflow="ellipsis"
|
|
486
|
-
whiteSpace="nowrap"
|
|
487
|
-
>
|
|
730
|
+
<Box overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap">
|
|
488
731
|
Long text that will be truncated...
|
|
489
732
|
</Box>
|
|
490
733
|
```
|
|
491
734
|
|
|
492
735
|
### Overlay/Modal Backdrop
|
|
736
|
+
|
|
493
737
|
```tsx
|
|
494
|
-
<Box
|
|
495
|
-
position="fixed"
|
|
496
|
-
top={0}
|
|
497
|
-
left={0}
|
|
498
|
-
right={0}
|
|
499
|
-
bottom={0}
|
|
500
|
-
bgColor="black"
|
|
501
|
-
opacity={0.5}
|
|
502
|
-
zIndex={50}
|
|
503
|
-
/>
|
|
738
|
+
<Box position="fixed" top={0} left={0} right={0} bottom={0} bgColor="black" opacity={0.5} zIndex={50} />
|
|
504
739
|
```
|
|
505
740
|
|
|
506
741
|
**Note**: For tooltips, dropdowns, and popups that need to escape `overflow: hidden` containers, use the `Tooltip` component instead of manual `zIndex`. It uses React portals to render content outside the DOM hierarchy, avoiding z-index and overflow issues.
|
|
@@ -510,7 +745,7 @@ import Tooltip from '@cronocode/react-box/components/tooltip';
|
|
|
510
745
|
|
|
511
746
|
<Tooltip content="Tooltip text">
|
|
512
747
|
<Button>Hover me</Button>
|
|
513
|
-
</Tooltip
|
|
748
|
+
</Tooltip>;
|
|
514
749
|
```
|
|
515
750
|
|
|
516
751
|
---
|
|
@@ -523,10 +758,7 @@ Style child elements when parent is hovered:
|
|
|
523
758
|
// Parent with a className
|
|
524
759
|
<Flex className="card-row" gap={2}>
|
|
525
760
|
{/* Child responds to parent hover */}
|
|
526
|
-
<Box
|
|
527
|
-
opacity={0}
|
|
528
|
-
hoverGroup={{ 'card-row': { opacity: 1 } }}
|
|
529
|
-
>
|
|
761
|
+
<Box opacity={0} hoverGroup={{ 'card-row': { opacity: 1 } }}>
|
|
530
762
|
Actions
|
|
531
763
|
</Box>
|
|
532
764
|
</Flex>
|
|
@@ -543,7 +775,7 @@ import { getStyles, resetStyles } from '@cronocode/react-box/ssg';
|
|
|
543
775
|
const cssString = getStyles();
|
|
544
776
|
|
|
545
777
|
// Inject into your HTML
|
|
546
|
-
<style id="crono-box">{cssString}</style
|
|
778
|
+
<style id="crono-box">{cssString}</style>;
|
|
547
779
|
|
|
548
780
|
// Reset for next request (in SSR)
|
|
549
781
|
resetStyles();
|
|
@@ -553,17 +785,34 @@ resetStyles();
|
|
|
553
785
|
|
|
554
786
|
## Key Reminders for AI Assistants
|
|
555
787
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
788
|
+
### ⚠️ MOST IMPORTANT (Common AI Mistakes)
|
|
789
|
+
|
|
790
|
+
1. **NEVER use `style={{ }}` attribute** - Always use Box props instead. If a prop doesn't exist, extend Box with `Box.extend()`
|
|
791
|
+
2. **NEVER use `<Box tag="...">` for common elements** - Use semantic components instead:
|
|
792
|
+
- `<Box tag="a">` → `<Link>`
|
|
793
|
+
- `<Box tag="img">` → `<Img>`
|
|
794
|
+
- `<Box tag="button">` → `<Button>`
|
|
795
|
+
- `<Box tag="h1/h2/h3">` → `<H1>/<H2>/<H3>`
|
|
796
|
+
- `<Box tag="p">` → `<P>`
|
|
797
|
+
- `<Box tag="nav/header/footer>` → `<Nav>/<Header>/<Footer>`
|
|
798
|
+
3. **NEVER use `<Box display="flex/grid">`** - Use `<Flex>` or `<Grid>` components instead
|
|
799
|
+
|
|
800
|
+
### Value Formatting
|
|
801
|
+
|
|
802
|
+
4. **fontSize uses divider 16**, not 4. `fontSize={14}` → 14px, NOT 3.5px
|
|
803
|
+
5. **Spacing uses divider 4**. `p={4}` → 16px (1rem)
|
|
804
|
+
6. **Border width is direct px**. `b={1}` → 1px
|
|
805
|
+
7. **lineHeight is direct px**. `lineHeight={24}` → 24px
|
|
806
|
+
|
|
807
|
+
### Syntax & Patterns
|
|
808
|
+
|
|
809
|
+
8. **Colors are Tailwind-like**: `'gray-500'`, `'blue-600'`, etc.
|
|
810
|
+
9. **Breakpoints are mobile-first**: base → sm → md → lg → xl → xxl
|
|
811
|
+
10. **Theme styles nest**: `theme={{ dark: { hover: { ... } } }}`
|
|
812
|
+
11. **HTML attributes go in `props`**: `<Link props={{ href: '/link' }}>` - NOT directly as Box props
|
|
813
|
+
12. **Percentage widths**: Use strings like `width="1/2"` for 50%
|
|
814
|
+
13. **Full size shortcuts**: `width="fit"` = 100%, `width="fit-screen"` = 100vw
|
|
815
|
+
14. **Box is memoized** with `React.memo` - props comparison is efficient
|
|
567
816
|
|
|
568
817
|
---
|
|
569
818
|
|