@cronocode/react-box 3.1.6 → 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 +825 -0
- package/components/dataGrid/components/dataGridEmptyColumns.d.ts +1 -0
- package/components/dataGrid/contracts/dataGridContract.d.ts +14 -0
- package/components/dataGrid/models/columnModel.d.ts +10 -0
- package/components/dataGrid/models/gridModel.d.ts +7 -1
- package/components/dataGrid.cjs +1 -1
- package/components/dataGrid.mjs +606 -417
- package/components/dropdown.cjs +1 -1
- package/components/dropdown.mjs +54 -54
- package/components/semantics.d.ts +25 -25
- package/core/boxStyles.d.ts +134 -22
- package/core/extends/boxComponents.d.ts +17 -167
- package/core/theme/theme.d.ts +1 -1
- package/core/variables.d.ts +2 -0
- package/core.cjs +3 -3
- package/core.mjs +570 -582
- package/package.json +6 -5
|
@@ -0,0 +1,825 @@
|
|
|
1
|
+
# @cronocode/react-box - AI Assistant Context
|
|
2
|
+
|
|
3
|
+
Reference document for AI assistants helping developers use this runtime CSS-in-JS library.
|
|
4
|
+
|
|
5
|
+
---
|
|
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
|
+
|
|
156
|
+
## Quick Overview
|
|
157
|
+
|
|
158
|
+
**What it is**: A React library that converts component props directly into CSS classes at runtime. No CSS files needed.
|
|
159
|
+
|
|
160
|
+
**Core component**: `Box` - a polymorphic component that accepts ~144 CSS props and renders any HTML element.
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import Box from '@cronocode/react-box';
|
|
164
|
+
|
|
165
|
+
// Basic usage
|
|
166
|
+
<Box p={4} bgColor="blue-500" color="white">Content</Box>
|
|
167
|
+
|
|
168
|
+
// Renders as different elements
|
|
169
|
+
<Box tag="button" p={3}>Button</Box>
|
|
170
|
+
<Box tag="a" props={{ href: '/link' }}>Link</Box>
|
|
171
|
+
|
|
172
|
+
// Alias components (recommended)
|
|
173
|
+
import Button from '@cronocode/react-box/components/button';
|
|
174
|
+
<Button p={3}>Button</Button>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Critical: Numeric Value Formatters
|
|
180
|
+
|
|
181
|
+
**This is the #1 source of confusion.** Different props have different dividers:
|
|
182
|
+
|
|
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` |
|
|
190
|
+
|
|
191
|
+
### Common fontSize Values
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
fontSize={12} // → 0.75rem ≈ 12px (small)
|
|
195
|
+
fontSize={14} // → 0.875rem ≈ 14px (body)
|
|
196
|
+
fontSize={16} // → 1rem = 16px (default)
|
|
197
|
+
fontSize={18} // → 1.125rem ≈ 18px (large)
|
|
198
|
+
fontSize={24} // → 1.5rem = 24px (h2)
|
|
199
|
+
fontSize={32} // → 2rem = 32px (h1)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Common Spacing Values (divider = 4)
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
p={1} // → 0.25rem = 4px
|
|
206
|
+
p={2} // → 0.5rem = 8px
|
|
207
|
+
p={3} // → 0.75rem = 12px
|
|
208
|
+
p={4} // → 1rem = 16px
|
|
209
|
+
p={6} // → 1.5rem = 24px
|
|
210
|
+
p={8} // → 2rem = 32px
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Prop Reference
|
|
216
|
+
|
|
217
|
+
### Spacing
|
|
218
|
+
|
|
219
|
+
| Prop | CSS Property |
|
|
220
|
+
| ---------------------- | ----------------------------- |
|
|
221
|
+
| `p` | padding |
|
|
222
|
+
| `px` | padding-left + padding-right |
|
|
223
|
+
| `py` | padding-top + padding-bottom |
|
|
224
|
+
| `pt`, `pr`, `pb`, `pl` | padding-top/right/bottom/left |
|
|
225
|
+
| `m` | margin |
|
|
226
|
+
| `mx`, `my` | margin horizontal/vertical |
|
|
227
|
+
| `mt`, `mr`, `mb`, `ml` | margin-top/right/bottom/left |
|
|
228
|
+
| `gap` | gap (flexbox/grid) |
|
|
229
|
+
|
|
230
|
+
### Layout
|
|
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 |
|
|
242
|
+
|
|
243
|
+
### Sizing
|
|
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 |
|
|
251
|
+
|
|
252
|
+
### Colors (Tailwind-like palette)
|
|
253
|
+
|
|
254
|
+
| Prop | CSS Property |
|
|
255
|
+
| ------------- | ---------------- |
|
|
256
|
+
| `bgColor` | background-color |
|
|
257
|
+
| `color` | color |
|
|
258
|
+
| `borderColor` | border-color |
|
|
259
|
+
|
|
260
|
+
**Color values**: `'gray-50'` through `'gray-900'`, same for `red`, `orange`, `yellow`, `green`, `teal`, `blue`, `indigo`, `purple`, `pink`, `violet`.
|
|
261
|
+
|
|
262
|
+
Also: `'white'`, `'black'`, `'transparent'`, `'inherit'`, `'currentColor'`
|
|
263
|
+
|
|
264
|
+
### Borders
|
|
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'`) |
|
|
274
|
+
|
|
275
|
+
### Typography
|
|
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 |
|
|
288
|
+
|
|
289
|
+
### Positioning
|
|
290
|
+
|
|
291
|
+
| Prop | CSS Property |
|
|
292
|
+
| -------------------------------- | ------------------------------------------------------------ |
|
|
293
|
+
| `position` | position (`'relative'`, `'absolute'`, `'fixed'`, `'sticky'`) |
|
|
294
|
+
| `top`, `right`, `bottom`, `left` | positioning offsets |
|
|
295
|
+
| `zIndex` | z-index |
|
|
296
|
+
|
|
297
|
+
### Effects
|
|
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 |
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Pseudo-Classes
|
|
311
|
+
|
|
312
|
+
Apply styles on interaction states:
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
<Box
|
|
316
|
+
bgColor="blue-500"
|
|
317
|
+
hover={{ bgColor: 'blue-600' }}
|
|
318
|
+
focus={{ outline: 'none', ring: 2 }}
|
|
319
|
+
active={{ bgColor: 'blue-700' }}
|
|
320
|
+
disabled={{ opacity: 0.5, cursor: 'not-allowed' }}
|
|
321
|
+
/>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**Available pseudo-classes**: `hover`, `focus`, `active`, `disabled`, `checked`, `indeterminate`, `required`, `selected`, `focusWithin`, `focusVisible`, `first`, `last`, `even`, `odd`, `empty`
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Responsive Breakpoints
|
|
329
|
+
|
|
330
|
+
Mobile-first breakpoints using min-width media queries:
|
|
331
|
+
|
|
332
|
+
```tsx
|
|
333
|
+
<Box
|
|
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
|
|
339
|
+
xxl={{ p: 10 }} // ≥1536px
|
|
340
|
+
/>
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Combine with pseudo-classes**:
|
|
344
|
+
|
|
345
|
+
```tsx
|
|
346
|
+
<Box
|
|
347
|
+
bgColor="white"
|
|
348
|
+
hover={{ bgColor: 'gray-100' }}
|
|
349
|
+
md={{
|
|
350
|
+
bgColor: 'gray-50',
|
|
351
|
+
hover: { bgColor: 'gray-200' },
|
|
352
|
+
}}
|
|
353
|
+
/>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## Theme System
|
|
359
|
+
|
|
360
|
+
### Setting Up Themes
|
|
361
|
+
|
|
362
|
+
The `Box.Theme` component provides theme management with automatic detection based on system preferences.
|
|
363
|
+
|
|
364
|
+
**Auto-detect theme** (recommended):
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
import Box from '@cronocode/react-box';
|
|
368
|
+
|
|
369
|
+
function App() {
|
|
370
|
+
return (
|
|
371
|
+
<Box.Theme>
|
|
372
|
+
{/* Theme auto-detects from prefers-color-scheme: 'light' or 'dark' */}
|
|
373
|
+
<YourApp />
|
|
374
|
+
</Box.Theme>
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
```
|
|
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
|
+
|
|
422
|
+
### Theme-Aware Styles
|
|
423
|
+
|
|
424
|
+
Apply styles based on the active theme:
|
|
425
|
+
|
|
426
|
+
```tsx
|
|
427
|
+
<Box
|
|
428
|
+
bgColor="white"
|
|
429
|
+
color="gray-900"
|
|
430
|
+
theme={{
|
|
431
|
+
dark: {
|
|
432
|
+
bgColor: 'gray-900',
|
|
433
|
+
color: 'gray-100',
|
|
434
|
+
},
|
|
435
|
+
}}
|
|
436
|
+
/>
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Theme + Pseudo-Classes
|
|
440
|
+
|
|
441
|
+
Combine theme styles with pseudo-classes:
|
|
442
|
+
|
|
443
|
+
```tsx
|
|
444
|
+
<Box
|
|
445
|
+
bgColor="white"
|
|
446
|
+
hover={{ bgColor: 'gray-100' }}
|
|
447
|
+
theme={{
|
|
448
|
+
dark: {
|
|
449
|
+
bgColor: 'gray-800',
|
|
450
|
+
hover: { bgColor: 'gray-700' },
|
|
451
|
+
},
|
|
452
|
+
}}
|
|
453
|
+
/>
|
|
454
|
+
```
|
|
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
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## Component System
|
|
482
|
+
|
|
483
|
+
### Using Built-in Components
|
|
484
|
+
|
|
485
|
+
```tsx
|
|
486
|
+
<Box component="button" variant="primary">Click me</Box>
|
|
487
|
+
<Box component="button.icon" />
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Pre-built Components
|
|
491
|
+
|
|
492
|
+
Import ready-to-use components:
|
|
493
|
+
|
|
494
|
+
```tsx
|
|
495
|
+
// Form components
|
|
496
|
+
import Button from '@cronocode/react-box/components/button';
|
|
497
|
+
import Textbox from '@cronocode/react-box/components/textbox';
|
|
498
|
+
import Checkbox from '@cronocode/react-box/components/checkbox';
|
|
499
|
+
import RadioButton from '@cronocode/react-box/components/radioButton';
|
|
500
|
+
import Dropdown from '@cronocode/react-box/components/dropdown';
|
|
501
|
+
import Tooltip from '@cronocode/react-box/components/tooltip';
|
|
502
|
+
|
|
503
|
+
// Layout
|
|
504
|
+
import Flex from '@cronocode/react-box/components/flex'; // Box with display="flex" (supports inline prop)
|
|
505
|
+
import Grid from '@cronocode/react-box/components/grid'; // Box with display="grid" (supports inline prop)
|
|
506
|
+
|
|
507
|
+
<Button variant="primary">Submit</Button>
|
|
508
|
+
<Textbox placeholder="Enter text..." />
|
|
509
|
+
<Flex gap={4} ai="center">...</Flex>
|
|
510
|
+
<Flex inline gap={2}>Inline flex</Flex>
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Semantic HTML Components
|
|
514
|
+
|
|
515
|
+
Alias components for semantic HTML elements (from `components/semantics`):
|
|
516
|
+
|
|
517
|
+
```tsx
|
|
518
|
+
import {
|
|
519
|
+
// Typography
|
|
520
|
+
P, H1, H2, H3, H4, H5, H6, Span, Mark,
|
|
521
|
+
// Structure
|
|
522
|
+
Header, Footer, Main, Nav, Section, Article, Aside,
|
|
523
|
+
// Other
|
|
524
|
+
Label, Link, Img, Figure, Figcaption, Details, Summary, Menu, Time,
|
|
525
|
+
} from '@cronocode/react-box/components/semantics';
|
|
526
|
+
|
|
527
|
+
// These are Box aliases with the correct HTML tag
|
|
528
|
+
<H1 fontSize={32} fontWeight={700}>Title</H1>
|
|
529
|
+
<P color="gray-600">Paragraph text</P>
|
|
530
|
+
<Link props={{ href: '/about' }} color="blue-500">About</Link>
|
|
531
|
+
<Flex tag="nav" gap={4}>...</Flex>
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Custom Components with Box.components()
|
|
535
|
+
|
|
536
|
+
```tsx
|
|
537
|
+
// Define custom component styles
|
|
538
|
+
Box.components({
|
|
539
|
+
card: {
|
|
540
|
+
styles: {
|
|
541
|
+
display: 'flex',
|
|
542
|
+
d: 'column',
|
|
543
|
+
p: 4,
|
|
544
|
+
bgColor: 'white',
|
|
545
|
+
borderRadius: 8,
|
|
546
|
+
shadow: 'medium',
|
|
547
|
+
},
|
|
548
|
+
variants: {
|
|
549
|
+
bordered: { b: 1, borderColor: 'gray-200', shadow: 'none' },
|
|
550
|
+
elevated: { shadow: 'large' },
|
|
551
|
+
},
|
|
552
|
+
children: {
|
|
553
|
+
header: { styles: { fontSize: 18, fontWeight: 600, mb: 3 } },
|
|
554
|
+
body: { styles: { flex: 1 } },
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// Use it
|
|
560
|
+
<Box component="card" variant="bordered">
|
|
561
|
+
<Box component="card.header">Title</Box>
|
|
562
|
+
<Box component="card.body">Content</Box>
|
|
563
|
+
</Box>;
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## Extension System
|
|
569
|
+
|
|
570
|
+
### Adding Custom Colors/Variables
|
|
571
|
+
|
|
572
|
+
```tsx
|
|
573
|
+
import Box from '@cronocode/react-box';
|
|
574
|
+
|
|
575
|
+
export const { extendedProps, extendedPropTypes } = Box.extend(
|
|
576
|
+
// Custom CSS variables
|
|
577
|
+
{
|
|
578
|
+
'brand-primary': '#ff6600',
|
|
579
|
+
'brand-secondary': '#0066ff',
|
|
580
|
+
},
|
|
581
|
+
|
|
582
|
+
// New props (optional)
|
|
583
|
+
{},
|
|
584
|
+
|
|
585
|
+
// Extend existing props with new values
|
|
586
|
+
{
|
|
587
|
+
bgColor: [
|
|
588
|
+
{
|
|
589
|
+
values: ['brand-primary', 'brand-secondary'] as const,
|
|
590
|
+
styleName: 'background-color',
|
|
591
|
+
valueFormat: (value, getVariable) => getVariable(value),
|
|
592
|
+
},
|
|
593
|
+
],
|
|
594
|
+
color: [
|
|
595
|
+
{
|
|
596
|
+
values: ['brand-primary', 'brand-secondary'] as const,
|
|
597
|
+
styleName: 'color',
|
|
598
|
+
valueFormat: (value, getVariable) => getVariable(value),
|
|
599
|
+
},
|
|
600
|
+
],
|
|
601
|
+
},
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
// Now use your custom colors
|
|
605
|
+
<Box bgColor="brand-primary" color="white">
|
|
606
|
+
Branded
|
|
607
|
+
</Box>;
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### TypeScript Type Augmentation
|
|
611
|
+
|
|
612
|
+
**Manual approach** (simple cases):
|
|
613
|
+
|
|
614
|
+
```typescript
|
|
615
|
+
// types.d.ts
|
|
616
|
+
import '@cronocode/react-box/types';
|
|
617
|
+
|
|
618
|
+
declare module '@cronocode/react-box/types' {
|
|
619
|
+
namespace Augmented {
|
|
620
|
+
interface BoxPropTypes {
|
|
621
|
+
bgColor: 'brand-primary' | 'brand-secondary';
|
|
622
|
+
}
|
|
623
|
+
interface ComponentsTypes {
|
|
624
|
+
card: 'bordered' | 'elevated';
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
**Generic approach** (recommended - auto-extracts types from your definitions):
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
// types.d.ts
|
|
634
|
+
import { ExtractComponentsAndVariants, ExtractBoxStyles } from '@cronocode/react-box/types';
|
|
635
|
+
import { components } from './boxComponents';
|
|
636
|
+
import { extendedPropTypes, extendedProps } from './boxExtends';
|
|
637
|
+
|
|
638
|
+
declare module '@cronocode/react-box/types' {
|
|
639
|
+
namespace Augmented {
|
|
640
|
+
interface BoxProps extends ExtractBoxStyles<typeof extendedProps> {}
|
|
641
|
+
interface BoxPropTypes extends ExtractBoxStyles<typeof extendedPropTypes> {}
|
|
642
|
+
interface ComponentsTypes extends ExtractComponentsAndVariants<typeof components> {}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
## Common Patterns
|
|
650
|
+
|
|
651
|
+
### Flex Container
|
|
652
|
+
|
|
653
|
+
```tsx
|
|
654
|
+
import Flex from '@cronocode/react-box/components/flex';
|
|
655
|
+
|
|
656
|
+
<Flex d="column" gap={4} ai="center" jc="between">
|
|
657
|
+
{children}
|
|
658
|
+
</Flex>;
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
### Card
|
|
662
|
+
|
|
663
|
+
```tsx
|
|
664
|
+
<Box p={4} bgColor="white" borderRadius={8} shadow="medium">
|
|
665
|
+
{content}
|
|
666
|
+
</Box>
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### Button
|
|
670
|
+
|
|
671
|
+
```tsx
|
|
672
|
+
import Button from '@cronocode/react-box/components/button';
|
|
673
|
+
|
|
674
|
+
<Button
|
|
675
|
+
px={4}
|
|
676
|
+
py={2}
|
|
677
|
+
bgColor="blue-500"
|
|
678
|
+
color="white"
|
|
679
|
+
borderRadius={6}
|
|
680
|
+
fontWeight={500}
|
|
681
|
+
hover={{ bgColor: 'blue-600' }}
|
|
682
|
+
disabled={{ opacity: 0.5, cursor: 'not-allowed' }}
|
|
683
|
+
>
|
|
684
|
+
Click me
|
|
685
|
+
</Button>;
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### Input Field
|
|
689
|
+
|
|
690
|
+
```tsx
|
|
691
|
+
import Textbox from '@cronocode/react-box/components/textbox';
|
|
692
|
+
|
|
693
|
+
<Textbox
|
|
694
|
+
placeholder="Enter text..."
|
|
695
|
+
width="fit"
|
|
696
|
+
px={3}
|
|
697
|
+
py={2}
|
|
698
|
+
b={1}
|
|
699
|
+
borderColor="gray-300"
|
|
700
|
+
borderRadius={6}
|
|
701
|
+
focus={{ borderColor: 'blue-500', outline: 'none' }}
|
|
702
|
+
/>;
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
### Grid Layout
|
|
706
|
+
|
|
707
|
+
```tsx
|
|
708
|
+
import Grid from '@cronocode/react-box/components/grid';
|
|
709
|
+
|
|
710
|
+
<Grid gridCols={3} gap={4}>
|
|
711
|
+
{items.map((item) => (
|
|
712
|
+
<Box key={item.id}>{item.content}</Box>
|
|
713
|
+
))}
|
|
714
|
+
</Grid>;
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
### Responsive Stack
|
|
718
|
+
|
|
719
|
+
```tsx
|
|
720
|
+
import Flex from '@cronocode/react-box/components/flex';
|
|
721
|
+
|
|
722
|
+
<Flex d="column" gap={2} md={{ d: 'row', gap: 4 }}>
|
|
723
|
+
{children}
|
|
724
|
+
</Flex>;
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
### Truncated Text
|
|
728
|
+
|
|
729
|
+
```tsx
|
|
730
|
+
<Box overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap">
|
|
731
|
+
Long text that will be truncated...
|
|
732
|
+
</Box>
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
### Overlay/Modal Backdrop
|
|
736
|
+
|
|
737
|
+
```tsx
|
|
738
|
+
<Box position="fixed" top={0} left={0} right={0} bottom={0} bgColor="black" opacity={0.5} zIndex={50} />
|
|
739
|
+
```
|
|
740
|
+
|
|
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.
|
|
742
|
+
|
|
743
|
+
```tsx
|
|
744
|
+
import Tooltip from '@cronocode/react-box/components/tooltip';
|
|
745
|
+
|
|
746
|
+
<Tooltip content="Tooltip text">
|
|
747
|
+
<Button>Hover me</Button>
|
|
748
|
+
</Tooltip>;
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
---
|
|
752
|
+
|
|
753
|
+
## Group Hover (hoverGroup)
|
|
754
|
+
|
|
755
|
+
Style child elements when parent is hovered:
|
|
756
|
+
|
|
757
|
+
```tsx
|
|
758
|
+
// Parent with a className
|
|
759
|
+
<Flex className="card-row" gap={2}>
|
|
760
|
+
{/* Child responds to parent hover */}
|
|
761
|
+
<Box opacity={0} hoverGroup={{ 'card-row': { opacity: 1 } }}>
|
|
762
|
+
Actions
|
|
763
|
+
</Box>
|
|
764
|
+
</Flex>
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
## Server-Side Rendering (SSG/SSR)
|
|
770
|
+
|
|
771
|
+
```tsx
|
|
772
|
+
import { getStyles, resetStyles } from '@cronocode/react-box/ssg';
|
|
773
|
+
|
|
774
|
+
// After rendering your app, get generated styles
|
|
775
|
+
const cssString = getStyles();
|
|
776
|
+
|
|
777
|
+
// Inject into your HTML
|
|
778
|
+
<style id="crono-box">{cssString}</style>;
|
|
779
|
+
|
|
780
|
+
// Reset for next request (in SSR)
|
|
781
|
+
resetStyles();
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
---
|
|
785
|
+
|
|
786
|
+
## Key Reminders for AI Assistants
|
|
787
|
+
|
|
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
|
|
816
|
+
|
|
817
|
+
---
|
|
818
|
+
|
|
819
|
+
## Debugging Tips
|
|
820
|
+
|
|
821
|
+
1. **Inspect styles**: Look for `<style id="crono-box">` in document head
|
|
822
|
+
2. **Check class names**: Elements get classes like `_b`, `_2a`, etc.
|
|
823
|
+
3. **Verify variables**: CSS variables are in `:root` rules
|
|
824
|
+
4. **Theme issues**: Ensure `<Box.Theme>` wraps your app
|
|
825
|
+
5. **Portal theming**: Tooltips/dropdowns use `#crono-box` container
|