@izumisy-tailor/tailor-data-viewer 0.2.22 → 0.2.23
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/README.md +98 -66
- package/package.json +1 -1
- package/src/component/field-helpers.test.ts +34 -13
- package/src/component/field-helpers.ts +2 -29
- package/src/component/index.ts +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ A low-level React component library for building data table interfaces with Tail
|
|
|
11
11
|
- **`DataTable.*` Compound Components**: Data-bound table with sort indicators, cell renderers, and `useDataTable` integration
|
|
12
12
|
- **`useDataTable` Hook**: Integrates data, column visibility, row operations (optimistic updates), and props generators
|
|
13
13
|
- **Column Definition Helpers**: `field()` for data columns with sort/filter, `display()` for render-only columns
|
|
14
|
-
- **Metadata-based Inference**: `
|
|
14
|
+
- **Metadata-based Inference**: `createColumnHelper().inferColumns()` auto-derives sort/filter config from generated table metadata
|
|
15
15
|
- **Utility Components**: `ColumnSelector`, `CsvButton`, `SearchFilterForm`, `Pagination` — all props-based, spreadable from hooks
|
|
16
16
|
- **Multi-sort Support**: Multiple simultaneous sort fields
|
|
17
17
|
- **Optimistic Updates**: `updateRow`, `deleteRow`, `insertRow` with rollback
|
|
@@ -49,27 +49,27 @@ npm install react react-dom
|
|
|
49
49
|
import {
|
|
50
50
|
useCollection,
|
|
51
51
|
useDataTable,
|
|
52
|
-
Collection,
|
|
53
52
|
DataTable,
|
|
54
53
|
Pagination,
|
|
55
|
-
|
|
56
|
-
display,
|
|
54
|
+
createColumnHelper,
|
|
57
55
|
} from "@izumisy-tailor/tailor-data-viewer/component";
|
|
58
56
|
import "@izumisy-tailor/tailor-data-viewer/styles/theme.css";
|
|
59
57
|
|
|
60
58
|
// 1. Define columns
|
|
59
|
+
const { field, display } = createColumnHelper<Order>();
|
|
60
|
+
|
|
61
61
|
const columns = [
|
|
62
|
-
field
|
|
62
|
+
field("name", {
|
|
63
63
|
label: "Name",
|
|
64
64
|
sort: { type: "string" },
|
|
65
65
|
filter: { type: "string" },
|
|
66
66
|
}),
|
|
67
|
-
field
|
|
67
|
+
field("amount", {
|
|
68
68
|
label: "Amount",
|
|
69
69
|
sort: { type: "number" },
|
|
70
70
|
filter: { type: "number" },
|
|
71
71
|
}),
|
|
72
|
-
field
|
|
72
|
+
field("status", {
|
|
73
73
|
label: "Status",
|
|
74
74
|
filter: {
|
|
75
75
|
type: "enum",
|
|
@@ -79,7 +79,7 @@ const columns = [
|
|
|
79
79
|
],
|
|
80
80
|
},
|
|
81
81
|
}),
|
|
82
|
-
display
|
|
82
|
+
display("actions", {
|
|
83
83
|
width: 50,
|
|
84
84
|
render: (row) => <button onClick={() => handleEdit(row)}>Edit</button>,
|
|
85
85
|
}),
|
|
@@ -98,13 +98,13 @@ function OrdersPage() {
|
|
|
98
98
|
});
|
|
99
99
|
|
|
100
100
|
return (
|
|
101
|
-
<
|
|
102
|
-
<DataTable.Root
|
|
101
|
+
<DataTable.Provider value={table}>
|
|
102
|
+
<DataTable.Root>
|
|
103
103
|
<DataTable.Headers />
|
|
104
104
|
<DataTable.Body />
|
|
105
105
|
</DataTable.Root>
|
|
106
|
-
<Pagination
|
|
107
|
-
</
|
|
106
|
+
<Pagination />
|
|
107
|
+
</DataTable.Provider>
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
```
|
|
@@ -128,8 +128,8 @@ const collection = useCollection({
|
|
|
128
128
|
const [result] = useQuery({ ...collection.toQueryArgs() });
|
|
129
129
|
|
|
130
130
|
// Filter operations
|
|
131
|
-
collection.addFilter("status", "
|
|
132
|
-
collection.setFilters([{ field: "status",
|
|
131
|
+
collection.addFilter("status", "eq", "ACTIVE");
|
|
132
|
+
collection.setFilters([{ field: "status", operator: "eq", value: "ACTIVE" }]);
|
|
133
133
|
collection.removeFilter("status");
|
|
134
134
|
collection.clearFilters();
|
|
135
135
|
|
|
@@ -140,26 +140,40 @@ collection.clearSort();
|
|
|
140
140
|
|
|
141
141
|
// Pagination
|
|
142
142
|
collection.nextPage(endCursor);
|
|
143
|
-
collection.prevPage();
|
|
143
|
+
collection.prevPage(startCursor);
|
|
144
144
|
collection.resetPage();
|
|
145
|
+
|
|
146
|
+
// Page info tracking
|
|
147
|
+
collection.setPageInfo(pageInfo);
|
|
148
|
+
collection.hasPrevPage; // boolean
|
|
149
|
+
collection.hasNextPage; // boolean
|
|
145
150
|
```
|
|
146
151
|
|
|
147
|
-
### `
|
|
152
|
+
### `DataTable.Provider` / `useDataTableContext()` / `useCollectionContext()`
|
|
148
153
|
|
|
149
|
-
|
|
154
|
+
`DataTable.Provider` wraps the table UI and provides both data table and collection context. All utility components (`Pagination`, `ColumnSelector`, `CsvButton`, `SearchFilterForm`) read from this context — no prop spreading needed.
|
|
155
|
+
|
|
156
|
+
When `collection` is passed to `useDataTable`, `DataTable.Provider` automatically wraps a `Collection.Provider` so child components can use `useCollectionContext()`.
|
|
150
157
|
|
|
151
158
|
```tsx
|
|
152
|
-
<
|
|
159
|
+
<DataTable.Provider value={table}>
|
|
153
160
|
<StatusFilter /> {/* useCollectionContext() inside */}
|
|
154
|
-
<DataTable.Root
|
|
161
|
+
<DataTable.Root>
|
|
155
162
|
<DataTable.Headers />
|
|
156
163
|
<DataTable.Body />
|
|
157
164
|
</DataTable.Root>
|
|
158
|
-
<Pagination
|
|
159
|
-
</
|
|
165
|
+
<Pagination />
|
|
166
|
+
</DataTable.Provider>
|
|
160
167
|
```
|
|
161
168
|
|
|
162
|
-
Provider
|
|
169
|
+
For cases where you need `Collection.Provider` without `DataTable.Provider` (e.g., non-table UIs), you can use it standalone:
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<Collection.Provider value={collection}>
|
|
173
|
+
<StatusFilter />
|
|
174
|
+
<CustomKanbanBoard />
|
|
175
|
+
</Collection.Provider>
|
|
176
|
+
```
|
|
163
177
|
|
|
164
178
|
### Column Definition Helpers
|
|
165
179
|
|
|
@@ -189,7 +203,7 @@ display("actions", {
|
|
|
189
203
|
|
|
190
204
|
### Table Metadata Generator
|
|
191
205
|
|
|
192
|
-
This library includes a metadata generator for [Tailor Platform SDK](https://www.npmjs.com/package/@tailor-platform/sdk) that produces type-safe table metadata with `as const` assertions. The generated metadata is used by `
|
|
206
|
+
This library includes a metadata generator for [Tailor Platform SDK](https://www.npmjs.com/package/@tailor-platform/sdk) that produces type-safe table metadata with `as const` assertions. The generated metadata is used by `createColumnHelper().inferColumns()` for automatic sort/filter configuration.
|
|
193
207
|
|
|
194
208
|
1. Configure the generator in your `tailor.config.ts`:
|
|
195
209
|
|
|
@@ -215,15 +229,16 @@ export default defineConfig({
|
|
|
215
229
|
tailor-sdk generate
|
|
216
230
|
```
|
|
217
231
|
|
|
218
|
-
### `
|
|
232
|
+
### `createColumnHelper().inferColumns(tableMetadata)`
|
|
219
233
|
|
|
220
|
-
`field()` requires manually specifying `sort`/`filter` type configs and enum `options` for every column. `
|
|
234
|
+
`field()` requires manually specifying `sort`/`filter` type configs and enum `options` for every column. `inferColumns()` eliminates this boilerplate by automatically deriving these from the generated table metadata. Based on each field's type (string, number, date, enum, etc.), the appropriate `SortConfig` / `FilterConfig` is set automatically, and enum fields get their options populated from the schema.
|
|
221
235
|
|
|
222
236
|
```tsx
|
|
223
|
-
import {
|
|
237
|
+
import { createColumnHelper } from "@izumisy-tailor/tailor-data-viewer/component";
|
|
224
238
|
import { tableMetadata } from "./generated/data-viewer-metadata.generated";
|
|
225
239
|
|
|
226
|
-
const {
|
|
240
|
+
const { inferColumns, display } = createColumnHelper<Task>();
|
|
241
|
+
const { column, columns } = inferColumns(tableMetadata.task);
|
|
227
242
|
|
|
228
243
|
const taskColumns = [
|
|
229
244
|
column("title"), // sort/filter auto-configured from metadata
|
|
@@ -237,7 +252,7 @@ const taskColumns = [
|
|
|
237
252
|
];
|
|
238
253
|
```
|
|
239
254
|
|
|
240
|
-
`
|
|
255
|
+
`inferColumns()` can be freely mixed with manual `field()` / `display()` definitions. Use `field()` for fields not in the metadata or those requiring custom configuration, and `inferColumns()` for everything else.
|
|
241
256
|
|
|
242
257
|
### `useDataTable(options)`
|
|
243
258
|
|
|
@@ -250,13 +265,19 @@ const table = useDataTable<Order>({
|
|
|
250
265
|
loading: result.fetching,
|
|
251
266
|
error: result.error,
|
|
252
267
|
collection,
|
|
268
|
+
onClickRow: (row) => navigate(`/orders/${row.id}`),
|
|
269
|
+
rowActions: [
|
|
270
|
+
{ id: "delete", label: "Delete", variant: "destructive", onClick: (row) => handleDelete(row.id) },
|
|
271
|
+
],
|
|
253
272
|
});
|
|
254
273
|
|
|
255
|
-
//
|
|
256
|
-
<DataTable.
|
|
257
|
-
<
|
|
258
|
-
<
|
|
259
|
-
<
|
|
274
|
+
// Wrap with DataTable.Provider (utility components read from context)
|
|
275
|
+
<DataTable.Provider value={table}>
|
|
276
|
+
<DataTable.Root>...</DataTable.Root>
|
|
277
|
+
<ColumnSelector />
|
|
278
|
+
<CsvButton filename="orders" />
|
|
279
|
+
<Pagination />
|
|
280
|
+
</DataTable.Provider>
|
|
260
281
|
|
|
261
282
|
// Column visibility
|
|
262
283
|
table.toggleColumn("amount");
|
|
@@ -296,52 +317,63 @@ Low-level table primitives without data binding. Use for fully custom layouts or
|
|
|
296
317
|
Pair with `useDataTable` for automatic header sorting, cell rendering, and row operations.
|
|
297
318
|
|
|
298
319
|
```tsx
|
|
299
|
-
// Basic usage (
|
|
300
|
-
<DataTable.
|
|
301
|
-
<DataTable.
|
|
302
|
-
|
|
303
|
-
|
|
320
|
+
// Basic usage (wrap with DataTable.Provider)
|
|
321
|
+
<DataTable.Provider value={table}>
|
|
322
|
+
<DataTable.Root>
|
|
323
|
+
<DataTable.Headers />
|
|
324
|
+
<DataTable.Body />
|
|
325
|
+
</DataTable.Root>
|
|
326
|
+
</DataTable.Provider>
|
|
304
327
|
|
|
305
328
|
// Custom row rendering
|
|
306
|
-
<DataTable.
|
|
307
|
-
<DataTable.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
</DataTable.Root>
|
|
329
|
+
<DataTable.Provider value={table}>
|
|
330
|
+
<DataTable.Root>
|
|
331
|
+
<DataTable.Headers />
|
|
332
|
+
<DataTable.Body>
|
|
333
|
+
{table.rows.map((row) => (
|
|
334
|
+
<DataTable.Row
|
|
335
|
+
key={row.id}
|
|
336
|
+
onClick={() => navigate(`/orders/${row.id}`)}
|
|
337
|
+
>
|
|
338
|
+
{table.visibleColumns.map((col) => (
|
|
339
|
+
<DataTable.Cell key={col.kind === "field" ? col.dataKey : col.id} />
|
|
340
|
+
))}
|
|
341
|
+
</DataTable.Row>
|
|
342
|
+
))}
|
|
343
|
+
</DataTable.Body>
|
|
344
|
+
</DataTable.Root>
|
|
345
|
+
</DataTable.Provider>
|
|
322
346
|
```
|
|
323
347
|
|
|
324
348
|
### Utility Components
|
|
325
349
|
|
|
326
|
-
All utility components
|
|
350
|
+
All utility components read from `DataTable.Provider` context.
|
|
351
|
+
|
|
352
|
+
| Component | Props | Description |
|
|
353
|
+
|-----------|-------|-------------|
|
|
354
|
+
| `Pagination` | (none) | Previous/Next page controls |
|
|
355
|
+
| `ColumnSelector` | (none) | Column visibility toggle UI |
|
|
356
|
+
| `CsvButton` | `filename?` | Export visible data as CSV |
|
|
357
|
+
| `SearchFilterForm` | `labels?`, `trigger?` | Multi-field filter form with operator selection |
|
|
327
358
|
|
|
328
|
-
|
|
329
|
-
|-----------|------------|-------------|
|
|
330
|
-
| `ColumnSelector` | `{...table}` | Column visibility toggle UI |
|
|
331
|
-
| `CsvButton` | `{...table}` | Export visible data as CSV |
|
|
332
|
-
| `SearchFilterForm` | `{...table, ...collection}` | Multi-field filter form with operator selection |
|
|
333
|
-
| `Pagination` | `{...table}` | Previous/Next page controls |
|
|
359
|
+
All utility components read from `DataTable.Provider` context — no prop spreading needed:
|
|
334
360
|
|
|
335
361
|
```tsx
|
|
336
|
-
<
|
|
337
|
-
<
|
|
338
|
-
<
|
|
339
|
-
<
|
|
362
|
+
<DataTable.Provider value={table}>
|
|
363
|
+
<SearchFilterForm />
|
|
364
|
+
<ColumnSelector />
|
|
365
|
+
<CsvButton filename="orders-export" />
|
|
366
|
+
<DataTable.Root>
|
|
367
|
+
<DataTable.Headers />
|
|
368
|
+
<DataTable.Body />
|
|
369
|
+
</DataTable.Root>
|
|
370
|
+
<Pagination />
|
|
371
|
+
</DataTable.Provider>
|
|
340
372
|
```
|
|
341
373
|
|
|
342
374
|
### Optimistic Updates in Cell Renderers
|
|
343
375
|
|
|
344
|
-
Use `useDataTableContext()` inside `DataTable.
|
|
376
|
+
Use `useDataTableContext()` inside `DataTable.Provider` to access row operations from custom cell renderers.
|
|
345
377
|
|
|
346
378
|
```tsx
|
|
347
379
|
const StatusEditor: CellRenderer<Order> = ({ value, row }) => {
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, expectTypeOf } from "vitest";
|
|
2
|
-
import { createColumnHelper
|
|
2
|
+
import { createColumnHelper } from "./field-helpers";
|
|
3
3
|
import type { TableMetadataMap } from "../generator/metadata-generator";
|
|
4
4
|
import { fieldTypeToSortConfig, fieldTypeToFilterConfig } from "./types";
|
|
5
5
|
import type { NodeType, TableFieldName } from "./types";
|
|
@@ -175,7 +175,7 @@ describe("fieldTypeToFilterConfig", () => {
|
|
|
175
175
|
});
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
-
describe("
|
|
178
|
+
describe("createColumnHelper().inferColumns()", () => {
|
|
179
179
|
const testMetadata = {
|
|
180
180
|
task: {
|
|
181
181
|
name: "task",
|
|
@@ -203,8 +203,19 @@ describe("inferColumnHelper()", () => {
|
|
|
203
203
|
},
|
|
204
204
|
} as const satisfies TableMetadataMap;
|
|
205
205
|
|
|
206
|
+
type TaskRow = {
|
|
207
|
+
id: string;
|
|
208
|
+
title: string;
|
|
209
|
+
status: string;
|
|
210
|
+
dueDate: string;
|
|
211
|
+
count: number;
|
|
212
|
+
isActive: boolean;
|
|
213
|
+
tags: string[];
|
|
214
|
+
};
|
|
215
|
+
|
|
206
216
|
it("creates a column with auto-detected sort/filter", () => {
|
|
207
|
-
const {
|
|
217
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
218
|
+
const { column } = inferColumns(testMetadata.task);
|
|
208
219
|
|
|
209
220
|
const titleCol = column("title");
|
|
210
221
|
expect(titleCol.kind).toBe("field");
|
|
@@ -214,7 +225,8 @@ describe("inferColumnHelper()", () => {
|
|
|
214
225
|
});
|
|
215
226
|
|
|
216
227
|
it("auto-detects enum options", () => {
|
|
217
|
-
const {
|
|
228
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
229
|
+
const { column } = inferColumns(testMetadata.task);
|
|
218
230
|
const statusCol = column("status");
|
|
219
231
|
expect(statusCol.filter).toEqual({
|
|
220
232
|
type: "enum",
|
|
@@ -229,42 +241,48 @@ describe("inferColumnHelper()", () => {
|
|
|
229
241
|
});
|
|
230
242
|
|
|
231
243
|
it("auto-detects date type", () => {
|
|
232
|
-
const {
|
|
244
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
245
|
+
const { column } = inferColumns(testMetadata.task);
|
|
233
246
|
const dateCol = column("dueDate");
|
|
234
247
|
expect(dateCol.sort).toEqual({ type: "date" });
|
|
235
248
|
expect(dateCol.filter).toEqual({ type: "date" });
|
|
236
249
|
});
|
|
237
250
|
|
|
238
251
|
it("disables sort with sort: false", () => {
|
|
239
|
-
const {
|
|
252
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
253
|
+
const { column } = inferColumns(testMetadata.task);
|
|
240
254
|
const col = column("title", { sort: false });
|
|
241
255
|
expect(col.sort).toBeUndefined();
|
|
242
256
|
expect(col.filter).toEqual({ type: "string" });
|
|
243
257
|
});
|
|
244
258
|
|
|
245
259
|
it("disables filter with filter: false", () => {
|
|
246
|
-
const {
|
|
260
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
261
|
+
const { column } = inferColumns(testMetadata.task);
|
|
247
262
|
const col = column("title", { filter: false });
|
|
248
263
|
expect(col.sort).toEqual({ type: "string" });
|
|
249
264
|
expect(col.filter).toBeUndefined();
|
|
250
265
|
});
|
|
251
266
|
|
|
252
267
|
it("uuid has no sort, has uuid filter", () => {
|
|
253
|
-
const {
|
|
268
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
269
|
+
const { column } = inferColumns(testMetadata.task);
|
|
254
270
|
const col = column("id");
|
|
255
271
|
expect(col.sort).toBeUndefined();
|
|
256
272
|
expect(col.filter).toEqual({ type: "uuid" });
|
|
257
273
|
});
|
|
258
274
|
|
|
259
275
|
it("array type has no sort/filter", () => {
|
|
260
|
-
const {
|
|
276
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
277
|
+
const { column } = inferColumns(testMetadata.task);
|
|
261
278
|
const col = column("tags");
|
|
262
279
|
expect(col.sort).toBeUndefined();
|
|
263
280
|
expect(col.filter).toBeUndefined();
|
|
264
281
|
});
|
|
265
282
|
|
|
266
283
|
it("columns() creates multiple columns at once", () => {
|
|
267
|
-
const {
|
|
284
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
285
|
+
const { columns } = inferColumns(testMetadata.task);
|
|
268
286
|
const cols = columns(["title", "status", "dueDate"]);
|
|
269
287
|
expect(cols).toHaveLength(3);
|
|
270
288
|
expect(cols[0].dataKey).toBe("title");
|
|
@@ -273,7 +291,8 @@ describe("inferColumnHelper()", () => {
|
|
|
273
291
|
});
|
|
274
292
|
|
|
275
293
|
it("columns() applies overrides", () => {
|
|
276
|
-
const {
|
|
294
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
295
|
+
const { columns } = inferColumns(testMetadata.task);
|
|
277
296
|
const cols = columns(["title", "status"], {
|
|
278
297
|
overrides: {
|
|
279
298
|
title: { label: "Custom Title", width: 300 },
|
|
@@ -284,7 +303,8 @@ describe("inferColumnHelper()", () => {
|
|
|
284
303
|
});
|
|
285
304
|
|
|
286
305
|
it("columns() applies global sort/filter options", () => {
|
|
287
|
-
const {
|
|
306
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
307
|
+
const { columns } = inferColumns(testMetadata.task);
|
|
288
308
|
const cols = columns(["title", "status"], { sort: false });
|
|
289
309
|
expect(cols[0].sort).toBeUndefined();
|
|
290
310
|
expect(cols[1].sort).toBeUndefined();
|
|
@@ -293,7 +313,8 @@ describe("inferColumnHelper()", () => {
|
|
|
293
313
|
});
|
|
294
314
|
|
|
295
315
|
it("throws for non-existent field", () => {
|
|
296
|
-
const {
|
|
316
|
+
const { inferColumns } = createColumnHelper<TaskRow>();
|
|
317
|
+
const { column } = inferColumns(testMetadata.task);
|
|
297
318
|
// @ts-expect-error - intentionally testing invalid field name
|
|
298
319
|
expect(() => column("nonExistent")).toThrow(
|
|
299
320
|
'Field "nonExistent" not found in table "task" metadata',
|
|
@@ -140,37 +140,10 @@ export function createColumnHelper<TRow extends Record<string, unknown>>(): {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
// =============================================================================
|
|
143
|
-
//
|
|
143
|
+
// Internal: metadata-based column inference (used by createColumnHelper)
|
|
144
144
|
// =============================================================================
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
* Create column definition helpers from generated table metadata.
|
|
148
|
-
*
|
|
149
|
-
* Automatically infers sort/filter configuration from field types,
|
|
150
|
-
* including enum options.
|
|
151
|
-
*
|
|
152
|
-
* @typeParam TRow - The row type for type-safe renderer access.
|
|
153
|
-
* @param tableMetadata - A single table metadata object from the generated map.
|
|
154
|
-
*
|
|
155
|
-
* @example
|
|
156
|
-
* ```tsx
|
|
157
|
-
* import { tableMetadata } from "./generated/data-viewer-metadata.generated";
|
|
158
|
-
*
|
|
159
|
-
* type Task = { id: string; title: string; status: string; dueDate: string };
|
|
160
|
-
*
|
|
161
|
-
* const { column, columns } = inferColumnHelper<Task>(tableMetadata.task);
|
|
162
|
-
*
|
|
163
|
-
* const taskColumns = [
|
|
164
|
-
* column("title"), // sort/filter auto-detected
|
|
165
|
-
* column("status"), // enum options auto-populated
|
|
166
|
-
* column("dueDate"), // date type auto-recognized
|
|
167
|
-
* column("title", {
|
|
168
|
-
* renderer: ({ row }) => <span>{row.title}</span>, // row: Task
|
|
169
|
-
* }),
|
|
170
|
-
* ];
|
|
171
|
-
* ```
|
|
172
|
-
*/
|
|
173
|
-
export function inferColumnHelper<
|
|
146
|
+
function inferColumnHelper<
|
|
174
147
|
TRow extends Record<string, unknown>,
|
|
175
148
|
const TTable extends TableMetadata = TableMetadata,
|
|
176
149
|
>(
|
package/src/component/index.ts
CHANGED
|
@@ -65,7 +65,7 @@ export { useDataTable } from "./data-table/use-data-table";
|
|
|
65
65
|
export { useDataTableContext } from "./data-table/data-table-context";
|
|
66
66
|
|
|
67
67
|
// Field helpers
|
|
68
|
-
export { createColumnHelper
|
|
68
|
+
export { createColumnHelper } from "./field-helpers";
|
|
69
69
|
|
|
70
70
|
// Utility components
|
|
71
71
|
export { Pagination } from "./pagination";
|