@colspec/tanstack 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Om Prakash Das
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md CHANGED
@@ -1,3 +1,70 @@
1
- # Temporary Holding Version
1
+ # @colspec/tanstack
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Turns a [colspec](https://github.com/Om1938/colspec) contract into native
4
+ TanStack Table v9 column definitions and table options. Framework-independent:
5
+ use it with any TanStack Table adapter.
6
+
7
+ ```sh
8
+ npm install @colspec/tanstack @colspec/core @tanstack/table-core
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Register the functions contracts may refer to, once:
14
+
15
+ ```ts
16
+ import { createTableRegistry } from "@colspec/tanstack";
17
+
18
+ const registry = createTableRegistry<Product>({
19
+ accessorFns: { "inventory.brandModel": (row) => `${row.brand} ${row.model}` },
20
+ cells: { "inventory.statusBadge": ({ getValue }) => renderBadge(getValue()) },
21
+ formatters: {
22
+ "inventory.date": (value: string) => new Date(value).toLocaleDateString(),
23
+ },
24
+ });
25
+ ```
26
+
27
+ Then hydrate a validated contract:
28
+
29
+ ```ts
30
+ import { hydrateContract } from "@colspec/tanstack";
31
+
32
+ const result = hydrateContract<typeof features, Product>(contract, registry);
33
+
34
+ if (result.ok) {
35
+ const { columns, options } = result.value;
36
+ // columns: ColumnDef[]
37
+ // options: { initialState, manualSorting, manualFiltering, manualPagination }
38
+ }
39
+ ```
40
+
41
+ ## How names resolve
42
+
43
+ | In the contract | Resolves to |
44
+ | -------------------------------------------- | ----------------------------------------- |
45
+ | `"sortFn": "alphanumeric"` | TanStack's built-in function of that name |
46
+ | `"sortFn": "auto"` | Passed through; TanStack chooses |
47
+ | `"cell": { "ref": "inventory.statusBadge" }` | Your registered function |
48
+ | `"header": "Name"` | Literal text |
49
+
50
+ A name that can't be found produces a `missing-reference` or `unknown-builtin`
51
+ diagnostic. colspec never substitutes a different function, and never executes
52
+ anything stored in a contract.
53
+
54
+ Results are memoized by contract and registry identity, so `columns` stays
55
+ stable between renders as long as you keep the same contract object.
56
+
57
+ ## Registry categories
58
+
59
+ `sortFns`, `filterFns`, `aggregationFns`, `accessorFns`, `cells`, `headers`
60
+ (also used for footers), `formatters`, `actions`.
61
+
62
+ ## Features
63
+
64
+ `defaultFeatures` is a ready-made TanStack feature set covering sorting,
65
+ filtering, pagination, visibility and sizing. Pass your own `tableFeatures()`
66
+ to add grouping or pinning, or to ship less.
67
+
68
+ Requires `@tanstack/table-core` 9.
69
+
70
+ [Documentation](https://github.com/Om1938/colspec/tree/main/apps/docs/guide) · MIT
@@ -0,0 +1,87 @@
1
+ import { AccessorFn, AggregationFnDef, CellContext, ColumnDef, FilterFn, HeaderContext, RowData, SortFn, TableFeatures } from "@tanstack/table-core";
2
+ import { ContractDefaults, Registry, RegistryInput, Result, TableContract } from "@colspec/core";
3
+ //#region src/features.d.ts
4
+ /**
5
+ * A ready-made feature set covering everything a contract can configure.
6
+ * Pass your own `tableFeatures(...)` instead to ship only what a table uses.
7
+ */
8
+ export declare const defaultFeatures: {
9
+ rowSortingFeature: import("@tanstack/table-core").TableFeature;
10
+ columnFilteringFeature: import("@tanstack/table-core").TableFeature;
11
+ rowPaginationFeature: import("@tanstack/table-core").TableFeature;
12
+ columnVisibilityFeature: import("@tanstack/table-core").TableFeature;
13
+ columnSizingFeature: import("@tanstack/table-core").TableFeature;
14
+ sortedRowModel: (table: import("@tanstack/table-core").Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
15
+ filteredRowModel: (table: import("@tanstack/table-core").Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
16
+ paginatedRowModel: (table: import("@tanstack/table-core").Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
17
+ sortFns: {
18
+ alphanumeric: import("@tanstack/table-core").CreatedSortFn<any, any>;
19
+ alphanumericCaseSensitive: import("@tanstack/table-core").CreatedSortFn<any, any>;
20
+ basic: import("@tanstack/table-core").CreatedSortFn<any, any>;
21
+ datetime: import("@tanstack/table-core").CreatedSortFn<any, any>;
22
+ text: import("@tanstack/table-core").CreatedSortFn<any, any>;
23
+ textCaseSensitive: import("@tanstack/table-core").CreatedSortFn<any, any>;
24
+ };
25
+ filterFns: {
26
+ arrIncludes: import("@tanstack/table-core").CreatedFilterFn<any, any>;
27
+ arrIncludesAll: import("@tanstack/table-core").CreatedFilterFn<any, any>;
28
+ arrHas: import("@tanstack/table-core").CreatedFilterFn<any, any>;
29
+ arrIncludesSome: import("@tanstack/table-core").CreatedFilterFn<any, any>;
30
+ between: import("@tanstack/table-core").CreatedFilterFn<any, any>;
31
+ betweenInclusive: import("@tanstack/table-core").CreatedFilterFn<any, any>;
32
+ empty: import("@tanstack/table-core").CreatedFilterFn<any, any>;
33
+ endsWith: import("@tanstack/table-core").CreatedFilterFn<any, any>;
34
+ equals: import("@tanstack/table-core").CreatedFilterFn<any, any>;
35
+ equalsString: import("@tanstack/table-core").CreatedFilterFn<any, any>;
36
+ equalsStringSensitive: import("@tanstack/table-core").CreatedFilterFn<any, any>;
37
+ inDateRange: import("@tanstack/table-core").CreatedFilterFn<any, any>;
38
+ inNumberRange: import("@tanstack/table-core").CreatedFilterFn<any, any>;
39
+ includesString: import("@tanstack/table-core").CreatedFilterFn<any, any>;
40
+ includesStringSensitive: import("@tanstack/table-core").CreatedFilterFn<any, any>;
41
+ notEmpty: import("@tanstack/table-core").CreatedFilterFn<any, any>;
42
+ startsWith: import("@tanstack/table-core").CreatedFilterFn<any, any>;
43
+ weakEquals: import("@tanstack/table-core").CreatedFilterFn<any, any>;
44
+ };
45
+ };
46
+ export type DefaultFeatures = typeof defaultFeatures;
47
+ //#endregion
48
+ //#region src/registry.d.ts
49
+ /** The function types each registry category holds for TanStack Table. */
50
+ export interface TableRegistryEntries<TData extends RowData = any> {
51
+ sortFns: SortFn<any, TData>;
52
+ filterFns: FilterFn<any, TData>;
53
+ accessorFns: AccessorFn<TData>;
54
+ cells: (context: CellContext<any, TData, any>) => unknown;
55
+ /** Used for both `header` and `footer`. */
56
+ headers: (context: HeaderContext<any, TData, any>) => unknown;
57
+ formatters: (value: any) => unknown;
58
+ actions: (row: TData) => unknown;
59
+ aggregationFns: AggregationFnDef<any, TData, any, any>;
60
+ }
61
+ export type TableRegistry<TData extends RowData = any> = Registry<TableRegistryEntries<TData>>;
62
+ /** `createRegistry` typed for TanStack Table functions over `TData` rows. */
63
+ export declare function createTableRegistry<TData extends RowData>(input?: RegistryInput<TableRegistryEntries<TData>>): TableRegistry<TData>;
64
+ //#endregion
65
+ //#region src/table-options.d.ts
66
+ /** Table options a contract controls besides its columns. */
67
+ export interface ContractTableOptions {
68
+ initialState: ContractDefaults;
69
+ manualSorting: boolean;
70
+ manualFiltering: boolean;
71
+ manualPagination: boolean;
72
+ }
73
+ /** Maps contract defaults and execution modes onto TanStack table options. */
74
+ export declare function toTableOptions(contract: TableContract): ContractTableOptions;
75
+ //#endregion
76
+ //#region src/hydrate.d.ts
77
+ export interface HydratedContract<TFeatures extends TableFeatures, TData extends RowData> {
78
+ columns: Array<ColumnDef<TFeatures, TData>>;
79
+ options: ContractTableOptions;
80
+ }
81
+ /**
82
+ * Converts a validated contract into TanStack column definitions and table
83
+ * options. The result is memoized per registry and contract object, so the
84
+ * columns keep a stable identity between renders.
85
+ */
86
+ export declare function hydrateContract<TFeatures extends TableFeatures = any, TData extends RowData = any>(contract: TableContract, registry: TableRegistry<TData>): Result<HydratedContract<TFeatures, TData>>;
87
+ //#endregion
package/dist/index.mjs ADDED
@@ -0,0 +1,143 @@
1
+ import { aggregationFns, columnFilteringFeature, columnSizingFeature, columnVisibilityFeature, createFilteredRowModel, createPaginatedRowModel, createSortedRowModel, filterFns, rowPaginationFeature, rowSortingFeature, sortFns, tableFeatures } from "@tanstack/table-core";
2
+ import { createRegistry, getMode, isRef, toResult } from "@colspec/core";
3
+ //#region src/features.ts
4
+ /**
5
+ * A ready-made feature set covering everything a contract can configure.
6
+ * Pass your own `tableFeatures(...)` instead to ship only what a table uses.
7
+ */
8
+ const defaultFeatures = tableFeatures({
9
+ rowSortingFeature,
10
+ columnFilteringFeature,
11
+ rowPaginationFeature,
12
+ columnVisibilityFeature,
13
+ columnSizingFeature,
14
+ sortedRowModel: createSortedRowModel(),
15
+ filteredRowModel: createFilteredRowModel(),
16
+ paginatedRowModel: createPaginatedRowModel(),
17
+ sortFns,
18
+ filterFns
19
+ });
20
+ //#endregion
21
+ //#region src/hydrate-columns.ts
22
+ /** Drops unset keys so they cannot shadow TanStack's column defaults. */
23
+ function defined(values) {
24
+ return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== void 0));
25
+ }
26
+ function hydrateColumn(column, index, resolve) {
27
+ const { accessorFn, header, footer, cell, formatter, actions, sortFn, filterFn, aggregationFn, meta, server: _server, ...serializable } = column;
28
+ const at = (key, ...rest) => [
29
+ "columns",
30
+ index,
31
+ key,
32
+ ...rest
33
+ ];
34
+ const format = resolve.ref("formatters", formatter, at("formatter"));
35
+ const handlers = actions?.map((action, actionIndex) => [action.ref, resolve.ref("actions", action, at("actions", actionIndex))]);
36
+ return {
37
+ ...serializable,
38
+ ...defined({
39
+ accessorFn: resolve.ref("accessorFns", accessorFn, at("accessorFn")),
40
+ header: resolve.template("headers", header, at("header")),
41
+ footer: resolve.template("headers", footer, at("footer")),
42
+ cell: resolve.ref("cells", cell, at("cell")) ?? (format && ((context) => format(context.getValue()))),
43
+ sortFn: resolve.named("sortFns", sortFn, at("sortFn")),
44
+ filterFn: resolve.named("filterFns", filterFn, at("filterFn")),
45
+ aggregationFn: resolve.named("aggregationFns", aggregationFn, at("aggregationFn")),
46
+ meta: meta || handlers ? {
47
+ ...meta,
48
+ ...handlers && { actions: Object.fromEntries(handlers) }
49
+ } : void 0
50
+ })
51
+ };
52
+ }
53
+ /** Converts contract columns into native TanStack column definitions. */
54
+ function hydrateColumns(columns, resolve) {
55
+ return columns.map((column, index) => hydrateColumn(column, index, resolve));
56
+ }
57
+ //#endregion
58
+ //#region src/resolve.ts
59
+ /** Functions TanStack ships, addressable from a contract by plain name. */
60
+ const BUILTINS = {
61
+ sortFns,
62
+ filterFns,
63
+ aggregationFns
64
+ };
65
+ /** Lets TanStack pick a function from the column's data. */
66
+ const AUTO = "auto";
67
+ /**
68
+ * Looks names up in the registry or TanStack's built-ins. A name that cannot
69
+ * be found is reported and never replaced with another function.
70
+ */
71
+ function createResolver(registry, diagnostics) {
72
+ function lookup(source, category, name, path, code) {
73
+ if (Object.hasOwn(source, name)) return source[name];
74
+ diagnostics.push({
75
+ code,
76
+ severity: "error",
77
+ path,
78
+ message: `"${name}" was not found in ${category}.`
79
+ });
80
+ }
81
+ /** Resolves a reference to an application-registered function. */
82
+ function ref(category, value, path) {
83
+ return value && lookup(registry[category], category, value.ref, path, "missing-reference");
84
+ }
85
+ /** Resolves a built-in name, `"auto"`, or a reference. */
86
+ function named(category, value, path) {
87
+ if (value === void 0 || value === AUTO) return value;
88
+ if (isRef(value)) return ref(category, value, path);
89
+ return lookup(BUILTINS[category] ?? {}, category, value, path, "unknown-builtin");
90
+ }
91
+ /** Resolves a renderer reference, passing literal text through. */
92
+ function template(category, value, path) {
93
+ return typeof value === "string" ? value : ref(category, value, path);
94
+ }
95
+ return {
96
+ ref,
97
+ named,
98
+ template
99
+ };
100
+ }
101
+ //#endregion
102
+ //#region src/table-options.ts
103
+ /** Maps contract defaults and execution modes onto TanStack table options. */
104
+ function toTableOptions(contract) {
105
+ const mode = getMode(contract);
106
+ return {
107
+ initialState: contract.defaults ?? {},
108
+ manualSorting: mode.sorting === "server",
109
+ manualFiltering: mode.filtering === "server",
110
+ manualPagination: mode.pagination === "server"
111
+ };
112
+ }
113
+ //#endregion
114
+ //#region src/hydrate.ts
115
+ const cache = /* @__PURE__ */ new WeakMap();
116
+ /**
117
+ * Converts a validated contract into TanStack column definitions and table
118
+ * options. The result is memoized per registry and contract object, so the
119
+ * columns keep a stable identity between renders.
120
+ */
121
+ function hydrateContract(contract, registry) {
122
+ let byContract = cache.get(registry);
123
+ if (!byContract) cache.set(registry, byContract = /* @__PURE__ */ new WeakMap());
124
+ let result = byContract.get(contract);
125
+ if (!result) {
126
+ const diagnostics = [];
127
+ const columns = hydrateColumns(contract.columns, createResolver(registry, diagnostics));
128
+ result = toResult({
129
+ columns,
130
+ options: toTableOptions(contract)
131
+ }, diagnostics);
132
+ byContract.set(contract, result);
133
+ }
134
+ return result;
135
+ }
136
+ //#endregion
137
+ //#region src/registry.ts
138
+ /** `createRegistry` typed for TanStack Table functions over `TData` rows. */
139
+ function createTableRegistry(input = {}) {
140
+ return createRegistry(input);
141
+ }
142
+ //#endregion
143
+ export { createTableRegistry, defaultFeatures, hydrateContract, toTableOptions };
package/package.json CHANGED
@@ -1,6 +1,54 @@
1
1
  {
2
2
  "name": "@colspec/tanstack",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.1",
4
+ "peerDependencies": {
5
+ "@tanstack/table-core": "^9.2.6"
6
+ },
7
+ "dependencies": {
8
+ "@colspec/core": "0.1.1"
9
+ },
10
+ "devDependencies": {
11
+ "@repo/eslint-config": "0.0.0",
12
+ "@repo/typescript-config": "0.0.0",
13
+ "@tanstack/table-core": "^9.2.6"
14
+ },
15
+ "type": "module",
16
+ "license": "MIT",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "sideEffects": false,
24
+ "exports": {
25
+ ".": "./dist/index.mjs",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "description": "Hydrate colspec JSON contracts into native TanStack Table v9 column definitions and table options.",
29
+ "author": "Om Prakash Das",
30
+ "homepage": "https://github.com/Om1938/colspec/tree/main/packages/tanstack#readme",
31
+ "bugs": {
32
+ "url": "https://github.com/Om1938/colspec/issues"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/Om1938/colspec.git",
37
+ "directory": "packages/tanstack"
38
+ },
39
+ "keywords": [
40
+ "tanstack-table",
41
+ "tanstack",
42
+ "table",
43
+ "datagrid",
44
+ "dynamic-columns",
45
+ "colspec",
46
+ "column-def hydration"
47
+ ],
48
+ "scripts": {
49
+ "lint": "eslint . --max-warnings 0",
50
+ "build": "tsdown",
51
+ "test": "vitest run",
52
+ "check-types": "tsc --noEmit"
53
+ }
6
54
  }