diff --git a/docs/config.json b/docs/config.json
index c2a170878a..6243d87d59 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -463,6 +463,10 @@
{
"to": "framework/lit/examples/sorting",
"label": "Sorting"
+ },
+ {
+ "to": "framework/lit/examples/virtualized-rows",
+ "label": "Virtualized Rows"
}
]
},
diff --git a/examples/lit/virtualized-rows/.gitignore b/examples/lit/virtualized-rows/.gitignore
new file mode 100644
index 0000000000..d451ff16c1
--- /dev/null
+++ b/examples/lit/virtualized-rows/.gitignore
@@ -0,0 +1,5 @@
+node_modules
+.DS_Store
+dist
+dist-ssr
+*.local
diff --git a/examples/lit/virtualized-rows/README.md b/examples/lit/virtualized-rows/README.md
new file mode 100644
index 0000000000..b168d3c4b1
--- /dev/null
+++ b/examples/lit/virtualized-rows/README.md
@@ -0,0 +1,6 @@
+# Example
+
+To run this example:
+
+- `npm install` or `yarn`
+- `npm run start` or `yarn start`
diff --git a/examples/lit/virtualized-rows/index.html b/examples/lit/virtualized-rows/index.html
new file mode 100644
index 0000000000..9807874fae
--- /dev/null
+++ b/examples/lit/virtualized-rows/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Vite App
+
+
+
+
+
+
+
+
diff --git a/examples/lit/virtualized-rows/package.json b/examples/lit/virtualized-rows/package.json
new file mode 100644
index 0000000000..2a6df304dd
--- /dev/null
+++ b/examples/lit/virtualized-rows/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "tanstack-lit-table-virtualized-rows",
+ "version": "0.0.0",
+ "private": true,
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "serve": "vite preview",
+ "start": "vite"
+ },
+ "dependencies": {
+ "@faker-js/faker": "^8.4.1",
+ "@lit-labs/virtualizer": "^2.0.13",
+ "@tanstack/lit-table": "^8.19.1",
+ "lit": "^3.1.3"
+ },
+ "devDependencies": {
+ "@rollup/plugin-replace": "^5.0.5",
+ "typescript": "5.4.5",
+ "vite": "^5.2.10"
+ }
+}
diff --git a/examples/lit/virtualized-rows/src/main.ts b/examples/lit/virtualized-rows/src/main.ts
new file mode 100644
index 0000000000..a33c18b877
--- /dev/null
+++ b/examples/lit/virtualized-rows/src/main.ts
@@ -0,0 +1,211 @@
+import { customElement } from 'lit/decorators.js'
+import { html, LitElement } from 'lit'
+import { repeat } from 'lit/directives/repeat.js'
+import {
+ ColumnDef,
+ flexRender,
+ getCoreRowModel,
+ getSortedRowModel,
+ TableController,
+} from '@tanstack/lit-table'
+import config from '../twind.config'
+import { styleMap } from 'lit/directives/style-map.js'
+import { virtualize, virtualizerRef } from '@lit-labs/virtualizer/virtualize.js'
+import { makeData, Person } from './makeData.ts'
+
+const columns: ColumnDef[] = [
+ {
+ accessorKey: 'id',
+ header: 'ID',
+ size: 60,
+ },
+ {
+ accessorKey: 'firstName',
+ cell: info => info.getValue(),
+ },
+ {
+ accessorFn: row => row.lastName,
+ id: 'lastName',
+ cell: info => info.getValue(),
+ header: () => html`Last Name`,
+ },
+ {
+ accessorKey: 'age',
+ header: () => 'Age',
+ size: 50,
+ },
+ {
+ accessorKey: 'visits',
+ header: () => html`Visits`,
+ size: 50,
+ },
+ {
+ accessorKey: 'status',
+ header: 'Status',
+ },
+ {
+ accessorKey: 'progress',
+ header: 'Profile Progress',
+ size: 80,
+ },
+ {
+ accessorKey: 'createdAt',
+ header: 'Created At',
+ cell: info => info.getValue().toLocaleString(),
+ size: 250,
+ },
+]
+const data = makeData(50_000)
+
+@customElement('lit-table-example')
+class LitTableExample extends LitElement {
+ private tableController = new TableController(this)
+
+ protected render(): unknown {
+ const table = this.tableController.table({
+ columns,
+ data,
+ getSortedRowModel: getSortedRowModel(),
+ getCoreRowModel: getCoreRowModel(),
+ })
+ const { rows } = table.getRowModel()
+ return html`
+
+ (${data.length} rows)
+
+
+
+ ${repeat(
+ table.getHeaderGroups(),
+ headerGroup => headerGroup.id,
+ headerGroup => html`
+
+ ${repeat(
+ headerGroup.headers,
+ header => header.id,
+ header => html`
+
+ ${flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+ ${{ asc: ' 🔼', desc: ' 🔽' }[
+ header.column.getIsSorted() as string
+ ] ?? null}
+ |
+ `
+ )}
+
+ `
+ )}
+
+
+ ${virtualize({
+ items: data,
+ renderItem: (_, index) => {
+ const row = rows[index]
+ return html`
+
+ ${repeat(
+ row.getVisibleCells(),
+ cell => cell.id,
+ cell => html`
+
+ ${flexRender(
+ cell.column.columnDef.cell,
+ cell.getContext()
+ )}
+ |
+ `
+ )}
+
+ `
+ },
+ })}
+
+
+
+
+
+
+ `
+ }
+}
diff --git a/examples/lit/virtualized-rows/src/makeData.ts b/examples/lit/virtualized-rows/src/makeData.ts
new file mode 100644
index 0000000000..e5695467f5
--- /dev/null
+++ b/examples/lit/virtualized-rows/src/makeData.ts
@@ -0,0 +1,50 @@
+import { faker } from '@faker-js/faker'
+
+export type Person = {
+ id: number
+ firstName: string
+ lastName: string
+ age: number
+ visits: number
+ progress: number
+ status: 'relationship' | 'complicated' | 'single'
+ createdAt: Date
+}
+
+const range = (len: number) => {
+ const arr: number[] = []
+ for (let i = 0; i < len; i++) {
+ arr.push(i)
+ }
+ return arr
+}
+
+const newPerson = (index: number): Person => {
+ return {
+ id: index + 1,
+ firstName: faker.person.firstName(),
+ lastName: faker.person.lastName(),
+ age: faker.number.int(40),
+ visits: faker.number.int(1000),
+ progress: faker.number.int(100),
+ createdAt: faker.date.anytime(),
+ status: faker.helpers.shuffle([
+ 'relationship',
+ 'complicated',
+ 'single',
+ ])[0]!,
+ }
+}
+
+export function makeData(...lens: number[]) {
+ const makeDataLevel = (depth = 0): Person[] => {
+ const len = lens[depth]!
+ return range(len).map((d): Person => {
+ return {
+ ...newPerson(d),
+ }
+ })
+ }
+
+ return makeDataLevel()
+}
diff --git a/examples/lit/virtualized-rows/tsconfig.json b/examples/lit/virtualized-rows/tsconfig.json
new file mode 100644
index 0000000000..3141563c8a
--- /dev/null
+++ b/examples/lit/virtualized-rows/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "emitDecoratorMetadata": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "experimentalDecorators": true,
+ "useDefineForClassFields": false,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": false,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"]
+}
diff --git a/examples/lit/virtualized-rows/twind.config.ts b/examples/lit/virtualized-rows/twind.config.ts
new file mode 100644
index 0000000000..f7e85ff4ae
--- /dev/null
+++ b/examples/lit/virtualized-rows/twind.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from '@twind/core'
+import presetAutoprefix from '@twind/preset-autoprefix'
+import presetTailwind from '@twind/preset-tailwind/base'
+
+export default defineConfig({
+ presets: [presetAutoprefix(), presetTailwind()],
+})
diff --git a/examples/lit/virtualized-rows/vite.config.js b/examples/lit/virtualized-rows/vite.config.js
new file mode 100644
index 0000000000..fa3b238ac6
--- /dev/null
+++ b/examples/lit/virtualized-rows/vite.config.js
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite'
+import rollupReplace from '@rollup/plugin-replace'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [
+ rollupReplace({
+ preventAssignment: true,
+ values: {
+ __DEV__: JSON.stringify(true),
+ 'process.env.NODE_ENV': JSON.stringify('development'),
+ },
+ }),
+ ],
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a9b7f50e5b..c9f0c0e40f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -942,6 +942,31 @@ importers:
specifier: ^5.2.10
version: 5.3.1(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(terser@5.31.1)
+ examples/lit/virtualized-rows:
+ dependencies:
+ '@faker-js/faker':
+ specifier: ^8.4.1
+ version: 8.4.1
+ '@lit-labs/virtualizer':
+ specifier: ^2.0.13
+ version: 2.0.13
+ '@tanstack/lit-table':
+ specifier: ^8.19.1
+ version: link:../../../packages/lit-table
+ lit:
+ specifier: ^3.1.3
+ version: 3.1.4
+ devDependencies:
+ '@rollup/plugin-replace':
+ specifier: ^5.0.5
+ version: 5.0.7(rollup@4.18.0)
+ typescript:
+ specifier: 5.4.5
+ version: 5.4.5
+ vite:
+ specifier: ^5.2.10
+ version: 5.3.1(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(terser@5.31.1)
+
examples/qwik/basic:
dependencies:
'@tanstack/qwik-table':
@@ -4565,6 +4590,9 @@ packages:
'@lit-labs/ssr-dom-shim@1.2.0':
resolution: {integrity: sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==}
+ '@lit-labs/virtualizer@2.0.13':
+ resolution: {integrity: sha512-OKojbIFohfrRpWd3OxcVSc2nyTd0jx10ZSQobuOW9H9jYkad02OJ1uFvV/sHJey8hoh95FIO4d43h+Ry/G4nGw==}
+
'@lit/reactive-element@2.0.4':
resolution: {integrity: sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==}
@@ -12382,6 +12410,11 @@ snapshots:
'@lit-labs/ssr-dom-shim@1.2.0': {}
+ '@lit-labs/virtualizer@2.0.13':
+ dependencies:
+ lit: 3.1.4
+ tslib: 2.6.2
+
'@lit/reactive-element@2.0.4':
dependencies:
'@lit-labs/ssr-dom-shim': 1.2.0