diff --git a/src/components/landing/AiLanding.tsx b/src/components/landing/AiLanding.tsx index 90f250a7..0b04d67f 100644 --- a/src/components/landing/AiLanding.tsx +++ b/src/components/landing/AiLanding.tsx @@ -264,7 +264,7 @@ export default function AiLanding({

A useful AI layer has to cross clients, servers, providers, tools, streaming events, approvals, and observability. AI keeps those - seams explicit so teams can swap pieces without rewriting the + boundaries explicit so teams can swap pieces without rewriting the product.

@@ -888,11 +888,15 @@ function RuntimePanel() {

- agent.run({'{'} provider, model, tools {'}'}) + const {'{'} messages, addToolApprovalResponse {'}'} = useChat({'{'}
- stream.on("tool.call", requestApproval) +   connection: fetchServerSentEvents("/api/chat"),
- devtools.record(event) +   tools, +
+   devtools: {'{'} name: "Support Chat" {'}'} +
+ {'}'})

diff --git a/src/components/landing/CliLanding.tsx b/src/components/landing/CliLanding.tsx index 852fcbd6..de9f0a63 100644 --- a/src/components/landing/CliLanding.tsx +++ b/src/components/landing/CliLanding.tsx @@ -28,7 +28,7 @@ import { LandingCopyPromptButton } from '~/components/landing/LandingCopyPromptB const library = getLibrary('cli') const cliAgentPrompt = [ 'Use TanStack CLI for a TanStack project workflow.', - 'Show how the CLI, MCP server, Builder, docs search, and modular integrations can scaffold or modify a TanStack Start app with auth, database, styling, deployment, and package-specific best practices.', + 'Show how the CLI, Builder, docs search, and modular integrations can scaffold or modify a TanStack Start app with auth, database, styling, deployment, and package-specific best practices.', 'Keep generated changes inspectable and grounded in TanStack docs instead of relying on generic framework assumptions.', ].join(' ') @@ -38,8 +38,8 @@ const heroProof = [ value: 'project commands and generated changes', }, { - label: 'MCP', - value: 'docs search and agent context', + label: 'Docs', + value: 'search, fetch, and introspect', }, { label: 'Builder', @@ -48,10 +48,10 @@ const heroProof = [ ] const commandRows = [ - ['search docs', 'router loaders'], - ['add integration', 'auth + database'], - ['scaffold start', 'Cloudflare target'], - ['export builder', 'checked project plan'], + ['search-docs', '"router loaders" --library router'], + ['create', 'my-app --add-ons clerk,drizzle'], + ['libraries', '--group state --json'], + ['ecosystem', '--category database --json'], ] const featureCards = [ @@ -61,8 +61,8 @@ const featureCards = [ icon: , }, { - title: 'MCP turns docs into agent context.', - body: 'Connect assistants to TanStack documentation so generated work can reference current docs and package-specific conventions.', + title: 'CLI introspection turns docs into agent context.', + body: 'Use JSON commands for docs, libraries, add-ons, and ecosystem data so generated work can reference current TanStack conventions.', icon: , }, { @@ -80,7 +80,7 @@ const featureCards = [ const workflowSteps = [ { label: 'Discover', - body: 'Search docs, examples, packages, and integrations through CLI or MCP.', + body: 'Search docs, examples, packages, and integrations through direct CLI commands.', }, { label: 'Choose', @@ -110,8 +110,8 @@ const builderOutputs = [ value: 'routes, server fns, env, deploy config', }, { - label: 'agent prompt', - value: 'copyable implementation brief', + label: 'CLI config', + value: '.tanstack.json and chosen add-ons', }, ] @@ -127,7 +127,7 @@ export default function CliLanding({
}> - CLI, MCP, and Builder + CLI, add-ons, and Builder
@@ -146,9 +146,9 @@ export default function CliLanding({

- CLI brings together commands, MCP docs access, modular + CLI brings together project commands, docs search, modular integrations, and the Builder so TanStack Start apps can be - scaffolded and customized with the same context the docs use. + scaffolded and customized with current TanStack context.

The Builder turns app intent into a readable stack brief: TanStack libraries, partner integrations, deployment target, generated - files, and an agent-ready prompt. + files, and CLI-ready configuration.

@@ -319,10 +319,7 @@ export default function CliLanding({ function CliWorkbenchPanel() { const [activeCommandIndex, setActiveCommandIndex] = React.useState(0) const activeCommand = commandRows[activeCommandIndex] ?? commandRows[0] - const activeCommandPreview = `npx @tanstack/cli ${activeCommand[0].replace( - ' ', - '-', - )} "${activeCommand[1]}"` + const activeCommandPreview = `npx @tanstack/cli ${activeCommand[0]} ${activeCommand[1]}` return (
@@ -339,11 +336,11 @@ function CliWorkbenchPanel() {

- npx @tanstack/cli mcp + npx @tanstack/cli create --list-add-ons --json
{activeCommandPreview}
- npx @tanstack/cli build-plan + npx @tanstack/cli doc query framework/react/overview --json

diff --git a/src/components/landing/ConfigLanding.tsx b/src/components/landing/ConfigLanding.tsx index e4c3b4c8..c859e20a 100644 --- a/src/components/landing/ConfigLanding.tsx +++ b/src/components/landing/ConfigLanding.tsx @@ -29,8 +29,8 @@ import { LandingCopyPromptButton } from '~/components/landing/LandingCopyPromptB const library = getLibrary('config') const configAgentPrompt = [ 'Set up TanStack Config for a TypeScript package.', - 'Use the opinionated lint, build, test, versioning, changelog, publishing, and package-quality defaults while keeping project-specific configuration minimal and explicit.', - 'Show how the package should produce publint-friendly output, stable npm releases, and repeatable local/CI workflows.', + 'Use the opinionated ESLint, Vite package build, CI/CD, package structure, and publish defaults while keeping project-specific configuration minimal and explicit.', + 'Show how the package should produce publint-friendly output, Changesets-backed releases, and repeatable local/CI workflows.', ].join(' ') const heroProof = [ @@ -40,11 +40,11 @@ const heroProof = [ }, { label: 'Validate', - value: 'lint, tests, publint-friendly checks', + value: 'ESLint, tests, package checks', }, { label: 'Release', - value: 'versioning, changelogs, npm + GitHub', + value: 'Changesets, npm + GitHub', }, ] @@ -52,14 +52,14 @@ const releaseRows = [ ['typecheck', 'passed'], ['lint', 'passed'], ['package exports', 'verified'], - ['changelog', 'generated'], + ['changesets', 'ready'], ['npm publish', 'ready'], ] const featureCards = [ { title: 'Opinionated where packages are repetitive.', - body: 'Linting, building, testing, formatting, publishing, and release hygiene should not become bespoke work in every package repo.', + body: 'Linting, package builds, CI tasks, publishing, and release hygiene should not become bespoke work in every package repo.', icon: , }, { @@ -69,7 +69,7 @@ const featureCards = [ }, { title: 'Publishing rules stay visible.', - body: 'Exports, changelogs, package metadata, versioning, and npm release behavior can be reviewed as part of the same workflow.', + body: 'Exports, package metadata, release branches, and npm publish behavior can be reviewed as part of the same workflow.', icon: , }, { @@ -94,7 +94,7 @@ const pipelineSteps = [ }, { label: 'Publish', - body: 'Version, changelog, tag, and publish through a repeatable release path.', + body: 'Version, tag, and publish through a repeatable release path.', }, ] @@ -108,8 +108,8 @@ const auditSignals = [ value: 'package shape checked', }, { - label: 'changes', - value: 'changelog generated', + label: 'changesets', + value: 'versioning ready', }, { label: 'release', @@ -142,8 +142,8 @@ export default function ConfigLanding({

Config is the opinionated toolchain TanStack uses to keep - JavaScript packages linted, built, tested, versioned, - changelogged, and published with minimal per-package ceremony. + JavaScript packages linted, built, tested in CI, versioned with + Changesets, and published with minimal per-package ceremony.

Every library needs the same boring promises: exports resolve, - types ship, tests pass, changelogs make sense, and npm publishes - what consumers expect. Config turns that repetition into shared - defaults. + types ship, tests pass, release branches are configured, and npm + publishes what consumers expect. Config turns that repetition into + shared defaults.

@@ -234,7 +234,7 @@ export default function ConfigLanding({

The consumer sees your package boundary: exports, module formats, - types, metadata, changelog, and version. Config keeps that + types, metadata, release branch, and version. Config keeps that boundary part of the workflow.

@@ -345,13 +345,13 @@ function ReleasePanel() {

- pnpm lint + vite build && publint --strict
- pnpm test + nx affected
- pnpm build --verify {completedCount}/{releaseRows.length} + changesets {completedCount}/{releaseRows.length}
- pnpm release{' '} + publish config: branchConfigs, packages, npm, github{' '} {completedCount === releaseRows.length ? '--ready' : '--blocked'}

@@ -432,7 +432,7 @@ function AuditPanel() {
dist/index.d.ts
- CHANGELOG.md + .changeset/*.md

diff --git a/src/components/landing/DbLanding.tsx b/src/components/landing/DbLanding.tsx index e296786c..82319e3c 100644 --- a/src/components/landing/DbLanding.tsx +++ b/src/components/landing/DbLanding.tsx @@ -574,13 +574,17 @@ function SyncPanel() {

- liveQuery({'{'} projects, issues, members {'}'}) + useLiveQuery((q) =>
-   .where(({`{`} issue, project {`}`}) => issue.projectId - === project.id) +   q.from({'{'} issue: issuesCollection {'}'})
-   .orderBy(({`{`} issue {`}`}) => issue.updatedAt, - "desc") +     .join({'{'} project: projectsCollection {'}'}, + ({`{`} issue, project {`}`}) => +
+       eq(issue.projectId, project.id)) +
+     .orderBy(({`{`} issue {`}`}) => + issue.updatedAt, "desc"))

diff --git a/src/components/landing/DevtoolsLanding.tsx b/src/components/landing/DevtoolsLanding.tsx index 3062b639..1faf2a91 100644 --- a/src/components/landing/DevtoolsLanding.tsx +++ b/src/components/landing/DevtoolsLanding.tsx @@ -31,7 +31,7 @@ const library = getLibrary('devtools') const devtoolsAgentPrompt = [ 'Add TanStack Devtools to a TypeScript app.', 'Use the unified devtools shell to host TanStack panels and any custom product devtools, keeping the panel lightweight, framework-friendly, and available during development without coupling product code to one library-specific inspector.', - 'Include examples for mounting built-in panels and registering a custom panel with useful runtime state.', + 'Include examples for mounting built-in panels and product-specific panels through the plugins array.', ].join(' ') const heroProof = [ @@ -45,7 +45,7 @@ const heroProof = [ }, { label: 'Framework friendly', - value: 'React, Preact, Solid, vanilla', + value: 'React, Vue, Solid, Preact, Angular', }, ] @@ -82,7 +82,7 @@ const featureCards = [ }, { title: 'Frameworks get adapters, not rewrites.', - body: 'Use the shell from React, Preact, Solid, or vanilla integration points while panels keep their own internal state model.', + body: 'Use the shell from React, Vue, Solid, Preact, Angular, or vanilla integration points while panels keep their own internal state model.', icon: , }, ] @@ -94,7 +94,7 @@ const panelLifecycle = [ }, { label: 'Register', - body: 'Provide TanStack panels or custom panels with a title, icon, and renderer.', + body: 'Provide TanStack panels or custom panels through the plugins array.', }, { label: 'Inspect', @@ -106,7 +106,14 @@ const panelLifecycle = [ }, ] -const frameworkAdapters = ['React', 'Preact', 'Solid', 'Vanilla'] +const frameworkAdapters = [ + 'React', + 'Vue', + 'Solid', + 'Preact', + 'Angular', + 'Vanilla', +] export default function DevtoolsLanding({ landingCodeExampleRsc, @@ -449,15 +456,17 @@ function CustomPanelExample() {

- registerDevtoolsPanel({'{'} + <TanStackDevtools +
+   plugins={'{'}[{'{'}
-   id: "jobs", +     name: "Background Jobs",
-   title: "Background Jobs", +     render: <JobsPanel />,
-   render: JobsPanel, +   {'}'}]{'}'}
- {'}'}) + />

diff --git a/src/components/landing/FormLanding.tsx b/src/components/landing/FormLanding.tsx index 65555a17..0b647051 100644 --- a/src/components/landing/FormLanding.tsx +++ b/src/components/landing/FormLanding.tsx @@ -62,7 +62,7 @@ type FormDemoPlan = 'team' | 'enterprise' const formFields: Array = [ { name: 'profile.email', - detail: 'zod + async availability', + detail: 'schema + async availability', }, { name: 'company.plan', @@ -129,7 +129,7 @@ const fieldStates = [ }, { label: 'pending', - value: 'field.state.meta.isValidating', + value: 'form.state.isFieldsValidating', }, { label: 'submit', @@ -537,9 +537,9 @@ function SubscriptionPanel() {

- form.Subscribe({'{'} selector: state => state.canSubmit {'}'}) + useStore(form.store, state => state.values.profile.email)
- field.Subscribe({'{'} selector: field => field.meta.errors {'}'}) + form.Subscribe({'{'} selector: state => state.canSubmit {'}'})

diff --git a/src/components/landing/HotkeysLanding.tsx b/src/components/landing/HotkeysLanding.tsx index 11c6b748..cbfe1697 100644 --- a/src/components/landing/HotkeysLanding.tsx +++ b/src/components/landing/HotkeysLanding.tsx @@ -387,8 +387,8 @@ function ShortcutPanel() {

- useHotkeys("{activeShortcut}", runCommand, {'{'} scope {'}'} - ) + useHotkey("{activeShortcut}", runCommand, {'{'} enabled:{' '} + isPanelOpen {'}'})

diff --git a/src/components/landing/IntentLanding.tsx b/src/components/landing/IntentLanding.tsx index 5cc5e3f5..5ea00910 100644 --- a/src/components/landing/IntentLanding.tsx +++ b/src/components/landing/IntentLanding.tsx @@ -57,10 +57,10 @@ const heroProof = [ ] const packageFiles = [ - ['package.json', 'exports skill metadata'], - ['skills/router.md', 'procedural agent knowledge'], + ['package.json', 'keywords and files entries'], + ['skills/router/SKILL.md', 'procedural agent knowledge'], ['docs/routing.md', 'source reference'], - ['CI stale check', 'fails when sources drift'], + ['stale report', 'flags source drift'], ] const featureCards = [ @@ -316,7 +316,7 @@ function IntentPackagePanel() {
npx @tanstack/intent validate {activeFile[0]}
- npx @tanstack/intent stale --source "{activeFile[1]}" + npx @tanstack/intent stale --json

diff --git a/src/components/landing/PacerLanding.tsx b/src/components/landing/PacerLanding.tsx index c6f21bdb..a9ce5c59 100644 --- a/src/components/landing/PacerLanding.tsx +++ b/src/components/landing/PacerLanding.tsx @@ -514,11 +514,11 @@ function AsyncPanel() {

- queue.add(uploadFile) + const queue = new AsyncQueuer(uploadFile, {'{'} concurrency: 3 {'}'})
- queue.setOptions({'{'} concurrency: 3, order: "fifo" {'}'}) + queue.addItem(file)
- queue.subscribe(state => state.status) + queue.store.subscribe(state => syncStatus(state.status))

diff --git a/src/components/landing/QueryLanding.tsx b/src/components/landing/QueryLanding.tsx index 589083bd..8b4db978 100644 --- a/src/components/landing/QueryLanding.tsx +++ b/src/components/landing/QueryLanding.tsx @@ -160,7 +160,7 @@ const mutationSteps = [ }, { label: 'targeted refresh', - code: "invalidateQueries(['todos'])", + code: "invalidateQueries({ queryKey: ['todos'] })", }, { label: 'rollback path', diff --git a/src/components/landing/RangerLanding.tsx b/src/components/landing/RangerLanding.tsx index 0af3eb45..fb95432e 100644 --- a/src/components/landing/RangerLanding.tsx +++ b/src/components/landing/RangerLanding.tsx @@ -351,8 +351,14 @@ function RangerLabPanel() {

- useRanger({'{'} min: 0, max: 1000, step: 10, values: [ - {values.join(', ')}] {'}'}) + useRanger({'{'} getRangerElement: () => rangerRef.current, +
+   min: 0, max: 1000, +
+   stepSize: 10, values: [{values.join(', ')}], +
+   onChange: instance => setValues(instance.sortedValues){' '} + {'}'})

diff --git a/src/components/landing/RouterLanding.tsx b/src/components/landing/RouterLanding.tsx index 01e3cfee..8fc250d0 100644 --- a/src/components/landing/RouterLanding.tsx +++ b/src/components/landing/RouterLanding.tsx @@ -501,7 +501,8 @@ function SearchStatePanel() {

- search: z.object({'{'} + validateSearch: z.object( + {'{'}
  q: z.string().optional(),
diff --git a/src/components/landing/StoreLanding.tsx b/src/components/landing/StoreLanding.tsx index 202bdad4..8e5fa1b4 100644 --- a/src/components/landing/StoreLanding.tsx +++ b/src/components/landing/StoreLanding.tsx @@ -93,7 +93,7 @@ const lifecycleSteps = [ const subscriptionExamples = [ { label: 'component', - value: 'useStore(appStore, state => state.filters)', + value: 'useSelector(appStore, state => state.filters)', }, { label: 'derived', @@ -101,7 +101,7 @@ const subscriptionExamples = [ }, { label: 'effect', - value: 'store.subscribe(selector, listener)', + value: 'store.subscribe(listener)', }, { label: 'adapter', @@ -533,9 +533,9 @@ function SubscriptionPanel() {

- const filters = useStore(store, state => state.filters) + const filters = useSelector(store, state => state.filters)
- const canSave = useStore(store, state => state.draft.isDirty) + const canSave = useSelector(store, state => state.draft.isDirty)

diff --git a/src/components/landing/WorkflowLanding.tsx b/src/components/landing/WorkflowLanding.tsx index 6703731e..4ad0a92d 100644 --- a/src/components/landing/WorkflowLanding.tsx +++ b/src/components/landing/WorkflowLanding.tsx @@ -29,8 +29,8 @@ import { LandingCopyPromptButton } from '~/components/landing/LandingCopyPromptB const library = getLibrary('workflow') const workflowAgentPrompt = [ 'Build a TanStack Workflow process for a TypeScript app.', - 'Model a durable multi-step workflow with typed inputs and outputs, retries, backoff, approvals, fan-out, resumable state, and observable execution history.', - 'Keep business process state inspectable instead of hiding it inside one-off background jobs.', + 'Model a multi-step workflow with typed inputs and outputs, retries, backoff, approvals, fan-out, and inspectable execution history.', + 'Keep business process state explicit, and verify concrete API calls against the current Workflow docs before implementation.', ].join(' ') const heroProof = [ @@ -39,8 +39,8 @@ const heroProof = [ value: 'inputs, outputs, context, transitions', }, { - label: 'Durable state', - value: 'resume through restarts and deploys', + label: 'Run state', + value: 'history, attempts, next actions', }, { label: 'Recovery', @@ -78,8 +78,8 @@ const featureCards = [ icon: , }, { - title: 'Durability is part of the model.', - body: 'Long-running work should survive deploys, restarts, slow systems, and human delays without losing the state the business cares about.', + title: 'State is part of the model.', + body: 'Long-running work needs visible run state around slow systems, retries, human delays, and the next action the process is waiting on.', icon: , }, { @@ -105,7 +105,7 @@ const lifecycleSteps = [ }, { label: 'Wait', - body: 'Durable state can pause for external systems, timers, or approvals.', + body: 'The run can pause around external systems, timers, or approvals.', }, { label: 'Resume', @@ -163,8 +163,8 @@ export default function WorkflowLanding({

- Workflow models approvals, retries, fan-out, slow external - systems, and resumable state as durable TypeScript workflows + Workflow is for modeling approvals, retries, fan-out, slow + external systems, and visible run state as TypeScript workflows instead of one-off background jobs scattered across the app.

@@ -236,9 +236,9 @@ export default function WorkflowLanding({ Start, step, wait, resume.

- Durable workflows let process state move through time deliberately - instead of hoping a single request, queue worker, or deploy window - keeps everything together. + Typed workflows let process state move through time deliberately + instead of hoping a single request or queue worker keeps + everything together.

@@ -465,12 +465,11 @@ function ObservabilityPanel() {

- workflow.step("reserve inventory") + step: "reserve inventory"
-   .retry({'{'} attempts: 5, backoff: "exponential"{' '} - {'}'}) + attempts: 2 / 5
-   .waitForApproval("manager") + next: "manager approval"

diff --git a/src/components/landing/codeExamples.server.tsx b/src/components/landing/codeExamples.server.tsx index 75b33d82..47090c20 100644 --- a/src/components/landing/codeExamples.server.tsx +++ b/src/components/landing/codeExamples.server.tsx @@ -1,10 +1,7 @@ import * as React from 'react' import type { LibraryId } from '~/libraries' -import { formProject } from '~/libraries/form' import { queryProject } from '~/libraries/query' import { routerProject } from '~/libraries/router' -import { tableProject } from '~/libraries/table' -import { virtualProject } from '~/libraries/virtual' import { LandingCodeExampleCard, type LandingCodeExample, @@ -88,19 +85,19 @@ const { data, isPending, error } = useQuery({ code: ` -{#if $todos.isPending} +{#if todos.isLoading} Loading... -{:else if $todos.error} +{:else if todos.isError} Oops! -{:else} +{:else if todos.isSuccess} @@ -148,7 +145,7 @@ export class TodosList extends LitElement { }) render() { - const { data, isPending, error } = this.todos.current + const { data, isPending, error } = this.todos() if (isPending) return html\`Loading...\` if (error) return html\`Oops!\` @@ -201,218 +198,118 @@ export default function App() { } const formCodeExample: LandingCodeExample = { - frameworks: formProject.frameworks, + frameworks: ['react'], + title: 'React field and submit state', codeByFramework: { react: { lang: 'tsx', code: `import { useForm } from '@tanstack/react-form' -const form = useForm({ - defaultValues: { name: '' }, - onSubmit: async ({ value }) => console.log(value), -}) -// Bind inputs to form.state and form.handleSubmit`, - }, - vue: { - lang: 'vue', - code: ` - -`, - }, - angular: { - lang: 'ts', - code: `import { Component } from '@angular/core' -import { createAngularForm } from '@tanstack/angular-form' - -@Component({ - standalone: true, - selector: 'app-form', - template: '
', -}) -export class AppComponent { - form = createAngularForm(() => ({ - defaultValues: { name: '' }, - onSubmit: async ({ value }) => console.log(value), - })) -}`, +export default function PeoplePage() { + const form = useForm({ + defaultValues: { age: 0 }, + onSubmit: ({ value }) => { + alert(JSON.stringify(value, null, 2)) }, - solid: { - lang: 'tsx', - code: `import { createForm } from '@tanstack/solid-form' - -export default function SimpleForm() { - const form = createForm({ - defaultValues: { name: '' }, - onSubmit: async ({ value }) => console.log(value), }) return ( -
- form.setFieldValue('name', e.currentTarget.value)} /> - + { + event.preventDefault() + event.stopPropagation() + form.handleSubmit() + }} + > + + value > 13 ? undefined : 'Must be 13 or older', + }} + children={(field) => ( + <> + + field.handleChange(event.target.valueAsNumber) + } + /> + {!field.state.meta.isValid && ( + {field.state.meta.errors.join(', ')} + )} + + )} + /> + [state.canSubmit, state.isSubmitting]} + children={([canSubmit, isSubmitting]) => ( + + )} + /> ) -}`, - }, - svelte: { - lang: 'svelte', - code: ` - -
- - -
`, - }, - lit: { - lang: 'ts', - code: `import { LitElement, customElement, html } from 'lit' -import { createLitForm } from '@tanstack/lit-form' - -@customElement('simple-form') -export class SimpleForm extends LitElement { - form = createLitForm({ - defaultValues: { name: '' }, - onSubmit: async ({ value }) => console.log(value), - }) - - override render() { - return html\`
{ e.preventDefault(); this.form.handleSubmit(e); }}> - this.form.setFieldValue('name', e.target.value)} /> - -
\` - } }`, }, }, } const virtualCodeExample: LandingCodeExample = { - frameworks: virtualProject.frameworks, + frameworks: ['react'], + title: 'React virtual rows', codeByFramework: { react: { lang: 'tsx', - code: `import { useVirtualizer } from '@tanstack/react-virtual' - -const rowVirtualizer = useVirtualizer({ - count: 1000, - getScrollElement: () => parentRef.current, - estimateSize: () => 36, -}) -// Map virtual rows to your UI`, - }, - solid: { - lang: 'tsx', - code: `import { createVirtualizer } from '@tanstack/solid-virtual' - -const parentRef: HTMLElement | undefined = undefined - -const rowVirtualizer = createVirtualizer({ - count: 1000, - getScrollElement: () => parentRef!, - estimateSize: () => 36, -}) -// Map rowVirtualizer.getVirtualItems() to your UI`, - }, - vue: { - lang: 'vue', - code: ` - -`, - }, - svelte: { - lang: 'svelte', - code: ` - -
- -
`, - }, - angular: { - lang: 'ts', - code: `import { Component, ElementRef, viewChild } from '@angular/core' -import { createAngularVirtualizer } from '@tanstack/angular-virtual' -@Component({ - standalone: true, - selector: 'virtual-list', - template: '
', -}) -export class VirtualListComponent { - parent = viewChild.required>('parent') - virtualizer = createAngularVirtualizer(() => ({ - count: 1000, - getScrollElement: () => this.parent().nativeElement, - estimateSize: () => 36, - })) -}`, - }, - lit: { - lang: 'ts', - code: `import { LitElement, customElement, html } from 'lit' -import { createLitVirtualizer } from '@tanstack/lit-virtual' - -@customElement('virtual-list') -export class VirtualList extends LitElement { - private parent?: HTMLDivElement - virtualizer = createLitVirtualizer({ - count: 1000, - getScrollElement: () => this.parent!, - estimateSize: () => 36, - }) - - render() { - return html\`
\` - } + return ( +
+
+ {rowVirtualizer.getVirtualItems().map((virtualRow) => ( +
+ Row {virtualRow.index} +
+ ))} +
+
+ ) }`, }, }, } const tableCodeExample: LandingCodeExample = { - frameworks: tableProject.frameworks, + frameworks: ['react'], + title: 'React table instance', codeByFramework: { react: { lang: 'tsx', @@ -422,16 +319,23 @@ const data = [{ id: 1, name: 'Ada' }] const columns = [{ accessorKey: 'name', header: 'Name' }] export default function SimpleTable() { - const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() }) + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + }) return ( - {table.getHeaderGroups().map((hg) => ( - - {hg.headers.map((header) => ( + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( ))} @@ -452,262 +356,6 @@ export default function SimpleTable() { ) }`, }, - angular: { - lang: 'ts', - code: `import { Component, signal } from '@angular/core' -import { createAngularTable, getCoreRowModel, FlexRenderDirective, type ColumnDef } from '@tanstack/angular-table' - -type Person = { id: number; name: string } - -@Component({ - standalone: true, - selector: 'app-table', - imports: [FlexRenderDirective], - template: \ -\` -
- {flexRender(header.column.columnDef.header, header.getContext())} + {flexRender( + header.column.columnDef.header, + header.getContext(), + )}
- - @for (hg of table.getHeaderGroups(); track hg.id) { - - @for (header of hg.headers; track header.id) { - - } - - } - - - @for (row of table.getRowModel().rows; track row.id) { - - @for (cell of row.getVisibleCells(); track cell.id) { - - } - - } - -
- -
- -
- \`, -}) -export class AppComponent { - data = signal([{ id: 1, name: 'Ada' }]) - - columns: ColumnDef[] = [ - { accessorKey: 'name', header: 'Name' }, - ] - - table = createAngularTable(() => ({ - data: this.data(), - columns: this.columns, - getCoreRowModel: getCoreRowModel(), - })) -}`, - }, - solid: { - lang: 'tsx', - code: `import { createSolidTable, getCoreRowModel, flexRender } from '@tanstack/solid-table' - -const data = [{ id: 1, name: 'Ada' }] -const columns = [{ accessorKey: 'name', header: 'Name' }] - -export default function SimpleTable() { - const table = createSolidTable({ data, columns, getCoreRowModel: getCoreRowModel() }) - - return ( - - - {table.getHeaderGroups().map((hg) => ( - - {hg.headers.map((header) => ( - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - ))} - - ))} - -
{flexRender(header.column.columnDef.header, header.getContext())}
{flexRender(cell.column.columnDef.cell, cell.getContext())}
- ) -}`, - }, - vue: { - lang: 'vue', - code: ` - -`, - }, - svelte: { - lang: 'svelte', - code: ` - - - - {#each table.getHeaderGroups() as hg} - - {#each hg.headers as header} - - {/each} - - {/each} - - - {#each table.getRowModel().rows as row} - - {#each row.getVisibleCells() as cell} - - {/each} - - {/each} - -
{flexRender(header.column.columnDef.header, header.getContext())}
{flexRender(cell.column.columnDef.cell, cell.getContext())}
`, - }, - lit: { - lang: 'ts', - code: `import { LitElement, customElement, html } from 'lit' -import { createLitTable, getCoreRowModel, flexRender } from '@tanstack/lit-table' - -const data = [{ id: 1, name: 'Ada' }] -const columns = [{ accessorKey: 'name', header: 'Name' }] - -@customElement('simple-table') -export class SimpleTable extends LitElement { - table = createLitTable({ data, columns, getCoreRowModel: getCoreRowModel() }) - - render() { - return html\` - - \${this.table.getHeaderGroups().map((hg) => html\` - \${hg.headers.map((header) => html\`\`)} - \`)} - - - \${this.table.getRowModel().rows.map((row) => html\` - \${row.getVisibleCells().map((cell) => html\`\`)} - \`)} - -
\${flexRender(header.column.columnDef.header, header.getContext())}
\${flexRender(cell.column.columnDef.cell, cell.getContext())}
\` - } -}`, - }, - qwik: { - lang: 'tsx', - code: `import { component$ } from '@builder.io/qwik' -import { createQwikTable, getCoreRowModel, flexRender } from '@tanstack/qwik-table' - -const data = [{ id: 1, name: 'Ada' }] -const columns = [{ accessorKey: 'name', header: 'Name' }] - -export default component$(() => { - const table = createQwikTable({ data, columns, getCoreRowModel: getCoreRowModel() }) - return ( - - - {table.getHeaderGroups().map((hg) => ( - - {hg.headers.map((header) => ( - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - ))} - - ))} - -
{flexRender(header.column.columnDef.header, header.getContext())}
{flexRender(cell.column.columnDef.cell, cell.getContext())}
- ) -})`, - }, - vanilla: { - lang: 'ts', - code: `import { createTable, getCoreRowModel, flexRender } from '@tanstack/table-core' - -const data = [{ id: 1, name: 'Ada' }] -const columns = [{ accessorKey: 'name', header: 'Name' }] - -const table = createTable({ data, columns, getCoreRowModel: getCoreRowModel() }) - -const thead = document.querySelector('thead')! -table.getHeaderGroups().forEach((hg) => { - const tr = document.createElement('tr') - hg.headers.forEach((header) => { - const th = document.createElement('th') - th.textContent = String(flexRender(header.column.columnDef.header, header.getContext())) - tr.appendChild(th) - }) - thead.appendChild(tr) -}) - -const tbody = document.querySelector('tbody')! -table.getRowModel().rows.forEach((row) => { - const tr = document.createElement('tr') - row.getVisibleCells().forEach((cell) => { - const td = document.createElement('td') - td.textContent = String(flexRender(cell.column.columnDef.cell, cell.getContext())) - tr.appendChild(td) - }) - tbody.appendChild(tr) -})`, - }, - }, - renderFallback: (framework) => { - return ( -
- Looking for the @tanstack/{framework}-table example? We - could use your help to build the{' '} - @tanstack/{framework}-table adapter! Join the{' '} - - TanStack Discord Server - {' '} - and let's get to work! -
- ) }, } diff --git a/src/libraries/libraries.ts b/src/libraries/libraries.ts index fd661888..f5c1ec4f 100644 --- a/src/libraries/libraries.ts +++ b/src/libraries/libraries.ts @@ -747,7 +747,7 @@ export const devtools: LibrarySlim = { bgRadial: 'from-black via-gray-600/50 to-transparent dark:from-gray-100 dark:via-gray-400/50', repo: 'tanstack/devtools', - frameworks: ['react', 'preact', 'solid', 'vanilla'], + frameworks: ['react', 'preact', 'solid', 'vue', 'angular', 'vanilla'], corePackageName: '@tanstack/devtools', npmPackageNames: ['@tanstack/devtools', '@tanstack/react-devtools'], latestVersion: 'v0', @@ -787,9 +787,9 @@ export const mcp: LibrarySlim = { availableVersions: ['v1'], visible: false, handleRedirects: (href: string) => { - // All /mcp routes redirect to CLI MCP docs + // All /mcp routes redirect to the CLI MCP migration guide if (/\/mcp(\/|$)/.test(href)) { - throw redirect({ href: '/cli/latest/docs/mcp/overview' }) + throw redirect({ href: '/cli/latest/docs/mcp-migration' }) } }, } @@ -799,9 +799,9 @@ export const cli: LibrarySlim = { name: 'TanStack CLI', cardStyles: 'text-indigo-500 dark:text-indigo-400 hover:border-current', to: '/cli', - tagline: 'CLI, MCP server, and AI toolkit for TanStack', + tagline: 'CLI and project scaffolding toolkit for TanStack', description: - 'A CLI, MCP server, and AI toolkit for TanStack. Create and customize TanStack Start apps, search docs, integrate with AI agents, and more.', + 'A CLI toolkit for TanStack. Create and customize TanStack Start apps, search docs, inspect add-ons, and generate project changes with current TanStack context.', badge: 'alpha', bgStyle: 'bg-indigo-500', borderStyle: 'border-indigo-500/50', diff --git a/src/utils/config.ts b/src/utils/config.ts index b9b5958d..ad326437 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -103,7 +103,7 @@ export const getTanstackDocsConfig = createServerFn({ method: 'GET' }) } if (!config) { - throw new Error(`Repo's ${docsRoot}/config.json was not found!`) + return getEmptyConfig() } try {