@cronocode/react-box 3.1.7 → 3.1.9

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 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 | Divider | Formula | Example | CSS Output |
35
- |--------------|---------|---------|---------|------------|
36
- | Spacing (`p`, `m`, `gap`, `px`, `py`, `mx`, `my`, etc.) | 4 | value/4 rem | `p={4}` | `padding: 1rem` (16px) |
37
- | Font size (`fontSize`) | **16** | value/16 rem | `fontSize={16}` | `font-size: 1rem` (16px) |
38
- | Width/Height (numeric) | 4 | value/4 rem | `width={20}` | `width: 5rem` (80px) |
39
- | Border width (`b`, `bx`, `by`, `bt`, `br`, `bb`, `bl`) | none | direct px | `b={1}` | `border-width: 1px` |
40
- | Border radius (`borderRadius`) | none | direct px | `borderRadius={8}` | `border-radius: 8px` |
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,135 @@ p={8} // → 2rem = 32px
64
215
  ## Prop Reference
65
216
 
66
217
  ### Spacing
67
- | Prop | CSS Property |
68
- |------|-------------|
69
- | `p` | padding |
70
- | `px` | padding-left + padding-right |
71
- | `py` | padding-top + padding-bottom |
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` | margin |
74
- | `mx`, `my` | margin horizontal/vertical |
75
- | `mt`, `mr`, `mb`, `ml` | margin-top/right/bottom/left |
76
- | `gap` | gap (flexbox/grid) |
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
- | Prop | CSS Property | Values |
80
- |------|-------------|--------|
81
- | `display` | display | `'flex'`, `'block'`, `'inline'`, `'grid'`, `'none'`, `'inline-flex'`, etc. |
82
- | `d` | flex-direction | `'row'`, `'column'`, `'row-reverse'`, `'column-reverse'` |
83
- | `wrap` | flex-wrap | `'wrap'`, `'nowrap'`, `'wrap-reverse'` |
84
- | `items` | align-items | `'center'`, `'start'`, `'end'`, `'stretch'`, `'baseline'` |
85
- | `justify` | justify-content | `'center'`, `'start'`, `'end'`, `'between'`, `'around'`, `'evenly'` |
86
- | `flex` | flex | number or string |
87
- | `grow` | flex-grow | number |
88
- | `shrink` | flex-shrink | number |
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
- | Prop | CSS Property | Accepts |
92
- |------|-------------|---------|
93
- | `width` | width | number (rem/4), string (`'auto'`, `'1/2'`, `'fit'`, `'fit-screen'`) |
94
- | `height` | height | number (rem/4), string (`'auto'`, `'fit'`, `'fit-screen'`) |
95
- | `minWidth`, `maxWidth` | min/max-width | number or string |
96
- | `minHeight`, `maxHeight` | min/max-height | number or string |
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
+ **Percentage/Fraction Values:**
253
+
254
+ All sizing, spacing, and positioning props accept percentage strings:
255
+
256
+ ```tsx
257
+ // Sizing
258
+ width="33%" // → 33%
259
+ height="50%" // → 50%
260
+ minWidth="20%" // → min-width: 20%
261
+ maxWidth="80%" // → max-width: 80%
262
+ minHeight="10%" // → min-height: 10%
263
+ maxHeight="90%" // → max-height: 90%
264
+
265
+ // Spacing (margin, padding, gap)
266
+ p="5%" // → padding: 5%
267
+ px="10%" // → padding-left/right: 10%
268
+ m="10%" // → margin: 10%
269
+ mt="5%" // → margin-top: 5%
270
+ gap="2%" // → gap: 2%
271
+
272
+ // Positioning
273
+ top="10%" // → top: 10%
274
+ left="50%" // → left: 50%
275
+ right="0%" // → right: 0%
276
+ bottom="20%" // → bottom: 20%
277
+
278
+ // Fraction shortcuts (width/height only)
279
+ width="1/2" // → 50%
280
+ width="1/3" // → 33.333%
281
+ width="2/3" // → 66.666%
282
+ width="1/4" // → 25%
283
+ width="3/4" // → 75%
284
+
285
+ // Special values
286
+ width="fit" // → 100%
287
+ width="fit-screen" // → 100vw
288
+ height="fit" // → 100%
289
+ height="fit-screen"// → 100vh
290
+ ```
97
291
 
98
292
  ### Colors (Tailwind-like palette)
99
- | Prop | CSS Property |
100
- |------|-------------|
101
- | `bgColor` | background-color |
102
- | `color` | color |
103
- | `borderColor` | border-color |
293
+
294
+ | Prop | CSS Property |
295
+ | ------------- | ---------------- |
296
+ | `bgColor` | background-color |
297
+ | `color` | color |
298
+ | `borderColor` | border-color |
104
299
 
105
300
  **Color values**: `'gray-50'` through `'gray-900'`, same for `red`, `orange`, `yellow`, `green`, `teal`, `blue`, `indigo`, `purple`, `pink`, `violet`.
106
301
 
107
302
  Also: `'white'`, `'black'`, `'transparent'`, `'inherit'`, `'currentColor'`
108
303
 
109
304
  ### Borders
110
- | Prop | CSS Property |
111
- |------|-------------|
112
- | `b` | border-width (all sides) |
113
- | `bx` | border-left-width + border-right-width |
114
- | `by` | border-top-width + border-bottom-width |
115
- | `bt`, `br`, `bb`, `bl` | individual sides |
116
- | `borderRadius` | border-radius |
117
- | `borderStyle` | border-style (`'solid'`, `'dashed'`, `'dotted'`, `'none'`) |
305
+
306
+ | Prop | CSS Property |
307
+ | ---------------------- | ---------------------------------------------------------- |
308
+ | `b` | border-width (all sides) |
309
+ | `bx` | border-left-width + border-right-width |
310
+ | `by` | border-top-width + border-bottom-width |
311
+ | `bt`, `br`, `bb`, `bl` | individual sides |
312
+ | `borderRadius` | border-radius |
313
+ | `borderStyle` | border-style (`'solid'`, `'dashed'`, `'dotted'`, `'none'`) |
118
314
 
119
315
  ### Typography
120
- | Prop | CSS Property |
121
- |------|-------------|
122
- | `fontSize` | font-size (divider: 16) |
123
- | `fontWeight` | font-weight (`400`, `500`, `600`, `700`, etc.) |
124
- | `lineHeight` | line-height |
125
- | `textAlign` | text-align |
126
- | `textDecoration` | text-decoration |
127
- | `textTransform` | text-transform |
128
- | `whiteSpace` | white-space |
129
- | `overflow` | overflow |
130
- | `textOverflow` | text-overflow |
316
+
317
+ | Prop | CSS Property |
318
+ | ---------------- | ------------------------------------------------------------ |
319
+ | `fontSize` | font-size (divider: 16) |
320
+ | `fontWeight` | font-weight (`400`, `500`, `600`, `700`, etc.) |
321
+ | `lineHeight` | line-height (number = pixels, e.g. `lineHeight={24}` → 24px) |
322
+ | `textAlign` | text-align |
323
+ | `textDecoration` | text-decoration |
324
+ | `textTransform` | text-transform |
325
+ | `whiteSpace` | white-space |
326
+ | `overflow` | overflow |
327
+ | `textOverflow` | text-overflow |
131
328
 
132
329
  ### Positioning
133
- | Prop | CSS Property |
134
- |------|-------------|
135
- | `position` | position (`'relative'`, `'absolute'`, `'fixed'`, `'sticky'`) |
136
- | `top`, `right`, `bottom`, `left` | positioning offsets |
137
- | `zIndex` | z-index |
330
+
331
+ | Prop | CSS Property |
332
+ | -------------------------------- | ------------------------------------------------------------ |
333
+ | `position` | position (`'relative'`, `'absolute'`, `'fixed'`, `'sticky'`) |
334
+ | `top`, `right`, `bottom`, `left` | positioning offsets |
335
+ | `zIndex` | z-index |
138
336
 
139
337
  ### Effects
140
- | Prop | CSS Property |
141
- |------|-------------|
142
- | `shadow` | box-shadow (`'small'`, `'medium'`, `'large'`, `'xl'`, `'none'`) |
143
- | `opacity` | opacity |
144
- | `cursor` | cursor |
145
- | `pointerEvents` | pointer-events |
146
- | `transition` | transition |
147
- | `transform` | transform |
338
+
339
+ | Prop | CSS Property |
340
+ | --------------- | --------------------------------------------------------------- |
341
+ | `shadow` | box-shadow (`'small'`, `'medium'`, `'large'`, `'xl'`, `'none'`) |
342
+ | `opacity` | opacity |
343
+ | `cursor` | cursor |
344
+ | `pointerEvents` | pointer-events |
345
+ | `transition` | transition |
346
+ | `transform` | transform |
148
347
 
149
348
  ---
150
349
 
@@ -172,23 +371,24 @@ Mobile-first breakpoints using min-width media queries:
172
371
 
173
372
  ```tsx
