yk-grid 0.1.1 → 0.1.3

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.
Files changed (2) hide show
  1. package/README.md +118 -116
  2. package/package.json +6 -2
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # yk-grid
2
2
 
3
+ ![yk-grid](.github/assets/yk-grid-banner.png)
4
+
3
5
  A production-ready React DataGrid component with built-in sorting, filtering, grouping, pagination, selection, column management, CSV export, virtual scrolling, inline cell editing, and optional AI-assisted natural-language query input.
4
6
 
5
7
  Dual-format library (ESM + CJS) with full TypeScript generics. Zero runtime dependencies beyond React, Zod, and @tanstack/react-virtual.
@@ -40,7 +42,7 @@ npm install react react-dom zod
40
42
  Import the library stylesheet once in your app entry point:
41
43
 
42
44
  ```tsx
43
- import 'yk-grid/dist/yk-grid.css'
45
+ import 'yk-grid/dist/yk-grid.css';
44
46
  ```
45
47
 
46
48
  ---
@@ -48,24 +50,24 @@ import 'yk-grid/dist/yk-grid.css'
48
50
  ## Quick start
49
51
 
50
52
  ```tsx
51
- import 'yk-grid/dist/yk-grid.css'
52
- import { DataGrid } from 'yk-grid'
53
- import type { ColumnDef } from 'yk-grid'
53
+ import 'yk-grid/dist/yk-grid.css';
54
+ import { DataGrid } from 'yk-grid';
55
+ import type { ColumnDef } from 'yk-grid';
54
56
 
55
57
  interface User {
56
- id: string
57
- name: string
58
- email: string
59
- age: number
60
- status: 'active' | 'inactive'
58
+ id: string;
59
+ name: string;
60
+ email: string;
61
+ age: number;
62
+ status: 'active' | 'inactive';
61
63
  }
62
64
 
63
65
  const columns: ColumnDef<User>[] = [
64
- { id: 'name', header: 'Name', accessor: r => r.name, sortable: true, filterable: true },
65
- { id: 'email', header: 'Email', accessor: r => r.email, sortable: true, filterable: true },
66
- { id: 'age', header: 'Age', accessor: r => r.age, sortable: true, filterType: 'number', editable: true },
66
+ { id: 'name', header: 'Name', accessor: r => r.name, sortable: true, filterable: true },
67
+ { id: 'email', header: 'Email', accessor: r => r.email, sortable: true, filterable: true },
68
+ { id: 'age', header: 'Age', accessor: r => r.age, sortable: true, filterType: 'number', editable: true },
67
69
  { id: 'status', header: 'Status', accessor: r => r.status, sortable: true, filterType: 'select' },
68
- ]
70
+ ];
69
71
 
70
72
  export default function App() {
71
73
  return (
@@ -81,7 +83,7 @@ export default function App() {
81
83
  enableColumnVisibility
82
84
  onCellEdit={(value, row, col) => console.log(col.id, row.id, '→', value)}
83
85
  />
84
- )
86
+ );
85
87
  }
86
88
  ```
87
89
 
