Skip to content

Commit bc4f3df

Browse files
kadoshmsMor KadoshKevinVandy
authored
feat: Add TanStack Lit Table Adapter (#5538)
* feat: initial integration for lit * feat: sorting example working * feat: add filters example * chore: removed "unknown" type * fix: use map instead of repeat for tbody * feat: add row-sorting example * configuration and doc templates * add missing faker deps to examples * update lit adapter docs * refactor: change getTable to useLitTable docs: fix Lit docs * docs: add twind and some styling to basic example * docs(lit): add column resizing example * chore: rename useLitTable to simply "table" * prettier * fix state type docs * docs config --------- Co-authored-by: Mor Kadosh <[email protected]> Co-authored-by: Kevin Van Cott <[email protected]>
1 parent a6e6c3b commit bc4f3df

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2832
-328
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ stats-hydration.json
3535
stats-react.json
3636
stats.html
3737
.vscode/settings.json
38+
.idea
3839

3940
*.log
4041
.DS_Store

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Try other [TanStack](https://tanstack.com) libraries:
4747
You may know **TanStack Table** by our adapter names, too!
4848

4949
- [Angular Table](https://tanstack.com/table/v8/docs/adapters/angular-table)
50+
- [Lit Table](https://tanstack.com/table/v8/docs/adapters/lit-table)
5051
- [Qwik Table](https://tanstack.com/table/v8/docs/adapters/qwik-table)
5152
- [**React Table**](https://tanstack.com/table/v8/docs/adapters/react-table)
5253
- [Solid Table](https://tanstack.com/table/v8/docs/adapters/solid-table)
@@ -117,6 +118,7 @@ Install one of the following packages based on your framework of choice:
117118
```bash
118119
# Npm
119120
npm install @tanstack/angular-table
121+
npm install @tanstack/lit-table
120122
npm install @tanstack/qwik-table
121123
npm install @tanstack/react-table
122124
npm install @tanstack/solid-table

docs/config.json

+43
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@
4040
}
4141
]
4242
},
43+
{
44+
"label": "lit",
45+
"children": [
46+
{
47+
"label": "Lit Table Adapter",
48+
"to": "framework/lit/lit-table"
49+
}
50+
]
51+
},
4352
{
4453
"label": "qwik",
4554
"children": [
@@ -146,6 +155,15 @@
146155
}
147156
]
148157
},
158+
{
159+
"label": "lit",
160+
"children": [
161+
{
162+
"label": "Table State",
163+
"to": "framework/lit/guide/table-state"
164+
}
165+
]
166+
},
149167
{
150168
"label": "qwik",
151169
"children": [
@@ -423,6 +441,31 @@
423441
}
424442
]
425443
},
444+
{
445+
"label": "lit",
446+
"children": [
447+
{
448+
"to": "framework/lit/examples/basic",
449+
"label": "Basic"
450+
},
451+
{
452+
"to": "framework/lit/examples/column-sizing",
453+
"label": "Column Sizing"
454+
},
455+
{
456+
"to": "framework/lit/examples/filters",
457+
"label": "Filters"
458+
},
459+
{
460+
"to": "framework/lit/examples/row-selection",
461+
"label": "Row Selection"
462+
},
463+
{
464+
"to": "framework/lit/examples/sorting",
465+
"label": "Sorting"
466+
}
467+
]
468+
},
426469
{
427470
"label": "qwik",
428471
"children": [

docs/framework/angular/angular-table.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ state the "angular signals" way, providing types and the rendering implementatio
77

88
## Exports
99

10-
`@tanstack/angular-table` re-exports all of `@tanstack/table-core`'s and the following:
10+
`@tanstack/angular-table` re-exports all of `@tanstack/table-core`'s APIs and the following:
1111

1212
### `createAngularTable`
1313

docs/framework/angular/guide/table-state.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ This is why you will see the `updater instanceof Function ? this.state.update(up
204204
All complex states in TanStack Table have their own TypeScript types that you can import and use. This can be handy for ensuring that you are using the correct data structures and properties for the state values that you are controlling.
205205

206206
```ts
207-
import {createAngularTable, SortingState} from '@tanstack/angular-table'
207+
import {createAngularTable, type SortingState} from '@tanstack/angular-table'
208208

209209
class TableComponent {
210210
readonly sorting = signal<SortingState>([
+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
---
2+
title: Table State (Lit) Guide
3+
---
4+
5+
## Table State (Lit) Guide
6+
7+
TanStack Table has a simple underlying internal state management system to store and manage the state of the table. It also lets you selectively pull out any state that you need to manage in your own state management. This guide will walk you through the different ways in which you can interact with and manage the state of the table.
8+
9+
### Accessing Table State
10+
11+
You do not need to set up anything special in order for the table state to work. If you pass nothing into either `state`, `initialState`, or any of the `on[State]Change` table options, the table will manage its own state internally. You can access any part of this internal state by using the `table.getState()` table instance API.
12+
13+
```ts
14+
private tableController = new TableController<Person>(this);
15+
16+
render() {
17+
const table = this.tableController.table({
18+
columns,
19+
data,
20+
...
21+
})
22+
23+
console.log(table.getState()) //access the entire internal state
24+
console.log(table.getState().rowSelection) //access just the row selection state
25+
// ...
26+
}
27+
```
28+
29+
### Custom Initial State
30+
31+
If all you need to do for certain states is customize their initial default values, you still do not need to manage any of the state yourself. You can simply set values in the `initialState` option of the table instance.
32+
33+
```ts
34+
render() {
35+
const table = this.tableController.table({
36+
columns,
37+
data,
38+
initialState: {
39+
columnOrder: ['age', 'firstName', 'lastName'], //customize the initial column order
40+
columnVisibility: {
41+
id: false //hide the id column by default
42+
},
43+
expanded: true, //expand all rows by default
44+
sorting: [
45+
{
46+
id: 'age',
47+
desc: true //sort by age in descending order by default
48+
}
49+
]
50+
},
51+
})
52+
53+
return html`...`;
54+
}
55+
```
56+
57+
> **Note**: Only specify each particular state in either `initialState` or `state`, but not both. If you pass in a particular state value to both `initialState` and `state`, the initialized state in `state` will take overwrite any corresponding value in `initialState`.
58+
59+
### Controlled State
60+
61+
If you need easy access to the table state in other areas of your application, TanStack Table makes it easy to control and manage any or all of the table state in your own state management system. You can do this by passing in your own state and state management functions to the `state` and `on[State]Change` table options.
62+
63+
#### Individual Controlled State
64+
65+
You can control just the state that you need easy access to. You do NOT have to control all of the table state if you do not need to. It is recommended to only control the state that you need on a case-by-case basis.
66+
67+
In order to control a particular state, you need to both pass in the corresponding `state` value and the `on[State]Change` function to the table instance.
68+
69+
Let's take filtering, sorting, and pagination as an example in a "manual" server-side data fetching scenario. You can store the filtering, sorting, and pagination state in your own state management, but leave out any other state like column order, column visibility, etc. if your API does not care about those values.
70+
71+
```jsx
72+
import {html} from "lit";
73+
74+
@customElement('my-component')
75+
class MyComponent extends LitElement {
76+
@state()
77+
private _sorting: SortingState = []
78+
79+
render() {
80+
const table = this.tableController.table({
81+
columns,
82+
data,
83+
state: {
84+
sorting: this._sorting,
85+
},
86+
onSortingChange: updaterOrValue => {
87+
if (typeof updaterOrValue === 'function') {
88+
this._sorting = updaterOrValue(this._sorting)
89+
} else {
90+
this._sorting = updaterOrValue
91+
}
92+
},
93+
getSortedRowModel: getSortedRowModel(),
94+
getCoreRowModel: getCoreRowModel(),
95+
})
96+
97+
return html`...`
98+
}
99+
}
100+
//...
101+
```
102+
103+
#### Fully Controlled State
104+
105+
Alternatively, you can control the entire table state with the `onStateChange` table option. It will hoist out the entire table state into your own state management system. Be careful with this approach, as you might find that raising some frequently changing state values up a component tree, like `columnSizingInfo` state`, might cause bad performance issues.
106+
107+
A couple of more tricks may be needed to make this work. If you use the `onStateChange` table option, the initial values of the `state` must be populated with all of the relevant state values for all of the features that you want to use. You can either manually type out all of the initial state values, or use the `table.setOptions` API in a special way as shown below.
108+
109+
```ts
110+
111+
private tableController = new TableController<Person>(this);
112+
113+
@state()
114+
private _tableState;
115+
116+
render() {
117+
const table = this.tableController.table({
118+
columns,
119+
data,
120+
getCoreRowModel: getCoreRowModel(),
121+
getSortedRowModel: getSortedRowModel()
122+
})
123+
const state = { ...table.initialState, ...this._tableState };
124+
table.setOptions(prev => ({
125+
...prev,
126+
state,
127+
onStateChange: updater => {
128+
this._tableState =
129+
updater instanceof Function ? updater(state) : updater //any state changes will be pushed up to our own state management
130+
},
131+
}))
132+
133+
return html`...`;
134+
}
135+
```
136+
137+
### On State Change Callbacks
138+
139+
So far, we have seen the `on[State]Change` and `onStateChange` table options work to "hoist" the table state changes into our own state management. However, there are a few things about these using these options that you should be aware of.
140+
141+
#### 1. **State Change Callbacks MUST have their corresponding state value in the `state` option**.
142+
143+
Specifying an `on[State]Change` callback tells the table instance that this will be a controlled state. If you do not specify the corresponding `state` value, that state will be "frozen" with its initial value.
144+
145+
```jsx
146+
@state()
147+
private _sorting = [];
148+
//...
149+
render() {
150+
const table = this.tableController.table({
151+
columns,
152+
data,
153+
state: {
154+
sorting: this._sorting,
155+
},
156+
onSortingChange: updaterOrValue => {
157+
if (typeof updaterOrValue === 'function') {
158+
this._sorting = updaterOrValue(this._sorting)
159+
} else {
160+
this._sorting = updaterOrValue
161+
}
162+
},
163+
getSortedRowModel: getSortedRowModel(),
164+
getCoreRowModel: getCoreRowModel(),
165+
})
166+
167+
return html`...`;
168+
}
169+
```
170+
171+
#### 2. **Updaters can either be raw values or callback functions**.
172+
173+
The `on[State]Change` and `onStateChange` callbacks work exactly like the `setState` functions in React. The updater values can either be a new state value or a callback function that takes the previous state value and returns the new state value.
174+
175+
What implications does this have? It means that if you want to add in some extra logic in any of the `on[State]Change` callbacks, you can do so, but you need to check whether or not the new incoming updater value is a function or value.
176+
177+
This is why you will see the `updater instanceof Function ? updater(state.value) : updater` pattern in the examples above. This pattern checks if the updater is a function, and if it is, it calls the function with the previous state value to get the new state value.
178+
179+
### State Types
180+
181+
All complex states in TanStack Table have their own TypeScript types that you can import and use. This can be handy for ensuring that you are using the correct data structures and properties for the state values that you are controlling.
182+
183+
```tsx
184+
import { TableController, type SortingState } from '@tanstack/lit-table'
185+
//...
186+
@state()
187+
private _sorting: SortingState = [
188+
{
189+
id: 'age', //you should get autocomplete for the `id` and `desc` properties
190+
desc: true,
191+
}
192+
]
193+
```

docs/framework/lit/lit-table.md

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
title: Lit Table
3+
---
4+
5+
The `@tanstack/lit-table` adapter is a wrapper around the core table logic. Most of it's job is related to managing state the "lit" way, providing types and the rendering implementation of cell/header/footer templates.
6+
7+
## Exports
8+
9+
`@tanstack/lit-table` re-exports all of `@tanstack/table-core`'s APIs and the following:
10+
11+
### `TableController`
12+
13+
Is a reactive controller that provides a `table` API that takes an `options` object and returns a table instance.
14+
15+
```ts
16+
import { TableController } from '@tanstack/lit-table'
17+
18+
@customElement('my-table-element')
19+
class MyTableElement extends LitElement {
20+
private tableController = new TableController<Person>(this)
21+
22+
protected render() {
23+
const table = this.tableController.table(options)
24+
// ...render your table
25+
}
26+
}
27+
```
28+
29+
### `flexRender`
30+
31+
A utility function for rendering cell/header/footer templates with dynamic values.
32+
33+
Example:
34+
35+
```jsx
36+
import { flexRender } from '@tanstack/lit-table'
37+
//...
38+
return html`
39+
<tbody>
40+
${table
41+
.getRowModel()
42+
.rows.slice(0, 10)
43+
.map(
44+
row => html`
45+
<tr>
46+
${row
47+
.getVisibleCells()
48+
.map(
49+
cell => html`
50+
<td>
51+
${flexRender(
52+
cell.column.columnDef.cell,
53+
cell.getContext()
54+
)}
55+
</td>
56+
`
57+
)}
58+
</tr>
59+
`
60+
)}
61+
</tbody>
62+
`
63+
```

docs/framework/qwik/guide/table-state.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ This is why you will see the `updater instanceof Function ? updater(state.value)
167167
All complex states in TanStack Table have their own TypeScript types that you can import and use. This can be handy for ensuring that you are using the correct data structures and properties for the state values that you are controlling.
168168

169169
```tsx
170-
import { useQwikTable, SortingState } from '@tanstack/qwik-table'
170+
import { useQwikTable, type SortingState } from '@tanstack/qwik-table'
171171
//...
172172
const sorting = Qwik.useSignal<SortingState[]>([
173173
{

docs/framework/qwik/qwik-table.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The `@tanstack/qwik-table` adapter is a wrapper around the core table logic. Mos
66

77
## Exports
88

9-
`@tanstack/qwik-table` re-exports all of `@tanstack/table-core`'s and the following:
9+
`@tanstack/qwik-table` re-exports all of `@tanstack/table-core`'s APIs and the following:
1010

1111
### `useQwikTable`
1212

docs/framework/react/guide/table-state.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ const table = useReactTable({
193193
All complex states in TanStack Table have their own TypeScript types that you can import and use. This can be handy for ensuring that you are using the correct data structures and properties for the state values that you are controlling.
194194

195195
```tsx
196-
import { useReactTable, SortingState } from '@tanstack/react-table'
196+
import { useReactTable, type SortingState } from '@tanstack/react-table'
197197
//...
198198
const [sorting, setSorting] = React.useState<SortingState[]>([
199199
{

docs/framework/solid/guide/table-state.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ const table = createSolidTable({
210210
All complex states in TanStack Table have their own TypeScript types that you can import and use. This can be handy for ensuring that you are using the correct data structures and properties for the state values that you are controlling.
211211

212212
```tsx
213-
import { createSolidTable, SortingState } from '@tanstack/solid-table'
213+
import { createSolidTable, type SortingState } from '@tanstack/solid-table'
214214
//...
215215
const [sorting, setSorting] = createSignal<SortingState[]>([
216216
{

0 commit comments

Comments
 (0)