174
373
  <Box
175
- p={2} // Base (mobile)
176
- sm={{ p: 3 }} // ≥640px
177
- md={{ p: 4 }} // ≥768px
178
- lg={{ p: 6 }} // ≥1024px
179
- xl={{ p: 8 }} // ≥1280px
374
+ p={2} // Base (mobile)
375
+ sm={{ p: 3 }} // ≥640px
376
+ md={{ p: 4 }} // ≥768px
377
+ lg={{ p: 6 }} // ≥1024px
378
+ xl={{ p: 8 }} // ≥1280px
180
379
  xxl={{ p: 10 }} // ≥1536px
181
380
  />
182
381
  ```
183
382
 
184
383
  **Combine with pseudo-classes**:
384
+
185
385
  ```tsx
186
386
  <Box
187
387
  bgColor="white"
188
388
  hover={{ bgColor: 'gray-100' }}
189
389
  md={{
190
390
  bgColor: 'gray-50',
191
- hover: { bgColor: 'gray-200' }
391
+ hover: { bgColor: 'gray-200' },
192
392
  }}
193
393
  />
194
394
  ```
@@ -199,20 +399,70 @@ Mobile-first breakpoints using min-width media queries:
199
399
 
200
400
  ### Setting Up Themes
201
401
 
402
+ The `Box.Theme` component provides theme management with automatic detection based on system preferences.
403
+
404
+ **Auto-detect theme** (recommended):
405
+
202
406
  ```tsx
