@izumisy-tailor/tailor-data-viewer 0.2.0 → 0.2.2

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.
@@ -1,6 +1,7 @@
1
1
  import { renderHook, act } from "@testing-library/react";
2
2
  import { describe, it, expect } from "vitest";
3
- import { useCollectionParams } from "./collection-params/use-collection-params";
3
+ import type { TableMetadataMap } from "../../generator/metadata-generator";
4
+ import { useCollectionParams } from "./use-collection-params";
4
5
 
5
6
  describe("useCollectionParams", () => {
6
7
  // ---------------------------------------------------------------------------
@@ -337,4 +338,129 @@ describe("useCollectionParams", () => {
337
338
  expect("after" in vars).toBe(false);
338
339
  });
339
340
  });
341
+
342
+ // ---------------------------------------------------------------------------
343
+ // Metadata-typed overload
344
+ // ---------------------------------------------------------------------------
345
+ describe("metadata-typed overload", () => {
346
+ const testMetadata = {
347
+ task: {
348
+ name: "task",
349
+ pluralForm: "tasks",
350
+ readAllowedRoles: [],
351
+ fields: [
352
+ { name: "id", type: "uuid", required: true },
353
+ { name: "title", type: "string", required: true },
354
+ {
355
+ name: "status",
356
+ type: "enum",
357
+ required: true,
358
+ enumValues: ["todo", "in_progress", "done"],
359
+ },
360
+ { name: "dueDate", type: "date", required: false },
361
+ { name: "count", type: "number", required: false },
362
+ ],
363
+ },
364
+ } as const satisfies TableMetadataMap;
365
+
366
+ it("works with metadata and tableName", () => {
367
+ const { result } = renderHook(() =>
368
+ useCollectionParams({
369
+ metadata: testMetadata,
370
+ tableName: "task",
371
+ pageSize: 10,
372
+ }),
373
+ );
374
+ expect(result.current.variables).toEqual({ first: 10 });
375
+ });
376
+
377
+ it("auto-detects fieldType from metadata for string field", () => {
378
+ const { result } = renderHook(() =>
379
+ useCollectionParams({
380
+ metadata: testMetadata,
381
+ tableName: "task",
382
+ }),
383
+ );
384
+
385
+ act(() => {
386
+ result.current.addFilter("title", "foo");
387
+ });
388
+
389
+ expect(result.current.filters[0].fieldType).toBe("string");
390
+ });
391
+
392
+ it("auto-detects fieldType from metadata for enum field", () => {
393
+ const { result } = renderHook(() =>
394
+ useCollectionParams({
395
+ metadata: testMetadata,
396
+ tableName: "task",
397
+ }),
398
+ );
399
+
400
+ act(() => {
401
+ result.current.addFilter("status", "todo");
402
+ });
403
+
404
+ expect(result.current.filters[0].fieldType).toBe("enum");
405
+ });
406
+
407
+ it("auto-detects fieldType from metadata for date field", () => {
408
+ const { result } = renderHook(() =>
409
+ useCollectionParams({
410
+ metadata: testMetadata,
411
+ tableName: "task",
412
+ }),
413
+ );
414
+
415
+ act(() => {
416
+ result.current.addFilter("dueDate", "2026-01-01");
417
+ });
418
+
419
+ expect(result.current.filters[0].fieldType).toBe("date");
420
+ });
421
+
422
+ it("auto-detects fieldType from metadata for uuid field", () => {
423
+ const { result } = renderHook(() =>
424
+ useCollectionParams({
425
+ metadata: testMetadata,
426
+ tableName: "task",
427
+ }),
428
+ );
429
+
430
+ act(() => {
431
+ result.current.addFilter("id", "some-uuid");
432
+ });
433
+
434
+ expect(result.current.filters[0].fieldType).toBe("uuid");
435
+ });
436
+
437
+ it("auto-detects fieldType from metadata for number field", () => {
438
+ const { result } = renderHook(() =>
439
+ useCollectionParams({
440
+ metadata: testMetadata,
441
+ tableName: "task",
442
+ }),
443
+ );
444
+
445
+ act(() => {
446
+ result.current.addFilter("count", 42);
447
+ });
448
+
449
+ expect(result.current.filters[0].fieldType).toBe("number");
450
+ });
451
+
452
+ it("applies typed initialSort", () => {
453
+ const { result } = renderHook(() =>
454
+ useCollectionParams({
455
+ metadata: testMetadata,
456
+ tableName: "task",
457
+ initialSort: [{ field: "dueDate", direction: "Desc" }],
458
+ }),
459
+ );
460
+
461
+ expect(result.current.sortStates).toEqual([
462
+ { field: "dueDate", direction: "Desc" },
463
+ ]);
464
+ });
465
+ });
340
466
  });
