@tanstack/preact-table 0.0.1 → 9.0.0-alpha.14

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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Tanner Linsley
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.
@@ -0,0 +1,46 @@
1
+ import { Cell, CellData, Header, RowData, TableFeatures } from '@tanstack/table-core';
2
+ import { ComponentChild, ComponentType } from 'preact';
3
+ export type Renderable<TProps> = ComponentChild | ComponentType<TProps>;
4
+ /**
5
+ * If rendering headers, cells, or footers with custom markup, use flexRender instead of `cell.getValue()` or `cell.renderValue()`.
6
+ * @example flexRender(cell.column.columnDef.cell, cell.getContext())
7
+ */
8
+ export declare function flexRender<TProps extends object>(Comp: Renderable<TProps> | null, props: TProps): ComponentChild | Element | null;
9
+ /**
10
+ * Simplified component wrapper of `flexRender`. Use this utility component to render headers, cells, or footers with custom markup.
11
+ * Only one prop (`cell`, `header`, or `footer`) may be passed.
12
+ * @example <FlexRender cell={cell} />
13
+ * @example <FlexRender header={header} />
14
+ * @example <FlexRender footer={footer} />
15
+ */
16
+ export type FlexRenderProps<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData = CellData> = {
17
+ cell: Cell<TFeatures, TData, TValue>;
18
+ header?: never;
19
+ footer?: never;
20
+ } | {
21
+ header: Header<TFeatures, TData, TValue>;
22
+ cell?: never;
23
+ footer?: never;
24
+ } | {
25
+ footer: Header<TFeatures, TData, TValue>;
26
+ cell?: never;
27
+ header?: never;
28
+ };
29
+ /**
30
+ * Simplified component wrapper of `flexRender`. Use this utility component to render headers, cells, or footers with custom markup.
31
+ * Only one prop (`cell`, `header`, or `footer`) may be passed.
32
+ * @example
33
+ * ```tsx
34
+ * <FlexRender cell={cell} />
35
+ * <FlexRender header={header} />
36
+ * <FlexRender footer={footer} />
37
+ * ```
38
+ *
39
+ * This replaces calling `flexRender` directly like this:
40
+ * ```tsx
41
+ * flexRender(cell.column.columnDef.cell, cell.getContext())
42
+ * flexRender(header.column.columnDef.header, header.getContext())
43
+ * flexRender(footer.column.columnDef.footer, footer.getContext())
44
+ * ```
45
+ */
46
+ export declare function FlexRender<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData = CellData>(props: FlexRenderProps<TFeatures, TData, TValue>): ComponentChild;
@@ -0,0 +1,41 @@
1
+ import { jsx } from "preact/jsx-runtime";
2
+ function isPreactComponent(component) {
3
+ return isClassComponent(component) || typeof component === "function" || isExoticComponent(component);
4
+ }
5
+ function isClassComponent(component) {
6
+ return typeof component === "function" && (() => {
7
+ const proto = Object.getPrototypeOf(component);
8
+ return proto.prototype && proto.prototype.isPreactComponent;
9
+ })();
10
+ }
11
+ function isExoticComponent(component) {
12
+ return typeof component === "object" && typeof component.$$typeof === "symbol" && ["preact.memo", "preact.forward_ref"].includes(
13
+ component.$$typeof.description
14
+ );
15
+ }
16
+ function flexRender(Comp, props) {
17
+ return !Comp ? null : isPreactComponent(Comp) ? /* @__PURE__ */ jsx(Comp, { ...props }) : Comp;
18
+ }
19
+ function FlexRender(props) {
20
+ if ("cell" in props && props.cell) {
21
+ return flexRender(props.cell.column.columnDef.cell, props.cell.getContext());
22
+ }
23
+ if ("header" in props && props.header) {
24
+ return flexRender(
25
+ props.header.column.columnDef.header,
26
+ props.header.getContext()
27
+ );
28
+ }
29
+ if ("footer" in props && props.footer) {
30
+ return flexRender(
31
+ props.footer.column.columnDef.footer,
32
+ props.footer.getContext()
33
+ );
34
+ }
35
+ return null;
36
+ }
37
+ export {
38
+ FlexRender,
39
+ flexRender
40
+ };
41
+ //# sourceMappingURL=FlexRender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlexRender.js","sources":["../../src/FlexRender.tsx"],"sourcesContent":["import type {\n Cell,\n CellData,\n Header,\n RowData,\n TableFeatures,\n} from '@tanstack/table-core'\nimport type { ComponentChild, ComponentType } from 'preact'\n\nexport type Renderable<TProps> = ComponentChild | ComponentType<TProps>\n\nfunction isPreactComponent<TProps>(\n component: unknown,\n): component is ComponentType<TProps> {\n return (\n isClassComponent(component) ||\n typeof component === 'function' ||\n isExoticComponent(component)\n )\n}\n\nfunction isClassComponent(component: any) {\n return (\n typeof component === 'function' &&\n (() => {\n const proto = Object.getPrototypeOf(component)\n return proto.prototype && proto.prototype.isPreactComponent\n })()\n )\n}\n\nfunction isExoticComponent(component: any) {\n return (\n typeof component === 'object' &&\n typeof component.$$typeof === 'symbol' &&\n ['preact.memo', 'preact.forward_ref'].includes(\n component.$$typeof.description,\n )\n )\n}\n\n/**\n * If rendering headers, cells, or footers with custom markup, use flexRender instead of `cell.getValue()` or `cell.renderValue()`.\n * @example flexRender(cell.column.columnDef.cell, cell.getContext())\n */\nexport function flexRender<TProps extends object>(\n Comp: Renderable<TProps> | null,\n props: TProps,\n): ComponentChild | Element | null {\n return !Comp ? null : isPreactComponent<TProps>(Comp) ? (\n <Comp {...props} />\n ) : (\n Comp\n )\n}\n\n/**\n * Simplified component wrapper of `flexRender`. Use this utility component to render headers, cells, or footers with custom markup.\n * Only one prop (`cell`, `header`, or `footer`) may be passed.\n * @example <FlexRender cell={cell} />\n * @example <FlexRender header={header} />\n * @example <FlexRender footer={footer} />\n */\nexport type FlexRenderProps<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n> =\n | { cell: Cell<TFeatures, TData, TValue>; header?: never; footer?: never }\n | {\n header: Header<TFeatures, TData, TValue>\n cell?: never\n footer?: never\n }\n | {\n footer: Header<TFeatures, TData, TValue>\n cell?: never\n header?: never\n }\n\n/**\n * Simplified component wrapper of `flexRender`. Use this utility component to render headers, cells, or footers with custom markup.\n * Only one prop (`cell`, `header`, or `footer`) may be passed.\n * @example\n * ```tsx\n * <FlexRender cell={cell} />\n * <FlexRender header={header} />\n * <FlexRender footer={footer} />\n * ```\n *\n * This replaces calling `flexRender` directly like this:\n * ```tsx\n * flexRender(cell.column.columnDef.cell, cell.getContext())\n * flexRender(header.column.columnDef.header, header.getContext())\n * flexRender(footer.column.columnDef.footer, footer.getContext())\n * ```\n */\nexport function FlexRender<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TValue extends CellData = CellData,\n>(props: FlexRenderProps<TFeatures, TData, TValue>) {\n if ('cell' in props && props.cell) {\n return flexRender(props.cell.column.columnDef.cell, props.cell.getContext())\n }\n if ('header' in props && props.header) {\n return flexRender(\n props.header.column.columnDef.header,\n props.header.getContext(),\n )\n }\n if ('footer' in props && props.footer) {\n return flexRender(\n props.footer.column.columnDef.footer,\n props.footer.getContext(),\n )\n }\n return null\n}\n"],"names":[],"mappings":";AAWA,SAAS,kBACP,WACoC;AACpC,SACE,iBAAiB,SAAS,KAC1B,OAAO,cAAc,cACrB,kBAAkB,SAAS;AAE/B;AAEA,SAAS,iBAAiB,WAAgB;AACxC,SACE,OAAO,cAAc,eACpB,MAAM;AACL,UAAM,QAAQ,OAAO,eAAe,SAAS;AAC7C,WAAO,MAAM,aAAa,MAAM,UAAU;AAAA,EAC5C,GAAA;AAEJ;AAEA,SAAS,kBAAkB,WAAgB;AACzC,SACE,OAAO,cAAc,YACrB,OAAO,UAAU,aAAa,YAC9B,CAAC,eAAe,oBAAoB,EAAE;AAAA,IACpC,UAAU,SAAS;AAAA,EAAA;AAGzB;AAMO,SAAS,WACd,MACA,OACiC;AACjC,SAAO,CAAC,OAAO,OAAO,kBAA0B,IAAI,IAClD,oBAAC,MAAA,EAAM,GAAG,MAAA,CAAO,IAEjB;AAEJ;AA2CO,SAAS,WAId,OAAkD;AAClD,MAAI,UAAU,SAAS,MAAM,MAAM;AACjC,WAAO,WAAW,MAAM,KAAK,OAAO,UAAU,MAAM,MAAM,KAAK,YAAY;AAAA,EAC7E;AACA,MAAI,YAAY,SAAS,MAAM,QAAQ;AACrC,WAAO;AAAA,MACL,MAAM,OAAO,OAAO,UAAU;AAAA,MAC9B,MAAM,OAAO,WAAA;AAAA,IAAW;AAAA,EAE5B;AACA,MAAI,YAAY,SAAS,MAAM,QAAQ;AACrC,WAAO;AAAA,MACL,MAAM,OAAO,OAAO,UAAU;AAAA,MAC9B,MAAM,OAAO,WAAA;AAAA,IAAW;AAAA,EAE5B;AACA,SAAO;AACT;"}
@@ -0,0 +1,44 @@
1
+ import { NoInfer, RowData, Table, TableFeatures, TableState } from '@tanstack/table-core';
2
+ import { ComponentChildren } from 'preact';
3
+ export type SubscribeProps<TFeatures extends TableFeatures, TData extends RowData, TSelected = {}> = {
4
+ /**
5
+ * The table instance to subscribe to. Required when using as a standalone component.
6
+ * Not needed when using as `table.Subscribe`.
7
+ */
8
+ table: Table<TFeatures, TData>;
9
+ /**
10
+ * A selector function that selects the part of the table state to subscribe to.
11
+ * This allows for fine-grained reactivity by only re-rendering when the selected state changes.
12
+ */
13
+ selector: (state: NoInfer<TableState<TFeatures>>) => TSelected;
14
+ /**
15
+ * The children to render. Can be a function that receives the selected state, or a Preact node.
16
+ */
17
+ children: ((state: TSelected) => ComponentChildren) | ComponentChildren;
18
+ };
19
+ /**
20
+ * A Preact component that allows you to subscribe to the table state.
21
+ *
22
+ * This is useful for opting into state re-renders for specific parts of the table state.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * // As a standalone component
27
+ * <Subscribe table={table} selector={(state) => ({ rowSelection: state.rowSelection })}>
28
+ * {({ rowSelection }) => (
29
+ * <div>Selected rows: {Object.keys(rowSelection).length}</div>
30
+ * )}
31
+ * </Subscribe>
32
+ * ```
33
+ *
34
+ * @example
35
+ * ```tsx
36
+ * // As table.Subscribe (table instance method)
37
+ * <table.Subscribe selector={(state) => ({ rowSelection: state.rowSelection })}>
38
+ * {({ rowSelection }) => (
39
+ * <div>Selected rows: {Object.keys(rowSelection).length}</div>
40
+ * )}
41
+ * </table.Subscribe>
42
+ * ```
43
+ */
44
+ export declare function Subscribe<TFeatures extends TableFeatures, TData extends RowData, TSelected = {}>(props: SubscribeProps<TFeatures, TData, TSelected>): ComponentChildren;
@@ -0,0 +1,9 @@
1
+ import { useStore } from "@tanstack/preact-store";
2
+ function Subscribe(props) {
3
+ const selected = useStore(props.table.store, props.selector);
4
+ return typeof props.children === "function" ? props.children(selected) : props.children;
5
+ }
6
+ export {
7
+ Subscribe
8
+ };
9
+ //# sourceMappingURL=Subscribe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Subscribe.js","sources":["../../src/Subscribe.ts"],"sourcesContent":["import { useStore } from '@tanstack/preact-store'\nimport type {\n NoInfer,\n RowData,\n Table,\n TableFeatures,\n TableState,\n} from '@tanstack/table-core'\nimport type { ComponentChildren } from 'preact'\n\nexport type SubscribeProps<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TSelected = {},\n> = {\n /**\n * The table instance to subscribe to. Required when using as a standalone component.\n * Not needed when using as `table.Subscribe`.\n */\n table: Table<TFeatures, TData>\n /**\n * A selector function that selects the part of the table state to subscribe to.\n * This allows for fine-grained reactivity by only re-rendering when the selected state changes.\n */\n selector: (state: NoInfer<TableState<TFeatures>>) => TSelected\n /**\n * The children to render. Can be a function that receives the selected state, or a Preact node.\n */\n children: ((state: TSelected) => ComponentChildren) | ComponentChildren\n}\n\n/**\n * A Preact component that allows you to subscribe to the table state.\n *\n * This is useful for opting into state re-renders for specific parts of the table state.\n *\n * @example\n * ```tsx\n * // As a standalone component\n * <Subscribe table={table} selector={(state) => ({ rowSelection: state.rowSelection })}>\n * {({ rowSelection }) => (\n * <div>Selected rows: {Object.keys(rowSelection).length}</div>\n * )}\n * </Subscribe>\n * ```\n *\n * @example\n * ```tsx\n * // As table.Subscribe (table instance method)\n * <table.Subscribe selector={(state) => ({ rowSelection: state.rowSelection })}>\n * {({ rowSelection }) => (\n * <div>Selected rows: {Object.keys(rowSelection).length}</div>\n * )}\n * </table.Subscribe>\n * ```\n */\nexport function Subscribe<\n TFeatures extends TableFeatures,\n TData extends RowData,\n TSelected = {},\n>(props: SubscribeProps<TFeatures, TData, TSelected>): ComponentChildren {\n const selected = useStore(props.table.store, props.selector)\n\n return typeof props.children === 'function'\n ? props.children(selected)\n : props.children\n}\n"],"names":[],"mappings":";AAwDO,SAAS,UAId,OAAuE;AACvE,QAAM,WAAW,SAAS,MAAM,MAAM,OAAO,MAAM,QAAQ;AAE3D,SAAO,OAAO,MAAM,aAAa,aAC7B,MAAM,SAAS,QAAQ,IACvB,MAAM;AACZ;"}
@@ -0,0 +1,349 @@
1
+ import { AccessorFn, AccessorFnColumnDef, AccessorKeyColumnDef, Cell, CellContext, CellData, Column, ColumnDef, DeepKeys, DeepValue, DisplayColumnDef, GroupColumnDef, Header, IdentifiedColumnDef, NoInfer, Row, RowData, Table, TableFeatures, TableOptions, TableState } from '@tanstack/table-core';
2
+ import { ComponentChildren, ComponentType } from 'preact';
3
+ import { PreactTable } from './useTable.js';
4
+ /**
5
+ * Enhanced CellContext with pre-bound cell components.
6
+ * The `cell` property includes the registered cellComponents.
7
+ */
8
+ export type AppCellContext<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData, TCellComponents extends Record<string, ComponentType<any>>> = {
9
+ cell: Cell<TFeatures, TData, TValue> & TCellComponents & {
10
+ FlexRender: () => ComponentChildren;
11
+ };
12
+ column: Column<TFeatures, TData, TValue>;
13
+ getValue: CellContext<TFeatures, TData, TValue>['getValue'];
14
+ renderValue: CellContext<TFeatures, TData, TValue>['renderValue'];
15
+ row: Row<TFeatures, TData>;
16
+ table: Table<TFeatures, TData>;
17
+ };
18
+ /**
19
+ * Enhanced HeaderContext with pre-bound header components.
20
+ * The `header` property includes the registered headerComponents.
21
+ */
22
+ export type AppHeaderContext<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData, THeaderComponents extends Record<string, ComponentType<any>>> = {
23
+ column: Column<TFeatures, TData, TValue>;
24
+ header: Header<TFeatures, TData, TValue> & THeaderComponents & {
25
+ FlexRender: () => ComponentChildren;
26
+ };
27
+ table: Table<TFeatures, TData>;
28
+ };
29
+ /**
30
+ * Template type for column definitions that can be a string or a function.
31
+ */
32
+ type AppColumnDefTemplate<TProps extends object> = string | ((props: TProps) => any);
33
+ /**
34
+ * Enhanced column definition base with pre-bound components in cell/header/footer contexts.
35
+ */
36
+ type AppColumnDefBase<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData, TCellComponents extends Record<string, ComponentType<any>>, THeaderComponents extends Record<string, ComponentType<any>>> = Omit<IdentifiedColumnDef<TFeatures, TData, TValue>, 'cell' | 'header' | 'footer'> & {
37
+ cell?: AppColumnDefTemplate<AppCellContext<TFeatures, TData, TValue, TCellComponents>>;
38
+ header?: AppColumnDefTemplate<AppHeaderContext<TFeatures, TData, TValue, THeaderComponents>>;
39
+ footer?: AppColumnDefTemplate<AppHeaderContext<TFeatures, TData, TValue, THeaderComponents>>;
40
+ };
41
+ /**
42
+ * Enhanced display column definition with pre-bound components.
43
+ */
44
+ type AppDisplayColumnDef<TFeatures extends TableFeatures, TData extends RowData, TCellComponents extends Record<string, ComponentType<any>>, THeaderComponents extends Record<string, ComponentType<any>>> = Omit<DisplayColumnDef<TFeatures, TData, unknown>, 'cell' | 'header' | 'footer'> & {
45
+ cell?: AppColumnDefTemplate<AppCellContext<TFeatures, TData, unknown, TCellComponents>>;
46
+ header?: AppColumnDefTemplate<AppHeaderContext<TFeatures, TData, unknown, THeaderComponents>>;
47
+ footer?: AppColumnDefTemplate<AppHeaderContext<TFeatures, TData, unknown, THeaderComponents>>;
48
+ };
49
+ /**
50
+ * Enhanced group column definition with pre-bound components.
51
+ */
52
+ type AppGroupColumnDef<TFeatures extends TableFeatures, TData extends RowData, TCellComponents extends Record<string, ComponentType<any>>, THeaderComponents extends Record<string, ComponentType<any>>> = Omit<GroupColumnDef<TFeatures, TData, unknown>, 'cell' | 'header' | 'footer' | 'columns'> & {
53
+ cell?: AppColumnDefTemplate<AppCellContext<TFeatures, TData, unknown, TCellComponents>>;
54
+ header?: AppColumnDefTemplate<AppHeaderContext<TFeatures, TData, unknown, THeaderComponents>>;
55
+ footer?: AppColumnDefTemplate<AppHeaderContext<TFeatures, TData, unknown, THeaderComponents>>;
56
+ columns?: Array<ColumnDef<TFeatures, TData, unknown>>;
57
+ };
58
+ /**
59
+ * Enhanced column helper with pre-bound components in cell/header/footer contexts.
60
+ * This enables TypeScript to know about the registered components when defining columns.
61
+ */
62
+ export type AppColumnHelper<TFeatures extends TableFeatures, TData extends RowData, TCellComponents extends Record<string, ComponentType<any>>, THeaderComponents extends Record<string, ComponentType<any>>> = {
63
+ /**
64
+ * Creates a data column definition with an accessor key or function.
65
+ * The cell, header, and footer contexts include pre-bound components.
66
+ */
67
+ accessor: <TAccessor extends AccessorFn<TData> | DeepKeys<TData>, TValue extends TAccessor extends AccessorFn<TData, infer TReturn> ? TReturn : TAccessor extends DeepKeys<TData> ? DeepValue<TData, TAccessor> : never>(accessor: TAccessor, column: TAccessor extends AccessorFn<TData> ? AppColumnDefBase<TFeatures, TData, TValue, TCellComponents, THeaderComponents> & {
68
+ id: string;
69
+ } : AppColumnDefBase<TFeatures, TData, TValue, TCellComponents, THeaderComponents>) => TAccessor extends AccessorFn<TData> ? AccessorFnColumnDef<TFeatures, TData, TValue> : AccessorKeyColumnDef<TFeatures, TData, TValue>;
70
+ /**
71
+ * Wraps an array of column definitions to preserve each column's individual TValue type.
72
+ */
73
+ columns: <TColumns extends ReadonlyArray<ColumnDef<TFeatures, TData, any>>>(columns: [...TColumns]) => Array<ColumnDef<TFeatures, TData, any>> & [...TColumns];
74
+ /**
75
+ * Creates a display column definition for non-data columns.
76
+ * The cell, header, and footer contexts include pre-bound components.
77
+ */
78
+ display: (column: AppDisplayColumnDef<TFeatures, TData, TCellComponents, THeaderComponents>) => DisplayColumnDef<TFeatures, TData, unknown>;
79
+ /**
80
+ * Creates a group column definition with nested child columns.
81
+ * The cell, header, and footer contexts include pre-bound components.
82
+ */
83
+ group: (column: AppGroupColumnDef<TFeatures, TData, TCellComponents, THeaderComponents>) => GroupColumnDef<TFeatures, TData, unknown>;
84
+ };
85
+ /**
86
+ * Options for creating a table hook with pre-bound components and default table options.
87
+ * Extends all TableOptions except 'columns' | 'data' | 'store' | 'state' | 'initialState'.
88
+ */
89
+ export type CreateTableHookOptions<TFeatures extends TableFeatures, TTableComponents extends Record<string, ComponentType<any>>, TCellComponents extends Record<string, ComponentType<any>>, THeaderComponents extends Record<string, ComponentType<any>>> = Omit<TableOptions<TFeatures, any>, 'columns' | 'data' | 'store' | 'state' | 'initialState'> & {
90
+ /**
91
+ * Table-level components that need access to the table instance.
92
+ * These are available directly on the table object returned by useAppTable.
93
+ * Use `useTableContext()` inside these components.
94
+ * @example { PaginationControls, GlobalFilter, RowCount }
95
+ */
96
+ tableComponents?: TTableComponents;
97
+ /**
98
+ * Cell-level components that need access to the cell instance.
99
+ * These are available on the cell object passed to AppCell's children.
100
+ * Use `useCellContext()` inside these components.
101
+ * @example { TextCell, NumberCell, DateCell, CurrencyCell }
102
+ */
103
+ cellComponents?: TCellComponents;
104
+ /**
105
+ * Header-level components that need access to the header instance.
106
+ * These are available on the header object passed to AppHeader/AppFooter's children.
107
+ * Use `useHeaderContext()` inside these components.
108
+ * @example { SortIndicator, ColumnFilter, ResizeHandle }
109
+ */
110
+ headerComponents?: THeaderComponents;
111
+ };
112
+ /**
113
+ * Props for AppTable component - without selector
114
+ */
115
+ export interface AppTablePropsWithoutSelector {
116
+ children: ComponentChildren;
117
+ selector?: never;
118
+ }
119
+ /**
120
+ * Props for AppTable component - with selector
121
+ */
122
+ export interface AppTablePropsWithSelector<TFeatures extends TableFeatures, TSelected> {
123
+ children: (state: TSelected) => ComponentChildren;
124
+ selector: (state: TableState<TFeatures>) => TSelected;
125
+ }
126
+ /**
127
+ * Props for AppCell component - without selector
128
+ */
129
+ export interface AppCellPropsWithoutSelector<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData, TCellComponents extends Record<string, ComponentType<any>>> {
130
+ cell: Cell<TFeatures, TData, TValue>;
131
+ children: (cell: Cell<TFeatures, TData, TValue> & TCellComponents & {
132
+ FlexRender: () => ComponentChildren;
133
+ }) => ComponentChildren;
134
+ selector?: never;
135
+ }
136
+ /**
137
+ * Props for AppCell component - with selector
138
+ */
139
+ export interface AppCellPropsWithSelector<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData, TCellComponents extends Record<string, ComponentType<any>>, TSelected> {
140
+ cell: Cell<TFeatures, TData, TValue>;
141
+ children: (cell: Cell<TFeatures, TData, TValue> & TCellComponents & {
142
+ FlexRender: () => ComponentChildren;
143
+ }, state: TSelected) => ComponentChildren;
144
+ selector: (state: TableState<TFeatures>) => TSelected;
145
+ }
146
+ /**
147
+ * Props for AppHeader/AppFooter component - without selector
148
+ */
149
+ export interface AppHeaderPropsWithoutSelector<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData, THeaderComponents extends Record<string, ComponentType<any>>> {
150
+ header: Header<TFeatures, TData, TValue>;
151
+ children: (header: Header<TFeatures, TData, TValue> & THeaderComponents & {
152
+ FlexRender: () => ComponentChildren;
153
+ }) => ComponentChildren;
154
+ selector?: never;
155
+ }
156
+ /**
157
+ * Props for AppHeader/AppFooter component - with selector
158
+ */
159
+ export interface AppHeaderPropsWithSelector<TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData, THeaderComponents extends Record<string, ComponentType<any>>, TSelected> {
160
+ header: Header<TFeatures, TData, TValue>;
161
+ children: (header: Header<TFeatures, TData, TValue> & THeaderComponents & {
162
+ FlexRender: () => ComponentChildren;
163
+ }, state: TSelected) => ComponentChildren;
164
+ selector: (state: TableState<TFeatures>) => TSelected;
165
+ }
166
+ /**
167
+ * Component type for AppCell - wraps a cell and provides cell context with optional Subscribe
168
+ */
169
+ export interface AppCellComponent<TFeatures extends TableFeatures, TData extends RowData, TCellComponents extends Record<string, ComponentType<any>>> {
170
+ <TValue extends CellData = CellData>(props: AppCellPropsWithoutSelector<TFeatures, TData, TValue, TCellComponents>): ComponentChildren;
171
+ <TValue extends CellData = CellData, TSelected = unknown>(props: AppCellPropsWithSelector<TFeatures, TData, TValue, TCellComponents, TSelected>): ComponentChildren;
172
+ }
173
+ /**
174
+ * Component type for AppHeader/AppFooter - wraps a header and provides header context with optional Subscribe
175
+ */
176
+ export interface AppHeaderComponent<TFeatures extends TableFeatures, TData extends RowData, THeaderComponents extends Record<string, ComponentType<any>>> {
177
+ <TValue extends CellData = CellData>(props: AppHeaderPropsWithoutSelector<TFeatures, TData, TValue, THeaderComponents>): ComponentChildren;
178
+ <TValue extends CellData = CellData, TSelected = unknown>(props: AppHeaderPropsWithSelector<TFeatures, TData, TValue, THeaderComponents, TSelected>): ComponentChildren;
179
+ }
180
+ /**
181
+ * Component type for AppTable - root wrapper with optional Subscribe
182
+ */
183
+ export interface AppTableComponent<TFeatures extends TableFeatures> {
184
+ (props: AppTablePropsWithoutSelector): ComponentChildren;
185
+ <TSelected>(props: AppTablePropsWithSelector<TFeatures, TSelected>): ComponentChildren;
186
+ }
187
+ /**
188
+ * Extended table API returned by useAppTable with all App wrapper components
189
+ */
190
+ export type AppPreactTable<TFeatures extends TableFeatures, TData extends RowData, TSelected, TTableComponents extends Record<string, ComponentType<any>>, TCellComponents extends Record<string, ComponentType<any>>, THeaderComponents extends Record<string, ComponentType<any>>> = PreactTable<TFeatures, TData, TSelected> & NoInfer<TTableComponents> & {
191
+ /**
192
+ * Root wrapper component that provides table context with optional Subscribe.
193
+ * @example
194
+ * ```tsx
195
+ * // Without selector - children is ComponentChildren
196
+ * <table.AppTable>
197
+ * <table>...</table>
198
+ * </table.AppTable>
199
+ *
200
+ * // With selector - children receives selected state
201
+ * <table.AppTable selector={(s) => s.pagination}>
202
+ * {(pagination) => <div>Page {pagination.pageIndex}</div>}
203
+ * </table.AppTable>
204
+ * ```
205
+ */
206
+ AppTable: AppTableComponent<TFeatures>;
207
+ /**
208
+ * Wraps a cell and provides cell context with pre-bound cellComponents.
209
+ * Optionally accepts a selector for Subscribe functionality.
210
+ * @example
211
+ * ```tsx
212
+ * // Without selector
213
+ * <table.AppCell cell={cell}>
214
+ * {(c) => <td><c.TextCell /></td>}
215
+ * </table.AppCell>
216
+ *
217
+ * // With selector - children receives cell and selected state
218
+ * <table.AppCell cell={cell} selector={(s) => s.columnFilters}>
219
+ * {(c, filters) => <td>{filters.length}</td>}
220
+ * </table.AppCell>
221
+ * ```
222
+ */
223
+ AppCell: AppCellComponent<TFeatures, TData, NoInfer<TCellComponents>>;
224
+ /**
225
+ * Wraps a header and provides header context with pre-bound headerComponents.
226
+ * Optionally accepts a selector for Subscribe functionality.
227
+ * @example
228
+ * ```tsx
229
+ * // Without selector
230
+ * <table.AppHeader header={header}>
231
+ * {(h) => <th><h.SortIndicator /></th>}
232
+ * </table.AppHeader>
233
+ *
234
+ * // With selector
235
+ * <table.AppHeader header={header} selector={(s) => s.sorting}>
236
+ * {(h, sorting) => <th>{sorting.length} sorted</th>}
237
+ * </table.AppHeader>
238
+ * ```
239
+ */
240
+ AppHeader: AppHeaderComponent<TFeatures, TData, NoInfer<THeaderComponents>>;
241
+ /**
242
+ * Wraps a footer and provides header context with pre-bound headerComponents.
243
+ * Optionally accepts a selector for Subscribe functionality.
244
+ * @example
245
+ * ```tsx
246
+ * <table.AppFooter header={footer}>
247
+ * {(f) => <td><table.FlexRender footer={footer} /></td>}
248
+ * </table.AppFooter>
249
+ * ```
250
+ */
251
+ AppFooter: AppHeaderComponent<TFeatures, TData, NoInfer<THeaderComponents>>;
252
+ };
253
+ /**
254
+ * Creates a custom table hook with pre-bound components for composition.
255
+ *
256
+ * This is the table equivalent of TanStack Form's `createFormHook`. It allows you to:
257
+ * - Define features, row models, and default options once, shared across all tables
258
+ * - Register reusable table, cell, and header components
259
+ * - Access table/cell/header instances via context in those components
260
+ * - Get a `useAppTable` hook that returns an extended table with App wrapper components
261
+ * - Get a `createAppColumnHelper` function pre-bound to your features
262
+ *
263
+ * @example
264
+ * ```tsx
265
+ * // hooks/table.ts
266
+ * export const {
267
+ * useAppTable,
268
+ * createAppColumnHelper,
269
+ * useTableContext,
270
+ * useCellContext,
271
+ * useHeaderContext,
272
+ * } = createTableHook({
273
+ * _features: tableFeatures({
274
+ * rowPaginationFeature,
275
+ * rowSortingFeature,
276
+ * columnFilteringFeature,
277
+ * }),
278
+ * _rowModels: {
279
+ * paginatedRowModel: createPaginatedRowModel(),
280
+ * sortedRowModel: createSortedRowModel(sortFns),
281
+ * filteredRowModel: createFilteredRowModel(filterFns),
282
+ * },
283
+ * tableComponents: { PaginationControls, RowCount },
284
+ * cellComponents: { TextCell, NumberCell },
285
+ * headerComponents: { SortIndicator, ColumnFilter },
286
+ * })
287
+ *
288
+ * // Create column helper with TFeatures already bound
289
+ * const columnHelper = createAppColumnHelper<Person>()
290
+ *
291
+ * // components/table-components.tsx
292
+ * function PaginationControls() {
293
+ * const table = useTableContext() // TFeatures already known!
294
+ * return <table.Subscribe selector={(s) => s.pagination}>...</table.Subscribe>
295
+ * }
296
+ *
297
+ * // features/users.tsx
298
+ * function UsersTable({ data }: { data: Person[] }) {
299
+ * const table = useAppTable({
300
+ * columns,
301
+ * data, // TData inferred from Person[]
302
+ * })
303
+ *
304
+ * return (
305
+ * <table.AppTable>
306
+ * <table>
307
+ * <thead>
308
+ * {table.getHeaderGroups().map(headerGroup => (
309
+ * <tr key={headerGroup.id}>
310
+ * {headerGroup.headers.map(h => (
311
+ * <table.AppHeader header={h} key={h.id}>
312
+ * {(header) => (
313
+ * <th>
314
+ * <table.FlexRender header={h} />
315
+ * <header.SortIndicator />
316
+ * </th>
317
+ * )}
318
+ * </table.AppHeader>
319
+ * ))}
320
+ * </tr>
321
+ * ))}
322
+ * </thead>
323
+ * <tbody>
324
+ * {table.getRowModel().rows.map(row => (
325
+ * <tr key={row.id}>
326
+ * {row.getAllCells().map(c => (
327
+ * <table.AppCell cell={c} key={c.id}>
328
+ * {(cell) => <td><cell.TextCell /></td>}
329
+ * </table.AppCell>
330
+ * ))}
331
+ * </tr>
332
+ * ))}
333
+ * </tbody>
334
+ * </table>
335
+ * <table.PaginationControls />
336
+ * </table.AppTable>
337
+ * )
338
+ * }
339
+ * ```
340
+ */
341
+ export declare function createTableHook<TFeatures extends TableFeatures, const TTableComponents extends Record<string, ComponentType<any>>, const TCellComponents extends Record<string, ComponentType<any>>, const THeaderComponents extends Record<string, ComponentType<any>>>({ tableComponents, cellComponents, headerComponents, ...defaultTableOptions }: CreateTableHookOptions<TFeatures, TTableComponents, TCellComponents, THeaderComponents>): {
342
+ appFeatures: TFeatures;
343
+ createAppColumnHelper: <TData extends RowData>() => AppColumnHelper<TFeatures, TData, TCellComponents, THeaderComponents>;
344
+ useAppTable: <TData extends RowData, TSelected = {}>(tableOptions: Omit<TableOptions<TFeatures, TData>, "_features" | "_rowModels">, selector?: (state: TableState<TFeatures>) => TSelected) => AppPreactTable<TFeatures, TData, TSelected, TTableComponents, TCellComponents, THeaderComponents>;
345
+ useTableContext: <TData extends RowData = RowData>() => PreactTable<TFeatures, TData>;
346
+ useCellContext: <TValue extends CellData = unknown>() => Cell<TFeatures, any, TValue>;
347
+ useHeaderContext: <TValue extends CellData = unknown>() => Header<TFeatures, any, TValue>;
348
+ };
349
+ export {};
@@ -0,0 +1,133 @@
1
+ "use client";
2
+ import { jsx } from "preact/jsx-runtime";
3
+ import { createContext } from "preact";
4
+ import { useContext, useMemo } from "preact/hooks";
5
+ import { createColumnHelper } from "@tanstack/table-core";
6
+ import { useTable } from "./useTable.js";
7
+ import { FlexRender } from "./FlexRender.js";
8
+ function createTableHook({
9
+ tableComponents,
10
+ cellComponents,
11
+ headerComponents,
12
+ ...defaultTableOptions
13
+ }) {
14
+ const TableContext = createContext(
15
+ null
16
+ );
17
+ const CellContext = createContext(null);
18
+ const HeaderContext = createContext(
19
+ null
20
+ );
21
+ function createAppColumnHelper() {
22
+ return createColumnHelper();
23
+ }
24
+ function useTableContext() {
25
+ const table = useContext(TableContext);
26
+ if (!table) {
27
+ throw new Error(
28
+ "`useTableContext` must be used within an `AppTable` component. Make sure your component is wrapped with `<table.AppTable>...</table.AppTable>`."
29
+ );
30
+ }
31
+ return table;
32
+ }
33
+ function useCellContext() {
34
+ const cell = useContext(CellContext);
35
+ if (!cell) {
36
+ throw new Error(
37
+ "`useCellContext` must be used within an `AppCell` component. Make sure your component is wrapped with `<table.AppCell cell={cell}>...</table.AppCell>`."
38
+ );
39
+ }
40
+ return cell;
41
+ }
42
+ function useHeaderContext() {
43
+ const header = useContext(HeaderContext);
44
+ if (!header) {
45
+ throw new Error(
46
+ "`useHeaderContext` must be used within an `AppHeader` or `AppFooter` component."
47
+ );
48
+ }
49
+ return header;
50
+ }
51
+ function CellFlexRender() {
52
+ const cell = useCellContext();
53
+ return /* @__PURE__ */ jsx(FlexRender, { cell });
54
+ }
55
+ function HeaderFlexRender() {
56
+ const header = useHeaderContext();
57
+ return /* @__PURE__ */ jsx(FlexRender, { header });
58
+ }
59
+ function FooterFlexRender() {
60
+ const header = useHeaderContext();
61
+ return /* @__PURE__ */ jsx(FlexRender, { footer: header });
62
+ }
63
+ function useAppTable(tableOptions, selector) {
64
+ const table = useTable(
65
+ { ...defaultTableOptions, ...tableOptions },
66
+ selector
67
+ );
68
+ const AppTable = useMemo(() => {
69
+ function AppTableImpl(props) {
70
+ const { children, selector: appTableSelector } = props;
71
+ return /* @__PURE__ */ jsx(TableContext.Provider, { value: table, children: appTableSelector ? /* @__PURE__ */ jsx(table.Subscribe, { selector: appTableSelector, children: (state) => children(
72
+ state
73
+ ) }) : children });
74
+ }
75
+ return AppTableImpl;
76
+ }, [table]);
77
+ const AppCell = useMemo(() => {
78
+ function AppCellImpl(props) {
79
+ const { cell, children, selector: appCellSelector } = props;
80
+ const extendedCell = Object.assign(cell, {
81
+ FlexRender: CellFlexRender,
82
+ ...cellComponents
83
+ });
84
+ return /* @__PURE__ */ jsx(CellContext.Provider, { value: cell, children: appCellSelector ? /* @__PURE__ */ jsx(table.Subscribe, { selector: appCellSelector, children: (state) => children(extendedCell, state) }) : children(extendedCell) });
85
+ }
86
+ return AppCellImpl;
87
+ }, [table]);
88
+ const AppHeader = useMemo(() => {
89
+ function AppHeaderImpl(props) {
90
+ const { header, children, selector: appHeaderSelector } = props;
91
+ const extendedHeader = Object.assign(header, {
92
+ FlexRender: HeaderFlexRender,
93
+ ...headerComponents
94
+ });
95
+ return /* @__PURE__ */ jsx(HeaderContext.Provider, { value: header, children: appHeaderSelector ? /* @__PURE__ */ jsx(table.Subscribe, { selector: appHeaderSelector, children: (state) => children(extendedHeader, state) }) : children(extendedHeader) });
96
+ }
97
+ return AppHeaderImpl;
98
+ }, [table]);
99
+ const AppFooter = useMemo(() => {
100
+ function AppFooterImpl(props) {
101
+ const { header, children, selector: appFooterSelector } = props;
102
+ const extendedHeader = Object.assign(header, {
103
+ FlexRender: FooterFlexRender,
104
+ ...headerComponents
105
+ });
106
+ return /* @__PURE__ */ jsx(HeaderContext.Provider, { value: header, children: appFooterSelector ? /* @__PURE__ */ jsx(table.Subscribe, { selector: appFooterSelector, children: (state) => children(extendedHeader, state) }) : children(extendedHeader) });
107
+ }
108
+ return AppFooterImpl;
109
+ }, [table]);
110
+ const extendedTable = useMemo(() => {
111
+ return Object.assign(table, {
112
+ AppTable,
113
+ AppCell,
114
+ AppHeader,
115
+ AppFooter,
116
+ ...tableComponents
117
+ });
118
+ }, [table, AppTable, AppCell, AppHeader, AppFooter]);
119
+ return extendedTable;
120
+ }
121
+ return {
122
+ appFeatures: defaultTableOptions._features,
123
+ createAppColumnHelper,
124
+ useAppTable,
125
+ useTableContext,
126
+ useCellContext,
127
+ useHeaderContext
128
+ };
129
+ }
130
+ export {
131
+ createTableHook
132
+ };
133
+ //# sourceMappingURL=createTableHook.js.map