203
407
  import Box from '@cronocode/react-box';
204
408
 
205
409
  function App() {
206
410
  return (
207
- <Box.Theme value="dark">
411
+ <Box.Theme>
412
+ {/* Theme auto-detects from prefers-color-scheme: 'light' or 'dark' */}
208
413
  <YourApp />
209
414
  </Box.Theme>
210
415
  );
211
416
  }
212
417
  ```
213
418
 
419
+ **Explicit theme**:
420
+
421
+ ```tsx
422
+ <Box.Theme theme="dark">
423
+ <YourApp />
424
+ </Box.Theme>
425
+ ```
426
+
427
+ **Global vs Local theme**:
428
+
429
+ ```tsx
430
+ // Global: Adds theme class to document.documentElement (affects entire page)
431
+ <Box.Theme theme="dark" use="global">
432
+ <YourApp />
433
+ </Box.Theme>
434
+
435
+ // Local (default): Wraps children in a Box with theme class (scoped)
436
+ <Box.Theme theme="dark" use="local">
437
+ <Section>Content</Section>
438
+ </Box.Theme>
439
+ ```
440
+
441
+ ### Using the Theme Hook
442
+
443
+ ```tsx
444
+ import Box from '@cronocode/react-box';
445
+
446
+ function ThemeSwitcher() {
447
+ const [theme, setTheme] = Box.useTheme();
448
+
449
+ return <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Current: {theme}</button>;
450
+ }
451
+
452
+ // Must be used within Box.Theme provider
453
+ function App() {
454
+ return (
455
+ <Box.Theme>
456
+ <ThemeSwitcher />
457
+ </Box.Theme>
458
+ );
459
+ }
460
+ ```
461
+
214
462
  ### Theme-Aware Styles
215
463
 
464
+ Apply styles based on the active theme:
465
+
216
466
  ```tsx
217
467
  <Box
218
468
  bgColor="white"