@@ -1,4 +1,8 @@
1
- import { useCallback, useMemo, useState } from "react";
1
+ import { useCallback, useMemo, useRef, useState } from "react";
2
+ import type {
3
+ FieldType,
4
+ TableMetadataMap,
5
+ } from "../../generator/metadata-generator";
2
6
  import type {
3
7
  Filter,
4
8
  FilterOperator,
@@ -7,6 +11,40 @@ import type {
7
11
  UseCollectionParamsOptions,
8
12
  UseCollectionParamsReturn,
9
13
  } from "../types";
14
+ import { fieldTypeToFilterConfig } from "../types";
15
+ import type { FieldName } from "../types";
16
+
17
+ // -----------------------------------------------------------------------------
18
+ // Overload signatures
19
+ // -----------------------------------------------------------------------------
20
+
21
+ /**
22
+ * Hook for managing collection query parameters (filters, sort, pagination)
23
+ * with metadata-based field name typing and automatic `fieldType` detection.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * import { tableMetadata } from "./generated/data-viewer-metadata.generated";
28
+ *
29
+ * const params = useCollectionParams({
30
+ * metadata: tableMetadata,
31
+ * tableName: "task",
32
+ * pageSize: 20,
33
+ * });
34
+ *
35
+ * params.addFilter("title", "foo"); // ✅ field name auto-completed
36
+ * params.addFilter("nonExistent", "foo"); // ❌ type error
37
+ * ```
38
+ */
39
+ export function useCollectionParams<
40
+ const TMetadata extends TableMetadataMap,
41
+ TTableName extends string & keyof TMetadata,
42
+ >(
43
+ options: UseCollectionParamsOptions<FieldName<TMetadata, TTableName>> & {
44
+ metadata: TMetadata;
45
+ tableName: TTableName;
46
+ },
47
+ ): UseCollectionParamsReturn<FieldName<TMetadata, TTableName>>;
10
48
 
11
49
  /**
12
50
  * Hook for managing collection query parameters (filters, sort, pagination).
@@ -16,19 +54,36 @@ import type {
16
54
  *
17
55
  * @example
18
56
  * ```tsx
19
- * const params = useCollectionParams<Order>({ pageSize: 20 });
57
+ * const params = useCollectionParams({ pageSize: 20 });
20
58
  * const [result] = useQuery({ query: GET_ORDERS, variables: params.variables });
21
59
  * ```
22
60
  */
23
61
  export function useCollectionParams(
24
- options: UseCollectionParamsOptions = {},
62
+ options?: UseCollectionParamsOptions,
63
+ ): UseCollectionParamsReturn;
64
+
65
+ // -----------------------------------------------------------------------------
66
+ // Implementation
67
+ // -----------------------------------------------------------------------------
68
+ export function useCollectionParams(
69
+ options: UseCollectionParamsOptions & {
70
+ metadata?: TableMetadataMap;
71
+ tableName?: string;
72
+ } = {},
25
73
  ): UseCollectionParamsReturn {
26
74
  const {
27
75
  initialFilters = [],
28
76
  initialSort = [],
29
77
  pageSize: initialPageSize = 20,
78
+ metadata,
79
+ tableName,
30
80
  } = options;
31
81
 
82
+ // Keep a ref to the resolved fields list so callbacks can look up fieldType.
83
+ const fieldsRef = useRef(
84
+ metadata && tableName ? metadata[tableName]?.fields : undefined,
85
+ );
86
+
32
87
  // ---------------------------------------------------------------------------
33
88
  // State
34
89
  // ---------------------------------------------------------------------------
@@ -45,9 +100,17 @@ export function useCollectionParams(
45
100
  (field: string, value: unknown, operator: FilterOperator = "eq") => {
46
101
  setFiltersState((prev) => {
47
102
  const existing = prev.findIndex((f) => f.field === field);
103
+ // Auto-detect fieldType from metadata when available
104
+ const fieldMeta = fieldsRef.current?.find((f) => f.name === field);
105
+ const detectedType: Filter["fieldType"] = fieldMeta
106
+ ? (fieldTypeToFilterConfig(
107
+ fieldMeta.type as FieldType,
108
+ fieldMeta.enumValues as readonly string[] | undefined,
109
+ )?.type ?? "string")
110
+ : "string";
48
111
  const newFilter: Filter = {
49
112
  field,
50
- fieldType: "string", // default, can be overridden by setFilters
113
+ fieldType: detectedType,
51
114
  operator,
52
115
  value,
53
116
  };
@@ -1,7 +1,7 @@
1
1
  import { renderHook, act } from "@testing-library/react";
2
2
  import { describe, it, expect } from "vitest";
3
- import { useDataTable } from "./data-table/use-data-table";
4
- import type { Column, CollectionResult } from "./types";
3
+ import { useDataTable } from "./use-data-table";
4
+ import type { Column, CollectionResult } from "../types";
5
5
 
6
6
  type TestRow = {
7
7
  id: string;
@@ -1,43 +1,76 @@
1
- import { describe, it, expect } from "vitest";
2
- import { field, display, inferColumns } from "./field-helpers";
1
+ import { describe, it, expect, expectTypeOf } from "vitest";
2
+ import { createColumnHelper, inferColumnHelper } from "./field-helpers";
3
3
  import type { TableMetadataMap } from "../generator/metadata-generator";
4
4
  import { fieldTypeToSortConfig, fieldTypeToFilterConfig } from "./types";
5
+ import type { NodeType } from "./types";
5
6
 
6
- describe("field()", () => {
7
- it("creates a field column with minimal options", () => {
8
- const col = field<{ name: string }>("name");
9
- expect(col.kind).toBe("field");
10
- expect(col.dataKey).toBe("name");
11
- expect(col.label).toBeUndefined();
12
- expect(col.sort).toBeUndefined();
13
- expect(col.filter).toBeUndefined();
7
+ describe("NodeType", () => {
8
+ it("extracts node type from a collection result", () => {
9
+ type Result = { edges: { node: { id: string; name: string } }[] };
10
+ type Row = NodeType<Result>;
11
+ expectTypeOf<Row>().toEqualTypeOf<{ id: string; name: string }>();
12
+ });
13
+
14
+ it("handles nullable collection (e.g. gql-tada ResultOf)", () => {
15
+ type Result =
16
+ | { edges: { node: { id: string; amount: number } }[] }
17
+ | null
18
+ | undefined;
19
+ type Row = NodeType<Result>;
20
+ expectTypeOf<Row>().toEqualTypeOf<{ id: string; amount: number }>();
21
+ });
22
+
23
+ it("works with createColumnHelper", () => {
24
+ type Result = { edges: { node: { id: string; title: string } }[] } | null;
25
+ type Row = NodeType<Result>;
26
+ const { field } = createColumnHelper<Row>();
27
+ const col = field("title");
28
+ expect(col.dataKey).toBe("title");
29
+ });
30
+ });
31
+
32
+ describe("createColumnHelper()", () => {
33
+ type TestRow = { name: string; age: number };
34
+
35
+ it("returns field and display helpers with TRow bound", () => {
36
+ const helpers = createColumnHelper<TestRow>();
37
+ expect(typeof helpers.field).toBe("function");
38
+ expect(typeof helpers.display).toBe("function");
14
39
  });
15
40
 
16
- it("creates a field column with full options", () => {
17
- const col = field<{ name: string }>("name", {
41
+ it("field helper creates a field column without explicit type param", () => {
42
+ const { field } = createColumnHelper<TestRow>();
43
+ const col = field("name", {
18
44
  label: "Name",
19
- width: 200,
20
45
  sort: { type: "string" },
21
46
  filter: { type: "string" },
22
47
  });
48
+ expect(col.kind).toBe("field");
49
+ expect(col.dataKey).toBe("name");
23
50
  expect(col.label).toBe("Name");
24
- expect(col.width).toBe(200);
25
51
  expect(col.sort).toEqual({ type: "string" });
26
52
  expect(col.filter).toEqual({ type: "string" });
27
53
  });
28
- });
29
54
 
30
- describe("display()", () => {
31
- it("creates a display column", () => {
32
- const col = display<{ id: string }>("actions", {
55
+ it("field helper creates minimal column", () => {
56
+ const { field } = createColumnHelper<TestRow>();
57
+ const col = field("age");
58
+ expect(col.kind).toBe("field");
59
+ expect(col.dataKey).toBe("age");
60
+ expect(col.label).toBeUndefined();
61
+ });
62
+
63
+ it("display helper creates a display column without explicit type param", () => {
64
+ const { display } = createColumnHelper<TestRow>();
65
+ const col = display("actions", {
33
66
  label: "Actions",
34
- width: 50,
35
- render: () => null,
67
+ width: 100,
68
+ render: (row) => `${row.name}: ${row.age}`,
36
69
  });
37
70
  expect(col.kind).toBe("display");
38
71
  expect(col.id).toBe("actions");
39
72
  expect(col.label).toBe("Actions");
40
- expect(col.width).toBe(50);
73
+ expect(col.width).toBe(100);
41
74
  expect(typeof col.render).toBe("function");
42
75
  });
43
76
  });
@@ -105,7 +138,7 @@ describe("fieldTypeToFilterConfig", () => {
105
138
  });
106
139
  });
107
140
 
108
- describe("inferColumns()", () => {
141
+ describe("inferColumnHelper()", () => {
109
142
  const testMetadata = {
110
143
  task: {
111
144
  name: "task",
@@ -134,7 +167,10 @@ describe("inferColumns()", () => {
134
167
  } as const satisfies TableMetadataMap;
135
168
 
136
169
  it("creates a column with auto-detected sort/filter", () => {
137
- const { column } = inferColumns(testMetadata, "task");
170
+ const { column } = inferColumnHelper({
171
+ metadata: testMetadata,
172
+ tableName: "task",
173
+ });
138
174
 
139
175
  const titleCol = column("title");
140
176
  expect(titleCol.kind).toBe("field");
@@ -144,7 +180,10 @@ describe("inferColumns()", () => {
144
180
  });
145
181
 
146
182
  it("auto-detects enum options", () => {
147
- const { column } = inferColumns(testMetadata, "task");
183
+ const { column } = inferColumnHelper({
184
+ metadata: testMetadata,
185
+ tableName: "task",
186
+ });
148
187
  const statusCol = column("status");
149
188
  expect(statusCol.filter).toEqual({
150
189
  type: "enum",
@@ -159,42 +198,60 @@ describe("inferColumns()", () => {
159
198
  });
160
199
 
161
200
  it("auto-detects date type", () => {
162
- const { column } = inferColumns(testMetadata, "task");
201
+ const { column } = inferColumnHelper({
202
+ metadata: testMetadata,
203
+ tableName: "task",
204
+ });
163
205
  const dateCol = column("dueDate");
164
206
  expect(dateCol.sort).toEqual({ type: "date" });
165
207
  expect(dateCol.filter).toEqual({ type: "date" });
166
208
  });
167
209
 
168
210
  it("disables sort with sort: false", () => {
169
- const { column } = inferColumns(testMetadata, "task");
211
+ const { column } = inferColumnHelper({
212
+ metadata: testMetadata,
213
+ tableName: "task",
214
+ });
170
215
  const col = column("title", { sort: false });
171
216
  expect(col.sort).toBeUndefined();
172
217
  expect(col.filter).toEqual({ type: "string" });
173
218
  });
174
219
 
175
220
  it("disables filter with filter: false", () => {
176
- const { column } = inferColumns(testMetadata, "task");
221
+ const { column } = inferColumnHelper({
222
+ metadata: testMetadata,
223
+ tableName: "task",
224
+ });
177
225
  const col = column("title", { filter: false });
178
226
  expect(col.sort).toEqual({ type: "string" });
179
227
  expect(col.filter).toBeUndefined();
180
228
  });
181
229
 
182
230
  it("uuid has no sort, has uuid filter", () => {
183
- const { column } = inferColumns(testMetadata, "task");
231
+ const { column } = inferColumnHelper({
232
+ metadata: testMetadata,
233
+ tableName: "task",
234
+ });
184
235
  const col = column("id");
185
236
  expect(col.sort).toBeUndefined();
186
237
  expect(col.filter).toEqual({ type: "uuid" });
187
238
  });
188
239
 
189
240
  it("array type has no sort/filter", () => {
190
- const { column } = inferColumns(testMetadata, "task");
241
+ const { column } = inferColumnHelper({
242
+ metadata: testMetadata,
243
+ tableName: "task",
244
+ });
191
245
  const col = column("tags");
192
246
  expect(col.sort).toBeUndefined();
193
247
  expect(col.filter).toBeUndefined();
194
248
  });
195
249
 
196
250
  it("columns() creates multiple columns at once", () => {
197
- const { columns } = inferColumns(testMetadata, "task");
251
+ const { columns } = inferColumnHelper({
252
+ metadata: testMetadata,
253
+ tableName: "task",
254
+ });
198
255
  const cols = columns(["title", "status", "dueDate"]);
199
256
  expect(cols).toHaveLength(3);
200
257
  expect(cols[0].dataKey).toBe("title");
@@ -203,7 +260,10 @@ describe("inferColumns()", () => {
203
260
  });
204
261
 
205
262
  it("columns() applies overrides", () => {
206
- const { columns } = inferColumns(testMetadata, "task");
263
+ const { columns } = inferColumnHelper({
264
+ metadata: testMetadata,
265
+ tableName: "task",
266
+ });
207
267
  const cols = columns(["title", "status"], {
208
268
  overrides: {
209
269
  title: { label: "Custom Title", width: 300 },
@@ -214,7 +274,10 @@ describe("inferColumns()", () => {
214
274
  });
215
275
 
216
276
  it("columns() applies global sort/filter options", () => {
217
- const { columns } = inferColumns(testMetadata, "task");
277
+ const { columns } = inferColumnHelper({
278
+ metadata: testMetadata,
279
+ tableName: "task",
280
+ });
218
281
  const cols = columns(["title", "status"], { sort: false });
219
282
  expect(cols[0].sort).toBeUndefined();
220
283
  expect(cols[1].sort).toBeUndefined();
@@ -223,7 +286,10 @@ describe("inferColumns()", () => {
223
286
  });
224
287
 
225
288
  it("throws for non-existent field", () => {
226
- const { column } = inferColumns(testMetadata, "task");
289
+ const { column } = inferColumnHelper({
290
+ metadata: testMetadata,
291
+ tableName: "task",
292
+ });
227
293
  // @ts-expect-error - intentionally testing invalid field name
228
294
  expect(() => column("nonExistent")).toThrow(
229
295
  'Field "nonExistent" not found in table "task" metadata',
@@ -83,7 +83,45 @@ export function display<TRow extends Record<string, unknown>>(
83
83
  }
84
84
 
85
85
  // =============================================================================
86
- // inferColumns() helper
86
+ // createColumnHelper() factory
87
+ // =============================================================================
88
+
89
+ /**
90
+ * Create `field` and `display` helpers with TRow bound once.
91
+ *
92
+ * This avoids repeating the row type parameter on every `field()` / `display()` call.
93
+ *
94
+ * @example
95
+ * ```tsx
96
+ * type Order = { id: string; title: string; amount: number };
97
+ *
98
+ * const { field, display } = createColumnHelper<Order>();
99
+ *
100
+ * const columns = [
101
+ * field("title", { label: "Title", sort: { type: "string" } }),
102
+ * field("amount", { label: "Amount", sort: { type: "number" } }),
103
+ * display("actions", { render: (row) => <ActionMenu row={row} /> }),
104
+ * ];
105
+ * ```
106
+ */
107
+ export function createColumnHelper<TRow extends Record<string, unknown>>(): {
108
+ field: (
109
+ dataKey: keyof TRow & string,
110
+ options?: FieldColumnOptions<TRow>,
111
+ ) => FieldColumn<TRow>;
112
+ display: (
113
+ id: string,
114
+ options: DisplayColumnOptions<TRow>,
115
+ ) => DisplayColumn<TRow>;
116
+ } {
117
+ return {
118
+ field: (dataKey, options) => field<TRow>(dataKey, options),
119
+ display: (id, options) => display<TRow>(id, options),
120
+ };
121
+ }
122
+
123
+ // =============================================================================
124
+ // inferColumnHelper() helper
87
125
  // =============================================================================
88
126
 
89
127
  /**
@@ -92,14 +130,16 @@ export function display<TRow extends Record<string, unknown>>(
92
130
  * Automatically infers sort/filter configuration from field types,
93
131
  * including enum options.
94
132
  *
95
- * @param metadata - The generated `tableMetadata` map (with `as const`).
96
- * @param tableName - Key of the table in the metadata map.
133
+ * @param options - Object containing `metadata` (the generated map) and `tableName`.
97
134
  *
98
135
  * @example
99
136
  * ```tsx
100
137
  * import { tableMetadata } from "./generated/data-viewer-metadata.generated";
101
138
  *
102
- * const { column, columns } = inferColumns(tableMetadata, "task");
139
+ * const { column, columns } = inferColumnHelper({
140
+ * metadata: tableMetadata,
141
+ * tableName: "task",
142
+ * });
103
143
  *
104
144
  * const taskColumns = [
105
145
  * column("title"), // sort/filter auto-detected
@@ -109,13 +149,13 @@ export function display<TRow extends Record<string, unknown>>(
109
149
  * ];
110
150
  * ```
111
151
  */
112
- export function inferColumns<
152
+ export function inferColumnHelper<
113
153
  const TMetadata extends TableMetadataMap,
114
154
  TTableName extends string & keyof TMetadata,
115
- >(
116
- metadata: TMetadata,
117
- tableName: TTableName,
118
- ): {
155
+ >(options: {
156
+ metadata: TMetadata;
157
+ tableName: TTableName;
158
+ }): {
119
159
  column: (
120
160
  dataKey: FieldName<TMetadata, TTableName>,
121
161
  options?: MetadataFieldOptions,
@@ -126,12 +166,13 @@ export function inferColumns<
126
166
  options?: MetadataFieldsOptions,
127
167
  ) => FieldColumn<Record<string, unknown>>[];
128
168
  } {
129
- const tableMetadata = metadata[tableName];
130
- const fields = tableMetadata.fields;
169
+ const { metadata, tableName } = options;
170
+ const tableMeta = metadata[tableName];
171
+ const fields = tableMeta.fields;
131
172
 
132
173
  const column = (
133
174
  dataKey: FieldName<TMetadata, TTableName>,
134
- options?: MetadataFieldOptions,
175
+ columnOptions?: MetadataFieldOptions,
135
176
  ): FieldColumn<Record<string, unknown>> => {
136
177
  const fieldMeta = fields.find((f) => f.name === dataKey);
137
178
  if (!fieldMeta) {
@@ -142,30 +183,30 @@ export function inferColumns<
142
183
 
143
184
  // Auto-detect sort config
144
185
  let sort: SortConfig | undefined;
145
- if (options?.sort !== false) {
186
+ if (columnOptions?.sort !== false) {
146
187
  sort = fieldTypeToSortConfig(fieldMeta.type);
147
188
  }
148
- if (options?.sort === false) {
189
+ if (columnOptions?.sort === false) {
149
190
  sort = undefined;
150
191
  }
151
192
 
152
193
  // Auto-detect filter config
153
194
  let filter: FilterConfig | undefined;
154
- if (options?.filter !== false) {
195
+ if (columnOptions?.filter !== false) {
155
196
  filter = fieldTypeToFilterConfig(fieldMeta.type, fieldMeta.enumValues);
156
197
  }
157
- if (options?.filter === false) {
198
+ if (columnOptions?.filter === false) {
158
199
  filter = undefined;
159
200
  }
160
201
 
161
202
  return {
162
203
  kind: "field",
163
204
  dataKey: fieldMeta.name,
164
- label: options?.label ?? fieldMeta.description ?? fieldMeta.name,
165
- width: options?.width,
205
+ label: columnOptions?.label ?? fieldMeta.description ?? fieldMeta.name,
206
+ width: columnOptions?.width,
166
207
  sort,
167
208
  filter,
168
- renderer: options?.renderer as
209
+ renderer: columnOptions?.renderer as
169
210
  | CellRenderer<Record<string, unknown>>
170
211
  | undefined,
171
212
  };
@@ -9,6 +9,7 @@ export type {
9
9
  PageInfo,
10
10
  QueryVariables,
11
11
  CollectionResult,
12
+ NodeType,
12
13
  CellRendererProps,
13
14
  CellRenderer,
14
15
  FieldColumnOptions,
@@ -59,7 +60,7 @@ export { useDataTable } from "./data-table/use-data-table";
59
60
  export { useDataTableContext } from "./data-table/data-table-context";
60
61
 
61
62
  // Field helpers
62
- export { field, display, inferColumns } from "./field-helpers";
63
+ export { createColumnHelper, inferColumnHelper } from "./field-helpers";
63
64
 
64
65
  // Utility components
65
66
  export { Pagination } from "./pagination";