@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 +658 -119
- package/components/dataGrid/contracts/dataGridContract.d.ts +2 -0
- package/components/dataGrid.cjs +1 -1
- package/components/dataGrid.mjs +233 -229
- 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,135 @@ 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 |
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
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}
|
|
176
|
-
sm={{ p: 3 }}
|
|
177
|
-
md={{ p: 4 }}
|
|
178
|
-
lg={{ p: 6 }}
|
|
179
|
-
xl={{ p: 8 }}
|
|
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
|
|
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}
|
|
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">
|
|
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}
|
|
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 =>
|
|
469
|
-
</
|
|
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
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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
|
|