@@ -228,6 +478,8 @@ function App() {
228
478
 
229
479
  ### Theme + Pseudo-Classes
230
480
 
481
+ Combine theme styles with pseudo-classes:
482
+
231
483
  ```tsx
232
484
  <Box
233
485
  bgColor="white"
@@ -241,6 +493,29 @@ function App() {
241
493
  />
242
494
  ```
243
495
 
496
+ ### Theme + Responsive Breakpoints
497
+
498
+ Combine all three systems:
499
+
500
+ ```tsx
501
+ <Box
502
+ p={4}
503
+ bgColor="white"
504
+ md={{
505
+ p: 6,
506
+ bgColor: 'gray-50',
507
+ }}
508
+ theme={{
509
+ dark: {
510
+ bgColor: 'gray-900',
511
+ md: {
512
+ bgColor: 'gray-800',
513
+ },
514
+ },
515
+ }}
516
+ />
517
+ ```
518
+
244
519
  ---
245
520
 
246
521
  ## Component System
@@ -261,6 +536,7 @@ Import ready-to-use components:
261
536
  import Button from '@cronocode/react-box/components/button';
262
537
  import Textbox from '@cronocode/react-box/components/textbox';
263
538
  import Checkbox from '@cronocode/react-box/components/checkbox';
539
+ import RadioButton from '@cronocode/react-box/components/radioButton';
264
540
  import Dropdown from '@cronocode/react-box/components/dropdown';
265
541
  import Tooltip from '@cronocode/react-box/components/tooltip';
266
542
 
@@ -270,7 +546,7 @@ import Grid from '@cronocode/react-box/components/grid'; // Box with display="g
270
546
 
271
547
  <Button variant="primary">Submit</Button>
272
548
  <Textbox placeholder="Enter text..." />
273
- <Flex gap={4} items="center">...</Flex>
549
+ <Flex gap={4} ai="center">...</Flex>
274
550
  <Flex inline gap={2}>Inline flex</Flex>
275
551
  ```
276
552
 
@@ -324,7 +600,7 @@ Box.components({
324
600
  <Box component="card" variant="bordered">
325
601
  <Box component="card.header">Title</Box>
326
602
  <Box component="card.body">Content</Box>
327
- </Box>
603
+ </Box>;
328
604
  ```
329
605
 
330
606
  ---
@@ -362,11 +638,13 @@ export const { extendedProps, extendedPropTypes } = Box.extend(
362
638
  valueFormat: (value, getVariable) => getVariable(value),
363
639
  },
364
640
  ],
365
- }
641
+ },
366
642
  );
367
643
 
368
644
  // Now use your custom colors
369
- <Box bgColor="brand-primary" color="white">Branded</Box>
645
+ <Box bgColor="brand-primary" color="white">
646
+ Branded
647
+ </Box>;
370
648
  ```
371
649
 
372
650
  ### TypeScript Type Augmentation
@@ -411,15 +689,17 @@ declare module '@cronocode/react-box/types' {
411
689
  ## Common Patterns
412
690
 
413
691
  ### Flex Container
692
+
414
693
  ```tsx
415
694
  import Flex from '@cronocode/react-box/components/flex';
416
695
 
417
- <Flex d="column" gap={4} items="center" justify="between">
696
+ <Flex d="column" gap={4} ai="center" jc="between">
418
697
  {children}
419
- </Flex>
698
+ </Flex>;
420
699
  ```
421
700
 
422
701
  ### Card
702
+
423
703
  ```tsx
424
704
  <Box p={4} bgColor="white" borderRadius={8} shadow="medium">
425
705
  {content}
@@ -427,6 +707,7 @@ import Flex from '@cronocode/react-box/components/flex';
427
707
  ```
428
708
 
429
709
  ### Button
710
+
430
711
  ```tsx
431
712
  import Button from '@cronocode/react-box/components/button';
432
713
 
@@ -441,10 +722,11 @@ import Button from '@cronocode/react-box/components/button';
441
722
  disabled={{ opacity: 0.5, cursor: 'not-allowed' }}
442
723
  >
443
724
  Click me