@@ -91,25 +93,25 @@ export default function App() {
91
93
 
92
94
  Every column is defined with a `ColumnDef<T>` object.
93
95
 
94
- | Property | Type | Description |
95
- |----------|------|-------------|
96
- | `id` | `string` | Unique column identifier |
97
- | `header` | `string` | Column header label |
98
- | `accessor` | `(row: T) => string \| number \| Date \| null` | Extracts the raw cell value from the row |
99
- | `cell` | `(value, row: T) => ReactNode` | Optional custom cell renderer |
100
- | `exportValue` | `(row: T) => string \| number` | Override the value used in CSV export |
101
- | `sortable` | `boolean` | Enable sort on this column |
102
- | `filterable` | `boolean` | Show the funnel filter button for this column |
103
- | `filterType` | `'text' \| 'number' \| 'select' \| 'date'` | Filter panel variant. Defaults to `'text'` |
104
- | `filterOptions` | `string[]` | Static options for `filterType: 'select'` |
105
- | `groupable` | `boolean` | Allow this column to be used as a grouping key |
106
- | `aggregation` | `'sum' \| 'avg' \| 'count' \| 'min' \| 'max'` | Aggregation shown in group header rows |
107
- | `editable` | `boolean` | Double-click to edit the cell inline |
108
- | `width` | `number` | Default column width in pixels |
109
- | `minWidth` | `number` | Minimum width when resizing (default: 50) |
110
- | `resizable` | `boolean` | Override per-column resize (default: inherits `enableColumnResize`) |
111
- | `hideable` | `boolean` | Whether this column can be hidden in the visibility picker |
112
- | `defaultHidden` | `boolean` | Start the column hidden |
96
+ | Property | Type | Description |
97
+ | --------------- | ---------------------------------------------- | ------------------------------------------------------------------- |
98
+ | `id` | `string` | Unique column identifier |
99
+ | `header` | `string` | Column header label |
100
+ | `accessor` | `(row: T) => string \| number \| Date \| null` | Extracts the raw cell value from the row |
101
+ | `cell` | `(value, row: T) => ReactNode` | Optional custom cell renderer |
102
+ | `exportValue` | `(row: T) => string \| number` | Override the value used in CSV export |
103
+ | `sortable` | `boolean` | Enable sort on this column |
104
+ | `filterable` | `boolean` | Show the funnel filter button for this column |
105
+ | `filterType` | `'text' \| 'number' \| 'select' \| 'date'` | Filter panel variant. Defaults to `'text'` |
106
+ | `filterOptions` | `string[]` | Static options for `filterType: 'select'` |
107
+ | `groupable` | `boolean` | Allow this column to be used as a grouping key |
108
+ | `aggregation` | `'sum' \| 'avg' \| 'count' \| 'min' \| 'max'` | Aggregation shown in group header rows |
109
+ | `editable` | `boolean` | Double-click to edit the cell inline |
110
+ | `width` | `number` | Default column width in pixels |
111
+ | `minWidth` | `number` | Minimum width when resizing (default: 50) |
112
+ | `resizable` | `boolean` | Override per-column resize (default: inherits `enableColumnResize`) |
113
+ | `hideable` | `boolean` | Whether this column can be hidden in the visibility picker |
114
+ | `defaultHidden` | `boolean` | Start the column hidden |
113
115
 
114
116
  ---
115
117
 
@@ -117,91 +119,91 @@ Every column is defined with a `ColumnDef<T>` object.
117
119
 
118
120
  ### Required
119
121
 
120
- | Prop | Type | Description |
121
- |------|------|-------------|
122
- | `data` | `T[]` | Row data |
123
- | `columns` | `ColumnDef<T>[]` | Column definitions |
122
+ | Prop | Type | Description |
123
+ | ---------- | -------------------- | ------------------------------ |
124
+ | `data` | `T[]` | Row data |
125
+ | `columns` | `ColumnDef<T>[]` | Column definitions |
124
126
  | `getRowId` | `(row: T) => string` | Unique row identifier function |
125
127
 
126
128
  ### Data & loading
127
129
 
128
- | Prop | Type | Default | Description |
129
- |------|------|---------|-------------|
130
- | `dataMode` | `'client' \| 'server'` | `'server'` | `client` handles sort/filter/page locally; `server` fires `onStateChange` for you to fetch |
131
- | `pageSize` | `number` | `20` | Initial rows per page |
132
- | `rowCount` | `number` | — | Total row count for server-side pagination |
133
- | `loading` | `boolean` | `false` | Shows a loading overlay |
134
- | `onStateChange` | `(state: GridState) => void` | — | Fires when sorts, filters, grouping, or pagination change |
135
- | `initialState` | `Partial<GridState>` | — | Seed initial sorts, filters, grouping, pagination, etc. |
130
+ | Prop | Type | Default | Description |
131
+ | --------------- | ---------------------------- | ---------- | ------------------------------------------------------------------------------------------ |
132
+ | `dataMode` | `'client' \| 'server'` | `'server'` | `client` handles sort/filter/page locally; `server` fires `onStateChange` for you to fetch |
133
+ | `pageSize` | `number` | `20` | Initial rows per page |
134
+ | `rowCount` | `number` | — | Total row count for server-side pagination |
135
+ | `loading` | `boolean` | `false` | Shows a loading overlay |
136
+ | `onStateChange` | `(state: GridState) => void` | — | Fires when sorts, filters, grouping, or pagination change |
137
+ | `initialState` | `Partial<GridState>` | — | Seed initial sorts, filters, grouping, pagination, etc. |
136
138
 
137
139
  ### Selection
138
140
 
139
- | Prop | Type | Default | Description |
140
- |------|------|---------|-------------|
141
- | `selectionMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | Row selection behaviour |
142
- | `selectAllScope` | `'page' \| 'filtered'` | `'page'` | What the select-all checkbox targets |
143
- | `onSelectionChange` | `(rows: T[], ids: string[]) => void` | — | Fires whenever the selection changes |
141
+ | Prop | Type | Default | Description |
142
+ | ------------------- | ------------------------------------ | -------- | ------------------------------------ |
143
+ | `selectionMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | Row selection behaviour |
144
+ | `selectAllScope` | `'page' \| 'filtered'` | `'page'` | What the select-all checkbox targets |
145
+ | `onSelectionChange` | `(rows: T[], ids: string[]) => void` | — | Fires whenever the selection changes |
144
146
 
145
147
  ### Click handlers
146
148
 
147
- | Prop | Type | Description |
148
- |------|------|-------------|
149
- | `onRowClick` | `(row: T, index: number, e: MouseEvent) => void` | Called when a data row is clicked |
149
+ | Prop | Type | Description |
150
+ | ------------- | -------------------------------------------------------------- | ----------------------------------------- |
151
+ | `onRowClick` | `(row: T, index: number, e: MouseEvent) => void` | Called when a data row is clicked |
150
152
  | `onCellClick` | `(value, row: T, column: ColumnDef<T>, e: MouseEvent) => void` | Called when an individual cell is clicked |
151
153
 
152
154
  ### Column features
153
155
 
154
- | Prop | Type | Default | Description |
155
- |------|------|---------|-------------|
156
- | `enableColumnResize` | `boolean` | `false` | Drag-to-resize column widths |
156
+ | Prop | Type | Default | Description |
157
+ | ------------------------ | --------- | ------- | --------------------------------------- |
158
+ | `enableColumnResize` | `boolean` | `false` | Drag-to-resize column widths |
157
159
  | `enableColumnVisibility` | `boolean` | `false` | Show/hide column picker in header menus |
158
160
 
159
161
  ### Filtering
160
162
 
161
- | Prop | Type | Description |
162
- |------|------|-------------|
163
+ | Prop | Type | Description |
164
+ | -------------------- | ----------------------------------------- | ------------------------------------------------------------- |
163
165
  | `fetchFilterOptions` | `(columnId: string) => Promise<string[]>` | Server mode: fetch options for `filterType: 'select'` columns |
164
166
 
165
167
  ### Virtual scrolling
166
168
 
167
- | Prop | Type | Default | Description |
168
- |------|------|---------|-------------|
169
- | `height` | `number \| string` | — | Fixed height activates virtual scrolling (e.g. `600` or `'80vh'`) |
170
- | `estimatedRowHeight` | `number` | `41` | Row height hint for the virtualiser; affects scroll accuracy |
169
+ | Prop | Type | Default | Description |
170
+ | -------------------- | ------------------ | ------- | ----------------------------------------------------------------- |
171
+ | `height` | `number \| string` | — | Fixed height activates virtual scrolling (e.g. `600` or `'80vh'`) |
172
+ | `estimatedRowHeight` | `number` | `41` | Row height hint for the virtualiser; affects scroll accuracy |
171
173
 
172
174
  ### Inline editing
173
175
 
174
- | Prop | Type | Description |
175
- |------|------|-------------|
176
+ | Prop | Type | Description |
177
+ | ------------ | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
176
178
  | `onCellEdit` | `(newValue: string \| number, row: T, column: ColumnDef<T>) => void` | Called when a cell edit is committed. Set `editable: true` on columns you want editable. |
177
179
 
178
180
  ### Export
179
181
 
180
- | Prop | Type | Default | Description |
181
- |------|------|---------|-------------|
182
- | `enableCsvExport` | `boolean` | `false` | Adds CSV export button to toolbar |
183
- | `csvFilename` | `string` | `'export.csv'` | Downloaded file name |
182
+ | Prop | Type | Default | Description |
183
+ | ----------------- | --------- | -------------- | --------------------------------- |
184
+ | `enableCsvExport` | `boolean` | `false` | Adds CSV export button to toolbar |
185
+ | `csvFilename` | `string` | `'export.csv'` | Downloaded file name |
184
186
 
185
187
  ### Toolbar
186
188
 
187
- | Prop | Type | Description |
188
- |------|------|-------------|
189
+ | Prop | Type | Description |
190
+ | ---------------- | ----------------------------------- | ------------------------------------- |
189
191
  | `toolbarActions` | `(ctx: ToolbarCtx<T>) => ReactNode` | Render prop injected into the toolbar |
190
192
 
191
193
  `ToolbarCtx<T>` contains: `selectedRows`, `selectedIds`, `processedRows`, `gridState`, `clearSelection`.
192
194
 
193
195
  ### AI
194
196
 
195
- | Prop | Type | Description |
196
- |------|------|-------------|
197
+ | Prop | Type | Description |
198
+ | ---- | -------------------------------------------- | ---------------------------------------- |
197
199
  | `ai` | `{ endpoint: string; placeholder?: string }` | Enables the natural-language command bar |
198
200
 
199
201
  ### Display
200
202
 
201
- | Prop | Type | Description |
202
- |------|------|-------------|
203
- | `emptyState` | `ReactNode` | Custom content when there are no rows |
204
- | `className` | `string` | Class applied to the root wrapper element |
203
+ | Prop | Type | Description |
204
+ | ------------ | ----------- | ----------------------------------------- |
205
+ | `emptyState` | `ReactNode` | Custom content when there are no rows |
206
+ | `className` | `string` | Class applied to the root wrapper element |
205
207
 
206
208
  ---
207
209
 
@@ -218,14 +220,14 @@ const gridRef = useRef<GridRef<User>>(null)
218
220
  <DataGrid ref={gridRef} ... />
219
221
  ```
220
222
 
221
- | Method | Returns | Description |
222
- |--------|---------|-------------|
223
- | `getSelectedRows()` | `T[]` | Currently selected row objects |
224
- | `getProcessedRows()` | `T[]` | All rows after filtering (ignores pagination) |
225
- | `getGridState()` | `GridState` | Full current grid state snapshot |
226
- | `clearSelection()` | `void` | Clear all selected rows |
227
- | `exportCsv(opts?)` | `void` | Trigger CSV download. `opts.selectedOnly` exports selection only |
228
- | `setState(partial)` | `void` | Programmatically set sorts, filters, or grouping |
223
+ | Method | Returns | Description |
224
+ | -------------------- | ----------- | ---------------------------------------------------------------- |
225
+ | `getSelectedRows()` | `T[]` | Currently selected row objects |
226
+ | `getProcessedRows()` | `T[]` | All rows after filtering (ignores pagination) |
227
+ | `getGridState()` | `GridState` | Full current grid state snapshot |
228
+ | `clearSelection()` | `void` | Clear all selected rows |
229
+ | `exportCsv(opts?)` | `void` | Trigger CSV download. `opts.selectedOnly` exports selection only |
230
+ | `setState(partial)` | `void` | Programmatically set sorts, filters, or grouping |
229
231
 
230
232
  ---
231
233
 
@@ -233,20 +235,20 @@ const gridRef = useRef<GridRef<User>>(null)
233
235
 
234
236
  All visual properties are controlled via CSS custom properties on `:root` (or any ancestor element):
235
237
 
236
- | Variable | Default | Description |
237
- |----------|---------|-------------|
238
- | `--grid-font-size` | `0.875rem` | Base font size |
239
- | `--grid-border-colour` | `#e2e8f0` | Cell/row border colour |
240
- | `--grid-header-bg` | `#f1f5f9` | Header and toolbar background |
241
- | `--grid-row-hover-bg` | `#f8fafc` | Row hover background |
242
- | `--grid-selected-bg` | `#eef2ff` | Selected row background |
243
- | `--grid-accent` | `#6366f1` | Accent colour (focus rings, active filters, sort indicators) |
244
- | `--grid-focus-ring` | `0 0 0 2px #6366f1` | Focus ring box-shadow |
245
- | `--grid-radius` | `0.5rem` | Border radius of the outer wrapper |
246
- | `--grid-cell-padding` | `0.625rem 0.875rem` | Cell padding (shorthand) |
247
- | `--grid-cell-padding-y` | `0.625rem` | Vertical cell padding |
248
- | `--grid-cell-padding-x` | `0.875rem` | Horizontal cell padding |
249
- | `--grid-toolbar-gap` | `0.5rem` | Toolbar item gap |
238
+ | Variable | Default | Description |
239
+ | ----------------------- | ------------------- | ------------------------------------------------------------ |
240
+ | `--grid-font-size` | `0.875rem` | Base font size |
241
+ | `--grid-border-colour` | `#e2e8f0` | Cell/row border colour |
242
+ | `--grid-header-bg` | `#f1f5f9` | Header and toolbar background |
243
+ | `--grid-row-hover-bg` | `#f8fafc` | Row hover background |
244
+ | `--grid-selected-bg` | `#eef2ff` | Selected row background |
245
+ | `--grid-accent` | `#6366f1` | Accent colour (focus rings, active filters, sort indicators) |
246
+ | `--grid-focus-ring` | `0 0 0 2px #6366f1` | Focus ring box-shadow |
247
+ | `--grid-radius` | `0.5rem` | Border radius of the outer wrapper |
248
+ | `--grid-cell-padding` | `0.625rem 0.875rem` | Cell padding (shorthand) |
249
+ | `--grid-cell-padding-y` | `0.625rem` | Vertical cell padding |
250
+ | `--grid-cell-padding-x` | `0.875rem` | Horizontal cell padding |
251
+ | `--grid-toolbar-gap` | `0.5rem` | Toolbar item gap |
250
252
 
251
253
  Example — dark theme:
252
254
 
@@ -267,20 +269,20 @@ Example — dark theme:
267
269
  In `dataMode="server"`, the grid fires `onStateChange` whenever the user sorts, filters, groups, or paginates. Use this to fetch from your API:
268
270
 
269
271
  ```tsx
270
- const [data, setData] = useState<User[]>([])
271
- const [rowCount, setRowCount] = useState(0)
272
- const [loading, setLoading] = useState(false)
272
+ const [data, setData] = useState<User[]>([]);
273
+ const [rowCount, setRowCount] = useState(0);
274
+ const [loading, setLoading] = useState(false);
273
275
 
274
276
  async function fetchData(state: GridState) {
275
- setLoading(true)
277
+ setLoading(true);
276
278
  const res = await fetch('/api/users', {
277
279
  method: 'POST',
278
280
  body: JSON.stringify(state),
279
- })
280
- const json = await res.json()
281
- setData(json.rows)
282
- setRowCount(json.total)
283
- setLoading(false)
281
+ });
282
+ const json = await res.json();
283
+ setData(json.rows);
284
+ setRowCount(json.total);
285
+ setLoading(false);
284
286
  }
285
287
 
286
288
  <DataGrid<User>
@@ -291,7 +293,7 @@ async function fetchData(state: GridState) {
291
293
  rowCount={rowCount}
292
294
  loading={loading}
293
295
  onStateChange={fetchData}
294
- />
296
+ />;
295
297
  ```
296
298
 
297
299
  ---
@@ -314,20 +316,20 @@ Wire up the server handler (Express or Next.js App Router):
314
316
 
315
317
  ```ts
316
318
  // Express
317
- import { handleGridAiRequest } from 'yk-grid/server'
319
+ import { handleGridAiRequest } from 'yk-grid/server';
318
320
 
319
321
  app.post('/api/grid-ai', async (req, res) => {
320
- const result = await handleGridAiRequest(req.body)
321
- res.json(result)
322
- })
322
+ const result = await handleGridAiRequest(req.body);
323
+ res.json(result);
324
+ });
323
325
 
324
326
  // Next.js App Router
325
- import { handleGridAiRequest } from 'yk-grid/server'
327
+ import { handleGridAiRequest } from 'yk-grid/server';
326
328
 
327
329
  export async function POST(req: Request) {
328
- const body = await req.json()
329
- const result = await handleGridAiRequest(body)
330
- return Response.json(result)
330
+ const body = await req.json();
331
+ const result = await handleGridAiRequest(body);
332
+ return Response.json(result);
331
333
  }
332
334
  ```
333
335
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yk-grid",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Production-ready AI-assisted React DataGrid component with sorting, filtering, grouping, pagination, virtual scrolling, and optional natural-language query input",
5
5
  "keywords": [
6
6
  "react",
@@ -62,7 +62,10 @@
62
62
  "test": "vitest run",
63
63
  "test:watch": "vitest",
64
64
  "test:e2e": "playwright test",
65
- "lint": "tsc --noEmit"
65
+ "lint": "tsc --noEmit",
66
+ "docs:dev": "vitepress dev docs",
67
+ "docs:build": "vitepress build docs",
68
+ "docs:preview": "vitepress preview docs"
66
69
  },
67
70
  "peerDependencies": {
68
71
  "@tanstack/react-virtual": ">=3",
@@ -85,6 +88,7 @@
85
88
  "react-dom": "^19.2.7",
86
89
  "typescript": "^6.0.3",
87
90
  "vite": "^8.0.16",
91
+ "vitepress": "^1.6.4",
88
92
  "vitest": "^3.2.6",
89
93
  "zod": "^4.4.3"
90
94
  }