444
- </Button>
725
+ </Button>;
445
726
  ```
446
727
 
447
728
  ### Input Field
729
+
448
730
  ```tsx
449
731
  import Textbox from '@cronocode/react-box/components/textbox';
450
732
 
@@ -457,50 +739,43 @@ import Textbox from '@cronocode/react-box/components/textbox';
457
739
  borderColor="gray-300"
458
740
  borderRadius={6}
459
741
  focus={{ borderColor: 'blue-500', outline: 'none' }}
460
- />
742
+ />;
461
743
  ```
462
744
 
463
745
  ### Grid Layout
746
+
464
747
  ```tsx
465
748
  import Grid from '@cronocode/react-box/components/grid';
466
749
 
467
750
  <Grid gridCols={3} gap={4}>
468
- {items.map(item => <Box key={item.id}>{item.content}</Box>)}
469
- </Grid>
751
+ {items.map((item) => (
752
+ <Box key={item.id}>{item.content}</Box>
753
+ ))}
754
+ </Grid>;
470
755
  ```
471
756
 
472
757
  ### Responsive Stack
758
+
473
759
  ```tsx
474
760
  import Flex from '@cronocode/react-box/components/flex';
475
761
 
476
762
  <Flex d="column" gap={2} md={{ d: 'row', gap: 4 }}>
477
763
  {children}
478
- </Flex>
764
+ </Flex>;
479
765
  ```
480
766
 
481
767
  ### Truncated Text
768
+
482
769
  ```tsx
483
- <Box
484
- overflow="hidden"
485
- textOverflow="ellipsis"
486
- whiteSpace="nowrap"
487
- >
770
+ <Box overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap">
488
771
  Long text that will be truncated...
489
772
  </Box>
490
773
  ```
491
774
 
492
775
  ### Overlay/Modal Backdrop
776
+
493
777
  ```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
- />
778
+ <Box position="fixed" top={0} left={0} right={0} bottom={0} bgColor="black" opacity={0.5} zIndex={50} />
504
779
  ```
505
780
 
506
781
  **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 +785,7 @@ import Tooltip from '@cronocode/react-box/components/tooltip';
510
785
 
511
786
  <Tooltip content="Tooltip text">
512
787
  <Button>Hover me</Button>
513
- </Tooltip>
788
+ </Tooltip>;
514
789
  ```
515
790
 
516
791
  ---
@@ -523,10 +798,7 @@ Style child elements when parent is hovered:
523
798
  // Parent with a className
524
799
  <Flex className="card-row" gap={2}>
525
800
  {/* Child responds to parent hover */}
526
- <Box
527
- opacity={0}
528
- hoverGroup={{ 'card-row': { opacity: 1 } }}
529
- >
801
+ <Box opacity={0} hoverGroup={{ 'card-row': { opacity: 1 } }}>
530
802
  Actions
531
803
  </Box>
532
804
  </Flex>
@@ -543,7 +815,7 @@ import { getStyles, resetStyles } from '@cronocode/react-box/ssg';
543
815
  const cssString = getStyles();
544
816
 
545
817
  // Inject into your HTML
546
- <style id="crono-box">{cssString}</style>
818
+ <style id="crono-box">{cssString}</style>;
547
819
 
548
820
  // Reset for next request (in SSR)
549
821
  resetStyles();
@@ -553,17 +825,284 @@ resetStyles();
553
825
 
554
826
  ## Key Reminders for AI Assistants
555
827
 
556
- 1. **fontSize uses divider 16**, not 4. `fontSize={14}` → 14px, NOT 3.5px
557
- 2. **Spacing uses divider 4**. `p={4}` → 16px (1rem)
558
- 3. **Border width is direct px**. `b={1}` 1px
559
- 4. **Colors are Tailwind-like**: `'gray-500'`, `'blue-600'`, etc.
560
- 5. **Breakpoints are mobile-first**: base sm md → lg → xl → xxl
561
- 6. **Theme styles nest**: `theme={{ dark: { hover: { ... } } }}`
562
- 7. **Use `tag` prop** to change the HTML element: `<Box tag="button">`
563
- 8. **HTML attributes go in `props`**: `<Box tag="a" props={{ href: '/link' }}>` - NOT directly as Box props
564
- 9. **Percentage widths**: Use strings like `width="1/2"` for 50%
565
- 10. **Full size shortcuts**: `width="fit"` = 100%, `width="fit-screen"` = 100vw
566
- 11. **Box is memoized** with `React.memo` - props comparison is efficient
828
+ ### ⚠️ MOST IMPORTANT (Common AI Mistakes)
829
+
830
+ 1. **NEVER use `style={{ }}` attribute** - Always use Box props instead. If a prop doesn't exist, extend Box with `Box.extend()`
831
+ 2. **NEVER use `<Box tag="...">` for common elements** - Use semantic components instead:
832
+ - `<Box tag="a">``<Link>`
833
+ - `<Box tag="img">` `<Img>`
834
+ - `<Box tag="button">` → `<Button>`
835
+ - `<Box tag="h1/h2/h3">` `<H1>/<H2>/<H3>`
836
+ - `<Box tag="p">` `<P>`
837
+ - `<Box tag="nav/header/footer>` `<Nav>/<Header>/<Footer>`
838
+ 3. **NEVER use `<Box display="flex/grid">`** - Use `<Flex>` or `<Grid>` components instead
839
+
840
+ ### Value Formatting
841
+
842
+ 4. **fontSize uses divider 16**, not 4. `fontSize={14}` → 14px, NOT 3.5px
843
+ 5. **Spacing uses divider 4**. `p={4}` → 16px (1rem)
844
+ 6. **Border width is direct px**. `b={1}` → 1px
845
+ 7. **lineHeight is direct px**. `lineHeight={24}` → 24px
846
+
847
+ ### Syntax & Patterns
848
+
849
+ 8. **Colors are Tailwind-like**: `'gray-500'`, `'blue-600'`, etc.
850
+ 9. **Breakpoints are mobile-first**: base → sm → md → lg → xl → xxl
851
+ 10. **Theme styles nest**: `theme={{ dark: { hover: { ... } } }}`
852
+ 11. **HTML attributes go in `props`**: `<Link props={{ href: '/link' }}>` - NOT directly as Box props
853
+ 12. **Percentage widths**: Use strings like `width="1/2"` for 50%
854
+ 13. **Full size shortcuts**: `width="fit"` = 100%, `width="fit-screen"` = 100vw
855
+ 14. **Box is memoized** with `React.memo` - props comparison is efficient
856
+
857
+ ---
858
+
859
+ ## DataGrid Component
860
+
861
+ A powerful data grid with sorting, filtering, grouping, row selection, column pinning, and virtualization.
862
+
863
+ ### Import and Basic Usage
864
+
865
+ ```tsx
866
+ import DataGrid from '@cronocode/react-box/components/dataGrid';
867
+
868
+ const data = [
869
+ { id: 1, name: 'John', email: 'john@example.com', age: 30 },
870
+ { id: 2, name: 'Jane', email: 'jane@example.com', age: 25 },
871
+ ];
872
+
873
+ <DataGrid
874
+ data={data}
875
+ def={{
876
+ columns: [
877
+ { key: 'name', header: 'Name' },
878
+ { key: 'email', header: 'Email' },
879
+ { key: 'age', header: 'Age', align: 'right' },
880
+ ],
881
+ }}
882
+ />;
883
+ ```
884
+
885
+ ### GridDefinition Props
886
+
887
+ | Prop | Type | Description |
888
+ |------|------|-------------|
889
+ | `columns` | `ColumnType[]` | Column definitions (required) |
890
+ | `rowKey` | `keyof TRow \| (row) => Key` | Unique key for each row |
891
+ | `rowHeight` | `number` | Row height in pixels (default: 36) |
892
+ | `visibleRowsCount` | `number` | Number of visible rows (default: 10) |
893
+ | `showRowNumber` | `boolean \| { pinned?: boolean; width?: number }` | Show row numbers |
894
+ | `rowSelection` | `boolean \| { pinned?: boolean }` | Enable row selection checkboxes |
895
+ | `topBar` | `boolean` | Show top bar with title and controls |
896
+ | `bottomBar` | `boolean` | Show bottom bar with row count |
897
+ | `title` | `ReactNode` | Title displayed in top bar |
898
+ | `topBarContent` | `ReactNode` | Custom content in top bar |
899
+ | `globalFilter` | `boolean` | Enable global search filter |
900
+ | `globalFilterKeys` | `Key[]` | Columns to search (default: all) |
901
+ | `sortable` | `boolean` | Enable sorting globally (default: true) |
902
+ | `resizable` | `boolean` | Enable column resizing globally (default: true) |
903
+ | `noDataComponent` | `ReactNode` | Custom empty state component |
904
+
905
+ ### ColumnType Props
906
+
907
+ | Prop | Type | Description |
908
+ |------|------|-------------|
909
+ | `key` | `string \| number` | Column key matching data property (required) |
910
+ | `header` | `string` | Column header text |
911
+ | `width` | `number` | Column width in pixels |
912
+ | `align` | `'left' \| 'right' \| 'center'` | Text alignment |
913
+ | `pin` | `'LEFT' \| 'RIGHT'` | Pin column to side |
914
+ | `columns` | `ColumnType[]` | Nested columns for grouping |
915
+ | `sortable` | `boolean` | Override global sortable setting |
916
+ | `resizable` | `boolean` | Override global resizable setting |
917
+ | `flexible` | `boolean` | Participate in flex distribution (default: true) |
918
+ | `filterable` | `boolean \| FilterConfig` | Enable column filtering |
919
+ | `Cell` | `React.ComponentType<{ cell }>` | Custom cell renderer |
920
+
921
+ ### DataGridProps
922
+
923
+ | Prop | Type | Description |
924
+ |------|------|-------------|
925
+ | `data` | `TRow[]` | Data array (required) |
926
+ | `def` | `GridDefinition` | Grid definition (required) |
927
+ | `loading` | `boolean` | Show loading state |
928
+ | `onSelectionChange` | `(event) => void` | Selection change callback |
929
+ | `globalFilterValue` | `string` | Controlled global filter |
930
+ | `onGlobalFilterChange` | `(value) => void` | Global filter change callback |
931
+ | `columnFilters` | `ColumnFilters` | Controlled column filters |
932
+ | `onColumnFiltersChange` | `(filters) => void` | Column filters change callback |
933
+
934
+ ### Filter Types
935
+
936
+ ```tsx
937
+ // Text filter (default) - fuzzy search
938
+ { key: 'name', filterable: true }
939
+ { key: 'name', filterable: { type: 'text', placeholder: 'Search...' } }
940
+
941
+ // Number filter - with comparison operators
942
+ { key: 'age', filterable: { type: 'number', min: 0, max: 100 } }
943
+
944
+ // Multiselect filter - dropdown with checkboxes
945
+ { key: 'status', filterable: { type: 'multiselect' } }
946
+ { key: 'status', filterable: {
947
+ type: 'multiselect',
948
+ options: [
949
+ { label: 'Active', value: 'active' },
950
+ { label: 'Inactive', value: 'inactive' },
951
+ ]
952
+ }}
953
+ ```
954
+
955
+ ### Column Grouping (Nested Headers)
956
+
957
+ ```tsx
958
+ columns: [
959
+ {
960
+ key: 'personal',
961
+ header: 'Personal Info',
962
+ columns: [
963
+ { key: 'firstName', header: 'First Name' },
964
+ { key: 'lastName', header: 'Last Name' },
965
+ ],
966
+ },
967
+ {
968
+ key: 'contact',
969
+ header: 'Contact',
970
+ columns: [
971
+ { key: 'email', header: 'Email' },
972
+ { key: 'phone', header: 'Phone' },
973
+ ],
974
+ },
975
+ ]
976
+ ```
977
+
978
+ ### Custom Cell Renderer
979
+
980
+ ```tsx
981
+ columns: [
982
+ {
983
+ key: 'status',
984
+ header: 'Status',
985
+ Cell: ({ cell }) => (
986
+ <Box
987
+ px={2}
988
+ py={1}
989
+ borderRadius={4}
990
+ bgColor={cell.value === 'active' ? 'green-100' : 'red-100'}
991
+ color={cell.value === 'active' ? 'green-800' : 'red-800'}
992
+ >
993
+ {cell.value}
994
+ </Box>
995
+ ),
996
+ },
997
+ {
998
+ key: 'actions',
999
+ header: 'Actions',
1000
+ Cell: ({ cell }) => (
1001
+ <Button onClick={() => handleEdit(cell.row)}>Edit</Button>
1002
+ ),
1003
+ },
1004
+ ]
1005
+ ```
1006
+
1007
+ The `cell` object provides:
1008
+ - `cell.value` - Cell value
1009
+ - `cell.row` - Full row data
1010
+ - `cell.column` - Column model
1011
+
1012
+ ### Row Selection
1013
+
1014
+ ```tsx
1015
+ <DataGrid
1016
+ data={data}
1017
+ def={{
1018
+ rowSelection: true, // or { pinned: true } to pin checkbox column
1019
+ columns: [...],
1020
+ }}
1021
+ onSelectionChange={(event) => {
1022
+ console.log('Selected keys:', event.selectedRowKeys);
1023
+ console.log('Action:', event.action); // 'select' | 'deselect'
1024
+ console.log('All selected:', event.isAllSelected);
1025
+ }}
1026
+ />
1027
+ ```
1028
+
1029
+ ### Sorting and Resizing Control
1030
+
1031
+ ```tsx
1032
+ // Disable globally
1033
+ def={{
1034
+ sortable: false,
1035
+ resizable: false,
1036
+ columns: [...]
1037
+ }}
1038
+
1039
+ // Override per column
1040
+ def={{
1041
+ sortable: false, // Global: no sorting
1042
+ columns: [
1043
+ { key: 'id', header: 'ID' }, // Not sortable (inherits global)
1044
+ { key: 'name', header: 'Name', sortable: true }, // Sortable (override)
1045
+ ]
1046
+ }}
1047
+ ```
1048
+
1049
+ ### Flexible Column Sizing
1050
+
1051
+ Columns automatically fill available space proportionally. Use `flexible: false` for fixed-width columns.
1052
+
1053
+ ```tsx
1054
+ columns: [
1055
+ { key: 'id', header: 'ID', width: 60, flexible: false }, // Fixed at 60px
1056
+ { key: 'name', header: 'Name', width: 200 }, // Flexes (200 base)
1057
+ { key: 'email', header: 'Email', width: 300 }, // Flexes more (300 base)
1058
+ ]
1059
+ ```
1060
+
1061
+ ### Custom Empty State
1062
+
1063
+ ```tsx
1064
+ def={{
1065
+ columns: [...],
1066
+ noDataComponent: (
1067
+ <Flex d="column" ai="center" gap={4} p={8}>
1068
+ <Box fontSize={48}>📭</Box>
1069
+ <Box color="gray-500">No records found</Box>
1070
+ </Flex>
1071
+ ),
1072
+ }}
1073
+ ```
1074
+
1075
+ ### Full-Featured Example
1076
+
1077
+ ```tsx
1078
+ <DataGrid
1079
+ data={users}
1080
+ def={{
1081
+ title: 'Users Table',
1082
+ topBar: true,
1083
+ bottomBar: true,
1084
+ globalFilter: true,
1085
+ rowSelection: { pinned: true },
1086
+ showRowNumber: { pinned: true },
1087
+ rowHeight: 40,
1088
+ visibleRowsCount: 10,
1089
+ columns: [
1090
+ {
1091
+ key: 'personal',
1092
+ header: 'Personal',
1093
+ columns: [
1094
+ { key: 'name', header: 'Name', filterable: true },
1095
+ { key: 'age', header: 'Age', width: 80, align: 'right', filterable: { type: 'number' } },
1096
+ ],
1097
+ },
1098
+ { key: 'email', header: 'Email', width: 250, filterable: true },
1099
+ { key: 'status', header: 'Status', filterable: { type: 'multiselect' } },
1100
+ { key: 'country', header: 'Country', pin: 'RIGHT' },
1101
+ ],
1102
+ }}
1103
+ onSelectionChange={(e) => setSelected(e.selectedRowKeys)}
1104
+ />
1105
+ ```
567
1106
 
568
1107
  ---
569
1108